Specs › order · version 1 · 2026-09-25 04:03 UTC

order

Placing an order: check the stock, price the lines, pick a discount, confirm. Each step is its own message, so each can be extended or replaced with rules of its own. The arithmetic is in expressions; the rules decide what happens next.

Stock

$when order.checkStock (items: Array, stock: Object) {
  short = items filter (i => (stock[i.sku] ?? 0) < i.qty) map (i => i.sku)
  if (short is not empty) {
    list = short mkString ", "
    diesel.throw (code = "E_STOCK", msg = "out of stock: ${list}")
  }
}

Pricing

$when order.price (items: Array) {
  payload = items map (i => i.qty * i.price) fold (s = 0.0) (x => s + x)
}

Discounts

Guards pick exactly one rule: members get 10%, anyone else spending over 100 gets 5%, the rest pay full price.

$when order.discount (subtotal: Float, member: Boolean) if (member) {
  payload = subtotal * 0.10
}
$when order.discount (subtotal: Float, member: Boolean) if (not member and subtotal > 100.0) {
  payload = subtotal * 0.05
}
$when order.discount (subtotal: Float, member: Boolean) if (not member and subtotal <= 100.0) {
  payload = 0.0
}

Placing it

Each step's variables (subtotal, discount) belong to this rule only; the caller sees just the payload it returns.

$when order.place (items: Array, member: Boolean, stock: Object) {
  order.checkStock (items, stock)
  subtotal = order.price(items = items)
  discount = order.discount(subtotal = subtotal, member = member)
  payload = {status: "confirmed", subtotal: subtotal, discount: discount, total: subtotal - discount}
}

order.submit is what a shop would call: the same, but a stock problem becomes a rejected order instead of an error.

$when order.submit (items: Array, member: Boolean, stock: Object) {
  try {
    order.place (items, member, stock)
  } catch (e) {
    payload = {status: "rejected", reason: e.message}
  }
}

Try it: order, or in the Fiddle.