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
ch-sjoch-sjo 

New / updated product: add / update standard price list entry for all currencies

We are synchronizing products from an external system. We provide a price in a custom field (cost__c) and also the currency.

To be able to import pricelists in all currencies (we create one price list per sales channel), SalesForce requires that the price must exist in the same currency in the Standard Price List.

So - I'd like to do the following:
Whenever a product is added / updated - take the value in cost__c and the currency on the product. Create an entry for every currency in the list of active currencies in the Standard Price List.
NagendraNagendra (Salesforce Developers) 
Hi Chsjo,

Please check with the below idea from success community which might give you better understanding of handing the above requirement. Please let us know if you are looking anything in addition.

Best Regards,
Nagendra.P
ch-sjoch-sjo
Hi Nagendra,

Thank you very much for this. I did the "Excel-excersise" when I tried to understand how price lists works - so I am quite familiar with such process. I just need to transfer that process into an apex-implementation that triggers on "after insert, after update".

I will spend tomorrow to start trying to implement this and I will keep this thread updated (or use it to ask for help). I suspect that I am not the only one that would like to have this functionality.

Best Regards,
Christer
ch-sjoch-sjo
I have created something that seems to worok ok!

Guys, please take a look and scrutinize my code - please feel free to suggest improvements. I also need to write tests for this and think that it is tricky to do. I'd appreciate if someone would help me with this (I will of course try myself and post the result here).
 
trigger UpdateStandardPrices on Product2 (after insert, after update) {
    
    //Update the Standard price in all currencies from the Cost price on the Product. Cost Price is always in SEK
    //Create a PriceBookEntry if it's a new Product
    
    System.Debug('USP TRIGGER');
    
    //This trigger will cause recursion if it's not stopped. 
    //The TriggerMonitor class is static, and remains for the lifetime of the insert/update
    //This prevents recursion.
    string TriggerName = 'UpdateStandardPrices';
    if (!TriggerMonitor.ExecutedTriggers.contains(TriggerName))
    {       
        TriggerMonitor.ExecutedTriggers.add(TriggerName);
        
        // GET ALL DATA //
        Id PriceBookId = [SELECT Id From Pricebook2 WHERE IsStandard=TRUE].Id; 															//Get the ID of the Standard Price Boook
        list<CurrencyType> ActiveCurrencies = [SELECT ISOCode, ConversionRate FROM CurrencyType WHERE IsActive=TRUE]; 					//Get a list of all active currencies
        list<Product2> Products = new List<Product2>([SELECT Id, BP_Cost__c, CurrencyIsoCode FROM Product2 WHERE Id in :Trigger.new]);	//Get a list of all new entries
        
        for( Product2 product : Products)
        {
            
            list<PricebookEntry> loopList = new list<PricebookEntry>([Select Id, CurrencyISOCode FROM PricebookEntry WHERE PricebookEntry.Product2Id =: product.Id]); //Get a list of all entries in the Standard Price Book for the product id
            
            for(CurrencyType c : ActiveCurrencies)
            {
                
                integer currencyExists = 0;					//Reset the currency exists flag
                PricebookEntry price = new PricebookEntry();
                
                for(PricebookEntry l : loopList)		
                {											//Is there already an entry in the currency
                    if(l.CurrencyIsoCode == c.IsoCode)
                        currencyExists = 1;
                }
                
                
                if(currencyExists == 0)
                {											//Does not exist in this currency: Insert new StandardPrice
                    
                    price.UnitPrice = product.BP_Cost__c * c.ConversionRate; 
                    price.Product2Id = product.Id;
                    price.CurrencyISOCode = c.IsoCode;
                    price.Pricebook2Id = PriceBookId;
                    price.IsActive = TRUE;
                    insert price;
                }
                else
                {											//Exist in this currency: Update with new StandardPrice
                    for(PricebookEntry l : loopList)		
                    {										//Loop through to find the unique Id for the PricebookEntry
                        
                        if(l.CurrencyIsoCode == c.IsoCode)
                            price.Id = l.Id;
                    }
                    
                    price.UnitPrice = product.BP_Cost__c * c.ConversionRate;
                    price.IsActive = TRUE;
                    update price;
                }
            }
            
        }  
    }
}

 
ch-sjoch-sjo
Update on this - I have learnt that I am doing a big no-no by putting the "update price;" in the for loop (I get "System.LimitException: Too many DML statements: 151" when I try to update more than 13 products in a batch).

I have moved the "insert" to outside the for-loop, but I still get the same results if I push to many updates at once.... Any ideas? 
ch-sjoch-sjo
My code is probably not bulk-safe. I have moved the update outside the loop, but still get "System.LimitException: Too many DML statements: 151".

Any ideas?
 
trigger UpdateStandardPrices on Product2 (after insert, after update) {
    
    //Update the Standard price in all currencies from the Cost price on the Product. Cost Price is always in SEK
    //Create a PriceBookEntry if it's a new Product
    
    System.Debug('USP TRIGGER');
    
    //This trigger will cause recursion if it's not stopped. 
    //The TriggerMonitor class is static, and remains for the lifetime of the insert/update
    //This prevents recursion.
    string TriggerName = 'UpdateStandardPrices';
    if (!TriggerMonitor.ExecutedTriggers.contains(TriggerName))
    {       
        TriggerMonitor.ExecutedTriggers.add(TriggerName);
        
        // GET ALL DATA //
        Id PriceBookId = [SELECT Id From Pricebook2 WHERE IsStandard=TRUE].Id; 															//Get the ID of the Standard Price Boook
        list<CurrencyType> ActiveCurrencies = [SELECT ISOCode, ConversionRate FROM CurrencyType WHERE IsActive=TRUE]; 					//Get a list of all active currencies
        list<Product2> Products = new List<Product2>([SELECT Id, BP_Cost__c, CurrencyIsoCode FROM Product2 WHERE Id in :Trigger.new]);	//Get a list of all new entries
        list<PricebookEntry> resultList = new list<PricebookEntry>();																	//List to populate and update
        
        for( Product2 product : Products)
        {
            
            list<PricebookEntry> loopList = new list<PricebookEntry>([Select Id, CurrencyISOCode FROM PricebookEntry WHERE PricebookEntry.Product2Id =: product.Id]); //Get a list of all entries in the Standard Price Book for the product id
            
            for(CurrencyType c : ActiveCurrencies)
            {
                
                integer currencyExists = 0;					//Reset the currency exists flag
                PricebookEntry price = new PricebookEntry();
                
                for(PricebookEntry l : loopList)		
                {											//Is there already an entry in the currency
                    if(l.CurrencyIsoCode == c.IsoCode)
                        currencyExists = 1;
                }
                
                
                if(currencyExists == 0)
                {											//Does not exist in this currency: Insert new StandardPrice
                    
                    price.UnitPrice = product.BP_Cost__c * c.ConversionRate; 
                    price.Product2Id = product.Id;
                    price.CurrencyISOCode = c.IsoCode;
                    price.Pricebook2Id = PriceBookId;
                    price.IsActive = TRUE;
                    insert price;
                }
                else
                {											//Exist in this currency: Update with new StandardPrice
                    for(PricebookEntry l : loopList)		
                    {										//Loop through to find the unique Id for the PricebookEntry
                        
                        if(l.CurrencyIsoCode == c.IsoCode)
                            price.Id = l.Id;
                    }
                    
                    price.UnitPrice = product.BP_Cost__c * c.ConversionRate;
                    price.IsActive = TRUE;
                    resultList.add(price);
                }
            }
            
        }
        update resultList;
    }
}

 
ch-sjoch-sjo
Stupid me - I missed the "insert price;" row - It seems like it is working now....
iaestemaniaesteman

Hey ch-sjo can you provide with the full trigger fixed code with the batch please. I am having the same issue.
Thanks,

Darko

iaestemaniaesteman

And can you also provide the triggermonitor because I am getting this error when i am trying to save.

 

Error: Compile Error: Variable does not exist: TriggerMonitor.ExecutedTriggers at line 12 column 10