# CONTEXT.md — domain glossary

Terms the team and the code use, one meaning each. When a word here clashes with a
table name or an older label in the UI, this file wins for new code, docs and specs.
Decisions that are hard to reverse are in `docs/adr/`.

## Orders

**Combined Order** (`combined_orders`, also "checkout", "purchase" in the rating module)
: Everything the customer bought in one checkout. Every checkout creates exactly one,
  on web and in the app, and every `orders` row belongs to one (0 orphans in the
  2026-10-19 copy). It holds what the checkout shares: the shipping address
  (`shipping_address`), the shipping cost (`shipping_cost`, charged once), the coupon
  (`coupon_*`), the Paymera payment (`payment_id`) and the grand total including
  shipping. Its id is the **invoice number** (`invoice_number()`), and it is the unit of
  an order rating. A Combined Order may span several sellers by design: that is why it
  is split into Child Orders.

**Child Order** (`orders`)
: One seller's share of a Combined Order: one row per seller per checkout. It has its
  own `code`, delivery status, payment status, payment method, seller confirmation,
  staff follow-up (Confirm / Deliver Orders) and Kapitano Logistic handover. Sellers,
  staff and couriers work on Child Orders; customers used to see them as separate
  "orders" on `/purchase_history`.

**Coupon of a Combined Order** (agreed 2026-10-20)
: One coupon per checkout. Its minimum and value are judged on the total of the whole
  Combined Order (products + tax of every live Child Order, never shipping), never on one
  Child Order alone, and customers see it once, on the Combined Order's totals. The
  per-Child-Order amount (`orders.coupon_discount`) is a bookkeeping split so each seller
  order has an amount to collect and settle. A Single Order's coupon applies to that
  order. See ADR 0003.

**Single Order**
: A Combined Order with exactly one Child Order (1,322 of 1,604 checkouts, 82%, in the
  2026-10-19 copy). It is not a separate record type and has no column of its own: it is
  the one-child case of a Combined Order.

**Order Line** (`order_details`)
: One product variant in a Child Order: `product_id`, `variation` (the variant text,
  e.g. `Red-XL`), `quantity`, and `price` / `tax` as **line totals** (unit × quantity) in
  BASE. A line has its own delivery status (a line can be `returned` while its order is
  not).

**Void** (`order_is_void()`)
: A Child Order that is cancelled or fully returned. It counts for nothing in totals.

## Statuses

**Delivery status** lives on the Child Order and on each Order Line
(`pending → confirmed → picked_up → on_the_way → delivered`, plus `cancelled`,
`returned`). Child Orders of one Combined Order regularly differ (59 checkouts in the
2026-10-19 copy).

**Combined delivery status** (`combined_delivery_status()`)
: Derived, never stored: the least advanced status among the live (non-void) Child
  Orders; with none live, `returned` if any part came back, else `cancelled`.

**Status time** (agreed 2026-10-28)
: The moment a Child Order last reached a delivery status: one time per status, kept on
  the order, never a history. Reaching a status again replaces its time; going back
  clears the times of every later status, so the times always describe the route the
  order is on now. A status the order skipped (staff jumped from confirmed to delivered)
  has no time, never a copied one. Confirmed is the exception: its time is when the order
  first reached confirmed or later, so a jump straight past it carries the later status's
  time, which reads as skipped. Cancelled and returned share one time, the closing time.

**Combined status time** (agreed 2026-10-28)
: When a Combined Order reached a status: the Status time of its last live Child Order to
  reach it, the same rule as the Combined delivery status (a void Child Order does not
  hold the others back). Cancelled or returned only once every Child Order is, at the
  last one's time. Its placement is its oldest Child Order's.

**Paid time** (agreed 2026-10-28)
: When a Child Order became paid, whichever path marked it (staff, Paymera, the wallet).
  A Combined Order is paid once every live Child Order is, at the last one's time, the
  same rule as the customer's "paid" notice.

**Seller answer** (agreed 2026-10-28)
: The moment the seller confirmed their share or said it is unavailable, whichever came
  first. It sits between placed and confirmed, so a slow seller is never read as a slow
  employee. An in-house order has no seller answer.

**Editable** (customer side, agreed 2026-10-20)
: A Child Order the customer may still change: delivery status `pending`, payment
  status `unpaid`, its seller has not answered yet (`seller_confirmed_at` and
  `seller_unavailable_at` both empty; an in-house order has no seller step), its payment
  method is not Paymera (the amount is fixed in the payment link), and it was placed
  after `stock_on_confirm_since` (older orders took their stock at placement). Once the
  seller answers, staff confirm, or anything is paid, the customer can only cancel (same
  pending + unpaid rule as today) or ask customer service. Because nothing is paid while
  an order is editable, an edit only changes the amount still to be paid: there is no
  extra charge, refund or store credit. See ADR 0001.

**Payment status** (`paid` / `unpaid`) lives on the Child Order and its lines. Cash on
delivery is settled per Child Order (the accountant marks each one paid), so Child
Orders of one Combined Order regularly differ (49 checkouts). A Paymera payment is one
payment for the whole Combined Order and marks every Child Order paid at once.

**Combined payment status** (customer pages, agreed 2026-10-20)
: Derived, never stored, over the live Child Orders: `Paid` when all are paid, `Unpaid`
  when none is, `Partly paid` when mixed; an unpaid Paymera purchase reads
  `Payment not completed`. Each Child Order still shows its own status.

## Accounts and sign-in

**Account** (agreed 2026-11-09, ADR 0010)
: One `users` row: one person in one role group - customer, seller, admin/staff or delivery
  boy. The same person may hold several accounts with the same phone (a seller who also shops
  has a seller account and a customer account); they are independent, nothing links them.
  Never "the user" when the role matters: say customer account, seller account, staff account.
  A seller who shops signs in to their customer account; purchases made before 2026-11-09 by
  customers who were turned into sellers stay on that seller account.

**Guard** (agreed 2026-11-09, ADR 0010)
: Where an account is signed in: `web` (the storefront), `seller` (the seller panel), `admin`
  (the admin panel). Each panel reads only its own guard (a customer is never signed in to a
  panel); outside the panels the request reads whichever account is signed in, so a seller on the
  storefront is still themselves, as before. One browser holds one signed-in account at a time: signing in anywhere signs
  out whoever was signed in before.

## Sellers

**Seller on sale** (agreed 2026-11-02)
: A seller whose shop is approved and whose account is not banned. Only their products reach
  customers: lists, the product's own link, quick view, cart, checkout and feeds, on the
  website and in the app alike. A seller staff ban or un-approve is **off**: their products
  vanish for customers but are not changed (still published, still in the seller's panel and
  in carts, hidden), and come back as they were when the seller is on sale again. Orders
  already placed with them are untouched. There is no separate "deactivated seller":
  deactivation is a customer-only word.

**Working hours** of a seller (أوقات الدوام, agreed 2026-11-07)
: When the seller's shop is open, in Syria's time: up to two periods a day (a period may run
  past midnight and belongs to the day it starts), plus **closures** (whole days closed:
  holiday, travel, stocktaking). A seller who set none follows the **general hours**, the
  window staff already set for the seller WhatsApp alerts. "Open now" and "the order arrived
  outside the hours" are worked out from them, never stored. The seller and staff both edit
  them; customers do not see them (yet).

**Seller discount** (agreed 2026-11-04)
: The money a running product discount (the product's own, a category-wise discount or a flash
  deal, whoever set it) takes off one piece of the customer's price, taken off the seller's
  purchase price too, never below 0: the seller pays for discounts, our margin stays the same.
  Never a fake discount, a coupon or a wholesale tier. A percentage the seller types is of their
  own price, and the seller only ever reads a discount on their own price (never the customer's
  price or our commission); a percentage staff set is of the customer's price. Kept on the Order
  Line when it is placed (`order_details.seller_discount`); lines placed before carry none. The
  customer sees every discount as a percentage.

**Discount parts** (agreed 2026-11-10, ADR 0012)
: A product's discount is the sum of two parts, each with its own dates: the **seller's part** (a
  percentage of the seller's own price or an amount; the seller pays it, the Seller discount above)
  and **Kapitano's part** (a percentage of the customer's price or an amount; it comes out of our
  margin, which may go below zero). The seller sets only their own part and sees Kapitano's as a
  percentage and dates, never money. Our own and partner products have only Kapitano's part. Kept on
  the Order Line as `seller_discount` and `kapitano_discount`. _Avoid_: "discount share" (there is no
  split of one discount).

## Seller panel

**Seller statement** (كشف حساب التاجر, agreed 2026-10-29)
: The seller's own record of their sales for a period: their Child Orders, what they sold of
  each product (one row per product + variant + unit price, with its quantity) and the totals,
  printable and exportable to Excel. Every amount is the seller's share (the line's purchase
  price, in the seller's currency), never our selling price, tax, shipping, the coupon or the
  payment method, and no customer is named. Paid and due are the seller's **account** with us
  (agreed 2026-11-03): due = what we owe them now (`shops.admin_to_pay`, "Due to seller" in
  Admin → Sellers → "Go to Payment"), paid = every payout made from that window, plus the
  period's payouts listed. Never the customer's payment: the customer paying us does not mean
  the seller has been paid. See ADR 0007.

**Earned / waiting** (seller side, agreed 2026-10-24)
: The seller's sales split by the Child Order's payment status: earned = paid by the customer
  (so we owe the seller), waiting = not paid yet. Shown on the dashboard only; the Seller
  statement leaves it out (agreed 2026-10-29) and shows the seller's account instead.

## Customer order pages (`/purchase_history`)

**Order entry** (agreed 2026-10-20)
: One item of the customer's order list = one Combined Order. A Single Order shows as
  one row; a Combined Order as a card with its Child Orders under it. Pagination and
  sorting count entries, not Child Orders. See ADR 0002.

**Order page** (agreed 2026-10-20)
: The one details page for a Combined Order. It shows what the Child Orders share once
  (address, payment method, totals, invoice, rating) and one section per Child Order
  (seller, code, statuses, lines, edit / cancel). Reached through any of its Child
  Orders' existing URLs (`/purchase_history/details/{encrypt(child id)}`), which scroll
  to that Child Order's section.

**Status filter match** (agreed 2026-10-20)
: A delivery- or payment-status filter matches an entry when **any** of its Child
  Orders has that status; the entry is then shown whole, with the matching Child
  Orders marked and expanded.

**Order edit** (agreed 2026-10-20)
: A customer's change to an Editable Child Order: a line's quantity, its variant (same
  product), or removing a line (removing the last line is a cancel, not an edit). No
  adding products. Money rules are in ADR 0003.

**Basket fingerprint**
: A hash of a Child Order's lines (id, variation, quantity), computed on the fly and
  never stored. A form that shows a basket sends the fingerprint it showed; a save whose
  fingerprint no longer matches is refused, because someone changed the basket in
  between. See ADR 0004.

## Company warehouse (مستودع الشركة, agreed 2026-10-29, revised 2026-10-31)

**Warehouse**
: Kapitano's own storage, where sellers leave part of their goods. There is exactly one, so the
  system has no list of warehouses. Every order is gathered there before it goes to the
  customer. Decisions: `docs/codebase/features/company-warehouse-brief.md`.

**Warehouse Stock** (`warehouse_stocks`)
: The pieces of one product variant (product + variant text, `''` for a product without
  variants) held in the Warehouse. Always a **part of** the variant's stock for sale
  (`product_stocks.qty`), never extra. So a variant has three numbers: **total for sale**
  (`product_stocks.qty`), **in Kapitano's warehouse** (the Warehouse Stock) and **at the
  seller's shop** (total − warehouse, never stored). The shop it belongs to is the product's
  owner. Pieces moving between the Warehouse and the shop never change the total.

**Warehouse Movement** (`warehouse_movements`)
: One change of a Warehouse Stock: fill, take out, count correction, order take, order give
  back, cancel in, return in, transfer. The stock is the sum of its movements; nobody types
  over the number.

**Warehouse pieces** (of an Order Line)
: How many of the line's pieces come from the Warehouse; the rest come from the seller's shop.
  Decided when the Child Order is marked "جاهز للشحن" (confirmed). No order is ever split by
  where its pieces come from. Stored on
  `order_details.warehouse_qty` (0 = all from the shop). Only for the **pilot shops** (setting
  `warehouse_order_shops`) while orders are tried on the warehouse. When the line is cancelled,
  sent back to pending or returned, the pieces that are in our building come into the Warehouse
  (order give back for the Warehouse pieces, cancel in for shop pieces the captain already
  collected, return in for every returned piece) and the line goes back to 0.

**Held for orders ready to ship**
: Warehouse pieces of Order Lines that are confirmed or picked up: no longer in the Warehouse
  Stock, still on the shelf until the order goes "في الطريق" (or straight to delivered).

**To prepare** (للتحضير)
: The list of Child Orders ready to ship that hold Warehouse pieces, one block per order, printed
  as the **pick list** staff pull the pieces with. An order leaves it when its pieces stop being
  held. **Held too long**: still on it more than N days (setting, 4) after "جاهز للشحن", so its
  "في الطريق" was probably forgotten; flagged, never corrected by a count.

**Take out** (إخراج من المستودع)
: Pieces leaving the Warehouse, always with a reason: **back to the seller's shop** (the
  pieces still exist, so the total for sale does not change), **damaged** or **lost** (they no
  longer exist, so the total for sale goes down by as many). Never more than we hold.

**Warehouse receipt** (إيصال المستودع)
: The printed proof of one fill or one take out (one batch of Warehouse Movements): shop, date,
  staff member, products and pieces, signed by our staff and the seller. Reprintable later.

**Warehouse count** (جرد متجر)
: Staff count one shop's pieces in our building against what the system expects: **free** (the
  Warehouse Stock) + **held for orders ready to ship**, shown apart with the holding orders. Open
  while they count, then **saved** (each difference becomes one count correction, a Warehouse
  Movement with a reason) or **cancelled** (nothing moves). Pieces that moved during the count,
  orders included, are never corrected back. Only free pieces are a correction: a shortfall beyond
  them while orders hold pieces is refused (move the forgotten order to "في الطريق").
