Custom Package Total Calculation
Use a quote calculator plugin to calculate the total price for all components in a
quote line and then store that value in the custom field Component Custom Total.
| Available in: Salesforce CPQ Winter ’16 and later |
These are sample Apex and Javascript plugins for use in the JavaScript Quote Calculator. Each version exports all of the methods that the calculator looks for, and documents their parameters and return types.
Javascript
1export function onInit(lines) {
2 if (lines != null) {
3 lines.forEach(function (line) {
4 line.record["Component_Custom_Total__c"] = 0;
5 });
6 }
7};
8
9export function onAfterCalculate(quoteModel, quoteLines) {
10 if (quoteLines != null) {
11 quoteLines.forEach(function (line) {
12 var parent = line.parentItem;
13 if (parent != null) {
14 var pComponentCustomTotal = parent.record["Component_Custom_Total__c"] || 0;
15 var cListPrice = line.ProratedListPrice__c || 0;
16 var cQuantity = line.Quantity__c == null ? 1 : line.Quantity__c;
17 var cPriorQuantity = line.PriorQuantity__c || 0;
18 var cPricingMethod = line.PricingMethod__c == null ? "List" : line.PricingMethod__c;
19 var cDiscountScheduleType = line.DiscountScheduleType__c || '';
20 var cRenewal = line.Renewal__c || false;
21 var cExisting = line.Existing__c || false;
22 var cSubscriptionPricing = line.SubscriptionPricing__c || '';
23
24 var cTotalPrice = getTotal(cListPrice, cQuantity, cPriorQuantity, cPricingMethod, cDiscountScheduleType, cRenewal, cExisting, cSubscriptionPricing, cListPrice);
25 pComponentCustomTotal += cTotalPrice;
26
27 parent.record["Component_Custom_Total__c"] = pComponentCustomTotal;
28 }
29 });
30 }
31};
32
33function getTotal(price, qty, priorQty, pMethod, dsType, isRen, isExist, subPricing, listPrice) {
34 if ((isRen === true) && (isExist === false) && (priorQty == null)) {
35 // Personal note: In onAfterCalculate, we specifically make sure that priorQuantity can't be null.
36 // So isn't this loop pointless?
37 return 0;
38 } else {
39 return price * getEffectiveQuantity(qty, priorQty, pMethod, dsType, isRen, isExist, subPricing, listPrice);
40 }
41}
42
43function getEffectiveQuantity(qty, priorQty, pMethod, dsType, isRen, exists, subPricing, listPrice) {
44 var delta = qty - priorQty;
45
46 if (pMethod == 'Block' && delta == 0) {
47 return 0;
48 } else if (pMethod == 'Block') {
49 return 1;
50 } else if (dsType == 'Slab' && (delta == 0 || (qty == 0 && isRen == true))) {
51 return 0;
52 } else if (dsType == 'Slab') {
53 return 1;
54 } else if (exists == true && subPricing == '' && delta < 0) {
55 return 0;
56 } else if (exists == true && subPricing == 'Percent Of Total' && listPrice != 0 && delta >= 0) {
57 return qty;
58 } else if (exists == true) {
59 return delta;
60 } else {
61 return qty;
62 }
63}Apex
1global class QCPWinter16Legacy implements SBQQ.QuoteCalculatorPlugin, SBQQ.QuoteCalculatorPlugin2 {
2
3 /* NOTE: the getReferencedFields method is no longer required if you use the ReferencedFields field set on
4 the Quote Line object.
5 This field set must be created as it's not a managed one.
6 NOTE: if you need to access Quote fields, you can create the ReferencedFields field set on the Quote object as well.
7 NOTE: if you do not use the getReferencedFields method, you can remove SBQQ.QuoteCalculatorPlugin2 from the class declaration.
8 */
9 global Set<String> getReferencedFields() {
10 return new Set<String>{
11 /* Note: add fields using the following format - Only add fields referenced
12
13 by the plugin and not in the Line Editor field set on the Quote Line object
14 String.valueOf(SBQQ__QuoteLine__c.My_Field_API_Name__c)
15 */
16 String.valueOf(SBQQ__QuoteLine__c.Component_Custom_Total__c),
17
18 String.valueOf(SBQQ__QuoteLine__c.SBQQ__ProratedListPrice__c),
19 String.valueOf(SBQQ__QuoteLine__c.SBQQ__PriorQuantity__c),
20 String.valueOf(SBQQ__QuoteLine__c.SBQQ__PricingMethod__c),
21 String.valueOf(SBQQ__QuoteLine__c.SBQQ__DiscountScheduleType__c),
22 String.valueOf(SBQQ__QuoteLine__c.SBQQ__Renewal__c),
23 String.valueOf(SBQQ__QuoteLine__c.SBQQ__Existing__c),
24 String.valueOf(SBQQ__QuoteLine__c.SBQQ__SubscriptionPricing__c)
25 };
26 }
27
28 global void onBeforePriceRules(SObject quote, SObject[] lines) {
29 }
30
31 global void onAfterPriceRules(SObject quote, SObject[] lines) {
32 }
33
34 global void onBeforeCalculate(SObject quote, SObject[] lines) {
35 }
36
37 global void onAfterCalculate(SObject quote, SObject[] lines) {
38 for(SObject line : lines) {
39 SObject parent = line.getSObject(SBQQ__QuoteLine__c.SBQQ__RequiredBy__c.getDescribe().getRelationshipName());
40 if(parent != null) {
41 Decimal pComponentCustomTotal = (Decimal)parent.get(String.valueOf(SBQQ__QuoteLine__c.Component_Custom_Total__c));
42
43 Decimal cListPrice = (Decimal)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__ProratedListPrice__c));
44 Decimal cQuantity = (Decimal)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__Quantity__c));
45 Decimal cPriorQuantity = (Decimal)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__PriorQuantity__c));
46 String cPricingMethod = (String)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__PricingMethod__c));
47 String cDiscountScheduleType = (String)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__DiscountScheduleType__c));
48 Boolean cRenewal = (Boolean)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__Renewal__c));
49 Boolean cExisting = (Boolean)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__Existing__c));
50 String cSubscriptionPricing = (String)line.get(String.valueOf(SBQQ__QuoteLine__c.SBQQ__SubscriptionPricing__c));
51
52 pComponentCustomTotal = (pComponentCustomTotal == null) ? 0 : pComponentCustomTotal;
53
54 cListPrice = (cListPrice == null) ? 0 : cListPrice;
55 cQuantity = (cQuantity == null) ? 1 : cQuantity;
56 cPriorQuantity = (cPriorQuantity == null) ? 0 : cPriorQuantity;
57 cPricingMethod = (cPricingMethod == null) ? 'List' : cPricingMethod;
58 cDiscountSCheduleType = (cDiscountSCheduleType == null) ? '' : cDiscountSCheduleType;
59 cRenewal = (cRenewal == null) ? false : cRenewal;
60 cExisting = (cExisting == null) ? false : cExisting;
61 cSubscriptionPricing = (cSubscriptionPricing == null) ? '' : cSubscriptionPricing;
62
63 Decimal cTotalPrice = getTotal(cListPrice, cQuantity, cPriorQuantity, cPricingMethod, cDiscountScheduleType, cRenewal, cExisting, cSubscriptionPricing, cListPrice);
64 pComponentCustomTotal += cTotalPrice;
65
66 parent.put(SBQQ__QuoteLine__c.Component_Custom_Total__c, pComponentCustomTotal);
67
68 }
69 }
70 }
71
72 global void onInit(SObject[] lines) {
73 for(SObject line : lines) {
74 line.put(SBQQ__QuoteLine__c.Component_Custom_Total__c, 0);
75 }
76 }
77
78 private Decimal getTotal(Decimal price, Decimal quantity, Decimal priorQuantity, String pricingMethod, String discountScheduleType, Boolean renewal, Boolean existing, String subscriptionPricing, Decimal ListPrice) {
79 price = (price == null) ? 0 : price;
80 renewal = (renewal == null) ? false : renewal;
81 existing = (existing == null) ? false : existing;
82
83 if(renewal == true && existing == false && priorQuantity == null) {
84 return 0;
85 } else {
86 return price * getEffectiveQuantity(quantity, priorQuantity, pricingMethod, discountScheduleType, renewal, existing, subscriptionPricing, listPrice);
87 }
88
89 }
90
91 private Decimal getEffectiveQuantity(Decimal quantity, Decimal priorQuantity, String pricingMethod, String discountScheduleType, Boolean renewal, Boolean existing, String subscriptionPricing, Decimal ListPrice) {
92 Decimal result = 0;
93 Decimal deltaQuantity = 0;
94
95 quantity = (quantity == null) ? 0 : quantity;
96 priorQuantity = (priorQuantity == null) ? 0 : priorQuantity;
97 pricingMethod = (pricingMethod == null) ? '' : pricingMethod;
98 discountScheduleType = (discountScheduleType == null) ? '' : discountScheduleType;
99 subscriptionPricing = (subscriptionPricing == null) ? '' : subscriptionPricing;
100 renewal = (renewal == null) ? false : renewal;
101 existing = (existing == null) ? false : existing;
102 listPrice = (listPrice == null) ? 0 : listPrice;
103
104 deltaQuantity = quantity - priorQuantity;
105
106 if(pricingMethod == 'Block' && deltaQuantity == 0) {
107 result = 0;
108 } else {
109 if(pricingMethod == 'Block') {
110 result = 1;
111 } else {
112 if(discountScheduleType == 'Slab' && (deltaQuantity == 0 || (quantity == 0 && renewal == true))) {
113 result = 0;
114 } else {
115 if(discountScheduleType == 'Slab') {
116 result = 1;
117 } else {
118 if(existing == true && subscriptionPricing == '' && deltaQuantity < 0) {
119 result = 0;
120 } else {
121 if(existing == true && subscriptionPricing == 'Percent Of Total' && listPrice != 0 && deltaQuantity >= 0) {
122 result = quantity;
123 } else {
124 if(existing == true) {
125 result = deltaQuantity;
126 } else {
127 result = quantity;
128 }
129 }
130 }
131 }
132 }
133 }
134 }
135
136 return result;
137 }
138
139}