You need to sign in to do that
Don't have an account?
Trigger/Class not firing on some records in an insert/update import to custom object feature
I just created an architecture for central trigger processing based on Dan Appleman's book, 'advanced apex programming'. It works fine unless I use the standard feature, imprort custom object where the import has a mix of inserts and updates based on an external ID. If the list is all inserts or all updates the trigger fires for all records. When it is a mix of the two it only fires for the inserts. The updates will have their records updated as the spreadsheet says but the trigger won't fire.
Central Dispatch class
--------------------------
<pre>
public class Dispatch{
Public Interface ITriggerEntry{
void MainEntry(Boolean IsUpdate, Boolean IsInsert,
Boolean IsDelete, Boolean IsExecuting,
Boolean IsBefore, Boolean IsAfter,
LIST<sObject> NewList, Map<Id,sObject> NewMap,
LIST<sObject> OldList, MAP<Id,sObject> OldMap);
void InProgressEntry(Boolean IsUpdate, Boolean IsInsert,
Boolean IsDelete, Boolean IsExecuting,
Boolean IsBefore, Boolean IsAfter,
LIST<sObject> NewList, Map<Id,sObject> NewMap,
LIST<sObject> OldList, MAP<Id,sObject> OldMap);
}
Public Static ITriggerEntry activeclass = null;
Public Static Void FrontDoor(String TriggerObject, Boolean IsUpdate, Boolean IsInsert, Boolean IsDelete, Boolean IsExecuting, Boolean IsBefore, Boolean IsAfter, LIST<sObject> NewList, Map<Id,sObject> NewMap, LIST<sObject> OldList, MAP<Id,sObject> OldMap){
If(activeclass != null){
activeclass.InProgressEntry(IsBefore,IsDelete,IsAfter,IsInsert,IsUpdate,IsExecuting,NewList,NewMap,OldList,OldMap);
return;
}
If(TriggerObject == 'CPM_Contract__c'){
IF(IsAfter && (IsInsert || IsUpdate)){
activeclass = new CPMeContractProcess();
activeclass.MainEntry(IsUpdate, IsInsert, IsDelete, IsExecuting, IsBefore, IsAfter, NewList, NewMap, OldList, OldMap);
}
}
}
}
</pre>
Central Dispatch class
--------------------------
<pre>
public class Dispatch{
Public Interface ITriggerEntry{
void MainEntry(Boolean IsUpdate, Boolean IsInsert,
Boolean IsDelete, Boolean IsExecuting,
Boolean IsBefore, Boolean IsAfter,
LIST<sObject> NewList, Map<Id,sObject> NewMap,
LIST<sObject> OldList, MAP<Id,sObject> OldMap);
void InProgressEntry(Boolean IsUpdate, Boolean IsInsert,
Boolean IsDelete, Boolean IsExecuting,
Boolean IsBefore, Boolean IsAfter,
LIST<sObject> NewList, Map<Id,sObject> NewMap,
LIST<sObject> OldList, MAP<Id,sObject> OldMap);
}
Public Static ITriggerEntry activeclass = null;
Public Static Void FrontDoor(String TriggerObject, Boolean IsUpdate, Boolean IsInsert, Boolean IsDelete, Boolean IsExecuting, Boolean IsBefore, Boolean IsAfter, LIST<sObject> NewList, Map<Id,sObject> NewMap, LIST<sObject> OldList, MAP<Id,sObject> OldMap){
If(activeclass != null){
activeclass.InProgressEntry(IsBefore,IsDelete,IsAfter,IsInsert,IsUpdate,IsExecuting,NewList,NewMap,OldList,OldMap);
return;
}
If(TriggerObject == 'CPM_Contract__c'){
IF(IsAfter && (IsInsert || IsUpdate)){
activeclass = new CPMeContractProcess();
activeclass.MainEntry(IsUpdate, IsInsert, IsDelete, IsExecuting, IsBefore, IsAfter, NewList, NewMap, OldList, OldMap);
}
}
}
}
</pre>
<pre>
public class CPMeContractProcess Implements Dispatch.ITriggerEntry{
Public Static Void MainEntry(Boolean IsUpdate, Boolean IsInsert, Boolean IsDelete, Boolean IsExecuting, Boolean IsBefore, Boolean IsAfter, LIST<sObject> NewList, Map<Id,sObject> NewMap, LIST<sObject> OldList, MAP<Id,sObject> OldMap){
Map<Id,CPM_Contract__c>NewContract = (Map<Id,CPM_Contract__c>)NewMap;
Map<Id,CPM_Contract__c>OldContract = (Map<Id,CPM_Contract__c>)OldMap;
Map<String,CPM_Contract__c> GC = new Map<String,CPM_Contract__C>();
Map<String,CPM_Contract__c> Sub = new Map<String,CPM_Contract__C>();
Map<String,CPM_Contract__c> User = new Map<String,CPM_Contract__C>();
Map<String,CPM_Contract__c> Proj = new Map<String,CPM_Contract__c>();
Map<String,CPM_Contract__c> Contr = New Map<String,CPM_Contract__c>();
list<Org_ID__c> UpdateGCAccount = new List<Org_ID__c>();
list<Org_ID__c> UpdateSubAccount = new List<Org_ID__c>();
list<User_ID__c> UpdateUser = new List<User_ID__c>();
list<CPM_Project__c> UpdateProj = new List<CPM_Project__c>();
List<String> AllCrtIds = New List<String>();
list<Account> NewGCAccount = new List<Account>();
list<Account> NewSubAccount = new List<Account>();
list<Contact> NewUser = new List<Contact>();
list<CPM_Project__c> NewProject = new List<CPM_Project__c>();
list<Report_Date__c> UpdateReport = new list<Report_Date__c>();
date ReportDate = null;
String ARTID = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Textura').getRecordTypeId();
String CRTID = Schema.SObjectType.Contact.getRecordTypeInfosByName().get('Textura Contact').getRecordTypeId();
id ReportID = null;
//------------------------ Parse the results into different maps to be processed later -----------------------
For (CPM_Contract__c SetCtr: NewContract.values()){
GC.put(SetCtr.Textura_Customer_Number_GC__c,SetCtr);
Sub.put(SetCtr.Textura_Customer_Number_Sub__c,SetCtr);
Proj.put(SetCtr.Project_ID__c,SetCtr);
User.put(SetCtr.User_ID__c,SetCtr);
Contr.put(SetCtr.Contract_Number__c,SetCtr);
AllCrtIds.add(SetCtr.Contract_Number__c);
if(SetCtr.Report_Date__c != null){
ReportDate = SetCtr.Report_Date__c;
}
}
//------------------------ Re-set the Report Date Object -----------------------------
if(ReportDate!=null){
for(Report_Date__c RD : [select Last_Report_Date__c, Name, ID from Report_Date__c where Name = 'CPM Contract Export']){
RD.Last_Report_Date__c = ReportDate;
ReportID = RD.Id;
UpdateReport.add(RD);
}
update UpdateReport;
}
//------------------------ GC Account Handling --------------------------------------
Map<String,Org_ID__c> OldGCMap = New Map<String,Org_ID__c>();
For(Org_ID__c AddOldGC : [Select ID__c, Account__r.ID From Org_ID__c Where Solution__c = 'CPM' And ID__c in :GC.keySet()]){
OldGCMap.put(AddOldGC.ID__c,AddOldGC);
}
//Add missing Accounts
For(CPM_Contract__c NewA1 : GC.values()){
IF(NewA1.Textura_Customer_Number_GC__c == Null){
Continue;
}Else If(!OldGCMap.containsKey(NewA1.Textura_Customer_Number_GC__c)){
Account A1 = new Account();
A1.Name = NewA1.Company_Name_GC__c;
A1.RecordTypeID = ARTID;
A1.BillingStreet = NewA1.Street_1_GC__c + '\r\n' + NewA1.Street_2_GC__c;
A1.BillingCity = NewA1.City_GC__c;
A1.BillingState = NewA1.State_GC__c;
A1.BillingPostalCode = NewA1.Zip_GC__c;
A1.CPM_Org_ID__c = NewA1.Textura_Customer_Number_GC__c;
A1.Phone = NewA1.Phone_GC__c;
A1.Fax = NewA1.Fax_GC__c;
A1.Email_Domain__c = NewA1.Email_GC__c;
A1.Type = 'General Contractor';
NewGCAccount.add(A1);
}
}
Insert NewGCAccount;
//updated existing GC ORG IDs
For(Org_ID__c GCNow : [Select ID__c from ORG_ID__c where Solution__c = 'CPM' AND ID__c in : GC.KeySet()]){
If(OldGCMap.containsKey(GCNow.ID__c)){
GCNow.Company_Name__c = GC.get(GCNow.ID__c).Company_Name_GC__c;
GCNow.Street_1__c = GC.get(GCNow.ID__c).Street_1_GC__c;
GCNow.Street_2__c=GC.get(GCNow.ID__c).Street_2_GC__c;
GCNow.City__c=GC.get(GCNow.ID__c).City_GC__c;
GCNow.State__c=GC.get(GCNow.ID__c).State_GC__c;
GCNow.Postal_Code__c=GC.get(GCNow.ID__c).Zip_GC__c;
GCNow.Email__c = GC.get(GCNow.ID__c).Email_GC__c;
GCNow.Phone__c = GC.get(GCNow.ID__c).Phone_GC__c;
GCNow.Fax__c = GC.get(GCNow.ID__c).Fax_GC__c;
GCNow.Tax_ID__c = GC.get(GCNow.ID__c).Tax_ID_GC__c;
UpdateGCAccount.add(GCNow);
}
}
Update UpdateGCAccount;
// Grab the final list of all Org IDs and their respective Account ID to link the GC with the Project
Map<String,Org_ID__c> NewGCMap = new Map<String,Org_ID__c>();
FOR(Org_ID__c AddNewGC : [Select ID__c, Account__r.ID From Org_ID__c Where Solution__c = 'CPM' And ID__c in : GC.keySet()]){
NewGCMap.put(AddNewGC.ID__c,AddNewGC);
}
//------------------------ Subcontractor Handling --------------------------
Map<String,Org_ID__c> OldSubMap = new Map<String,Org_ID__c>();
FOR(Org_ID__c AddOldSub : [Select ID__c From Org_ID__c Where Solution__c = 'CPM' And ID__c in : Sub.keySet()]){
OldSubMap.put(AddOldSub.ID__c,AddOldSub);
}
//Add missing Accounts
For(CPM_Contract__c NewA2 : Sub.values()){
IF(NewA2.Textura_Customer_Number_Sub__c==Null){
Continue;
}ELSE IF(!OldSubMap.containsKey(NewA2.Textura_Customer_Number_Sub__c)){
Account A2 = new Account();
A2.Name = NewA2.Company_Name_Sub__c;
A2.RecordTypeID = ARTID;
A2.BillingStreet = NewA2.Street_1_Sub__c + '\r\n' + NewA2.Street_2_Sub__c;
A2.BillingCity = NewA2.City_Sub__c;
A2.BillingState = NewA2.State_Sub__c;
A2.BillingPostalCode = NewA2.Zip_Sub__c;
A2.CPM_Org_ID__c = NewA2.Textura_Customer_Number_Sub__c;
A2.Phone = NewA2.Phone_Sub__c;
A2.Fax = NewA2.Fax_Sub__c;
A2.Email_Domain__c = NewA2.Email_Sub__c;
A2.Type = 'Subcontractor';
NewSubAccount.add(A2);
}
}
Insert NewSubAccount;
//updated existing Sub ORG IDs
For(Org_ID__c SubNow : [Select ID__c from ORG_ID__c where Solution__c = 'CPM' AND ID__c in :Sub.keySet()]){
IF(OldSubMap.containsKey(SubNow.ID__c)){
SubNow.Company_Name__c = Sub.get(SubNow.ID__c).Company_Name_Sub__c;
SubNow.Street_1__c = Sub.get(SubNow.ID__c).Street_1_Sub__c;
SubNow.Street_2__c=Sub.get(SubNow.ID__c).Street_2_Sub__c;
SubNow.City__c=Sub.get(SubNow.ID__c).City_Sub__c;
SubNow.State__c=Sub.get(SubNow.ID__c).State_Sub__c;
SubNow.Postal_Code__c=Sub.get(SubNow.ID__c).Zip_Sub__c;
SubNow.Email__c = Sub.get(SubNow.ID__c).Email_Sub__c;
SubNow.Phone__c = Sub.get(SubNow.ID__c).Phone_Sub__c;
SubNow.Fax__c = Sub.get(SubNow.ID__c).Fax_Sub__c;
SubNow.Tax_ID__c = Sub.get(SubNow.ID__c).Tax_ID_Sub__c;
UpdateSubAccount.add(SubNow);
}
}
Update UpdateSubAccount;
// Grab the final list of all Org IDs and their respective Account ID to link the GC with the Project
Map<String,Org_ID__c> NewSubMap = new Map<String,Org_ID__c>();
FOR(Org_ID__c AddNewSub : [Select ID__c, Account__r.ID From Org_ID__c Where Solution__c = 'CPM' And ID__c in : Sub.keySet()]){
NewSubMap.put(AddNewSub.ID__c,AddNewSub);
}
//------------------------ User Handling -----------------------------------
Map<String,User_ID__c> OldUserMap = new Map<String,User_ID__c>();
FOR(User_ID__c AddOldUser : [Select External_System_ID__c from User_ID__c where Solution__c = 'CPM' AND External_System_ID__c in :User.keySet()]){
OldUserMap.put(AddOldUser.External_System_ID__c,AddOldUser);
}
//Add missing User
For(CPM_Contract__c NewU : User.values()){
IF(NewU.User_ID__c==Null){
Continue;
}Else IF(!OldUserMap.containsKey(NewU.User_ID__c)){
Contact U = new Contact();
U.FirstName = NewU.First_Name__c;
U.LastName = NewU.Last_Name__c;
U.Email = NewU.Email_User__c;
U.Phone = NewU.Phone_1__c;
U.RecordTypeID = CRTID;
U.CPM_User_ID__c = NewU.User_ID__c;
U.AccountId = NewSubMap.get(NewU.Textura_Customer_Number_Sub__c).Account__r.ID;
NewUser.add(U);
}
}
Insert NewUser;
//updated existing User IDs
For(User_ID__c UserNow : [Select External_System_ID__c from User_ID__c where Solution__c = 'CPM' AND External_System_ID__c in :User.keySet()]){
IF(OldUserMap.containsKey(UserNow.External_System_ID__c)){
UserNow.First_Name__c = User.get(UserNow.External_System_ID__c).First_Name__c;
UserNow.Last_Name__c = User.get(UserNow.External_System_ID__c).Last_Name__c;
UserNow.Email__c = User.get(UserNow.External_System_ID__c).Email_User__c;
UserNow.Phone_1__c = User.get(UserNow.External_System_ID__c).Phone_1__c;
UserNow.Phone_2__c = User.get(UserNow.External_System_ID__c).Phone_2__c;
UserNow.Related_Org_ID__c = User.get(UserNow.External_System_ID__c).Textura_Customer_Number_Sub__c;
UpdateUser.add(UserNow);
}
}
Update UpdateUser;
// Grab the final list of all User IDs and their respective Contact ID to link the GC with the Project
Map<String,User_ID__c> NewUserMap = new Map<String,User_ID__c>();
FOR(User_ID__c AddNewUser : [Select External_System_ID__c from User_ID__c where Solution__c = 'CPM' AND External_System_ID__c in :User.keySet()]){
NewUserMap.put(AddNewUser.External_System_ID__c,AddNewUser);
}
//------------------------ Project Handling -------------------------------
Map<String,CPM_Project__c> OldProjMap = new Map<String,CPM_Project__c>();
FOR(CPM_Project__c AddOldProj : [Select Project_ID__c From CPM_Project__c Where Project_ID__c in :proj.keySet()]){
OldProjMap.put(AddOldProj.Project_ID__c,AddOldProj);
}
//Add missing Projects
For(CPM_Contract__c NewP : [Select Project_ID__c, Project_Name__c, Project_Street_1__c, Project_Street_2__c, Project_State__C, Project_City__c, Project_Postal_Code__c, Project_Description__c, Notary__c, Notary_State__c, Textura_Customer_Number_GC__c From CPM_Contract__c Where Project_ID__c In :Proj.keySet()]){
IF(NewP.Project_ID__c==Null){
Continue;
}Else If(!OldProjMap.containsKey(NewP.Project_ID__c)){
CPM_Project__c P = new CPM_Project__c();
P.Project_ID__c = NewP.Project_ID__c;
P.Project_Name__C = NewP.Project_Name__c;
P.Street_1__c = NewP.Project_Street_1__c;
P.Street_2__c = NewP.Project_Street_2__c;
P.State__c = NewP.Project_State__C;
P.City__c = NewP.Project_City__c;
P.Postal_Code__c = NewP.Project_Postal_Code__c;
P.Project_Description__c = NewP.Project_Description__c;
P.Notary__c = NewP.Notary__c;
P.Notary_State__c = NewP.Notary_State__c;
P.GC_ID__c = NewP.Textura_Customer_Number_GC__c;
NewProject.add(P);
}
}
Insert NewProject;
//Project Updates
For(CPM_Project__c ProjNow : [Select Project_ID__c from CPM_Project__c where project_ID__c in :proj.keySet()]){
If(OldProjMap.containsKey(ProjNow.Project_ID__c)){
ProjNow.Project_Name__c = Proj.get(ProjNow.Project_ID__c).Project_Name__c;
ProjNow.Street_1__c = Proj.get(ProjNow.Project_ID__c).Project_Street_1__c;
ProjNow.Street_2__c = Proj.get(ProjNow.Project_ID__c).Project_Street_2__c;
ProjNow.City__C = Proj.get(ProjNow.Project_ID__c).Project_City__c;
ProjNow.State__C = Proj.get(ProjNow.Project_ID__c).Project_State__c;
ProjNow.Postal_Code__C = Proj.get(ProjNow.Project_ID__c).Project_Postal_Code__c;
ProjNow.Country__c = Proj.get(ProjNow.Project_ID__c).Project_Country__c;
ProjNow.Notary__c = Proj.get(ProjNow.Project_ID__c).Notary__c;
ProjNow.Country__c = Proj.get(ProjNow.Project_ID__c).Project_Country__c;
ProjNow.Project_Description__C = Proj.get(ProjNow.Project_ID__c).Project_Description__C;
ProjNow.GC_ID__c = Proj.get(ProjNow.Project_ID__c).Textura_Customer_Number_GC__c;
UpdateProj.add(ProjNow);
}
}
Update UpdateProj;
Map<String,CPM_Project__c> NewProjMap = new Map<String,CPM_Project__c>();
FOR(CPM_Project__c AddNewProj : [Select Project_ID__c, ID From CPM_Project__c Where Project_ID__c in :proj.keySet()]){
NewProjMap.put(AddNewProj.Project_ID__c,AddNewProj);
}
//------------------------ Record Linking -------------------------------
// Link Contract to Project and Subcontractors
List<CPM_Contract__c> LinkCtr = New List<CPM_Contract__c>();
For(CPM_Contract__c LinkC : [SELECT Project_ID__c, Textura_Customer_Number_Sub__c, Report_Date__c, Last_Report_Update__c FROM CPM_Contract__c WHERE Contract_Number__c In :AllCrtIds]){
IF(NewProjMap.containsKey(LinkC.Project_ID__c)){
LinkC.CPM_Project__c = NewProjMap.get(LinkC.Project_ID__c).ID;
}
IF(NewSubMap.containsKey(LinkC.Textura_Customer_Number_Sub__c)){
LinkC.Subcontractor__c = NewSubMap.get(LinkC.Textura_Customer_Number_Sub__c).Account__r.ID;
}
IF(LinkC.Report_Date__c != Null){
LinkC.Last_Report_Update__c = LinkC.Report_Date__c;
LinkC.Report_Date__c = Null;
}
IF(ReportID != null){
LinkC.Report_Date_Record__c = ReportID;
}
LinkCtr.add(LinkC);
}
Update LinkCtr;
// Link Project to GC
List<CPM_Project__c> LinkProj = New List<CPM_Project__c>();
For(CPM_Project__c LinkP : [Select GC_ID__c FROM CPM_Project__c WHERE Project_ID__c in :proj.keySet()]){
IF(NewGCMap.containsKey(LinkP.GC_ID__c)){
LinkP.General_Contractor__c = NewGCMap.get(LinkP.GC_ID__c).Account__r.ID;
}
LinkProj.add(LinkP);
}
Update LinkProj;
}
//------------------------ In Progress Method -------------------------------
Public Static Void InProgressEntry(Boolean IsUpdate, Boolean IsInsert, Boolean IsDelete, Boolean IsExecuting, Boolean IsBefore, Boolean IsAfter, LIST<sObject> NewList, Map<Id,sObject> NewMap, LIST<sObject> OldList, MAP<Id,sObject> OldMap){
}
}
</pre>
I'm stumbling across your question a little late so you may have already figured out the answer, but for anyone else who runs into this issue here is the solution.
The order of execution in an upsert is to execute the Before/After Insert and then the Before/After Update events. The program flow will enter your Dispatch class for all four of those events.
The execution context is the same for all four of those events, however, so when your TriggerObject After Insert condition is true and you set activeclass to an instance of CPMeContractProcess it retains that value as the program flow enters the Dispatch class for the Before/After Update events. As a result the program flow is diverted to your CPMeContractProcess.InProgressEntry method.
The easiest way to resolve this is to set activeclass back to null.
Hope that helps