Context for managing internal orders (warehouse demand documents).
Internal orders bridge sub-order material sheets and supplier orders. They do NOT affect stock — posting only flips status and sets timestamps.
Summary
Functions
Manually attaches a traceability reference to an internal order.
Corrects the note of an internal order without changing status. Works on documents in any status.
Generic entry point for creating a draft internal order from arbitrary
lines plus a single (optional) source ref — no domain knowledge of
"material sheets" or any other host concept required. A host app (e.g.
Andi's sub-order Show page, per the design doc's "one piece of business
logic that stays in Andi") builds its own lines from whatever concept
it has, builds a %{"type" => kind, "uuid" => uuid} source ref itself,
and calls this function — replacing the removed create_from_material_sheet/3.
Creates a new draft internal order.
Returns {:ok, order} or {:error, :not_found}.
Returns the internal order or raises.
Imports material lines from a list of source refs into an internal order.
Returns import candidates from every registered PhoenixKitWarehouse.SourceKinds
kind, merged, as %{kind:, label_prefix:, uuid:, label:, extra:} maps
(the exact shape SourceKinds.search_candidates/1 returns). Returns []
when no source_kinds are configured — this is what makes the module
usable standalone, with no host "order" concept at all.
Lists non-deleted internal orders ordered by number descending (newest first).
Lists non-deleted posted internal orders ordered by number descending. Used for goods issue source picker — filters in SQL so only relevant rows are loaded.
Posts an internal order in an Ecto.Multi transaction.
Detaches a traceability reference from an internal order. No-op when the
{type, uuid} pair isn't present.
Soft-deletes a draft internal order. Returns {:error, :not_draft} for posted documents.
Updates a draft internal order. Returns {:error, :not_draft} when not in
draft status.
Functions
Manually attaches a traceability reference to an internal order.
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.
Corrects the note of an internal order without changing status. Works on documents in any status.
@spec create([map()], map() | nil, keyword()) :: {:ok, PhoenixKitWarehouse.InternalOrder.t()} | {:error, Ecto.Changeset.t()}
Generic entry point for creating a draft internal order from arbitrary
lines plus a single (optional) source ref — no domain knowledge of
"material sheets" or any other host concept required. A host app (e.g.
Andi's sub-order Show page, per the design doc's "one piece of business
logic that stays in Andi") builds its own lines from whatever concept
it has, builds a %{"type" => kind, "uuid" => uuid} source ref itself,
and calls this function — replacing the removed create_from_material_sheet/3.
opts:
:created_by_uuid— set programmatically, not via cast.:location_uuid— defaults toStockLedger.default_location_uuid/0.
Creates a new draft internal order.
location_uuid defaults to the configured default warehouse when not given.
created_by_uuid is set programmatically — not via cast.
Returns {:ok, order} or {:error, :not_found}.
Returns the internal order or raises.
Imports material lines from a list of source refs into an internal order.
selected_refs is a list of %{"type" => "order" | "sub_order", "uuid" => uuid}.
For each source, builds lines via the registered SourceKinds.build_lines/3
callback. Lines are merged into the order's current lines, summing
required_quantity by item_uuid. New source refs are appended to source_refs
(deduped). Saves via update_draft. Returns {:ok, order} or {:error, reason}.
Draft-only.
Returns import candidates from every registered PhoenixKitWarehouse.SourceKinds
kind, merged, as %{kind:, label_prefix:, uuid:, label:, extra:} maps
(the exact shape SourceKinds.search_candidates/1 returns). Returns []
when no source_kinds are configured — this is what makes the module
usable standalone, with no host "order" concept at all.
query (optional) is forwarded to every registered kind's own search
callback — filtering is each kind's own responsibility, not this
function's, since only the host knows how to match against its own data
(order number, client name, etc).
Lists non-deleted internal orders ordered by number descending (newest first).
Lists non-deleted posted internal orders ordered by number descending. Used for goods issue source picker — filters in SQL so only relevant rows are loaded.
Posts an internal 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.
Detaches a traceability reference from an internal order. No-op when the
{type, uuid} pair isn't present.
Soft-deletes a draft internal order. Returns {:error, :not_draft} for posted documents.
Updates a draft internal 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.