-- ============================================================ -- 14_v3_phase2_tables.sql -- Phase 2: 供应链SRM + MES + 审批流 + 消息推送 + HR + LMS + 营销 + 财务 + 扫码 + 闭环验证 + 安全 -- ============================================================ -- T-201: 供应商主数据 CREATE TABLE IF NOT EXISTS analytics.v3_supplier_master ( id SERIAL PRIMARY KEY, supplier_code TEXT NOT NULL UNIQUE, supplier_name TEXT NOT NULL, category TEXT, grade TEXT DEFAULT '合格', -- 战略/优选/合格/淘汰 contact_person TEXT, contact_phone TEXT, address TEXT, delivery_on_time_rate NUMERIC(5,2), quality_score NUMERIC(5,2), price_score NUMERIC(5,2), service_score NUMERIC(5,2), food_safety_score NUMERIC(5,2), overall_score NUMERIC(5,2), is_strategic BOOLEAN DEFAULT false, backup_supplier_code TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-203: 采购订单 CREATE TABLE IF NOT EXISTS analytics.v3_purchase_order ( id SERIAL PRIMARY KEY, po_number TEXT NOT NULL UNIQUE, supplier_code TEXT NOT NULL, store_code TEXT, order_date DATE NOT NULL, expected_delivery_date DATE, actual_delivery_date DATE, status TEXT DEFAULT 'draft', -- draft/submitted/approved/executed/delivered/settled total_amount NUMERIC(14,2), approval_status TEXT DEFAULT 'pending', created_by TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-203: 采购订单明细 CREATE TABLE IF NOT EXISTS analytics.v3_purchase_order_item ( id SERIAL PRIMARY KEY, po_id INT REFERENCES analytics.v3_purchase_order(id) ON DELETE CASCADE, sku_code TEXT NOT NULL, sku_name TEXT, quantity NUMERIC(12,2) NOT NULL, unit TEXT, unit_price NUMERIC(10,2), total_price NUMERIC(14,2), received_quantity NUMERIC(12,2) ); -- T-220: 审批申请 CREATE TABLE IF NOT EXISTS analytics.v3_approval_request ( id SERIAL PRIMARY KEY, request_type TEXT NOT NULL, -- salary_adjust/purchase/promotion/recipe/supplier_close/store_close applicant_id TEXT NOT NULL, applicant_name TEXT, store_code TEXT, status TEXT DEFAULT 'pending', -- pending/approved/rejected/cancelled current_step INT DEFAULT 1, total_steps INT, request_data JSONB, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-221: 审批步骤 CREATE TABLE IF NOT EXISTS analytics.v3_approval_step ( id SERIAL PRIMARY KEY, request_id INT REFERENCES analytics.v3_approval_request(id) ON DELETE CASCADE, step_order INT NOT NULL, approver_role TEXT NOT NULL, approver_id TEXT, approver_name TEXT, result TEXT, -- approved/rejected/pending comment TEXT, approved_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- T-222: 审批规则 CREATE TABLE IF NOT EXISTS analytics.v3_approval_rule ( id SERIAL PRIMARY KEY, request_type TEXT NOT NULL, step_order INT NOT NULL, approver_role TEXT NOT NULL, escalation_condition JSONB, escalation_role TEXT, is_enabled BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(request_type, step_order) ); -- T-241: 站内消息 CREATE TABLE IF NOT EXISTS analytics.v3_notification ( id SERIAL PRIMARY KEY, user_id TEXT, user_role TEXT, title TEXT NOT NULL, content TEXT, notification_type TEXT, -- alert/task/report/approval related_id INT, is_read BOOLEAN DEFAULT false, is_handled BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW() ); -- T-260: 培训课程 CREATE TABLE IF NOT EXISTS analytics.v3_training_course ( id SERIAL PRIMARY KEY, course_name TEXT NOT NULL, course_type TEXT, -- SOP/技能/食安/管理 content_url TEXT, exam_enabled BOOLEAN DEFAULT false, pass_score INT DEFAULT 60, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-261: 学习记录 CREATE TABLE IF NOT EXISTS analytics.v3_learning_record ( id SERIAL PRIMARY KEY, course_id INT REFERENCES analytics.v3_training_course(id) ON DELETE CASCADE, employee_name TEXT NOT NULL, store_code TEXT, progress_pct NUMERIC(5,2) DEFAULT 0, completion_status TEXT DEFAULT '未开始', -- 未开始/进行中/已完成/未通过 exam_score INT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-270: 营销活动 CREATE TABLE IF NOT EXISTS analytics.v3_marketing_campaign ( id SERIAL PRIMARY KEY, campaign_name TEXT NOT NULL, campaign_type TEXT, -- 促销/拉新/召回/品牌 start_date DATE NOT NULL, end_date DATE NOT NULL, budget NUMERIC(14,2), actual_spend NUMERIC(14,2), roi NUMERIC(8,2), target_stores TEXT, status TEXT DEFAULT 'draft', -- draft/active/completed/cancelled created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-271: 券码 CREATE TABLE IF NOT EXISTS analytics.v3_coupon ( id SERIAL PRIMARY KEY, campaign_id INT REFERENCES analytics.v3_marketing_campaign(id) ON DELETE CASCADE, coupon_code TEXT NOT NULL UNIQUE, coupon_type TEXT, -- 满减/折扣/赠品 face_value NUMERIC(10,2), min_spend NUMERIC(10,2), status TEXT DEFAULT 'unused', -- unused/used/expired/refunded issued_to TEXT, used_at TIMESTAMPTZ, expiry_date DATE, created_at TIMESTAMPTZ DEFAULT NOW() ); -- T-280: 预算管理 CREATE TABLE IF NOT EXISTS analytics.v3_budget ( id SERIAL PRIMARY KEY, year INT NOT NULL, month DATE, store_code TEXT, department TEXT, budget_type TEXT, -- revenue/expense/capex budget_amount NUMERIC(14,2), actual_amount NUMERIC(14,2), execution_rate NUMERIC(5,2), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- T-302: 审计日志 CREATE TABLE IF NOT EXISTS analytics.v3_audit_log ( id SERIAL PRIMARY KEY, user_id TEXT, user_name TEXT, user_role TEXT, action TEXT NOT NULL, -- create/update/delete/view resource_type TEXT, resource_id TEXT, details JSONB, ip_address TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- T-295: 闭环验证 CREATE TABLE IF NOT EXISTS analytics.v3_loop_verification ( id SERIAL PRIMARY KEY, loop_name TEXT NOT NULL, store_code TEXT, check_date DATE NOT NULL, status TEXT DEFAULT 'open', -- open/completed/escalated completion_rate NUMERIC(5,2), cycle_days INT, bottleneck TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 索引 CREATE INDEX IF NOT EXISTS idx_v3_supplier_grade ON analytics.v3_supplier_master(grade); CREATE INDEX IF NOT EXISTS idx_v3_po_supplier ON analytics.v3_purchase_order(supplier_code); CREATE INDEX IF NOT EXISTS idx_v3_po_status ON analytics.v3_purchase_order(status); CREATE INDEX IF NOT EXISTS idx_v3_approval_req_status ON analytics.v3_approval_request(status); CREATE INDEX IF NOT EXISTS idx_v3_approval_step_req ON analytics.v3_approval_step(request_id); CREATE INDEX IF NOT EXISTS idx_v3_notification_user ON analytics.v3_notification(user_id); CREATE INDEX IF NOT EXISTS idx_v3_notification_read ON analytics.v3_notification(is_read); CREATE INDEX IF NOT EXISTS idx_v3_training_course_type ON analytics.v3_training_course(course_type); CREATE INDEX IF NOT EXISTS idx_v3_learning_record_course ON analytics.v3_learning_record(course_id); CREATE INDEX IF NOT EXISTS idx_v3_learning_record_employee ON analytics.v3_learning_record(employee_name); CREATE INDEX IF NOT EXISTS idx_v3_campaign_status ON analytics.v3_marketing_campaign(status); CREATE INDEX IF NOT EXISTS idx_v3_coupon_code ON analytics.v3_coupon(coupon_code); CREATE INDEX IF NOT EXISTS idx_v3_budget_month ON analytics.v3_budget(year, month); CREATE INDEX IF NOT EXISTS idx_v3_audit_log_user ON analytics.v3_audit_log(user_id); CREATE INDEX IF NOT EXISTS idx_v3_audit_log_created ON analytics.v3_audit_log(created_at); CREATE INDEX IF NOT EXISTS idx_v3_loop_verification_date ON analytics.v3_loop_verification(check_date); -- 初始化默认审批规则 INSERT INTO analytics.v3_approval_rule (request_type, step_order, approver_role, escalation_condition, escalation_role) VALUES ('salary_adjust', 1, 'regional', '{"amount": 5000}', 'hq'), ('salary_adjust', 2, 'hq', NULL, NULL), ('purchase', 1, 'regional', '{"amount": 10000}', 'hq'), ('purchase', 2, 'hq', NULL, NULL), ('promotion', 1, 'regional', NULL, NULL), ('promotion', 2, 'hq', NULL, NULL), ('recipe_change', 1, 'hq', '{"cost_change_pct": 5}', 'platform_admin'), ('supplier_close', 1, 'hq', NULL, 'platform_admin'), ('store_close', 1, 'hq', '{"consecutive_loss_months": 3}', 'platform_admin') ON CONFLICT DO NOTHING;