PhoenixKitWarehouse.StockLedger (PhoenixKitWarehouse v0.2.2)

Copy Markdown View Source

Context for managing warehouse stock balances.

Provides functions to read stock levels and upsert quantities. Decimal coercion helpers ensure callers passing jsonb-origin strings or floats are handled safely.

Summary

Functions

UUID of the default warehouse Location stock is held at (setting), or nil.

Returns the current quantity for the given item UUID as a Decimal. Returns Decimal.new("0") if no row exists.

Returns the current quantity for the given item UUID at the given location_uuid, as a Decimal. Returns Decimal.new("0") if no row exists.

Conditionally decrements warehouse stock for item_uuid.

Returns all stock rows.

Lists all Locations tagged with the configured warehouse LocationType.

Additively increases the stock quantity for item_uuid.

Sets the default warehouse Location UUID. Pass nil to clear.

Sets the LocationType UUID that marks warehouses. Pass nil to clear.

Returns stock rows for the given list of item UUIDs.

Returns stock rows for the given list of item UUIDs, scoped to a single warehouse location_uuid. Unlike stock_map_for_location/1, this returns the raw %Stock{} rows (unmapped) — used for audit snapshots when posting.

Returns a map of item_uuid => %{quantity: Decimal, unit_value: Decimal | nil}, aggregated across every warehouse location, for fast tree annotation.

Returns a map of item_uuid => %{quantity: Decimal, unit_value: Decimal | nil} scoped to a single warehouse location_uuid — the exact, non-aggregated counterpart of stock_map/0. At most one row per item_uuid is possible here, since {item_uuid, location_uuid} is unique.

Coerces a value to Decimal. nil and "" become Decimal.new("0").

Coerces a value to Decimal or nil. nil, blank strings, and empty strings return nil. All other values convert like to_decimal/1.

Returns the total stock value: Σ (quantity * unit_value), skipping rows where unit_value is nil.

Upserts the stock quantity for item_uuid.

UUID of the LocationType that marks warehouses (admin-configurable setting), or nil.

Functions

default_location_uuid()

UUID of the default warehouse Location stock is held at (setting), or nil.

get_quantity(item_uuid)

Returns the current quantity for the given item UUID as a Decimal. Returns Decimal.new("0") if no row exists.

get_quantity(item_uuid, location_uuid)

Returns the current quantity for the given item UUID at the given location_uuid, as a Decimal. Returns Decimal.new("0") if no row exists.

Unlike get_quantity/1 — which looks up by item_uuid alone and, once an item has Stock rows at more than one location, returns an unpredictable row — this filters by both columns. Use this (not get_quantity/1) for new warehouse operations that are location-aware (transfers).

issue_quantity(item_uuid, quantity, opts \\ [])

Conditionally decrements warehouse stock for item_uuid.

Performs an atomic UPDATE with WHERE quantity >= qty to guard against driving stock negative. Never inserts a row — if no stock row exists for the item/location, the WHERE predicate matches 0 rows and the function returns {:error, {:insufficient_stock, item_uuid}}.

Options:

Returns:

  • {:ok, new_quantity} on success (Decimal).
  • {:error, {:insufficient_stock, item_uuid}} when stock row is missing OR when quantity < qty (covers both cases atomically via the WHERE guard).

list_stock()

Returns all stock rows.

list_warehouses()

Lists all Locations tagged with the configured warehouse LocationType.

Returns nil when warehouse_location_type_uuid/0 is not configured (distinct from an empty list, which means the type is configured but no Locations are tagged with it yet).

receive_quantity(item_uuid, quantity, opts \\ [])

Additively increases the stock quantity for item_uuid.

Unlike upsert_quantity/3 which does an absolute SET, this function performs an additive INSERT … ON CONFLICT DO UPDATE SET quantity = quantity + EXCLUDED.quantity.

Options:

  • :unit_value — when not nil, also sets the unit_value; when nil, leaves existing value intact.
  • :repo — override the repo (default from PhoenixKit.RepoHelper.repo/0), used by Ecto.Multi transactions.
  • :location_uuid — warehouse location (default: configured default warehouse).

Returns {:ok, %Stock{}}.

set_default_location_uuid(uuid)

Sets the default warehouse Location UUID. Pass nil to clear.

set_warehouse_location_type_uuid(uuid)

Sets the LocationType UUID that marks warehouses. Pass nil to clear.

stock_for_items(item_uuids, target_repo \\ nil)

Returns stock rows for the given list of item UUIDs.

stock_for_items_at_location(item_uuids, location_uuid, target_repo \\ nil)

Returns stock rows for the given list of item UUIDs, scoped to a single warehouse location_uuid. Unlike stock_map_for_location/1, this returns the raw %Stock{} rows (unmapped) — used for audit snapshots when posting.

stock_map()

Returns a map of item_uuid => %{quantity: Decimal, unit_value: Decimal | nil}, aggregated across every warehouse location, for fast tree annotation.

Two things to know about the aggregation:

  • quantity is a cross-warehouse sum: the total quantity on hand for the item across every location_uuid it has a Stock row at.
  • unit_value is only an approximation: it is taken from whichever location's row was updated_at most recently among rows where it is not nil (or nil if none has one set). It is NOT necessarily the value at any particular warehouse. For the exact per-warehouse value, use stock_map_for_location/1 instead.

stock_map_for_location(location_uuid)

Returns a map of item_uuid => %{quantity: Decimal, unit_value: Decimal | nil} scoped to a single warehouse location_uuid — the exact, non-aggregated counterpart of stock_map/0. At most one row per item_uuid is possible here, since {item_uuid, location_uuid} is unique.

to_decimal(v)

Coerces a value to Decimal. nil and "" become Decimal.new("0").

to_decimal_or_nil(s)

Coerces a value to Decimal or nil. nil, blank strings, and empty strings return nil. All other values convert like to_decimal/1.

total_value()

Returns the total stock value: Σ (quantity * unit_value), skipping rows where unit_value is nil.

upsert_quantity(item_uuid, quantity, opts \\ [])

Upserts the stock quantity for item_uuid.

Options:

  • :unit_value — when not nil, also sets the unit_value; when nil, leaves existing value intact.
  • :repo — override the repo (default from PhoenixKit.RepoHelper.repo/0), used by Ecto.Multi transactions.

Returns {:ok, %Stock{}}.

warehouse_location_type_uuid()

UUID of the LocationType that marks warehouses (admin-configurable setting), or nil.