Skip to content

Commit 936c135

Browse files
authored
v1.6.21 - Rollup to Multicurrency Parents Bugfix (#580)
* Adds safety step in pipeline for cleaning up scratch org * Fixes compilation issue with null coalesce/ternary * Fixes an edge case in RollupMultiCurrencytTests scratch orgs without multiple currencies loaded * Fixes an issue reported by Joseph Mason where rollups to different parents accidentally cached the converted IsoCode value of the first child -> parent multicurrency conversion
1 parent 2a9e4de commit 936c135

File tree

14 files changed

+16646
-5395
lines changed

14 files changed

+16646
-5395
lines changed

.github/workflows/deploy.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,16 @@ jobs:
7979
DEVHUB_SERVER_KEY: ${{ secrets.DEVHUB_SERVER_KEY }}
8080

8181
- name: 'Deploy & Test'
82+
id: 'deploy'
8283
shell: pwsh
8384
run: '. ./scripts/test.ps1'
8485

86+
- name: 'Possible Scratch Org Cleanup'
87+
if: ${{ failure() && steps.deploy.conclusion == 'failure' }}
88+
run: |
89+
npm run delete:org
90+
exit 1
91+
8592
# Delete temporary test files that Codecov is unable to parse
8693
- name: 'Delete unparseable test coverage'
8794
run: rm ./tests/apex/test-result-707*-codecoverage.json -f

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co
2424

2525
## Deployment & Setup
2626

27-
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OanPAAS">
27+
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OatsAAC">
2828
<img alt="Deploy to Salesforce"
2929
src="./media/deploy-package-to-prod.png">
3030
</a>
3131

32-
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OanPAAS">
32+
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OatsAAC">
3333
<img alt="Deploy to Salesforce Sandbox"
3434
src="./media/deploy-package-to-sandbox.png">
3535
</a>

extra-tests/classes/RollupCurrencyInfoTests.cls

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ private class RollupCurrencyInfoTests {
1818
RollupCurrencyInfo.setCurrencyIsoCode(opp, mockUsdInfo.IsoCode);
1919
RollupCurrencyInfo.transform(new List<SObject>{ opp }, Opportunity.Amount, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
2020

21-
opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp);
21+
opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, mockEurInfo.IsoCode);
2222
System.assertEquals(0, opp.Amount, 'Should make it here without divide by zero error!');
2323
}
2424

@@ -41,7 +41,7 @@ private class RollupCurrencyInfoTests {
4141
RollupCurrencyInfo.setCurrencyIsoCode(opp, 'USD');
4242
RollupCurrencyInfo.transform(new List<SObject>{ opp }, Opportunity.Amount, 'EUR', new List<RollupOrderBy__mdt>());
4343

44-
opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp);
44+
opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, 'EUR');
4545
System.assertEquals(null, opp.Amount, 'Should make it here without NPE!');
4646
}
4747

@@ -76,12 +76,12 @@ private class RollupCurrencyInfoTests {
7676
RollupCurrencyInfo.setCurrencyIsoCode(camp, mockUsdInfo.IsoCode);
7777
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.BudgetedCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
7878

79-
Campaign updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp);
79+
Campaign updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
8080
System.assertEquals(mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost), updatedCamp.BudgetedCost);
8181

8282
// now for the second field update
8383
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.ActualCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
84-
updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp);
84+
updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
8585
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.ActualCost)).doubleValue(), updatedCamp.ActualCost);
8686
}
8787

@@ -107,7 +107,7 @@ private class RollupCurrencyInfoTests {
107107

108108
RollupCurrencyInfo.transform(new List<SObject>{ opp }, currencyFormulaToken, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
109109

110-
Opportunity updatedOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp);
110+
Opportunity updatedOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, mockEurInfo.IsoCode);
111111
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / opp.AmountFormula__c)).doubleValue(), updatedOpp.AmountFormula__c);
112112
}
113113

@@ -154,8 +154,8 @@ private class RollupCurrencyInfoTests {
154154
// quite a bit of ceremony to get here - but finally the method under test
155155
RollupCurrencyInfo.transform(opps, Opportunity.Amount, eurPeriodOne.IsoCode, new List<RollupOrderBy__mdt>());
156156

157-
firstOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(0));
158-
secondOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(1));
157+
firstOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(0), eurPeriodOne.IsoCode);
158+
secondOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(1), eurPeriodOne.IsoCode);
159159
System.assertEquals(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / opps[0].Amount), firstOpp.Amount);
160160
System.assertEquals(eurPeriodTwo.ConversionRate / (usdInfo.ConversionRate / opps[1].Amount), secondOpp.Amount);
161161
}
@@ -201,7 +201,7 @@ private class RollupCurrencyInfoTests {
201201
RollupCurrencyInfo.overrideDatedMultiCurrency(olis.getSObjectType().getDescribe().getName(), new List<String>{ 'Opportunity', 'CloseDate' });
202202
RollupCurrencyInfo.transform(olis, OpportunityLineItem.TotalPrice, eurPeriodOne.IsoCode, new List<RollupOrderBy__mdt>());
203203

204-
OpportunityLineItem oli = (OpportunityLineItem) RollupCurrencyInfo.getCalcItem(oliToUpdate);
204+
OpportunityLineItem oli = (OpportunityLineItem) RollupCurrencyInfo.getCalcItem(oliToUpdate, eurPeriodOne.IsoCode);
205205
System.assertEquals(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / oliToUpdate.TotalPrice), oli.TotalPrice);
206206
}
207207
}

extra-tests/classes/RollupMultiCurrencyTests.cls

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ private class RollupMultiCurrencyTests {
3232

3333
@IsTest
3434
static void shouldCorrectlyRollupMaxForMultiCurrency() {
35+
if (hasCurrencyInfo('EUR') == false) {
36+
return;
37+
}
3538
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
3639
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
3740
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -81,6 +84,9 @@ private class RollupMultiCurrencyTests {
8184

8285
@IsTest
8386
static void shouldCorrectlyRollupMinForMultiCurrency() {
87+
if (hasCurrencyInfo('EUR') == false) {
88+
return;
89+
}
8490
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
8591
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
8692
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -131,6 +137,9 @@ private class RollupMultiCurrencyTests {
131137

132138
@IsTest
133139
static void shouldCorrectlyRollupSumForMultiCurrency() {
140+
if (hasCurrencyInfo('EUR') == false) {
141+
return;
142+
}
134143
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
135144
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
136145
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -182,6 +191,9 @@ private class RollupMultiCurrencyTests {
182191

183192
@IsTest
184193
static void shouldCorrectlyRollupAverageForMultiCurrency() {
194+
if (hasCurrencyInfo('EUR') == false) {
195+
return;
196+
}
185197
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
186198
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
187199
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -240,6 +252,9 @@ private class RollupMultiCurrencyTests {
240252

241253
@IsTest
242254
static void shouldCorrectlyRollupFirstForMultiCurrency() {
255+
if (hasCurrencyInfo('EUR') == false) {
256+
return;
257+
}
243258
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
244259
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
245260
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -300,6 +315,9 @@ private class RollupMultiCurrencyTests {
300315

301316
@IsTest
302317
static void shouldCorrectlyRollupLastForMultiCurrency() {
318+
if (hasCurrencyInfo('EUR') == false) {
319+
return;
320+
}
303321
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
304322
System.assertEquals(null, acc.AnnualRevenue, 'Test has started under the wrong conditions!');
305323
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
@@ -358,6 +376,62 @@ private class RollupMultiCurrencyTests {
358376
System.assertEquals(lastOpportunityId, acc.Name, 'Should have taken last based on multi-currency Amount! Records: ' + opportunities);
359377
}
360378

379+
@IsTest
380+
static void properlyTracksCurrencyItemsForDifferentParentCurrencies() {
381+
if (hasCurrencyInfo('EUR') == false || hasCurrencyInfo('JPY') == false) {
382+
return;
383+
}
384+
delete [SELECT Id FROM Opportunity];
385+
386+
Account acc = (Account) RollupTestUtils.queryRecord(Account.SObjectType, new List<Schema.SObjectField>{ Account.AnnualRevenue });
387+
acc.AnnualRevenue = 100;
388+
update acc;
389+
System.assertEquals('USD', getCurrencyIsoCode(acc), 'Test has started under the wrong conditions!');
390+
391+
Opportunity eurOpp = new Opportunity(Name = 'First Parent', StageName = 'a', CloseDate = System.today(), AccountId = acc.Id);
392+
RollupCurrencyInfo.setCurrencyIsoCode(eurOpp, 'EUR');
393+
Contract contract = new Contract(AccountId = acc.Id, Name = 'Second Parent');
394+
RollupCurrencyInfo.setCurrencyIsoCode(contract, 'JPY');
395+
insert new List<SObject>{ eurOpp, contract };
396+
397+
Rollup.onlyUseMockMetadata = true;
398+
Rollup__mdt firstParent = new Rollup__mdt(
399+
RollupFieldOnCalcItem__c = 'AnnualRevenue',
400+
LookupObject__c = 'Opportunity',
401+
LookupFieldOnCalcItem__c = 'Id',
402+
LookupFieldOnLookupObject__c = 'AccountId',
403+
RollupFieldOnLookupObject__c = 'Amount',
404+
RollupOperation__c = 'SUM',
405+
CalcItem__c = 'Account'
406+
);
407+
Rollup__mdt secondParent = new Rollup__mdt(
408+
RollupFieldOnCalcItem__c = 'AnnualRevenue',
409+
LookupObject__c = 'Contract',
410+
LookupFieldOnCalcItem__c = 'Id',
411+
LookupFieldOnLookupObject__c = 'AccountId',
412+
RollupFieldOnLookupObject__c = 'ContractTerm',
413+
RollupOperation__c = 'SUM',
414+
CalcItem__c = 'Account'
415+
);
416+
Rollup.rollupMetadata = new List<Rollup__mdt>{ firstParent, secondParent };
417+
Rollup.apexContext = TriggerOperation.AFTER_INSERT;
418+
Rollup.shouldRun = true;
419+
Rollup.records = new List<Account>{ acc };
420+
421+
Test.startTest();
422+
Rollup.runFromTrigger();
423+
Test.stopTest();
424+
425+
contract = [SELECT ContractTerm FROM Contract WHERE Id = :contract.Id];
426+
eurOpp = [SELECT Amount FROM Opportunity WHERE Id = :eurOpp.Id];
427+
System.assertNotEquals(null, contract.ContractTerm, 'Rollup should have occurred');
428+
System.assertNotEquals(contract.ContractTerm, eurOpp.Amount);
429+
}
430+
431+
private static Boolean hasCurrencyInfo(String currencyCode) {
432+
return RollupCurrencyInfo.getCurrencyInfo(currencyCode).IsoCode != null;
433+
}
434+
361435
private static String getCurrencyIsoCode(SObject record) {
362436
return UserInfo.isMultiCurrencyOrganization() ? (String) record.get(RollupCurrencyInfo.CURRENCY_ISO_CODE_FIELD_NAME) : 'USD';
363437
}

0 commit comments

Comments
 (0)