Skip to content

Price lists & overrides ​

Every product has a base price. The pricing suite lets you charge a different price in specific situations — a wholesale list, a branch that prices higher, or a special rate for one customer — without touching the base price.

🔷 For managers & admins
Pricing is **module-gated**: enable **Pricing** under Modules first. Viewing needs pricing.read; creating or editing prices needs pricing.manage (owners, admins, managers).

How a price is chosen ​

When a line is sold, the system picks the most specific price that applies, in this order — the first match wins:

  1. Branch price — a price set for the selling branch.
  2. Customer price — a price set directly for the order's customer.
  3. The customer's assigned price list — e.g. a wholesale list attached to that customer.
  4. Active price list — the default price list's price for the product.
  5. Base price — the product's own price, if none of the above apply.

So a branch price beats a direct customer price, which beats the customer's assigned (e.g. wholesale) list, which beats the default price list, which beats the base price. If you haven't set any overrides, every product simply uses its base price — the suite stays dormant until you use it.

Price lists ​

A price list is a named set of product prices — for example "Wholesale" or a seasonal promotion.

  1. Go to Price lists and select Add price list.
  2. Give it a name; optionally mark it the Default price list (used when no branch or customer price applies).
  3. Save, then on the edit screen add each product and its price under this list.

Branch & customer prices ​

Open Branch & customer prices, choose whether you're pricing for a branch or a customer, pick the branch/customer, then add products and their prices. These are the most specific prices and win over price lists and the base price.

Prices are enforced at the till

The chosen price is also the minimum a cashier may charge for that line — the backend rejects a sale priced below it (unless the user has the price-override permission). This stops accidental underpricing.

At the register, adding a product to the cart uses this effective price automatically: the line starts at the branch/customer price (not the base price), so what the cashier sees and charges already matches what the till enforces. If no override applies, the base price is used as before.

🟢 For everyone
**API:** `/api/v1/pricing` — `price-lists` CRUD, `price-list-items` / `branch-prices` / `customer-prices` upserts, `customer-list` (assign a price list to a customer, via `contacts.price_list_id`), `GET /pricing/resolve` (effective price for a line) and `POST /pricing/resolve-batch` (many lines in one call — the POS cart uses this to price the whole grid for the current branch/customer). Both reads need `pricing.read`, held by cashiers and sales staff. Resolution order is branch → direct customer price → customer's assigned list → active (default) price list → base (`PriceResolver`), enforced in the order pricing path. Prices are product-level with an optional variant id. Module gate: `catalog_pricing`.

On the mobile app ​

The mobile app carries the same two screens under More → Catalog:

  • Price lists — add, rename, mark one as the default, enable or delete a list, then open it to set a price per product.
  • Branch & customer prices — pick A branch or A customer, choose the one you mean, then set a price per product.

To set a price, select Set a product price, search for the product and type the amount. Viewing needs pricing.read; the buttons that change a price only appear with pricing.manage. The screens are hidden until the Pricing module is on, the same as in the browser.

Next steps ​

ZeylonPOS Knowledge Base