47 lines
2.8 KiB
SQL
47 lines
2.8 KiB
SQL
-- +goose Up
|
|
|
|
-- A purchase order to a supplier — deliberately thin lifecycle (draft ->
|
|
-- ordered -> partially_received/received, or cancelled from draft/ordered/
|
|
-- partially_received). Line items are fixed once the PO leaves draft (no
|
|
-- partial line edits after that — cancel and recreate for a real mistake);
|
|
-- draft itself is fully replaceable (see internal/purchaseorder.Update).
|
|
CREATE TABLE purchase_orders (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
supplier_id UUID NOT NULL REFERENCES suppliers(id) ON DELETE RESTRICT,
|
|
status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN
|
|
('draft', 'ordered', 'partially_received', 'received', 'cancelled')),
|
|
note TEXT,
|
|
created_by_staff_id UUID NOT NULL,
|
|
created_by_staff_name TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX purchase_orders_supplier_id_idx ON purchase_orders (supplier_id);
|
|
CREATE INDEX purchase_orders_status_idx ON purchase_orders (status);
|
|
|
|
-- qty_received is a running total updated transactionally by each GRN
|
|
-- receive (internal/purchaseorder.Receive) — not derived from stock_batches
|
|
-- on read, since a PO line's fulfillment needs to be checked/updated
|
|
-- atomically against concurrent receives on other lines of the same PO.
|
|
-- No CHECK tying qty_received to qty_ordered — a supplier over-shipping a
|
|
-- line is a real occurrence this shouldn't hard-block.
|
|
CREATE TABLE purchase_order_items (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
purchase_order_id UUID NOT NULL REFERENCES purchase_orders(id) ON DELETE CASCADE,
|
|
part_id UUID NOT NULL REFERENCES parts(id) ON DELETE RESTRICT,
|
|
qty_ordered INT NOT NULL CHECK (qty_ordered > 0),
|
|
qty_received INT NOT NULL DEFAULT 0 CHECK (qty_received >= 0),
|
|
unit_price NUMERIC(10, 2) NOT NULL CHECK (unit_price >= 0)
|
|
);
|
|
CREATE INDEX purchase_order_items_po_id_idx ON purchase_order_items (purchase_order_id);
|
|
|
|
-- GRN linkage — receiving against a PO reuses internal/inventory's existing
|
|
-- ReceiveBatch (the same stock_batches/stock_serials/stock_movements
|
|
-- machinery a manual receipt uses), just additionally tagged with which
|
|
-- PO/line it fulfills. A GRN is not a separate table: the set of
|
|
-- stock_batches rows carrying a given purchase_order_id *is* its goods
|
|
-- receipt history.
|
|
ALTER TABLE stock_batches ADD COLUMN purchase_order_id UUID REFERENCES purchase_orders(id) ON DELETE SET NULL;
|
|
ALTER TABLE stock_batches ADD COLUMN purchase_order_item_id UUID REFERENCES purchase_order_items(id) ON DELETE SET NULL;
|
|
CREATE INDEX stock_batches_purchase_order_id_idx ON stock_batches (purchase_order_id) WHERE purchase_order_id IS NOT NULL;
|