Context for managing supplier orders (purchase orders to a single supplier).
Supplier orders are generated (semi-automatically) from posted internal orders. Posting has NO stock effect — goods receipt will do that.
Summary
Functions
Manually attaches a traceability reference (type "internal_order") to a
supplier order.
Corrects the note and/or storage_folder_uuid of a supplier order without changing status or lines. Works on documents in any status.
Creates a new draft supplier order.
Generates draft supplier orders from a posted internal order.
Returns {:ok, order} or {:error, :not_found}.
Returns the supplier order or raises.
Imports lines from one or more posted internal orders into an existing draft
supplier order, filtering to items whose resolved supplier matches
supplier_order.supplier_uuid.
Lists posted (non-deleted) internal orders for use as source-picker candidates when importing into a supplier order.
Lists non-deleted POSTED supplier orders ordered by number descending.
Lists non-deleted supplier orders ordered by number descending (newest first).
Lists all suppliers from the catalogue.
Returns a list of supplier structs with at least :uuid and :name fields.
Posts a supplier order in an Ecto.Multi transaction.
Returns %{supplier_order_uuid => %{item_uuid => Decimal}} — for each uuid in
supplier_order_uuids, the received_quantity already recorded against it,
summed across all POSTED, non-deleted goods receipts referencing it — either
as the primary supplier_order_uuid FK, or as a secondary "supplier_order"
source_refs entry.
Returns %{item_uuid => Decimal} summing received_quantity already recorded
against supplier_order across all POSTED, non-deleted goods receipts
referencing it — either as the primary supplier_order_uuid FK, or as a
secondary "supplier_order" source_refs entry.
Detaches a traceability reference from a supplier order. No-op when the
{type, uuid} pair isn't present.
Sets the storage_folder_uuid on a supplier order.
Works on documents in any status.
Soft-deletes a draft supplier order. Returns {:error, :not_draft} for posted documents.
Updates a draft supplier order. Returns {:error, :not_draft} when not in
draft status.
Functions
Manually attaches a traceability reference (type "internal_order") to a
supplier order.
Pure metadata — does not touch lines and is not gated to draft status.
A duplicate {type, uuid} pair is a no-op.
Corrects the note and/or storage_folder_uuid of a supplier order without changing status or lines. Works on documents in any status.
Creates a new draft supplier order.
location_uuid defaults to the configured default warehouse when not given.
created_by_uuid is set programmatically — not via cast.
Generates draft supplier orders from a posted internal order.
All-or-nothing inside a single Ecto.Multi transaction:
Computes net shortfall per line: shortfall = max(0, required − on_hand) Lines with shortfall == 0 are dropped (fully stocked).
Resolves supplier per material via the item's manufacturer:
- Exactly 1 linked supplier → line is assigned to that supplier.
- 0 OR >1 linked suppliers → line goes to the "unassigned" bucket (never auto-picked from multiple suppliers).
Groups assigned lines by supplier_uuid → creates ONE DRAFT per supplier. Line shape carries: on_hand_quantity, shortfall_quantity, ordered_quantity (= shortfall, keeper edits later), base_price (catalogue base price), required_quantity.
Returns {:ok, %{supplier_orders: [...drafts...], unassigned_lines: [...]}}.
Drafts are NOT posted.
Returns {:ok, order} or {:error, :not_found}.
Returns the supplier order or raises.
Imports lines from one or more posted internal orders into an existing draft
supplier order, filtering to items whose resolved supplier matches
supplier_order.supplier_uuid.
Steps:
- Loads each selected IO (must be posted and non-deleted).
- Enriches lines using the same stock + catalogue helpers as
generate_from_internal_order/2. - Filters to items whose single resolved supplier == supplier_order.supplier_uuid.
- Merges new lines with existing ones by item_uuid, summing required/shortfall/ordered quantities.
- Appends
source_refsentries of type"internal_order"for each IO. - Sets
internal_order_uuidto the first selected IO (primary back-compat). - Saves via
update_draft/2.
Returns:
{:ok, updated_order}on success.{:error, :no_supplier}whensupplier_order.supplier_uuidis nil.{:error, :not_draft}when the order is not a draft.{:error, reason}on DB failure.
Lists posted (non-deleted) internal orders for use as source-picker candidates when importing into a supplier order.
Returns a list of %InternalOrder{} ordered by number descending.
Lists non-deleted POSTED supplier orders ordered by number descending.
Used as candidates for importing lines into a goods receipt.
Lists non-deleted supplier orders ordered by number descending (newest first).
Lists all suppliers from the catalogue.
Returns a list of supplier structs with at least :uuid and :name fields.
Posts a supplier order in an Ecto.Multi transaction.
- Locks the row FOR UPDATE and re-checks status == "draft" (prevents double-posting of the same draft).
- Deduplicates lines by item_uuid.
- Flips status → "posted", sets posted_at and performed_by_uuid.
- Does NOT write any stock rows.
Returns {:error, :not_draft} for non-draft orders.
Returns %{supplier_order_uuid => %{item_uuid => Decimal}} — for each uuid in
supplier_order_uuids, the received_quantity already recorded against it,
summed across all POSTED, non-deleted goods receipts referencing it — either
as the primary supplier_order_uuid FK, or as a secondary "supplier_order"
source_refs entry.
Returns %{item_uuid => Decimal} summing received_quantity already recorded
against supplier_order across all POSTED, non-deleted goods receipts
referencing it — either as the primary supplier_order_uuid FK, or as a
secondary "supplier_order" source_refs entry.
Detaches a traceability reference from a supplier order. No-op when the
{type, uuid} pair isn't present.
Sets the storage_folder_uuid on a supplier order.
Works on documents in any status.
Soft-deletes a draft supplier order. Returns {:error, :not_draft} for posted documents.
Updates a draft supplier order. 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 an order that was posted concurrently by another tab/user.