54 lines
3.5 KiB
SQL
54 lines
3.5 KiB
SQL
-- +goose Up
|
|
|
|
-- Generic raw-part -> finished-part conversion recipes (internal/manufacture)
|
|
-- — "make your own parts from other parts". Motivating example was toner
|
|
-- (bulk raw toner -> a specific model's ready-to-use portion), but this is
|
|
-- deliberately not toner/cartridge-specific: any two parts already in the
|
|
-- warehouse catalog can be linked. cartridge_model_id is an optional hint
|
|
-- for auto-suggesting the right recipe during a cartridge refill — a
|
|
-- recipe with no cartridge link still works standalone via the manual
|
|
-- "произвести" action.
|
|
--
|
|
-- One recipe per finished part (UNIQUE below) — unambiguous for both the
|
|
-- low-stock auto-trigger (Фаза 19 next step) and "how is this thing made"
|
|
-- lookups; a raw part may feed multiple different finished goods, so no
|
|
-- uniqueness constraint on raw_part_id.
|
|
CREATE TABLE production_recipes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
raw_part_id UUID NOT NULL REFERENCES parts(id) ON DELETE RESTRICT,
|
|
finished_part_id UUID NOT NULL REFERENCES parts(id) ON DELETE RESTRICT,
|
|
-- Raw units consumed per 1 finished unit produced. NUMERIC (not INT) so
|
|
-- a future non-1:1 recipe doesn't need a schema change — today's actual
|
|
-- use case is always 1 (see wiki decision log), enforced nowhere beyond
|
|
-- the UI default because there's no reason to forbid a real 2:1/0.5:1
|
|
-- recipe once someone actually needs one.
|
|
ratio NUMERIC(10,4) NOT NULL DEFAULT 1 CHECK (ratio > 0),
|
|
cartridge_model_id UUID REFERENCES cartridge_models(id) ON DELETE SET NULL,
|
|
-- 'confirm' (default): crossing min_stock on the finished part raises a
|
|
-- notification with a one-click confirm, never converts material on its
|
|
-- own. 'auto': the conversion runs immediately, no staff action needed —
|
|
-- an owner opts a specific recipe into this once they trust it. Neither
|
|
-- mode is wired yet (next step); the column exists now so recipes don't
|
|
-- need a migration later to carry it.
|
|
trigger_mode TEXT NOT NULL DEFAULT 'confirm' CHECK (trigger_mode IN ('auto', 'confirm')),
|
|
created_by_staff_id UUID NOT NULL,
|
|
created_by_staff_name TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CHECK (raw_part_id != finished_part_id)
|
|
);
|
|
CREATE UNIQUE INDEX production_recipes_finished_part_idx ON production_recipes (finished_part_id);
|
|
CREATE INDEX production_recipes_cartridge_model_idx ON production_recipes (cartridge_model_id);
|
|
|
|
-- 'production' is the raw-material draw-down side of a "произвести"
|
|
-- action, same shape as 'sale'/'rma_out' before it. The finished-good side
|
|
-- reuses the existing 'receipt' type (it genuinely is one) rather than
|
|
-- inventing a fifth type — production_recipe_id below tags both rows of
|
|
-- one conversion so they're traceable back to each other and to the
|
|
-- recipe, regardless of which of the two types a given row is.
|
|
ALTER TABLE stock_movements DROP CONSTRAINT stock_movements_type_check;
|
|
ALTER TABLE stock_movements ADD CONSTRAINT stock_movements_type_check
|
|
CHECK (type IN ('receipt', 'consumption', 'adjustment', 'reversal', 'rma_out', 'sale', 'reservation', 'release', 'production'));
|
|
ALTER TABLE stock_movements ADD COLUMN production_recipe_id UUID REFERENCES production_recipes(id) ON DELETE SET NULL;
|
|
CREATE INDEX stock_movements_production_recipe_id_idx ON stock_movements (production_recipe_id) WHERE production_recipe_id IS NOT NULL;
|