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
Farihin GhaffarFarihin Ghaffar 

APEX Trigger Coding

Hello, I'm receiving an error message for something that I believe was custom built by our integration partners who are no longer working with us. Below is the message. I can get to the Apex Trigger Page, I just don't know what I should be changing. Can someone advise? Thank you!

Error:Apex trigger kell01_OpportunityTrigger caused an unexpected exception, contact your administrator: kell01_OpportunityTrigger: execution of AfterUpdate caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Opportunity.AccountId: Trigger.kell01_OpportunityTrigger: line 108, column 1
TomSnyderTomSnyder
You can not disable or alter the trigger in production.  This change needs to be made in a sandbox then deployed (typically using a changed set) to production. 
Shikha AgashiShikha Agashi
Can you please paste your trigger code as well as if you any helper  class associated with it? It looks like AccountId is not queried in List of Opportunity. Please look into SOQL query related to Opportunity and see if you have AccountID there.
Farihin GhaffarFarihin Ghaffar
Below is the trigger code for line 108. There is no helper class associated and how do I check if there is an Account ID on the opp?

toInsert.add(new Allocation__c(Opportunity__c = opp.Id, Projection__c = projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) ? projections.get(opp.AccountId).get(fy).Id : null, Fund__c = primaryFunds.get(opp.Id), Amount__c = opp.Amount));
Shikha AgashiShikha Agashi
Please share entire code. Sometime error is not line specific.
Bhaswanthnaga vivek vutukuriBhaswanthnaga vivek vutukuri
@farhin - plese check the soql query on the opportunity and include accountId in the fields list. or just comment out the SOQL query here
yeshabyeshab
In your SOQL query where you are getting values for opp, add AccountId field.
Farihin GhaffarFarihin Ghaffar
Hi Bashwanthnaga and Yeshab - can you explain how i can check the SOQL query and add the accountid? Thank you!
Bhaswanthnaga vivek vutukuriBhaswanthnaga vivek vutukuri
Post code here.... at least that query
Farihin GhaffarFarihin Ghaffar
Hi Bhaswanthnaga - below is the code. Its actually a bit longer, but this part shows the Account ID query. Any ideas? Thank you!
Farihin GhaffarFarihin Ghaffar
User-added image
Farihin GhaffarFarihin Ghaffar
any idea how i can make this bigger for you?
Shikha AgashiShikha Agashi
This code is not helpful. As this trigger is on Opportunity, you do not need to Query AccountId. But after seeing error, do you have map 
projections in your code. I would recommend, even code is big copy and paste here. Please do not paste image file. It is tough to debug.
Farihin GhaffarFarihin Ghaffar
trigger kell01_OpportunityTrigger on Opportunity (before insert, before update, after insert, after update) {
    if (trigger.isBefore) { // SetOpportunityHousehold
        Set<Id> donorIds = new Set<Id>();
        for (Opportunity opp : trigger.new) {
            if (opp.AccountId != null) {
                donorIds.add(opp.AccountId);
            } else {
                opp.Household__c = null;
            }
        }
        if (!donorIds.isEmpty()) {
            Map<Id, Account> donors = new Map<Id, Account>([SELECT Id, npe01__One2OneContact__r.npo02__Household__c, npe01__One2OneContact__r.npo02__Household__r.Name, npe01__One2OneContact__r.Account.Name 
                                                            FROM Account WHERE Id IN :donorIds AND npe01__One2OneContact__c != null AND npe01__SYSTEM_AccountType__c != 'Household Account']);
            for (Opportunity opp : trigger.new) {
                if (opp.AccountId != null && donors.containsKey(opp.AccountId)) {
                    Account donor = donors.get(opp.AccountId);
                    opp.Household__c = donor.npe01__One2OneContact__r.npo02__Household__c;
                    //opp.Household_or_Account_Name__c = donor.npe01__One2OneContact__r.npo02__Household__r.Name != null ? donor.npe01__One2OneContact__r.npo02__Household__r.Name : donor.npe01__One2OneContact__r.Account.Name;
                }
            }
        }
    } else if (trigger.isAfter) { // CreateDefaultAllocation
        Allocation_Settings__c setting = Allocation_Settings__c.getOrgDefaults();
        Set<Id> campaignIds = new Set<Id>();
        for (Opportunity opp : trigger.new) campaignIds.add(opp.CampaignId);
        Map<Id, Campaign> campaigns = new Map<Id, Campaign>([SELECT Id, Primary_Fund__c FROM Campaign WHERE Id IN :campaignIds]);
        
        Map<Id, List<Allocation__c>> defaultDesignations = new Map<Id, List<Allocation__c>>();
        Set<Id> accountIds = new Set<Id>();
        Set<String> fiscalYears = new Set<String>();
        Integer fyStart = [SELECT Id, FiscalYearStartMonth FROM Organization LIMIT 1].FiscalYearStartMonth;
        for (Opportunity opp : trigger.new) {
            if (!opp.Do_Not_Update_Projection_Allocations__c) {
                accountIds.add(opp.AccountId);
                fiscalYears.add(String.valueOf(opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0)));
            }
        }


  
Farihin GhaffarFarihin Ghaffar
the code is actually much longer than this, but I can't fit it all. Does this portion help?
Shikha AgashiShikha Agashi
No. Please paste next lines. Please select highlighted option to paste code.I think you would be able to post it then.
User-added image
Farihin GhaffarFarihin Ghaffar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
trigger kell01_OpportunityTrigger on Opportunity (before insert, before update, after insert, after update) {
    if (trigger.isBefore) { // SetOpportunityHousehold
        Set<Id> donorIds = new Set<Id>();
        for (Opportunity opp : trigger.new) {
            if (opp.AccountId != null) {
                donorIds.add(opp.AccountId);
            } else {
                opp.Household__c = null;
            }
        }
        if (!donorIds.isEmpty()) {
            Map<Id, Account> donors = new Map<Id, Account>([SELECT Id, npe01__One2OneContact__r.npo02__Household__c, npe01__One2OneContact__r.npo02__Household__r.Name, npe01__One2OneContact__r.Account.Name 
                                                            FROM Account WHERE Id IN :donorIds AND npe01__One2OneContact__c != null AND npe01__SYSTEM_AccountType__c != 'Household Account']);
            for (Opportunity opp : trigger.new) {
                if (opp.AccountId != null && donors.containsKey(opp.AccountId)) {
                    Account donor = donors.get(opp.AccountId);
                    opp.Household__c = donor.npe01__One2OneContact__r.npo02__Household__c;
                    //opp.Household_or_Account_Name__c = donor.npe01__One2OneContact__r.npo02__Household__r.Name != null ? donor.npe01__One2OneContact__r.npo02__Household__r.Name : donor.npe01__One2OneContact__r.Account.Name;
                }
            }
        }
    } else if (trigger.isAfter) { // CreateDefaultAllocation
        Allocation_Settings__c setting = Allocation_Settings__c.getOrgDefaults();
        Set<Id> campaignIds = new Set<Id>();
        for (Opportunity opp : trigger.new) campaignIds.add(opp.CampaignId);
        Map<Id, Campaign> campaigns = new Map<Id, Campaign>([SELECT Id, Primary_Fund__c FROM Campaign WHERE Id IN :campaignIds]);
        
        Map<Id, List<Allocation__c>> defaultDesignations = new Map<Id, List<Allocation__c>>();
        Set<Id> accountIds = new Set<Id>();
        Set<String> fiscalYears = new Set<String>();
        Integer fyStart = [SELECT Id, FiscalYearStartMonth FROM Organization LIMIT 1].FiscalYearStartMonth;
        for (Opportunity opp : trigger.new) {
            if (!opp.Do_Not_Update_Projection_Allocations__c) {
                accountIds.add(opp.AccountId);
                fiscalYears.add(String.valueOf(opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0)));
            }
        }

        Map<Id, Map<Decimal, Projection__c>> projections = new Map<Id, Map<Decimal, Projection__c>>();
        for (Projection__c p : [SELECT Id, Account__c, Fiscal_Year__c, Projection_Allocation_Primary_Fund__c FROM Projection__c WHERE Account__c IN :accountIds AND Fiscal_Year__c IN :fiscalYears]) {
            if (!projections.containsKey(p.Account__c)) projections.put(p.Account__c, new Map<Decimal, Projection__c>());
            projections.get(p.Account__c).put(Integer.valueOf(p.Fiscal_Year__c), p);
        }
        
        for (Opportunity opp : trigger.new) {
            if ((setting.Opportunity_Record_Type_Exclusion_List__c == null || !setting.Opportunity_Record_Type_Exclusion_List__c.contains(opp.RecordTypeId)) 
             && !opp.Do_Not_Automatically_Create_Allocation__c && opp.Amount != null && opp.Amount > 0 
             && (trigger.isInsert || trigger.oldMap.get(opp.Id).Amount == null || trigger.oldMap.get(opp.Id).Amount == 0)) {
                Id primaryFund = null;
                Integer fy = opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0);
                if (!opp.Do_Not_Update_Projection_Allocations__c && projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) && projections.get(opp.AccountId).get(fy).Projection_Allocation_Primary_Fund__c != null) {
                    primaryFund = projections.get(opp.AccountId).get(fy).Projection_Allocation_Primary_Fund__c;
                } else if (opp.Primary_Fund__c != null) {
                    primaryFund = opp.Primary_Fund__c;
                } else if (campaigns.containsKey(opp.CampaignId) && campaigns.get(opp.CampaignId).Primary_Fund__c != null) {
                    primaryFund = campaigns.get(opp.CampaignId).Primary_Fund__c;
                } else if (setting.Set_Default_Fund__c && setting.Default_Fund__c != null) {
                    primaryFund = setting.Default_Fund__c;
                }
                
                if (primaryFund != null) {
                    defaultDesignations.put(
                        opp.Id,
                        new List<Allocation__c>{
                            new Allocation__c(
                            Opportunity__c = opp.Id,
                            Projection__c = projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) ? projections.get(opp.AccountId).get(fy).Id : null,
                            Fund__c = primaryFund,
                            Amount__c = opp.Amount
                            )
                        }
                    );
                }
            }
        }
        if (!defaultDesignations.isEmpty()) {
            for (Allocation__c a : [SELECT Id, Opportunity__c FROM Allocation__c WHERE Opportunity__c IN :defaultDesignations.keySet()]) {
                if (defaultDesignations.containsKey(a.Opportunity__c)) defaultDesignations.remove(a.Opportunity__c);
            }
            List<Allocation__c> toInsert = new List<Allocation__c>();
            for (List<Allocation__c> aList : defaultDesignations.values()) toInsert.addAll(aList);
            insert toInsert;
        }
    
        if (trigger.isUpdate) { // CHANGE PRIMARY FUND ON A SINGLE ALLOCATION + CHANGE ALLOCATED AMOUNTS IF OPPORTUNITY AMOUNT CHANGES + CREATE NEW ALLOCATION IF ALL ARE REVERSED
            Map<Id, Id> primaryFunds = new Map<Id, Id>();
            Set<Id> oppsWithChangedAmount = new Set<Id>();
            Set<Id> repostedOpps = new Set<Id>();
            for (Opportunity opp : trigger.new) {        
                if (opp.Primary_Fund__c != trigger.oldMap.get(opp.Id).Primary_Fund__c && opp.Primary_Fund__c != null) {
                    primaryFunds.put(opp.Id, opp.Primary_Fund__c);
                }
                if (opp.Amount != trigger.oldMap.get(opp.Id).Amount && trigger.oldMap.get(opp.Id).Amount != null && trigger.oldMap.get(opp.Id).Amount > 0) {
                    oppsWithChangedAmount.add(opp.Id);
                }
                if (opp.Opportunity_Posted__c && !trigger.oldMap.get(opp.Id).Opportunity_Posted__c && trigger.oldMap.get(opp.Id).Opportunity_Reversed__c) {
                    repostedOpps.add(opp.Id);
                }
            }
            if (!primaryFunds.isEmpty()) {
                List<Allocation__c> toUpdate = new List<Allocation__c>();
                List<Allocation__c> toInsert = new List<Allocation__c>();
                for (Opportunity opp : [SELECT Id, Amount, CloseDate, (SELECT Id, Fund__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :primaryFunds.keySet()]) {
                    if (opp.Allocations__r.size() == 1 && opp.Allocations__r[0].Fund__c != primaryFunds.get(opp.Id)) {
                        toUpdate.add(new Allocation__c(Id = opp.Allocations__r[0].Id, Fund__c = primaryFunds.get(opp.Id)));
                    } else if (opp.Allocations__r.size() == 0) {
                        Integer fy = opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0);
                        toInsert.add(new Allocation__c(Opportunity__c = opp.Id, Projection__c = projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) ? projections.get(opp.AccountId).get(fy).Id : null, Fund__c = primaryFunds.get(opp.Id), Amount__c = opp.Amount));
                    }
                }
                update toUpdate;
                insert toInsert;
            }
            if (!oppsWithChangedAmount.isEmpty()) {
                List<Allocation__c> toUpdate = new List<Allocation__c>();
                List<Allocation__c> toDelete = new List<Allocation__c>();
                for (Opportunity opp : [SELECT Id, Amount, Allocated_Amount__c, (SELECT Id, Amount__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :oppsWithChangedAmount]) {
                    if (opp.Amount != opp.Allocated_Amount__c) {
                        Double oldAmount = trigger.oldMap.get(opp.Id).Amount;
                        Double allocated = 0;
                        List<Allocation__c> allToUpdate = new List<Allocation__c>();
                        List<Allocation__c> allToDelete = new List<Allocation__c>();
                        for (Allocation__c a : opp.Allocations__r) {
                            Decimal newAllocAmount = (a.Amount__c * opp.Amount / oldAmount).setScale(2, RoundingMode.HALF_UP);
                            if (newAllocAmount > 0) {
                                allToUpdate.add(new Allocation__c(Id = a.Id, Amount__c = newAllocAmount));
                                allocated += newAllocAmount;
                            } else {
                                allToDelete.add(new Allocation__c(Id = a.Id));
                            }
                        }
                        if (allocated != opp.Amount) { // rounding inaccuracy
                            if (!allToUpdate.isEmpty()) {
                                allToUpdate[allToUpdate.size()-1].Amount__c += (opp.Amount-allocated);
                            } else if (!allToDelete.isEmpty() && opp.Amount > allocated) {
                                Allocation__c a = allToDelete.remove(allToDelete.size()-1);
                                a.Amount__c = (opp.Amount-allocated);
                                allToUpdate.add(a);
                            }
                        }
                        toUpdate.addAll(allToUpdate);
                        toDelete.addAll(allToDelete);
                    }
                }
                delete toDelete;
                update toUpdate;
            }
            if (!repostedOpps.isEmpty()) {
                List<Allocation__c> toInsert = new List<Allocation__c>();
                for (Opportunity opp : [SELECT Id, Primary_Fund__c, (SELECT Id, Fund__c, Amount__c, Reversed__c, Reversed_Date__c FROM Allocations__r ORDER BY Reversed__c ASC) 
                                        FROM Opportunity WHERE Id IN :repostedOpps]) {
                    if (!opp.Allocations__r.isEmpty() && opp.Allocations__r[0].Reversed__c) {
                        for (Allocation__c a : opp.Allocations__r) {
                            if (a.Reversed_Date__c >= trigger.OldMap.get(opp.Id).Opportunity_Reversed_Date__c) {
                                Allocation__c newA = new Allocation__c(Opportunity__c = opp.Id, Fund__c = a.Fund__c, Amount__c = a.Amount__c, Posted__c = true);
                                if (!toInsert.isEmpty() && a.Fund__c == opp.Primary_Fund__c) toInsert.add(0, newA);
                                else toInsert.add(newA);
                            }
                        }
                    }
                }
                if (setting.Lock_Allocation_if_Opportunity_is_Posted__c) {
                    setting.Lock_Allocation_if_Opportunity_is_Posted__c = false;
                    update setting;
                    insert toInsert;
                    setting.Lock_Allocation_if_Opportunity_is_Posted__c = true;
                    update setting;
                } else {
                    insert toInsert;
                }
            }
        }
        
        // VALIDATION
        if (setting.Check_Max_Allocated_Amount__c) {
            Map<Id, Opportunity> opportunities = new Map<Id, Opportunity>([SELECT Id, Amount, (SELECT Id, Amount__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :trigger.new]);
            for (Opportunity opp : trigger.new) {
                Double allocatedAmount = 0;
                for (Allocation__c a : opportunities.get(opp.Id).Allocations__r) {
                    allocatedAmount += a.Amount__c;
                }
                if (allocatedAmount > 0 && allocatedAmount > opportunities.get(opp.Id).Amount) {
                    opp.addError('Total allocated amount cannot exceed opportunity amount.');
                }
            }
        }
    }
    
    if (trigger.isUpdate) { // PostUnpostAllAllocationsOnOpportunity
        Set<Id> opportunitiesToPost = new Set<Id>();
        Set<Id> opportunitiesToUnpost = new Set<Id>();
        for (Opportunity opp : trigger.new) {
            if (trigger.isInsert || trigger.isUndelete || opp.Opportunity_Posted__c != trigger.oldMap.get(opp.Id).Opportunity_Posted__c) {
                if (opp.Opportunity_Posted__c) {
                    opportunitiesToPost.add(opp.Id);
                } else {
                    opportunitiesToUnpost.add(opp.Id);
                }
            }
        }
        
        if (trigger.isBefore && !opportunitiesToPost.isEmpty()) {
            List<Allocation__c> allocationsToPost = [SELECT Id FROM Allocation__c 
                                                               WHERE Opportunity__c IN :opportunitiesToPost AND Posted__c = false AND Reversed__c = false
                                                                 AND Opportunity__r.Opportunity_Posted__c = false AND Opportunity__r.All_Payments_Posted__c = false];
            for (Allocation__c a : allocationsToPost) {
                a.Posted__c = true;
                a.Reversed__c = false;
            }
            update allocationsToPost;
        }
        
        if (trigger.isAfter && !opportunitiesToUnpost.isEmpty()) {
            List<Allocation__c> allocationsToUnpost = [SELECT Id FROM Allocation__c 
                                                               WHERE Opportunity__c IN :opportunitiesToUnpost AND Posted__c = true AND Reversed__c = false
                                                                 AND Opportunity__r.Opportunity_Posted__c = false AND Opportunity__r.All_Payments_Posted__c = false];
            for (Allocation__c a : allocationsToUnpost) {
                a.Posted__c = false;
            }
            update allocationsToUnpost;
        }
    }
}
Farihin GhaffarFarihin Ghaffar
Shikha - thank you. i have posted it above. the only weird thing is that the code actually takes up the first 223 lines. I'm not sure why it shifted it down so many lines when i posted. let me know what you think. thanks!
Bhaswanthnaga vivek vutukuriBhaswanthnaga vivek vutukuri
Use this code, I have changed in line number 103
  1. trigger kell01_OpportunityTrigger on Opportunity (before insert, before update, after insert, after update) {
  2.     if (trigger.isBefore) { // SetOpportunityHousehold
  3.         Set<Id> donorIds = new Set<Id>();
  4.         for (Opportunity opp : trigger.new) {
  5.             if (opp.AccountId != null) {
  6.                 donorIds.add(opp.AccountId);
  7.             } else {
  8.                 opp.Household__c = null;
  9.             }
  10.         }
  11.         if (!donorIds.isEmpty()) {
  12.             Map<Id, Account> donors = new Map<Id, Account>([SELECT Id, npe01__One2OneContact__r.npo02__Household__c, npe01__One2OneContact__r.npo02__Household__r.Name, npe01__One2OneContact__r.Account.Name 
  13.                                                             FROM Account WHERE Id IN :donorIds AND npe01__One2OneContact__c != null AND npe01__SYSTEM_AccountType__c != 'Household Account']);
  14.             for (Opportunity opp : trigger.new) {
  15.                 if (opp.AccountId != null && donors.containsKey(opp.AccountId)) {
  16.                     Account donor = donors.get(opp.AccountId);
  17.                     opp.Household__c = donor.npe01__One2OneContact__r.npo02__Household__c;
  18.                     //opp.Household_or_Account_Name__c = donor.npe01__One2OneContact__r.npo02__Household__r.Name != null ? donor.npe01__One2OneContact__r.npo02__Household__r.Name : donor.npe01__One2OneContact__r.Account.Name;
  19.                 }
  20.             }
  21.         }
  22.     } else if (trigger.isAfter) { // CreateDefaultAllocation
  23.         Allocation_Settings__c setting = Allocation_Settings__c.getOrgDefaults();
  24.         Set<Id> campaignIds = new Set<Id>();
  25.         for (Opportunity opp : trigger.new) campaignIds.add(opp.CampaignId);
  26.         Map<Id, Campaign> campaigns = new Map<Id, Campaign>([SELECT Id, Primary_Fund__c FROM Campaign WHERE Id IN :campaignIds]);
  27.         
  28.         Map<Id, List<Allocation__c>> defaultDesignations = new Map<Id, List<Allocation__c>>();
  29.         Set<Id> accountIds = new Set<Id>();
  30.         Set<String> fiscalYears = new Set<String>();
  31.         Integer fyStart = [SELECT Id, FiscalYearStartMonth FROM Organization LIMIT 1].FiscalYearStartMonth;
  32.         for (Opportunity opp : trigger.new) {
  33.             if (!opp.Do_Not_Update_Projection_Allocations__c) {
  34.                 accountIds.add(opp.AccountId);
  35.                 fiscalYears.add(String.valueOf(opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0)));
  36.             }
  37.         }
  38.  
  39.         Map<Id, Map<Decimal, Projection__c>> projections = new Map<Id, Map<Decimal, Projection__c>>();
  40.         for (Projection__c p : [SELECT Id, Account__c, Fiscal_Year__c, Projection_Allocation_Primary_Fund__c FROM Projection__c WHERE Account__c IN :accountIds AND Fiscal_Year__c IN :fiscalYears]) {
  41.             if (!projections.containsKey(p.Account__c)) projections.put(p.Account__c, new Map<Decimal, Projection__c>());
  42.             projections.get(p.Account__c).put(Integer.valueOf(p.Fiscal_Year__c), p);
  43.         }
  44.         
  45.         for (Opportunity opp : trigger.new) {
  46.             if ((setting.Opportunity_Record_Type_Exclusion_List__c == null || !setting.Opportunity_Record_Type_Exclusion_List__c.contains(opp.RecordTypeId)) 
  47.              && !opp.Do_Not_Automatically_Create_Allocation__c && opp.Amount != null && opp.Amount > 0 
  48.              && (trigger.isInsert || trigger.oldMap.get(opp.Id).Amount == null || trigger.oldMap.get(opp.Id).Amount == 0)) {
  49.                 Id primaryFund = null;
  50.                 Integer fy = opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0);
  51.                 if (!opp.Do_Not_Update_Projection_Allocations__c && projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) && projections.get(opp.AccountId).get(fy).Projection_Allocation_Primary_Fund__c != null) {
  52.                     primaryFund = projections.get(opp.AccountId).get(fy).Projection_Allocation_Primary_Fund__c;
  53.                 } else if (opp.Primary_Fund__c != null) {
  54.                     primaryFund = opp.Primary_Fund__c;
  55.                 } else if (campaigns.containsKey(opp.CampaignId) && campaigns.get(opp.CampaignId).Primary_Fund__c != null) {
  56.                     primaryFund = campaigns.get(opp.CampaignId).Primary_Fund__c;
  57.                 } else if (setting.Set_Default_Fund__c && setting.Default_Fund__c != null) {
  58.                     primaryFund = setting.Default_Fund__c;
  59.                 }
  60.                 
  61.                 if (primaryFund != null) {
  62.                     defaultDesignations.put(
  63.                         opp.Id,
  64.                         new List<Allocation__c>{
  65.                             new Allocation__c(
  66.                             Opportunity__c = opp.Id,
  67.                             Projection__c = projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) ? projections.get(opp.AccountId).get(fy).Id : null,
  68.                             Fund__c = primaryFund,
  69.                             Amount__c = opp.Amount
  70.                             )
  71.                         }
  72.                     );
  73.                 }
  74.             }
  75.         }
  76.         if (!defaultDesignations.isEmpty()) {
  77.             for (Allocation__c a : [SELECT Id, Opportunity__c FROM Allocation__c WHERE Opportunity__c IN :defaultDesignations.keySet()]) {
  78.                 if (defaultDesignations.containsKey(a.Opportunity__c)) defaultDesignations.remove(a.Opportunity__c);
  79.             }
  80.             List<Allocation__c> toInsert = new List<Allocation__c>();
  81.             for (List<Allocation__c> aList : defaultDesignations.values()) toInsert.addAll(aList);
  82.             insert toInsert;
  83.         }
  84.     
  85.         if (trigger.isUpdate) { // CHANGE PRIMARY FUND ON A SINGLE ALLOCATION + CHANGE ALLOCATED AMOUNTS IF OPPORTUNITY AMOUNT CHANGES + CREATE NEW ALLOCATION IF ALL ARE REVERSED
  86.             Map<Id, Id> primaryFunds = new Map<Id, Id>();
  87.             Set<Id> oppsWithChangedAmount = new Set<Id>();
  88.             Set<Id> repostedOpps = new Set<Id>();
  89.             for (Opportunity opp : trigger.new) {        
  90.                 if (opp.Primary_Fund__c != trigger.oldMap.get(opp.Id).Primary_Fund__c && opp.Primary_Fund__c != null) {
  91.                     primaryFunds.put(opp.Id, opp.Primary_Fund__c);
  92.                 }
  93.                 if (opp.Amount != trigger.oldMap.get(opp.Id).Amount && trigger.oldMap.get(opp.Id).Amount != null && trigger.oldMap.get(opp.Id).Amount > 0) {
  94.                     oppsWithChangedAmount.add(opp.Id);
  95.                 }
  96.                 if (opp.Opportunity_Posted__c && !trigger.oldMap.get(opp.Id).Opportunity_Posted__c && trigger.oldMap.get(opp.Id).Opportunity_Reversed__c) {
  97.                     repostedOpps.add(opp.Id);
  98.                 }
  99.             }
  100.             if (!primaryFunds.isEmpty()) {
  101.                 List<Allocation__c> toUpdate = new List<Allocation__c>();
  102.                 List<Allocation__c> toInsert = new List<Allocation__c>();
  103.                 for (Opportunity opp : [SELECT Id, Amount, CloseDate, AccountId, (SELECT Id, Fund__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :primaryFunds.keySet()]) {
  104.                     if (opp.Allocations__r.size() == 1 && opp.Allocations__r[0].Fund__c != primaryFunds.get(opp.Id)) {
  105.                         toUpdate.add(new Allocation__c(Id = opp.Allocations__r[0].Id, Fund__c = primaryFunds.get(opp.Id)));
  106.                     } else if (opp.Allocations__r.size() == 0) {
  107.                         Integer fy = opp.CloseDate.Year() + (opp.CloseDate.Month() > fyStart && fyStart > 1 ? 1 : 0);
  108.                         toInsert.add(new Allocation__c(Opportunity__c = opp.Id, Projection__c = projections.containsKey(opp.AccountId) && projections.get(opp.AccountId).containsKey(fy) ? projections.get(opp.AccountId).get(fy).Id : null, Fund__c = primaryFunds.get(opp.Id), Amount__c = opp.Amount));
  109.                     }
  110.                 }
  111.                 update toUpdate;
  112.                 insert toInsert;
  113.             }
  114.             if (!oppsWithChangedAmount.isEmpty()) {
  115.                 List<Allocation__c> toUpdate = new List<Allocation__c>();
  116.                 List<Allocation__c> toDelete = new List<Allocation__c>();
  117.                 for (Opportunity opp : [SELECT Id, Amount, Allocated_Amount__c, (SELECT Id, Amount__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :oppsWithChangedAmount]) {
  118.                     if (opp.Amount != opp.Allocated_Amount__c) {
  119.                         Double oldAmount = trigger.oldMap.get(opp.Id).Amount;
  120.                         Double allocated = 0;
  121.                         List<Allocation__c> allToUpdate = new List<Allocation__c>();
  122.                         List<Allocation__c> allToDelete = new List<Allocation__c>();
  123.                         for (Allocation__c a : opp.Allocations__r) {
  124.                             Decimal newAllocAmount = (a.Amount__c * opp.Amount / oldAmount).setScale(2, RoundingMode.HALF_UP);
  125.                             if (newAllocAmount > 0) {
  126.                                 allToUpdate.add(new Allocation__c(Id = a.Id, Amount__c = newAllocAmount));
  127.                                 allocated += newAllocAmount;
  128.                             } else {
  129.                                 allToDelete.add(new Allocation__c(Id = a.Id));
  130.                             }
  131.                         }
  132.                         if (allocated != opp.Amount) { // rounding inaccuracy
  133.                             if (!allToUpdate.isEmpty()) {
  134.                                 allToUpdate[allToUpdate.size()-1].Amount__c += (opp.Amount-allocated);
  135.                             } else if (!allToDelete.isEmpty() && opp.Amount > allocated) {
  136.                                 Allocation__c a = allToDelete.remove(allToDelete.size()-1);
  137.                                 a.Amount__c = (opp.Amount-allocated);
  138.                                 allToUpdate.add(a);
  139.                             }
  140.                         }
  141.                         toUpdate.addAll(allToUpdate);
  142.                         toDelete.addAll(allToDelete);
  143.                     }
  144.                 }
  145.                 delete toDelete;
  146.                 update toUpdate;
  147.             }
  148.             if (!repostedOpps.isEmpty()) {
  149.                 List<Allocation__c> toInsert = new List<Allocation__c>();
  150.                 for (Opportunity opp : [SELECT Id, Primary_Fund__c, (SELECT Id, Fund__c, Amount__c, Reversed__c, Reversed_Date__c FROM Allocations__r ORDER BY Reversed__c ASC) 
  151.                                         FROM Opportunity WHERE Id IN :repostedOpps]) {
  152.                     if (!opp.Allocations__r.isEmpty() && opp.Allocations__r[0].Reversed__c) {
  153.                         for (Allocation__c a : opp.Allocations__r) {
  154.                             if (a.Reversed_Date__c >= trigger.OldMap.get(opp.Id).Opportunity_Reversed_Date__c) {
  155.                                 Allocation__c newA = new Allocation__c(Opportunity__c = opp.Id, Fund__c = a.Fund__c, Amount__c = a.Amount__c, Posted__c = true);
  156.                                 if (!toInsert.isEmpty() && a.Fund__c == opp.Primary_Fund__c) toInsert.add(0, newA);
  157.                                 else toInsert.add(newA);
  158.                             }
  159.                         }
  160.                     }
  161.                 }
  162.                 if (setting.Lock_Allocation_if_Opportunity_is_Posted__c) {
  163.                     setting.Lock_Allocation_if_Opportunity_is_Posted__c = false;
  164.                     update setting;
  165.                     insert toInsert;
  166.                     setting.Lock_Allocation_if_Opportunity_is_Posted__c = true;
  167.                     update setting;
  168.                 } else {
  169.                     insert toInsert;
  170.                 }
  171.             }
  172.         }
  173.         
  174.         // VALIDATION
  175.         if (setting.Check_Max_Allocated_Amount__c) {
  176.             Map<Id, Opportunity> opportunities = new Map<Id, Opportunity>([SELECT Id, Amount, (SELECT Id, Amount__c FROM Allocations__r WHERE Reversed__c = false) FROM Opportunity WHERE Id IN :trigger.new]);
  177.             for (Opportunity opp : trigger.new) {
  178.                 Double allocatedAmount = 0;
  179.                 for (Allocation__c a : opportunities.get(opp.Id).Allocations__r) {
  180.                     allocatedAmount += a.Amount__c;
  181.                 }
  182.                 if (allocatedAmount > 0 && allocatedAmount > opportunities.get(opp.Id).Amount) {
  183.                     opp.addError('Total allocated amount cannot exceed opportunity amount.');
  184.                 }
  185.             }
  186.         }
  187.     }
  188.     
  189.     if (trigger.isUpdate) { // PostUnpostAllAllocationsOnOpportunity
  190.         Set<Id> opportunitiesToPost = new Set<Id>();
  191.         Set<Id> opportunitiesToUnpost = new Set<Id>();
  192.         for (Opportunity opp : trigger.new) {
  193.             if (trigger.isInsert || trigger.isUndelete || opp.Opportunity_Posted__c != trigger.oldMap.get(opp.Id).Opportunity_Posted__c) {
  194.                 if (opp.Opportunity_Posted__c) {
  195.                     opportunitiesToPost.add(opp.Id);
  196.                 } else {
  197.                     opportunitiesToUnpost.add(opp.Id);
  198.                 }
  199.             }
  200.         }
  201.         
  202.         if (trigger.isBefore && !opportunitiesToPost.isEmpty()) {
  203.             List<Allocation__c> allocationsToPost = [SELECT Id FROM Allocation__c 
  204.                                                                WHERE Opportunity__c IN :opportunitiesToPost AND Posted__c = false AND Reversed__c = false
  205.                                                                  AND Opportunity__r.Opportunity_Posted__c = false AND Opportunity__r.All_Payments_Posted__c = false];
  206.             for (Allocation__c a : allocationsToPost) {
  207.                 a.Posted__c = true;
  208.                 a.Reversed__c = false;
  209.             }
  210.             update allocationsToPost;
  211.         }
  212.         
  213.         if (trigger.isAfter && !opportunitiesToUnpost.isEmpty()) {
  214.             List<Allocation__c> allocationsToUnpost = [SELECT Id FROM Allocation__c 
  215.                                                                WHERE Opportunity__c IN :opportunitiesToUnpost AND Posted__c = true AND Reversed__c = false
  216.                                                                  AND Opportunity__r.Opportunity_Posted__c = false AND Opportunity__r.All_Payments_Posted__c = false];
  217.             for (Allocation__c a : allocationsToUnpost) {
  218.                 a.Posted__c = false;
  219.             }
  220.             update allocationsToUnpost;
  221.         }
  222.     }
  223. }
Farihin GhaffarFarihin Ghaffar
I'm new to this - do you know where I can edit the code? I do not see an "edit" option on the opportunity page. Thank you!
Shikha AgashiShikha Agashi
You need to update code in Sandbox and then move to PROD. You cannot modify code in PROD.