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
Siddharth LakhotiaSiddharth Lakhotia 

Trigger to throw an error message , when updating value of a Cloned Record

Hi,

I want to write a trigger, which throws error message , when the accountname is changed from the cloned version of record.

I have tried writting code, somehow its not working

Can someone help

Please find the code below : 

trigger PreventChangeOfAccountName on Order (before update , after insert) {
    
    for (Order o : trigger.new){
        
       If  (o.isClone() && trigger.oldmap.get(o.Id).AccountId <> trigger.oldmap.get(o.Id).AccountId)
       {
           o.addError('Account Name for Cloned records cant be changed');
       }
    }
}  
Best Answer chosen by Siddharth Lakhotia
Om PrakashOm Prakash
Hi ,

oldMAp is a map of IDs to the old versions of the sObject records.
This map is only available in update and delete triggers.
So we need to use getCloneSourceId() methods during clone.
Find  the sample code bellow for your above trigger:
 
trigger PreventChangeOfAccountName on Order (after insert) {
    
	Map<String, String> mapSourceOrderIdToAccount = new Map<String, String>();
    for (Order obj : trigger.new){
		mapSourceOrderIdToAccount.put(obj.getCloneSourceId(), null);
	}
	for(Order objOrder : [Select id, AccountId from Order where id in : mapSourceOrderIdToAccount.keySet() Limit 5000]){
		mapSourceOrderIdToAccount.put(objOrder.id, objOrder.AccountId);
	}
	
    for (Order o : trigger.new){
       If  (o.isClone() && mapSourceOrderIdToAccount.get(o.getCloneSourceId()) <> o.AccountId)
       {
		   
           o.addError('Account Name for Cloned records cant be changed');
       }
    }
}

 

All Answers

Om PrakashOm Prakash
Hello
trigger.oldmap is null in after insert, so null pointer exception will be throw from your code.
I suggest use the method getCloneSourceId() to get Source record ID then after soql query you can check if account is changed in clone record or not.
String SourceOrderId = o.getCloneSourceId();
Siddharth LakhotiaSiddharth Lakhotia
Can you explain in bit detail. 

Cant gather you...
Om PrakashOm Prakash
Hi ,

oldMAp is a map of IDs to the old versions of the sObject records.
This map is only available in update and delete triggers.
So we need to use getCloneSourceId() methods during clone.
Find  the sample code bellow for your above trigger:
 
trigger PreventChangeOfAccountName on Order (after insert) {
    
	Map<String, String> mapSourceOrderIdToAccount = new Map<String, String>();
    for (Order obj : trigger.new){
		mapSourceOrderIdToAccount.put(obj.getCloneSourceId(), null);
	}
	for(Order objOrder : [Select id, AccountId from Order where id in : mapSourceOrderIdToAccount.keySet() Limit 5000]){
		mapSourceOrderIdToAccount.put(objOrder.id, objOrder.AccountId);
	}
	
    for (Order o : trigger.new){
       If  (o.isClone() && mapSourceOrderIdToAccount.get(o.getCloneSourceId()) <> o.AccountId)
       {
		   
           o.addError('Account Name for Cloned records cant be changed');
       }
    }
}

 
This was selected as the best answer
Siddharth LakhotiaSiddharth Lakhotia
Hi Om,

It worked. ! Thanks a lot.

Can you suggest the rational behind using this statement

 mapSourceOrderIdToAccount.put(obj.getCloneSourceId(), null);
Om PrakashOm Prakash
Thanks for confirming. mapSourceOrderIdToAccount.put(obj.getCloneSourceId(), null) is used for putting all source record id as keys of map and later mapSourceOrderIdToAccount.keyset() is used in soql query of line 7. You can replace this by using a set as well. I have refilled this map later when we have account id too in line 8. As we know map only contains unique key so I reused map variable.
Siddharth LakhotiaSiddharth Lakhotia

Hi OmPrakash,

I am unable to cover for error message while trying to write Test class for this trigger.. Seems like, I am unable to fit the logic in try statement,


Please find the code below for my test class , Can you suggest some changes regarding this/


@isTest(SeeAllData = false)
public class preventChangeOfAccountNameTestClass {
    

    static testmethod void preventAccNameChange(){

Account acc = new Account();
        acc.name='TestAccount1';
        insert acc;
Order ord = new Order();
           ord.AccountId = acc.Id;
           ord.EffectiveDate = System.Today();
          ord.EndDate = System.Today()+5;
        ord.Status = 'NA';
        ord.Offer_Status__c = 'Open';
        
        insert ord;
      
        try{
            ord.isClone();
            update ord;
        }
        catch(DMLexception e){
           Boolean expectedExceptionThrown =  e.getMessage().contains('Account Name for Cloned records cant be changed') ? true : false;
           System.AssertEquals(expectedExceptionThrown, true);
    }
}
}

Om PrakashOm Prakash
Pls try bellow code in try block of your test method.
Account objNewAc = newAccount();
objNewAc.Name = ‘Test account record’;
insert objNewAc;

Order objNewOrder = ord.clone(false, true); //ord is instance of your test record Order
objNewOrder.AccountId= objNewAc.Id; 
insert objNewOrder;
Additionaly, I recommend to dont use see all data true in test class until it forcefully required in few cases.

Siddharth LakhotiaSiddharth Lakhotia
Hi Omprakash;

It worked!!! You are a genious...

Can you still tell me , how does it cover for .adderror message
Om PrakashOm Prakash
When objNewOrder was inserted in test method then trigger fired.

objNewOrder is cloned instance of order in your code (we used clone method) and we have mapped accountid = new account id.

If statement satisfied as per above statement and desire code covered.

Hope I explained well.
Let me know if any additional query.