# WP3 [FIN] — Inventory Receipt + Purchase GRN

## Goal
Wire the two documents where inventory **value and the GR-IR accrual enter the books**:
- **Purchase GRN** — `PurchaseGrnController@approve():401` **moves stock** (`:536` → `ApproveReceipt`) and **posts a GR-IR journal entry** (`:539` → `FinalizeApprovedGrn` → `PostGrnGrniAccrual`). It is currently **unwired**. (The KB's old note "GRN has no submit→approve→post lifecycle, deferred" is **stale** — literally true that there's no *submit*, but the conclusion was wrong: its `approve()` is a full financial commit.)
- **Inventory Receipt** — `InventoryReceiptController@approve():429` → `ApproveReceipt` increases stock (`:141`) and fires `InventoryReceiptApproved` (`:175`), which drives the GR-IR accrual for controlled GRNs.

Same approved shape as WP2: **Shape 1 "authorize, then post"**. Follow WP2's implementation exactly — it is the template.

## Two edge cases that MUST be handled (mandatory, from the analysis)

### 1. `receipt_auto_approve` must NOT bypass the workflow
`stock-receipts.component.ts:167` reads setting `inventory.receipt_auto_approve`, and the BE may auto-approve a receipt **the moment it is created**. If an approval workflow matches the document, **the approval wins** — auto-approve must not short-circuit it. Find where the BE auto-approves on create and make the workflow take precedence. **This is a required test case.**

### 2. GRN + its receipt = ONE approval, not two
`PurchaseGrnController:524` branches:
- `grnReceiptRequiresApproval = true` → GRN goes `PendingReceipt`, the receipt stays Draft, stock is deferred to the keeper. The keeper's receipt approval then fires `InventoryReceiptApproved` → `FinalizeGrnOnReceiptApproval` → `FinalizeApprovedGrn`.
- `false` (default) → stock moves immediately + GR-IR JE.

If both GRN **and** Receipt have workflows, the same money must not require two separate authorizations. **Approved decision: the approval sits on the GRN; the receipt follows it.** Implement so that a receipt created *by* a GRN does not independently demand its own approval. A standalone receipt (not from a GRN) still gets its own. **Required test case.**

## Exact files

### BE
- `Modules/Core/app/Enums/ApprovalDocumentType.php` — `GRN` and `DeliveryNote` cases **already exist** (`:16`, `:11`) — do NOT re-add. Add `InventoryReceipt = 'inventory_receipt'`.
- `Modules/Core/app/Services/ApprovalWorkflowService.php:382-391` — add rows for **`grn`** and **`inventory_receipt`**. ⚠️ Missing row = blank inbox rows, silently (`:396-398` `continue`s on unknown types). GRN's missing row is exactly why it's a dead enum case today.
- `Modules/Purchases/app/Http/Controllers/PurchaseGrnController.php` — `use DrivesApprovalWorkflow`; add `submit`; guard `approve():401` with `assertApprovedForPost` **before** the branch at `:524` (i.e. before ANY stock movement or JE); engine approve/reject routing. GRN status enum (`Modules/Purchases/app/Enums/PurchaseGrnStatus.php`) — add `PendingApproval` (no migration).
- `Modules/Inventory/app/Http/Controllers/InventoryReceiptController.php` — same, commit at `:429`. `ReceiptStatus` — add `PendingApproval`.
- Models: virtual `total` accessor for `InventoryReceipt` (no `total`/`grand_total` column). GRN — check whether it already exposes a total; if not, add one. Precedent: `PurchaseRequest.php:128-136`.

### FE
- `features/stock-receipts/stock-receipts.component.{html,ts}` and `features/purchases/grns/grns.component.{html,ts}`:
  - Drop in `<app-approval-actions [approval]="item.approval" (acted)="load()" />` (shared component from WP1).
  - Submit-for-approval button when `approval.required && draft`; commit hidden while pending.
  - **RENAME (approved):** the receipts commit button is currently **"استلام واعتماد" (Receive & Approve)** — rename to **"استلام" / "Receive"**, drop the green ✓, use `pi pi-box`. ✓+green is reserved for the governance approve.
  - ⚠️ **The receipts commit is heavyweight** — `stock-receipts.component.ts:438-458` `approve()` re-fetches the receipt, resolves `tracking_type` per line, and either shows a simple confirm OR opens the full `ReceiptApprovalDialogComponent` (batch/serial/expiry capture). **Keep all of that intact** — you are only renaming it and gating it behind `approval.state !== 'pending'`.
- `core/models/inventory.model.ts` + the GRN model — add `approval?: DocumentApprovalState`.
- i18n: `APPROVAL_WF.DT_INVENTORY_RECEIPT` (+ `DT_GRN` already exists) in both `ar.json`/`en.json`; new button labels.

## Interfaces
- **Consumes from WP1/WP2:** `<app-approval-actions>`, the `document-types` endpoint, and WP2's exact controller pattern.
- **Exposes:** `grn` and `inventory_receipt` become `wired: true` in the document-types endpoint (via their `attachDocumentReferences` rows) — which is what makes them selectable in WP5's config screen.

## Acceptance criteria
- [ ] **INVARIANT (test):** a pending GRN / pending receipt moves **ZERO stock** and creates **ZERO GR-IR journal entry**.
- [ ] **NO REGRESSION (test):** no workflow → byte-for-byte today's behaviour on both.
- [ ] **`receipt_auto_approve` does NOT bypass an active workflow** (test).
- [ ] **GRN + its receipt require ONE approval, not two** (test). A standalone receipt still gets its own.
- [ ] Both `PendingReceipt` and default GRN branches are guarded (the guard sits before `:524`).
- [ ] The receipts batch/serial capture dialog still works unchanged after approval.
- [ ] `grn` + `inventory_receipt` return `wired: true` from the document-types endpoint and render correctly in the inbox (number + amount).
- [ ] Receipts commit button renamed, no longer green ✓.
- [ ] `ng build` green.

## Tests
- Pest: pending-blocks-commit; pending → no stock + no GR-IR JE; no-workflow unchanged; auto-approve doesn't bypass; GRN+receipt = one approval; standalone receipt = own approval.
- Re-run `Modules/Inventory/tests` + `Modules/Purchases/tests` — no NEW failures vs baseline.

## Flags
- **[FIN]** — GR-IR journal entry + stock. **Fable consult mandatory**, specifically on: guard placement relative to `:524`, the GRN↔receipt single-approval rule, and the auto-approve precedence.
- **Migration:** none.

## Out of scope
- Delivery Note (WP4). Count / Transfer / Opening Balance (not in scope / deferred — see LEDGER).
- Do NOT alter the receipt lot/batch/serial capture logic.
