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
Shubham NandwanaShubham Nandwana 

Superbadge:Advance Apex Specialist step 8 Error

Hello,
While solving challenge 8 I am getting an error:- 
Challenge Not yet complete... here's what's wrong: 
Ensure that orderTrigger and orderHelper are still working as specified in the earlier challenge.
Please let me know what I am doing wrong else paste the correct code here.
My code goes as follows-:

CLASS- OrderTests

@isTest
public class OrderTests {
    @testSetup 
    public static void SetupTestData() {     
            TestDataFactory.InsertTestData(3);      
    }
    
   @isTest
    public static void OrderUpdate_UnitTest (){
        Test.startTest();
        
        List<Product2> originalProduct=[Select Quantity_Ordered__c from Product2 where Name like 'ProductConstruction%'];
        
        List<Order> ord=new List<Order>();
        List<Order> testOrders=[Select status from Order where status='Draft'];
        System.debug('originalPro '+originalProduct);
        System.debug('Ordertest orders '+testOrders);
        
        for(Order o:testOrders){
            
            o.Status=Constants.ACTIVATED_ORDER_STATUS;
            ord.add(o);
        }
        System.debug('OrderTests 21 '+ord);
        update ord;
        List<Product2> updatedProduct=OrderHelper.pr; 
        //System.debug(updatedProduct.get(0)+' '+originalProduct.get(0));
           TestDataFactory.VerifyQuantityOrdered(originalProduct.get(0), updatedProduct.get(0), (Integer)OrderHelper.temp.get(0)); 
        Test.stopTest();
    }
    @isTest
    public static void OrderExtension_UnitTest (){
        Test.startTest();
        
        Account ac=new Account();
        ac.Name='Test1';
        insert ac;
        
        Contract ct=new Contract();
        ct.AccountId=ac.Id;
        ct.StartDate =date.today();
        ct.Status='Draft';
        ct.ContractTerm=4; 
        insert ct;
        
        Order obj=new Order();
        obj.AccountId=ac.Id;
        obj.EffectiveDate=date.today();
        obj.ContractId=ct.Id;
        obj.Status='Draft';
        obj.Name='OrderName';
       
        insert obj;
        
        ApexPages.StandardController sc = new ApexPages.StandardController(obj);
        
        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();
        Test.stopTest();
    }
}

CLASS- prouct2Tests
@isTest (seeAllData=true)
private class Product2Tests {

    /**
     * @name product2Extension_UnitTest
     * @description UnitTest for product2Extension
    **/ 
    static TestMethod void Product2Extension_UnitTest(){
        Test.startTest();
           PageReference pageRef = Page.Product2New;
           Test.setCurrentPage(pageRef);
          
        
        ApexPages.StandardController controller =new Apexpages.StandardController(new Product2());
            Product2Extension ext = new Product2Extension(controller);
            ext.addRows();
            ext.save();
            System.assertEquals(Product2Extension.productsToInsert.size(), Constants.DEFAULT_ROWS);
        
         
         //if(addValue.equals('Add'))
                  //System.assertEquals(Product2Extension.productsToInsert.size(), 2*Constants.DEFAULT_ROWS);
        
        Integer i=0;
        for(Product2Extension.ProductWrapper pr: Product2Extension.productsToInsert){
            if (String.isBlank(pr.productRecord.Name) || pr.productRecord.Name==null){
                pr.productRecord.Name='Product'+i;
            }
               
            if(String.isBlank(pr.productRecord.Family) ||  pr.productRecord.Family==null ){
                pr.productRecord.Family='Side';
            }
                  
            if(pr.productRecord.IsActive==false){
                pr.productRecord.IsActive=true;
            }
            if(pr.productRecord.Initial_Inventory__c==null){
                pr.productRecord.Initial_Inventory__c=15;
            }
            i++;
                   
        }
        PageReference p=ext.save();
        List<Product2> queryResults=[Select Name,IsActive,Initial_Inventory__c from Product2 where Initial_Inventory__c=15 and IsActive= true and Family='Side'];
                Test.stopTest();
        System.assertEquals(queryResults.size(), 5);
        System.debug(Product2Extension.productsToInsert.size());       

    }
    static void Product2Trigger_UnitTest(){
        Test.startTest();
        
        Product2 p=new Product2();
        p.Name='TestProduct';
        p.Family='Side';
        p.IsActive=true;
        p.Quantity_Ordered__c =100;
        p.Initial_Inventory__c =10;
        insert p;
        
        p.Quantity_Ordered__c=200;
        update p;
            
        Test.stopTest();
    }

}

CLASS - OrderHelper
public without sharing class OrderHelper {

    /**
     * @name AfterUpdate
     * @description 
     * @param List<Order> newList
     * @param List<Order> oldList
     * @return void
    **/
    public static List<Product2> pr=new List<Product2>();
    public static List<Decimal> temp;
    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);
            }
        }
        System.debug('New Order '+newList);
        System.debug('Old Order '+oldList);
        System.debug('OrderIDS '+orderIds);
        OrderHelper.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){
        List<OrderItem> oi=[Select Id, Product2Id ,AvailableQuantity from OrderItem where OrderId IN:activatedOrderIds];
        Map<Id,Product2> productMap=new Map<Id,Product2>();
        //ToDo: Declare a Map named "productMap" of Ids to Product2 records

        //ToDo: Loop through a query of OrderItems related to the activatedOrderIds
        for(OrderItem ord:oi){
            Product2 p=[Select Id,Name, Quantity_Ordered__c , Quantity_Remaining__c from Product2 where Id=: ord.Product2Id ];
            productMap.put(ord.Product2Id, p);
         }
         
        
          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');
                temp.add(p.Quantity_Ordered__c);
               pr.add(p);
        }
        System.debug('orderHelper'+pr+' '+activatedOrderIds+' '+groupedResults);
        update pr;
            //ToDo: Populate the map with the Id of the related Product2 as the key and Product2 record as the value
            
        //ToDo: Loop through a query that aggregates the OrderItems related to the Products in the ProductMap keyset

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

}

Thanks in advance
Shubham Nandwana
BHASKAR GANGULYBHASKAR GANGULY
Hi All,
i am gettingbelow error while trying to verify this.
Challenge Not yet complete... here's what's wrong: 
Ensure that product2Controller is still working as specified in the earlier challenge.
Someone please help me to get it through.i am stuck on this for last couple of days.
Below are my classes :
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 = Product2.Family.getDescribe().getPicklistValues();
  public static final String DRAFT_ORDER_STATUS = 'Draft';
  public static final String ACTIVATED_ORDER_STATUS = 'Activated';
  public static final String INVENTORY_ANNOUNCEMENTS = 'Inventory Announcements';
  public static final String ERROR_MESSAGE = 'An error has occurred, please take a screenshot with the URL and send it to IT.';
  public static final Id STANDARD_PRICEBOOK_ID = '01s6A0000031LaYQAU'; //Test.isRunningTest() ? Test.getStandardPricebookId() : [SELECT Id FROM PriceBook2 WHERE isStandard = true LIMIT 1].Id;
}

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);
                break;
            }
        }
        if (announcements.size() > 0 && !test.isRunningTest()){
            AnnouncementQueueable q = new AnnouncementQueueable(announcements);
            System.enqueueJob(q);
            //ToDo: Enqueue the above instance of announcementQueueable
        }
    }
}

ChartHelper
public without sharing class ChartHelper {
    
    @AuraEnabled// Make sure annotation should be applied for this method 
    public static List<chartData> GetInventory(){
        List<chartData> cht = new List<chartData>();
        for(AggregateResult ar : [SELECT Family family, Sum(Quantity_Remaining__c) total 
                                  FROM Product2
                                  WHERE Quantity_Remaining__c > 0 GROUP BY Family]){
                                      cht.add(new chartData((String)ar.get('family'), Integer.valueOf(ar.get('total'))));
                                  }
        return cht;
    }
    
    public class ChartData {
        public String name {get;set;}
        public Decimal val {get;set;}
        public ChartData(String name, Decimal val){
            this.name = name;
            this.val = val;
        }
    }
}
OrderExtension:
/**
* @name OrderExtension
* @description This class is provided for you to facilitate the Super Badge
**/
public class OrderExtension {
    
    public Order orderRecord {get;set;}
    public List<OrderItem> orderItemList {get;set;}
    public String selectedFamily {get;set;}
    public List<chartHelper.chartData> pieData {get;set;}
    public Decimal total {get;set;}
    public Map<Id,OrderItem> orderItemMap;
    ApexPages.StandardSetController standardSetController;
    public OrderExtension(ApexPages.StandardController standardController){
        orderRecord = (Order)standardController.getRecord();
        orderItemMap = new Map<id,OrderItem>();
        if ( orderRecord.Id != null ){
            orderRecord = queryOrderRecord(orderRecord.Id);
        }
        resetSsc();
        total = 0;
        for (OrderItem oi : orderRecord.OrderItems) {
            orderItemMap.put(oi.Product2Id, oi);
            if (oi.Quantity > 0) {
                if (null == pieData) {
                    pieData = new List<ChartHelper.ChartData>();
                }
                pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
                total += oi.UnitPrice * oi.Quantity;
            }
        }
        PopulateOrderItems();
    }
    void resetSsc() {
        String query = 'SELECT Name, Product2.Family, Product2.Name, Product2Id, UnitPrice, Product2.Quantity_Remaining__c'
            + '  FROM PricebookEntry WHERE IsActive = TRUE';
        if (selectedFamily != null && selectedFamily != Constants.SELECT_ONE) {
            query += ' AND Product2.Family = \'' + selectedFamily + '\'';
        }
        query += ' ORDER BY Name';
        standardSetController = new ApexPages.StandardSetController(Database.getQueryLocator(query));
        standardSetController.setPageSize(Constants.DEFAULT_ROWS);
    }
    //ToDo: Implement your own method to populate orderItemList
    //  that you will call after pagination and/or family selection
    void PopulateOrderItems() {
        orderItemList = new List<OrderItem>();
        for (SObject obj : standardSetController.getRecords()) {
            PricebookEntry pbe = (PricebookEntry)obj;
            
            if (orderItemMap.containsKey(pbe.Product2Id)) {
                orderItemList.add(orderItemMap.get(pbe.Product2Id));
            } else {
                orderItemList.add(new OrderItem(
                    PricebookEntryId=pbe.Id,
                    Product2Id=pbe.Product2Id,
                    UnitPrice=pbe.UnitPrice,
                    Quantity=0,
                    Product2=pbe.Product2
                ));
            }
        }
    }
    /**
* @name OnFieldChange
* @description
**/
    public void OnFieldChange(){
        //ToDo: Implement logic to store the values changed on the page
        for (OrderItem oi : orderItemList) {
            orderItemMap.put(oi.Product2Id, oi);
        }
        //      and populate pieData
        pieData = null;
        total = 0;
        for (OrderItem oi : orderItemMap.values()) {
            if (oi.Quantity > 0) {
                if (null == pieData) {
                    pieData = new List<chartHelper.ChartData>();
                }
                pieData.add(new chartHelper.ChartData(oi.Product2.Name, oi.Quantity * oi.UnitPrice));
                //      and populate total
                total += oi.UnitPrice * oi.Quantity;
            }
        }
    }
    /**
* @name SelectFamily
* @description
**/
    public void SelectFamily(){
        //ToDo: Implement logic to filter based on the selected product family
        resetSsc();
        PopulateOrderItems();
    }
    /**
* @name Save
* @description
**/
    public void Save(){
        //ToDo: Implement logic to save the Order and populated OrderItems
        System.Savepoint sp = Database.setSavepoint();
        try {
            if (null == orderRecord.Pricebook2Id) {
                orderRecord.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
            }
            upsert orderRecord;
            List<OrderItem> orderItemsToUpsert = new List<OrderItem>();
            List<OrderItem> orderItemsToDelete = new List<OrderItem>();
            for (OrderItem oi : orderItemList) {
                if (oi.Quantity > 0) {
                    if (null == oi.OrderId) {
                        oi.OrderId = orderRecord.Id;
                    }
                    orderItemsToUpsert.add(oi);
                } else if (oi.Id != null) {
                    orderItemsToDelete.add(oi);
                }
            }
            upsert orderItemsToUpsert;
            delete orderItemsToDelete;
        } catch (Exception e) {
            Database.rollback(sp);
            apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,Constants.ERROR_MESSAGE));
        }
    }
    /**
* @name First
* @description
**/
    public void First(){
        standardSetController.first();
        PopulateOrderItems();
    }
    /**
* @name Next
* @description
**/
    public void Next(){
        standardSetController.next();
        PopulateOrderItems();
    }
    
    
    /**
* @name Previous
* @description
**/
    public void Previous(){
        standardSetController.previous();
        PopulateOrderItems();
    }
    /**
* @name Last
* @description
**/
    public void Last(){
        standardSetController.last();
        PopulateOrderItems();
    }
    /**
* @name GetHasPrevious
* @description
**/
    public Boolean GetHasPrevious(){
        return standardSetController.getHasPrevious();
    }
    
    /**
* @name GetHasNext
* @description
**/
    public Boolean GetHasNext(){
        return standardSetController.getHasNext();
    }
    
    /**
* @name GetTotalPages
* @description
**/
    public Integer GetTotalPages(){
        return (Integer)Math.ceil(standardSetController.getResultSize() / (Decimal)Constants.DEFAULT_ROWS);
    }
    
    /**
* @name GetPageNumber
* @description
**/
    public Integer GetPageNumber(){
        return standardSetController.getPageNumber();
    }
    
    /**
* @name GetFamilyOptions
* @description
**/
    public List<SelectOption> GetFamilyOptions() {
        List<SelectOption> options = new List<SelectOption>{
            new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE)
                };
                    
                    for (Schema.PicklistEntry ple : Constants.PRODUCT_FAMILY) {
                        options.add(new SelectOption(ple.getValue(), ple.getLabel()));
                    }
        return options;
    }
    
    /**
* @name QueryOrderRecord
* @description
**/
    public static Order QueryOrderRecord(Id orderId){
        return [
            SELECT Id, AccountId, EffectiveDate, Name, Status, Pricebook2Id,
            (
                SELECT Id, OrderId, Quantity, UnitPrice, PricebookEntryId, Product2Id,
                Product2.Name, Product2.Family, Product2.Quantity_Remaining__c
                FROM OrderItems
            )
            FROM Order
            WHERE Id = :orderId
        ];
    }
}
OrderHelper :
public class OrderHelper {

  /**
   * @name AfterUpdate
   * @description
   * @param List<Order> newList
   * @param List<Order> oldList
   * @return void
   **/
  public static void AfterUpdate(List<Order> newList, List<Order> oldList){
    Set<Id> activatedOrderIds = new Set<Id>();

    //Create list of OrderIds
    for (Integer i = 0; i < newList.size(); i++) {
      if(newList[i].Status == Constants.ACTIVATED_ORDER_STATUS && oldList[i].Status == Constants.DRAFT_ORDER_STATUS) {
        activatedOrderIds.add(newList[i].Id);
      }
    }

    RollUpOrderItems(activatedOrderIds);
  }

  /**
   * @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>();
    Set<Id> productIds = new Set<Id>();

    //ToDo: Loop through a query of OrderItems related to the activatedOrderIds
    List<OrderItem> items = [SELECT Id, Product2Id, Quantity FROM OrderItem WHERE OrderId In :activatedOrderIds];

    //ToDo: Populate the map with the Id of the related Product2 as the key and Product2 record as the value
    for(OrderItem oi : items) {
      productIds.add(oi.Product2Id);
    }

    productMap = new Map<Id, Product2>([SELECT Id, Quantity_Ordered__c FROM Product2 WHERE Id IN:productIds]);

    AggregateResult[] aggregatedResults  = [SELECT Product2Id, SUM(Quantity) aggregatedQuantity FROM OrderItem WHERE Product2Id In :productMap.keySet() GROUP BY Product2Id];

    for (AggregateResult ar : aggregatedResults)  {
      productMap.get((String)ar.get('Product2Id')).Quantity_Ordered__c = Integer.valueOf(ar.get('aggregatedQuantity'));
    }

    //ToDo: Perform an update on the records in the productMap
    if(productMap != null && productMap.size() > 0) {
      update productMap.values();
    }
  }

}
OrderTests:

@isTest(SeeAllData=true)
public class OrderTests {
 
public  static Map<String, List<Object>> testData;  
    
@isTest static void OrderUpdate_UnitTest (){
       // TestDataFactory.InsertTestData(5); 
       // List<Account> accts=new List<Account>();
       
            Account a=new Account();
            a.Name='Account';
            a.Rating='Hot';

    insert a;
       List<Order> orders=new List<Order>();
       // Integer k=0;
        
            //Contract c=new Contract(AccountId=accts.get(k).Id,Status='Draft',StartDate =date.today(),ContractTerm =12);
            Order o=new Order();
            o.AccountId=a.Id;
            o.EffectiveDate=date.today();
            //o.Pricebook2Id='01s6A0000031LaYQAU';
            //o.ContractId=c.Id ;
            o.Status='Draft';
          //  k++;
       
        insert o;
       List<Product2> pros=new List<Product2>();
        Integer picklistSize=Constants.PRODUCT_FAMILY.size();
        Integer j=0;
        for(Integer s=0;s<5;s++){
            Product2 p=new Product2();
            p.Name='Side';
            p.IsActive=true;
            p.Initial_Inventory__c =10;
            p.Family=Constants.PRODUCT_FAMILY[j].getValue();
            p.Quantity_Ordered__c=10;
            if(j==picklistSize-1){
                j=0;
            }else{
                j++;
            }
          
            pros.add(p);
        }
     insert pros;
        Order rec = [select id, Status from Order limit 1];
        Product2 prod = [SELECT Initial_Inventory__c,Family,Id,Name,Quantity_Ordered__c,Quantity_Remaining__c FROM Product2 where name ='Side' limit 1];
        system.debug('product2Controller => '+prod.Quantity_Ordered__c);
        system.debug('Quantity_Remaining__c => '+prod.Quantity_Remaining__c);
        rec.status = constants.ACTIVATED_ORDER_STATUS;
        Update rec;
        Product2 updatedprod = [SELECT Initial_Inventory__c,Family,Id,Name,Quantity_Ordered__c,Quantity_Remaining__c FROM Product2 Where name ='Side' limit 1];
        system.debug('itial_Inventory__c =>'+updatedprod.Initial_Inventory__c);
        system.debug('Quantity_Ordered__c =>'+updatedprod.Quantity_Ordered__c);
        system.debug('Quantity_Remaining__c =>'+updatedprod.Quantity_Remaining__c);
        TestDataFactory.VerifyQuantityOrdered(prod,updatedprod,constants.DEFAULT_ROWS);
        
        //upsert updatedprod;
    }    
@isTest(SeeAllData=true) 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();
        //Constants.getStdPriceBook();

}


//@testSetup static void SetupTestData (){
    
//}


}



Thanks,
BHaskar
BHASKAR GANGULYBHASKAR GANGULY
Product2Extension 
public class Product2Extension {

  public List<ProductWrapper> productsToInsert {get; set;}

  public Product2Extension(ApexPages.StandardController controller){
    productsToInsert = new List<ProductWrapper>();
    AddRows();
  }

  public void AddRows(){
    for (Integer i=0; i<Constants.DEFAULT_ROWS; i++ ) {
      productsToInsert.add( new ProductWrapper() );
    }
  }

  public List<ChartHelper.ChartData> GetInventory(){
    return ChartHelper.GetInventory();
  }

  public List<SelectOption> GetFamilyOptions() {
    List<SelectOption> options = new List<SelectOption>();
    options.add(new SelectOption(Constants.SELECT_ONE, Constants.SELECT_ONE));
    for(PickListEntry eachPicklistValue : Constants.PRODUCT_FAMILY) {
      options.add(new SelectOption(eachPicklistValue.getValue(), eachPicklistValue.getLabel()));
    }
    return options;
  }

  public PageReference Save(){
    Savepoint sp = Database.setSavepoint();
    try {
      List<Product2> products = new List<Product2>();
      List<PricebookEntry> pbes = new List<PricebookEntry>();

      for (ProductWrapper prodwrapper : productsToInsert) {
      //  if(prodwrapper.productRecord != null && prodwrapper.pricebookEntryRecord != null) {
        //  if(prodwrapper.productRecord.Name != null && prodwrapper.productRecord.Family != null && constants.SELECT_ONE != prodwrapper.productRecord.Family && prodwrapper.productRecord.Initial_Inventory__c != null && prodwrapper.pricebookEntryRecord.UnitPrice != null) {
            products.add(prodwrapper.productRecord);
            PricebookEntry pbe = prodwrapper.pricebookEntryRecord;
            pbe.IsActive = true;
            pbe.Pricebook2Id = Constants.STANDARD_PRICEBOOK_ID;
            pbes.add(pbe);
         // }
        //}
      }

      insert products;

      for (integer i = 0; i < pbes.size(); i++) {
        pbes[i].Product2Id = products[i].Id;
      }
      insert pbes;

      //If successful clear the list and display an informational message
      apexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,productsToInsert.size()+' Inserted'));
      productsToInsert.clear();         //Do not remove
      AddRows();        //Do not remove
    } catch (Exception e){
      Database.rollback(sp);
      apexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR, Constants.ERROR_MESSAGE));
    }
    return null;
  }

  public class ProductWrapper {
    public Product2 productRecord {get; set;}
    public PriceBookEntry pricebookEntryRecord {get; set;}

    public ProductWrapper() {
      productRecord = new product2(Initial_Inventory__c =0);
      pricebookEntryRecord = new pricebookEntry(Unitprice=0.0);
    }
  }
}
Product2Helper
public class Product2Helper {
    /**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
    static List<CollaborationGroup> COLLABORATION_GROUP = [
        SELECT Id
        FROM CollaborationGroup
        WHERE Name = :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.Family) && prod.Quantity_Remaining__c <= invSettingsMap.get(prod.Family)) {
                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(toPost);
        // q.toPost = toPost;
        System.enqueueJob(q);
    }
}

Product2Tests:
@isTest(SeeAllData=true)
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(12, 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();
    }
   

}

TestFactory :

/**
* @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 void VerifyQuantityOrdered(Product2 originalProduct, Product2 updatedProduct, Integer qtyOrdered) {
        System.assertEquals(updatedProduct.Quantity_Ordered__c, (originalProduct.Quantity_Ordered__c + qtyOrdered));
    }
}
I have moved the code from Testfactory as i was getting error insufficient prevelilage.

Somebody please help me.
Amardeep ChauhanAmardeep Chauhan
is this resolved ? I am gettting same error and not able to figuour out from last 2 days.
"Please ensure that product2Extension and its methods are still working as specified in the earlier challenge."
Harshita DwivediHarshita Dwivedi
Hi All,
Was anyone able to troubleshoot and find the root cause. I am still getting below error:
"Please ensure that product2Extension and its methods are still working as specified in the earlier challenge."
Thanks,
Harshita DwivediHarshita Dwivedi
Worked for me after updating wrapper class and re-running the test class.
Below is the code.
Product2Extension
public class Product2Extension {
    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);
        }
    }
}


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 newProduct = new Product2();
        newProduct.Name = 'Test';
        newProduct.Family = 'Dessert';
        newProduct.IsActive = true;
        newProduct.Quantity_Ordered__c = 5;
        newProduct.Initial_Inventory__c = 10;
        insert newProduct;
        
        CollaborationGroup c = new CollaborationGroup();
        c.Name = 'TEST' + Constants.INVENTORY_ANNOUNCEMENTS;
        c.Description = 'Description';
        c.CollaborationType = 'Public';
        insert c;
        
        newProduct.Quantity_Ordered__c=96;
        update newProduct;
        Test.stopTest();
    } 
   
}
Amardeep ChauhanAmardeep Chauhan
i fixed with total product should be more than 12 and less than 15 . i think internally salesforce has assert for number of product. and in class product2Extension should be checked one condition for pricebook instead on Products. (i forgot the condition) that was on some thoher thread 
vijay kanth reddy sattivijay kanth reddy satti
Thanks Harshita Dwivedi. It helped to resolved the issue
karan singhalkaran singhal
Thanks, Harshita!! It worked for me!
Santosh-GaddamSantosh-Gaddam
@harshitha Dwivedi, Thank you am able to resolve the issue. 
Gilmar Amaral 7Gilmar Amaral 7
In my case the problem wa the class access modifier which was 'public' na the methods where also 'public', I just changed to 'private' both the class and the test methods.
shrutika waghmare 5shrutika waghmare 5
I had faced the same issue, even after the code and functionality were working fine, and test classes were run correctly, at last challenge (challenge 8) overall test code was failing, it was showing this error - "System.QueryException: List has no rows for assignment to SObject".
I've found that in Prodcut2Tests test class we need to set @isTest (seeAllData=true) because in ProductHelper class we are querying custom metadata and getting custom metadata record info in the test class we need to set @isTest (seeAllData=true). After this, please comment on the System.asserts because since we are looking at all data the asserts will fail. 
Another issue was in Constants class I had dynamically got the standard price book Id using this - public static final Id STANDARD_PRICEBOOK_ID = [Select Id from Pricebook2 where isStandard =true].Id; 
But it was not working, and in the challenge description also, it was mentioned that to add hardcoded Id, so I'd modified this line to - public static final String STANDARD_PRICEBOOK_ID= (add 15 characters standard Price book Id of your Org).
Another issue was that in OrderTrigger, I've added before and after both DML statements, here just add after update event.
These were some of the issues, after fixing them, I was able to pass the challenge.
One more thing before running tests, go to dev console->Test>Clear Test Data and select Run All. If the test fails, again do the same thing; Test>Clear Test Data and then do the Run All command.
Samuel ReyesSamuel Reyes

"i fixed with total product should be more than 12 and less than 15 . i think internally salesforce has assert for number of product. and in class product2Extension should be checked one condition for pricebook instead on Products. (i forgot the condition) that was on some thoher thread"

 

@Amardeep Chauhan - Thanks for that! I was at 11 and sitting at my machine for 2 hours trying to figure out why it wasn't working. Added a couple more after I saw your comment and then it worked to let me pass step 8.

Achutha TAchutha T
Can anyone please help me for the below error :

I was getting this error for Advanced Apex Super Badge Specialist for Challenge 8(Final Challenge).

Even though my Test Coverage was 94%.

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.

Please help me anyone in this community!!!!
Achutha TAchutha T
@samuel Rayes can you please help me I got the 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.