From d958f03f90fe868e72dbcb435267cd3ff73f05ce Mon Sep 17 00:00:00 2001 From: tcdahlberg Date: Wed, 18 Feb 2026 17:07:11 -0600 Subject: [PATCH 1/3] added back in match only functionality for metadata --- .../classes/SummitEventsContactMatching.cls | 34 +++++++++- .../SummitEventsContactMatching_TEST.cls | 62 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/force-app/main/default/classes/SummitEventsContactMatching.cls b/force-app/main/default/classes/SummitEventsContactMatching.cls index 3e8dec65..1dcd416f 100644 --- a/force-app/main/default/classes/SummitEventsContactMatching.cls +++ b/force-app/main/default/classes/SummitEventsContactMatching.cls @@ -263,6 +263,8 @@ public without sharing class SummitEventsContactMatching { doCRUD crud = new doCRUD(); if (matches.isEmpty() && noMatchBehavior.startsWithIgnoreCase('Create')) { + //remove values of mappings set to match only so that they are not inserted into the new record + newObj = removeMatchOnlyFields(newObj, customMappingType, mappings, sObjectType); crud.addRecord(newObj); reg.put(fieldAPIName, newObj.Id); reg.put(newFieldAPIName, true); @@ -292,7 +294,7 @@ public without sharing class SummitEventsContactMatching { mappedMatchingMethods = new Map>(); if (mappedMatchingMethods.isEmpty()) { if (matchingMethods.size() > 0) { - String query = 'SELECT Source_Value__c, Source_Type__c, ' + fieldAPIName + ', ' + sourceValue + ' FROM ' + namespace + sObjectType + ' WHERE ' + fieldAPIName + ' IN :matchingMethods'; + String query = 'SELECT Source_Value__c, Source_Type__c, Matching_Only__c, ' + fieldAPIName + ', ' + sourceValue + ' FROM ' + namespace + sObjectType + ' WHERE ' + fieldAPIName + ' IN :matchingMethods'; List results = Database.query(query); for (SObject mapping : results) { String method = (String) mapping.get(fieldAPIName); @@ -375,6 +377,36 @@ public without sharing class SummitEventsContactMatching { return record; } + @TestVisible + private static SObject removeMatchOnlyFields(SObject record, String matchingMethod, Map> mappings, String sObjectType) { + String namespace = SummitEventsNamespace.StrTokenNSPrefix(''); + String objFieldAPIName = getFieldAPINameForObjectType(sObjectType); + + if (mappings.containsKey(matchingMethod)) { + List mappingList = mappings.get(matchingMethod); + for (SObject mapping : mappingList) { + Boolean matchingOnly = (Boolean) mapping.get(namespace + 'Matching_Only__c'); + if (matchingOnly != null && matchingOnly) { + String fieldAPIName = (String) mapping.get(namespace + objFieldAPIName); + // Set the field to null to remove it from the record before insert + record.put(fieldAPIName, null); + } + } + } + return record; + } + + private static String getFieldAPINameForObjectType(String sObjectType) { + if (sObjectType.equals('Contact')) { + return 'Contact_Field_API_Name__c'; + } else if (sObjectType.equals('Account')) { + return 'Person_Account_Field_API_Name__c'; + } else if (sObjectType.equals('Lead')) { + return 'Lead_Field_API_Name__c'; + } + return null; + } + private static Account makePerson(Summit_Events_Registration__c reg, String customMappingType, Map> contactMappings) { Account personAccount = new Account(); Boolean personAccountActive = SummitEventsShared.personAccountsEnabled(); diff --git a/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls b/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls index 5735a74c..90f001b6 100644 --- a/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls +++ b/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls @@ -267,4 +267,66 @@ public class SummitEventsContactMatching_TEST { System.assertEquals(newDate, result5.get('Birthdate'), 'The Birthdate field should be set to 2021-01-05'); Test.stopTest(); } + + @IsTest + static void testRemoveMatchOnlyFields() { + // Create a mock Contact with some fields populated + Contact testContact = new Contact( + FirstName = 'Test', + LastName = 'Contact', + Email = 'test@example.com', + Title = 'Manager', + Department = 'Sales' + ); + + // Create mock mappings with one field marked as Matching_Only__c = true + String namespace = SummitEventsNamespace.StrTokenNSPrefix(''); + Map> mockMappings = new Map>(); + List mappingList = new List(); + + // Create a mapping that is match-only (should be removed) + Summit_Events_Contact_Matching_Mapping__mdt matchOnlyMapping = new Summit_Events_Contact_Matching_Mapping__mdt( + DeveloperName = 'Title_Match_Only', + MasterLabel = 'Title Match Only', + Source_Type__c = 'Field', + Contact_Field_API_Name__c = 'Title', + Contact_Matching_Method__c = 'TestMethod', + Matching_Only__c = true + ); + mappingList.add(matchOnlyMapping); + + // Create a mapping that is NOT match-only (should be kept) + Summit_Events_Contact_Matching_Mapping__mdt regularMapping = new Summit_Events_Contact_Matching_Mapping__mdt( + DeveloperName = 'Department_Regular', + MasterLabel = 'Department Regular', + Source_Type__c = 'Field', + Contact_Field_API_Name__c = 'Department', + Contact_Matching_Method__c = 'TestMethod', + Matching_Only__c = false + ); + mappingList.add(regularMapping); + + mockMappings.put('TestMethod', mappingList); + + Test.startTest(); + // Verify fields are set before calling removeMatchOnlyFields + System.assertEquals('Manager', testContact.Title, 'Title should be Manager before removal'); + System.assertEquals('Sales', testContact.Department, 'Department should be Sales before removal'); + + // Call the removeMatchOnlyFields method + SObject result = SummitEventsContactMatching.removeMatchOnlyFields(testContact, 'TestMethod', mockMappings, 'Contact'); + + // Verify that the match-only field (Title) was removed + System.assertEquals(null, result.get('Title'), 'Title should be null after removeMatchOnlyFields'); + + // Verify that the regular field (Department) was NOT removed + System.assertEquals('Sales', result.get('Department'), 'Department should still be Sales after removeMatchOnlyFields'); + + // Verify other fields remain intact + System.assertEquals('Test', result.get('FirstName'), 'FirstName should remain Test'); + System.assertEquals('Contact', result.get('LastName'), 'LastName should remain Contact'); + System.assertEquals('test@example.com', result.get('Email'), 'Email should remain test@example.com'); + + Test.stopTest(); + } } \ No newline at end of file From c2d673ed4f8dac9b9aec62af7f3addc4b0fea44c Mon Sep 17 00:00:00 2001 From: tcdahlberg Date: Fri, 20 Feb 2026 14:22:02 -0600 Subject: [PATCH 2/3] update unit tests for email and contact matching --- cumulusci.yml | 2 +- .../classes/SummitEventsRegistration.cls | 43 ++--- .../SummitEventsContactMatching_TEST.cls | 154 ++++++++++++++++++ .../classes/SummitEventsRegistration_TEST.cls | 2 +- 4 files changed, 172 insertions(+), 29 deletions(-) diff --git a/cumulusci.yml b/cumulusci.yml index f18fdfa8..d4ca259e 100644 --- a/cumulusci.yml +++ b/cumulusci.yml @@ -244,6 +244,6 @@ orgs: namespaced: true dev: - config_file: orgs/educloud.json + config_file: orgs/dev.json days: 7 namespaced: false \ No newline at end of file diff --git a/force-app/main/default/classes/SummitEventsRegistration.cls b/force-app/main/default/classes/SummitEventsRegistration.cls index 4c2bd72e..e7c937d8 100644 --- a/force-app/main/default/classes/SummitEventsRegistration.cls +++ b/force-app/main/default/classes/SummitEventsRegistration.cls @@ -11,28 +11,6 @@ public class SummitEventsRegistration { List affectedRegs = new List(); String namespace = SummitEventsNamespace.StrTokenNSPrefix(''); - - //Tags that need a little TLC to turn them into real links - List emailTags = new List{ - 'UG_Parking_Pass_Link__c', - 'Add_To_Calendar_Link__c', - 'Event_Registration_Cancel_Link__c', - 'Add_to_Apple_Calendar__c', - 'Add_To_Google_Calendar_Link__c', - 'Add_to_Outlook_Calendar__c', - 'Add_To_Outlook_Web_Calendar__c', - 'Add_To_Yahoo_Calendar__c' - }; - - //Add the namespace to the email tags so that both namespaced and non-namespaced version work - if (String.isNotBlank(namespace)) { - List emailTagsPackaged = new List(); - for (String tag : emailTags) { - emailTagsPackaged.add(namespace + tag); - } - emailTags.addAll(emailTagsPackaged); - } - //Delineator of content in the email templase String originalTemplate = '[[DONT_DELETE_CONTENT_HERE]]'; @@ -155,12 +133,23 @@ public class SummitEventsRegistration { found = ''; } - //replace all hooks with found values from registration - if (emailTags.contains(matcher2.group(1))) { + //Fix formula links that are encoded with the following format: _HL_ENCODED_[link URL]_HL__blank_HL_[link text]_HL_ + if (found.startsWith('_HL_ENCODED_') && found.endsWith('_HL__blank_HL_')) { found = found.replace('_HL_ENCODED_', ''); + found = found.replace('%20target=', ''); found = found.replace(' target=', ''); + found = found.replace('_HL_', '" target="_blank">'); + } + + //Fix any image links that are encoded with the following format: _IM1_[image source]_IM2_[alt text]_IM3_[height]_IM4_[width]_IM5_ + if (found.startsWith('_IM1_') && found.endsWith('_IM5_')) { + found = found.replace('_IM1_', '');
+                                    found = found.replace('_IM3_', ' taskToSave) { + public void saveTask(List taskToSave) { try { insert taskToSave; } catch (Exception e) { diff --git a/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls b/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls index 90f001b6..d319a93b 100644 --- a/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls +++ b/force-app/test/default/classes/SummitEventsContactMatching_TEST.cls @@ -329,4 +329,158 @@ public class SummitEventsContactMatching_TEST { Test.stopTest(); } + + @IsTest + static void testRemoveMatchOnlyFieldsForLead() { + // Create a mock Lead with some fields populated + Lead testLead = new Lead( + FirstName = 'Test', + LastName = 'Lead', + Email = 'testlead@example.com', + Company = 'Test Company', + Title = 'CEO', + Industry = 'Technology' + ); + + // Create mock mappings with Lead-specific fields + String namespace = SummitEventsNamespace.StrTokenNSPrefix(''); + Map> mockMappings = new Map>(); + List leadMappingList = new List(); + + // Create a match-only mapping for Lead (should be removed) + Summit_Events_Lead_Matching_Mapping__mdt matchOnlyMapping = new Summit_Events_Lead_Matching_Mapping__mdt( + DeveloperName = 'Title_Match_Only', + MasterLabel = 'Title Match Only', + Source_Type__c = 'Field', + Lead_Field_API_Name__c = 'Title', + Lead_Matching_Method__c = 'TestLeadMethod', + Matching_Only__c = true + ); + leadMappingList.add(matchOnlyMapping); + + // Create a regular mapping (should be kept) + Summit_Events_Lead_Matching_Mapping__mdt regularMapping = new Summit_Events_Lead_Matching_Mapping__mdt( + DeveloperName = 'Industry_Regular', + MasterLabel = 'Industry Regular', + Source_Type__c = 'Field', + Lead_Field_API_Name__c = 'Industry', + Lead_Matching_Method__c = 'TestLeadMethod', + Matching_Only__c = false + ); + leadMappingList.add(regularMapping); + + mockMappings.put('TestLeadMethod', leadMappingList); + + Test.startTest(); + // Verify fields are set before calling removeMatchOnlyFields + System.assertEquals('CEO', testLead.Title, 'Title should be CEO before removal'); + System.assertEquals('Technology', testLead.Industry, 'Industry should be Technology before removal'); + + // Call the removeMatchOnlyFields method for Lead + SObject result = SummitEventsContactMatching.removeMatchOnlyFields(testLead, 'TestLeadMethod', mockMappings, 'Lead'); + + // Verify that the match-only field (Title) was removed + System.assertEquals(null, result.get('Title'), 'Title should be null after removeMatchOnlyFields'); + + // Verify that the regular field (Industry) was NOT removed + System.assertEquals('Technology', result.get('Industry'), 'Industry should still be Technology after removeMatchOnlyFields'); + + // Verify other fields remain intact + System.assertEquals('Test', result.get('FirstName'), 'FirstName should remain Test'); + System.assertEquals('Lead', result.get('LastName'), 'LastName should remain Lead'); + System.assertEquals('testlead@example.com', result.get('Email'), 'Email should remain testlead@example.com'); + System.assertEquals('Test Company', result.get('Company'), 'Company should remain Test Company'); + + Test.stopTest(); + } + + @IsTest + static void testRemoveMatchOnlyFieldsForAccount() { + // Only run this test if Person Accounts are enabled + Boolean personAccountsEnabled = SummitEventsShared.personAccountsEnabled(); + if (!personAccountsEnabled) { + // Skip this test in orgs without Person Accounts + System.assert(true, 'Skipping Person Account test - Person Accounts not enabled'); + return; + } + + // Create a mock Account (for Person Account testing) + Account testAccount = new Account( + Name = 'Test Account', + Industry = 'Education', + Type = 'Prospect' + ); + + // Create mock mappings with Account-specific fields + String namespace = SummitEventsNamespace.StrTokenNSPrefix(''); + Map> mockMappings = new Map>(); + List accountMappingList = new List(); + + // Create a match-only mapping for Account (should be removed) + Summit_Events_Person_Matching_Mapping__mdt matchOnlyMapping = new Summit_Events_Person_Matching_Mapping__mdt( + DeveloperName = 'Type_Match_Only', + MasterLabel = 'Type Match Only', + Source_Type__c = 'Field', + Person_Account_Field_API_Name__c = 'Type', + Person_Account_Matching_Method__c = 'TestAccountMethod', + Matching_Only__c = true + ); + accountMappingList.add(matchOnlyMapping); + + // Create a regular mapping (should be kept) + Summit_Events_Person_Matching_Mapping__mdt regularMapping = new Summit_Events_Person_Matching_Mapping__mdt( + DeveloperName = 'Industry_Regular', + MasterLabel = 'Industry Regular', + Source_Type__c = 'Field', + Person_Account_Field_API_Name__c = 'Industry', + Person_Account_Matching_Method__c = 'TestAccountMethod', + Matching_Only__c = false + ); + accountMappingList.add(regularMapping); + + mockMappings.put('TestAccountMethod', accountMappingList); + + Test.startTest(); + // Verify fields are set before calling removeMatchOnlyFields + System.assertEquals('Prospect', testAccount.Type, 'Type should be Prospect before removal'); + System.assertEquals('Education', testAccount.Industry, 'Industry should be Education before removal'); + + // Call the removeMatchOnlyFields method for Account + SObject result = SummitEventsContactMatching.removeMatchOnlyFields(testAccount, 'TestAccountMethod', mockMappings, 'Account'); + + // Verify that the match-only field (Type) was removed + System.assertEquals(null, result.get('Type'), 'Type should be null after removeMatchOnlyFields'); + + // Verify that the regular field (Industry) was NOT removed + System.assertEquals('Education', result.get('Industry'), 'Industry should still be Education after removeMatchOnlyFields'); + + // Verify other fields remain intact + System.assertEquals('Test Account', result.get('Name'), 'Name should remain Test Account'); + + Test.stopTest(); + } + + @IsTest + static void testRemoveMatchOnlyFieldsWithNoMappings() { + // Test case where no mappings exist for the method + Contact testContact = new Contact( + FirstName = 'Test', + LastName = 'Contact', + Email = 'test@example.com', + Title = 'Manager' + ); + + Map> mockMappings = new Map>(); + + Test.startTest(); + // Call the removeMatchOnlyFields method with non-existent method name + SObject result = SummitEventsContactMatching.removeMatchOnlyFields(testContact, 'NonExistentMethod', mockMappings, 'Contact'); + + // Verify that nothing changed when no mappings exist + System.assertEquals('Manager', result.get('Title'), 'Title should remain Manager when no mappings exist'); + System.assertEquals('Test', result.get('FirstName'), 'FirstName should remain Test'); + System.assertEquals('Contact', result.get('LastName'), 'LastName should remain Contact'); + + Test.stopTest(); + } } \ No newline at end of file diff --git a/force-app/test/default/classes/SummitEventsRegistration_TEST.cls b/force-app/test/default/classes/SummitEventsRegistration_TEST.cls index 2f24f571..b64aaf26 100644 --- a/force-app/test/default/classes/SummitEventsRegistration_TEST.cls +++ b/force-app/test/default/classes/SummitEventsRegistration_TEST.cls @@ -25,7 +25,7 @@ public class SummitEventsRegistration_TEST { email2.Event__c = seaTestInstances[1].Event__c; email2.Action_Status__c = 'Registered'; email2.Action_Sub_status__c = 'In Progress'; - email2.Email_Content__c = 'Sample text here {!Registrant_Last_Name__c} {!Add_To_Calendar_Link__c}'; + email2.Email_Content__c = 'Sample text here {!Registrant_Last_Name__c} {!Add_To_Calendar_Link__c} {!Registrant_QR_Code_Image_URL__c}'; email2.Letterhead_HTML__c = 'Letterhead goes here
[[DONT_DELETE_CONTENT_HERE]]'; email2.BCC_Email__c = 'bcc@example.com'; insert email2; From 0c6eaedda7fce448980f882ac4824f48910e6397 Mon Sep 17 00:00:00 2001 From: tcdahlberg Date: Fri, 20 Feb 2026 15:02:25 -0600 Subject: [PATCH 3/3] switch cci to educloud --- cumulusci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulusci.yml b/cumulusci.yml index d4ca259e..f18fdfa8 100644 --- a/cumulusci.yml +++ b/cumulusci.yml @@ -244,6 +244,6 @@ orgs: namespaced: true dev: - config_file: orgs/dev.json + config_file: orgs/educloud.json days: 7 namespaced: false \ No newline at end of file