2

I've seen some strange behaviour with the new ability to have trigger on OpportunityContactRole and its rather special IsPrimary field.

For a long time, I've observed that if you set IsPrimary=true on an OCR, then Salesforce takes care of setting it false for any other records on the same Opportunity. But, this produces weird results in the trigger context...

It seems that if I use this method to implicitly unset IsPrimary on an OCR, then later directly set IsPrimary=true, then the trigger context shows IsPrimary=true in both the old and new trigger lists.

Fortunately, I have code to explain all this more clearly.

There are two tests here, sharing the same setup code. In the first test, one OCR is primary and the other is not. In the second test, both OCRs are set to primary, so the second one implicitly wins. In both tests, we query back the OCRs after insert to check that the first has IsPrimary=false. And, in both tests, we store the results of that query in a static variable. The trigger asserts that IsPrimary is the same in Trigger.old as it is the static variable. For the second test, this assertion fails.

@IsTest
public class OpportunityContactRoleChangedTest {

    public static OpportunityContactRole afterInsert;

    private static Opportunity testOpportunity = new Opportunity(Name = 'Test Opp', CloseDate = Date.today(), StageName = 'Open');
    private static List<Contact> testContacts = new List<Contact> { new Contact(LastName = 'Test 1'), new Contact(LastName = 'Test 2') };
    private static List<OpportunityContactRole> testOpportunityContactRoles;

    static void setup() {
        insert testOpportunity;
        insert testContacts;

        testOpportunityContactRoles = new List<OpportunityContactRole> {
                new OpportunityContactRole(
                        OpportunityId = testOpportunity.Id,
                        ContactId = testContacts[0].Id,
                        IsPrimary = false
                ),
                new OpportunityContactRole(
                        OpportunityId = testOpportunity.Id,
                        ContactId = testContacts[1].Id,
                        IsPrimary = true
                )
        };
    }

    @IsTest
    static void succeeds() {
        setup();

        insert testOpportunityContactRoles;

        afterInsert = [SELECT IsPrimary FROM OpportunityContactRole WHERE Id = :testOpportunityContactRoles[0].Id];

        System.assertEquals(false, afterInsert.IsPrimary);

        testOpportunityContactRoles[0].IsPrimary = true;
        update testOpportunityContactRoles[0];
    }

    @IsTest
    static void fails() {
        setup();

        testOpportunityContactRoles[0].IsPrimary = true;

        insert testOpportunityContactRoles;

        afterInsert = [SELECT IsPrimary FROM OpportunityContactRole WHERE Id = :testOpportunityContactRoles[0].Id];

        System.assertEquals(false, afterInsert.IsPrimary);

        testOpportunityContactRoles[0].IsPrimary = true;
        update testOpportunityContactRoles[0];
    }
}

Trigger code:

trigger OpportunityContactRoleChanged on OpportunityContactRole (after update) {
    for(OpportunityContactRole ocr : Trigger.old) {
        System.assertEquals(OpportunityContactRoleChangedTest.afterInsert.IsPrimary, ocr.IsPrimary, ocr);
    }
}

So, I the question is: Is this a bug in SF? Or is it wrong to just go around setting IsPrimary without unsetting it elsewhere? Or have I made some silly mistake here?

  • perhaps explaining why it took so long for triggers to be enabled for OCR :-) – cropredy Oct 24 '19 at 1:03
0

Salesforce support investigated this for a few weeks, then found that it behaves as expected in Spring 20.

So, I guess this was a bug but they never found an internal bug reference.

| improve this answer | |

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.