PhoenixKitWarehouse.InternalOrders (PhoenixKitWarehouse v0.1.0)

Copy Markdown View Source

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

add_source_ref(order, type, uuid)

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.

correct_internal_order(order, attrs)

Corrects the note of an internal order without changing status. Works on documents in any status.

create(lines, source_ref, opts \\ [])

@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 to StockLedger.default_location_uuid/0.

create_internal_order(attrs)

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.

get_internal_order(uuid)

Returns {:ok, order} or {:error, :not_found}.

get_internal_order!(uuid)

Returns the internal order or raises.

import_from_sources(order, selected_refs, actor_uuid)

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.

list_import_candidates(query \\ nil)

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).

list_internal_orders(opts \\ [])

Lists non-deleted internal orders ordered by number descending (newest first).

list_posted_internal_orders()

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.

post_internal_order(order, performed_by_uuid)

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.

remove_source_ref(order, type, uuid)

Detaches a traceability reference from an internal order. No-op when the {type, uuid} pair isn't present.

soft_delete_internal_order(order, actor_uuid)

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

update_draft(internal_order, attrs)

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.