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

54 comments:

  1. Test run fails:
    System.AssertException: Assertion Failed: Expected : 0, Actual 5

    Stack Track:
    class.TestDataFactory.VerifyQuanityOrdered: Line 159, column 1
    Class.OrderTests.OrderUpdate_UnitTest: line 16, column 1

    ReplyDelete
    Replies
    1. Same here..anyone please help

      Delete
    2. same issue. Did anyone resolve this issue?

      Delete
    3. Use this

      @isTest
      private class OrderTests {

      @testSetup static void SetupTestData(){
      TestDataFactory.InsertTestData(1);
      }

      @isTest private static void OrderUpdate_UnitTest(){
      Test.startTest();
      Order o = [SELECT Id, Status FROM Order LIMIT 1];
      Product2 p = [SELECT Id, Family, Name, Quantity_Ordered__c, Quantity_Remaining__c FROM Product2 LIMIT 1];

      o.status = constants.ACTIVATED_ORDER_STATUS;
      Update o;
      Product2 updatedp = [SELECT Id, Family, Name, Quantity_Ordered__c, Quantity_Remaining__c FROM Product2 LIMIT 1];

      TestDataFactory.VerifyQuantityOrdered(p, updatedp, constants.DEFAULT_ROWS);
      Test.stopTest();
      }

      @isTest private static void OrderExtension_UnitTest(){
      PageReference pageRef = Page.OrderEdit;
      Test.setCurrentPage(pageRef);
      Order o = [SELECT Id, Status FROM Order LIMIT 1];
      ApexPages.StandardController stdcontroller = new ApexPages.StandardController(o);
      OrderExtension ext = new OrderExtension(stdcontroller);
      System.assertEquals(1, ext.orderItemList.size());
      ext.OnFieldChange();
      ext.SelectFamily();
      ext.Save();
      ext.First();
      ext.Next();
      ext.Previous();
      ext.Last();
      ext.GetHasPrevious();
      ext.GetHasNext();
      ext.GetTotalPages();
      ext.GetPageNumber();
      List options = ext.GetFamilyOptions();
      }
      }

      Delete
    4. still getting the same error

      Delete
  2. Also when submit challange I get this error :

    Challenge Not yet complete... here's what's wrong:
    Ensure that you test all the methods from orderExtension in your orderExtension_unitTest.

    ReplyDelete
    Replies
    1. I too get same error... what's the fix?

      Delete
    2. .cognizant?

      Delete
    3. It will work 100%
      @isTest
      private class OrderTests {

      @testSetup static void SetupTestData(){
      TestDataFactory.InsertTestData(1);
      }

      @isTest private static void OrderUpdate_UnitTest(){
      Test.startTest();
      Order o = [SELECT Id, Status FROM Order LIMIT 1];
      Product2 p = [SELECT Id, Family, Name, Quantity_Ordered__c, Quantity_Remaining__c FROM Product2 LIMIT 1];

      o.status = constants.ACTIVATED_ORDER_STATUS;
      Update o;
      Product2 updatedp = [SELECT Id, Family, Name, Quantity_Ordered__c, Quantity_Remaining__c FROM Product2 LIMIT 1];

      TestDataFactory.VerifyQuantityOrdered(p, updatedp, constants.DEFAULT_ROWS);
      Test.stopTest();
      }

      @isTest private static void OrderExtension_UnitTest(){
      PageReference pageRef = Page.OrderEdit;
      Test.setCurrentPage(pageRef);
      Order o = [SELECT Id, Status FROM Order LIMIT 1];
      ApexPages.StandardController stdcontroller = new ApexPages.StandardController(o);
      OrderExtension ext = new OrderExtension(stdcontroller);
      System.assertEquals(1, ext.orderItemList.size());
      ext.OnFieldChange();
      ext.SelectFamily();
      ext.Save();
      ext.First();
      ext.Next();
      ext.Previous();
      ext.Last();
      ext.GetHasPrevious();
      ext.GetHasNext();
      ext.GetTotalPages();
      ext.GetPageNumber();
      List options = ext.GetFamilyOptions();
      }
      }

      Delete
  3. For step 4 below error occurs -
    Error: Compile Error: Variable does not exist: INVENTORY_ANNOUNCEMENTS at line 12 column 39

    ReplyDelete
    Replies
    1. you gotta declare that variable manually in the 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 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 = '01s5e000003eJb8AAE';
      }

      Delete
    2. Hiii vivek if you had clear can you post your code cause my Announcement class is not covered

      Delete
  4. Stuck in 7th Challenge. Getting this error

    Challenge Not yet complete... here's what's wrong:
    Ensure that you implement all the pagination methods using the corresponding StandardSetController methods.

    ReplyDelete
  5. For the 7th challenge, there has to be limit.

    query += ' ORDER BY Name LIMIT 14';

    ReplyDelete
  6. Stuck in 1st challenge. Getting this error.

    Challenge Not yet complete... here's what's wrong:
    Ensure the STANDARD_PRICEBOOK_ID constant returns the expected value

    Please help

    ReplyDelete
    Replies
    1. Do this in query editor:- SELECT Id FROM PriceBook2 WHERE Name = 'Standard Price Book'

      And then copy ur STANDARD_PRICEBOOK_ID into your constants class .

      Delete
  7. 'Tier 2 DOD Restricted', 'Tier 1 PA Activation', 'Tier 1 Amber Activation', 'Tier 1 FTTB/N Business Activation', 'Tier 1 FTTB/N High Value Product', 'Tier 1 FTTB/N Enterprise Ethernet', 'Tier 1 FTTB/N Activation', 'Tier 1 FTTC Business Activation', 'Tier 1 FTTC High Value Product', 'Tier 1 FTTC Enterprise Ethernet', 'Tier 1 FTTC Activation', 'Tier 1 FTTP Business Activation', 'Tier 1 FTTP High Value Product', 'Tier 1 FTTP Enterprise Ethernet', 'Tier 1 FTTP Activation', 'Tier 2 HFC Tech Support', 'Tier 1 HFC Business Activation', 'Tier 1 HFC High Value Product', 'Tier 1 HFC Enterprise Ethernet', 'Tier 1 HFC Activation', 'Tier 2 Prescope Tech Support Hotline', 'Tier 1 ACCM', 'Tier 1 Fibre Connect', 'Tier 2 N_to_P', 'Tier 2 C_to_P'

    public class Constants {



    public static ID getStanderbookId() {
    Integer stdPriceBookRecId2;
    List stdPriceBookRecId = new List();
    stdPriceBookRecId = [SELECT Id, isstandard FROM Pricebook2 WHERE IsStandard=true];
    stdPriceBookRecId2 = stdPriceBookRecId[0];
    id testid= Test.isRunningTest() ? '01s5j000003ioIcAAI' :stdPriceBookRecId[0].id;

    return stdPriceBookRecId2; // '01s5j000003ioIcAAI';

    }

    public static final Integer DEFAULT_ROWS = 1;
    public static final String SELECT_ONE = Label.Select_One;
    public static final String INVENTORY_LEVEL_LOW = Label.Inventory_Level_Low;
    public static final List 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 = dummycoverage; // '01s5j000003ioIcAAI';// : getStanderbookId() ;
    public static final ID dummycoverage = getStanderbookId() ;
    }

    ReplyDelete
  8. //Below code is working fine

    public class Constants {



    public static ID getStanderbookId() {
    Integer stdPriceBookRecId2;
    List stdPriceBookRecId = new List();
    stdPriceBookRecId = [SELECT Id, isstandard FROM Pricebook2 WHERE IsStandard=true];
    stdPriceBookRecId2 = stdPriceBookRecId[0];
    id testid= Test.isRunningTest() ? '01s5j000003ioIcAAI' :stdPriceBookRecId[0].id;

    return stdPriceBookRecId2; // '01s5j000003ioIcAAI';

    }

    public static final Integer DEFAULT_ROWS = 1;
    public static final String SELECT_ONE = Label.Select_One;
    public static final String INVENTORY_LEVEL_LOW = Label.Inventory_Level_Low;
    public static final List 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 = dummycoverage; // '01s5j000003ioIcAAI';// : getStanderbookId() ;
    public static final ID dummycoverage = getStanderbookId() ;
    }

    ReplyDelete
  9. advanced apex specialist superbadge challenge 3
    I'm stuck on this challenge, returning the following error;

    Challenge Not yet complete... here's what's wrong:
    Ensure that the save method inserts only Products and Pricebooks for rows that have all fields populated.

    ReplyDelete
    Replies
    1. Stuck at the same step, any solution???

      Delete
  10. Stuck on the 7th challenge, recevied this error:
    Ensure that values are preserved during pagination.

    ReplyDelete
  11. Iam also facing same issue but still no solution

    ReplyDelete
  12. AnnouncementQueueable is not covered by your test methods

    ReplyDelete
  13. in Product2Test Unit Test class, here one method was missing so i added Product2Trigger_unitTest Method.
    @isTest
    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 createdProducts = [
    SELECT Id FROM Product2 where Name LIKE :'Test Product%'];

    System.assertEquals(5, createdProducts.size());
    }
    @isTest
    static void Product2Trigger_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 createdProducts = [
    SELECT Id FROM Product2 where Name LIKE :'Test Product%'];

    System.assertEquals(5, createdProducts.size());
    }
    }

    ReplyDelete
  14. Challenge Not yet complete... here's what's wrong:
    Ensure that orderTrigger and orderHelper are still working as specified in the earlier challenge.

    ReplyDelete
    Replies
    1. any idea on this error.getting at final challenge

      Delete
    2. dont forget to 1.create chatter group and 2. remove none value from family picklist value .3. ProductTests code should be like this @isTest (seeAllData=false)
      private class Product2Tests {

      /**
      * @name product2Extension_UnitTest
      * @description UnitTest for product2Extension
      **/
      @isTest
      private 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 createdProducts = [
      SELECT Id FROM Product2 where Name LIKE :'Test Product%'];

      System.assertEquals(5, createdProducts.size());
      }

      @isTest private static void Product2Trigger_UnitTest(){

      Test.startTest();
      Product2 p = new Product2();
      p.Name = 'TestProduct';
      p.Family = 'Side';
      p.IsActive = true;
      p.Quantity_Ordered__c = 50;
      p.Initial_Inventory__c = 100;
      insert p;

      CollaborationGroup c = new CollaborationGroup();
      c.Name = 'TEST' + Constants.INVENTORY_ANNOUNCEMENTS;
      c.Description = 'test';
      c.CollaborationType = 'Public';
      insert c;

      p.Quantity_Ordered__c=96;
      update p;
      Test.stopTest();
      }


      }

      Delete
  15. Ensure that values are preserved during pagination.

    ReplyDelete
    Replies
    1. Did you find the solution of this error?

      Delete
  16. Stuck on the 8th challenge, received this error:
    Ensure that values are preserved during pagination.

    ReplyDelete
    Replies
    1. hey, did you find any solution?
      please help

      Delete
    2. SELECT Name, Product2.Family, Product2.Name, Product2Id, UnitPrice, Product2.Quantity_Remaining__c FROM PricebookEntry WHERE IsActive = TRUE ORDER BY Name make sure this query as only 14 rows delete the remaining

      Delete
    3. Hi , Did you find the solution of this error?

      Delete
    4. This query is returning only 12 rows in my case but still getting this error, can someone please help

      Delete
    5. Did you find any Solutions?

      Delete
    6. HEELP, I'M STUCKED HERE

      Delete
  17. Ensure that you create the orderExtension_unitTest method error comming for the last challenge(Step8)

    ReplyDelete
  18. Same error please reply me with me the solution challenge 9.

    ReplyDelete
  19. Getting below error for problem - 8 :-
    Complete the controller extension for a Visualforce page to enable rapid order entry

    ReplyDelete
  20. Hi
    Receiving an error on step 7. Below is the error please help.

    Challenge Not yet complete... here's what's wrong:
    Please ensure that the Announcement has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant.

    ReplyDelete
  21. Challenge Not yet complete... here's what's wrong:
    Ensure that the Quantity Ordered field on the Product object is correctly calculated when an Order is Activated.
    Challenge #3, Error.

    ReplyDelete
  22. CompleteChallenge 3 then change other class

    ReplyDelete
  23. Hi! I have completed Challenges 1-3 for Advanced Apex Specialist. As per the Business requirements, it is mentioned that "New Millenium Delivery Products" will be created in the salesforce org but, I do not see any of those product records.

    I have created a new Trailhead playground at least 3 times (and also have used a new Salesforce Developer Edition org). In each case, I have then installed the unmanaged package (package ID: 04tf4000001O5si) as specified in the 'Prework & Notes.' In my attempts for Challenge 4 in the last month, I have not seen these test records created any of the times I have created a new org.

    In order to move forward, I created these Product records manually. However, I am getting an error on the Challenge which appears to be incorrect.

    Challenge Not yet complete... here's what's wrong:
    "Ensure that the getFamilyOptions method returns the correct picklist values."

    Here's what the markup is in the Visualforce page for the Product Family Select List values:

    <select name="j_id0:form:j_id33:orderItemTable:0:j_id41" size="1"> <option value="Select one">Select one</option>
    <option value="Entree">Entree</option>
    <option value="Side">Side</option>
    <option value="Dessert">Dessert</option>
    <option value="Beverage">Beverage</option>
    </select>

    The challenge error message is, as far as I can tell, inaccurate?

    Thank you in advance!

    ReplyDelete
  24. Hello Guys I am getting below error,
    Challenge Not yet complete... here's what's wrong:
    Ensure that after you clear test data, you run your tests once and the required test coverage is achieved.
    cleared all steps and getting error in last step and I run all test classes no failed methods.

    ReplyDelete
  25. Product2Helper has coverage only 83% this class covered from this method OrderUpdate_UnitTest (OrderTests.cls)
    Please help to increase to 90%
    Thanks in advance

    ReplyDelete
    Replies
    1. because of above issues super badge not completed

      Delete
  26. Had to change OrderTests class, OrderUpdate_UnitTest was failing no matter what. Corrected this and I was able to complete the superbadge

    @isTest
    public class OrderTests {
    @testSetup
    public static void SetupTestData(){
    TestDataFactory.InsertTestData(5);
    }
    static testmethod void OrderUpdate_UnitTest (){
    insert TestDataFactory.ConstructCollaborationGroup();

    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;
    test.startTest();
    Update rec;
    Test.stopTest();
    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);


    }


    @isTest private static void OrderExtension_UnitTest(){
    PageReference pageRef = Page.OrderEdit;
    Test.setCurrentPage(pageRef);
    Order o = [SELECT Id, Status FROM Order LIMIT 1];
    ApexPages.StandardController stdcontroller = new ApexPages.StandardController(o);
    OrderExtension ext = new OrderExtension(stdcontroller);
    System.assertEquals(5, ext.orderItemList.size());
    ext.OnFieldChange();
    ext.SelectFamily();
    ext.Save();
    ext.First();
    ext.Next();
    ext.Previous();
    ext.Last();
    ext.GetHasPrevious();
    ext.GetHasNext();
    ext.GetTotalPages();
    ext.GetPageNumber();
    List options = ext.GetFamilyOptions();
    }




    }

    ReplyDelete
  27. Anyone still having issues with this, I found that there are two pricebooks in the org, and that all the items in one pricebook needed to be set to isActive=false; also if there were more than 14 items , then some of the items in the active Pricebook needed to be de-activated, as well, that there would always be 3 pages for the total number of pages query. This superbadge is a pain!

    ReplyDelete
    Replies
    1. Ensure that values are preserved during pagination. I keep getting this error.

      These are the assertions:

      // Initialize the OrderExtension class with a standard controller for a new Order
      OrderExtension ext = new OrderExtension(new ApexPages.StandardController(new Order()));

      // Perform actions
      ext.OnFieldChange();
      ext.next();


      // Validate assertions
      system.assert(ext.orderItemList.size() > 0);

      // Assertions after the next() method
      system.assert(ext.orderItemList[0].Quantity != 1);
      system.assert(ext.orderItemList[0].UnitPrice != 1);
      system.assert(ext.orderItemList[1].Quantity != 2);
      system.assert(ext.orderItemList[1].UnitPrice != 2);
      ext.previous();
      // Assertions after the previous() method
      system.assert(ext.orderItemList[0].Quantity == 1);
      system.assert(ext.orderItemList[0].UnitPrice == 1);
      system.assert(ext.orderItemList[1].Quantity == 2);
      system.assert(ext.orderItemList[1].UnitPrice == 2);

      Delete
    2. Full list:

      Execute Anonymous: system.assert(ext.orderItemList.size() > 0);
      Execute Anonymous: ext.orderItemList[0].Quantity = 1;
      Execute Anonymous: ext.orderItemList[0].UnitPrice = 1;
      Execute Anonymous: ext.orderItemList[1].Quantity = 2;
      Execute Anonymous: ext.orderItemList[1].UnitPrice = 2;
      Execute Anonymous: ext.OnFieldChange();
      Execute Anonymous: ext.next();
      Execute Anonymous: system.assert(ext.orderItemList[0].Quantity != 1);
      Execute Anonymous: system.assert(ext.orderItemList[0].UnitPrice != 1);
      Execute Anonymous: system.assert(ext.orderItemList[1].Quantity != 2);
      Execute Anonymous: system.assert(ext.orderItemList[1].UnitPrice != 2);
      Execute Anonymous: ext.previous();
      Execute Anonymous: system.assert(ext.orderItemList[0].Quantity == 1);
      Execute Anonymous: system.assert(ext.orderItemList[0].UnitPrice == 1);
      Execute Anonymous: system.assert(ext.orderItemList[1].Quantity == 2);
      Execute Anonymous: system.assert(ext.orderItemList[1].UnitPrice == 2);

      Delete
  28. I am stuck at challenge of Unit tests
    Getting the following error as OrderTests(OrderUpdate_UnitTest) is failing:
    System.AssertException: Assertion Failed: Expected: 0, Actual: 5
    Class.TestDataFactory.VerifyQuantityOrdered: line 158, column 1
    Class.OrderTests.OrderUpdate_UnitTest: line 17, column 1

    ReplyDelete