-- Weight-based products (e.g. fish sold per ons/kg). -- One weighing = one order_items row: quantity stays 1, the weight goes in `weight`. ALTER TABLE products ADD COLUMN sell_by VARCHAR(20) NOT NULL DEFAULT 'unit'; ALTER TABLE products ADD CONSTRAINT chk_products_sell_by CHECK (sell_by IN ('unit', 'weight')); ALTER TABLE order_items ADD COLUMN weight DECIMAL(12,3), ADD COLUMN unit_id UUID REFERENCES units(id) ON DELETE RESTRICT; -- A weighed line always carries a positive weight... ALTER TABLE order_items ADD CONSTRAINT chk_order_items_weight_positive CHECK (weight IS NULL OR weight > 0); -- ...and always represents exactly one weighing, so its quantity is pinned to 1. -- This is what makes billable quantity unambiguous and keeps void all-or-nothing. ALTER TABLE order_items ADD CONSTRAINT chk_order_items_weight_single_line CHECK (weight IS NULL OR quantity = 1); CREATE INDEX idx_order_items_unit_id ON order_items(unit_id); COMMENT ON COLUMN products.sell_by IS 'How the product is sold: unit (discrete count) or weight (weighed per transaction)'; COMMENT ON COLUMN order_items.weight IS 'Weighed amount in unit_id units; NULL for unit-priced products. Price is weight * unit_price.'; COMMENT ON COLUMN order_items.unit_id IS 'Snapshot of the product unit at sale time, so historical lines keep their meaning';