Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Solution for this use case is easy: api.global.

In header Header logic:

Code Block
languagegroovy
api.retainGlobal = true   
api.global.variableTest = "value from header2"

Quote Line Logicline logic:

Code Block
def value = api.global.variableTest

api.logInfo("LineItemLogic value:" + value);

...

Instead of api.retainGlobal = true you can set set flag “apithe option api.retainGlobal defaults to TRUE” in configuration of partition (Admin->Configuration->General Settings) TRUE in Administration > Configuration > General Settings to true.

...

Use

...

Case 4: Quote Line Item Logic → Quote Header Logic

This can be useful e.g. if you want to, for example, calculate a summary on the header level or display a summary chart on Custom Quote Headerin the custom Quote header.

This is very easy, as it is involves just reading the quote structure. This needs to be done in the Quote Post Phase post-phase (= after line item calculation).

In the header logic, you can read the values from line items this way:

Code Block
languagegroovy
if(quoteProcessor.isPostPhase()){
  def lineItems = quoteProcessor.getQuoteView().lineItems  
  lineItems.each{ lineItem ->
    
    def sku= lineItem.sku
    def outputItems = lineItem.outputs
    def value = outputItems.find{ it.resultName == "LineItemValue"}?.result
    api.trace("result", "sku: " +sku + " value: "+ value);    
  }  
}

Use

...

Case 5: Quote Header Logic → Publishing (Preprocessing) Logic

If you are using use publishing templates for quotes, you have to pass data to the preprocessing (publishing) logic. Simply call api.currentItem from the preprocessing logic to get a full quote view.

Code Block
def quote = api.currentItem().

Note: data Data will be available in the preprocessing logic only after the quote was saved, not before.

Use

...

Case 6: Quote Header Configurator → Line Item Logic

From the configurator logic you don’t do not have a direct access to the quote object. This means you have to pass values from the header logic to the line item logic.

To accomplish do this behavior , you need to combine the following use cases: Use case 1: Quote Header Logic Configurator → Quote Header Logic. and then Use case 3: Quote Header Logic -> Line Item logic.

Without priceEntityAfterSave set up to true the recalculate Recalculate button has to be pressed clicked after saving values in Configuratorthe configurator.

Use

...

Case 7: Line Item Logic → Quote Header Configurator Logic

To read values from a line item logic, we can use a logic from Use case 4: Quote Line Item Logic → Quote Header Logic.

Then at PostPhase the post-phase in the header logic we pass those values through the “value” property inside in the configurator. Refer to Use case 2: Quote Header Logic → Quote Header Logic Configurator.

Thanks to postPhase the post-phase we can pass those these values within one recalculation transaction.

This how would look like final Final code:

Code Block
if (quoteProcessor.isPostPhase()) {
    def quote = quoteProcessor.getQuoteView()

    def lineItems = quote?.lineItems
    def sum = 0
    lineItems.each { lineItem ->
        def outputItems = lineItem.outputs
        def value = outputItems.find { it.resultName == "LineItemValue" }?.result
        sum = sum + value
    }

    def passedSumValue = sum
    def mergedValue = quote.inputs?.find { it.name == "Configurator" }?.value ?: [:]
    mergedValue.put("PassedValue", passedSumValue)

    quoteProcessor.addOrUpdateInput(
            "ROOT",
            [
                    "name" : "Configurator",
                    "label": "Configurator",
                    "url"  : "ConfiguratorLogic",
                    "type" : "CONFIGURATOR",
                    "value": mergedValue
            ]
    )
}

Now when you click on the configurator button, you will have values from line items available in that the configurator.

Use

...

Case 8: Quote Header Logic Configurator → Line Item Logic Configurator

This may can be useful if you want to, for example to , set generic parameters in the quote header configurator and then have a pre-filled configurator on each line item, to edit the values for each line item separately.

It is possible to pass data from Quote Header Logic Configurator to Line Logicthe quote header logic configurator to the line item logic, but it is not possible to pass data from Quote Header Logic Configurator to Configurator defined in Line Item Logic.Why? Let’s the quote header logic configurator to the configurator defined in the line item logic.

To explain this, let’s see the example of how you pass the passing values from Line Item Logic to Line Item Configuratorthe line item logic to the line item configurator.

Code Block
api.configurator("Configurator A","ConfiguratorFormula")
def confA = api.getParameter("Configurator A")
if(confA != null && confA.getValue() == null) {
     confA.setValue(["ConfiguratorType":"A"])
}

This works fine as you use static (hard-coded) values. Data are not loaded dynamically. If you want to load data dynamically from the quote header configurator, this is the code is like this in the line item logic (non-working demo!).:

Code Block
languagegroovy
//NOTE: this is NON WORKING code - it is here just forto exlanationexplain whatwhy this approach itdoes not workingwork

def conf = api.configurator("test", "ConfiguratorLogic"); //line item configurator
def headerValues = api.input("valueFromHeaderConfigurator") //loadingload values from hidden input created in header logic
valueToSet = headerValues?.QuoteFeatures?.Name?.getAt(0) //get one of the values 

def confA = api.getParameter("test") //gettingget reference for line item configurator
def valueToSet = ["QuoteFeatures":["Name":valueToSet, "selected":"false"]] //data structure for input matrix to set

confA?.setValue(valueToSet) //settingset value to configurator

But this is does not not working, work because:

  1. Line Item Configurator item configurator “test” is created during syntax check.

  2. During syntax check, api.input returns only mock data, not real data.

  3. During syntax check (and only during syntax check), api.getParameter(“test”) return contex "test") returns a context parameter of the “test” "test" configurator. During recalculation (when syntax check is not running), api.getParameter(“test”"test") returns null.

  4. ConfA?.setValue in syntax check:

    1. has a context parameter of the configurator;

    2. does not have a value loaded from api.input.

  5. ConfA?.setvalue setValue when quote is recalculated:

    1. does not have a context parameter of the configurator;

    2. has a value loaded from api.input, but it cannot be set , as confA is null.

As a result:

  • you are able to set You can set a static value via confA.setValue() as a value are which is known at syntax check.

  • you are not able to You cannot set dynamically loaded data from the header configurator because in the syntax check api.input does not return the expected value and during recalculation, api.getParameters(“test”"test") does not return the context parameter of the configurator.

In this case, quote recalculation will not help , as during recalculation, there is no syntax check. So let’s talk about see a workaround.

Workaround

...

: Create Line Item Configurator on Quote Header

Create a configurator for line items from the header logic and pass it to the line items via the addOrUpdate function.

Example:

Configurator on the header level, defined in the header logic. From this configurator, we load data to our line item configurator.

...

Code Block
languagegroovy
if(quoteProcessor.isPostPhase()) {  
	for (lineItemMap in quoteProcessor.getQuoteView().lineItems) {
		if (lineItemMap.folder) continue  //skip folders
  
      	def quote = quoteProcessor.getQuoteView()
      
      	def configuratorValues = quote.inputs?.find { it.name == "Configurator" }?.value ?: [:]	
      	def valuesToSet = configuratorValues;
  
		quoteProcessor.addOrUpdateInput(lineItemMap.lineId,
                        ["name"    : "LinteItemConfigurator",
                         "label"   : "LinteItemConfigurator",
                         "type"    : InputType.CONFIGURATOR,
                         "url"     : "ConfiguratorLogic",
                         "readOnly": false,
                         "value"   : valuesToSet]
                )
		}
}

In this case, the line item configurator will always have the same values as the quote header configurator. Any change in the line item configurator will be overwritten on quote recalculation. If you want to keep changes done on the item level, you have to merge it them with the header value , before you set them via addOrUpdateInput.

Use

...

Case 9: Quote Line Item Configurator → Quote Header Configurator

The principles are same as in Use case Case 7: Line Item Logic -> Quote Header Configurator Logic.

Only The only change here is when you are iterating iterate over lineItems line items you need to look inside the configurator value field and collect the needed values.

This needs to be done in the quote header logic.

Code Block
    def quote = quoteProcessor.getQuoteView()
    def lineItems = quote?.lineItems
    
    lineItems.each { lineItem ->
        def inputItems = lineItem.inputs
        def value = inputItems.find { it.name == "ConfiguratorName" }?.value
        sum = sum + value?.configuratorFieldValue? : 0
    }

Use

...

Case 10: Line Item Logic → Line Item Logic Configurator

It is possible to add default values to the line item configurator from the line item logic using the following code:

Code Block
api.configurator("Configurator A","ConfiguratorFormula")
def confA = api.getParameter("Configurator A")
if(confA != null && confA.getValue() == null) {
     confA.setValue(["ConfiguratorType":"A"])
}

So when you need pass values only onceas an initialization step, it can be done using the code above. If you would like to pass different values each time on recalculate, you must change the approach.

Problem The problem here is the function api.getParameter("Configurator A"). It returns Configurator the configurator object only in case that when the configurator was not open opened before and has no value in the value property. Same is with f.e. stringuserentry, while The same applies to e.g. stringUserEntry: while it is empty you can get the userEntry object by calling api.getParameter. After you fill it in, no object is returned to you.

...

To dynamically fill in configurators in the line item calculation logic, you have to update it using the header logic. Basically follow the instructions in Use case Case 4: Quote Line Item Logic → Quote Header Logic and update configurator values while iterating.

Possible

...

Design Troubles

“Add new line item”

...

Architecture Awareness

Some of the use cases above are implemented with the header logic updating line items.

Example:

Header logic configurator has three string inputs. I You need to see those these input values at the line item level to work with them. I You can do this in the quote header prephase pre-phase logic. I You will iterate over lineItems and passing them some HIDDEN fields.

So far so good.

What happen happens when I you add a new item? Only the item logic syntax check and item logic is executed. When the quote header prephase pre-phase did the iteration over all items, this new line was not there yet.

Conclusion:

It means that I you will get those these passed values on a new line item only after clicking on the Recalculate button. This could be UX issue.