Recommended Logic Structure for Line Item Calculation Logics

Based on experience, it turns out that there are different element types that follow a certain logical structure. This table shows how to organize these elements into corresponding blocks based on their logical order.

Element BlockElement NameSample CodeDisplayComment

Gathering data needed for parameters gathering

SalesOrgs
if (!api.global.salesOrgs) {
api.global.salesOrgs = api.findLookupTableValues("SalesOrg")
     .collect {
it.name
}
}
return api.global.salesOrgs
None

Only queries really needed for parameters gathering should be placed in this block.

Keeping each data query in a separate element avoids an element timeout.

Make sure the display is set to None, so this value does not get persisted.

Input parameters gathering elements

SalesOrg
api.inputBuilderFactory()
.createOptionEntry("SalesOrg")
.setOptions(out.SalesOrgs)
.getInput()

Keeping each user entry / input in a separate element is useful when testing the logic.

Currency

api.inputBuilderFactory()
.createOptionEntry("Currency")
.setOptions(out.SalesOrgs)
.getInput()

......

Stopping input generation execution element

AbortInputGeneration
if (api.isInputGenerationExecution()) {
api.abortCalculation()
}
None

Cancels the calculation run if running in the input generation mode (parameters gathering).

See also: /wiki/spaces/KB/pages/784957624

(tick) In release 10.0 Bees Knees, api.isInputGenerationExecution() replaces api.isSyntaxCheck(), which will however remain supported for backward compatibility.

Marked item dirty check element

ReferencePrice
...
if (needsSecondPass) {
api.markItemDirty()
// api.abortCalculation() - to be considered
// return - to be considered
}
...

It is good to check if the item needs a next pass at the very beginning of the logic if you plan to call api.abortCalculation.


Data gathering for logic calculation

CostRecord
def filters = [
Filter.equal("Cost"),
...
]

def pxCosts = api.find("PX", 0, 1, null, *filters)
return pxCosts ? pxCosts.getAt(0) : null
None

Returns the PX Cost records at one place and other elements can refer to it.

Make sure the display is set to None, so this value does not get persisted.

Keeping this query in a separate element is useful when testing the logic.

The data querying for big data should be done using api.getBatchInfo(). There is a sample code in BatchUtils in Shared library.

Margin
return api.vLookup("Margins", ...)

MinMargin

...
...

Calculation elements

CostPlus
if (out.Cost != null && out.Margin != null) {
return out.Cost * (1 + out.Margin)
}

return null

Calculates all the elements using the data queried in the previous block.
......

Result price element

ResultPrice
return out.CostPlus

Calculates the result price.

Auto-approve element

AutoApprove
def isAutoApproved = ...

return isAutoApproved ? 1 : 0

For LPG calculation the auto approval element can be placed here.

Found an issue in documentation? Write to us.