Salesforce Lead Trigger CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY - triggers

I want to clone the Profile__c record. The lead has a profile__c associated with it. When conversion happens, the Profile_c on the lead is copied to the account created. What I need to do is a deep clone of the Profile__c on the new account created after the conversion. I am able to copy the profile_c over but cloning throws this error:
Error: System.DmlException: Update failed. First exception on row 0 with id 00QJ0000007dDmHMAU; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, profile: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_UPDATE_CONVERTED_LEAD, cannot reference converted lead: [] Trigger.profile:, column 1: [] (System Code)
trigger profile on Lead (after update) {
Map<Id, Lead> cl = new Map<Id,Lead>();
Lead parent;
List<Contact> clist = new List<Contact>();
Set<Id> convertedids = new Set<Id>();
//list of converted leads
for (Lead t:Trigger.new){
Lead ol = Trigger.oldMap.get(t.ID);
if(t.IsConverted == true && ol.isConverted == false)
{
cl.put(t.Id, t);
convertedids.add(t.ConvertedContactId);
}
}
Set<Id> leadIds = cl.keySet();
List<Profile__c> mp = [select Id, lock__c, RecordTypeId, reason__c, End_Date__c,startus__c , Opportunity__c, Account__c, Lead__c from Profile__c where Lead__c in :leadIds];
List<ID>AccountIDs = new List<ID>();
List<Profile__c>clonedList = new list<Profile__c>();
for (Profile__c mpi:mp){
parent = cl.get(mpi.Lead__c );
mpi.opportunity__c = parent.ConvertedOpportunityId;
mpi.account__c = parent.ConvertedAccountId;
AccountIDs.add(parent.ConvertedAccountId);
Profile__c profile = mpi.clone(false,true,false,false);
clonedList.add(profile);
mpi.lock__c= true;
mpi.reason__c= 'Converted';
}
update mp;
insert clonelist
}

You are doing insert operation(insert clonelist) in which you are accessing Converted lead Id value in a field. You can't use converted LeadId field in DML operations.
Below is the Sample code that will work-
trigger ConvertedLead_Trigger on Lead (after update) {
Map<Id, Lead> cl = new Map<Id,Lead>();
Lead parent;
List<Contact> clist = new List<Contact>();
Set<Id> convertedids = new Set<Id>();
//list of converted leads
for (Lead t:Trigger.new){
Lead ol = Trigger.oldMap.get(t.ID);
if(t.IsConverted == true && ol.isConverted == false)
{
cl.put(t.Id, t);
convertedids.add(t.ConvertedContactId);
}
}
Set<Id> leadIds = cl.keySet();
List<ConvertLeadTest__c> mp =[Select Id,Name,Lead__c, Account__c,Opportunity__c from ConvertLeadTest__c where Lead__c in :leadIds];
List<ConvertLeadTest__c> mp1=new List<ConvertLeadTest__c>();
List<ConvertLeadTest__c> mp2=new List<ConvertLeadTest__c>();
for(ConvertLeadTest__c cc:mp)
{
if(cl.containsKey(cc.Lead__c))
{
cc.Account__c=cl.get(cc.Lead__c).ConvertedAccountId;
cc.Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId;
mp1.add(cc);
mp2.add(new ConvertLeadTest__c(Account__c=cl.get(cc.Lead__c).ConvertedAccountId,Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId));
}
}
update mp;
insert mp2;
}
But if you write
ConvertLeadTest__c(Lead__c=cc.Lead__c,Account__c=cl.get(cc.Lead__c).ConvertedAccountId,Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId));
then it will throw error.
Hope this will help you.
Thanks :)

We are not able to perform any operation on the Lead once the lead is converted.
Anything you do to try o update the converted lead will give you error.

What eventually did it for me was after the conversion, I grabbed the convertedAccountIds. Since I was already copying Profile__c to the account after conversion, I just cloned the profile there and had to set the lead on that profile to null since it can't be updated

Related

Clone Opportunity records with all the fields without using standard clone() method?

I have try to clone Opportunity records and done till 3 fix field But I need for all fields.But without using clone() method.
Code -
public class Cloningwithout {
public static void insertclone(){
Opportunity opp = new Opportunity(Name='Opportunity2', CloseDate=date.parse('06/07/2012'),StageName='Prospecting');
insert opp;
ID Oppid =opp.ID;
clone1(Oppid);
}
public static void clone1(String IDs){
Opportunity sourceopp = [SELECT Id,Name,CloseDate,StageName from Opportunity Where Id=:IDs];
Opportunity targertopp = new Opportunity();
targertopp.Name = sourceopp.Name;
targertopp.CloseDate = sourceopp.CloseDate;
targertopp.StageName = sourceopp.StageName;
insert targertopp;
} }
maximum trigger depth exceeded
Your trigger runs after Opportunity is inserted. It inserts new opportunity, which causes the trigger to run, which inserts new opportunity... Until about 16 recursive operations, then SF terminates your action. Using clone() or not has nothing to do with it.
What are you trying to do, insert just once and then skip the trigger? You could have helper checkbox on Opportunity or a static variable
trigger CloneTrigger on Opportunity (after insert) {
static Boolean skip = false;
if(!skip){
skip = true;
Opportunity[] ls=new Opportunity[]{};
for(Opportunity o: trigger.new){
Opportunity obj=new Opportunity();
// obj.id = null;
obj.name=o.name;
obj.CloseDate = o.CloseDate;
obj.StageName = o.StageName;
ls.add(obj);
}
insert ls;
}
}

Test Class in apex

So i am new to salesforce and i finished my training and now im working on a project. But on my project i have stumbled on a test class that i am not finding a way to write it, so i would appreciate if anyone can help me figure out a way to write it. Here is the code:
public class AP01_Opportunity
{
//Method to create a new service contract when opportunity = Gagné
public static void CreateContract(List<Opportunity> listOpp, Map<Id, Opportunity> oldMap)
{
//Variable Declaration
ServiceContract sc;
List<ServiceContract> listSCToAdd = new List<ServiceContract>();
List<ContractLineItem> listContractItems = new List<ContractLineItem>();
List<Opportunity> listOppGagne = new list<Opportunity>();
//Loop in list of opportunities
for(Opportunity opp : listOpp)
{
if(opp.StageName == Label.ClotureGagne && !oldMap.get(opp.Id).isWon)
{
listOppGagne.add(opp);
}
}
//check if list has opportunity becoming won
if(listOppGagne.size() > 0){
Map<Id, Opportunity> mapOppGagne = new Map<Id, Opportunity> ([SELECT Id,
Name,
StageName,
Pricebook2Id,
Account.Name,
(SELECT Id,
PricebookEntryId,
PricebookEntry.Name,
Quantity,
UnitPrice
FROM OpportunityLineItems)
FROM Opportunity
WHERE Id in :listOppGagne]);
for( Opportunity opp : listOppGagne )
{
//Create new service contract
sc = new ServiceContract();
sc.Name = opp.Name;
sc.ApprovalStatus = Label.Activated;
sc.OpportunityId__c = Id.valueOf(opp.Id);
sc.Pricebook2Id = opp.Pricebook2Id;
sc.StartDate = Date.today();
listSCToAdd.add(sc);
}
if(listSCToAdd.size() > 0){
insert listSCToAdd;
Opportunity currentOpp;
ContractLineItem cli;
Id oppId;
for(ServiceContract servcont : listSCToAdd)
{
oppId = servcont.OpportunityId__c;
if(mapOppGagne.containsKey(oppId))
{
currentOpp = mapOppGagne.get(oppId);
//copy the oppLineItems per opportunity to the respective Service Contract
for(OpportunityLineItem items : currentOpp.OpportunityLineItems)
{
cli = new ContractLineItem();
cli.PricebookEntryId = items.PricebookEntryId;
cli.Quantity = items.Quantity;
cli.UnitPrice = items.UnitPrice;
cli.ServiceContractId = servcont.Id;
listContractItems.add(cli);
}
}
}
if(listContractItems.size() > 0)
{
insert listContractItems;
}
}
}
}
}
this code is a trigger that creates a new service contract record with contract line items copied from the opportunity line items, when the opportunity stage changes to "Cloturé Gagné" which means closed won in french.
Thank you in advance.
In order to write a simple test class I would recommend you to use the following guide: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_qs_test.htm
The idea is simple: Lets say you create an Opportunity in your Test class and make an insert or update in your case - your trigger class will automatically fire and run the code from your AP01_Opportunity class. You can put some
System.debug('some message');
to check if your logic works as expected and also which code blocks are executed

I've created trigger for below mentioned scenario and I want solution for that. - apex , salesforce

There is two object: Fund and opportunity. and opportunity object has a lookup of Fund. I've developed one trigger that sums up the total amount of all the relative opportunity and set that amount in a custom field of fund object. now a problem in my code is that whenever I try to create bulk opportunity using CSV file that contains data for multiple funds at that time it sums up the total of all fund and set that only in first record fund ID. I need a solution using Map.
Thank you.
Trigger:
trigger newLeadTrigger on Opportunity (after insert , after update, after delete , after undelete) {
if(trigger.isAfter && (trigger.isInsert || trigger.isUpdate || trigger.isUndelete)){
OpportunityCustomRollup.CountRollup(Trigger.new);
}
if(Trigger.isDelete)
{
OpportunityCustomRollup.CountRollup(Trigger.old);
}
}
Controller class:
public class OpportunityCustomRollup {
public static void CountRollup(List<Opportunity> lstOpportunity){
set<id> oppIds = new set<id>();
map<string, integer> classroomIDToDeskCountMap = new map<string, integer>();
id objrecordtypeid = [SELECT Id FROM RecordType WHERE DeveloperName ='Fund_Raising'].Id;
double amount = 0;
try {
for (Opportunity objOpportunity : lstOpportunity){
oppIds.add(objOpportunity.Fund__c);
}
Fund__c objfund = [SELECT Id, Total_opportunity_amount__c FROM Fund__c WHERE Id = :oppIds];
List<Opportunity> list_Opportunity = [SELECT Id, Amount FROM Opportunity WHERE Fund__c = :objfund.Id and StageName = 'Closed Won' and RecordTypeId =: objrecordtypeid];
for(Opportunity AmountOpportunity : list_Opportunity) {
amount += AmountOpportunity.amount;
}
objfund.Total_opportunity_amount__c = amount;
update objfund;
}
catch (Exception e) {
System.debug(e);
}
}
}
This should give you some ideas but you'll have to experiment a bit yourself. Edit your question with updated code and drop me a comment if you're still stuck.
// This is just for testing because when executing standalone apex code
// you don't have trigger.new. Modify the query as you want.
List<Opportunity> lstOpportunity = [SELECT Id
FROM Opportunity
WHERE StageName = 'Closed Won' and RecordType.DeveloperName = 'Fund_Raising'
LIMIT 10];
List<Fund__c> funds = new List<Fund__c>();
for(AggreateResult ar : [SELECT SUM(Amount) amt, Fund__c fund
FROM Opportunity
WHERE Id IN :lstOpportunity
AND StageName = 'Closed Won' and RecordType.DeveloperName = 'Fund_Raising'
AND Fund__c != null
GROUP BY Fund__c]){
Fund__c f = new Fund__c(
Id = (Id) ar.get('fund'),
Total_opportunity_amount__c = (Decimal) ar.get('amt')
);
funds.add(fund);
}
update funds;
P.S. Check this app on appexchange: https://appexchange.salesforce.com/appxListingDetail?listingId=a0N30000009i3UpEAI
I'm not affiliated with them but if you're an admin it might be easier to configure it than to write code, unit tests..

Trigger to copy image from child record to parent record

I am trying to write a trigger that will update a RTA field on a parent object with an image from a RTA field on the child object.
I am getting the below error when creating the child object
Apex trigger Updateparent caused an unexpected exception, contact your administrator: Updateparent: execution of AfterInsert caused by: System.StringException: Invalid id: (.....IMAGE IS DISPLAYED HERE....)External entry point.
Info
Man Utd is the child object
Account is the parent object
Image__c is the RTA field on the child object
Copy_image__c is the RTA field on accounts
Here is the trigger code
trigger Updateparent on Man_Utd_1__c (after insert, after update) {
Map<ID, Account> parentAccounts = new Map<ID, Account>();
List<Id> listIds = new List<Id>();
for (Man_Utd_1__c childObj : Trigger.new) {
listIds.add(childObj.Image__c);
}
parentAccounts = new Map<Id, Account>([SELECT id, (SELECT ID, Image__c FROM Man_Utd_s__r) FROM Account WHERE ID IN :listIds]);
for (Man_Utd_1__c manu : Trigger.new) {
Account myParentAccounts = parentAccounts.get(manu.Image__c);
myParentAccounts.Copy_image__c = manu.Image__c;
}
update parentAccounts.values();
}
Can anyone advise on how to rectify this or if it is even possible to do?
EDIT to answer comments
This one works for me, there's a slight modification around the null check. Give it a go? The field is called Image__c both on Account and Contact.
trigger rollupImage on Contact (after insert, after update) {
Set<Account> parents = new Set<Account>();
for (Contact child : trigger.new) {
if(child.AccountId != null && child.Image__c != null){
parents.add(new Account(Id = child.AccountId, Image__c = child.Image__c));
}
}
if(!parents.isEmpty()){
List<Account> toUpdate = new List<Account>();
toUpdate.addAll(parents);
update toUpdate;
}
}
ORIGINAL
The error
It's all written there ;)
List<Id> listIds = new List<Id>();
for (Man_Utd_1__c childObj : Trigger.new) {
listIds.add(childObj.Image__c); // boom happens here?
}
You're assigning rich text area value (very long string with encoded image in it) to Id variable (15 or 18 char special string)
Try like this:
Set<Id> ids = new Set<Id>(); // Set will ensure we won't have duplicate values
for (Man_Utd_1__c childObj : Trigger.new) {
ids.add(childObj.Account__c);
}
Optimization - round 1
In the second loop you're setting the Copy_Image__c field but on the local copy of Account (local variable in the scope of the loop). I'm not sure setting it there will propagate the change to the parent acc (it might be a full copy and not a reference to the item in the map. You could put it back (parentAccounts.put(manu.Account__c, myParentAccounts)) to the map or just do the image assignment directly:
parentAccounts = new Map<Id, Account>([SELECT id FROM Account WHERE ID IN :ids]);
// I've removed the subquery, you don't need it, right?
for (Man_Utd_1__c manu : Trigger.new) {
if(parentAccounts.containsKey(manu.Account__c)){
parentAccounts.get(manu.Account__c).Copy_image__c = manu.Image__c;
}
}
update parentAccounts.values();
Optimization - round 2
It looks bit stupid - we query for Accounts but all we need to fetch is the Id... But we know the Id already, right? So - behold this "pro trick" (shared just because my colleague is a big fan of Man U ;))
trigger Updateparent on Man_Utd_1__c (after insert, after update) {
Set<Account> parents = new Set<Account>();
for (Man_Utd_1__c child : trigger.new) {
if(child.Account__c != null){
parents.add(new Account(Id = child.Account__c, Copy_Image__c = child.Image__c));
}
}
if(!parents.isEmpty()){
List<Account> toUpdate = new List<Account>();
toUpdate.addAll(parents);
update toUpdate;
}
}
Note: Optimization is the key thing while writing trigger.
While writing trigger make sure you follow all the best practises:
Keynotes On Trigger:
OPTIMIZATION - I have specified it in Uppercase and in first line because its the key thing while writing logic
Proper indentation and code commenting, so that anyone who works on the same code will easily understand the logic by just glancing on the comments. Make sure you update lastModifiedBy line on initial comments so that it will be helpful to keep a trace who worked last/updated last and on what date. Better keep proper code comments on every line- IF NEEDED ONLY
Variables with proper names ex: if var of list type then 'lst' prefix or 'List' postfix and then the proper name ex: lstContactsToInsert OR lstContactsToUpdate
Always create a seperate handler class and don't write all the logics on trigger itself 'AS A BEST PRACTISE TO FOLLOW'
Have proper trigger contexts. Know when to use proper trigger contexts through salesforce documentations on trigger. Use 'Before' contexts if it can be handled using this, If Not then go for 'After' contexts so you limit DML's.
Keynotes On Handler:
The First 3 steps as mentioned for trigger applies here as well
Use common private methods where you write logic and use it in other methods
Keynotes On TestClass:
Always write a test class utilizing 'GENERIC TEST DATA CLASS' in your test class.
Use proper test method names like: test_Method_One 'OR' testImageUpdates as such
Use asserts and test all usecases - Both negative and positive tests
#1. Trigger
/**
* #TriggerName : ContactTrigger
* #CreatedBy : Rajesh Kamath
* #CreatedOn : 30-Nov, 2016
* #Description : Trigger to update the image on parent object 'Account' based on the child object 'Contact'
* #LastModified: None
*/
trigger ContactTrigger on Contact(after insert, after update) {
//Instantiate the handler class
ContactTriggerHandler objContactHandler = new ContactTriggerHandler();
/* Trigger Context */
if(Trigger.isAfter) {
//Fire on Insert
if(Trigger.isInsert) {
objContactHandler.onAfterInsert(trigger.new);
}
//Fire on Update
if(Trigger.isUpdate) {
objContactHandler.onAfterUpdate(trigger.new, trigger.oldMap);
}
}
}
#2. Handler
/**
* #HandlerName : ContactTriggerHandler
* #TriggerName : ContactTrigger
* #TestClassName : ContactTriggerHandlerTest [Make sure you create this with the steps at the end of this handler]
* #CreatedBy : Rajesh Kamath
* #CreatedOn : 30-Nov, 2016
* #Description : Trigger to update the image on parent object 'Account' based on the child object 'Contact'
* #LastModified: None
*/
public with sharing class ContactTriggerHandler {
/*
#MethodName : onAfterInsert
#Parameters : List<Contact> lstNewContactRecords
#LastModifiedBy : None [Make sure when anyone updates even this line will be updated for help for other users who work on later phase]
*/
public void onAfterInsert(List<Contact> lstNewContactRecords){
//Call a common method where we have logic
reflectChildImageOnParent(lstNewContactRecords, null);
}
/*
#MethodName : onAfterUpdate
#Parameters : List<Contact> lstContactRecords, Map<Id, Contact> mapOldContactRecords
#LastModifiedBy : None [Make sure when anyone updates even this line will be updated for help for other users who work on later phase]
*/
public void onAfterUpdate(List<Contact> lstContactRecords, Map<Id, Contact> mapOldContactRecords){
//Call a common method where we have logic
reflectChildImageOnParent(lstContactRecords, mapOldContactRecords);
}
/*
#MethodName : reflectChildImageOnParent
#Parameters : List<Contact> lstContactRecords, Map<Id, Contact> mapOldContactRecords
#LastModifiedBy : None [Make sure when anyone updates even this line will be updated for help for other users who work on later phase]
*/
private static void reflectChildImageOnParent(List<Contact> lstContactRecords, Map<Id, Contact> mapOldContactRecords){
/* Local variable declaration */
List<Account> lstAccountsToUpdate = new List<Account>();
for(Contact objContact : lstContactRecords) {
//Execute on insert and update
if((Trigger.isInsert || (Trigger.isUpdate && objContact.Child_Image__c != mapOldContactRecords.get(objContact.Id).Child_Image__c)) && objContact.Account__c != null) {
//List of accounts to update
lstAccountsToUpdate.add(new Account(Id = objContact.Account__c, Parent_Image__c = objContact.Child_Image__c));
}
}
//Update the account records
if(!lstAccountsToUpdate.isEmpty()) {
update lstAccountsToUpdate;
}
}
}
This can be referred for your usecase.
Please mark as 'Best Answer' if this was helpful
loyalty - Child Obj
fields:
lightingdata__Contact__c (relationship)
lightingdata__imagenims__c // Image field
Contact - Parent Obj
field: lightingdata__Imagefromloyalty__c
trigger loyaltytocon on Loyalty__c (after insert, after update) {
Map<id, Contact> conlist;
List<Id> idlist=new List<id>();
for (Loyalty__c loy:trigger.new) {
idlist.add(loy.lightingdata__Contact__c);
}
conlist= new Map<id, contact>([select id, lightingdata__Imagefromloyalty__c from contact where id In : idlist]);
for(Loyalty__c lo:trigger.new){
contact con = conlist.get(lo.lightingdata__Contact__c) ;
system.debug('con data' + con);
con.lightingdata__Imagefromloyalty__c = lo.lightingdata__imagenims__c;
}
update conlist.values();
}
In pareant object field it will return that image filed have URL.
Then you can create one formula filed and just refer (lightingdata__Imagefromloyalty__c) in formul it will display the image.

Apex Trigger to Update Contact from Custom Object

Long story short, I need to update a custom field in my standard Contact, that fires after a different, unrelated Custom Object is updated. I've tried to write a trigger that passes the field value from my Custom Object to the Contact, but I keep getting a variety of errors - the most recent of which has stumped me. The end goal is to update Passing__c from Passing_Field__c.
I'm getting an unexpected Token: "(" error on the for(Contact C: line. It is literally so simple I cannot figure it out.
Here is my code below. I've simplified the naming convention to try and make it more relatable. Any help is appreciated. I'm pretty new to Apex and Triggers, and I've been at this for a couple of hours now, hopefully some advice can send me to 'home plate'.
trigger ContactUpdater on Custom_Object_Name__c (after update) {
List<Contact> updatedContacts = new List<Contact>();
Set<Id> ObjectIds = new Set<Id>();
Set<String> ObjectCont = new Set<String>();
Set<Boolean> ObjectActive = new Set<Boolean>();
Set<String> ObjectPass = new Set<String>();
for(Custom_Object_Name__c p : trigger.new)
{
If(p.Active__c == true){
ObjectIds.add(p.Id);
ObjectCont.add(p.Contact__c);
ObjectActive.add(p.Active__c);
ObjectPass.add(p.Passing_Field__c);
}
try{ for(Contact c : [SELECT Id, Passing__c FROM Contact WHERE (AccountId IN (Select Account__c from Custom_Object_Name__c )) AND ObjectActive = true])
{
set(c.Passing__c = p.Passing_Field__c);
c.FieldToUpdate = c.Passing__c;
updatedContacts.add(c);
}
update updatedContacts;
}
catch(exception e){
throw e;
}
}
}
Notes: Active__c is a checkbox. Passing__c and Passing_Field__c are both text boxes.
I believe the issue is in the WHERE clause of your SOQL query:
WHERE (AccountId = (Select Account__c from Custom_Object_Name__c ))
Salesforce is expecting you to compare AccountId to an Id of some sort, rather than the results of some subquery. You probably want to try something like:
WHERE (AccountId in (Select Account__c from Custom_Object_Name__c))