Skip to content

Money and ledgers

Adocommerce Kit treats money as an integer amount plus an ISO 4217 currency. It never stores floating-point prices and never silently combines currencies.

Adocommerce Kit treats money as an integer amount plus an ISO 4217 currency. It never stores floating-point prices and never silently combines currencies.

Minor units, explicit currency

import { Money } from "@adocommercekit/core";

const shirt = Money.of(2_500n, "USD");
const twoShirts = shirt.multiply(2n);

shirt.add(Money.of(500n, "EUR")); // throws E_CURRENCY_MISMATCH

amount is a bigint in domain code and a decimal string in JSON. The storefront transformer shape is stable:

{
  "amount": "2500",
  "currency": "USD",
  "formatted": "$25.00"
}

Formatting is presentation only. Arithmetic always uses the integer amount.

Rows are the source of truth

Cart and order totals are cached columns for fast reads. Line and adjustment rows are the ledger that can reconstruct those caches.

subtotal = Σ(line.unitPrice × line.quantity)
grand    = subtotal + Σ(eligible, non-included adjustments)

Adjustments are signed money rows with a source, label, eligibility flag, inclusion flag, and position. Tax, shipping, and future promotion packages all write the same primitive. They do not add unrelated total columns.

  • Included adjustment: represented in the displayed line price; excluded from the grand-total addition.
  • Eligible adjustment: participates in totals. Ineligible history may remain for auditability.
  • Negative adjustment: reduces the total and contributes to discountTotal.

Recalculation owns writes

Every cart mutation locks the cart, changes one input, and calls the processor pipeline. Price resolution runs before shipping and tax processors. The service replaces generated adjustments, recomputes the ledger, and writes cached totals in one transaction.

Never edit grandTotalAmount directly. Extend a processor or resolver so the ledger remains explainable.

Allocation without lost cents

When a total must be distributed across lines, Adocommerce Kit allocates integer minor units. The invariant is:

$$ \sum_i allocation_i = total $$

Remainders are distributed deterministically. This matters for inclusive tax, proportional discounts, partial refunds, and reconciliation: repeated calculation must produce the same rows.

Persistence conventions

@moneyColumn() maps a domain Money value to <prefix>_amount and <prefix>_currency columns. Host-owned model subclasses inherit this mapping. Database amounts are strings or integer-compatible values on write and normalize to bigint on read.

Use serializeMoney only at HTTP boundaries. Drivers and services should accept and return Money.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close