Sample code for hooks and events
This reference provides sample code for using hooks and events in the extensibility framework, including async operations and various quote-related functionalities.
Use async / await for long-running async JS tasks.
Code | Hooks/events |
---|---|
Use this sample code to:
|
|
Use this sample code to auto-populate billing language picklist values when the Sold To Contact field is modified. |
updateQuote event |
Use this sample code to change the quote name before saving execution. |
|
Use this sample code to open and close the sidebar component and modify the sidebar width. |
|
Use this sample code to redirect the Quote Studio to the Custom Visualforce page. |
|
Use this sample code to execute rules. |
beforeRulesExecution hook |
Use this sample code to apply text color to fields and update the quote name using Quote update based on the Initial Term value change. |
|
Use this sample code to choose the billing country based on the region selected. |
|
Use this sample code to update the Quote name, display a toast message, and stop execution based on the Quote Initial Term. |
|
Use this sample code to block users from performing future-dated remove on products from the first interval. Additionally, it prevents the deletion of newly added products in the second interval of a ramp amendment quote with an error message. |
|
Sample code 1
Following is a sample code that uses the following hooks and events:
- beforeproductAdd hook
- afterProductAdd hook
- beforeProductUpdate hook
- afterProductUpdate hook
- beforeRulesExecution hook
- afterRulesExecution hook
- objectfieldconfig event
- toastMessageDisplay event
import {
LightningElement,
api
} from "lwc";
export default class ComponentHeadless extends LightningElement {
prefix = "zqu__";
applyConfigsForQuotes = true;
@api quoteState;
@api metricState;
@api pageState;
@api masterQuoteState;
@api parentQuoteState;
@api
beforeProductAdd(ratePlanMap, effectiveDate) {
if (ratePlanMap.hasOwnProperty("a0aRL0000084T2aYAK")) {
return { // If the Product Rate Plan to be added is a0aRL0000084T2aYAK. Then stop product add
proceed: false
};
}
const ratePlanToAdd = "a0aRL000008Q3AaYAK"; //Product Rate Plan Id to add
const quantity = 2; //Quantity of the above product rate plan to be added
ratePlanMap = {
...ratePlanMap,
[ratePlanToAdd]: quantity
};
let newEffectiveDate;
if (
this.quoteState.quote.zqu__Billing_Account_Name__c === "Test Account" &&
effectiveDate === "2024-10-10"
) { // Change the effective date based on conditions
newEffectiveDate = "2024-10-20"; //Optional
}
this.dispatchEvent(
new CustomEvent("toastmessagedisplay", {
detail: {
message: "From beforeProductAdd",
theme: "success",
},
})
);
if (!newEffectiveDate) { // Effective Date prop is optional, if not provided, the existing effective date will be considered
return {
proceed: true,
newRatePlanMap: ratePlanMap
};
}
return {
proceed: true,
newRatePlanMap: ratePlanMap,
effectiveDate: newEffectiveDate,
};
}
@api
afterProductAdd(newProductTimeline) {
this.processProductTimelines(newProductTimeline, false);
}
@api
beforeProductUpdate(
updatedCharges,
updatedAmendment,
updatedRatePlan,
isRevert
) {
if (updatedCharges && !(updatedAmendment && updatedRatePlan)) {
//Quote Rate Plan Charge update
if (updatedCharges[0].Name === "Economy") {
updatedCharges[0].zqu__Quantity__c = 5; // Update the quantity field of the charge based on condition
return {
proceed: true,
updatedCharges
};
} else if (updatedCharges[0].Name === "Standard") {
return { // Stop the Charge Update
proceed: false
};
}
return { // Proceed with the Charge Update If no changes are required
proceed: true,
updatedCharges
};
} else if (updatedAmendment && !(updatedCharges && updatedRatePlan)) {
// Quote Amendment update
// Quote Amendment record is present in updatedAmendment.amendment only for Amendment update
if (
updatedAmendment.amendment.zqu__ContractEffectiveDate__c ===
"2024-10-10"
) {
// update the Quote Amendment fields based on conditions
updatedAmendment.amendment.zqu__ContractEffectiveDate__c = "2024-10-20";
updatedAmendment.amendment.zqu__CustomerAcceptanceDate__c =
"2024-10-20";
updatedAmendment.amendment.zqu__ServiceActivationDate__c = "2024-10-20";
} else if (updatedAmendment.specificUpdateDate === "2024-10-12") {
// specificUpdateDate will be present in the updatedAmendment object only if there is an update on that property in the order Action Modal
updatedAmendment.specificUpdateDate === "2024-11-20"; // Update the specificUpdateDate based on conditions
} else if (
updatedAmendment.amendment.zqu__ContractEffectiveDate__c ===
"2024-10-10"
) {
return { // Stop the Quote Amendment update
proceed: false
};
}
return { // Proceed with the Amendment field Update If no changes are required
proceed: true,
updatedAmendment
};
} else if (updatedRatePlan && !(updatedCharges && updatedAmendment)) {
//Quote Rate Plan custom fields update
if (updatedRatePlan.Name === "Recurring Fee") {
updatedRatePlan.zqu__Custom_Field = 20; // Update Quote Rate Plan Custom Fields based on conditions
return {
proceed: true,
updatedRatePlan
};
} else if (updatedCharges[0].Name === "Flat Fee") {
return { // Stop Quote Rate Plan Custom Field Update
proceed: false
};
}
return {
proceed: true,
updatedRatePlan
};
} else if (
updatedCharges &&
updatedAmendment &&
updatedRatePlan &&
!isRevert
) {
//Future Dated Update
if (updatedRatePlan.Name === "Standard Plan") { // Update Quote Rate Plan, Quote Amendment and Charge fields based on conditions if it is a Future Dated Update
updatedRatePlan.zqu__Custom_Field = 11;
updatedAmendment.zqu__ContractEffectiveDate__c = "2024-10-11";
updatedCharges[0].zqu_Quantity__c = 10;
}
return {
proceed: true,
updatedRatePlan,
updatedCharges,
updatedAmendment,
};
} else if (
updatedCharges &&
updatedAmendment &&
updatedRatePlan &&
isRevert
) {
// Future Dated Update revert or Future Dated Remove revert
return {
proceed: true
};
}
}
@api
afterProductUpdate(updatedCharges, updatedRatePlan) {
let stopLoop = false;
let configs = [];
const timelines = this.quoteState.subscription.productTimelines;
for (const [, timeline] of Object.entries(timelines)) {
if (stopLoop) break;
for (const [index, version] of timeline.versions.entries()) {
if (stopLoop) break;
const nextEffectiveDate =
timeline.versions[index + 1]?.amendment.record[
this.prefix + "ContractEffectiveDate__c"
];
const currentEffectiveDate =
version.amendment.record[this.prefix + "ContractEffectiveDate__c"];
if (
!timeline.versions[index + 1]?.voidAction &&
currentEffectiveDate === nextEffectiveDate
) // Skip if the effective date is same as the next version (Scenario: While amending the original charge on the same date)
continue;
for (const [chargeIndex, charge] of version.charges.entries()) {
if (
updatedRatePlan[0].Id === version.Id &&
(!updatedCharges ||
updatedCharges.find(
(updatedCharge) =>
updatedCharge[this.prefix + "ProductRatePlanCharge__c"] ===
charge.record[this.prefix + "ProductRatePlanCharge__c"]
))
) {
const quantity = charge.record[this.prefix + "Quantity__c"];
configs.push(
...this.generateConfigsForCharges( //Generate configs for the charge fields based on the change in quantity field
chargeIndex,
timeline.timelineId,
version.amendment.record[
this.prefix + "ContractEffectiveDate__c"
],
quantity
)
);
if (quantity >= = 10) {
configs.push({ // Apply configs for custom Quote Rate Plan fields in the Quote Rate Plan Modal
field: this.prefix + "Custom_Field__c",
effectiveDate: currentEffectiveDate,
timelineId: timeline.timelineId,
object: this.prefix + "QuoteRatePlan__c",
backgroundColor: "orange",
readOnly: false,
});
configs.push({ // Apply configs for Quote Amendment fields in the Order Action Detail Modal
field: this.prefix + "ContractEffectiveDate__c",
effectiveDate: currentEffectiveDate,
timelineId: timeline.timelineId,
object: this.prefix + "QuoteAmendment__c",
backgroundColor: "blue",
helpText: "Quanity cannot be greater than 9",
disabled: true,
});
configs.push({ // Apply configs for Quote Amendment fields in the Future Dated Update Modal
field: this.prefix + "ContractEffectiveDate__c",
timelineId: timeline.timelineId,
object: this.prefix + "QuoteAmendment__c",
hidden: true
});
} else {
configs.push({
field: this.prefix + "Custom_Field__c",
effectiveDate: currentEffectiveDate,
timelineId: timeline.timelineId,
object: this.prefix + "QuoteRatePlan__c",
backgroundColor: "default",
readOnly: true,
});
configs.push({
field: this.prefix + "ContractEffectiveDate__c",
effectiveDate: currentEffectiveDate,
timelineId: timeline.timelineId,
object: this.prefix + "QuoteAmendment__c",
backgroundColor: "default",
helpText: null,
disabled: false,
});
configs.push({
field: this.prefix + "ContractEffectiveDate__c",
timelineId: timeline.timelineId,
object: this.prefix + "QuoteAmendment__c",
hidden: false
});;
stopLoop = true; //Stop the loop after the execution is completed for the particular charge update
}
}
}
}
if (configs.length > 0) {
this.dispatchEvent(
new CustomEvent("objectfieldconfig", {
detail: {
configs
}
})
);
}
}
}
@api
async beforeRulesExecution(context) {
console.log(`Running beforeRulesExecution in context : ${context.triggerEvent}`);
const rulesIdsToExecute = this.pageState.rules?.active.filter(rule => rule.name === 'Test Rule')?.map(fiteredRule => fiteredRule.Id); //Filter the rule Ids based on criteria
return {
rulesToExecute: rulesIdsToExecute,
runRules: true
}
}
@api
afterRulesExecution(rulesResponse) {
if (
rulesResponse.newlyAddedTimelines &&
Object.keys(rulesResponse.newlyAddedTimelines).length > 0
) // If an new product is added through rules engine
this.processProductTimelines(rulesResponse.newlyAddedTimelines);
const updatedProductTimelines =
rulesResponse.updatedQuoteState.subscription.productTimelines;
if (updatedProductTimelines) // If there are changes in the product timelines
this.processProductTimelines(updatedProductTimelines, true);
}
/* Generates config for charges based on quantity change and returns back the JS object of config */
generateConfigsForCharges(chargeIndex, timelineId, effectiveDate, quantity) {
const baseConfig = {
chargeIndex,
timelineId,
effectiveDate,
object: this.prefix + "QuoteRatePlanCharge__c",
};
const customConfig = {
...baseConfig,
field: "Custom_Field__c"
};
const discountConfig = {
...baseConfig,
field: this.prefix + "Discount__c",
readOnly: false,
disabled: false,
hidden: false,
};
if (quantity === 1) {
customConfig.backgroundColor = "red";
customConfig.helpText = "Quantity is 1";
} else if (quantity >= 2 && quantity <= 5) {
customConfig.backgroundColor = "#ff6347";
customConfig.helpText = "Quantity is between 2 and 5";
discountConfig.hidden = true;
} else if (quantity >= 6 && quantity <= 10) {
customConfig.backgroundColor = "rgba(255, 0, 191, 0.5)";
customConfig.helpText = "Quantity is between 6 and 10";
discountConfig.disabled = true;
} else if (quantity >= 11 && quantity <= 15) {
customConfig.backgroundColor = "hsl(105, 100%, 50%)";
customConfig.helpText = "Quantity is between 11 and 15";
discountConfig.readOnly = true;
} else {
customConfig.backgroundColor = "default";
customConfig.helpText = null;
}
return [customConfig, discountConfig];
}
/* Process the product timeline and fire the objectfieldconfig event */
processProductTimelines(productTimelines, rulesExecuted) {
const productTimelineEntries = Object.entries(productTimelines);
if (!productTimelineEntries.length) return;
let configs = [];
for (const [, timeline] of productTimelineEntries) {
for (const [index, version] of timeline.versions.entries()) {
// Check if version is changed in the rules engine and voidAction (deleted rate plan) is not true
if (
!version.voidAction &&
(!rulesExecuted || version.isChangedInRulesEngine)
) {
const currentEffectiveDate =
version.amendment.record[this.prefix + "ContractEffectiveDate__c"];
const nextEffectiveDate =
timeline.versions[index + 1]?.amendment.record[
this.prefix + "ContractEffectiveDate__c"
];
if (currentEffectiveDate === nextEffectiveDate) continue; // Skip if the effective date is same as the next version (Scenario: While amending the original charge on the same date)
for (const [chargeIndex, charge] of version.charges.entries()) {
if (
!rulesExecuted ||
charge.fieldsChangedInRulesEngine?.length > 0
) {
const quantity = charge.record[this.prefix + "Quantity__c"];
configs.push(
...this.generateConfigs(
chargeIndex,
timeline.timelineId,
currentEffectiveDate,
quantity
)
);
}
}
}
}
}
if (this.applyConfigsForQuotes) {
if (this.quoteState?.quote) { // Apply configs for the quote
configs.push({
field: this.prefix + 'ValidUntil__c',
object: this.prefix + 'Quote__c',
quoteId: this.quoteState.quote.Id,
backgroundColor: 'blue',
helpText: 'Fill the Valid Till Date for the quote',
});
configs.push({
field: this.prefix + 'InitialTerm__c',
object: this.prefix + 'Quote__c',
quoteId: this.quoteState.quote.Id,
readOnly: true,
helpText: 'Default Initial term cannot be changed'
});
configs.push({
field: 'Name',
object: this.prefix + 'Quote__c',
quoteId: this.quoteState.quote.Id,
backgroundColor: 'red',
helpText: 'Fill the Quote Name',
});
configs.push({
field: this.prefix + 'Opportunity__c',
object: this.prefix + 'Quote__c',
quoteId: this.quoteState.quote.Id,
hidden: true
});
}
if (this.parentQuoteState?.quote) { // Applying configs for parent quote in the MSQ context
configs.push({
field: 'Name',
object: this.prefix + 'Quote__c',
quoteId: this.parentQuoteState.quote.Id,
backgroundColor: 'pink'
});
configs.push({
field: 'Name',
object: this.prefix + 'Quote__c',
quoteId: this.parentQuoteState.quote.Id,
helpText: 'Fill the Parent Quote Name',
hidden: true
});
configs.push({
field: this.prefix + 'Opportunity__c',
object: this.prefix + 'Quote__c',
quoteId: this.parentQuoteState.quote.Id,
backgroundColor: 'violet',
helpText: 'Fill the opportunity Name',
hidden: false
});
}
this.applyConfigsForQuotes = false;
}
if (configs.length > 0) {
this.dispatchEvent(
new CustomEvent("objectfieldconfig", {
detail: {
configs
}
})
);
this.executed = true;
}
}
}
Sample code 2
Following is the sample code that uses the updateQuote event to auto-populate billing language picklist values when the Sold To Contact field is modified.
import { LightningElement, api } from 'lwc';
const PREFIX = 'zqu__';
export default class HeadLessComp extends LightningElement {
@api pageState;
_previousQuoteState;
_currentQuoteState;
@api metricState;
connectedCallback() {
console.log('Component Loaded...');
}
@api
get quoteState() {
return this._currentQuoteState;
}
set quoteState(newState) {
this._currentQuoteState = newState;
// Destructure quotes for easier access
const newQuote = newState?.quote;
const oldQuote = this._previousQuoteState?.quote;
if (oldQuote && this.hasFieldChanged(oldQuote, newQuote, 'SoldToContact__c')) {
const updatedQuote = { ...newQuote, [`${PREFIX}Custom_Picklist__c`]: 'Value2' };
// Store the current state and dispatch the event
this._previousQuoteState = { ...newState };
this.dispatchQuoteUpdate(updatedQuote);
} else {
// Simply store the current state if no changes detected
this._previousQuoteState = { ...newState };
}
}
hasFieldChanged(oldQuote, newQuote, fieldName) {
return newQuote?.[`${PREFIX}${fieldName}`] && oldQuote?.[`${PREFIX}${fieldName}`] !== newQuote?.[`${PREFIX}${fieldName}`];
}
dispatchQuoteUpdate(updatedQuote) {
this.dispatchEvent(new CustomEvent('updatequote', {
detail: { quote: updatedQuote }
}));
}
}
Sample code 3
The following is the sample code to change the quote name before saving execution. This example uses a hook before saving and an event before the preview call. The following hooks and events are used in the sample code:
- beforeSave hook
- beforeSubmit hook
- beforePreviewCall hook
- toastMessageDisplay event
- updateQuote event
import { LightningElement, api } from 'lwc';
export default class HeadLessComp extends LightningElement {
@api quoteState;
@api metricState;
@api pageState;
sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
connectedCallback() {
console.log('Custom Component is Loaded,..');
this.dispatchEvent(new CustomEvent('toastmessagedisplay', {
detail: {
message: 'Custom Component is Loaded...',
theme: 'success'
}
}));
}
@api
async beforeSave() {
//Use Async / Await to dely execution - If any long running task like external API Calls to be completed and if it's response has a dependency on the logics in this method
await this.sleep(5000);
// will be executed after 5000 ms
this.dispatchEvent(new CustomEvent('toastmessagedisplay', {
detail: {
message: 'Ssve logic from Custom Component',
theme: 'error'
}
}));
this.quoteState = JSON.parse(JSON.stringify(this.quoteState));
this.quoteState.quote.Name = 'Quote Name from Custom Comp';
this.dispatchEvent(new CustomEvent('updatequote', {
detail: { quote: this.quoteState.quote }
}));
//continue Quote Studio SAVE Logic
return true;
}
@api
beforePreviewCall() {
this.dispatchEvent(new CustomEvent('toastmessagedisplay', {
detail: {
message: 'Preview Call logic from Custom Component',
theme: 'success'
}
}));
//continue Quote Studio Preview on-demand Logic
return true;
}
@api
beforeSubmit() {
this.dispatchEvent(new CustomEvent('toastmessagedisplay', {
detail: {
message: 'Submit logic from Custom Component',
theme: 'error'
}
}));
//STOP Quote Studio SUBMIT Logic
return false;
}
}
Sample code 4
The following is a sample code for opensidebarcomponent, closesidebar and changesidebarwidth.
When the Save button is clicked, the sidebar component opens to allow input for the Initial Term value. After clicking the Save button in the custom component, the sidebar closes, and the quote is saved.
The following hooks and events are used in the sample code:
- beforeSave hook
- updateQuote event
- opensidebarcomponent event
- closesidebar event
- changesidebarwidth event
//commonUtils to hold the static value on whether beforeSave hook should execute or not
let _executeSaveLogic = true;
export const getExecuteSaveLogic = () => {
return _executeSaveLogic;
};
export const setExecuteSaveLogic = (value) => {
_executeSaveLogic = value;
};
// Custom sidebar component which takes the initial term value as input, updates the quote with new initial term and save the quote
import { LightningElement, api } from 'lwc';
import { setExecuteSaveLogic } from 'c/commonUtils';
export default class CustomSidebarComponent extends LightningElement {
@api quoteState;
@api metricState;
@api pageState;
@api masterQuoteState;
@api parentQuoteState;
initialTerm; // To store the Initial Term values
handleClick() {
this.dispatchEvent(new CustomEvent('closesidebar')); // Event to close the sidebar component
let quoteClone = Object.assign({}, this.quoteState.quote);
quoteClone.zqu__InitialTerm__c = this.initialTerm;
const updateQuoteEvent = new CustomEvent('updatequote', { // Update the quote with new initial term value
detail: {
quote: quoteClone
}
});
this.dispatchEvent(updateQuoteEvent);
setTimeout(() => { // Save the quote after update quote event is executed
setExecuteSaveLogic(false); // Do not run the beforeSave hook
this.dispatchEvent(new CustomEvent('savequote'));
}, 0);
}
handleChange(event) {
this.initialTerm = event.target.value; // To store the Initial Term value on change
}
}
import { LightningElement, api } from 'lwc';
import { getExecuteSaveLogic } from 'c/commonUtils';
export default class ComponentHeadless extends LightningElement {
@api quoteState;
@api metricState;
@api pageState;
@api masterQuoteState;
@api parentQuoteState;
connectedCallback() {
this.dispatchEvent(
new CustomEvent('changesidebarwidth', { detail: { width: '80vw' } }) // Event to change the sidebar width
);
}
@api
beforeSave() {
if (getExecuteSaveLogic()) { // Check whether to execute the logic in beforeSave hook
this.dispatchEvent(
new CustomEvent('opensidebarcomponent', { // Open Sidebar component
detail: {
componentName: 'componentHead'
}
})
);
return false;
}
return true;
}
}
Sample code 5
The following is the sample code to redirect the Quote Studio to the Custom Visualforce page. The following hooks and events are used in the sample code:
- beforeSubmitNavigation hook
- toastMessageDisplay event
@api
beforeSubmitNavigation() {
this.dispatchEvent(
new CustomEvent('toastmessagedisplay', {
detail: {
message: 'from beforeSubmitNavigation',
theme: 'success'
}
})
);
const pageUrl = 'https://innovation-page-7892-dev-ed.scratch.lightning.force.com/apex/CustomVFPage?quoteId=' + this.quoteState.quote.Id; //Redirection URL
return { proceed: true, redirectionURL: pageUrl };
}
Sample code 6
The following is the sample code that uses the beforeRulesExecution hook with forceExecuteRules and includeRemovedRatePlan parameters.
@api
async beforeRulesExecution(context) {
console.log(`Running beforeRulesExecution in context :
${context.triggerEvent}`);
const rulesToExecute = this.pageState.rules?.active.filter(rule =>
rule.zqu__TriggerEvent__c === 'SaveSubmit' || rule.zqu__TriggerEvent__c ===
'InitialLoad')?.map(fiteredRule => fiteredRule.Id);
return {
rulesToExecute : rulesToExecute,
runRules : false,
forceExecuteRules: true
includeRemovedRatePlan: true
}
}
Sample code 7
The following is the sample code to apply text color to fields and update the quote name based on the Initial Term value change.
The following hooks and events are used in the sample code:
- afterQuoteUpdate hook
- updateQuote event
- objectFieldConfig event
@api
afterQuoteUpdate(oldQuote, newQuote) {
console.log('afterQuoteUpdate - oldQuote ', oldQuote.Name);
console.log('afterQuoteUpdate - newQuote ', newQuote.Name);
let configs = [];
if (newQuote[this.prefix + 'InitialTerm__c'] == 20) {
configs.push({
field: this.prefix + 'RenewalTerm__c',
quoteId: this.quoteState.quote.Id,
object: this.prefix + 'Quote__c',
helpText: 'Initial term is 20',
textColor: 'magenta',
readOnly: true
});
let quoteObj = Object.assign({}, this.quoteState.quote);
quoteObj.Name = 'Updated Quote Name';
const updateQuoteEvent2 = new CustomEvent('updatequote', {
detail: {
quote: quoteObj
}
});
setTimeout(() => {
this.dispatchEvent(updateQuoteEvent2);
}, 0); // Update the Quote
} else if (newQuote[this.prefix + 'InitialTerm__c'] == 21) {
configs.push({
field: this.prefix + 'RenewalTerm__c',
object: this.prefix + 'Quote__c',
quoteId: this.quoteState.quote.Id,
helpText: 'Initial term is 21',
textColor: 'brown',
readOnly: false,
disabled: true
});
}
if (configs.length > 0) this.dispatchEvent(new CustomEvent('objectfieldconfig', {
detail: { configs } }));
}
Sample code 8
Following is the sample code that uses afterQuoteUpdate hook and objectfieldconfig event.
@api
afterQuoteUpdate(oldQuote, newQuote) {
let configs = [];
if(newQuote?.zqu__Billing_Region__c !== oldQuote.zqu__Billing_Region__c)
{
if(newQuote?.zqu__Billing_Region__c === "APAC") {
configs.push({
field: 'zqu__Billing_Country__c',
object: 'zqu__Quote__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"India",
"value":"India"
},
{
"isDefault":false,
"label":"Srilanka",
"value":"Srilanka"
}
]
});
configs.push({
field: 'zqu__Charge_Category_Code__c',
object: 'zqu__QuoteRatePlanCharge__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"APAC",
"value":"APAC"
}
]
});
} else if (newQuote?.zqu__Billing_Region__c === "EMEA") {
configs.push({
field: 'zqu__Billing_Country__c',
object: 'zqu__Quote__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"France",
"value":"France"
},
{
"isDefault":false,
"label":"Austria",
"value":"Austria"
}
]
});
configs.push({
field: 'zqu__Charge_Category_Code__c',
object: 'zqu__QuoteRatePlanCharge__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"EMEA",
"value":"EMEA"
}
]
});
} else if (newQuote?.zqu__Billing_Region__c === "NA") {
configs.push({
field: 'zqu__Billing_Country__c',
object: 'zqu__Quote__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"Canada",
"value":"Canada"
},
{
"isDefault":false,
"label":"US",
"value":"US"
}
]
});
configs.push({
field: 'zqu__Charge_Category_Code__c',
object: 'zqu__QuoteRatePlanCharge__c',
quoteId: newQuote.Id,
options : [
{
"isDefault":false,
"label":"NA",
"value":"NA"
}
]
});
}
}
if (configs.length > 0) {
this.dispatchEvent(
new CustomEvent("objectfieldconfig", {
detail: {
configs
}
})
);
}
}
Sample code 9
The following is the sample code to update the Quote name, display a toast message, and stop execution based on the Quote Initial Term. The following hooks and events are used in the sample code:
- beforeMSQChildSave hook
- updateQuote event
- toastMessageDisplay event
@api
beforeMSQChildSave() {
let quoteClone = Object.assign({}, this.quoteState.quote);
if (quoteClone.zqu__InitialTerm__c == 12) {
quoteClone.Name = 'Updated from beforeMSQChildSave';
this.dispatchEvent(
new CustomEvent('updatequote', {
detail: {
quote: quoteClone
}
})
);
} else {
this.dispatchEvent(
new CustomEvent('toastmessagedisplay', {
detail: {
message: 'Set the Initial Term to 12 months',
theme: 'error'
}
})
);
return false;
}
return true; //Optional
}
Sample code 10
Following is the sample code to block users from performing future-dated remove on products from the first interval. Additionally, it prevents the deletion of newly added products in the second interval of a ramp amendment quote with an error message. The following hooks and events are used in the sample code:
- beforeProductRemove hook
- toastMessageDisplay event
@api
beforeProductRemove(removedQplan, deletedTimeline, timelineId) {
if (
this.quoteState.quote['zqu__Ramp__c'] &&
this.quoteState.quote['zqu__SubscriptionType__c'] === 'Amend Subscription' &&
((removedQplan && this.pageState.currentInterval.index === 0) || (deletedTimeline && this.pageState.currentInterval.index === 1))
) {
const action = removedQplan ? 'remove' : 'delete';
this.dispatchEvent(
new CustomEvent('toastmessagedisplay', {
detail: {
message: `You cannot ${action} products from interval ${this.pageState.currentInterval.index + 1}`,
theme: 'error'
}
})
);
return false;
}
return true;
}