function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
bainesybainesy 

Advanced Apex Specialist Step 8

I've gone through every step successfully but am banging my head against the wall with step 8. I have more than adequate code coverage but continue to get this error message:
User-added image
I have gone back and rewritten OrderTests twice according to the requirements but can't get past this error. Anyone else had any luck with this?

Here's my code for reference:
@isTest (SeeAllData=false)
private class OrderTests {
    
    static void SetupTestData() {
	    TestDataFactory.InsertTestData(5);
    }
 
    @isTest static void OrderExtension_UnitTest() {
        PageReference pageRef = Page.OrderEdit;
        Test.setCurrentPage(pageRef);
        SetupTestData();
        ApexPages.StandardController stdcontroller = new ApexPages.StandardController(TestDataFactory.orders[0]);        
        OrderExtension ext = new OrderExtension(stdcontroller);        
       	System.assertEquals(Constants.DEFAULT_ROWS, 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<SelectOption> options = ext.GetFamilyOptions();
    }
    
@isTest
public static void OrderUpdate_UnitTest(){
    setupTestData();
    
   
    Test.startTest();
    
    List<Order> orders = TestDataFactory.orders;
    for (Order o : orders){
        o.Status = Constants.ACTIVATED_ORDER_STATUS;
    }
    List<Product2> oldProducts = TestDataFactory.products;
    Set<Id> productIds = new Set<Id>();
    for (Product2 oldProd : oldProducts){
        productIds.add(oldProd.Id);
    }
    oldProducts = [SELECT Id, Quantity_Ordered__c FROM Product2 WHERE ID IN :productIds];
    Map<Id, Integer> quantities = new Map<Id, Integer>();
    for (OrderItem oi : TestDataFactory.orderItems){
        Integer quantity = 0;
        List<PricebookEntry> pricebookentries = TestDataFactory.pbes;
        for (PricebookEntry pbe : pricebookentries){
            if (oi.PricebookEntryId == pbe.Id){                
                if (quantities.containsKey(pbe.Product2Id)){
                    quantity = quantities.get(pbe.Product2Id);
                }
                quantity += (Integer)oi.Quantity;
                quantities.put(pbe.Product2Id, quantity);
                break;
            }
        }
    }
   
    update orders;
    Map<Id, Product2> currentProducts = new Map<Id, Product2>([Select Id, Quantity_Ordered__c FROM Product2 WHERE Id IN :productIds]);
  
    for (Product2 prod : oldProducts){
      
        TestDataFactory.VerifyQuantityOrdered(prod, currentProducts.get(prod.Id), quantities.get(prod.Id));
  }
  Test.stopTest();
}
}

 
Best Answer chosen by bainesy
bainesybainesy
FYI Thanks to some help from the amazing Jeff Douglas, I was missing the @testSetup annotation on the SetupTestData method.

All Answers

Alain CabonAlain Cabon
Hi,

The problem should be a percent just below the minimum expected level for at least one trigger or class (including the Constants). 

Select all the class tests and run them (all the percents will be refreshed together).

Ensure you have 75% or higher test coverage on Product2Trigger and OrderTrigger triggers.
Ensure you have 75% or higher test coverage on Product2Extension and OrderExtensionclasses.
Ensure you have 90% or higher coverage on ConstantsChartHelperProduct2HelperOrderHelper, and TestDataFactory classes.
Nick Tang 1Nick Tang 1
Hi bainesy 
have you fix this issue ?
 
bainesybainesy
FYI Thanks to some help from the amazing Jeff Douglas, I was missing the @testSetup annotation on the SetupTestData method.
This was selected as the best answer
Shubham NandwanaShubham Nandwana
hi Bainesy,
I am still getting the error after using your code and adding @testSetup. If someone can please paste the correct code, it would be thankful.
Reply me if anyone wants me to paste my code here.
Regards,
Shubham Nandwana
Jim Rigney 16Jim Rigney 16
For me, the Product2Extension class was not adding a new Product2 in the Save() method.  I had some filter logic which was preventing it from saving thus the assertion (productCount+1) was failing.  Removed the filter logic and cleared the Challenge 8.
veeranjaneyulu kunchala 9veeranjaneyulu kunchala 9
hi, i am getting following error, can anybody help me . Its regarding Standard Set methods, even though i am using standard set methods.

User-added image


 public void Next(){
        this.standardSetController.next();
        PopulateOrderItems();
    }


Thanks,
Shubham NandwanaShubham Nandwana
hi veeranjaneyulu kunchala 9,
I was getting the same error although I used all the standardSetController methods. To get past this you can delete all the products added by you. Go to Home->products and delete all the products which you have added (through the testDataFactory class or by inserting manually). Hope this error will get resolved.

 
Shubham NandwanaShubham Nandwana
hi veeranjaneyulu kunchala 9,
Your code looks fine. What error are you getting?
veeranjaneyulu kunchala 9veeranjaneyulu kunchala 9
Hi Shubham Nandwana,  

I am getting "StandardSetController" Methods error.

User-added image

Thanks, 
Shubham NandwanaShubham Nandwana
hi veeranjaneyulu kunchala 9,
I'm afraid, this error should not be there. You can try deleting all the extra orders,pricebookEntry,products etc(all the SObjects which were created through the testDataFactory class or by inserting manually). This is how got past this particular error.
Thanks
Santosh Reddy MaddhuriSantosh Reddy Maddhuri
Jim Rigney 16 I am able to pass the test class execution for Product2Tests but unable to clear the challenge, as i am facing the same issue as you.Can you please guide me as to which filter logic you have altered o Product2Extension to pass the challenge.

Any help from anyone woould be apprieciated.
 
BTW am receiving the following error for step 8.

Challenge Not yet complete... here's what's wrong: 
Ensure that product2Controller is still working as specified in the earlier challenge.

Thanks!
andycbsandycbs

Anyone please help me with my issue? I have tried to finish step 8 but keep getting the following 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.



When I run the test, I found out that there are issues with SetupTestData method under Product2Test and ConstructCollaborationGroup under testDataFactory from OrderTests have returned with no results which gave errors: System.QueryException: List has no rows for assignment to SObject

These are my code: 

CLASS - OrderTests
@isTest 
private class OrderTests {

    @testSetup  
    public static void setupTestData(){
        
        TestDataFactory.InsertTestData(7);
    }
    
  public  static Map<String, List<Object>> testData;  
    

    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();
    }
    
     @isTest
    static  void OrderExtension_UnitTest(){
        
         Order rec = [select id, Status from Order limit 1];
        PageReference pageRef = Page.OrderEdit;
        Test.setCurrentPage(pageRef);
        pageRef.getParameters().put('id',rec.id);
        ApexPages.StandardController sc = new ApexPages.standardController(rec);
        
        OrderExtension cc = new OrderExtension(sc);
        cc.SelectFamily();
        cc.OnFieldChange();
        cc.Save();
        cc.First();
        cc.Next();
        cc.Previous();
        cc.Last();
        cc.GetHasPrevious();
        cc.GetHasNext();
        cc.GetTotalPages();
        cc.GetFamilyOptions();
        
        ChartHelper.GetInventory();
        
    }
    
    
}


CLASS-Product2Test

@isTest (seeAllData=false)
private class Product2Tests {
@testSetup
public static void SetupTestData(){  
    
    CollaborationGroup ChatterGroup = new CollaborationGroup(
        Name = 'TEST'+ constants.INVENTORY_ANNOUNCEMENTS,  
        CollaborationType = 'Public',
        CanHaveGuests = false,
        IsArchived = false,
        IsAutoArchiveDisabled = true
        );
    insert ChatterGroup;
     
}
    
@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
        ];
        System.assertEquals(5, createdProducts.size());
    }
    
   @isTest
    static void Product2Trigger_UnitTest(){
        TestDataFactory.InsertTestData(5); 
          test.startTest();
        
       Constants con = new Constants();
       //con.emptyMethod(); //dummy method for constants coverage
       //con.emptyMethod2();
       //con.emptyMethod3();

        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];
         
       rec.status = constants.ACTIVATED_ORDER_STATUS;      
       Update rec;
       Product2 updatedprod = [SELECT 
       Family,Id,Name,Quantity_Ordered__c,Quantity_Remaining__c FROM Product2 limit 
       1];
        
  TestDataFactory.VerifyQuantityOrdered(prod,updatedprod,constants.DEFAULT_ROWS);
       Test.stopTest();
    
    }
}
gauravbtgauravbt
Ditto for me
Santosh Reddy MaddhuriSantosh Reddy Maddhuri
Hi,
andycbs & gauravbt.

In your TesDataFactory code under ConstructPricebookEntries() method use Id pricebookId = constants.STANDARD_PRICEBOOK_ID; and same in the method ConstructOrders(); to declare PricebookId.

Hope this helps!

 
andycbsandycbs
Hi Santosh, 
Still no luck. I attached my TestDataFactory for your reference:

/**
 * @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.
        string abc = 'TEST'+ Constants.INVENTORY_ANNOUNCEMENTS;
        List<CollaborationGroup> CGlist = [select id, name from CollaborationGroup where name =:abc];
        system.debug('@@@CGlist'+CGlist);
        if(!CGList.ISEMPTY())
         //   Delete CGList;
        system.debug('@@@CGlistafter'+CGlist);    
        //integer cgi = CGList.size();
        if(CGList.ISEMPTY()){
        CollaborationGroup myGroup = new CollaborationGroup();
        myGroup.Name='TEST'+ Constants.INVENTORY_ANNOUNCEMENTS;
        myGroup.CollaborationType='Public'; //can be 'Public' or 'Private'                   
        return myGroup;
        }else{
        return CGList[0];
        }
    }

    /**
     * @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>();
        Integer s=0;
        for(Integer n=0; n<cnt; n++)
        {
            if(s==Constants.PRODUCT_FAMILY.size())
                s=0;
            
            Product2 p=new Product2();
            if(n==0){
                p.Name='Side';
            }
            else if(n==1){
                p.Name='Entree';
            }
            else if(n==2){
                p.Name='Dessert';
            }
            else if(n==3){
                p.Name='Beverage';
            }
            else if(n==4){
                p.Name='Test';
            }
            else{
                p.name = 'wasblank';
            }
            
            p.Family=Constants.PRODUCT_FAMILY[s].getLabel();
            p.Initial_Inventory__c=10;
            p.IsActive=true;
            //p.Quantity_Ordered__c=Constants.DEFAULT_ROWS;
            products.add(p);
            System.assertEquals(p.Initial_Inventory__c, 10);
            s++;
            
        }
        
        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> listPBE=new List<PriceBookEntry>();
        for(Product2 p: prods)
        {
            PriceBookEntry pbe=new PriceBookEntry();
            pbe.isActive=true;
            pbe.Pricebook2Id=Constants.STANDARD_PRICEBOOK_ID; 
            pbe.Product2Id=p.Id;
            pbe.UnitPrice=10;
            listPBE.add(pbe);
        }
        return listPBE;
    }

    /**
     * @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> listAcc=new List<Account>();
        for(Integer n=0;n<cnt;n++)
        {
            Account a=new Account();
            a.Name='TEST1_'+n;
            listAcc.add(a);
        }
        
        return listAcc;
    }

    /**
     * @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> listCC=new List<Contact>();
     
        for(Integer n=0;n<cnt;n++)
        {
            Contact c=new Contact();
            c.LastName='LN1_'+n;
            c.AccountId=accts[n].Id;
            listCC.add(c);
            
        }
        
        return listCC;
    }

    /**
     * @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> listOrd=new List<Order>();
       
        
        for(Integer n=0;n<cnt;n++)
        {
            Order o=new Order();
            o.EffectiveDate=System.today();
            o.AccountId=accts[n].Id;
            o.Status='Draft';
            //o.Pricebook2Id= Constants.getStdPricebookId();
            o.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
            listOrd.add(o);
           
        }
        
        return listOrd;

        
    }

    /**
     * @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> listOi=new List<OrderItem>();
      
        for(Integer n=0; n<cnt;n++)
        {
            OrderItem oi=new OrderItem();
            oi.OrderId=ords[n].Id;
            oi.PricebookEntryId=pbes[n].id;
            oi.UnitPrice=pbes[n].UnitPrice;
            oi.Quantity=Constants.DEFAULT_ROWS;
           
            
            listOi.add(oi);
        }
        
        return listOi;
    }
    
    public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered)
    {
     
        //System.assertNotEquals(updatedProduct.Quantity_Ordered__c, originalProduct.Quantity_Ordered__c +qtyOrdered);
        //updatedProduct.Quantity_Ordered__c=originalProduct.Quantity_Ordered__c + qtyOrdered;
        Integer sumQ=Integer.valueOf(originalProduct.Quantity_Ordered__c) + qtyOrdered;
        //System.assertEquals(updatedProduct.Quantity_Ordered__c, sumQ);
     
        
    }


    /**
     * @name SetupTestData
     * @description Inserts accounts, contacts, Products, PricebookEntries, Orders, and OrderItems.
    **/
    public static  Map<String, List<Object>> InsertTestData(Integer cnt){
        //ToDo: Ensure this method calls each of the construct methods
        //  and inserts the results for use as test data.
    
       CollaborationGroup colG=ConstructCollaborationGroup();
        upsert colG;
        
       List<Account> a=ConstructAccounts(cnt);
        insert a;
        
       List<Contact> c=ConstructContacts(cnt, a);
        insert c;
        
       List<Product2> p= ConstructProducts(cnt);
        insert p;
        
        List<PriceBookEntry> pbe=ConstructPricebookEntries(p);
        insert pbe;
       
        List<Order> o=ConstructOrders(cnt, a);
        insert o;
       
       
       List<OrderItem> oi=ConstructOrderItems(cnt, pbe, o);
        insert oi;
        
        Map<String, List<Object>> returnMap = new Map<String, List<Object>>();
        returnMap.put('accounts', a);
        returnMap.put('contacts', c);
        returnMap.put('products', p);
        returnMap.put('pricebookentries', pbe);
        returnMap.put('orders', o);
        returnMap.put('orderitems', oi);
        
        return returnMap;
    }

}
Santosh Reddy MaddhuriSantosh Reddy Maddhuri
Hi andycbs,

I see few difference in your TestDataFactory for 4 methods.

1.There shouldn't be any return for InsertTestData.Only Insert suffices.
2. VerifyQuantityOrdered method should be of system.assertions and not integer.
3.ConstructOrderItems method , unit price = 10;
4.ConstructCollaborationGroup need to create a ne collabration group , return it in method and insert in InserTestData method.

Please use the below code for reference.Hope this helps.
/**
 * @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',//CanHaveGuests = true,
                                                                   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> prodsToInst = new List<product2>(); 
        Schema.DescribeFieldResult fieldResult =Product2.Family.getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();

        for(integer i=0;i< cnt;i++)
        {
                product2 p = new product2();
                 p.Name = 'Product Curry-'+ i ;
                 p.IsActive = true;
                 p.Initial_Inventory__c =10;
                 if(i>=4)
                 p.Family = constants.PRODUCT_FAMILY[0].getValue();
                 else if(i<4)
                 p.Family = constants.PRODUCT_FAMILY[i].getValue();
                
                prodsToInst.add(p);
                
        }
        
        
        return prodsToInst;  
    }

    /**
     * @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
           Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();
          List<pricebookEntry> PBEntryToInst = new List<pricebookEntry>(); 
          
        for( integer i=0 ;i < prods.size();i++){
          pricebookEntry pbe = new pricebookEntry ( Product2Id = prods[i].Id , PriceBook2Id = pricebookId,
                                                    IsActive = true , UnitPrice = 10
                                                   );
          PBEntryToInst.add(pbe);
        }
         
          
          return PBEntryToInst;                                         

    }

    /**
     * @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> AccListToInst = new List<Account>();
        
        
        for(integer i=0;i< cnt;i++) {
        
          Account acc = new Account ( Name = 'TestAcco' + i);
          AccListToInst.add(acc);
        }
        
        
        return AccListToInst;
        
    }

    /**
     * @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> ConListToInst = new List<Contact>();
        
        
        for(integer i=0;i< cnt;i++) {
             Contact con = new Contact ( LastName = 'TestCont' + i , AccountId = accts[i].Id);
             ConListToInst.add(con);
        }
        
        
        return ConListToInst;
        
    }

    /**
     * @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> OrdListToInst = new List<Order>();
        //Id PricebookId = [SELECT Id From Pricebook2 WHERE IsStandard = true].Id
        Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();

        for(integer i=0;i< cnt;i++) {
             Order o = new Order ( EffectiveDate = Date.Today() , AccountId = accts[i].Id, Status = 'Draft',Pricebook2Id = pricebookId);
             OrdListToInst.add(o);
        }
        
        
        return OrdListToInst;
        
    }

    /**
     * @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> OrderItemListToInst = new List<OrderItem>();
        
       for(integer i=0;i< cnt;i++) {
            OrderItem oi = new OrderItem (Quantity = Constants.DEFAULT_ROWS, UnitPrice = 10,
                                          orderId = ords[i].Id, pricebookentryId = pbes[i].Id);
           OrderItemListToInst.add(oi);                               
        }  
          
        return OrderItemListToInst;
    }

    /**
     * @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.
        
        CollaborationGroup cg = ConstructCollaborationGroup();
        insert cg;
        List<Account> accountList = ConstructAccounts(cnt);
        insert accountList;
        List<Contact> contactList = ConstructContacts(cnt, accountList);
        insert contactList ;
        List<Product2> prodList = ConstructProducts(cnt);
        insert prodList ;
        List<PriceBookEntry> pbeEntry = ConstructPricebookEntries(prodList);
        insert pbeEntry ;
        List<Order> orderList = ConstructOrders(cnt, accountList);
        insert orderList ;
        List<OrderItem> itemList = ConstructOrderItems(cnt, pbeEntry , orderList);
        insert itemList ;

    }
    
     /**
     * @name VerifyQuantityOrdered
     * @description
    **/
    
       public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered){
       
         System.assertEquals(originalProduct.Quantity_Ordered__c + qtyOrdered , updatedProduct.Quantity_Ordered__c,'QuantityOrdered mismatch after update' );
       
       }

}


 
andycbsandycbs
Hi Santosh, 
Thanks for coming back to me. I still have the same issues shown as below: 
User-added image
I wonder if there is an issue with Constants class which returns no value. 

CLASS-CONSTANTS
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;
    
       static {
        Schema.DescribeFieldResult fieldResult = Product2.Family.getDescribe();
        PRODUCT_FAMILY = fieldResult.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 = [SELECT Id From Pricebook2 WHERE IsStandard = true].Id;
 }       
    
Much appreciate your feedback. 


 
Santosh Reddy MaddhuriSantosh Reddy Maddhuri
Hi andycbs,

go to --> Price book Tab --> Click on All pricebook list view and --> select Standard Price book record -->copy id of it and hardcode the id value in Constants class.
Replace From :
 public static final Id STANDARD_PRICEBOOK_ID = [SELECT Id From Pricebook2 WHERE IsStandard = true].Id;

Replace To :

 public static final Id STANDARD_PRICEBOOK_ID = '<Id of Standard Price record from pricebook tab>';
andycbsandycbs
Hi Santosh, 

Great. It solved the issue with Constants class, however, there seems to be an issue with TestDataFactory's InsertTestData class. 
User-added image


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',//CanHaveGuests = true,
                                                                   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> prodsToInst = new List<product2>(); 
        Schema.DescribeFieldResult fieldResult =Product2.Family.getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();

        for(integer i=0;i< cnt;i++)
        {
                product2 p = new product2();
                 p.Name = 'Product Curry-'+ i ;
                 p.IsActive = true;
                 p.Initial_Inventory__c =10;
                 if(i>=4)
                 p.Family = constants.PRODUCT_FAMILY[0].getValue();
                 else if(i<4)
                 p.Family = constants.PRODUCT_FAMILY[i].getValue();
                
                prodsToInst.add(p);
                
        }
        
        
        return prodsToInst;  
    }

    /**
     * @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
           Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();
          List<pricebookEntry> PBEntryToInst = new List<pricebookEntry>(); 
          
        for( integer i=0 ;i < prods.size();i++){
          pricebookEntry pbe = new pricebookEntry ( Product2Id = prods[i].Id , PriceBook2Id = pricebookId,
                                                    IsActive = true , UnitPrice = 10
                                                   );
          PBEntryToInst.add(pbe);
        }
         
          
          return PBEntryToInst;                                         

    }

    /**
     * @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> AccListToInst = new List<Account>();
        
        
        for(integer i=0;i< cnt;i++) {
        
          Account acc = new Account ( Name = 'TestAcco' + i);
          AccListToInst.add(acc);
        }
        
        
        return AccListToInst;
        
    }

    /**
     * @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> ConListToInst = new List<Contact>();
        
        
        for(integer i=0;i< cnt;i++) {
             Contact con = new Contact ( LastName = 'TestCont' + i , AccountId = accts[i].Id);
             ConListToInst.add(con);
        }
        
        
        return ConListToInst;
        
    }

    /**
     * @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> OrdListToInst = new List<Order>();
        //Id PricebookId = [SELECT Id From Pricebook2 WHERE IsStandard = true].Id
        Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();

        for(integer i=0;i< cnt;i++) {
             Order o = new Order ( EffectiveDate = Date.Today() , AccountId = accts[i].Id, Status = 'Draft',Pricebook2Id = pricebookId);
             OrdListToInst.add(o);
        }
        
        
        return OrdListToInst;
        
    }

    /**
     * @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> OrderItemListToInst = new List<OrderItem>();
        
       for(integer i=0;i< cnt;i++) {
            OrderItem oi = new OrderItem (Quantity = Constants.DEFAULT_ROWS, UnitPrice = 10,
                                          orderId = ords[i].Id, pricebookentryId = pbes[i].Id);
           OrderItemListToInst.add(oi);                               
        }  
          
        return OrderItemListToInst;
    }

 /**
     * @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.
        
        CollaborationGroup cg = ConstructCollaborationGroup();
        insert cg;
        List<Account> accountList = ConstructAccounts(cnt);
        insert accountList;
        List<Contact> contactList = ConstructContacts(cnt, accountList);
        insert contactList ;
        List<Product2> prodList = ConstructProducts(cnt);
        insert prodList ;
        List<PriceBookEntry> pbeEntry = ConstructPricebookEntries(prodList);
        insert pbeEntry ;
        List<Order> orderList = ConstructOrders(cnt, accountList);
        insert orderList ;
        List<OrderItem> itemList = ConstructOrderItems(cnt, pbeEntry , orderList);
        insert itemList ;

    }
    
     /**
     * @name VerifyQuantityOrdered
     * @description
    **/
    
       public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered){
       
         System.assertEquals(originalProduct.Quantity_Ordered__c + qtyOrdered , updatedProduct.Quantity_Ordered__c,'QuantityOrdered mismatch after update' );
       
       }

}

 
Shubham NandwanaShubham Nandwana
Hello,

I have completed challenge 8. I am pasting my code for classes orderTests, product2Tests,OrderHelper, Product2Extension.
Hope that helps. Please give an upvote if you are able to move forward with the challenge.
Regards,

Shubham Nandwana.
AppPerfect Corp.
salesforce@appperfect.com
408-252-4100
http://www.appperfect.com/services/salesforce/
Salesforce Development & Operations Experts

Product2Tests
@isTest (seeAllData=false)
private class Product2Tests {

    /**
     * @name product2Extension_UnitTest
     * @description UnitTest for product2Extension
    **/
  @isTest 
    static void Product2Extension_UnitTest(){
        Test.startTest();
        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;
        }
        
        
      
        System.debug('productTests 41'+[SELECT Id FROM CollaborationGroup WHERE Name = 'Inventory Announcements'
    ]);
        ext.save();
        
        
        ext.GetFamilyOptions();
        ext.GetInventory();
        Test.stopTest();
        List<Product2> createdProducts = [
            SELECT
                Id
            FROM
                   Product2
        ];
        System.assertEquals(5, createdProducts.size());
    }
    
    static TestMethod 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 Inventory Announcements';
        c.Description='test';
       // c.OwnerId=[Select Id from Account Limit 1].Id;
        c.CollaborationType='public';
        insert c;
        
        p.Quantity_Ordered__c=96;
        update p;
            
        Test.stopTest();
    }
   

}

OrderTests
@isTest (SeeAllData=false)
private class OrderTests {
    
    @testSetup
    static void SetupTestData() {
        TestDataFactory.InsertTestData(5);
    }
 
    @isTest static void OrderExtension_UnitTest() {
        Test.startTest();
        PageReference pageRef = Page.OrderEdit;
        Test.setCurrentPage(pageRef);
        SetupTestData();
        ApexPages.StandardController stdcontroller = new ApexPages.StandardController(TestDataFactory.orders[0]);        
        OrderExtension ext = new OrderExtension(stdcontroller);        
           System.assertEquals(Constants.DEFAULT_ROWS, 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<SelectOption> options = ext.GetFamilyOptions();
        
        Test.stopTest();
    }
    
@isTest
public static void OrderUpdate_UnitTest(){
     
   
    Test.startTest();
    SetupTestData();
    List<Order> orders = TestDataFactory.orders;
    for (Order o : orders){
        o.Status = Constants.ACTIVATED_ORDER_STATUS;
    }
    List<Product2> oldProducts = TestDataFactory.pros;
    Set<Id> productIds = new Set<Id>();
    for (Product2 oldProd : oldProducts){
        productIds.add(oldProd.Id);
    }
    oldProducts = [SELECT Id, Quantity_Ordered__c FROM Product2 WHERE ID IN :productIds];
    Map<Id, Integer> quantities = new Map<Id, Integer>();
    for (OrderItem oi : TestDataFactory.orderItems){
        Integer quantity = 0;
        List<PricebookEntry> pricebookentries = TestDataFactory.enteries;
        for (PricebookEntry pbe : pricebookentries){
            if (oi.PricebookEntryId == pbe.Id){                
                if (quantities.containsKey(pbe.Product2Id)){
                    quantity = quantities.get(pbe.Product2Id);
                }
                quantity += (Integer)oi.Quantity;
                quantities.put(pbe.Product2Id, quantity);
                break;
            }
        }
    }
   
    CollaborationGroup c=new CollaborationGroup();
        c.Name='Test Inventory Announcements';
        c.Description='test';
        //c.OwnerId=[Select Id from Account Limit 1].Id;
        c.CollaborationType='public';
        insert c;
    
    update orders;
    Map<Id, Product2> currentProducts = new Map<Id, Product2>([Select Id, Quantity_Ordered__c FROM Product2 WHERE Id IN :productIds]);
  
    for (Product2 prod : oldProducts){
      
        TestDataFactory.VerifyQuantityOrdered(prod, currentProducts.get(prod.Id), quantities.get(prod.Id));
  }
  Test.stopTest();
}
}

OrderHelper
public without sharing class OrderHelper {

    /**
     * @name AfterUpdate
     * @description 
     * @param List<Order> newList
     * @param List<Order> oldList
     * @return void
    **/
    public static List<Double> check =new List<Double>();
    public Static List<Product2> pr;
    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);
    }

    /**
     * @name RollUpOrderItems
     * @description Given a set of Activated Order ids, query the child Order Items and related Products to calculate Inventory levels
     * @param Set<Id> activatedOrderIds
     * @return void
    **/
    public static void RollUpOrderItems(Set<Id> activatedOrderIds){
        
        //ToDo: Declare a Map named "productMap" of Ids to Product2 records
        Map<ID,Product2> productMap =new Map<ID,Product2>();
        List<OrderItem> orderId =[Select OrderID,Product2Id from OrderItem where OrderId IN: activatedOrderIds];
        
        //ToDo: Loop through a query of OrderItems related to the activatedOrderIds
        for(OrderItem o: orderId){
            //ToDo: Populate the map with the Id of the related Product2 as the key and Product2 record as the value
            Product2 p= [select name,Quantity_Ordered__c from Product2 where Id=: o.Product2Id];
            productmap.put(o.Product2Id,p );
            
        }
        //ToDo: Loop through a query that aggregates the OrderItems related to the Products in the ProductMap keyset
         pr = new List<Product2>();
        
       
        
        AggregateResult[] groupedResults =[select Product2Id ,SUM(Quantity) from OrderItem where Product2Id IN : productMap.keySet() group by Product2Id];
    
            for(AggregateResult ag: groupedResults){
                
               Product2 p= productmap.get((Id)ag.get('Product2Id'));
               p.Quantity_Ordered__c =(Double)ag.get('expr0');
               pr.add(p);
               check.add((Double)ag.get('expr0'));
               
               
            }
        
            update pr;
        
                 

        //ToDo: Perform an update on the records in the productMap
    }

}
Product2Extension
public class Product2Extension {
    //public List<Product2Extension.productWrapper> productsToInsert {get;set;}
    //public Product2Extension(ApexPages.StandardController controller){
        //productsToInsert = new List<Product2Extension.productWrapper>();          
        //AddRows();    }
    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 Product2Extension.productWrapper() );
        }
    }
    public List<ChartHelper.ChartData> GetInventory(){
        return ChartHelper.GetInventory();
    }
    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 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);
        }
    }
}
 
Yashita Goyal 17Yashita Goyal 17
Facing issue on Step 8.
Can someone please share TestDataFactory and Order Test class code.
janardhanareddy gowkanpallijanardhanareddy gowkanpalli
AM Getting below error can anyone help badge 8 

Challenge Not yet complete... here's what's wrong: 
Ensure that orderTrigger and orderHelper are still working as specified in the earlier challenge.
Shubham NandwanaShubham Nandwana
Hello Yashita,
Here is the testDataFactory class. Ordertests I have already posted above. I have completed the challenge.
Please give an upvote if my answer helps.
Shubham Nandwana
AppPerfect Corp.
salesforce@appperfect.com
408-252-4100
http://www.appperfect.com/services/salesforce/
Salesforce Development & Operations Experts

TestDataFactory
/**
 * @name TestDataFactory
 * @description Contains methods to construct and/or validate commonly used records
**/
public with sharing class TestDataFactory {

    /**
     * @name ConstructCollaborationGroup
     * @description
    **/
    public static List<Product2> pros;
    public static List<PricebookEntry> enteries;
    public static List<Account> acts;
    public static  List<Contact> contacts;
    public static  List<Order> orders;
    public static List<OrderItem> orderItems;
    static CollaborationGroup nameGroup=new CollaborationGroup ();
    public static CollaborationGroup ConstructCollaborationGroup(){
        //String nameGroup=TEST+Constants.INVENTORY_ANNOUNCEMENTS;
         
        //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.
        nameGroup.CollaborationType='Public';
        nameGroup.Name='TEST'+Constants.INVENTORY_ANNOUNCEMENTS;
        return nameGroup;
    }

    /**
     * @name CreateProducts
     * @description Constructs a list of Product2 records for unit tests
    **/
    public static List<Product2> ConstructProducts(Integer cnt){
        List<Product2> pros=new List<Product2>();
               
        Integer picklistSize=Constants.PRODUCT_FAMILY.size();
        System.debug(picklistSize+''+Constants.PRODUCT_FAMILY[0].getValue());
        Integer j=0;
        for(Integer i=0;i<cnt;i++){
            Product2 p=new Product2();
            p.Name='ProductConstruction'+i;
            p.IsActive=true;
            p.Initial_Inventory__c =10;
            p.Family=Constants.PRODUCT_FAMILY[j].getValue();
            if(j==picklistSize-1){
                j=0;
            }else{
            j++;
            }
            pros.add(p);
        }
        System.debug('before insert '+pros);
       // insert pros;
        System.debug('after insert '+pros);
        return pros;
        //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.
    }


    /**
     * @name CreatePricebookEntries
     * @description Constructs a list of PricebookEntry records for unit tests
    **/
    public static List<PricebookEntry> ConstructPricebookEntries(List<Product2> prods){
        List<PriceBookEntry> priceBooks= new List<PriceBookEntry>();
        
        for(product2 p:prods){
            PricebookEntry pbe=new PricebookEntry();
            pbe.UnitPrice=(Decimal)100;
            pbe.IsActive=true;
            pbe.Product2Id=p.Id;
            pbe.Pricebook2Id=Constants.STANDARD_PRICEBOOK_ID;
            
            priceBooks.add(pbe);
        }
            
        if(priceBooks!=null && !priceBooks.isEmpty()) {
              //insert priceBooks;
        }
        return priceBooks;

        //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
    }

    /**
     * @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> acts=new List<Account>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            Account a=new Account();
            a.Name='Account'+i;
            a.Rating='Hot';
            i++;
            acts.add(a);
        }
        //insert acts;
        return acts;
    }

    /**
     * @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> contacts=new List<Contact>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            Contact c=new Contact();
            c.AccountId=accts.get(i).Id;
            c.LastName='Contact'+i;
            i++;
            contacts.add(c);
        }
        //insert contacts;
        return contacts;
    }

    /**
     * @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>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
          Contract c=new Contract(AccountId=accts.get(i).Id,Status='Draft',StartDate =date.today(),ContractTerm =12);
          Order o=new Order();
          o.AccountId=accts.get(i).Id;
          o.EffectiveDate=date.today();
          o.Pricebook2Id=Constants.STANDARD_PRICEBOOK_ID;
          o.ContractId=c.Id ;
          o.Status='Draft';
          
          i++;
            orders.add(o);
        }
        //insert orders;
        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> items=new List<OrderItem>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            OrderItem oi=new OrderItem();
            oi.Quantity=Constants.DEFAULT_ROWS;
            oi.PricebookEntryId=pbes.get(i).Id;
            System.debug('pricebook'+oi.PricebookEntryId+' '+pbes.get(i).Id);
            oi.OrderId=ords.get(i).Id;
            oi.UnitPrice=(Decimal)100;
            i++;
            items.add(oi);
        }
        //insert items;
        return items;
    }

    /**
     * @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.
        //CollaborationGroup cg=ConstructCollaborationGroup();
       // List<CollaborationGroup> cgroup=[Select Name from CollaborationGroup where Name=: 'Inventory Announcements'];
        //if(cgroup.size()==0){
        //    insert cg;
       // }
        
        pros=ConstructProducts(cnt);
           insert pros;
        enteries=ConstructPricebookEntries(pros);
        insert enteries;
        acts=ConstructAccounts(cnt);
        insert acts;
       contacts=ConstructContacts(cnt,acts);
        insert contacts;
       orders=ConstructOrders(cnt,acts);
            insert orders;
        System.debug('TestFactory'+orders);
        orderItems=ConstructOrderItems(cnt,enteries,orders);      
       insert orderItems;
        
       
    }
    public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered) {
     System.assertEquals(updatedProduct.Quantity_Ordered__c, (originalProduct.Quantity_Ordered__c + qtyOrdered));
}
    
}
Yashita Goyal 17Yashita Goyal 17
Am still facing code coverage issue for below classes:

AnnouncementQueueable class is just 41%
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements Queueable{
    
    public void execute(QueueableContext context){
        PostAnnouncements(toPost);
    }
    public List<ConnectApi.AnnouncementInput> toPost;
    //ToDo: Modify this class to implement the Queueable interface and call the postAnnouncements method
    /**
* @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 {
                break;
            }
        }
        if ( announcements.size() > 0 && !test.isRunningTest() ){
            AnnouncementQueueable q = new AnnouncementQueueable();
            q.toPost = announcements;
            System.enqueueJob(q);
            
            //ToDo: Enqueue the above instance of announcementQueueable
        }
    }
}

Product2Helper class is 60%
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 = :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> oldList, List<Product2> newList){
        //ToDo: Declare a List of Product2 records named needsAnnouncement
        List<Product2> needsAnnouncement = new List<Product2>();
        
        //ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
        Map<String, Decimal> invSettingsMap = new Map<String, Decimal>();
        
        //ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
        List<Inventory_Setting__mdt> invSettings = [SELECT Id, DeveloperName, Low_Quantity_Alert__c FROM Inventory_Setting__mdt];
        for (Inventory_Setting__mdt sett : invSettings) {
            invSettingsMap.put(sett.DeveloperName, sett.Low_Quantity_Alert__c);
        }
        //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
        for (Product2 prod : newList) {
            if (invSettingsMap.containsKey(prod.Name) && prod.Quantity_Remaining__c < invSettingsMap.get(prod.Name)) {
                needsAnnouncement.add(prod);
            }
        }
        //ToDo: Pass records to the postAlerts method
        PostAlerts(needsAnnouncement);
    }
    
    /**
* @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 ){
            // 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
            ConnectApi.MessageBodyInput mbi = new ConnectApi.MessageBodyInput();
            ConnectApi.TextSegmentInput textSegmentInput = new ConnectApi.TextSegmentInput();
            mbi.messageSegments = new List<ConnectApi.MessageSegmentInput>();
            textSegmentInput.text = p.Name + Constants.INVENTORY_LEVEL_LOW;
            mbi.messageSegments.add(textSegmentInput);
            
            ConnectApi.AnnouncementInput ai = new ConnectApi.AnnouncementInput();
            ai.expirationDate = Date.today().addDays(1);
            ai.sendEmails = true;
            ai.parentId = COLLABORATION_GROUP[0].Id;
            ai.body = mbi;
            
            toPost.add(ai);
        }
        // ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
        AnnouncementQueueable q = new AnnouncementQueueable();
        q.toPost = toPost;
        System.enqueueJob(q);
    }
}

Can you please tell the issue.

Thanks
Yashita​
janardhanareddy gowkanpallijanardhanareddy gowkanpalli
Hi All
Could please help anyone am getting below error for badge 8 and i covered test coverage 79  still am getting below error.


Challenge Not yet complete... here's what's wrong: 
Ensure that you haven't deleted the product2Trigger_UnitTest in orderTests.
8
Create unit tests
Ensure test coverage is sufficient for deployment and run all tests.

 
Yashita Goyal 17Yashita Goyal 17
I was able to resolve all issues and achieve the superbadge. Here is the updated code:

https://developer.salesforce.com/forums/ForumsMain?id=9060G0000005QQaQAM

Thanks
Yashita
Karthik KKarthik K
Hello All,

Have anyone received the below error message? I'm receiving it in the last step (Step 8). Made sure there are already 12+ products and all test classes are having above 90%. OrderExtenstion works as expected. Unfortunately, i tried to delete the standard data from the org and recreated the test data and started getting the below message. Tried restoring the recycle bin and no luck. Is there any way redo the exercise again from the step 1. Currently, step 1 to step 7 are already completed and not letting me redo the steps again. Any suggestions are appreciated. 

"Ensure that you have at least 12 products created and that OrderExtension is still working as specified in the earlier challenge."
Paweł WoźniakPaweł Woźniak
Jut rerun all tests.
Cristina CamachoCristina Camacho
Hi Karthik,
did you solve the problem? I am also stuck...
Poonam Agarwal 7Poonam Agarwal 7
Hi, I am facing issue with test coverage of Constants class....it shows 62%......It should automatically be covered by testing other classes except for  this line of code because it  cannot be executed in testing context--->
 else {
            if (stdPriceBook == null) 
                stdPriceBook    = [select id, name from Pricebook2 where isStandard = true limit 1];
               STANDARD_PRICEBOOK_ID = (stdPriceBook!=null)?stdPriceBook.id:'';
        }
Below is the coverage shown...it is not showing blue for other lines-----Any help would be appreciated

User-added image
Harshal Gosavi 37Harshal Gosavi 37
Hiii All,

In last challege i am facing following issue, I don't understand why that error is occur. if any one has solution for this error then plzz inform me. 

User-added image
 
kai hou 1kai hou 1
"Ensure that you have at least 12 products created and that OrderExtension is still working as specified in the earlier challenge."

1. delete all the records and make them exactly equal to 12.
such as, Developer console --> COMMAND + E, type :   TestDataFactory.InsertTestData(12); excute. will create 12 new records.

2. my guess, check if you are running in the same playground. for example,  select the playground you are currently using. it's near the 'Launch' batton and  submit the code.

 
Vivian Charlie 1208Vivian Charlie 1208
Hi Team,

Few points I noted while trying to successfully complete Challenge 8 for Advanced Apex Specialist.

1. In Product2Helper when trying to check the condition for quantity falling below the threshold we need the condition to be less than or equal to and NOT just less than
updatedProduct.Quantity_Remaining__c <= setting.Low_Quantity_Alert__c

2. In Product2Extension when checking if all fields have been filled for the product to be inserted we need to check for
wrapper.pricebookEntryRecord.isActive and NOT wrapper.productRecord.isActive

Note : Setup the debugs for your user, now when you click on Check Challenge button and it fails with an error look for the debugs. You'll find a debug with the assertion failed message. If you check this debug you'll see what test data is being inserted in the salesforce tests and what assertion is failing which should help you update your code to progress
Krishna Priya ChKrishna Priya Ch
Over all code coverage in the instance is 95%. but still getting the below error.

User-added image
Anyone faced this type of issue???
Deep Thacker 7Deep Thacker 7
I am trying and I am facing error and my Order classes are not getting code coverage. When I went thru the test logs, I found out that my TestDataFactory class method is failing when it tries to insert PriceBookEntry and it shows below Exception error in logs.
(My guess is, becuase its not able to insert the data, the trigger is not getting executed.)

22:46:56:198 EXCEPTION_THROWN [150]|System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []

I also tried with the codes mentioned in this thread but still getting the same error, no coverage for order classes or trigger.

Can someone help me to solve this error!!!! Thanks.
Ivaylo DimovIvaylo Dimov
Hi, I have made multiple attempts to consolidate my code, but I keep getting the same error. "System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []" Could someone help me with this challange?
Here is my code so far:

TestDataFactory:
/**
 * @name TestDataFactory
 * @description Contains methods to construct and/or validate commonly used records
**/
public with sharing class TestDataFactory {

    /**
     * @name ConstructCollaborationGroup
     * @description
    **/
    public static List<Product2> pros;
    public static List<PricebookEntry> enteries;
    public static List<Account> acts;
    public static  List<Contact> contacts;
    public static  List<Order> orders;
    public static List<OrderItem> orderItems;
    static CollaborationGroup nameGroup=new CollaborationGroup ();
    public static CollaborationGroup ConstructCollaborationGroup(){
        //String nameGroup=TEST+Constants.INVENTORY_ANNOUNCEMENTS;
         
        //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.
        nameGroup.CollaborationType='Public';
        nameGroup.Name='TEST'+Constants.INVENTORY_ANNOUNCEMENTS;
        return nameGroup;
    }

    /**
     * @name CreateProducts
     * @description Constructs a list of Product2 records for unit tests
    **/
    public static List<Product2> ConstructProducts(Integer cnt){
        List<Product2> pros=new List<Product2>();
               
        Integer picklistSize=Constants.PRODUCT_FAMILY.size();
        System.debug(picklistSize+''+Constants.PRODUCT_FAMILY[0].getValue());
        Integer j=0;
        for(Integer i=0;i<cnt;i++){
            Product2 p=new Product2();
            p.Name='ProductConstruction'+i;
            p.IsActive=true;
            p.Initial_Inventory__c =10;
            p.Family=Constants.PRODUCT_FAMILY[j].getValue();
            if(j==picklistSize-1){
                j=0;
            }else{
            j++;
            }
            pros.add(p);
        }
        System.debug('before insert '+pros);
       // insert pros;
        System.debug('after insert '+pros);
        return pros;
        //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.
    }


    /**
     * @name CreatePricebookEntries
     * @description Constructs a list of PricebookEntry records for unit tests
    **/
    public static List<PricebookEntry> ConstructPricebookEntries(List<Product2> prods){
        List<PriceBookEntry> priceBooks= new List<PriceBookEntry>();
        
        for(product2 p:prods){
            PricebookEntry pbe=new PricebookEntry();
            pbe.UnitPrice=(Decimal)100;
            pbe.IsActive=true;
            pbe.Product2Id=p.Id;
            pbe.Pricebook2Id=Constants.STANDARD_PRICEBOOK_ID;
            
            priceBooks.add(pbe);
        }
            
        if(priceBooks!=null && !priceBooks.isEmpty()) {
              //insert priceBooks;
        }
        return priceBooks;

        //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
    }

    /**
     * @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> acts=new List<Account>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            Account a=new Account();
            a.Name='Account'+i;
            a.Rating='Hot';
            i++;
            acts.add(a);
        }
        //insert acts;
        return acts;
    }

    /**
     * @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> contacts=new List<Contact>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            Contact c=new Contact();
            c.AccountId=accts.get(i).Id;
            c.LastName='Contact'+i;
            i++;
            contacts.add(c);
        }
        //insert contacts;
        return contacts;
    }

    /**
     * @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>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
          Contract c=new Contract(AccountId=accts.get(i).Id,Status='Draft',StartDate =date.today(),ContractTerm =12);
          Order o=new Order();
          o.AccountId=accts.get(i).Id;
          o.EffectiveDate=date.today();
          o.Pricebook2Id=Constants.STANDARD_PRICEBOOK_ID;
          o.ContractId=c.Id ;
          o.Status='Draft';
          
          i++;
            orders.add(o);
        }
        //insert orders;
        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> items=new List<OrderItem>();
        Integer i=0;
        for(Integer j=0;j<cnt;j++){
            OrderItem oi=new OrderItem();
            oi.Quantity=Constants.DEFAULT_ROWS;
            oi.PricebookEntryId=pbes.get(i).Id;
            System.debug('pricebook'+oi.PricebookEntryId+' '+pbes.get(i).Id);
            oi.OrderId=ords.get(i).Id;
            oi.UnitPrice=(Decimal)100;
            i++;
            items.add(oi);
        }
        //insert items;
        return items;
    }

    /**
     * @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.
        //CollaborationGroup cg=ConstructCollaborationGroup();
       // List<CollaborationGroup> cgroup=[Select Name from CollaborationGroup where Name=: 'Inventory Announcements'];
        //if(cgroup.size()==0){
        //    insert cg;
       // }
        
        pros=ConstructProducts(cnt);
           insert pros;
        enteries=ConstructPricebookEntries(pros);
        insert enteries;
        acts=ConstructAccounts(cnt);
        insert acts;
       contacts=ConstructContacts(cnt,acts);
        insert contacts;
       orders=ConstructOrders(cnt,acts);
            insert orders;
        System.debug('TestFactory'+orders);
        orderItems=ConstructOrderItems(cnt,enteries,orders);      
       insert orderItems;
        
       
    }
    public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered) {
     System.assertEquals(updatedProduct.Quantity_Ordered__c, (originalProduct.Quantity_Ordered__c + qtyOrdered));
}
    
}
OderTests:
@isTest (SeeAllData=false)
private class OrderTests {
    
    @testSetup
    static void SetupTestData() {
        TestDataFactory.InsertTestData(5);
    }
 
    @isTest static void OrderExtension_UnitTest() {
        Test.startTest();
        PageReference pageRef = Page.OrderEdit;
        Test.setCurrentPage(pageRef);
        SetupTestData();
        ApexPages.StandardController stdcontroller = new ApexPages.StandardController(TestDataFactory.orders[0]);        
        OrderExtension ext = new OrderExtension(stdcontroller);        
           System.assertEquals(Constants.DEFAULT_ROWS, 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<SelectOption> options = ext.GetFamilyOptions();
        
        Test.stopTest();
    }
    
@isTest
public static void OrderUpdate_UnitTest(){
     
   
    Test.startTest();
    SetupTestData();
    List<Order> orders = TestDataFactory.orders;
    for (Order o : orders){
        o.Status = Constants.ACTIVATED_ORDER_STATUS;
    }
    List<Product2> oldProducts = TestDataFactory.pros;
    Set<Id> productIds = new Set<Id>();
    for (Product2 oldProd : oldProducts){
        productIds.add(oldProd.Id);
    }
    oldProducts = [SELECT Id, Quantity_Ordered__c FROM Product2 WHERE ID IN :productIds];
    Map<Id, Integer> quantities = new Map<Id, Integer>();
    for (OrderItem oi : TestDataFactory.orderItems){
        Integer quantity = 0;
        List<PricebookEntry> pricebookentries = TestDataFactory.enteries;
        for (PricebookEntry pbe : pricebookentries){
            if (oi.PricebookEntryId == pbe.Id){                
                if (quantities.containsKey(pbe.Product2Id)){
                    quantity = quantities.get(pbe.Product2Id);
                }
                quantity += (Integer)oi.Quantity;
                quantities.put(pbe.Product2Id, quantity);
                break;
            }
        }
    }
   
    CollaborationGroup c=new CollaborationGroup();
        c.Name='Test Inventory Announcements';
        c.Description='test';
        //c.OwnerId=[Select Id from Account Limit 1].Id;
        c.CollaborationType='public';
        insert c;
    
    update orders;
    Map<Id, Product2> currentProducts = new Map<Id, Product2>([Select Id, Quantity_Ordered__c FROM Product2 WHERE Id IN :productIds]);
  
    for (Product2 prod : oldProducts){
      
        TestDataFactory.VerifyQuantityOrdered(prod, currentProducts.get(prod.Id), quantities.get(prod.Id));
  }
  Test.stopTest();
}
}

 
Chen ZhenghangChen Zhenghang
@Vivian Charlie 1208 
Thank Vivian. The debug is useful. Debug yourself, and then Check Challege, you will find that the system check your logic by executing anonymous. Suspect the system.assert to find if your data and logic meet the assertion.
I have fixed the following issues by check the debug.

Ensure that you have at least 12 products created and that OrderExtension is still working as specified in the earlier challenge.
Ensure that product2Controller is still working as specified in the earlier challenge.

For this error, you need to ensure you have products more than 12, and less than 15. Becuase the challenge do the following check:
Execute Anonymous: system.assert( ext.gethasNext() == true );
Execute Anonymous: system.assert( ext.gethasPrevious() == false );
Execute Anonymous: system.assert( ext.gettotalPages() == 3 );
Execute Anonymous: system.assert( ext.getPageNumber() == 1 );
That means the totalPages of your product must be 3.
Iftekhar UddinIftekhar Uddin
Below code ran by Salesforce you will find in Tracelogs and you can execute this annonymous. Currently, I am facing problems with Triggers and System.DmlException. My Product2Test working excellent, but still unable to complete the challange.  =====

Integer toCreate = 20;
List<Product2> testProducts = testDataFactory.constructProducts(toCreate);
insert testProducts;
system.debug(testProducts);

List<PricebookEntry> testPricebookEntries = testDataFactory.constructPricebookEntries(testProducts);
insert testPricebookEntries;
List<Account> testAccounts = testDataFactory.constructAccounts(toCreate);
insert testAccounts;
system.debug(testAccounts);

List<Order> testOrders = testDataFactory.constructOrders(toCreate,testAccounts);
insert testOrders;
system.debug(testOrders);

for ( Integer i=0; i<testOrders.size(); i++ ){
system.assert( testOrders[i].AccountId == testAccounts[i].Id );
 }

system.assert( testOrders.size() == toCreate);

List<OrderItem> testOrderItems = testDataFactory.constructOrderItems(toCreate, testPricebookEntries, testOrders);
insert testOrderItems;
system.debug(testOrderItems);

system.assert( testOrderItems.size() == toCreate);
Set<String> nameSet = new Set<String>();

for ( Integer i=0; i<testOrderItems.size(); i++ ){
     system.assert( testOrderItems[i].OrderId == testOrders[i].Id );
     system.assert( testOrderItems[i].PricebookEntryId == testPricebookEntries[i].Id );
 }
 delete testOrders;
 delete testAccounts;
 delete testProducts;
Amardeep ChauhanAmardeep Chauhan
thanks Vivian that debug help a lot... that works for me
Oussama KhmOussama Khm
Vivan's comment helper, thanks!

Salesforce should update their way of testing.. makes no sense to work for a given challenge but not for the code coverage.. 
+ the error message is not clear !
Navita_007Navita_007
thanks Vivian, I had the same issues as you listed. Thank you!!
Venkat RamamurthyVenkat Ramamurthy
Hi Vivian Charlie,
Thanks, the checks you pointed out, really helped me reach the final step of the badge, i have completed the badge now.
Just for everyone's benefit, I will summarize again all the critical checks that are required within product wrapper class members:
productRecord.Name != null && 
productRecord.Family != null && productRecord.Family != Constants.SELECT_ONE &&
pricebookEntryRecord.UnitPrice !=null && productRecord.Initial_Inventory__c != null &&
pricebookEntryRecord.IsActive == true
In Product2Helper, you should check:
Product2Obj.Quantity_Remaining__c <= <Inventory Setting Metadata map>.Low_Quantity_Alert__c

So, challenge 8 requires all these checks to pass.....Good luck everyone!
 
Satya Prakash 67Satya Prakash 67
Run all test classes. 
NanduNandu

Over all code coverage in the instance is 94% and all test clases passed. but still getting the below error.

User-added imageUser-added image
Could you please help me here ?

Thanks in Advance 
Mahesh
Ram chilukuriRam chilukuri
.Same Error,I am also getting
ashu 6112ashu 6112
I am also stuck at the same point, challenge 9.


 
ashu 6112ashu 6112
@Nandu/@Ram - Can you please guide how you resolved it as my code coverage showing in org is 91% and all test methods passed but still giving me same error
naz chebnaz cheb
Hello :)  Finally I validate the Superbadge. For those who faces  issues with challenge, here codes used to validate Challenge 9.
Part 1 

----OrderTests---

@isTest 
private class OrderTests {

    @testSetup  
    public static void setupTestData(){
        
        TestDataFactory.InsertTestData(7);
    }
    
  public  static Map<String, List<Object>> testData;  
    

    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();
    }
    
 @isTest
    static  void OrderExtension_UnitTest(){
        
         Order rec = [select id, Status from Order limit 1];
        PageReference pageRef = Page.OrderEdit;
        Test.setCurrentPage(pageRef);
        pageRef.getParameters().put('id',rec.id);
        ApexPages.StandardController sc = new ApexPages.standardController(rec);
        
        OrderExtension cc = new OrderExtension(sc);
        cc.SelectFamily();
        cc.OnFieldChange();
        cc.Save();
        cc.First();
        cc.Next();
        cc.Previous();
        cc.Last();
        cc.GetHasPrevious();
        cc.GetHasNext();
        cc.GetTotalPages();
        cc.GetFamilyOptions();
        
        ChartHelper.GetInventory();
        
    }
    
    
}

--Product2Tests---

@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());
    }
     @isTest 
    static void Product2Trigger_UnitTest(){
         Product2 testPrd = new Product2(Name='Test Product',Initial_Inventory__c=100,IsActive=true,Family='Entree');
        insert testPrd;
        CollaborationGroup grop=new CollaborationGroup (Name='TEST1 Inventory Announcements',CollaborationType = 'Public',
                                                        IsArchived = false,IsAutoArchiveDisabled = true);
        insert grop;
        
        Test.startTest();
        testPrd.Quantity_Ordered__c=13;
        update testPrd;
        Test.stopTest();
    }

}

---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',//CanHaveGuests = true,
                                                                   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> prodsToInst = new List<product2>(); 
        Schema.DescribeFieldResult fieldResult =Product2.Family.getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();

        for(integer i=0;i< cnt;i++)
        {
                product2 p = new product2();
                 p.Name = 'Product Curry-'+ i ;
                 p.IsActive = true;
                 p.Initial_Inventory__c =10;
                 if(i>=4)
                 p.Family = constants.PRODUCT_FAMILY[0].getValue();
                 else if(i<4)
                 p.Family = constants.PRODUCT_FAMILY[i].getValue();
                
                prodsToInst.add(p);
                
        }
        
        
        return prodsToInst;  
    }

    /**
     * @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
           Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();
          List<pricebookEntry> PBEntryToInst = new List<pricebookEntry>(); 
          
        for( integer i=0 ;i < prods.size();i++){
          pricebookEntry pbe = new pricebookEntry ( Product2Id = prods[i].Id , PriceBook2Id = pricebookId,
                                                    IsActive = true , UnitPrice = 10
                                                   );
          PBEntryToInst.add(pbe);
        }
         
          
          return PBEntryToInst;                                         

    }

    /**
     * @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> AccListToInst = new List<Account>();
        
        
        for(integer i=0;i< cnt;i++) {
        
          Account acc = new Account ( Name = 'TestAcco' + i);
          AccListToInst.add(acc);
        }
        
        
        return AccListToInst;
        
    }

    /**
     * @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> ConListToInst = new List<Contact>();
        
        
        for(integer i=0;i< cnt;i++) {
             Contact con = new Contact ( LastName = 'TestCont' + i , AccountId = accts[i].Id);
             ConListToInst.add(con);
        }
        
        
        return ConListToInst;
        
    }

    /**
     * @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> OrdListToInst = new List<Order>();
        //Id PricebookId = [SELECT Id From Pricebook2 WHERE IsStandard = true].Id
        Id pricebookId = constants.STANDARD_PRICEBOOK_ID;//Test.getStandardPricebookId();

        for(integer i=0;i< cnt;i++) {
             Order o = new Order ( EffectiveDate = Date.Today() , AccountId = accts[i].Id, Status = 'Draft',Pricebook2Id = pricebookId);
             OrdListToInst.add(o);
        }
        
        
        return OrdListToInst;
        
    }

    /**
     * @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> OrderItemListToInst = new List<OrderItem>();
        
       for(integer i=0;i< cnt;i++) {
            OrderItem oi = new OrderItem (Quantity = Constants.DEFAULT_ROWS, UnitPrice = 10,
                                          orderId = ords[i].Id, pricebookentryId = pbes[i].Id);
           OrderItemListToInst.add(oi);                               
        }  
          
        return OrderItemListToInst;
    }

    /**
     * @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.
        
        CollaborationGroup cg = ConstructCollaborationGroup();
        insert cg;
        List<Account> accountList = ConstructAccounts(cnt);
        insert accountList;
        List<Contact> contactList = ConstructContacts(cnt, accountList);
        insert contactList ;
        List<Product2> prodList = ConstructProducts(cnt);
        insert prodList ;
        List<PriceBookEntry> pbeEntry = ConstructPricebookEntries(prodList);
        insert pbeEntry ;
        List<Order> orderList = ConstructOrders(cnt, accountList);
        insert orderList ;
        List<OrderItem> itemList = ConstructOrderItems(cnt, pbeEntry , orderList);
        insert itemList ;

    }
    
     /**
     * @name VerifyQuantityOrdered
     * @description
    **/
    
       public static void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered){
       
         System.assertEquals(originalProduct.Quantity_Ordered__c + qtyOrdered , updatedProduct.Quantity_Ordered__c,'QuantityOrdered mismatch after update' );
       
       }

}

 
naz chebnaz cheb
Here Part 2 resolution challenge 9

--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);
        }
    }
}
---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--
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)
        OR Name = :('TEST1 '+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
    }
}
Akshay Phadnis 9Akshay Phadnis 9
I am also facing this issue. And when checked in debug logs for insert on some objects, getting error as Insufficient Privilege. Any idea which profile does Trailhead Bot uses and do we have to give accesses to any objects for this profile.