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
MoggyMoggy 

pricebook entry currency code does not match opportunity currency code

I am tasked to force a product onto an opportunity while lead conversion, and in standard environment its an easy go, but with multi currency this seems to be a no go as it looks like that Salesforce internal referencing is at random.

I have created a map ( found something similar in the net ) where I hold the pricbookentry by isocode 
once a currency is chosen in the page , the product slection will be populated
that all works fine and i get only those products shwon which are available at a certain currency but if i then start the convert it throws at 98% the time the above error and if I system.debug i get show that 
Lead Currency equals the opportunity currency and also the pricebookentry currency but not the product currency
I also exported the pricebookentry and observed that the ID of the entry is unique against product pricebook and currency but the product id is for all currencies the same that is why i think that it might be an server interanl issue but who knows maybe i just misssed something
Can you have a look if i miss something here

here the piece where i collect all Pricebookentries  PBID is [select Id from Pricebook2 where isStandard=true]
private void popPBE(){
        PBISO = new Map<Id,Map<String,Map<Id,PriceBookEntry>>>();
        List<PriceBookEntry> opal = new List<PriceBookEntry>([SELECT Id, Name,PriceBook2Id, Product2Id, CurrencyIsoCode FROM PriceBookEntry WHERE
                                        PriceBook2Id =: PBID AND IsActive =: True AND IsDeleted =:False]);
        for(PriceBookEntry pri: opal)
        {
            if(!PBISO.containsKey(pri.PriceBook2Id))
            {
                PBISO.put(pri.PriceBook2Id,new Map<String,Map<Id,PriceBookEntry>>());
             }
            if(!PBISO.get(pri.PriceBook2Id).containsKey(pri.CurrencyIsoCode))
            {
              
               PBISO.get(pri.PriceBook2Id).put(pri.CurrencyIsoCode,new Map<Id,PriceBookEntry>());
             }
          
            PBISO.get(pri.PriceBook2Id).get(pri.CurrencyIsoCode).put(pri.Id,pri);
          
        }                               
    }

This seems to be ok as the products are correct populated in the selectOption as below

public void populateProducts() {
        products = new List<selectOption>();
        products.add(new SelectOption('None',' ',false));
        System.Debug('######## PBID=' + PBID + ' ##### ISOC=' + isoc + ' ##### ');  // this showed the correct Pricebook ID and the correct CurrencyIsoCode
        for(PriceBookEntry x: PBISO.get(PBID).get(isoc).values())
       {
           products.add(new SelectOption(x.id,x.Name));
          
       }
       
    }

Now when the product gets selected in the page, I do the following (as you can see  I tried 2 way, without success)

public PageReference productChanged() {
      //List<PriceBookEntry> priceBookList = [SELECT Id,Name, PriceBook2Id, Product2Id, CurrencyIsoCode FROM PriceBookEntry  
      //          WHERE     Id =: selectedProduct LIMIT 1];
     //OppItemID.PricebookEntryId = priceBookList[0].Id;
    OppItemID.PricebookEntryId = selectedProduct;
    
     return null;
     }

the currency selection is as follows and alredy needed a nasty trick to get this in the right direction
( I needed to update the lead record wth the selected currency if it was different to the original )

populate the diff currencies

private void popcurrency(){
        curre = new List<selectOption>();
        curre.add(new SelectOption('none','-NONE-',true));
        if(curren == null){
        curren = new List<CurrencyType>([SELECT Id, ISOCode FROM CurrencyType WHERE IsActive=:true]);
        }
        for(CurrencyType x: curren)
        {
          
            curre.add(new SelectOption(x.id,x.ISOCode));
        }
      }

change of the currency via page

public PageReference curreChanged() {  
     
  
   List<CurrencyType> ex = [SELECT ISOCode FROM CurrencyType WHERE Id=: Currencyselected LIMIT 1];
     this.Currencyselected = Currencyselected ;
     isoc =ex[0].ISOCode;
     leadConvert.CurrencyIsoCode=isoc;
    
     opportunityId.CurrencyIsoCode=isoc;
     system.debug('iso: ' + isoc);
    
     populateProducts();
     return null;
     }

this works all fine beside the fact the the final Product is not in the correct currency ???
and strange on this is theat the WHERE  Id =: selectedProduct within the productChange()
holds the correct ID of the correct PriceBookEntry record, I am a bit confused why the product then is not

Please help
Avidev9Avidev9
Can you filter your records by CurrencyIsoCode ?
MoggyMoggy
They are filtered in the Map 
PBISO.get(pri.PriceBook2Id).get(pri.CurrencyIsoCode).put(pri.Id,pri);
the put statement fills the last part of the map with the CurrencyIsoCode as Key
and when the products (pricebookentries) gets pupolated only the ones in the correct currncy gets shown
for(PriceBookEntry x: PBISO.get(PBID).get(isoc).values())
       {
           products.add(new SelectOption(x.id,x.Name));
         
       }

as you can see PBID is the ID of the Pricebook
and isoc is the CurrencyIsoCode

That if the user then selects a shown entry it will be the correct PriceBookEntry selected and be written onto the 
OpportunityLineItem by
OppItemID.PricebookEntryId = selectedProduct;
whereby the selectedProduct carries the ID of the PriceBookEntry

and this should be indeed the correct one as the following debugs shows, but as you can see on product it isn't 
System.Debug('LeadCurrency: ' + leaadconvert.CurrencyIsocode);  //as sample it showed CHF
System.Debug('OppCurrency: ' + opportunityId.CurrencyIsoCode);  //as sample it showed CHF
The following two I have done with the shown SQL above as one way to get the PriceBookEntry ID
System.Debug('PricebookentryCurrency: ' + priceBookList[0].CurrencyIsoCode); //as sample it showed CHF
System.Debug('ProductCurrency: ' + priceBookList[0].Product2.CurrencyIsoCode);  //as sample it showed GBP

If we look now onto a sample extraction ( via Data loader) of a PriceBookEntry you will understand my confusion as the selection above
takes the ID which is unique ?  

sample pricebookentrytable