0

I am working on a requirement to create an opportunity and opportunity products , when there is an update on the asset object.

The asset object has a filed called Refresh_Asset_To__c, this is a lookup to the product object.

Basically each time I change the product on the Refresh_Asset_To__c, a new opportunity should be generated with the Refresh_Asset_To__c being the opportunity product.

I have tested , and its generating the opportunity , but each time i try to insert the opportunity product I get the error :

Update failed. First exception on row 0 with id 02i3B000003TAk7QAG; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AssetRefreshOpp: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: PricebookEntryId (pricebook entry currency code does not match opportunity currency code): [PricebookEntryId] Trigger.AssetRefreshOpp: line 56, column 1: []

This is my code:

trigger AssetRefreshOpp on Asset (after update) {
     Pricebook2 ikmBook    = [SELECT Id,CurrencyIsoCode FROM Pricebook2 WHERE Id = '01s46000003K1zXAAS'];

List<OpportunityLineItem> oppLiList = new List<OpportunityLineItem>();
Opportunity opp;
OpportunityLineItem oli;
string refeshed;

   List<asset> refreshedAss = [select Id,Contract__r.EndDate,OwnerId,quantity,Name,Refresh_Asset_To__c,Refresh_Asset_To__r.Id,AccountId,account.name from asset 
                                    where Id IN : Trigger.new 
                                    And Refresh_Asset__c = True];


       for(asset myAss:refreshedAss){


          // Create New Opportunity

            Opportunity newopp =new Opportunity();


newopp.Name=myAss.account.name + ' ' + 'refreshed';
newOpp.AccountId = myAss.AccountId;
newOpp.CloseDate = myAss.Contract__r.EndDate;
newOpp.StageName = 'Create';
newOpp.RecordTypeID = '01246000000TfMZAA0';
newOpp.OwnerId = myAss.OwnerId;
newOpp.Amount = 0;
newOpp.Type= 'Existing Business';
newOpp.OM_Order_Type__c = 'Regular';
newOpp.CurrencyIsoCode = ikmBook.CurrencyIsoCode;
newOpp.Pricebook2Id = ikmBook.Id;

insert newOpp;


       List<PriceBookEntry> priceBookList = [SELECT Id, Product2Id,CurrencyIsoCode, Product2.Id, Product2.Name FROM PriceBookEntry WHERE  PriceBook2.isStandard=true LIMIT 1];


            for(asset myAssets:refreshedAss){

             OpportunityLineItem oli = new OpportunityLineItem();

              oli.OpportunityId = newOpp.Id;

              oli.Product2Id = myAssets.Refresh_Asset_To__r.Id;

              oli.PriceBookEntryId = priceBookList[0].Id;

              oli.UnitPrice = 0;
              oli.Quantity = myAssets.Quantity;
              oppLiList.add(oli);

         }

         insert oppLiList;         

    }
} 
  • do not use hardcoded Ids – Santanu Boral Jan 9 '18 at 20:08
  • The only hard coded Id is for the opportunity record type. – Tony Curtis Jan 9 '18 at 20:09
  • You will also want to remove the DML and SOQL queries from the FOR Loop. – Bob Lopez Jan 9 '18 at 20:12
  • See here for Apex Best Practices (see #2 & #5) – Bob Lopez Jan 9 '18 at 20:17
  • ikmbook is also hardcoded. – DavidSchach Jan 9 '18 at 20:24
1

Unless the hard-coded PriceBook in your second line is the same as the Standard Price Book, this is going to fail. All the products in an Opportunity must be from the same Price Book, and you're querying a price book entry record from a price book that might not be the same as the hard-coded one.

Also, I don't think you need to specify the OLI Product2 field if you're specifying the PBE field. Salesforce will do that for you. As long as the priceBookList[0] record is the same product as the asset refers to (and I don't think you can guarantee that in your code) then you're fine. But as I see it, this is risky code. Simplify, and many of your problems will fall away.

| improve this answer | |
  • Thanks david, really appreciate your response. You hit it spot on with the line ; "As long as the priceBookList[0] record is the same product as the asset refers to (and I don't think you can guarantee that in your code)" How do I query in order to get the pricebook entry for the asset ? Thanks – Tony Curtis Jan 9 '18 at 20:38
  • You're very welcome! Feel free to mark my answer accordingly. – DavidSchach Jan 9 '18 at 20:39
  • How do I query in order to get the pricebook entry for the asset ? – Tony Curtis Jan 9 '18 at 20:53
  • 1
    Assets don't have PriceBookEntry records. However, if you know the product, the currency, and the pricebook, you can get the pricebookentry record in a query. The combination of product and currency are unique for a given pricebook. – DavidSchach Jan 9 '18 at 20:55
  • @TonyCurtis If the answer was sufficient, please mark it as accepted. – DavidSchach Jan 22 '18 at 20:17

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.