Skip to content

Commit

Permalink
v1.7.7 - Additional Multi-Currency Bugfixes (#659)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamessimone authored Feb 17, 2025
1 parent 1cf0954 commit 399ed0f
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 84 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008Ofr7AAC">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrlAAC">
<img alt="Deploy to Salesforce" src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008Ofr7AAC">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrlAAC">
<img alt="Deploy to Salesforce Sandbox" src="./media/deploy-package-to-sandbox.png">
</a>
<br/>
Expand Down
107 changes: 87 additions & 20 deletions extra-tests/classes/RollupCurrencyInfoTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(new List<SObject>{ opp }, Opportunity.Amount, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());

opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, mockEurInfo.IsoCode);
System.assertEquals(0, opp.Amount, 'Should make it here without divide by zero error!');
Assert.areEqual(0, opp.Amount, 'Should make it here without divide by zero error!');
}

@IsTest
Expand All @@ -38,7 +38,7 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(new List<SObject>{ opp }, Opportunity.Amount, 'EUR', new List<RollupOrderBy__mdt>());

opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, 'EUR');
System.assertEquals(null, opp.Amount, 'Should make it here without NPE!');
Assert.areEqual(null, opp.Amount, 'Should make it here without NPE!');
}

@IsTest
Expand Down Expand Up @@ -71,17 +71,17 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.BudgetedCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());

Campaign updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
System.assertEquals(mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost), updatedCamp.BudgetedCost);
Assert.areEqual(mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost), updatedCamp.BudgetedCost);

// now for the second field update
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.ActualCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.ActualCost)).doubleValue(), updatedCamp.ActualCost);
Assert.areEqual((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.ActualCost)).doubleValue(), updatedCamp.ActualCost);
// sanity check that updates on previously transformed fields still calculate correctly
camp.BudgetedCost = 6;
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.BudgetedCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
Campaign again = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost)).doubleValue(), again.BudgetedCost);
Assert.areEqual((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost)).doubleValue(), again.BudgetedCost);
}

@IsTest
Expand All @@ -105,7 +105,7 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(new List<SObject>{ opp }, currencyFormulaToken, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());

Opportunity updatedOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, mockEurInfo.IsoCode);
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / opp.AmountFormula__c)).doubleValue(), updatedOpp.AmountFormula__c);
Assert.areEqual((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / opp.AmountFormula__c)).doubleValue(), updatedOpp.AmountFormula__c);
}

@IsTest
Expand Down Expand Up @@ -153,8 +153,11 @@ private class RollupCurrencyInfoTests {

firstOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(0), eurPeriodOne.IsoCode);
secondOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(opps.get(1), eurPeriodOne.IsoCode);
System.assertEquals(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / opps[0].Amount), firstOpp.Amount);
System.assertEquals(eurPeriodTwo.ConversionRate / (usdInfo.ConversionRate / opps[1].Amount), secondOpp.Amount);
Assert.areEqual(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / opps[0].Amount), firstOpp.Amount);
Assert.areEqual(eurPeriodTwo.ConversionRate / (usdInfo.ConversionRate / opps[1].Amount), secondOpp.Amount);

Assert.areEqual(Date.newInstance(9999, 12, 31), RollupCurrencyInfo.REPOSITORY.args.bindVars.get('maxStartDate'));
Assert.areEqual(Date.newInstance(0, 12, 30), RollupCurrencyInfo.REPOSITORY.args.bindVars.get('minStartDate'));
}

@IsTest
Expand Down Expand Up @@ -183,8 +186,8 @@ private class RollupCurrencyInfoTests {
eurPeriodTwo.NextStartDate = System.today().addDays(1);

RollupCurrencyInfo unusedStandardEurPeriod = new RollupCurrencyInfo();
eurPeriodTwo.ConversionRate = 1.5;
eurPeriodTwo.IsoCode = 'EUR';
unusedStandardEurPeriod.ConversionRate = 1;
unusedStandardEurPeriod.IsoCode = 'EUR';

RollupCurrencyInfo.mockBasicCurrencies = new List<RollupCurrencyInfo>{ unusedStandardEurPeriod };
RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ usdInfo, eurPeriodOne, eurPeriodTwo };
Expand All @@ -203,7 +206,7 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(olis, OpportunityLineItem.TotalPrice, eurPeriodOne.IsoCode, new List<RollupOrderBy__mdt>());

OpportunityLineItem oli = (OpportunityLineItem) RollupCurrencyInfo.getCalcItem(oliToUpdate, eurPeriodOne.IsoCode);
System.assertEquals(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / oliToUpdate.TotalPrice), oli.TotalPrice);
Assert.areEqual(eurPeriodOne.ConversionRate / (usdInfo.ConversionRate / oliToUpdate.TotalPrice), oli.TotalPrice);
}

@IsTest
Expand All @@ -219,30 +222,94 @@ private class RollupCurrencyInfoTests {
usdInfo.StartDate = Date.newInstance(0, 12, 30);
usdInfo.NextStartDate = Date.newInstance(9999, 12, 31);
RollupCurrencyInfo eurPeriodOne = new RollupCurrencyInfo();
eurPeriodOne.ConversionRate = 1.1;
eurPeriodOne.ConversionRate = 2;
eurPeriodOne.IsoCode = 'EUR';
eurPeriodOne.StartDate = System.today().addDays(-10);
eurPeriodOne.NextStartDate = System.today().addDays(-5);
RollupCurrencyInfo eurPeriodTwo = new RollupCurrencyInfo();
eurPeriodTwo.ConversionRate = 1.2;
eurPeriodTwo.ConversionRate = 1;
eurPeriodTwo.IsoCode = 'EUR';
eurPeriodTwo.StartDate = Date.newInstance(0, 12, 30);
eurPeriodTwo.NextStartDate = System.today().addDays(-10);
RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ usdInfo, eurPeriodOne };
Opportunity opp = new Opportunity(StageName = 'a', CloseDate = System.today().addDays(-7), Name = 'One', Amount = 14);
Opportunity secondOpp = new Opportunity(StageName = 'a', CloseDate = System.today().addYears(-7), Name = 'One', Amount = 14);
eurPeriodTwo.NextStartDate = eurPeriodOne.StartDate;
RollupCurrencyInfo.mockBasicCurrencies = new List<RollupCurrencyInfo>{ usdInfo };
RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ eurPeriodOne };
Opportunity opp = new Opportunity(StageName = 'a', CloseDate = eurPeriodOne.StartDate.addDays(2), Name = 'One', Amount = 10);
Opportunity secondOpp = new Opportunity(StageName = 'b', CloseDate = eurPeriodOne.StartDate.addYears(-7), Name = 'Two', Amount = 10);
insert new List<Opportunity>{ opp, secondOpp };
opp = (Opportunity) RollupTestUtils.queryRecord(opp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });
secondOpp = (Opportunity) RollupTestUtils.queryRecord(secondOpp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });

RollupCurrencyInfo.transform(new List<Opportunity>{ opp }, Opportunity.Amount, eurPeriodOne.IsoCode, new List<RollupOrderBy__mdt>());

opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, eurPeriodOne.IsoCode);
System.assertEquals(15.4, opp.Amount);
Assert.areEqual(20, opp.Amount);

RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ usdInfo, eurPeriodOne, eurPeriodTwo };
RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ eurPeriodOne, eurPeriodTwo };
RollupCurrencyInfo.transform(new List<Opportunity>{ secondOpp }, Opportunity.Amount, eurPeriodOne.IsoCode, new List<RollupOrderBy__mdt>());
secondOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(secondOpp, eurPeriodOne.IsoCode);
System.assertEquals(16.8, secondOpp.Amount);
Assert.areEqual(10, secondOpp.Amount);
}

@IsTest
static void multipleDateRangesContinueToWork() {
if (RollupCurrencyInfo.isMultiCurrency() == false) {
return;
}

RollupCurrencyInfo usdInfo = new RollupCurrencyInfo();
usdInfo.ConversionRate = 1;
usdInfo.IsoCode = 'USD';
// default dated currency range - all time
usdInfo.StartDate = Date.newInstance(0, 12, 30);
usdInfo.NextStartDate = Date.newInstance(9999, 12, 31);
RollupCurrencyInfo.mockBasicCurrencies = new List<RollupCurrencyInfo>{ usdInfo };

RollupCurrencyInfo eurPeriodOne = new RollupCurrencyInfo();
eurPeriodOne.ConversionRate = 1;
eurPeriodOne.IsoCode = 'EUR';
eurPeriodOne.StartDate = usdInfo.StartDate;
eurPeriodOne.NextStartDate = System.today().addYears(-10);
RollupCurrencyInfo eurPeriodTwo = new RollupCurrencyInfo();
eurPeriodTwo.ConversionRate = 2;
eurPeriodTwo.IsoCode = 'EUR';
eurPeriodTwo.StartDate = eurPeriodOne.NextStartDate;
eurPeriodTwo.NextStartDate = eurPeriodTwo.StartDate.addYears(3);
RollupCurrencyInfo eurPeriodThree = new RollupCurrencyInfo();
eurPeriodThree.ConversionRate = 3;
eurPeriodThree.IsoCode = 'EUR';
eurPeriodThree.StartDate = eurPeriodTwo.NextStartDate;
eurPeriodThree.NextStartDate = eurPeriodThree.StartDate.addYears(3);
RollupCurrencyInfo eurPeriodFour = new RollupCurrencyInfo();
eurPeriodFour.ConversionRate = 4;
eurPeriodFour.IsoCode = 'EUR';
eurPeriodFour.StartDate = eurPeriodThree.NextStartDate;
eurPeriodFour.NextStartDate = System.today().addYears(10);
RollupCurrencyInfo.mockDatedCurrencies = new List<RollupCurrencyInfo>{ eurPeriodOne, eurPeriodTwo, eurPeriodThree, eurPeriodFour };

Opportunity opp = new Opportunity(StageName = 'a', CloseDate = eurPeriodOne.NextStartDate.addDays(-2), Name = 'One', Amount = 10);
Opportunity secondOpp = new Opportunity(StageName = 'b', CloseDate = eurPeriodTwo.StartDate.addDays(1), Name = 'Two', Amount = 10);
Opportunity thirdOpp = new Opportunity(StageName = 'c', CloseDate = eurPeriodThree.StartDate.addDays(1), Name = 'Three', Amount = 10);
Opportunity fourthOpp = new Opportunity(StageName = 'd', CloseDate = eurPeriodFour.StartDate.addDays(1), Name = 'Four', Amount = 10);
insert new List<Opportunity>{ opp, secondOpp, thirdOpp, fourthOpp };
opp = (Opportunity) RollupTestUtils.queryRecord(opp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });
secondOpp = (Opportunity) RollupTestUtils.queryRecord(secondOpp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });
thirdOpp = (Opportunity) RollupTestUtils.queryRecord(thirdOpp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });
fourthOpp = (Opportunity) RollupTestUtils.queryRecord(fourthOpp.Id, new List<Schema.SObjectField>{ Opportunity.Amount, Opportunity.CloseDate });

RollupCurrencyInfo.transform(
new List<Opportunity>{ opp, secondOpp, thirdOpp, fourthOpp },
Opportunity.Amount,
eurPeriodOne.IsoCode,
new List<RollupOrderBy__mdt>()
);

opp = (Opportunity) RollupCurrencyInfo.getCalcItem(opp, eurPeriodOne.IsoCode);
Assert.areEqual(10, opp.Amount);
secondOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(secondOpp, eurPeriodOne.IsoCode);
Assert.areEqual(20, secondOpp.Amount);
thirdOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(thirdOpp, eurPeriodOne.IsoCode);
Assert.areEqual(30, thirdOpp.Amount);
fourthOpp = (Opportunity) RollupCurrencyInfo.getCalcItem(fourthOpp, eurPeriodOne.IsoCode);
Assert.areEqual(40, fourthOpp.Amount);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apex-rollup",
"version": "1.7.6",
"version": "1.7.7",
"description": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions rollup-namespaced/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ For more info, see the base `README`.

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrCAAS">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrqAAC">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrCAAS">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfrqAAC">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
7 changes: 4 additions & 3 deletions rollup-namespaced/sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"default": true,
"package": "apex-rollup-namespaced",
"path": "rollup-namespaced/source/rollup",
"versionName": "Better support for INCLUDES in where clauses",
"versionNumber": "1.2.5.0",
"versionName": "More multi-currency bugfixes",
"versionNumber": "1.2.6.0",
"versionDescription": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"releaseNotesUrl": "https://github.com/jamessimone/apex-rollup/releases/latest",
"unpackagedMetadata": {
Expand All @@ -30,6 +30,7 @@
"[email protected]": "04t6g000008OfXYAA0",
"[email protected]": "04t6g000008Off4AAC",
"[email protected]": "04t6g000008OfqYAAS",
"[email protected]": "04t6g000008OfrCAAS"
"[email protected]": "04t6g000008OfrCAAS",
"[email protected]": "04t6g000008OfrqAAC"
}
}
11 changes: 8 additions & 3 deletions rollup/core/classes/RollupAsyncProcessor.cls
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
@SuppressWarnings(
'PMD.AvoidGlobalModifier,PMD.ExcessiveClassLength,PMD.ExcessiveParameterList,PMD.NcssTypeCount,PMD.TooManyFields'
)
@SuppressWarnings('PMD.AvoidGlobalModifier,PMD.ExcessiveClassLength,PMD.ExcessiveParameterList,PMD.NcssTypeCount,PMD.TooManyFields')
global virtual without sharing class RollupAsyncProcessor extends Rollup implements Database.Batchable<SObject>, Database.RaisesPlatformEvents, System.Comparable {
private final Evaluator eval;
private final Op op;
Expand Down Expand Up @@ -904,6 +902,13 @@ global virtual without sharing class RollupAsyncProcessor extends Rollup impleme
if (groupedProcessors != null) {
processor.rollups.addAll(groupedProcessors);
}
if (processor.metadata?.CurrencyFieldMapping__c != null) {
List<String> fieldMappings = processor.metadata.CurrencyFieldMapping__c.split(',');
for (Integer index = 0; index < fieldMappings.size(); index++) {
fieldMappings[index] = fieldMappings[index].trim();
}
RollupCurrencyInfo.overrideDatedMultiCurrency(processor.metadata.CalcItem__c, fieldMappings);
}
}
}

Expand Down
11 changes: 0 additions & 11 deletions rollup/core/classes/RollupCalculator.cls
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ public without sharing abstract class RollupCalculator {
this.isDistinct = this.metadata.IsDistinct__c == true;
this.calcItemSObjectType = opFieldOnCalcItem?.getDescribe().getSObjectType();
this.repo = new RollupRepository(RollupMetaPicklists.getAccessLevel(this.metadata));
this.updateAdvancedCurrencyMappings();
}

public virtual void setDefaultValues(String lookupRecordKey, Object priorVal) {
Expand Down Expand Up @@ -468,16 +467,6 @@ public without sharing abstract class RollupCalculator {
}
}

private void updateAdvancedCurrencyMappings() {
if (this.metadata.CurrencyFieldMapping__c != null) {
List<String> fieldMappings = this.metadata.CurrencyFieldMapping__c.split(',');
for (Integer index = 0; index < fieldMappings.size(); index++) {
fieldMappings[index] = fieldMappings[index].trim();
}
RollupCurrencyInfo.overrideDatedMultiCurrency(this.metadata.CalcItem__c, fieldMappings);
}
}

private without sharing class CountDistinctRollupCalculator extends RollupCalculator {
private Boolean isIdCount;
public CountDistinctRollupCalculator(
Expand Down
Loading

0 comments on commit 399ed0f

Please sign in to comment.