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

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.

# `default_location_uuid`

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

# `get_quantity`

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

# `get_quantity`

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`

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:
- `: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, 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`

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`

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

# `set_warehouse_location_type_uuid`

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

# `stock_for_items`

Returns stock rows for the given list of item UUIDs.

# `stock_for_items_at_location`

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`

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`

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

# `to_decimal_or_nil`

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`

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.

---

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