At a Glance
Persona: Receiver (Store Keeper / Receiving Clerk + Store / Inventory Manager) · Module: good-receive-note · Workflow stages:(none) → draft(create against PO or manual) ·draft → saved(line entry complete) ·saved → committed(Inventory Manager — fires inventory increment + cost-layer write + PO advance + AP accrual) ·draft / saved → voided· Key permissions: create / edit draft (Store Keeper); commit (Inventory Manager); SoD — cannot commit GRN against own upstream PO
What this persona does: Records dock receipt, captures lot / expiry, then commits the GRN that increments inventory and writes the cost layer.
The Receiver persona covers the Store Keeper / Receiving Clerk at the dock and the Store Manager / Inventory Manager who supervises the receipt. The Store Keeper owns the editable draft — they create the GRN against the upstream PO (or manually for ad-hoc receipts), count and inspect the physical delivery against the PO and the vendor delivery note, record received_qty and accepted_qty per line, capture lot numbers and expiry dates through the linked inventory transaction (tb_inventory_transaction_detail, addressed from the GRN detail_item via inventory_transaction_id), attach packing slips and quality evidence, and save the document for review. The Inventory Manager owns the irrevocable posting step — they review the saved GRN against the actual stock received, run the commit (saved → committed) on individual documents or batch-commit multiple saved GRNs at end of shift / end of period, and are the only persona within this drill-down authorised to fire the inventory increment, cost-layer write, and PO line received_qty advance. On entry to this flow the source PO is at po_status ∈ {sent, partial}. The GRN states owned by this persona are draft and saved (Store Keeper) and the saved → committed transition (Inventory Manager); voided is reachable from draft or saved by either sub-persona with a reason and no inventory impact, while post-commit reversal of a committed GRN requires elevated co-authorisation with Finance and is out of scope for the routine Receiver path. Segregation of duties forbids the user who created or transmitted the upstream PO from posting the GRN against it (carries over from the PO persona's PO_AUTH_010).
The Receiver persona covers two sub-roles: Store Keeper / Receiving Clerk (creates and edits the GRN, draft and saved owner) and Inventory Manager / Store Manager (commits the GRN, saved → committed). Both sub-roles operate on GRNs across both PO-sourced and manual creation paths. The server-side RBAC (GRN_AUTH_001–GRN_AUTH_011) enforces the segregation-of-duties rule at commit: the user committing the GRN must not be the same user who created or transmitted the upstream PO.
| Action | draft | saved | committed | voided | Store Keeper | Inventory Manager |
|---|---|---|---|---|---|---|
| Create GRN (from PO) | ✅ → creates draft |
❌ | ❌ | ❌ | ✅ | ❌ |
| Create GRN (manual) | ✅ → creates draft |
❌ | ❌ | ❌ | ✅ | ❌ |
| Edit header (vendor, currency, date) | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ (reverts to draft on substantive change) |
| Add / edit lines and detail_items | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
Enter received_qty per line |
✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
Enter accepted_qty per line |
✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Record lot / expiry (via linked inventory transaction) | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Attach packing slips / evidence | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Save for review (draft → saved) |
✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
Resume edit (stay in saved) |
❌ | ✅ | ❌ | ❌ | ✅ | ✅ |
Commit (saved → committed) |
❌ | ✅ | ❌ | ❌ | ❌ per GRN_AUTH_005 (unless below-threshold self-commit) |
✅ |
| Batch commit | ❌ | ✅ (multiple GRNs) | ❌ | ❌ | ❌ | ✅ |
Void (draft → voided or saved → voided) |
✅ | ✅ | ❌ | ❌ | ✅ (own document) | ✅ |
| Add comment | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| View (read only) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ℹ️ Post-commit reversal: Voiding a
committedGRN requires elevated co-authorisation by the Inventory Manager and Finance (or System Administrator); this is out of scope for the routine Receiver path and is not an action either sub-role can trigger unilaterally. SeeGRN_POST_010andGRN_AUTH_008.
Entry point: Two equivalent paths into draft creation, with one downstream variant:
tb_purchase_order_detail with pending_qty (= order_qty − received_qty − cancelled_qty) as the default editable received quantity.po_status ∈ {sent, partial} and click Receive on the header; deep-links into the GRN module with the PO pre-selected, identical screen and effects.doc_type = manual; vendor, currency, exchange rate, and receipt date entered directly; no purchase_order_detail_id written on any line. Used for emergency / no-PO receipts.Primary flow (happy path, 10 steps):
order_qty, the running received_qty, cancelled_qty, and the pending balance.tb_good_received_note at doc_status = draft (initial editable state, no stock or GL impact); header fields are inherited from the PO snapshot (vendor_id, currency_id, exchange_rate) or entered directly for manual receipts.received_qty per line — what physically arrived in the order UoM. The screen accepts values equal to, less than, or (subject to the tenant over-delivery tolerance) greater than the pending balance.accepted_qty per line — what passes the quality / specification inspection at the dock and is to be admitted into inventory. accepted_qty ≤ received_qty; the gap (received_qty − accepted_qty) is the quality-rejection variance that stays with the vendor for return / credit note.detail_item row links to an tb_inventory_transaction (via inventory_transaction_id) whose tb_inventory_transaction_detail children carry the lot_no, expiry_date, and per-lot quantity. Auto-generated lot numbers may be accepted or manually overridden; multiple lots per line are supported by adding additional inventory transaction detail rows.draft → saved). Line-level validation runs at save — all rules GRN_VAL_006–GRN_VAL_010 must pass; the document becomes visible to the Inventory Manager and Finance for review while remaining editable by the Receiver as the owner. Still no inventory or GL impact.saved → committed). Commit-time rules GRN_VAL_011–GRN_VAL_014 are evaluated in one transaction: at least one detail_item present, lot data present on inventory transactions for inventory-tracked items, source PO status still valid (sent or partial), extra costs allocated. On success the system: (a) writes the stock-IN movement and posts tb_inventory_transaction per line, (b) increments InventoryStatus.QuantityOnHand, updates LastUnitCost, refreshes TotalCost, (c) creates new FIFO cost layers or recomputes AverageCostTracking per the item's costing method, (d) advances tb_purchase_order_detail.received_qty by the GRN line quantity and may flip the source PO's po_status from sent → partial or sent → completed / partial → completed, (e) raises the AP accrual, and (f) locks the GRN against further edits. The document is now the evidence anchor for the three-way match (PO ↔ GRN ↔ invoice).received_qty < pending_balance): save the GRN with what physically arrived; commit when ready. The source PO transitions to (or stays at) partial; the unfulfilled balance remains open for a subsequent GRN against the same PO. A variance comment is written on the line, and the Purchaser is notified via the activity log to chase the vendor for the remainder. The Receiver may re-enter this flow when the next shipment arrives.received_qty > pending_balance): the GRN screen gates the entry against the tenant over-delivery tolerance. Within tolerance — received_qty is accepted, the GRN commits, received_qty on the PO line exceeds order_qty − cancelled_qty, and the PO flips to completed. Out of tolerance — the screen blocks the save; the Receiver caps received_qty at the pending balance and refuses the excess at the dock with no system record for the rejected excess; the Purchaser logs the vendor-side dispute on the PO.accepted_qty < received_qty): record both values on the line; save and (on Inventory Manager authority) commit. The PO line's pending balance is reduced by received_qty, but inventory on-hand only rises by accepted_qty; the variance is held as the return / credit-note quantity on the GRN and feeds vendor-performance metrics. The Purchaser is handed off the variance for vendor-side resolution (return, credit note, replacement) — no auto-correction on the PO itself.sent or moves to partial based on what was correctly received.partial. When the next shipment arrives, repeat the primary flow against the same PO; the PO either stays partial or progresses to completed when the final balance clears. Multiple committed GRNs may exist against a single PO.saved GRN individually, the Inventory Manager opens the batch-commit screen at end of shift / end of period and selects multiple saved GRNs. Each GRN in the batch is evaluated against the same commit-time rule set in a single transaction; partial-batch failure rolls back only the failing GRN — successful GRNs in the same batch still commit. Useful when many small deliveries arrive through the day and individual commits would fragment the cost-layer write.The Receiver's involvement on a given GRN ends at one of four boundaries:
saved → committed) — handoff to Finance for the three-way match (PO ↔ GRN ↔ vendor invoice) and AP posting. The GRN is locked; any subsequent correction is via a credit note against the GRN or a compensating adjustment in [inventory-adjustment](/en/inventory/inventory-adjustment). The Purchaser is also re-notified if any line carried a variance comment at commit time.draft or saved, the Receiver / Inventory Manager voids it with a reason (draft → voided or saved → voided); no inventory or GL impact, document terminates. (2) If individual lines are rejected on quality but the rest of the delivery is accepted, accepted_qty is reduced on those lines and the GRN commits with the reject variance recorded for vendor return / credit note.received_qty decrement, and the reversing AP entry, with the GRN transitioning to voided. The Receiver may then raise a replacement GRN if the underlying receipt is to be re-recorded.draft / saved / committed / voided) on enum_good_received_note_status, the global state machine that this persona's path traverses, and the cross-persona handoff table.../carmen/docs/good-recive-note-managment/GRN-User-Experience.md — carmen/docs source for the Receiving Clerk and Inventory Manager personas, the main GRN user flow, and the PO-anchored creation flow (the legacy DRAFT / PENDING_APPROVAL / APPROVED / REJECTED / CANCELLED model used there is not canonical; this page follows the four-state Prisma enum).../carmen/docs/good-recive-note-managment/GRN-Overview.md — carmen/docs module overview: receiving as the three-way-match anchor, integration points with PO, Inventory, Finance, and Vendor modules, lot / batch tracking, and quality control gates.enum_good_received_note_status and the inventory-transaction linkage (tb_good_received_note_detail_item.inventory_transaction_id → tb_inventory_transaction_detail.lot_no / expiry_date) used in steps 6 and 10.GRN_VAL_006–GRN_VAL_010 (save-time) and GRN_VAL_011–GRN_VAL_014 (commit-time) referenced in the primary flow.tb_purchase_order_detail.received_qty and may flip po_status (sent → partial → completed); see the PO module's 03-user-flow-receiver.md for the PO-side effects mirrored here.tb_inventory_transaction carries the lot, expiry, and cost-layer data, and InventoryStatus.QuantityOnHand is incremented by accepted_qty.saved → committed transition.