Skip to content

Products — Price Lookup Module

The Products app exports a Filtrera module at /apps/products/price-lookup.module.hrc that computes the effective price of one or more products across a set of price lists, plus a price-change history within a configurable time window.

It is the canonical building block for:

  • Custom price-lookup ingresses — exposing pricing data to a storefront, marketing system, or BI tool with a request and response shape that fits your project.
  • Bulk price exports — computing prices in batches for export to ERP, PIM, or marketing platforms.
  • EU Omnibus 30-day-low displayslowestPrice over a 30-day window is the canonical input for "lowest price in the last 30 days" labels.

Module path

/apps/products/price-lookup.module.hrc

Exports

lookupPrices

Computes effective prices and price history for a list of products against a list of price lists, scoped to one currency and one time window.

Filtrera type signature

(params: {
  productNumbers: [text]
  currencyCode: text
  priceListKeys: [text]
  window: duration
}) => { text -> {
  currentPrice: number | nothing
  history: [{ at: instant, price: number | nothing }]
  lowestPrice: number | nothing
  highestPrice: number | nothing
} }

Inputs

FieldTypeDescription
productNumbers[text]Asset numbers of the products to look up.
currencyCodetextISO 4217 currency code. Only prices in this currency are considered.
priceListKeys[text]Price lists to consider. Only prices on these lists are considered.
windowdurationHow far back to compute history, lowest, and highest. For EU Omnibus, use 30 days.

Output

A map keyed by productNumber (asset.product.assetNumber) where each entry has:

FieldTypeDescription
currentPricenumber | nothingThe current best price across active price lists, ignoring deactivated prices. nothing if no active price applies.
history[{ at: instant, price: number | nothing }]Chronologically-ordered entries — one per change of the effective best price within window. price is nothing when the effective price was not defined (no active list, or all lists deactivated) at that moment.
lowestPricenumber | nothingLowest effective price observed within window.
highestPricenumber | nothingHighest effective price observed within window.

Window semantics

  • The history is computed by replaying activity-log events (priceChange, priceDeactivation, priceReactivation, priceListActivation, priceListDeactivation — see Activity log event types) from the start of the window forward.
  • An entry is appended to history whenever the effective best price for the product changes — not on every individual priceChange event. Activations and deactivations of price lists or individual prices contribute to this only when they affect the effective price.
  • Products that exist but have no matching active prices appear in the result with currentPrice = nothing and an empty or deactivation-only history.
  • Products that don't exist do not appear in the result map.

Declaring the dependency

Add this to your app's h_app.yaml:

yaml
requires:
  modules:
    /apps/products/price-lookup.module.hrc:
      exports:
        lookupPrices:
          type: '(params: { productNumbers: [text], currencyCode: text, priceListKeys: [text], window: duration }) => { text -> { currentPrice: number | nothing, history: [{ at: instant, price: number | nothing }], lowestPrice: number | nothing, highestPrice: number | nothing } }'

See Declaring App Dependencies for the surrounding context.

Use cases

Custom price-lookup ingress

Expose a project-specific HTTP ingress backed by lookupPrices. The contract — request body, response shape, auth, channel filtering, tax handling — is intentionally up to the implementer because storefront pricing rules vary widely.

filtrera
import './price-lookup.module.hrc' as priceLookup

param request: {
  productNumbers: [text]
  currencyCode: text
  priceListKeys: [text]
}

let result =
  priceLookup.lookupPrices {
    productNumbers = request.productNumbers
    currencyCode = request.currencyCode
    priceListKeys = request.priceListKeys
    window = 30 days
  }

from {
  currencyCode = request.currencyCode
  prices =
    result entries
    select e => {
      productNumber = e.key
      currentPrice = e.value.currentPrice
      lowestIn30Days = e.value.lowestPrice
      timeline = e.value.history
    }
}

Register the component as a public HTTP ingress in your h_app.yaml and your storefront can call it directly.

Bulk price export

Call lookupPrices from a job that emits an export feed for ERP, PIM, or marketing platforms. Batch the input list to keep memory usage bounded and to fit any downstream API limits.

filtrera
import './price-lookup.module.hrc' as priceLookup

param batch: {
  productNumbers: [text]
  priceListKeys: [text]
  currencyCode: text
}

let prices =
  priceLookup.lookupPrices {
    productNumbers = batch.productNumbers
    currencyCode = batch.currencyCode
    priceListKeys = batch.priceListKeys
    window = 30 days
  }

from
  prices entries
  select e => {
    productNumber = e.key
    price = e.value.currentPrice
    lowestPrice = e.value.lowestPrice
  }

EU Omnibus 30-day-low

For storefront price displays that need to show the lowest price in the last 30 days (per the EU Omnibus Directive), pass window = 30 days and surface lowestPrice alongside currentPrice. The history field is available if you want to render a price-over-time chart or audit trail.

© 2024 Hantera AB. All rights reserved.