[SalesForce] DML Merge Fails INVALID_FIELD_FOR_INSERT_UPDATE

Question

Is there something special you need to do before merging a record in apex to avoid an INVALID_FIELD_FOR_INSERT_UPDATE DML exceptions? I'm not actually setting these fields, so why does the system care about them?

System.DmlException: Merge failed. First exception on row 0 with id
00QV0000007HzSvMAK; first error: INVALID_FIELD_FOR_INSERT_UPDATE,
Unable to create/update fields: Q_Calc_2__c, IsDeleted,
Lead_RFP_Calc__c, Q_Calc_Score__c, Lead_Quote_Score__c, IsConverted,
Q_Calc_1__c. Please check the security settings of this field and
verify that it is read/write for your profile or permission set.:
[Q_Calc_2__c, IsDeleted, Lead_RFP_Calc__c, Q_Calc_Score__c,
Lead_Quote_Score__c, IsConverted, Q_Calc_1__c]

Background

I'm writing a test method for some merge related functionality (trigger to prevent deleting leads if not merging). It's complaining that some fields are read only, but I'm a bit lost about why it's caring about those fields in the first place since I'm not setting them.

Code

@isTest
private static void testMergeAllowed() {
    User testUser = TestUtil.generateUser();
    testUser.ProfileId = TestUtil.STANDARD_PROFILE_ID;
    testUser.Allow_Delete_Lead__c = false;

    Lead testLead1 = TestUtil.generateLead();
    Lead testLead2 = TestUtil.generateLead();
    insert new Lead[] { testLead1, testLead2 };

    System.runAs(testUser) {
        try {
            merge testLead1 testLead2;
        } catch (Exception e) {
            System.assert(false, 'exception on merge: ' + e);
        }
    }
}
// Leads
public static Lead createLead() {
    Lead record = generateLead();
    insert record;
    return record;
}
public static Lead generateLead() {
    Lead record = (Lead) Lead.SObjectType.newSObject(null, true);
    record.LastName = generateRandomString(16);
    record.Company = generateRandomString(16);
    return record;
}

Best Answer

I'm not sure why, but the merge statement appears to be sensitive to the fields that are in memory for an sObject when passed to the merge statement. The operation fails if any of the fields are not updateable for the current user (e.g. audit fields, formula fields, field level security settings).

The above code is running into issues since the .newSObject(null, true) method populates default values for a lot of fields that must not be visible to the standard user in your test method. For the purposes of the test method you can just create a clone with just the id to perform the merge.

merge (new Lead(Id = testLead1.Id)) (new Lead(Id = testLead2.Id));

I haven't tested how the field values in memory affect the resulting merge, so you'll want to do some testing before adjusting for merge statements you're doing.

Related Topic