Advanced Apex Specialist Superbadge
Step 1:
Constants Class:
public class Constants{
public static final Integer DEFAULT_ROWS = 5;
public static final String SELECT_ONE = Label.Select_One;
public static final String INVENTORY_LEVEL_LOW = Label.Inventory_Level_Low;
public static final List<Schema.PicklistEntry> PRODUCT_FAMILY = Product2.Family.getDescribe().getPicklistValues();
public static final String DRAFT_ORDER_STATUS = 'Draft';
public static final String ACTIVATED_ORDER_STATUS = 'Activated';
public static final String INVENTORY_ANNOUNCEMENTS = 'Inventory Announcements';
public static final String ERROR_MESSAGE = 'An error has occurred, please take a screenshot with the URL and send it to IT.';
public static final Id STANDARD_PRICEBOOK_ID = '01s1N000007brPH';
}
Create Custom Metadata type
Step 2:
Order Trigger:
trigger orderTrigger on Order (after update)
{
OrderHelper.AfterUpdate(Trigger.New, Trigger.Old);
}
{
OrderHelper.AfterUpdate(Trigger.New, Trigger.Old);
}
Order Helper
public without sharing class OrderHelper {
public static void AfterUpdate(List<Order> newList, List<Order> oldList){
Set<Id> orderIds = new Set<Id>();
for ( Integer i=0; i< newList.size(); i++ ){
if ( newList[i].Status == Constants.ACTIVATED_ORDER_STATUS && oldList[i].Status == Constants.DRAFT_ORDER_STATUS ){
orderIds.add(newList[i].Id);
}
}
RollUpOrderItems(orderIds);
}
public static void RollUpOrderItems(Set<Id> activatedOrderIds){
Map<Id, Product2> productMap = new Map<Id, Product2>();
for(OrderItem orderLine : [SELECT Id, Product2Id, Product2.Quantity_Ordered__c, Quantity, Order.ActivatedDate
FROM OrderItem WHERE OrderId IN : activatedOrderIds]){
if(!productMap.containsKey(orderLine.Product2Id))
productMap.put(orderLine.Product2Id, new Product2(Id =orderLine.Product2Id, Quantity_Ordered__c=0));
}
for(AggregateResult ag : [SELECT Sum(Quantity), Product2Id FROM OrderItem WHERE Product2Id IN : productMap.keySet() Group By Product2Id]){
Id product2Id = (Id)ag.get('Product2Id');
Product2 prod = productMap.get(product2Id);
prod.Quantity_Ordered__c = (Decimal)ag.get('expr0');
productMap.put(product2Id , prod);
}
try {
if(productMap.values() != null && productMap.values().size() > 0){
update productMap.values();
}
}catch ( Exception e ){
System.debug('#### Exception Executed : '+e.getStackTraceString());
}
}
}
Step 3:
Product2New Page
<apex:page standardController="Product2" extensions="Product2Extension">
<apex:sectionHeader title="New Product" subtitle="Add Inventory" />
<apex:pageMessages id="pageMessages" />
<apex:form id="form" >
<apex:actionRegion >
<apex:pageBlock title="Existing Inventory" >
<apex:chart height="250" width="350" data="{!Inventory}">
<apex:axis type="Numeric" position="left" fields="data" title="MT WON" />
<apex:axis type="Category" position="bottom" fields="name" title="Month"/>
<apex:barSeries orientation="horizontal" axis="left" xField="data" yField="name" />
</apex:chart>
</apex:pageBlock>
<apex:pageBlock title="New Products" >
<apex:pageBlockButtons location="top">
<apex:commandButton action="{!save}" value="Save" />
</apex:pageBlockButtons>
<apex:pageBlockButtons location="bottom">
<apex:commandButton action="{!addRows}" value="Add" reRender="orderItemTable,pageMessages"/>
</apex:pageBlockButtons>
<apex:pageBlockTable value="{!productsToInsert}" var="p" id="orderItemTable" >
<apex:column headerValue="{!$ObjectType.Product2.fields.Name.label}" >
<apex:inputText value="{!p.productRecord.Name}" />
</apex:column>
<apex:column headerValue="{!$ObjectType.Product2.fields.Family.label}" >
<apex:selectList value="{!p.productRecord.Family}" size="1" multiselect="false">
<apex:selectOptions value="{!FamilyOptions}"/>
</apex:selectList>
</apex:column>
<apex:column headerValue="{!$ObjectType.Product2.fields.IsActive.label}" >
<apex:inputField value="{!p.productRecord.isActive}" />
</apex:column>
<apex:column headerValue="{!$ObjectType.pricebookEntry.fields.UnitPrice.label}" >
<apex:inputField value="{!p.pricebookEntryRecord.UnitPrice}" />
</apex:column>
<apex:column headerValue="{!$ObjectType.Product2.fields.Initial_Inventory__c.label}" >
<apex:inputField value="{!p.productRecord.Initial_Inventory__c}" />
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:actionRegion>
</apex:form>
</apex:page>
Product2Extension
public class Product2Extension {
//public List<Product2> productsToInsert {get;set;}
public List<ProductWrapper> productsToInsert {get;set;}
public Product2Extension(ApexPages.StandardController controller){
productsToInsert = new List<ProductWrapper>();
addRows();
}
public void AddRows(){
for ( Integer i=0; i<Constants.DEFAULT_ROWS; i++ ){
productsToInsert.add( new productWrapper() );
}
}
//Get family options
public List<SelectOption> GetFamilyOptions() {
List<SelectOption> options = new List<SelectOption>{
new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE)
};
for (Schema.PicklistEntry ple : Constants.PRODUCT_FAMILY) {
options.add(new SelectOption(ple.getValue(), ple.getLabel()));
}
return options;
}
public List<ChartHelper.ChartData> GetInventory(){
return ChartHelper.GetInventory();
}
public PageReference Save(){
Savepoint sp = Database.setSavepoint();
try {
List<Product2> products = new List<Product2>();
List<PricebookEntry> entries = new List<PricebookEntry>();
for (ProductWrapper wrp : productsToInsert){
if(wrp.productRecord != null && wrp.pricebookEntryRecord != null){
if(wrp.productRecord.Name != null && wrp.productRecord.Family != null &&
wrp.productRecord.Family != Constants.SELECT_ONE && wrp.productRecord.Initial_Inventory__c != null &&
wrp.pricebookEntryRecord.UnitPrice != null){
products.add(wrp.productRecord);
PricebookEntry entry=wrp.pricebookEntryRecord;
entry.IsActive=true;
entry.Pricebook2Id=constants.STANDARD_PRICEBOOK_ID;
entries.add(entry);
}
}
}
insert products;
for (integer itr=0; itr<entries.size();itr++){
entries[itr].Product2Id=products[itr].id;
}
insert entries;
//If successful clear the list and display an informational message
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,productsToInsert.size()+' Inserted'));
productsToInsert.clear(); //Do not remove
addRows(); //Do not remove
} catch (Exception e){
Database.rollback(sp);
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,constants.ERROR_MESSAGE));
}
return null;
}
//Product Wrapper Class
public class ProductWrapper{
public product2 productRecord {get;set;}
public pricebookEntry pricebookEntryRecord{get;set;}
public productWrapper(){
productRecord = new product2(Initial_Inventory__c =0);
pricebookEntryRecord = new pricebookEntry(Unitprice=0.0);
}
}
}
ChartHelper class
public without sharing class ChartHelper {
@AuraEnabled
public static List<chartData> GetInventory(){
List<chartData> cht = new List<chartData>();
for (AggregateResult ar : [SELECT Family, SUM(Quantity_Remaining__c) FROM Product2
WHERE Quantity_Remaining__c>0
AND IsActive = true
GROUP BY Family]) {
cht.add(new ChartData(String.ValueOf(ar.get('Family')), Integer.ValueOf(ar.get('expr0'))));
}
return cht;
}
public class ChartData {
public String name {get;set;}
public Decimal val {get;set;}
public ChartData(String name, Decimal val){
this.name = name;
this.val = val;
}
}
}
Step 4:
TestDataFactory
/**
* @name TestDataFactory
* @description Contains methods to construct and/or validate commonly used records
**/
public with sharing class TestDataFactory {
/**
* @name ConstructCollaborationGroup
* @description
**/
public static CollaborationGroup ConstructCollaborationGroup(){
//ToDo: Ensure this method returns a single Chatter CollaborationGroup
// whose Name starts with 'TEST' followed by the INVENTORY_ANNOUNCEMENTS constant
// and configured so anyone can join, see and post updates.
CollaborationGroup ChatterGroup = new CollaborationGroup(
Name = 'TEST'+Constants.INVENTORY_ANNOUNCEMENTS,
CollaborationType = 'Public',
IsArchived = false,
IsAutoArchiveDisabled = true
);
return ChatterGroup;
}
/**
* @name CreateProducts
* @description Constructs a list of Product2 records for unit tests
**/
public static list<Product2> ConstructProducts(Integer cnt){
//ToDo: Ensure this method returns a list, of size cnt, of uniquely named Product2 records
// with all the required fields populated
// and IsActive = true
// an Initial Inventory set to 10
// and iterating through the product family picklist values throughout the list.
list<Product2> products=new list<Product2>();
list<Schema.PicklistEntry> pEntries = Constants.PRODUCT_FAMILY;
Integer pVal = 0;
for(Integer i=0;i<cnt;i++){
Product2 pd2=new Product2();
pd2.Name='Product-'+i;
pd2.IsActive = true;
pd2.Initial_Inventory__c = 10;
if(pVal == 4){
pVal = 0;
}
pd2.Family = pEntries.get(pVal).getValue();
pVal++;
products.add(pd2);
}
return products;
}
/**
* @name CreatePricebookEntries
* @description Constructs a list of PricebookEntry records for unit tests
**/
public static list<PriceBookEntry> ConstructPricebookEntries(List<Product2> prods){
//ToDo: Ensure this method returns a corresponding list of PricebookEntries records
// related to the provided Products
// with all the required fields populated
// and IsActive = true
// and belonging to the standard Pricebook
list<PriceBookEntry> entries=new list<PriceBookEntry>();
for(Product2 pd2: prods){
PriceBookEntry pbe=new PriceBookEntry();
pbe.isActive = true;
pbe.UnitPrice = 100;
pbe.Product2Id = pd2.id;
pbe.PriceBook2Id = Constants.STANDARD_PRICEBOOK_ID;
entries.add(pbe);
}
return entries;
}
/**
* @name CreateAccounts
* @description Constructs a list of Account records for unit tests
**/
public static list<Account> ConstructAccounts(Integer cnt){
//ToDo: Ensure this method returns a list of size cnt of uniquely named Account records
// with all of the required fields populated.
list<Account> accounts=new list<Account>();
for(Integer i=0;i<cnt;i++){
Account ac=new Account();
ac.Name = 'Account'+i;
accounts.add(ac);
}
return accounts;
}
/**
* @name CreateContacts
* @description Constructs a list of Contacxt records for unit tests
**/
public static list<Contact> ConstructContacts(Integer cnt, List<Account> accts){
//ToDo: Ensure this method returns a list, of size cnt, of uniquely named Contact records
// related to the provided Accounts
// with all of the required fields populated.
list<Contact> conts=new list<Contact>();
for(Integer i=0;i<cnt;i++){
contact con=new contact();
con.LastName = 'Contact'+i;
con.AccountId = accts.get(i).id;
conts.add(con);
}
return conts;
}
/**
* @name CreateOrders
* @description Constructs a list of Order records for unit tests
**/
public static list<Order> ConstructOrders(Integer cnt, List<Account> accts){
//ToDo: Ensure this method returns a list of size cnt of uniquely named Order records
// related to the provided Accounts
// with all of the required fields populated.
list<Order> orders=new list<Order>();
for(Integer i=0;i<cnt;i++){
Order ord=new Order();
ord.Name = 'Order'+i;
ord.AccountId = accts.get(i).Id;
ord.EffectiveDate = Date.Today();
ord.Status = Constants.DRAFT_ORDER_STATUS;
ord.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
orders.add(ord);
}
return orders;
}
/**
* @name CreateOrderItems
* @description Constructs a list of OrderItem records for unit tests
**/
public static list<OrderItem> ConstructOrderItems(integer cnt, list<pricebookentry> pbes, list<order> ords){
//ToDo: Ensure this method returns a list of size cnt of OrderItem records
// related to the provided Pricebook Entries
// and related to the provided Orders
// with all of the required fields populated.
// Hint: Use the DEFAULT_ROWS constant for Quantity as it will be used in the next challenge
list<OrderItem> orderItems=new list<OrderItem>();
for(Integer i=0;i<cnt;i++){
OrderItem oItem=new OrderItem();
oItem.OrderId = ords.get(i).Id;
oItem.PriceBookEntryId = pbes.get(i).Id;
oItem.Quantity = Constants.DEFAULT_ROWS;
oItem.UnitPrice = 10;
orderItems.add(oItem);
}
return orderItems;
}
/**
* @name SetupTestData
* @description Inserts accounts, contacts, Products, PricebookEntries, Orders, and OrderItems.
**/
public static void InsertTestData(Integer cnt){
//ToDo: Ensure this method calls each of the construct methods
// and inserts the results for use as test data.
list<Account> accounts = ConstructAccounts(cnt);
Insert accounts;
list<Contact> contacts = ConstructContacts(cnt, accounts);
insert contacts;
list<Product2> prods= ConstructProducts(cnt);
insert prods;
list<PriceBookEntry> entries = ConstructPricebookEntries(prods);
insert entries;
list<Order> orders = ConstructOrders(cnt, accounts);
insert orders;
list<OrderItem> ordItems = ConstructOrderItems(cnt, entries, orders);
insert ordItems;
}
}
Step 5
TestDataFactory
public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered){
system.AssertEquals(updatedProduct.Quantity_Ordered__c,originalProduct.Quantity_Ordered__c +qtyOrdered);
}
system.AssertEquals(updatedProduct.Quantity_Ordered__c,originalProduct.Quantity_Ordered__c +qtyOrdered);
}
Product2Test
@isTest (seeAllData=false)
private class Product2Tests {
/**
* @name product2Extension_UnitTest
* @description UnitTest for product2Extension
**/
@isTest
static void Product2Extension_UnitTest(){
PageReference pageRef = Page.Product2New;
Test.setCurrentPage(pageRef);
Product2 prod = new Product2(name='Test',isActive=true);
ApexPages.StandardController stdcontroller = new ApexPages.StandardController(prod);
Product2Extension ext = new Product2Extension(stdcontroller);
System.assertEquals(Constants.DEFAULT_ROWS, ext.productsToInsert.size());
ext.addRows();
System.assertEquals(Constants.DEFAULT_ROWS * 2, ext.productsToInsert.size());
for (Integer i = 0; i < 5; i++) {
Product2Extension.ProductWrapper wrapper = ext.productsToInsert[i];
Product2 testProduct = new Product2();
testProduct.Name = 'Test Product_' + i;
testProduct.IsActive = true;
testProduct.Initial_Inventory__c = 20;
testProduct.Family = Constants.PRODUCT_FAMILY[0].getValue();
wrapper.productRecord = testProduct;
PricebookEntry testEntry = new PricebookEntry();
testEntry.IsActive = true;
testEntry.UnitPrice = 10;
wrapper.pricebookEntryRecord = testEntry;
}
Test.startTest();
ext.save();
Test.stopTest();
ext.GetFamilyOptions();
ext.GetInventory();
List<Product2> createdProducts = [
SELECT Id FROM Product2 where Name LIKE :'Test Product%'];
System.assertEquals(5, createdProducts.size());
}
}
OrderTests
@isTest
public class OrderTests {
@testSetup
public static void SetupTestData(){
TestDataFactory.InsertTestData(5);
}
static testmethod void OrderUpdate_UnitTest (){
test.startTest();
Order rec = [select id, Status from Order limit 1];
Product2 prod = [SELECT Family,Id,Name,Quantity_Ordered__c,Quantity_Remaining__c FROM Product2 limit 1];
system.debug('kkk '+prod.Quantity_Ordered__c);
rec.status = constants.ACTIVATED_ORDER_STATUS;
Update rec;
Product2 updatedprod = [SELECT Family,Id,Name,Quantity_Ordered__c,Quantity_Remaining__c FROM Product2 limit 1];
system.debug('kkk '+updatedprod.Quantity_Ordered__c);
TestDataFactory.VerifyQuantityOrdered(prod,updatedprod,constants.DEFAULT_ROWS);
Test.stopTest();
}
}
Step 6
Create a chatter group name Inventory Announcements with correct discription
AnnouncementQueueable
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements System.Queueable{
public List<ConnectApi.AnnouncementInput> toPost;
public AnnouncementQueueable(List<ConnectApi.AnnouncementInput> toPost){
this.toPost = toPost;
}
public void execute(QueueableContext context){
PostAnnouncements(toPost);
}
/**
* @name postAnnouncements
* @description This method is provided for you to facilitate the Super Badge
**/
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
AnnouncementQueueable announcementQueuable
= new AnnouncementQueueable(announcements);
// announcementQueuable.toPost = announcements;
System.enqueueJob(announcementQueuable);
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q =
new AnnouncementQueueable(announcements);
// q.toPost = announcements;
System.enqueueJob(q);
//ToDo: Enqueue the above instance of announcementQueueable
}
}
}
Product2Helper Class
public class Product2Helper {
/**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
static List<CollaborationGroup> COLLABORATION_GROUP = [
SELECT Id
FROM CollaborationGroup
//WHERE Name = 'group name'
WHERE Name = :Constants.INVENTORY_ANNOUNCEMENTS
OR Name = :('TEST'+Constants.INVENTORY_ANNOUNCEMENTS)
LIMIT 1
];
/**
* @name afterUpdate
* @description called by product2 Trigger on After Update
* @param List<Product2> newList
* @param List<Product2> oldList
**/
public static void AfterUpdate(List<Product2> newList){
// public static void AfterUpdate(List<Product2> newList, List<Product2> oldList){
List<Product2> needsAnnouncement = new List<Product2>();
Map<String, Inventory_Setting__mdt> records =
new Map<String, Inventory_Setting__mdt>();
List<Inventory_Setting__mdt> inventorySettings = [SELECT Label, Low_Quantity_Alert__c FROM Inventory_Setting__mdt];
for(Inventory_Setting__mdt inventorySetting:inventorySettings){
records.put(inventorySetting.Label,inventorySetting);
}
for(Integer i=0;i<newList.size();i++){
Inventory_Setting__mdt inventorySetting =
(Inventory_Setting__mdt)records.get(newList[i].Family);
Integer alertQuantity = (Integer)inventorySetting.Low_Quantity_Alert__c;
if( newList[i].Quantity_Remaining__c <= alertQuantity ){
needsAnnouncement.add(newList[i]);
}
/*(if( newList[i].Quantity_Remaining__c <= alertQuantity &&
oldList[i].Quantity_Remaining__c > alertQuantity){
needsAnnouncement.add(newList[i]);
}*/
}
PostAlerts(needsAnnouncement);
//ToDo: Declare a List of Product2 records named needsAnnouncement
//ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
//ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
//ToDo: Loop through the Products in newList
// Use the corresponding Inventory Setting record to determine the correct Low Quantity Alert
// If the Product's Quantity Remaining has been changed to less than the Low Quantity Alert
// add it to the needsAnnouncement list
//ToDo: Pass records to the postAlerts method
}
/**
* @name postAlerts
* @description called by product2 Trigger on After Update
* @param List<Product2> productList
**/
public static void PostAlerts(List<Product2> productList){
List<ConnectApi.AnnouncementInput> toPost = new List<ConnectApi.AnnouncementInput>();
for ( Product2 p : productList ){
ConnectApi.AnnouncementInput announcement =
new ConnectApi.AnnouncementInput();
ConnectApi.MessageBodyInput messageBodyInput =
new ConnectApi.MessageBodyInput();
List<ConnectApi.MessageSegmentInput> messageSegmentInput =
new List<ConnectApi.MessageSegmentInput>();
ConnectApi.TextSegmentInput bodySegmentInput = new ConnectApi.TextSegmentInput();
bodySegmentInput.text = p.Name + ' ' + Constants.INVENTORY_LEVEL_LOW;
messageSegmentInput.add(bodySegmentInput);
messageBodyInput.messageSegments = messageSegmentInput;
announcement.parentId = COLLABORATION_GROUP.get(0).Id;
announcement.sendEmails = false;
announcement.expirationDate = System.today()+1;
announcement.body = messageBodyInput;
toPost.add(announcement);
// ToDo: Construct a new AnnouncementInput for the Chatter Group so that it:
// expires in a day
// does not notify users via email.
// and has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant
}
AnnouncementQueueable announcementQueuable = new AnnouncementQueueable(toPost);
// announcementQueuable.toPost = toPost;
Id jobId = System.enqueueJob(announcementQueuable);
// ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
}
}
Product Trigger
/**
* @name product2Trigger
* @description Trigger to notify staff of low levels of inventory
**/
trigger product2Trigger on Product2 (
after update
) {
Product2Helper.AfterUpdate((List<Product2>)Trigger.new);
}
Step 7:
OrderExtension
/**
* @name OrderExtension
* @description This class is provided for you to facilitate the Super Badge
**/
public class OrderExtension {
public Order orderRecord {get;set;}
public List<OrderItem> orderItemList {get;set;}
public String selectedFamily {get;set;}
public List<chartHelper.chartData> pieData {get;set;}
public Decimal total {get;set;}
public Map<Id,OrderItem> orderItemMap;
ApexPages.StandardSetController standardSetController;
public OrderExtension(ApexPages.StandardController standardController){
orderRecord = (Order)standardController.getRecord();
orderItemMap = new Map<id,OrderItem>();
if ( orderRecord.Id != null ){
orderRecord = queryOrderRecord(orderRecord.Id);
}
resetSsc();
total = 0;
for (OrderItem oi : orderRecord.OrderItems) {
orderItemMap.put(oi.Product2Id, oi);
if (oi.Quantity > 0) {
if (null == pieData) {
pieData = new List<ChartHelper.ChartData>();
}
pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
total += oi.UnitPrice * oi.Quantity;
}
}
PopulateOrderItems();
}
void resetSsc() {
String query = 'SELECT Name, Product2.Family, Product2.Name, Product2Id, UnitPrice, Product2.Quantity_Remaining__c'
+ ' FROM PricebookEntry WHERE IsActive = TRUE';
if (selectedFamily != null && selectedFamily != Constants.SELECT_ONE) {
query += ' AND Product2.Family = \'' + selectedFamily + '\'';
}
query += ' ORDER BY Name';
standardSetController = new ApexPages.StandardSetController(Database.getQueryLocator(query));
standardSetController.setPageSize(Constants.DEFAULT_ROWS);
}
//ToDo: Implement your own method to populate orderItemList
// that you will call after pagination and/or family selection
void PopulateOrderItems() {
orderItemList = new List<OrderItem>();
for (SObject obj : standardSetController.getRecords()) {
PricebookEntry pbe = (PricebookEntry)obj;
if (orderItemMap.containsKey(pbe.Product2Id)) {
orderItemList.add(orderItemMap.get(pbe.Product2Id));
} else {
orderItemList.add(new OrderItem(
PricebookEntryId=pbe.Id,
Product2Id=pbe.Product2Id,
UnitPrice=pbe.UnitPrice,
Quantity=0,
Product2=pbe.Product2
));
}
}
}
/**
* @name OnFieldChange
* @description
**/
public void OnFieldChange(){
//ToDo: Implement logic to store the values changed on the page
for (OrderItem oi : orderItemList) {
orderItemMap.put(oi.Product2Id, oi);
}
// and populate pieData
pieData = null;
total = 0;
for (OrderItem oi : orderItemMap.values()) {
if (oi.Quantity > 0) {
if (null == pieData) {
pieData = new List<chartHelper.ChartData>();
}
pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
// and populate total
total += oi.UnitPrice * oi.Quantity;
}
}
}
/**
* @name SelectFamily
* @description
**/
public void SelectFamily(){
//ToDo: Implement logic to filter based on the selected product family
resetSsc();
PopulateOrderItems();
}
/**
* @name Save
* @description
**/
public void Save(){
//ToDo: Implement logic to save the Order and populated OrderItems
System.Savepoint sp = Database.setSavepoint();
try {
if (null == orderRecord.Pricebook2Id) {
orderRecord.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
}
upsert orderRecord;
List<OrderItem> orderItemsToUpsert = new List<OrderItem>();
List<OrderItem> orderItemsToDelete = new List<OrderItem>();
for (OrderItem oi : orderItemList) {
if (oi.Quantity > 0) {
if (null == oi.OrderId) {
oi.OrderId = orderRecord.Id;
}
orderItemsToUpsert.add(oi);
} else if (oi.Id != null) {
orderItemsToDelete.add(oi);
}
}
upsert orderItemsToUpsert;
delete orderItemsToDelete;
} catch (Exception e) {
Database.rollback(sp);
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,Constants.ERROR_MESSAGE));
}
}
/**
* @name First
* @description
**/
public void First(){
standardSetController.first();
PopulateOrderItems();
}
/**
* @name Next
* @description
**/
public void Next(){
standardSetController.next();
PopulateOrderItems();
}
/**
* @name Previous
* @description
**/
public void Previous(){
standardSetController.previous();
PopulateOrderItems();
}
/**
* @name Last
* @description
**/
public void Last(){
standardSetController.last();
PopulateOrderItems();
}
/**
* @name GetHasPrevious
* @description
**/
public Boolean GetHasPrevious(){
return standardSetController.getHasPrevious();
}
/**
* @name GetHasNext
* @description
**/
public Boolean GetHasNext(){
return standardSetController.getHasNext();
}
/**
* @name GetTotalPages
* @description
**/
public Integer GetTotalPages(){
return (Integer)Math.ceil(standardSetController.getResultSize() / (Decimal)Constants.DEFAULT_ROWS);
}
/**
* @name GetPageNumber
* @description
**/
public Integer GetPageNumber(){
return standardSetController.getPageNumber();
}
/**
* @name GetFamilyOptions
* @description
**/
public List<SelectOption> GetFamilyOptions() {
List<SelectOption> options = new List<SelectOption>{
new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE)
};
for (Schema.PicklistEntry ple : Constants.PRODUCT_FAMILY) {
options.add(new SelectOption(ple.getValue(), ple.getLabel()));
}
return options;
}
/**
* @name QueryOrderRecord
* @description
**/
public static Order QueryOrderRecord(Id orderId){
return [
SELECT Id, AccountId, EffectiveDate, Name, Status, Pricebook2Id,
(
SELECT Id, OrderId, Quantity, UnitPrice, PricebookEntryId, Product2Id,
Product2.Name, Product2.Family, Product2.Quantity_Remaining__c
FROM OrderItems
)
FROM Order
WHERE Id = :orderId
];
}
}
Step 8:
AnnouncementQueueable Class
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements System.Queueable{
public List<ConnectApi.AnnouncementInput> toPost;
public AnnouncementQueueable(List<ConnectApi.AnnouncementInput> toPost){
this.toPost = toPost;
}
public void execute(QueueableContext context){
PostAnnouncements(toPost);
}
/**
* @name postAnnouncements
* @description This method is provided for you to facilitate the Super Badge
**/
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
AnnouncementQueueable announcementQueuable
= new AnnouncementQueueable(announcements);
// announcementQueuable.toPost = announcements;
//System.enqueueJob(announcementQueuable);
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q =
new AnnouncementQueueable(announcements);
// q.toPost = announcements;
System.enqueueJob(q);
//ToDo: Enqueue the above instance of announcementQueueable
}
}
}
Product2Extension
Public without sharing class Product2Extension {
public List<productWrapper> productsToInsert {get;set;}
public Product2Extension(ApexPages.StandardController controller){
productsToInsert = new List<productWrapper>();
AddRows();
}
//Get select list options//
public List<SelectOption> GetFamilyOptions() {
List<SelectOption> options = new List<SelectOption>{
new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE)
};
for (Schema.PicklistEntry ple : Constants.PRODUCT_FAMILY) {
options.add(new SelectOption(ple.getValue(), ple.getLabel()));
}
return options;
}
public void AddRows(){
for ( Integer i=0; i<Constants.DEFAULT_ROWS; i++ ){
productsToInsert.add( new ProductWrapper() );
}
}
public List<ChartHelper.ChartData> GetInventory(){
return ChartHelper.GetInventory();
}
public PageReference Save(){
Savepoint sp = Database.setSavepoint();
try {
List<Product2> products = new List<Product2>();
List<PricebookEntry> entries = new List<PricebookEntry>();
for (ProductWrapper wrp : productsToInsert){
if(null!=wrp.productRecord && null!=wrp.pricebookEntryRecord){
if(null!=wrp.productRecord.Name && null!=wrp.productRecord.Family && constants.SELECT_ONE!=wrp.productRecord.Family
&& null!=wrp.productRecord.Initial_Inventory__c && null!=wrp.pricebookEntryRecord.UnitPrice){
products.add(wrp.productRecord);
PricebookEntry entry=wrp.pricebookEntryRecord;
entry.IsActive=true;
entry.Pricebook2Id=constants.STANDARD_PRICEBOOK_ID;
entries.add(entry);
}
}
}
insert products;
for (integer itr=0; itr<entries.size();itr++){
entries[itr].Product2Id=products[itr].id;
}
insert entries;
//If successful clear the list and display an informational message
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,productsToInsert.size()+' Inserted'));
productsToInsert.clear(); //Do not remove
addRows(); //Do not remove
} catch (Exception e){
Database.rollback(sp);
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,constants.ERROR_MESSAGE));
}
return null;
}
public class ProductWrapper{
public product2 productRecord {get;set;}
public pricebookEntry pricebookEntryRecord{get;set;}
public productWrapper(){
productRecord = new product2(Initial_Inventory__c =0);
pricebookEntryRecord = new pricebookEntry(Unitprice=0.0);
}
}
}
Product2Helper
public class Product2Helper {
/**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
static List<CollaborationGroup> COLLABORATION_GROUP = [
SELECT Id
FROM CollaborationGroup
//WHERE Name = 'group name'
WHERE Name = :Constants.INVENTORY_ANNOUNCEMENTS
OR Name = :('TEST'+Constants.INVENTORY_ANNOUNCEMENTS)
LIMIT 1
];
/**
* @name afterUpdate
* @description called by product2 Trigger on After Update
* @param List<Product2> newList
* @param List<Product2> oldList
**/
public static void AfterUpdate(List<Product2> newList){
// public static void AfterUpdate(List<Product2> newList, List<Product2> oldList){
List<Product2> needsAnnouncement = new List<Product2>();
Map<String, Inventory_Setting__mdt> records =
new Map<String, Inventory_Setting__mdt>();
List<Inventory_Setting__mdt> inventorySettings = [SELECT Label, Low_Quantity_Alert__c FROM Inventory_Setting__mdt];
for(Inventory_Setting__mdt inventorySetting:inventorySettings){
records.put(inventorySetting.Label,inventorySetting);
}
for(Integer i=0;i<newList.size();i++){
Inventory_Setting__mdt inventorySetting =
(Inventory_Setting__mdt)records.get(newList[i].Family);
Integer alertQuantity = (Integer)inventorySetting.Low_Quantity_Alert__c;
if( newList[i].Quantity_Remaining__c <= alertQuantity ){
needsAnnouncement.add(newList[i]);
}
/*(if( newList[i].Quantity_Remaining__c <= alertQuantity &&
oldList[i].Quantity_Remaining__c > alertQuantity){
needsAnnouncement.add(newList[i]);
}*/
}
PostAlerts(needsAnnouncement);
//ToDo: Declare a List of Product2 records named needsAnnouncement
//ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
//ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
//ToDo: Loop through the Products in newList
// Use the corresponding Inventory Setting record to determine the correct Low Quantity Alert
// If the Product's Quantity Remaining has been changed to less than the Low Quantity Alert
// add it to the needsAnnouncement list
//ToDo: Pass records to the postAlerts method
}
/**
* @name postAlerts
* @description called by product2 Trigger on After Update
* @param List<Product2> productList
**/
public static void PostAlerts(List<Product2> productList){
List<ConnectApi.AnnouncementInput> toPost = new List<ConnectApi.AnnouncementInput>();
for ( Product2 p : productList ){
ConnectApi.AnnouncementInput announcement =
new ConnectApi.AnnouncementInput();
ConnectApi.MessageBodyInput messageBodyInput =
new ConnectApi.MessageBodyInput();
List<ConnectApi.MessageSegmentInput> messageSegmentInput =
new List<ConnectApi.MessageSegmentInput>();
ConnectApi.TextSegmentInput bodySegmentInput = new ConnectApi.TextSegmentInput();
bodySegmentInput.text = p.Name + ' ' + Constants.INVENTORY_LEVEL_LOW;
messageSegmentInput.add(bodySegmentInput);
messageBodyInput.messageSegments = messageSegmentInput;
announcement.parentId = COLLABORATION_GROUP.get(0).Id;
announcement.sendEmails = false;
announcement.expirationDate = System.today()+1;
announcement.body = messageBodyInput;
toPost.add(announcement);
// ToDo: Construct a new AnnouncementInput for the Chatter Group so that it:
// expires in a day
// does not notify users via email.
// and has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant
}
AnnouncementQueueable announcementQueuable = new AnnouncementQueueable(toPost);
// announcementQueuable.toPost = toPost;
Id jobId = System.enqueueJob(announcementQueuable);
// ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
}
}
TestDataFactory
/**
* @name TestDataFactory
* @description Contains methods to construct and/or validate commonly used records
**/
public with sharing class TestDataFactory {
public static List<Product2> prods;
public static List<PricebookEntry> entries;
public static List<Order> orders;
public static List<OrderItem> orderItems;
/**
* @name ConstructCollaborationGroup
* @description
**/
public static CollaborationGroup ConstructCollaborationGroup(){
//ToDo: Ensure this method returns a single Chatter CollaborationGroup
// whose Name starts with 'TEST' followed by the INVENTORY_ANNOUNCEMENTS constant
// and configured so anyone can join, see and post updates.
CollaborationGroup ChatterGroup = new CollaborationGroup(
Name = 'TEST'+Constants.INVENTORY_ANNOUNCEMENTS,
CollaborationType = 'Public',
IsArchived = false,
IsAutoArchiveDisabled = true
);
return ChatterGroup;
}
/**
* @name CreateProducts
* @description Constructs a list of Product2 records for unit tests
**/
public static list<Product2> ConstructProducts(Integer cnt){
//ToDo: Ensure this method returns a list, of size cnt, of uniquely named Product2 records
// with all the required fields populated
// and IsActive = true
// an Initial Inventory set to 10
// and iterating through the product family picklist values throughout the list.
list<Product2> products=new list<Product2>();
list<Schema.PicklistEntry> pEntries = Constants.PRODUCT_FAMILY;
Integer pVal = 0;
for(Integer i=0;i<cnt;i++){
Product2 pd2=new Product2();
pd2.Name='Product-'+i;
pd2.IsActive = true;
pd2.Initial_Inventory__c = 10;
if(pVal == 4){
pVal = 0;
}
pd2.Family = pEntries.get(pVal).getValue();
pVal++;
products.add(pd2);
}
return products;
}
/**
* @name CreatePricebookEntries
* @description Constructs a list of PricebookEntry records for unit tests
**/
public static list<PriceBookEntry> ConstructPricebookEntries(List<Product2> prods){
//ToDo: Ensure this method returns a corresponding list of PricebookEntries records
// related to the provided Products
// with all the required fields populated
// and IsActive = true
// and belonging to the standard Pricebook
list<PriceBookEntry> entries=new list<PriceBookEntry>();
for(Product2 pd2: prods){
PriceBookEntry pbe=new PriceBookEntry();
pbe.isActive = true;
pbe.UnitPrice = 100;
pbe.Product2Id = pd2.id;
pbe.PriceBook2Id = Constants.STANDARD_PRICEBOOK_ID;
entries.add(pbe);
}
return entries;
}
/**
* @name CreateAccounts
* @description Constructs a list of Account records for unit tests
**/
public static list<Account> ConstructAccounts(Integer cnt){
//ToDo: Ensure this method returns a list of size cnt of uniquely named Account records
// with all of the required fields populated.
list<Account> accounts=new list<Account>();
for(Integer i=0;i<cnt;i++){
Account ac=new Account();
ac.Name = 'Account'+i;
accounts.add(ac);
}
return accounts;
}
/**
* @name CreateContacts
* @description Constructs a list of Contacxt records for unit tests
**/
public static list<Contact> ConstructContacts(Integer cnt, List<Account> accts){
//ToDo: Ensure this method returns a list, of size cnt, of uniquely named Contact records
// related to the provided Accounts
// with all of the required fields populated.
list<Contact> conts=new list<Contact>();
for(Integer i=0;i<cnt;i++){
contact con=new contact();
con.LastName = 'Contact'+i;
con.AccountId = accts.get(i).id;
conts.add(con);
}
return conts;
}
/**
* @name CreateOrders
* @description Constructs a list of Order records for unit tests
**/
public static list<Order> ConstructOrders(Integer cnt, List<Account> accts){
//ToDo: Ensure this method returns a list of size cnt of uniquely named Order records
// related to the provided Accounts
// with all of the required fields populated.
list<Order> orders=new list<Order>();
for(Integer i=0;i<cnt;i++){
Order ord=new Order();
ord.Name = 'Order'+i;
ord.AccountId = accts.get(i).Id;
ord.EffectiveDate = Date.Today();
ord.Status = Constants.DRAFT_ORDER_STATUS;
ord.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
orders.add(ord);
}
return orders;
}
/**
* @name CreateOrderItems
* @description Constructs a list of OrderItem records for unit tests
**/
public static list<OrderItem> ConstructOrderItems(integer cnt, list<pricebookentry> pbes, list<order> ords){
//ToDo: Ensure this method returns a list of size cnt of OrderItem records
// related to the provided Pricebook Entries
// and related to the provided Orders
// with all of the required fields populated.
// Hint: Use the DEFAULT_ROWS constant for Quantity as it will be used in the next challenge
list<OrderItem> orderItems=new list<OrderItem>();
for(Integer i=0;i<cnt;i++){
OrderItem oItem=new OrderItem();
oItem.OrderId = ords.get(i).Id;
oItem.PriceBookEntryId = pbes.get(i).Id;
oItem.Quantity = Constants.DEFAULT_ROWS;
oItem.UnitPrice = (Decimal)10;
orderItems.add(oItem);
}
return orderItems;
}
public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered){
//updatedProduct.Quantity_Ordered__c ==originalProduct.Quantity_Ordered__c +qtyOrdered;
system.AssertEquals(updatedProduct.Quantity_Ordered__c,originalProduct.Quantity_Ordered__c +qtyOrdered);
}
/**
* @name SetupTestData
* @description Inserts accounts, contacts, Products, PricebookEntries, Orders, and OrderItems.
**/
public static void InsertTestData(Integer cnt){
//ToDo: Ensure this method calls each of the construct methods
// and inserts the results for use as test data.
list<Account> accounts = ConstructAccounts(cnt);
Insert accounts;
list<Contact> contacts = ConstructContacts(cnt, accounts);
insert contacts;
prods= ConstructProducts(cnt);
insert prods;
entries = ConstructPricebookEntries(prods);
insert entries;
orders = ConstructOrders(cnt, accounts);
insert orders;
orderItems = ConstructOrderItems(cnt, entries, orders);
insert orderItems;
}
}
OrderHelper
public without sharing class OrderHelper {
public static void AfterUpdate(List<Order> newList, List<Order> oldList){
Set<Id> orderIds = new Set<Id>();
for ( Integer i=0; i< newList.size(); i++ ){
if ( newList[i].Status == Constants.ACTIVATED_ORDER_STATUS && oldList[i].Status == Constants.DRAFT_ORDER_STATUS ){
orderIds.add(newList[i].Id);
}
}
RollUpOrderItems(orderIds);
}
public static void RollUpOrderItems(Set<Id> activatedOrderIds){
Map<Id, Product2> productMap = new Map<Id, Product2>();
for(OrderItem orderLine : [SELECT Id, Product2Id, Product2.Quantity_Ordered__c, Quantity, Order.ActivatedDate
FROM OrderItem WHERE OrderId IN : activatedOrderIds]){
if(!productMap.containsKey(orderLine.Product2Id))
productMap.put(orderLine.Product2Id, new Product2(Id =orderLine.Product2Id, Quantity_Ordered__c=0));
}
for(AggregateResult ag : [SELECT Sum(Quantity), Product2Id FROM OrderItem WHERE Product2Id IN : productMap.keySet() Group By Product2Id]){
Id product2Id = (Id)ag.get('Product2Id');
Product2 prod = productMap.get(product2Id);
prod.Quantity_Ordered__c = (Decimal)ag.get('expr0');
productMap.put(product2Id , prod);
}
try {
if(productMap.values() != null && productMap.values().size() > 0){
update productMap.values();
}
}catch ( Exception e ){
System.debug('#### Exception Executed : '+e.getStackTraceString());
}
}
}
OrderExtension
/**
* @name OrderExtension
* @description This class is provided for you to facilitate the Super Badge
**/
public class OrderExtension {
public Order orderRecord {get;set;}
public List<OrderItem> orderItemList {get;set;}
public String selectedFamily {get;set;}
public List<chartHelper.chartData> pieData {get;set;}
public Decimal total {get;set;}
public Map<Id,OrderItem> orderItemMap;
ApexPages.StandardSetController standardSetController;
public OrderExtension(ApexPages.StandardController standardController){
orderRecord = (Order)standardController.getRecord();
orderItemMap = new Map<id,OrderItem>();
if ( orderRecord.Id != null ){
orderRecord = queryOrderRecord(orderRecord.Id);
}
resetSsc();
total = 0;
for (OrderItem oi : orderRecord.OrderItems) {
orderItemMap.put(oi.Product2Id, oi);
if (oi.Quantity > 0) {
if (null == pieData) {
pieData = new List<ChartHelper.ChartData>();
}
pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
total += oi.UnitPrice * oi.Quantity;
}
}
PopulateOrderItems();
}
void resetSsc() {
String query = 'SELECT Name, Product2.Family, Product2.Name, Product2Id, UnitPrice, Product2.Quantity_Remaining__c'
+ ' FROM PricebookEntry WHERE IsActive = TRUE';
if (selectedFamily != null && selectedFamily != Constants.SELECT_ONE) {
query += ' AND Product2.Family = \'' + selectedFamily + '\'';
}
query += ' ORDER BY Name';
standardSetController = new ApexPages.StandardSetController(Database.getQueryLocator(query));
standardSetController.setPageSize(Constants.DEFAULT_ROWS);
}
//ToDo: Implement your own method to populate orderItemList
// that you will call after pagination and/or family selection
void PopulateOrderItems() {
orderItemList = new List<OrderItem>();
for (SObject obj : standardSetController.getRecords()) {
PricebookEntry pbe = (PricebookEntry)obj;
if (orderItemMap.containsKey(pbe.Product2Id)) {
orderItemList.add(orderItemMap.get(pbe.Product2Id));
} else {
orderItemList.add(new OrderItem(
PricebookEntryId=pbe.Id,
Product2Id=pbe.Product2Id,
UnitPrice=pbe.UnitPrice,
Quantity=0,
Product2=pbe.Product2
));
}
}
}
/**
* @name OnFieldChange
* @description
**/
public void OnFieldChange(){
//ToDo: Implement logic to store the values changed on the page
for (OrderItem oi : orderItemList) {
orderItemMap.put(oi.Product2Id, oi);
}
// and populate pieData
pieData = null;
total = 0;
for (OrderItem oi : orderItemMap.values()) {
if (oi.Quantity > 0) {
if (null == pieData) {
pieData = new List<chartHelper.ChartData>();
}
pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
// and populate total
total += oi.UnitPrice * oi.Quantity;
}
}
}
/**
* @name SelectFamily
* @description
**/
public void SelectFamily(){
//ToDo: Implement logic to filter based on the selected product family
resetSsc();
PopulateOrderItems();
}
/**
* @name Save
* @description
**/
public void Save(){
//ToDo: Implement logic to save the Order and populated OrderItems
System.Savepoint sp = Database.setSavepoint();
try {
if (null == orderRecord.Pricebook2Id) {
orderRecord.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
}
upsert orderRecord;
List<OrderItem> orderItemsToUpsert = new List<OrderItem>();
List<OrderItem> orderItemsToDelete = new List<OrderItem>();
for (OrderItem oi : orderItemList) {
if (oi.Quantity > 0) {
if (null == oi.OrderId) {
oi.OrderId = orderRecord.Id;
}
orderItemsToUpsert.add(oi);
} else if (oi.Id != null) {
orderItemsToDelete.add(oi);
}
}
upsert orderItemsToUpsert;
delete orderItemsToDelete;
} catch (Exception e) {
Database.rollback(sp);
apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,Constants.ERROR_MESSAGE));
}
}
/**
* @name First
* @description
**/
public void First(){
standardSetController.first();
PopulateOrderItems();
}
/**
* @name Next
* @description
**/
public void Next(){
standardSetController.next();
PopulateOrderItems();
}
/**
* @name Previous
* @description
**/
public void Previous(){
standardSetController.previous();
PopulateOrderItems();
}
/**
* @name Last
* @description
**/
public void Last(){
standardSetController.last();
PopulateOrderItems();
}
/**
* @name GetHasPrevious
* @description
**/
public Boolean GetHasPrevious(){
return standardSetController.getHasPrevious();
}
/**
* @name GetHasNext
* @description
**/
public Boolean GetHasNext(){
return standardSetController.getHasNext();
}
/**
* @name GetTotalPages
* @description
**/
public Integer GetTotalPages(){
return (Integer)Math.ceil(standardSetController.getResultSize() / (Decimal)Constants.DEFAULT_ROWS);
}
/**
* @name GetPageNumber
* @description
**/
public Integer GetPageNumber(){
return standardSetController.getPageNumber();
}
/**
* @name GetFamilyOptions
* @description
**/
public List<SelectOption> GetFamilyOptions() {
List<SelectOption> options = new List<SelectOption>{
new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE)
};
for (Schema.PicklistEntry ple : Constants.PRODUCT_FAMILY) {
options.add(new SelectOption(ple.getValue(), ple.getLabel()));
}
return options;
}
/**
* @name QueryOrderRecord
* @description
**/
public static Order QueryOrderRecord(Id orderId){
return [
SELECT Id, AccountId, EffectiveDate, Name, Status, Pricebook2Id,
(
SELECT Id, OrderId, Quantity, UnitPrice, PricebookEntryId, Product2Id,
Product2.Name, Product2.Family, Product2.Quantity_Remaining__c
FROM OrderItems
)
FROM Order
WHERE Id = :orderId
];
}
}
Happy Coding !!!