diff --git a/src/classes/BDI_DataImportService.cls b/src/classes/BDI_DataImportService.cls index 80832131dbc..7ca27344fc7 100644 --- a/src/classes/BDI_DataImportService.cls +++ b/src/classes/BDI_DataImportService.cls @@ -860,7 +860,7 @@ global with sharing class BDI_DataImportService { * also explicitly ignores boolean false's, since we can't differentiate null from false. * @param dataImport The DataImport record * @param dataImportField The DI field to copy from - * @param objDst The object to copy to + * @param destinationRecord The object to copy to * @param mapDIFieldToDstField The field map from a DI field to the destination field * @return boolean True if copied, False is not copied. */ @@ -878,6 +878,15 @@ global with sharing class BDI_DataImportService { return false; } + // If the destination field is a Boolean and the DI field intermediate requires interpretation to Boolean + // This allows for mapping checkboxes to a tri-state picklist - null, True, False - or a text with either + // null, "True", or "False" + if (!(value instanceof Boolean) && + fieldIsBooleanDisplayType(destinationRecord, destinationField)) { + + value = Boolean.valueOf(value); + } + destinationRecord.put(destinationField, value); return true; } else { @@ -885,6 +894,27 @@ global with sharing class BDI_DataImportService { } } + /******************************************************************************************************* + * @description Correctly handling checkbox fields requires mapping to a non-checkbox intermediate + * DI field. Check if the destination field is boolean + * @param destinationRecord The SObject to copy to + * @param destinationField The field mapped to on the destination record + * @return true if field is Display Type BOOLEAN + */ + private static Boolean fieldIsBooleanDisplayType(SObject destinationRecord, String destinationField) { + + String destinationSObjectname = destinationRecord.getSObjectType().getDescribe().getName(); + Schema.DisplayType destinationFieldDisplayType = + UTIL_Describe.getFieldDisplayType(destinationSObjectname, destinationField.toLowerCase()); + + if(destinationFieldDisplayType == Schema.DisplayType.BOOLEAN) { + return true; + } + + return false; + } + + /******************************************************************************************************* * @description disables the Opportunity trigger handler that invokes rollups (unless settings say * otherwise!) diff --git a/src/classes/BDI_Donations_TEST.cls b/src/classes/BDI_Donations_TEST.cls index 2ca8803fc38..f054d9ff932 100644 --- a/src/classes/BDI_Donations_TEST.cls +++ b/src/classes/BDI_Donations_TEST.cls @@ -61,6 +61,175 @@ public with sharing class BDI_Donations_TEST { UTIL_unitTestData_TEST.getOpenStage(), system.Today(), 100, null, null); insert listOppT; } + + /********************************************************************************************************* + * @description operation + * map to checkbox field and manually match to exiting opp + * verify: + * checkbox field is updated by Data Import + */ + static testMethod void TwoDIWithExistingDonationsSpecified_mapAndUpdateCheckbox() { + //skip the test if Advancement is installed + if (ADV_PackageInfo_SVC.useAdv()) return; + + createTestData(); + + List contacts = listConT; + List opportunities = listOppT; + + list dataImports = new list(); + dataImports.add(new DataImport__c(Contact1_Firstname__c=contacts[0].Firstname, + Contact1_Lastname__c=contacts[0].Lastname, + Contact1_Work_Email__c=contacts[0].npe01__WorkEmail__c)); + dataImports.add(new DataImport__c(Contact1_Firstname__c=contacts[1].Firstname, + Contact1_Lastname__c=contacts[1].Lastname, + Contact1_Work_Email__c=contacts[1].npe01__WorkEmail__c)); + + dataImports[0].Donation_Amount__c = opportunities[0].Amount; + dataImports[0].Donation_Date__c = opportunities[0].CloseDate; + dataImports[0].DonationImported__c = opportunities[0].Id; + dataImports[0].Donation_Membership_Origin__c = 'True'; // will map to 'Opp.IsPrivate' + dataImports[0].Payment_Check_Reference_Number__c = 'abc'; + dataImports[0].Payment_Method__c = 'Check'; + + dataImports[1].Donation_Amount__c = opportunities[1].Amount; + dataImports[1].Donation_Date__c = opportunities[1].CloseDate; + dataImports[1].DonationImported__c = opportunities[1].Id; + dataImports[1].Donation_Membership_Origin__c = 'False'; // will map to 'Opp.IsPrivate' + dataImports[1].Payment_Check_Reference_Number__c = '1234'; + dataImports[1].Payment_Method__c = 'Visa'; + insert dataImports; + + // set the specified settings + Data_Import_Settings__c diSettings = UTIL_CustomSettingsFacade.getDataImportSettings(); + diSettings.Donation_Matching_Rule__c = UTIL_Namespace.StrTokenNSPrefix('Donation_Amount__c') + ';' + + UTIL_Namespace.StrTokenNSPrefix('Donation_Date__c'); + // make sure we support matching by Id even when no match specified. + diSettings.Donation_Matching_Behavior__c = BDI_DataImport_API.RequireNoMatch; + diSettings.Run_Opportunity_Rollups_while_Processing__c = true; + + // manually insert checkbox field mapping + Map oppFieldsByDIFields = BDI_Donations.dataImportFieldToOpportunityField; + oppFieldsByDIFields.put(UTIL_Namespace.StrTokenNSPrefix('Donation_Membership_Origin__c'), + 'IsPrivate'); + + //run batch data import + Test.StartTest(); + BDI_DataImport_BATCH bdi = new BDI_DataImport_BATCH(); + ID ApexJobId = Database.executeBatch(bdi, 10); + Test.stopTest(); + + // verify expected results + list updatedOpps = [SELECT + Id, + Name, + Amount, + StageName, + IsWon, + IsPrivate, + IsClosed, + AccountId + FROM Opportunity + ORDER BY Id]; + + System.assertEquals(2, updatedOpps.size()); + for(Opportunity opp: updatedOpps) { + if(opp.Id == opportunities[0].Id) { + System.assertEquals(true, opp.IsPrivate, + 'Import should have set checkbox IsPrivate to true'); + } else { + System.assertEquals(false, opp.IsPrivate, + 'Import should have set checkbox IsPrivate to false'); + } + } + } + + /********************************************************************************************************* + * @description operation + * map to checkbox field and manually match to exiting opp but don't specify value in DI source field + * verify: + * checkbox field is not changed by Data Import + */ + static testMethod void TwoDIWithExistingDonationsSpecified_mapCheckboxNoUpdate() { + //skip the test if Advancement is installed + if (ADV_PackageInfo_SVC.useAdv()) return; + + createTestData(); + + List contacts = listConT; + List opportunities = listOppT; + + opportunities[0].IsPrivate = true; + opportunities[1].IsPrivate = false; + update opportunities; + + list dataImports = new list(); + dataImports.add(new DataImport__c(Contact1_Firstname__c=contacts[0].Firstname, + Contact1_Lastname__c=contacts[0].Lastname, + Contact1_Work_Email__c=contacts[0].npe01__WorkEmail__c)); + dataImports.add(new DataImport__c(Contact1_Firstname__c=contacts[1].Firstname, + Contact1_Lastname__c=contacts[1].Lastname, + Contact1_Work_Email__c=contacts[1].npe01__WorkEmail__c)); + + dataImports[0].Donation_Amount__c = opportunities[0].Amount; + dataImports[0].Donation_Date__c = opportunities[0].CloseDate; + dataImports[0].DonationImported__c = opportunities[0].Id; + dataImports[0].Donation_Membership_Origin__c = null; // will map to 'Opp.IsPrivate' + dataImports[0].Payment_Check_Reference_Number__c = 'abc'; + dataImports[0].Payment_Method__c = 'Check'; + + dataImports[1].Donation_Amount__c = opportunities[1].Amount; + dataImports[1].Donation_Date__c = opportunities[1].CloseDate; + dataImports[1].DonationImported__c = opportunities[1].Id; + dataImports[1].Donation_Membership_Origin__c = null; // will map to 'Opp.IsPrivate' + dataImports[1].Payment_Check_Reference_Number__c = '1234'; + dataImports[1].Payment_Method__c = 'Visa'; + insert dataImports; + + // set the specified settings + Data_Import_Settings__c diSettings = UTIL_CustomSettingsFacade.getDataImportSettings(); + diSettings.Donation_Matching_Rule__c = UTIL_Namespace.StrTokenNSPrefix('Donation_Amount__c') + ';' + + UTIL_Namespace.StrTokenNSPrefix('Donation_Date__c'); + // make sure we support matching by Id even when no match specified. + diSettings.Donation_Matching_Behavior__c = BDI_DataImport_API.RequireNoMatch; + diSettings.Run_Opportunity_Rollups_while_Processing__c = true; + + // manually insert checkbox field mapping + Map oppFieldsByDIFields = BDI_Donations.dataImportFieldToOpportunityField; + oppFieldsByDIFields.put(UTIL_Namespace.StrTokenNSPrefix('Donation_Membership_Origin__c'), + 'IsPrivate'); + + //run batch data import + Test.StartTest(); + BDI_DataImport_BATCH bdi = new BDI_DataImport_BATCH(); + ID ApexJobId = Database.executeBatch(bdi, 10); + Test.stopTest(); + + // verify expected results + list updatedOpps = [SELECT + Id, + Name, + Amount, + StageName, + IsWon, + IsPrivate, + IsClosed, + AccountId + FROM Opportunity + ORDER BY Id]; + + system.assertEquals(2, updatedOpps.size()); + for(Opportunity opp: updatedOpps) { + if(opp.Id == opportunities[0].Id) { + System.assertEquals(true, opp.IsPrivate, + 'Import should not have changed initial value of IsPrivate'); + } else { + System.assertEquals(false, opp.IsPrivate, + 'Import should not have changed initial value of IsPrivate'); + } + } + } + /********************************************************************************************************* * @description Verifies rollups are not calculated when rollup settings if not checked */