1

I am creating a ContractLineItem record on the creation of ServiceContract by using a trigger. Below is the error I am getting

Error: Invalid Data. Review all error messages below to correct your data. Apex trigger CreatingControlLineItems caused an unexpected exception, contact your administrator: CreatingControlLineItems: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, The price book entry is in a different price book than the one assigned to the Service Contract, or Service Contract has no price book assigned.: Price Book Entry ID: [PricebookEntryId]: Trigger.CreatingControlLineItems: line 30, column 1

Here is the trigger which I have written:

trigger CreatingControlLineItems on ServiceContract (after insert)
{
List<ContractLineItem> toinsertCLT = NEW List<ContractLineItem>();
MAP<id,ServiceContract> mapTriggerNew = NEW MAP<id,ServiceContract>();
MAP<string,string> mapProdwithPBE = NEW MAP<string,string>();
SET<String> productIDS = NEW SET<String>();
for(ServiceContract sc : [SELECT Id,Pricebook2Id,Product__c FROM ServiceContract WHERE Id IN: trigger.new])
{
    mapTriggerNew.put(sc.Id,sc);
    productIDS.add(sc.Product__c);
}
system.debug('mapTriggerNew - ' +mapTriggerNew);
for(PricebookEntry pbe : [SELECT Id,Name,Pricebook2Id,Product2Id FROM PricebookEntry WHERE Product2Id IN: productIDS])
{
    mapProdwithPBE.put(pbe.Product2Id,pbe.id);
}
system.debug('mapProdwithPBE - ' +mapProdwithPBE);
for(ServiceContract sc : mapTriggerNew.values())
{
    ContractLineItem cli = New ContractLineItem();
    cli.ServiceContractid = sc.Id;
    cli.PricebookEntryId = mapProdwithPBE.get(sc.Product__c);
    //cli.Product2Id =sc.Product__c;
    cli.Quantity = 1.00;
    cli.Description = 'test';
    cli.UnitPrice = 0.00;
    toinsertCLT.add(cli);
}
system.debug('toinsertCLT - ' +toinsertCLT);
insert toinsertCLT;
}

Why do I get this error? How can I fix it?

  • 2
    1) You need to verify that the ServiceContract was saved with a Pricebook2Id and 2) you need to query for that ServiceContract.Pricebook2Id to locate the PricebookEntry(s) for the specific Product2 that each lineItem corresponds to – cropredy Apr 17 at 18:31
  • @cropredy I have tried as said but ContractLineItem is getting Inserted. – Code hunter Apr 19 at 17:31
  • I have edited the code, please check – Code hunter Apr 19 at 17:32
1

Try this - untested

allows for

  • ServiceContracts without Pricebook2Id
  • Multiple Pricebooks sharing the same Product2Id

does not allow for multiple currencies but extension should be straightforward

I renamed some variables to be clearer

trigger CreatingControlLineItems on ServiceContract (after insert) {}

    // collection to insert in bulk
    ContractLineItem[] contractLineItems = NEW List<ContractLineItem>();

    // Lookup map to find the right PBE in bulk manner
    Map<Id,Map<Id,PriceboookEntry> PbesByPriceBookIdByProductId = new Map<Id,Map<Id,PricebookEntry>>();

    // Search keys
    Set<Id> productIdS = new Set<Id>();
    Set<Id> pricebook2Ids = new Set<Id>();

    for(ServiceContract sc  : trigger.new]){
        if (sc.Pricebook2Id == null) {continue;}
        productIDS.add(sc.Product__c);
        pricebook2Ids.add(sc.Pricebook2Id);
    }

    //  Trigger batch could have service contracts with different pricebooks
    //  And a given product2Id could be on multiple pricebooks
    //  So we need a map of Product2Id => map <PriceBook2Id, PricebookEntry>
    for(PricebookEntry pbe : [SELECT Id,Name,Pricebook2Id,Product2Id 
       FROM PricebookEntry 
       WHERE Product2Id IN: productIdS AND
             Pricebook2Id IN : pricebook2Ids]){
        if (PbesByPriceBookIdByProductId.containsKey(pbe.Product2Id) {
            PbesByPriceBookIdByProductId.get(pbe.Product2Id}.put(pbe.Pricebook2Id,pbe));
        }
        else {
            PbesByPriceBookIdByProductId.put(pbe.Product2Id,
                    new Map<Id,PricebookEntry> {pbe.Pricebook2Id => pbe});
        }
    }
    // Build the lineItems using the correct PBE that matches parent's PricebOOk2Id and custom
    //  field Product__c
    for(ServiceContract sc : Trigger.new) {
        if (sc.Pricebook2Id == null) {continue;}
        contractLineItems.add( new ContractLineItem (
            ServiceContractid = sc.Id,
            PricebookEntryId = PbesByPriceBookIdByProductId.get(sc.Product__c).get(sc.Pricebook2Id).Id,
            Quantity = 1.00,
            Description = 'test',
            UnitPrice = 0.00));

    }
    insert contractLineItems;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.