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
Jean Grey 10Jean Grey 10 

Invalid Id error

Please help, I am getting the following errors when I run the unit test:

FATAL_ERROR System.StringException: Invalid id: 
and
FATAL_ERROR External entry point

referencing the submit method in my class.

Class:
public class ContractExtension {

    //private final Hearing_Aids__c ha;

    public final Contact con;
    public List<Hearing_Aids__c> haList {get; set;}
    public List<Hearing_Aids__c> haSelectedList {get; set;}
    public List<WrapperClass> hearingAidWrappers {get; set;}
    public Boolean hearingAidSelection {get; set;}
    public Boolean productSelection {get; set;}
    public List<SelectOption> classOptions {get; set;}
    public String classSelection {get; set;}
    

    public ContractExtension(ApexPages.StandardController stdController) {
        if (!Test.isRunningTest()) { 
        stdController.addFields(new List<String>{'Account.Id','Price_Book__c'});
        hearingAidSelection = true;
        classOptions = new List<SelectOption>();
        classOptions.add(new SelectOption('Gold','Gold'));
        classOptions.add(new SelectOption('Silver','Silver'));
        classSelection = 'Gold';
        }

        //get current contact record
        con = (Contact)stdController.getRecord();
        
        haList = [  SELECT  Id, Name, Battery__c, Class__c, Contact__c, Ear__c, Has_Accessory__c, Invoice_Date__c, Quantity__c, Opportunity__c, 
                            Is_Accessory__c, Manufacturer__c, Manufacturer_Warranty_Expiration__c, Model__c, Related_Hearing_Aid__c, 
                            Serial_Number__c, Related_Hearing_Aid__r.ID, Related_Hearing_Aid__r.Name, SKU__c
                    FROM Hearing_Aids__c 
                    WHERE Contact__c = :con.ID AND Opportunity__c = null];

        hearingAidWrappers = new List<WrapperClass>();
        for(Hearing_Aids__c ha : haList){
            hearingAidWrappers.add(new WrapperClass(ha));
        }
    }

    public void hearingAidSelectionProceed(){

        hearingAidSelection = false;
        integer i = 0;
        while (i < hearingAidWrappers.size()){
            if(hearingAidWrappers[i].associateWithNewContract == false){
                hearingAidWrappers.remove(i);
            }
            i++;
        }
        productSelection = true;
        getProductOptions();
    }

    public PageReference cancel(){
        return new PageReference('/' + con.Id);
    }

    public void getProductOptions(){
        Set<String> classSet = new Set<String>();
        
        //Put each wrapperclass into the three sets
        for(WrapperClass wc : hearingAidWrappers){
            classSet.add(wc.hearingAid.Class__c);
        }

        //query for the product2 records
        List<Product2> prodList =  [SELECT Id, Name, ProductCode, Class__c, Type__c FROM Product2 WHERE Class__c IN :classSet AND Type__c = :classSelection AND isActive = true];
    
        //Organize into Map of List of Product2 records with the id being the combination of class and tier
        Map<String,List<Product2>> prodMap = new Map<String,List<Product2>>();
        for(Product2 prod : prodList){
            if(prodMap.containsKey(prod.Class__c)){
                prodMap.get(prod.Class__c).add(prod);
            } else {
                prodMap.put(prod.Class__c, new List<Product2>{prod});
            }
        }

        //Loop through each Wrapper class again and see if you can find an existing match from the product2 map.  If so, add them all as selectoptions on the wrapper class list of select options
        for(WrapperClass wc : hearingAidWrappers){
            if(prodMap.containsKey(wc.hearingAid.Class__c)){
                for(Product2 prod : prodMap.get(wc.hearingAid.Class__c)){
                    wc.productOptions.add(new SelectOption(prod.Id, prod.Name));
                }
            }
        }
    }

    //Submit
    public PageReference submit(){
        Map<Id,PricebookEntry> pricebookEntriesMap = getPricebookEntries();

        //Create new opportunity
        Opportunity opp = new Opportunity();
        opp.AccountId = con.Account.Id;
        opp.Contact__r.Id = con.Id;
        opp.Name = 'Test Opp';
        opp.StageName = 'Closed Won';
        opp.CloseDate = System.today();
        insert opp;
        //Now that it has been inserted, we are taking the auto number field and setting it as the name
        Opportunity updatedOpp = [SELECT Id, Contract__c, AccountId, Contact__c, Name, StageName, CloseDate FROM Opportunity WHERE Id = :opp.Id];
        opp.Name = updatedOpp.Contract__c;
        update opp;
    
        insert getOlisToInsert(updatedOpp, pricebookEntriesMap);

        //create contact role on opportunity to relate to contact
        OpportunityContactRole ocr = new OpportunityContactRole();
        ocr.ContactId = con.Id;
        ocr.IsPrimary = True;
        ocr.OpportunityId = opp.Id;
        insert ocr;


        //Return to the newly created opportunity
        return new PageReference('/' + opp.Id);
    }

    /**
     * Method to ge the matching pricebookentry records in order to save the correct information on the OLI
     * @return Returns a map of Id and PricebookEntry, the Id is the Product2Id
     */
    public Map<Id,PricebookEntry> getPricebookEntries(){
        Map<Id,PricebookEntry> pricebookEntriesMap = new Map<Id,PriceBookEntry>();
        
        Set<Id> prodIdSet = new Set<Id>();
        for(WrapperClass wrapper : hearingAidWrappers){
          prodIdSet.add(wrapper.selectedProduct);
        }

        Id newLeafPricebookId = [SELECT Id FROM Pricebook2 WHERE Name = 'New Leaf' LIMIT 1].Id;
        for(PricebookEntry pbe : [SELECT Id, Pricebook2Id, Product2Id, ProductCode, UnitPrice FROM PriceBookEntry WHERE isActive = true AND Product2Id IN :prodIdSet AND Pricebook2Id = :newLeafPricebookId]){
            pricebookEntriesMap.put(pbe.Product2Id, pbe);
        }

        return pricebookEntriesMap;
    }

    /**
     * Method to return all of the newly created opportunity line items and update the hearing aids
     * @param  opp                 Parent Opp
     * @param  pricebookEntriesMap Map of pricebook entries in order to 
     * @return                     List of opportunity line items to be updated.
     */


    public List<OpportunityLineItem> getOlisToInsert (Opportunity opp, Map<Id,PricebookEntry> pricebookEntriesMap){
        List<Hearing_Aids__c> hearingAidsToUpdate = new List<Hearing_Aids__c>();
        List<OpportunityLineItem> oliListToInsert = new List<OpportunityLineItem>();
        //Create new opportunity line items (each hearing aid and accessory)
        Integer i = 1;
        
        for(WrapperClass wrapper : hearingAidWrappers){
            Boolean contractAssigned = false;
            PricebookEntry pbe = priceBookEntriesMap.get(wrapper.selectedProduct);
            OpportunityLineItem oli = new OpportunityLineItem();
            oli.OpportunityId = opp.Id;
            oli.Quantity = 1;
            oli.SKU__c = wrapper.hearingAid.SKU__c;
            oli.TotalPrice = pbe.UnitPrice;
            oli.Ear__c = wrapper.hearingAid.Ear__c;
            oli.PriceBookEntryId = pbe.Id;
            oli.Contact_related__c = wrapper.hearingAid.Contact__c;
            oli.Manufacturer__c = wrapper.hearingAid.Manufacturer__c;
            oli.Model__c = wrapper.hearingAid.Model__c;
            
            //Loop through the hearing aids and give priority to left, then right, then the accessories after that
            //Note, this will not ensure that all Left ears are 1 and Right ears are 2, becuase if we have two lefts,
            //then the first would receieve 1, and the second could receive anything after that (and after a right ear too).
            //This will work properly in the normal flow.
            if(wrapper.hearingAid.Is_Accessory__c == false && wrapper.hearingAid.Ear__c == 'Left'){
                oli.Contract__c = opp.Contract__c + '-' + i;
                i++;
            } else if(wrapper.hearingAid.Is_Accessory__c == false && wrapper.hearingAid.Ear__c == 'Right'){
                oli.Contract__c = opp.Contract__c + '-' + i;
                i++;
            } else if(wrapper.hearingAid.Is_Accessory__c == true && wrapper.hearingAid.Ear__c == 'Left'){
                oli.Contract__c = opp.Contract__c + '-' + i;
                i++;
            } else if(wrapper.hearingAid.Is_Accessory__c == true && wrapper.hearingAid.Ear__c == 'Right'){
                oli.Contract__c = opp.Contract__c + '-' + i;
                i++;
            } else {
                oli.Contract__c = opp.Contract__c + '-' + i;            
                i++;
            }

            oliListToInsert.add(oli);
            
            wrapper.hearingAid.Opportunity__c = opp.Id;
            hearingAidsToUpdate.add(wrapper.hearingAid);
        }

        update hearingAidsToUpdate;
        return oliListToInsert;

    }

    //Wrapper class to hold each instance of a hearing aid conversion to an opportunity line item.  This is also where the extra variables that need to be
    //associated with the hearing aid live.
    public class wrapperClass {
        public Hearing_Aids__c hearingAid {get; set;}
        public Boolean associateWithNewContract {get; set;}
        public List<SelectOption> productOptions {get; set;}
        public String selectedProduct {get; set;}

        public wrapperClass(Hearing_Aids__c ha){
            hearingAid = ha;
            associateWithNewContract = true;
            productOptions = new List<SelectOption>();
            selectedProduct = '';
        }
    }


}

Test: @isTest(seeAllData=true)

private class ContractExtensionTest {
    static testMethod void validateOpp() {

        Test.startTest();
        
        Account acc = new Account(Name = 'TestAccount');
        insert acc;

        Contact con = new Contact(LastName='Test',AccountId=acc.ID,RecordTypeId='0127A0000008l3I',Patient_ID__c='1234');
        insert con;
        
        
        ApexPages.StandardController setCon = new ApexPages.StandardController(con); 


        Hearing_Aids__c hal = new Hearing_Aids__c(Contact__c = con.ID, Class__c = 'TIER 1 (BAS)', Ear__c = 'Left', Manufacturer__c = 'TestManu',Model__c = 'TestModel', Serial_Number__c = '12345');
        insert hal;

        Hearing_Aids__c haa = new Hearing_Aids__c(Contact__c = con.ID, Class__c = 'Accessory', Ear__c = 'Left', Manufacturer__c = 'TestManu',Model__c = 'TestModel', Serial_Number__c = '12345');
        insert haa;
        
        ContractExtension ce = new ContractExtension(setCon);
        
        ce.hearingAidSelectionProceed();
        
        ce.getProductOptions();
        
        //ce.getPricebookEntries();
        
        ce.submit();

        List<Opportunity> opp = new List<Opportunity>([SELECT AccountId FROM Opportunity WHERE Contact__c= :con.ID AND CloseDate = Today]);
        
        List<OpportunityLineItem> oli = new List<OpportunityLineItem>([SELECT ID,Manufacturer__c,Model__c,Ear__c,Contact_related__c,OpportunityId FROM OpportunityLineItem WHERE Contact_related__c= :con.ID]);

        System.debug('debug line 1 Opp: '+opp+' Oli: '+oli);
        
        
        Opportunity opp1 = opp.get(0);
        
        OpportunityLineItem oli1 = oli.get(0);

        //update opp;

        //update oli;

        update con;

        System.debug('debug line 2 Opp: '+opp+' Oli: '+oli);
                
        System.assertEquals(hal.Manufacturer__c,oli1.Manufacturer__c);
        
        System.assertEquals(hal.Model__c,oli1.Model__c);

        System.assertEquals(hal.Ear__c,oli1.Ear__c);
        
        
    }
}
Best Answer chosen by Jean Grey 10
rajat Maheshwari 6rajat Maheshwari 6

Hi Jean,

Please use this under submit function : -

  opp.Contact__c = con.Id; 

Instead   opp.Contact__r.Id = con.Id;

Please let me know in cas eof any help :)

Thanks
Rajat Maheshwari
rajatzmaheshwari@gmail.com

All Answers

NahuelNahuel
Is 
opp.Name = updatedOpp.Contract__c;

ok? Name should be text but not sure what "Contract__c" in the Opportunity is.
Naval Sharma4Naval Sharma4
Can you try by updating your code as below?
/Create new opportunity
Opportunity opp = new Opportunity(); 
opp.AccountId = con.Account.Id; 
opp.Contact__c = con.Id; 
opp.Name = 'Test Opp'; 
opp.StageName = 'Closed Won'; 
opp.CloseDate = System.today();
 insert opp; ​

 
Jean Grey 10Jean Grey 10
Hi Naval, I tried that, still the same error.

Hi Nahuel, the Contract__c is an auto-number, could that be the problem?
rajat Maheshwari 6rajat Maheshwari 6

Hi Jean,

Please use this under submit function : -

  opp.Contact__c = con.Id; 

Instead   opp.Contact__r.Id = con.Id;

Please let me know in cas eof any help :)

Thanks
Rajat Maheshwari
rajatzmaheshwari@gmail.com

This was selected as the best answer