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
+221 -26

No files matched your search

+3
View File
@@ -42,6 +42,9 @@ package.xml
#Exclude Dashboards
**/dashboards/**
# EXclude Listviews
**/listViews/**
# 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,
"serverMaxRevisionCounter": 81,
"serverMaxRevisionCounter": 125,
"sourceMembers": {
"ReportFolder__prm_channel_reports_folder": {
"memberType": "ReportFolder",
@@ -196,20 +196,20 @@
},
"Profile__Admin": {
"memberType": "Profile",
"serverRevisionCounter": 44,
"serverRevisionCounter": 124,
"lastRetrievedFromServer": null,
"isNameObsolete": false
},
"ApexClass__OpportunityCloneService": {
"memberType": "ApexClass",
"serverRevisionCounter": 45,
"lastRetrievedFromServer": 45,
"serverRevisionCounter": 115,
"lastRetrievedFromServer": 115,
"isNameObsolete": false
},
"ApexClass__OpportunityCloneServiceTest": {
"memberType": "ApexClass",
"serverRevisionCounter": 46,
"lastRetrievedFromServer": 46,
"serverRevisionCounter": 125,
"lastRetrievedFromServer": 125,
"isNameObsolete": false
},
"ApexClass__TestCloneUtility": {
@@ -337,6 +337,72 @@
"serverRevisionCounter": 81,
"lastRetrievedFromServer": null,
"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-07-08 - CJG - removed functionality to clear out OpportunityLineItem.UnitPrice in
* 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 {
/**
@@ -19,30 +20,50 @@ public with sharing class OpportunityCloneService {
* @description Map of Child relationship objects to the opportunity.
*/
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
*/
static {
List<Schema.ChildRelationship> childRelationshipList =
Schema.Opportunity.getSObjectType().getDescribe().getChildRelationships();
opportunityChildrenMap = new Map<String, Schema.DescribeSObjectResult>();
List<String> restrictedRelationshipList = new List<String>();
String restrictedChildList = Label.SmartCloneChildList;
if(String.isNotBlank(restrictedChildList)){
restrictedRelationshipList = restrictedChildList.split(';');
}
for(Schema.ChildRelationship childRel:childRelationshipList) {
if(String.isNotBlank(childRel.getRelationshipName())){
Schema.DescribeSObjectResult childObjRes = childRel.getChildSObject().getDescribe();
if(!restrictedRelationshipList.isEmpty() && restrictedRelationshipList[0] != 'N/A'){
if(restrictedRelationshipList.contains(childObjRes.getName())){
opportunityChildrenMap.put(childRel.getRelationshipName(),childObjRes);
}
} else {
opportunityChildrenMap = new Map<String, Schema.DescribeSObjectResult>();
List<String> restrictedRelationshipList = new List<String>();
String restrictedChildList = Label.SmartCloneChildList;
if(String.isNotBlank(restrictedChildList)){
restrictedRelationshipList = restrictedChildList.split(';');
}
for(Schema.ChildRelationship childRel:childRelationshipList) {
if(String.isNotBlank(childRel.getRelationshipName())){
Schema.DescribeSObjectResult childObjRes = childRel.getChildSObject().getDescribe();
if(!restrictedRelationshipList.isEmpty() && restrictedRelationshipList[0] != 'N/A'){
if(restrictedRelationshipList.contains(childObjRes.getName())){
opportunityChildrenMap.put(childRel.getRelationshipName(),childObjRes);
}
} else {
opportunityChildrenMap.put(childRel.getRelationshipName(),childObjRes);
}
}
}
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
@@ -185,16 +206,30 @@ public with sharing class OpportunityCloneService {
}
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>();
for(SObject rec:recList){
SObject newRec = rec.clone(false,true,false,false);
newRec.put(parentFieldName, newParentId);
/**
if(newRec.getSObjectType().getDescribe().getName().toUpperCase() == 'OPPORTUNITYLINEITEM') {
String sObjectName = newRec.getSObjectType().getDescribe().getName();
if(sObjectName.toUpperCase() == 'OPPORTUNITYLINEITEM') {
newRec.put('UnitPrice',null);
}
*/
newList.add(newRec);
//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);
}
}
return newList;
}
@@ -70,6 +70,7 @@ private class OpportunityCloneServiceTest {
}
}
insert oliTestLines;
testFutureMethod();
}
@isTest
@@ -106,10 +107,11 @@ private class OpportunityCloneServiceTest {
}
@isTest
static void CloneOpportunityWithChildren(){
Test.startTest();
Opportunity testOpp = [SELECT Id, Name FROM Opportunity LIMIT 1];
Map<String,String> testReplacements = new Map<String,String>();
testReplacements.put('Name',TestCloneUtility.GenerateRandomString(10));
Test.startTest();
Id testResult = OpportunityCloneService.CloneOpportunityWithChildren(testOpp.Id, testReplacements,
new List<String>{'OpportunityLineItems'});
@@ -117,4 +119,9 @@ private class OpportunityCloneServiceTest {
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>