Merge branch 'client-request/ticket_1633454444'

This commit is contained in:
cgary committed 2025-04-25 17:00:33 -04:00
commit e577b2d0b4
92 files changed
+206 -11

No files matched your search

+3
View File
@@ -42,6 +42,9 @@ package.xml
#Exclude Dashboards #Exclude Dashboards
**/dashboards/** **/dashboards/**
# EXclude Listviews
**/listViews/**
# Exclude Remote Site Settings # Exclude Remote Site Settings
@@ -0,0 +1,2 @@
xœ•ÎM
1 @a×=E. $ý› ˆwiÒTG:ðø‚k7îßO·u]xJ§ÑÍ@U'A�FVÓ,F)rõ­F­ÄRdÏRÝ«t{�PRN*…ªÏI*Kh„1ÔÙ7d6%öJ®ã¾uØ[}þ]␍F/úXž7¸\�¦˜|8g8cDtúöq¿J÷ŽFDé
@@ -0,0 +1,4 @@
xœ•ÎÁ
!€áÎ>ż@ ŽŽ
Ñ»ŒãXKl® =~йK÷ÿƒ_¶u]&xOs¨btI3Jò•Äybn¡&ÌͲ”–Ù:6/úœÐ­Hë5”Ø]ÊDEmeÌèÑ1§–¼¯I«ácÞ·{ooØ·cˆÂ,�åyƒË\
ÑStálƒµF¾cSÿ æWi>¯ÑCÓ
@@ -0,0 +1,2 @@
xœ•ÎA
1 @Q×=E. ¤m&mA¼Kš¦:È8R+x|Áµ÷ÿÁ×}ÛÖ Á/‡9Ì ‹Ï‚¹ùŠÑ—ÆJ�¬´Ð‰c‰•b"²{Ȱû„Ê5ÕØXsW$ž f.Ü’ZÓÜ¥5qòš×}À³·7<÷×Pƒ9Doëý§3øDKàÄK�#¢ÓïØ´?ˆûUº©ID
@@ -0,0 +1,4 @@
xś•ÎA
Â0@Q×9Ĺ\@H2“¦ń.“ÉŚ©•4Ź/¸văţ?ř˛­ë2 †t]Ě(Ô2U¬1Ńdł™I#VMy´2×,d-¸w}`m%cDÎč˝z±9N¨)zndą”ăľuŘ­˝aߎ.
Łł<–ç␍.W™R$*>ĂŮ“÷NľcC˙ îWé>~
DŰ
@@ -0,0 +1,2 @@
xœ•ÎA
Â0@Q×9Å\@H&3ɤwI§S-ÒVÒ<¾àÚ�ûÿàë¾®K |éÍ b¦¬X“Äb¹VC?&Ï%Î�¢”0fBq¯Úlë 9 ià4'"1bŸ-)F?&RŽšeWÏþØóô†c?›ôVõ¹lw¸␍21’`a¸zòÞéw¬ÛÄý*ÝlÜAÝ
@@ -0,0 +1,2 @@
xœ•ÎM
1 @a×=E. ¤iâ]Ú4ÕAÆ‘N<¾àÚ�û÷Á“m]— ÎÆÓªÀ=&ÌVPkL܈(‡Œ wßšRwÜ,b2¯2ô9»‹…‹PMÔ’cñY{.9‡V) ±·,Õ”cÞ·{ooØ·cˆÂEËó—+Ø¢£ˆäáŒÑÈwlêÄü*ÍUCK
@@ -0,0 +1 @@
x°+)JMU06d01000PхMллcх*][И╥╗Ё╜NИмcmУWsYУv/
@@ -1 +1 @@
16e7a98d17a40cc2d21421b23373f5f54a6d4214 3f635a585a79811712905e7ed8bacd891fb2dbd1
+72 -6
View File
@@ -1,6 +1,6 @@
{ {
"fileVersion": 0, "fileVersion": 0,
"serverMaxRevisionCounter": 81, "serverMaxRevisionCounter": 125,
"sourceMembers": { "sourceMembers": {
"ReportFolder__prm_channel_reports_folder": { "ReportFolder__prm_channel_reports_folder": {
"memberType": "ReportFolder", "memberType": "ReportFolder",
@@ -196,20 +196,20 @@
}, },
"Profile__Admin": { "Profile__Admin": {
"memberType": "Profile", "memberType": "Profile",
"serverRevisionCounter": 44, "serverRevisionCounter": 124,
"lastRetrievedFromServer": null, "lastRetrievedFromServer": null,
"isNameObsolete": false "isNameObsolete": false
}, },
"ApexClass__OpportunityCloneService": { "ApexClass__OpportunityCloneService": {
"memberType": "ApexClass", "memberType": "ApexClass",
"serverRevisionCounter": 45, "serverRevisionCounter": 115,
"lastRetrievedFromServer": 45, "lastRetrievedFromServer": 115,
"isNameObsolete": false "isNameObsolete": false
}, },
"ApexClass__OpportunityCloneServiceTest": { "ApexClass__OpportunityCloneServiceTest": {
"memberType": "ApexClass", "memberType": "ApexClass",
"serverRevisionCounter": 46, "serverRevisionCounter": 125,
"lastRetrievedFromServer": 46, "lastRetrievedFromServer": 125,
"isNameObsolete": false "isNameObsolete": false
}, },
"ApexClass__TestCloneUtility": { "ApexClass__TestCloneUtility": {
@@ -337,6 +337,72 @@
"serverRevisionCounter": 81, "serverRevisionCounter": 81,
"lastRetrievedFromServer": null, "lastRetrievedFromServer": null,
"isNameObsolete": false "isNameObsolete": false
},
"ListView__Opportunity.AllOpportunities": {
"memberType": "ListView",
"serverRevisionCounter": 88,
"lastRetrievedFromServer": null,
"isNameObsolete": false
},
"ListView__Product2.AllProducts": {
"memberType": "ListView",
"serverRevisionCounter": 90,
"lastRetrievedFromServer": null,
"isNameObsolete": false
},
"Layout__SmartCloneRecordExclusionRule__mdt-SmartClone Record Exclusion Rule Layout": {
"memberType": "Layout",
"serverRevisionCounter": 104,
"lastRetrievedFromServer": null,
"isNameObsolete": false
},
"Profile__B2B Reordering Portal Buyer Profile": {
"memberType": "Profile",
"serverRevisionCounter": 96,
"lastRetrievedFromServer": null,
"isNameObsolete": false
},
"CustomObject__SmartCloneRecordExclusionRule__mdt": {
"memberType": "CustomObject",
"serverRevisionCounter": 98,
"lastRetrievedFromServer": 98,
"isNameObsolete": false
},
"CustomField__SmartCloneRecordExclusionRule__mdt.RelatedObject__c": {
"memberType": "CustomField",
"serverRevisionCounter": 99,
"lastRetrievedFromServer": 99,
"isNameObsolete": false
},
"CustomField__SmartCloneRecordExclusionRule__mdt.ExclusionFormula__c": {
"memberType": "CustomField",
"serverRevisionCounter": 101,
"lastRetrievedFromServer": 101,
"isNameObsolete": false
},
"CustomField__SmartCloneRecordExclusionRule__mdt.IsActive__c": {
"memberType": "CustomField",
"serverRevisionCounter": 103,
"lastRetrievedFromServer": 103,
"isNameObsolete": false
},
"CustomMetadata__SmartCloneRecordExclusionRule.LineItemPriceBelowFiftyDollars": {
"memberType": "CustomMetadata",
"serverRevisionCounter": 112,
"lastRetrievedFromServer": null,
"isNameObsolete": true
},
"CustomMetadata__SmartCloneRecordExclusionRule.QuantityLessThanTwo": {
"memberType": "CustomMetadata",
"serverRevisionCounter": 116,
"lastRetrievedFromServer": 116,
"isNameObsolete": false
},
"StaticResource__SmartClone_TestData": {
"memberType": "StaticResource",
"serverRevisionCounter": 117,
"lastRetrievedFromServer": 117,
"isNameObsolete": false
} }
} }
} }
@@ -8,6 +8,7 @@
* 2021-04-12 - CJG - Added setting to restrict child records shown to a particular List * 2021-04-12 - CJG - Added setting to restrict child records shown to a particular List
* 2021-07-08 - CJG - removed functionality to clear out OpportunityLineItem.UnitPrice in * 2021-07-08 - CJG - removed functionality to clear out OpportunityLineItem.UnitPrice in
* order to insert OpportunityLineItems. * order to insert OpportunityLineItems.
* 2024-04-12 - CJG - Added functionality to evaluate the record against a formula to determine if it should be excluded from the clone.
*/ */
public with sharing class OpportunityCloneService { public with sharing class OpportunityCloneService {
/** /**
@@ -19,6 +20,8 @@ public with sharing class OpportunityCloneService {
* @description Map of Child relationship objects to the opportunity. * @description Map of Child relationship objects to the opportunity.
*/ */
public static Map<String,Schema.DescribeSObjectResult> opportunityChildrenMap; public static Map<String,Schema.DescribeSObjectResult> opportunityChildrenMap;
public static Map<String,SmartCloneRecordExclusionRule__mdt> exclusionRuleMap;
public static Map<String,List<FormulaEval.FormulaInstance>> formulaInstanceBySObjectMap;
/** /**
* @description static constructor that will populate the opportunityChildrenMap * @description static constructor that will populate the opportunityChildrenMap
*/ */
@@ -43,6 +46,24 @@ public with sharing class OpportunityCloneService {
} }
} }
} }
exclusionRuleMap = new Map<String,SmartCloneRecordExclusionRule__mdt>();
formulaInstanceBySObjectMap = new Map<String,List<FormulaEval.FormulaInstance>>();
Map<String,Schema.SObjectType> sObjectTypeMap = Schema.getGlobalDescribe();
for(SmartCloneRecordExclusionRule__mdt rule:SmartCloneRecordExclusionRule__mdt.getAll().values()){
if(rule.IsActive__c && String.isNotBlank(rule.ExclusionFormula__c)){
exclusionRuleMap.put(rule.DeveloperName,rule);
String sObjectName = rule.RelatedObject__c;
FormulaEval.FormulaInstance fInstance = Formula.builder().withType(sObjectTypeMap.get(sObjectName.toLowerCase()))
.withReturnType(FormulaEval.FormulaReturnType.Boolean)
.withFormula(rule.ExclusionFormula__c).build();
List<FormulaEval.FormulaInstance> fInstanceList = formulaInstanceBySObjectMap.get(sObjectName);
if(fInstanceList == null){
fInstanceList = new List<FormulaEval.FormulaInstance>();
}
fInstanceList.add(fInstance);
formulaInstanceBySObjectMap.put(sObjectName,fInstanceList);
}
}
} }
/** /**
* @description Lightning Exposed method that will provide a map of Child relationships * @description Lightning Exposed method that will provide a map of Child relationships
@@ -185,17 +206,31 @@ public with sharing class OpportunityCloneService {
} }
private static List<SObject> CloneAndReassociateRecords(List<SObject> recList, String parentFieldName, Id newParentId) { private static List<SObject> CloneAndReassociateRecords(List<SObject> recList, String parentFieldName, Id newParentId) {
System.debug(LoggingLevel.INFO,'\n\nOpportunityCloneService.CloneAndReassociateRecords Executing.\n\n ');
List<SObject> newList = new List<sObject>(); List<SObject> newList = new List<sObject>();
for(SObject rec:recList){ for(SObject rec:recList){
SObject newRec = rec.clone(false,true,false,false); SObject newRec = rec.clone(false,true,false,false);
newRec.put(parentFieldName, newParentId); newRec.put(parentFieldName, newParentId);
/** String sObjectName = newRec.getSObjectType().getDescribe().getName();
if(newRec.getSObjectType().getDescribe().getName().toUpperCase() == 'OPPORTUNITYLINEITEM') { if(sObjectName.toUpperCase() == 'OPPORTUNITYLINEITEM') {
newRec.put('UnitPrice',null); newRec.put('UnitPrice',null);
} }
*/ //TODO: This is where we can evaluate the record to determine if it meets the formula criteria being included
// as a child record.
Boolean fResult = false;
if(formulaInstanceBySObjectMap.containsKey(sObjectName)){
List<FormulaEval.FormulaInstance> fInstanceList = formulaInstanceBySObjectMap.get(sObjectName);
for(FormulaEval.FormulaInstance fInstance:fInstanceList){
fResult = (Boolean)fInstance.evaluate(newRec);
if(fResult) {
break;
}
}
}
if(!fResult) {
newList.add(newRec); newList.add(newRec);
} }
}
return newList; return newList;
} }
@@ -70,6 +70,7 @@ private class OpportunityCloneServiceTest {
} }
} }
insert oliTestLines; insert oliTestLines;
testFutureMethod();
} }
@isTest @isTest
@@ -106,10 +107,11 @@ private class OpportunityCloneServiceTest {
} }
@isTest @isTest
static void CloneOpportunityWithChildren(){ static void CloneOpportunityWithChildren(){
Test.startTest();
Opportunity testOpp = [SELECT Id, Name FROM Opportunity LIMIT 1]; Opportunity testOpp = [SELECT Id, Name FROM Opportunity LIMIT 1];
Map<String,String> testReplacements = new Map<String,String>(); Map<String,String> testReplacements = new Map<String,String>();
testReplacements.put('Name',TestCloneUtility.GenerateRandomString(10)); testReplacements.put('Name',TestCloneUtility.GenerateRandomString(10));
Test.startTest();
Id testResult = OpportunityCloneService.CloneOpportunityWithChildren(testOpp.Id, testReplacements, Id testResult = OpportunityCloneService.CloneOpportunityWithChildren(testOpp.Id, testReplacements,
new List<String>{'OpportunityLineItems'}); new List<String>{'OpportunityLineItems'});
@@ -117,4 +119,9 @@ private class OpportunityCloneServiceTest {
Test.stopTest(); Test.stopTest();
} }
@future
public static void testFutureMethod(){
//insert some Exlusion rules
Test.loadData(SmartCloneRecordExclusionRule__mdt.SObjectType, 'SmartClone_TestData');
}
} }
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<label>QuantityLessThanTwo</label>
<protected>false</protected>
<values>
<field>ExclusionFormula__c</field>
<value xsi:type="xsd:string">Quantity &lt; 2</value>
</values>
<values>
<field>IsActive__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>RelatedObject__c</field>
<value xsi:type="xsd:string">OpportunityLineItem</value>
</values>
</CustomMetadata>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Exclusion rules that the SmartClone component will use to evaluate each record and determine if it can be cloned.</description>
<label>SmartClone Record Exclusion Rule</label>
<pluralLabel>SmartClone Record Exclusion Rules</pluralLabel>
<visibility>Public</visibility>
</CustomObject>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>ExclusionFormula__c</fullName>
<description>The formula to apply to the record that determines if it is excluded from the Clone process. If the formula is true, the record is excluded.</description>
<fieldManageability>SubscriberControlled</fieldManageability>
<inlineHelpText>The formula to apply to the record that determines if it is excluded from the Clone process. If the formula is true, the record is excluded.</inlineHelpText>
<label>Exclusion Formula</label>
<length>3900</length>
<type>LongTextArea</type>
<visibleLines>3</visibleLines>
</CustomField>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>IsActive__c</fullName>
<defaultValue>true</defaultValue>
<description>Use the rule to evaluate exclusions</description>
<fieldManageability>SubscriberControlled</fieldManageability>
<inlineHelpText>Determine whether to actively use the rule in excluding records.</inlineHelpText>
<label>Active</label>
<type>Checkbox</type>
</CustomField>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>RelatedObject__c</fullName>
<description>The Object that ruleset should apply to. It must be a child of the Opportunity Record.</description>
<fieldManageability>SubscriberControlled</fieldManageability>
<inlineHelpText>The Object that ruleset should apply to. It must be a child of the Opportunity Record.</inlineHelpText>
<label>Related Object</label>
<referenceTo>EntityDefinition</referenceTo>
<relationshipLabel>SmartCloneRecordExclusionRules</relationshipLabel>
<relationshipName>SmartCloneRecordExclusionRules</relationshipName>
<required>true</required>
<type>MetadataRelationship</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,2 @@
DeveloperName,MasterLabel,IsActive__c,RelatedObject__c,ExclusionFormula__c
QuantityLessThanThree,QuantityLessThanThree,TRUE,OpportunityLineItem,Quantity < 3
1 DeveloperName MasterLabel IsActive__c RelatedObject__c ExclusionFormula__c
2 QuantityLessThanThree QuantityLessThanThree TRUE OpportunityLineItem Quantity < 3
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata">
<cacheControl>Public</cacheControl>
<contentType>text/csv</contentType>
<description>Test Data for SmartClone Code Coverage.</description>
</StaticResource>