Files
aura-crm/production/backend/migrations/033_production_recipes.sql
T

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;