Multi-pass Calculation of a Price List or Live Price Grid

When the price of one product depends on the price of another product within the same price list (or LPG) then you need to calculate the price list in several rounds (= passes).

From the technical perspective:

  • There is no guarantee that the line items are calculated in any specific order.
  • Also, the line items can be calculated in parallel threads, so the related product can be calculated on a different machine.

The calculation of the price list line items will then run in several passes:

  • 1st pass – Calculation logic is executed for all lines:
    1. Lines, which can be priced/calculated right away are calculated.
    2. Lines, which need to wait for a price of another product, have to be marked as "dirty" and scheduled for the calculation in the next pass.
  • 2nd pass – Calculation logic is executed only for lines marked as "dirty":
    1. Lines, which can be already priced/calculated are calculated.
    2. Lines, which still need to wait for a price of another product (i.e. the product, they refer to, is still not calculated), will mark themselves as "dirty".
  • 3rd pass – If there are still some lines marked as "dirty" then the system will repeat the steps of the 2nd pass. By default the server is set to do only 2 passes.

(info) The current item is only dirty-recalculated when it is the only dirty item. If there are more dirty items resulting from the initial calculation, all dirty items including the initial item are calculated in the same background process. 


Conceptual Example - only for 2-pass calculation
def resultPrice

if (isLeader()) {

    /* result price doesn't have dependency on another product => calculate the price right away */
    resultPrice = calculateLeaderPrice()

} else {

    /* result price is derived from the price of the other (= leading) product */
    if (api.getIterationNumber() == 0) {

        /* in the 1st pass the leader product is not yet calculated, so mark this item to be calculated in the next pass */
        api.markItemDirty()

        /* do not calculate remaining elements for a better performance */
        api.abortCalculation()

    } else {

        /* in the 2nd pass, the leader product is calculated already */
        def leaderPrice = api.currentContext(leaderSku)?.ResultPrice

        resultPrice = calculateFollowerPrice(leaderPrice)

    }
}

return resultPrice

Useful Functions and Properties

  • api.getIterationNumber() – Returns the number of passes the list has been through. (Initial 1st pass = 0, second pass = 1, and so on). It replaces api.isSecondPass() function which is now deprecated.
  • api.currentContext(otherSku) – Reads the results from another product (within the same Price List or Live Price Grid).
  • api.markItemDirty() – Sets the current line item as dirty (when we need some other product to be calculated first).

You can also suppress autoApprove when an item is dirty by setting an advanced config property on a partition:

skipAutoApproveOnDirtyPGI = true

Found an issue in documentation? Write to us.