CREATE TYPE freight_pricing_method AS ENUM ('by_piece', 'by_weight'); CREATE TABLE freight_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), shop_id UUID NOT NULL REFERENCES shops (id) ON DELETE CASCADE, name TEXT NOT NULL, is_default BOOLEAN NOT NULL DEFAULT false, always_free BOOLEAN NOT NULL DEFAULT false, pricing_method freight_pricing_method NOT NULL DEFAULT 'by_piece', first_fee_minor BIGINT NOT NULL DEFAULT 0 CHECK (first_fee_minor >= 0), first_unit INT NOT NULL DEFAULT 1 CHECK (first_unit > 0), additional_fee_minor BIGINT NOT NULL DEFAULT 0 CHECK (additional_fee_minor >= 0), additional_unit INT NOT NULL DEFAULT 1 CHECK (additional_unit > 0), free_threshold_minor BIGINT CHECK (free_threshold_minor > 0), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- At most one default template per shop. CREATE UNIQUE INDEX freight_templates_one_default ON freight_templates (shop_id) WHERE is_default; CREATE INDEX idx_freight_templates_shop ON freight_templates (shop_id); CREATE TABLE freight_region_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), template_id UUID NOT NULL REFERENCES freight_templates (id) ON DELETE CASCADE, regions TEXT[] NOT NULL, first_fee_minor BIGINT NOT NULL CHECK (first_fee_minor >= 0), first_unit INT NOT NULL CHECK (first_unit > 0), additional_fee_minor BIGINT NOT NULL CHECK (additional_fee_minor >= 0), additional_unit INT NOT NULL CHECK (additional_unit > 0) ); CREATE INDEX idx_freight_region_rules_template ON freight_region_rules (template_id); CREATE TABLE shipping_companies ( code TEXT PRIMARY KEY, name JSONB NOT NULL, active BOOLEAN NOT NULL DEFAULT true ); INSERT INTO shipping_companies (code, name) VALUES ('sf-express', '{"en": "SF Express", "zh": "顺丰速运"}'), ('zto', '{"en": "ZTO Express", "zh": "中通快递"}'), ('yto', '{"en": "YTO Express", "zh": "圆通速递"}'), ('ems', '{"en": "EMS", "zh": "中国邮政 EMS"}'), ('ups', '{"en": "UPS", "zh": "联合包裹"}'), ('fedex', '{"en": "FedEx", "zh": "联邦快递"}'); ALTER TABLE products ADD COLUMN freight_template_id UUID REFERENCES freight_templates (id) ON DELETE SET NULL; ALTER TABLE skus ADD COLUMN weight_grams INT CHECK (weight_grams > 0); ALTER TABLE orders ADD COLUMN shipping_fee_minor BIGINT NOT NULL DEFAULT 0 CHECK (shipping_fee_minor >= 0); -- Checkout snapshots so later template edits never touch history. ALTER TABLE order_items ADD COLUMN freight_template_id UUID, ADD COLUMN freight_pricing_method freight_pricing_method; ALTER TABLE shipments ADD COLUMN shipping_company_code TEXT REFERENCES shipping_companies (code);