# `PhoenixKitWarehouse.GoodsReceipts`
[🔗](https://github.com/BeamLabEU/phoenix_kit_warehouse/blob/0.4.0/lib/phoenix_kit_warehouse/goods_receipts.ex#L1)

Context for managing goods receipts (goods arrival onto the warehouse).

A goods receipt registers the arrival of goods from a supplier order and
INCREASES warehouse stock when posted. There is NO repost — posting a goods
receipt is an additive delta operation. Correction after posting is limited
to note and storage_folder only.

## unit_value

Each receipt line may carry a `"unit_value"` field (string, number, or
Decimal). When present and non-nil, posting the receipt writes that value
into `phoenix_kit_warehouse_stock.unit_value` for the corresponding item/
location via `StockLedger.receive_quantity/3`. The last posted receipt wins
— earlier values are overwritten. When `"unit_value"` is absent or `nil` the
existing stock unit_value is left untouched.

# `add_source_ref`

Manually attaches a traceability reference to a goods receipt.

`"internal_order"` and `"supplier_order"` are always valid (intra-module).
Any other `type` must be a kind registered via `PhoenixKitWarehouse.SourceKinds`.
Pure metadata — does not touch `lines` and is not gated to draft status.
A duplicate `{type, uuid}` pair is a no-op.

# `correct_goods_receipt`

Corrects the note and/or storage_folder_uuid of a goods receipt without
changing status or lines. Works on documents in any status.
Lines are immutable once posted.

# `create_from_supplier_order`

Creates a draft goods receipt from a posted supplier order.

Lines are copied from the supplier order with:
- `ordered_quantity` = the supplier order's ordered_quantity (snapshot)
- `received_quantity` = 0 (default; keeper edits actual received)

Sets supplier_order_uuid, supplier_uuid, and location_uuid from the source order.

# `create_goods_receipt`

Creates a new draft goods receipt.

`location_uuid` defaults to the configured default warehouse when not given.
`created_by_uuid` is set programmatically — not via cast.

# `get_goods_receipt`

Returns `{:ok, receipt}` or `{:error, :not_found}`.

# `get_goods_receipt!`

Returns the goods receipt or raises.

# `import_from_supplier_orders`

Imports lines from a list of posted supplier orders into an existing draft
goods receipt.

Lines are merged by item_uuid (ordered_quantity summed across all SOs).
supplier_uuid and supplier_order_uuid are taken from the first selected SO
(primary SO). source_refs are enriched with the full traceability chain —
each selected supplier order, the internal order(s) that fed it, and the
customer order(s)/sub-order(s) that fed those — and saved via update_draft.

Returns `{:ok, updated_receipt}` or `{:error, reason}`.

# `list_goods_receipts`

Lists non-deleted goods receipts ordered by number descending (newest first).

# `post_goods_receipt`

Posts a goods receipt in an `Ecto.Multi` transaction. INCREASES warehouse stock.

- Locks the row FOR UPDATE and re-checks status == "draft" (prevents double-posting).
- Deduplicates lines by item_uuid.
- For each line with received_quantity > 0:
  - Captures `previous_quantity` = current on-hand for audit.
  - Calls `StockLedger.receive_quantity/3` (additive stock delta).
- Lines with received_quantity == 0 contribute no stock change.
- Merges `previous_quantity` into the persisted lines (audit trail).
- Flips status → "posted", sets posted_at and performed_by_uuid.

Returns `{:error, :not_draft}` for non-draft receipts.

# `remove_source_ref`

Detaches a traceability reference from a goods receipt. No-op when the
`{type, uuid}` pair isn't present.

# `set_storage_folder`

Sets the `storage_folder_uuid` on a goods receipt.
Works on documents in any status.

# `soft_delete`

Soft-deletes a draft goods receipt. Returns {:error, :not_draft} for posted documents.

# `update_draft`

Updates a draft goods receipt. Returns `{:error, :not_draft}` when not in
draft status.

Locks the row FOR UPDATE and re-checks status == "draft" in the DB (not
just the in-memory struct) so a stale tab cannot overwrite a receipt that
was posted concurrently by another tab/user.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
