Tuesday 30 January 2018

Advanced Apex Specialist Superbadge

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);

}

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);
    }

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 !!!