Tuesday, July 31, 2018

Trapped in Process fails with error 'The flow failed to access the value because it hasn't been set or assigned' WHILE IT IS NOT


If you have no idea about Known Issue : Process fails with error 'The flow failed to access the value because it hasn't been set or assigned' , it's worth to check it first then you might want to read this entry.
Issue : The user reports that when using Mass Edit to edit Opportunity it will prompt error

Can't Save Record

That's it. No sweet lovely sentence, no flowery and it's leave the mystery for us to dig out the root cause.Typical communication breakdown in love story.

Luckily we have email system whereby we got chance to get the exception email straight in our inbox.Here the error :


Error element myDecision (FlowDecision).
The flow failed to access the value for myVariable_current.Owner.UserRole.DeveloperName because it hasn't been set or assigned.

Just to clarify , yes we use process builder and we are aware of issue above whereby we need to put condition checking in proper order whenever our condition need to check value from other object.This is known issue described here.

A Process that makes a cross-object reference will fail when the foreign key (i.e. relationship field) the reference depends on is not populated.

Our process builder complied with the rules still it happening?

Why  error?

To test , I modified from condition based to formula well something like this.

AND(NOT(ISBLANK([Opportunity].Owner.UserRoleId  )) , OR (  [Opportunity].Owner.UserRole.DeveloperName ='Sales Manager' ,  [Opportunity].Owner.UserRole.DeveloperName ='APAC Manager'') ) 

and pray to God.

Unfortunately it's still happening and I am not able to get much information when Googling.
.
.
.

How the user input?
Using Mass Edit.

Is Process Builder does not support bulk?
Nope- process builder support bulkified .This is delivered in Winter 16. Plus the exception that we face nothing to do with limit.

What is MassEdit?
It is visualforce page that we installed long time ago.

Is it using customize controller?
No, it using standard controller.The save still same like standard, the only thing that different is the UI.No fancy code.
.
.
.
Click on Version Settings of visualforce page.
Version 15.
15...
Change to 42 and pray to God.

Success. No Error.

Yes, upgrade version can solve problem.It will be easier if the error message tell me something wrong with version.

Typical communication-breakdown =)

Thursday, July 05, 2018

Pricebook, Pricebook Entry and Product : Adding custom pricebook in Salesforce

Lately I worked on these object a lot and learned a lot of new things.

Some issues that we face around these object :
  • Some exceptions during data upload  such as :
    • FIELD_INTEGRITY_EXCEPTION .Message :field integrity exception: PricebookEntryId, unknown (versions 3.0 and higher must specify pricebook entry id, others must specify product id)
    • No Standard Price defined
  • Not able to retrieve standard price in test class


Understand the relationship of these object


Ignore Opportunity and Opportunity Line Item- these two object are using Price Book entry .Image credit to ForceTalk forum

PriceBook

  • Pricebook object store a list of products and services for sale.
  • A pricebook can be used in one or more different opportunities.
  • A pricebook has one or more different price entries.
  • Pricebook can be divided into type which are :
    •  Standard Price Book which is the master list of all the products and their default standard price.
    • Custom Price Book is separate list of product with custom price - called list price.


Product2

  • Product object is a catalogue of items or services for sales.
  • A product may contain one or more different sets of prices (PriceBookEntry).

PriceBookEntry

  • PricebookEntry object is a product entry in a pricebook.
  • This object allows products to be linked to standard price book or custom price book.
  • One price book entry is linked to only one product.
  • One price book entry can only appear in one pricebook.
  • One price book entry can be used in multiple line items. This also further creates flexibility for users to set their own prices.

Rules for Data Upload

  • PriceBookentry is junction object that connect Product and PriceBook so the order will be like this :
    • Insert PriceBook
    • Insert Product
    • Insert PriceBookEntry with PricebookId and Product Id

Scenario 1 : I am not able to insert PriceBookEntry for custom PriceBook.

We already have custom PriceBook and Product data inserted but we not able to insert PriceBookEntry to link these two objects

Reason : In order to insert PriceBookEntry for custom PriceBook , those Products must be added to Standard PriceBook first because Standard PriceBook is considered as master price. 

Refer knowledge articles here : 

Scenario 2 : Standard Price is not querable and insertable in test class

Well nothing I can do much because this how it works currently. But I can give some advice :

If the code contains SOQL on Pricebook make sure it get surrounded with try and catch. Add Test.isRunningTest() checking in the code and assign Standard Price Book.
If you have custom price you may want get an idea how to handle catch based on code below

 catch (Exception e){
   if(Test.isRunningTest()){
      List<Pricebook2>  listPB= [ select Id ,Name , IsStandard from Pricebook2 where Name ='Custom'  LIMIT 1];
      mapPriceBook.put('Standard',Test.getStandardPricebookId() );
      mapPriceBook.put('Custom',listPB[0].Id);
    
   }
 }

Also avoid retrieve and using PriceBook object but use Id.

Example of code that you want to avoid.Note that there is no way for you to get away with Test class exception because you only can use Test.getStandardPriceBookId() , not the whole object in test class.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
List<Pricebook2> listPB = [select Id ,Name , IsStandard from Pricebook2 where IsStandard = True OR  Name ='Custom'  LIMIT 2];

static  Map<String,Pricebook2> mapPriceBook =new Map<String,Pricebook2> ();

for(Pricebook2 pb : listPB){

if(pb.IsStandard){
  mapPriceBook.put('Standard',pb); //this will not get over the test class
}
else if(pb.Name =='Custom'){
 mapPriceBook.put('Custom',pb);
}

One way to be safe is using Id.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
List<Pricebook2> listPB = [select Id ,Name , IsStandard from Pricebook2 where IsStandard = True OR  Name ='Custom'  LIMIT 2];

static  Map<String,Id> mapPriceBook =new Map<String,Id> ();
             
             for(Pricebook2 pb : listPB){
             
               if(pb.IsStandard){
                  mapPriceBook.put('Standard',pb.Id);
               }
               else if(pb.Name =='Custom'){
                 mapPriceBook.put('Custom',pb.Id);
               }

I think that's all I can think today. I believe you also got some of tips and trick to get over exception related to these objects. Please let me know how you do that?

References