0

I am writing custom before insert validation rules into a Case trigger to check fields on Account when a related Case is created.

When running my test classes they all pass which leads me to believe I missed something, however it is far from obvious to me.

Making a new Case record from my own System Admin profile, no issue is encountered and the record is created successfully when testing a known good record.

When logged in as my QA user which has Modify All on Account and Case I am getting the NPE on all of the if(bool) lines in the Validate_____() functions, going down the line from Name, to Gender if Name is commented out, to DOB if Name and Gender are commented out, etc. All on the same record as the prior test from Sys Admin profile.

From main function called by trigger helper (trigger.new goes in as caseList)

public static Map<Id, Case> acctIdToCaseMap = new Map<Id, Case>();
public static Map<Account, Case> acctCaseMap = new Map<Account, Case>();

public static void SyncValidation(List<Case> caseList){
    for (Case c : caseList){acctIdToCaseMap.put(c.AccountId, c);}
    
    List<Account> accts = [SELECT Id,FirstName,LastName,Patient_Gender__c,
                                  HealthCloudGA__Gender__pc,Patient_Birthdate__c,PersonBirthdate,
                                  PersonMailingCountry,PersonMailingState,PersonMailingCity,isPersonAccount
                           FROM Account 
                           WHERE Id IN : acctIdToCaseMap.keyset()];
    
    Map<Id,Account> acctsMap = new Map<Id,Account>(accts);
    
    for (Case c : caseList){
        acctCaseMap.put(acctsMap.get(c.AccountId), c);
    }
    for (Account a : acctCaseMap.keySet()){
        ValidatePatient(a, acctCaseMap.get(a));
    }
}

static void ValidatePatient(Account a, Case c){
    ValidateName(a, c);
    ValidateGender(a, c);
    ValidateDOB(a, c);
    ValidateMailingCountry(a, c);
    ValidateMailingState(a, c);
}

static void ValidateName(Account a){
    system.debug('Record FirstName: ' +a.FirstName); //confirmed account record is passed into function with expected values
    if (String.isBlank(a.FirstName)){
        c.addError('Care Plan not ready to sync. Confirm data in Patient FirstName.');
    }
}
static void ValidateDOB(Account a){
    system.debug(a); //confirmed account record is passed into function with expected values
    Boolean bDay1empty = String.isEmpty(String.valueOf(a.Patient_Birthdate__c));
    Boolean bDay2empty = String.isEmpty(String.valueOf(a.PersonBirthdate));
    if (bDay1empty || bDay2empty){
        c.addError('Care Plan not ready to sync. Confirm data in Patient Birthdate.');
    }
}
static void ValidateGender(Account a){
    system.debug(a); //confirmed account record is passed into function with expected values
    List<String> validGenders = getGenderValuesList();
    if (!validGenders.contains(a.Patient_Gender__c) 
        || !validGenders.contains(a.HealthCloudGA__Gender__pc)){
        c.addError('Care Plan not ready to sync. Confirm data in Patient Gender.');
    }
}
static void ValidateMailingCountry(Account a){
    system.debug(a);
    String validCountries = 'USA:US:United States:PR:Puerto Rico';
    if (!validCountries.contains(a.PersonMailingCountry)){
        c.addError('Care Plan not ready to sync. Confirm data in Patient Mailing Country.');
    }
}
static void ValidateMailingState(Account a){
    system.debug(a);
    String validStates = 'AL:AK:AZ:AR:CA:CO:CT:DE:DC:FL:GA:HI:ID:' +
                         'IL:IN:IA:KS:KY:LA:ME:MD:MA:MI:MN:MS:MO:MT:NE:NV:NH:' + 
                         'NJ:NM:NY:NC:ND:OH:OK:OR:PA:RI:SC:SD:TN:TX:UT:VT:VA:' +
                         'WA:WV:WI:WY:PR';
    if (!validStates.contains(a.PersonMailingState)){
        c.addError('Care Plan not ready to sync. Confirm data in Patient Mailing State.');
    }
}

Test methods

@testSetup static void setupMethod(){
    //Allow errors which may exist in historic records
    Automation_Settings__c setting = new Automation_Settings__c();
    setting.Disable_Patient_ProcessBuilder__c = TRUE;
    setting.Disable_Alayacare_Sync_Validation_Rules__c = TRUE;
    insert setting;
}

@isTest static void testStateValidation(){
    //ValidateMailingState
    //patient setup
    Account a2 = testAccountSetup(2);
    Account tca = testCustomerAccountSetup();
    Contact tcc = testCustomerContactSetup(tca);
    a2.PersonMailingState = 'MM'; //known invalid value
    update a2;
    //case setup
    Case c2 = testCaseSetup(a2, tca, tcc);
    Test.startTest();
    try {
        insert c2;
    } catch (Exception e) {
        Boolean expectedErrorMessage = e.getMessage().contains('Patient Mailing State')? true : false;
        system.assert(expectedErrorMessage);
    }        
    Test.stopTest();
}
@isTest static void testCountryValidation(){
    //ValidateMailingCountry
    //patient setup
    Account a3 = testAccountSetup(3);
    Account tca = testCustomerAccountSetup();
    Contact tcc = testCustomerContactSetup(tca);
    a3.PersonMailingCountry = 'Unitedstaztes'; //known invalid value
    update a3;
    //case setup
    Case c3 = testCaseSetup(a3, tca, tcc);
    Test.startTest();
    try {
        insert c3;
    } catch (Exception e) {
        Boolean expectedErrorMessage = e.getMessage().contains('Patient Mailing Country')? true : false;
        system.assert(expectedErrorMessage);
    }        
    Test.stopTest();
}
@isTest static void testDOBValidation(){
    //patient setup
    Account a4 = testAccountSetup(4);
    Account tca = testCustomerAccountSetup();
    Contact tcc = testCustomerContactSetup(tca);
    a4.Patient_Birthdate__c = null;
    a4.PersonBirthdate = null;
    update a4;
    //case setup
    Case c4 = testCaseSetup(a4, tca, tcc);
    Test.startTest();
    try {
        insert c4;
    } catch (Exception e) {
        Boolean expectedErrorMessage = e.getMessage().contains('Patient Birthdate')? true : false;
        system.assert(expectedErrorMessage, e.getMessage());
    }        
    Test.stopTest();
}
@isTest static void testGenderValidation(){
    //ValidateGender
    //patient setup
    Account a5 = testAccountSetup(5);
    Account tca = testCustomerAccountSetup();
    Contact tcc = testCustomerContactSetup(tca);
    a5.Patient_Gender__c = '';
    a5.HealthCloudGA__Gender__pc = '';
    update a5;
    //case setup
    Case c5 = testCaseSetup(a5, tca, tcc);
    Test.startTest();        
    try {
        insert c5;
    } catch (Exception e) {
        Boolean expectedErrorMessage = e.getMessage().contains('Patient Gender')? true : false;
        //system.assert(expectedErrorMessage);
        system.assert(expectedErrorMessage, e.getMessage());
    }        
    Test.stopTest();
    
}

@isTest static void testNameValidation(){
    //ValidateName
    //patient setup
    Account a6 = testAccountSetup(6);
    Account tca = testCustomerAccountSetup();
    Contact tcc = testCustomerContactSetup(tca);
    a6.FirstName = '';
    update a6;
    //case setup
    Case c6 = testCaseSetup(a6, tca, tcc); 
    Test.startTest();
    try {
        insert c6;
    } catch (Exception e) {
        Boolean expectedErrorMessage = e.getMessage().contains('Patient FirstName')? true : false;
        system.assert(expectedErrorMessage, e.getMessage());
    }
    Test.stopTest();
}

1 Answer 1

0

If, for some reason, there is no account, you'd get a NullPointer exception. So, it'd be helpful to check if you have an account before validating:

public static void syncValidation(Case[] records) {
    Set<Id> accountIds = new Set<Id>();
    for(Case caseRecord: records) {
        accountIds.add(caseRecord.AccountId);
    }
    Map<Id, Account> accounts = new Map<Id, Account>([
        SELECT FirstName, LastName, 
            Patient_Gender__c, HealthCloudGA__Gender__pc, 
            Patient_Birthdate__c, PersonBirthdate,
            PersonMailingCountry, PersonMailingState, PersonMailingCity,
            isPersonAccount
        FROM Account
        WHERE Id = :accountIds
    ]);
    for(Case caseRecord: records) {
        Account caseAccount = accounts.get(caseRecord.AccountId);
        if(caseAccount == null) {
            continue;
        }
        ValidateName(caseAccount, caseRecord);
        ValidateGender(caseAccount, caseRecord);
        ValidateDOB(caseAccount, caseRecord);
        ValidateMailingCountry(caseAccount, caseRecord);
        ValidateMailingState(caseAccount, caseRecord);
    }
}

I also cleaned up the initial bits; it is a bad idea to map by account to a case, because this will cause problems in bulk. Namely, if two cases happen to enter this trigger at once, only one will be validated. Therefore, we just need a map of the accounts.

Also, the parameters in your validate method don't line up, so your deploy would have failed. Make sure that your parameter lists have the same number of parameters and data types.

3
  • Thanks for the help with cleanup, I see what you mean. However the issue I am encountering is how the Account can be null. I am querying the account based on the ID in the required AccountId field and in all my testing I am unable to manually reproduce via code. Using the above snippet simply skips all validation functions because account is null when the trigger fires via record creation in the UI.
    – JaredT
    May 16, 2023 at 20:08
  • ... only for non-system admin users, despite having modify all for both Account and Case.
    – JaredT
    May 16, 2023 at 20:23
  • @JaredT Out of context, it's hard to tell. Maybe another process is clearing out the account Id field? Or perhaps it's even because the contact you're assigning to the case does not have an Account Id?
    – sfdcfox
    May 16, 2023 at 21:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .