Table of Contents

Lists and inventory

Shared lists (ValueList, LookupValue, LookupService)

A shared list has one row of its own (ValueList): its name, its order (most used, or the window's line order), what a value a requester types does (ListEntry: added for everyone, kept on its request, or refused), optional detail columns (ColumnsJson: text, number, yes/no, or a value of another list) and two optional roles: held values and stock items.

  • A list is written by one method, LookupService.SaveListAsync: new lines are added, removed lines switched off (a request keeps its words), and a line whose text changed keeps its row (renames, audited as lookup.renamed).
  • A value a published rule reads is never switched off or deleted; a column a rule reads never goes or changes type.
  • The branches' and the rooms' lists follow their own pages: their values change only there.
  • A list read by a published service, a draft or a stopped service is not deleted.

Held values (HeldValuesListener)

A list marked «قيمها تُحجز» lends its values (a car, a projector). A value is taken while an open request's form holds it (waiting for approval, in progress or returned), and free once that request closes. Nothing is stored: the forms are the record. Every stored version of a service is read, so a request on an older version still holds its value. Writes refuse a taken value under an advisory lock; publishing refuses a held list in a table column.

The stock ledger (modules/requests/Stock)

flowchart LR
    V[Voucher\nreceipt, issue, transfer, correction] --> P[StockService.PostAsync]
    T[Task «حركة مخزون»\nStockListener.StepDoneAsync] --> P
    R[Return / reject / cancel\nReverseRequestAsync] --> P
    P --> M[(StockMove\nthe ledger)]
    P --> B[(StockBalance\nper item and branch)]
    P --> L[(StockLot\nper expiry batch)]
    P --> N[Low-stock notice]
  • Any list may hold stock («قيمها أصناف مخزون», ValueList.StockJson, StockList): an item's unit and minimum are two of the list's own detail columns. A warehouse is a branch's.
  • One writer. StockService.PostAsync writes the movement, the balance and the batch in its caller's save. A balance is never edited; StockTests checks every balance equals the sum of its ledger.
  • Weighted average cost, one rule for every line (AverageAfter): a receipt weighs its cost in; a line out at the average leaves it unchanged; a receipt taken back leaves at its own cost.
  • Vouchers (SaveVoucherAsync) are saved with their lines in one transaction. «عكس السند» posts the opposite lines at their own costs; «حذف السند» is allowed only while nothing moved the voucher's items after it, then the balances are recounted from the ledger.
  • From a request. A task's «حركة مخزون» (StepDef.Stock: a table, its item and quantity columns, a direction, a warehouse field) posts when its holder presses «تم». A way out and a way in over one table on one step are a transfer, posted both sides or neither. A return, a rejection or a cancellation puts back what the request moved, and a resubmission moves it again. A correction never changes a warehouse a step already moved stock in.
  • Warn, then allow. An issue above the balance is allowed; the confirm before «تم» (WarningsAsync) says each shortfall and each row that will not move (an unknown item, an unknown branch, a list that holds no stock).
  • Batches. An item whose list expires moves by batch (StockLot): a receipt dates it, a way out takes the batch the holder picks (ChoicesAsync, nearest unexpired first). A line with no known date goes to «بلا تاريخ» (StockService.NoDate), so batches always add up to the balance; a list that starts expiring puts its stock there.
  • Notices go to every holder of ManageStock: once when a balance crosses its minimum (StockLow), and from the daily sweep (StockExpirySweep) once before a batch expires and once when it does (StockExpiring).
  • Audit keys: stock.received, stock.issued, stock.transferred, stock.adjusted, stock.voucher_cancelled, stock.voucher_deleted.

The audit of 2026-10-13 and its fixes: docs/checklists/stock-lists-audit-2026-10-13.md.