Business use case:
...
When we have all the information about our promotion safely stored in Price Records, we can use it in quotes.
Quote Configurator
To achieve the functionality described at the beggining of this article, we need to transport information from the quote header logic (that adds the bonus item) to the line logic. We will use HIDDEN type inputs to do that (see also How to Create Quote Line Items from Header Logic).
First, we will create a quote header formula, whose logic will be as follows:
Paste code macro | ||
---|---|---|
| ||
api.logInfo("Quote Header Logic", "************ START ************") api.logInfo("IsPrePhase", quoteProcessor.isPrePhase()) if (quoteProcessor.isPrePhase()) { for (lineItemMap in quoteProcessor.getQuoteView().lineItems) { if (lineItemMap.folder) continue def yId = shallPromoXforYBeApplied(lineItemMap) if (yId!=null) { def isPromoAlreadyApplied = isPromoXforYAlreadyApplied(lineItemMap) if (!isPromoAlreadyApplied) { def quoteQuantity = getInputValueForLine(lineItemMap.lineId, "Quote_Quantity") list = [] list.add([name: "XforY", type: InputType.HIDDEN, "value": lineItemMap.lineId]) list.add([name: "Requested_Price", label: "Requested_Price", type: InputType.USERENTRY, "value": 0]) list.add(["name": "Quote_Quantity", "label": "Quote_Quantity", "type": InputType.USERENTRY, "readOnly" : true, "value": quoteQuantity ]) addedLineItem = quoteProcessor.addLineItem(lineItemMap.parentId, yId, list) setPromoXforYAlreadyApplied(lineItemMap) } } } for (lineItemMap in quoteProcessor.getQuoteView().lineItems) { if (lineItemMap.folder) continue isItY = getInputValueForLine(lineItemMap.lineId, "XforY") if (isItY != null) { if(!checkIfXExist(isItY)){ quoteProcessor.deleteItem(lineItemMap.lineId) } setRequestedPriceReadOnly(lineItemMap.lineId) yQuantity = getInputValueForLine(lineItemMap.lineId, "Quote_Quantity") xQuantity = getInputValueForLine(isItY, "Quote_Quantity") api.logInfo("yQuantity", yQuantity) api.logInfo("xQuantity", xQuantity) setYQuantity(lineItemMap.lineId, xQuantity) } } } /** * after changing the quantity of productX and choosing 'Recalculate Changes' or 'Recalculate' , the quantity of product Y should be also changed, * in PrePhase only "Quote_Quantity" input is being changed by setYQuantity, output "Quantity" remains without any changes, after * invoking setYOutputQuantity in postPhase it is finally changed * */ if (quoteProcessor.isPostPhase()) { api.logInfo("IsPrePhase", "PostPhase!") api.logInfo("IsPrePhase", quoteProcessor.getQuoteView().lineItems) def qq = api.getParameter("Quote_Quantity") api.logInfo("IsPrePhase qq", qq) for (lineItemMap in quoteProcessor.getQuoteView().lineItems) { if (lineItemMap.folder) continue isItY = getInputValueForLine(lineItemMap.lineId, "xforY") api.logInfo("isItY", isItY) if (isItY != null) { yInPutQuantity = getInputValueForLine(lineItemMap.lineId, "Quote_Quantity") yOutPutQuantity = getOutputValueForLine(lineItemMap.lineId, "Quantity") api.logInfo("yInPutQuantity", yInPutQuantity) api.logInfo("yOutPutQuantity", yOutPutQuantity) if (yInPutQuantity != yOutPutQuantity) { setYOutputQuantity(lineItemMap.lineId, yInPutQuantity) } } } } api.logInfo("Test Quote Header Logic", "************ END ************") // ************************* FUNCTiONS ****************************** def shallPromoXforYBeApplied(lineItem) { // x should be read from PriceRecords def targetDate = api.targetDate() def sku = lineItem?.sku def customerId = quoteProcessor.getHelper().getRoot().getInputByName("Customer")?.value if(customerId!=null){ def filtersPromotion = [ api.productToRelatedObjectsFilter("PR", sku), api.customerToRelatedObjectsFilter("PR", customerId), Filter.lessOrEqual("validAfter", targetDate), Filter.or(Filter.greaterOrEqual("expiryDate", targetDate), Filter.isNull("expiryDate")) ] priceRecordRows = api.find("PR", 0, 1, "attribute1", *filtersPromotion, Filter.like("attribute5", "XforY")) def yId = priceRecordRows[0]?.attribute6 return yId } return null } /** * returns given input from the quote header. We need to read it this way, because api.input() works only on the line items. * */ def getInputValue(inputName) { return quoteProcessor.getQuoteView()?.inputs?.find { it.name == inputName }?.value } def getInputValueForLine(lineId, inputName) { inputs = quoteProcessor.getQuoteView()?.lineItems?.find { it.lineId == lineId }?.inputs for (input in inputs) { if (inputName.equals(input.name)) return input.value } return null } def getOutputValueForLine(lineId, outputName) { outputs = quoteProcessor.getQuoteView()?.lineItems?.find { it.lineId == lineId }?.outputs for (output in outputs) { if (outputName.equals(output.resultName)) return output.result } return null } def setPromoXforYAlreadyApplied(lineItem) { def rootPromoAlreadyAppliedMap = api.isSyntaxCheck() ? [:] : (getInputValue("ROOT_IsPromoXforYAlreadyAppliedMap") ?: [:]) rootPromoAlreadyAppliedMap[lineItem.lineId] = "true" quoteProcessor.addOrUpdateInput(["name" : "ROOT_IsPromoXforYAlreadyAppliedMap", //"label":"ROOT_IsPromoXforYAlreadyAppliedMap", "type" : InputType.HIDDEN, "value": rootPromoAlreadyAppliedMap] ) api.logInfo("rootPromoAlreadyAppliedMap", rootPromoAlreadyAppliedMap) } /** * returns TRUE, if the special Promo Line (X for Y) was already added for this line */ def isPromoXforYAlreadyApplied(lineItem) { def rootPromoAlreadyAppliedMap = api.isSyntaxCheck() ? [:] : getInputValue("ROOT_IsPromoXforYAlreadyAppliedMap") promoAlreadyApplied = (rootPromoAlreadyAppliedMap?.get(lineItem.lineId) == "true") return promoAlreadyApplied } def setYQuantity(lineId, newQuantity) { quoteProcessor.addOrUpdateInput(lineId, ["name": "Quote_Quantity", "label": "Quote_Quantity", "value": newQuantity, "readOnly" : true]) quoteProcessor.addOrUpdateOutput(lineId, ["resultName": "Quantity", "label": "Quantity", "result": newQuantity]) } def setYOutputQuantity(lineId, newQuantity) { quoteProcessor.addOrUpdateOutput(lineId, ["resultName": "Quantity", "label": "Quantity", "result": newQuantity]) } def setRequestedPriceReadOnly(lineId){ quoteProcessor.addOrUpdateInput(lineId, ["name": "Requested_Price", "label": "Requested_Price", "value": 0, "readOnly" : true]) } def checkIfXExist(isItY){ quoteProcessor.getQuoteView().lineItems xExist = quoteProcessor.getQuoteView()?.lineItems?.find { it.lineId == isItY } if(xExist!= null) return true return false } |
...