-- ============================================================ -- 润滑油行业 B2B ERP/CRM 综合系统 - PostgreSQL 数据库建模 -- 技术栈: Python (FastAPI) + PostgreSQL -- 生成时间: 2026-02-27 -- ============================================================ -- 启用 uuid-ossp 扩展(用于 UUID 主键生成) CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- ============================================================ -- 通用函数:自动更新 updated_at 触发器 -- ============================================================ CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; -- ************************************************************ -- 1. RBAC 权限域 -- ************************************************************ -- ============================================================ -- 1.1 部门树表 sys_departments -- ============================================================ CREATE TABLE sys_departments ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), parent_id UUID REFERENCES sys_departments(id), name VARCHAR(100) NOT NULL, sort_order INT DEFAULT 0, status SMALLINT DEFAULT 1, -- 1:启用 0:停用 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE sys_departments IS '部门树表'; COMMENT ON COLUMN sys_departments.id IS '部门主键 UUID'; COMMENT ON COLUMN sys_departments.parent_id IS '父级部门ID,NULL表示顶级'; COMMENT ON COLUMN sys_departments.name IS '部门名称'; COMMENT ON COLUMN sys_departments.sort_order IS '排序序号'; COMMENT ON COLUMN sys_departments.status IS '状态 1:启用 0:停用'; CREATE INDEX idx_dept_parent ON sys_departments(parent_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_dept_updated BEFORE UPDATE ON sys_departments FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 1.2 角色表 sys_roles -- ============================================================ CREATE TABLE sys_roles ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), role_name VARCHAR(50) NOT NULL UNIQUE, data_scope VARCHAR(20) NOT NULL DEFAULT 'self', -- all / dept_and_sub / self menu_keys JSONB DEFAULT '[]'::JSONB, -- 菜单与按钮权限键集合 description VARCHAR(255), status SMALLINT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE sys_roles IS '角色表'; COMMENT ON COLUMN sys_roles.id IS '角色主键 UUID'; COMMENT ON COLUMN sys_roles.role_name IS '角色名称'; COMMENT ON COLUMN sys_roles.data_scope IS '数据权限范围: all=全部 / dept_and_sub=本部门及下属 / self=仅本人'; COMMENT ON COLUMN sys_roles.menu_keys IS '拥有的菜单/按钮权限键列表 (JSONB数组)'; CREATE TRIGGER trg_role_updated BEFORE UPDATE ON sys_roles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 1.3 员工/账号表 sys_users -- ============================================================ CREATE TABLE sys_users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), dept_id UUID REFERENCES sys_departments(id), role_id UUID REFERENCES sys_roles(id), username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, real_name VARCHAR(50), phone VARCHAR(20), email VARCHAR(100), avatar_url VARCHAR(500), status SMALLINT DEFAULT 1, -- 1:在职 0:离职 last_login_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE sys_users IS '员工/账号表'; COMMENT ON COLUMN sys_users.id IS '用户主键 UUID'; COMMENT ON COLUMN sys_users.dept_id IS '所属部门ID'; COMMENT ON COLUMN sys_users.role_id IS '所属角色ID'; COMMENT ON COLUMN sys_users.username IS '登录账号'; COMMENT ON COLUMN sys_users.password_hash IS '密码哈希值'; COMMENT ON COLUMN sys_users.real_name IS '真实姓名'; COMMENT ON COLUMN sys_users.status IS '状态 1:在职 0:离职'; CREATE INDEX idx_user_dept ON sys_users(dept_id) WHERE is_deleted = FALSE; CREATE INDEX idx_user_role ON sys_users(role_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_user_updated BEFORE UPDATE ON sys_users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ************************************************************ -- 2. CRM 客户域 -- ************************************************************ -- ============================================================ -- 2.1 客户主表 crm_customers -- ============================================================ CREATE TABLE crm_customers ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(200) NOT NULL, level CHAR(1) DEFAULT 'C', -- A / B / C 三级 industry VARCHAR(100), contact VARCHAR(50), -- 联系人姓名 phone VARCHAR(30), email VARCHAR(100), address TEXT, ai_score NUMERIC(5,2) DEFAULT 0, -- AI 客情健康度评分 0~100 owner_id UUID REFERENCES sys_users(id), -- 负责销售 status SMALLINT DEFAULT 1, -- 1:活跃 0:冻结 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE crm_customers IS '客户主表'; COMMENT ON COLUMN crm_customers.id IS '客户主键 UUID'; COMMENT ON COLUMN crm_customers.name IS '客户/公司名称'; COMMENT ON COLUMN crm_customers.level IS '客户等级 A/B/C'; COMMENT ON COLUMN crm_customers.ai_score IS 'AI客情健康度评分 0~100'; COMMENT ON COLUMN crm_customers.owner_id IS '负责销售ID'; CREATE INDEX idx_cust_level ON crm_customers(level) WHERE is_deleted = FALSE; CREATE INDEX idx_cust_owner ON crm_customers(owner_id) WHERE is_deleted = FALSE; CREATE INDEX idx_cust_name ON crm_customers(name) WHERE is_deleted = FALSE; CREATE TRIGGER trg_cust_updated BEFORE UPDATE ON crm_customers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 2.2 客户跟进日志表 crm_follow_up_logs -- ============================================================ CREATE TABLE crm_follow_up_logs ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), customer_id UUID NOT NULL REFERENCES crm_customers(id), salesperson_id UUID NOT NULL REFERENCES sys_users(id), content TEXT NOT NULL, emotion_type VARCHAR(20), -- positive / neutral / negative next_visit_time TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE crm_follow_up_logs IS '客户跟进日志表(AI简报数据源)'; COMMENT ON COLUMN crm_follow_up_logs.customer_id IS '关联客户ID'; COMMENT ON COLUMN crm_follow_up_logs.salesperson_id IS '操作销售人员ID'; COMMENT ON COLUMN crm_follow_up_logs.content IS '跟进内容'; COMMENT ON COLUMN crm_follow_up_logs.emotion_type IS '情感标记: positive/neutral/negative'; COMMENT ON COLUMN crm_follow_up_logs.next_visit_time IS '计划下次拜访时间'; CREATE INDEX idx_follow_cust ON crm_follow_up_logs(customer_id) WHERE is_deleted = FALSE; CREATE INDEX idx_follow_sales ON crm_follow_up_logs(salesperson_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_follow_updated BEFORE UPDATE ON crm_follow_up_logs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ************************************************************ -- 3. ERP 供应链域 -- ************************************************************ -- ============================================================ -- 3.1 产品分类树 erp_product_categories -- ============================================================ CREATE TABLE erp_product_categories ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), parent_id UUID REFERENCES erp_product_categories(id), name VARCHAR(100) NOT NULL, sort_order INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_product_categories IS '产品分类树表(左树结构支撑)'; COMMENT ON COLUMN erp_product_categories.parent_id IS '父级分类ID,NULL为顶级分类'; CREATE INDEX idx_pcat_parent ON erp_product_categories(parent_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_pcat_updated BEFORE UPDATE ON erp_product_categories FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 3.2 产品 SKU 表 erp_product_skus -- ============================================================ CREATE TABLE erp_product_skus ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), category_id UUID REFERENCES erp_product_categories(id), sku_code VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(200) NOT NULL, spec VARCHAR(100), -- 规格,如 200L/桶 standard_price NUMERIC(12,2) NOT NULL DEFAULT 0, stock_qty NUMERIC(12,2) NOT NULL DEFAULT 0, warning_threshold NUMERIC(12,2) DEFAULT 0, -- 库存预警阈值 unit VARCHAR(20) DEFAULT '桶', status SMALLINT DEFAULT 1, -- 1:在售 0:停售 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_product_skus IS '产品SKU主档表'; COMMENT ON COLUMN erp_product_skus.sku_code IS 'SKU编号,全局唯一'; COMMENT ON COLUMN erp_product_skus.spec IS '包装规格,如 200L/桶、18L/桶'; COMMENT ON COLUMN erp_product_skus.standard_price IS '标准售价'; COMMENT ON COLUMN erp_product_skus.stock_qty IS '当前库存数量'; COMMENT ON COLUMN erp_product_skus.warning_threshold IS '库存预警阈值,低于此值触发预警'; CREATE INDEX idx_sku_category ON erp_product_skus(category_id) WHERE is_deleted = FALSE; CREATE INDEX idx_sku_code ON erp_product_skus(sku_code) WHERE is_deleted = FALSE; CREATE TRIGGER trg_sku_updated BEFORE UPDATE ON erp_product_skus FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 3.3 出入库流水表 erp_inventory_flows -- ============================================================ CREATE TABLE erp_inventory_flows ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), sku_id UUID NOT NULL REFERENCES erp_product_skus(id), change_qty NUMERIC(12,2) NOT NULL, -- 正数=入库,负数=出库 reason VARCHAR(50) NOT NULL, -- purchase/shipment/loss/adjust remark TEXT, operator_id UUID REFERENCES sys_users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_inventory_flows IS '出入库流水账表'; COMMENT ON COLUMN erp_inventory_flows.sku_id IS '关联SKU ID'; COMMENT ON COLUMN erp_inventory_flows.change_qty IS '变动数量:正=入库 负=出库'; COMMENT ON COLUMN erp_inventory_flows.reason IS '变动原因: purchase/shipment/loss/adjust'; COMMENT ON COLUMN erp_inventory_flows.operator_id IS '操作人ID'; CREATE INDEX idx_invflow_sku ON erp_inventory_flows(sku_id) WHERE is_deleted = FALSE; CREATE INDEX idx_invflow_operator ON erp_inventory_flows(operator_id) WHERE is_deleted = FALSE; CREATE INDEX idx_invflow_time ON erp_inventory_flows(created_at) WHERE is_deleted = FALSE; CREATE TRIGGER trg_invflow_updated BEFORE UPDATE ON erp_inventory_flows FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ************************************************************ -- 4. ERP 交易域 -- ************************************************************ -- ============================================================ -- 4.1 订单主表 erp_orders -- ============================================================ CREATE TABLE erp_orders ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), order_no VARCHAR(30) NOT NULL UNIQUE, -- 业务单号,如 ORD-20260227-001 customer_id UUID NOT NULL REFERENCES crm_customers(id), salesperson_id UUID REFERENCES sys_users(id), total_amount NUMERIC(14,2) NOT NULL DEFAULT 0, shipping_state VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending / partial / shipped payment_state VARCHAR(20) NOT NULL DEFAULT 'unpaid', -- unpaid / partial / cleared paid_amount NUMERIC(14,2) DEFAULT 0, remark TEXT, order_date DATE DEFAULT CURRENT_DATE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_orders IS '订单主表'; COMMENT ON COLUMN erp_orders.order_no IS '业务订单号'; COMMENT ON COLUMN erp_orders.customer_id IS '下单客户ID'; COMMENT ON COLUMN erp_orders.salesperson_id IS '负责销售ID'; COMMENT ON COLUMN erp_orders.total_amount IS '订单总金额'; COMMENT ON COLUMN erp_orders.shipping_state IS '发货状态: pending/partial/shipped'; COMMENT ON COLUMN erp_orders.payment_state IS '付款状态: unpaid/partial/cleared'; COMMENT ON COLUMN erp_orders.paid_amount IS '已付金额'; CREATE INDEX idx_order_no ON erp_orders(order_no) WHERE is_deleted = FALSE; CREATE INDEX idx_order_cust ON erp_orders(customer_id) WHERE is_deleted = FALSE; CREATE INDEX idx_order_sales ON erp_orders(salesperson_id) WHERE is_deleted = FALSE; CREATE INDEX idx_order_date ON erp_orders(order_date) WHERE is_deleted = FALSE; CREATE TRIGGER trg_order_updated BEFORE UPDATE ON erp_orders FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 4.2 订单明细表 erp_order_items -- ============================================================ CREATE TABLE erp_order_items ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), order_id UUID NOT NULL REFERENCES erp_orders(id), sku_id UUID NOT NULL REFERENCES erp_product_skus(id), qty NUMERIC(12,2) NOT NULL, unit_price NUMERIC(12,2) NOT NULL, -- 本次成交单价(可能是专属价) sub_total NUMERIC(14,2) NOT NULL, shipped_qty NUMERIC(12,2) DEFAULT 0, -- 已发货累计量(用于分批发货扣减) created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_order_items IS '订单明细行表'; COMMENT ON COLUMN erp_order_items.order_id IS '归属订单ID'; COMMENT ON COLUMN erp_order_items.sku_id IS '关联SKU ID'; COMMENT ON COLUMN erp_order_items.qty IS '下单数量'; COMMENT ON COLUMN erp_order_items.unit_price IS '成交单价(可能为客户专属价)'; COMMENT ON COLUMN erp_order_items.sub_total IS '小计金额 = qty * unit_price'; COMMENT ON COLUMN erp_order_items.shipped_qty IS '已发货累计数量,用于分批发货进度追踪'; CREATE INDEX idx_oitem_order ON erp_order_items(order_id) WHERE is_deleted = FALSE; CREATE INDEX idx_oitem_sku ON erp_order_items(sku_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_oitem_updated BEFORE UPDATE ON erp_order_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ************************************************************ -- 5. ERP 物流域 -- ************************************************************ -- ============================================================ -- 5.1 发货主单表 erp_shipping_records -- ============================================================ CREATE TABLE erp_shipping_records ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), shipping_no VARCHAR(30) NOT NULL UNIQUE, -- 发货单号 SHP-xxx order_id UUID NOT NULL REFERENCES erp_orders(id), carrier VARCHAR(100), -- 承运方,如德邦 tracking_no VARCHAR(100), -- 物流追踪号 status VARCHAR(20) NOT NULL DEFAULT 'transit', -- transit / delivered ship_date DATE DEFAULT CURRENT_DATE, remark TEXT, operator_id UUID REFERENCES sys_users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_shipping_records IS '发货主单表'; COMMENT ON COLUMN erp_shipping_records.shipping_no IS '发货单号'; COMMENT ON COLUMN erp_shipping_records.order_id IS '关联订单ID'; COMMENT ON COLUMN erp_shipping_records.carrier IS '承运方'; COMMENT ON COLUMN erp_shipping_records.tracking_no IS '物流追踪号'; COMMENT ON COLUMN erp_shipping_records.status IS '物流状态: transit=运输中 / delivered=已签收'; CREATE INDEX idx_ship_order ON erp_shipping_records(order_id) WHERE is_deleted = FALSE; CREATE INDEX idx_ship_no ON erp_shipping_records(shipping_no) WHERE is_deleted = FALSE; CREATE TRIGGER trg_ship_updated BEFORE UPDATE ON erp_shipping_records FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 5.2 发货明细表 erp_shipping_items -- ============================================================ CREATE TABLE erp_shipping_items ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), shipping_id UUID NOT NULL REFERENCES erp_shipping_records(id), order_item_id UUID NOT NULL REFERENCES erp_order_items(id), sku_id UUID NOT NULL REFERENCES erp_product_skus(id), shipped_qty NUMERIC(12,2) NOT NULL, -- 本次发货数量 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE erp_shipping_items IS '发货明细行表(承接分批发货扣减)'; COMMENT ON COLUMN erp_shipping_items.shipping_id IS '归属发货单ID'; COMMENT ON COLUMN erp_shipping_items.order_item_id IS '关联订单明细行ID(用于回写已发货量)'; COMMENT ON COLUMN erp_shipping_items.sku_id IS '关联SKU ID'; COMMENT ON COLUMN erp_shipping_items.shipped_qty IS '本次实际发货数量'; CREATE INDEX idx_sitem_shipping ON erp_shipping_items(shipping_id) WHERE is_deleted = FALSE; CREATE INDEX idx_sitem_oitem ON erp_shipping_items(order_item_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_sitem_updated BEFORE UPDATE ON erp_shipping_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ************************************************************ -- 6. 财务票据域 -- ************************************************************ -- ============================================================ -- 6.1 统一发票池表 fin_invoice_pool -- ============================================================ CREATE TABLE fin_invoice_pool ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), uploader_id UUID REFERENCES sys_users(id), file_url VARCHAR(500), merchant_name VARCHAR(200), amount NUMERIC(14,2) NOT NULL DEFAULT 0, invoice_date DATE, type VARCHAR(30) NOT NULL DEFAULT 'expense', -- customer=客户发票 / expense=报销发票 ai_extracted_data JSONB DEFAULT '{}'::JSONB, -- OCR + AI 解析的原始结构化数据 is_used BOOLEAN DEFAULT FALSE, -- 是否已被报销单引用 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE -- 软删除=作废 ); COMMENT ON TABLE fin_invoice_pool IS '统一发票池表(上传即OCR提取)'; COMMENT ON COLUMN fin_invoice_pool.uploader_id IS '上传人ID'; COMMENT ON COLUMN fin_invoice_pool.file_url IS '原始票据文件URL'; COMMENT ON COLUMN fin_invoice_pool.merchant_name IS '商户/开票方名称'; COMMENT ON COLUMN fin_invoice_pool.amount IS '票面金额'; COMMENT ON COLUMN fin_invoice_pool.type IS '票据类型: customer=客户发票 / expense=报销发票'; COMMENT ON COLUMN fin_invoice_pool.ai_extracted_data IS 'AI/OCR提取的结构化数据 (JSONB)'; COMMENT ON COLUMN fin_invoice_pool.is_used IS '是否已被报销单引用'; COMMENT ON COLUMN fin_invoice_pool.is_deleted IS '软删除标识(作废,防物理篡改)'; CREATE INDEX idx_inv_uploader ON fin_invoice_pool(uploader_id) WHERE is_deleted = FALSE; CREATE INDEX idx_inv_type ON fin_invoice_pool(type) WHERE is_deleted = FALSE; CREATE INDEX idx_inv_date ON fin_invoice_pool(invoice_date) WHERE is_deleted = FALSE; CREATE TRIGGER trg_inv_updated BEFORE UPDATE ON fin_invoice_pool FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 6.2 报销单主表 fin_expense_records -- ============================================================ CREATE TABLE fin_expense_records ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), system_no VARCHAR(30) NOT NULL UNIQUE, -- 系统单号 EXP-xxx applicant_id UUID NOT NULL REFERENCES sys_users(id), total_amount NUMERIC(14,2) NOT NULL DEFAULT 0, status VARCHAR(20) NOT NULL DEFAULT 'draft', -- draft/pending/approved/rejected remark TEXT, approved_by UUID REFERENCES sys_users(id), approved_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE fin_expense_records IS '报销单主表'; COMMENT ON COLUMN fin_expense_records.system_no IS '系统报销单号'; COMMENT ON COLUMN fin_expense_records.applicant_id IS '申请人ID'; COMMENT ON COLUMN fin_expense_records.total_amount IS '报销总金额'; COMMENT ON COLUMN fin_expense_records.status IS '报销状态: draft/pending/approved/rejected'; COMMENT ON COLUMN fin_expense_records.approved_by IS '审批人ID'; CREATE INDEX idx_exp_applicant ON fin_expense_records(applicant_id) WHERE is_deleted = FALSE; CREATE INDEX idx_exp_status ON fin_expense_records(status) WHERE is_deleted = FALSE; CREATE INDEX idx_exp_no ON fin_expense_records(system_no) WHERE is_deleted = FALSE; CREATE TRIGGER trg_exp_updated BEFORE UPDATE ON fin_expense_records FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 6.3 报销明细行表 fin_expense_details -- ============================================================ CREATE TABLE fin_expense_details ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), expense_id UUID NOT NULL REFERENCES fin_expense_records(id), invoice_id UUID REFERENCES fin_invoice_pool(id), expense_desc VARCHAR(500), -- 费用说明 original_type VARCHAR(50), -- 原始费用类型: fuel/entertainment/travel/office offset_type VARCHAR(50), -- 冲顶类型(二级类型转换后) amount NUMERIC(14,2) NOT NULL DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE ); COMMENT ON TABLE fin_expense_details IS '报销明细行表'; COMMENT ON COLUMN fin_expense_details.expense_id IS '归属报销单ID'; COMMENT ON COLUMN fin_expense_details.invoice_id IS '关联发票ID'; COMMENT ON COLUMN fin_expense_details.expense_desc IS '费用说明描述'; COMMENT ON COLUMN fin_expense_details.original_type IS '原始费用类型: fuel/entertainment/travel/office'; COMMENT ON COLUMN fin_expense_details.offset_type IS '冲顶类型(二级票据类型转换后的类型)'; COMMENT ON COLUMN fin_expense_details.amount IS '本行金额'; CREATE INDEX idx_expd_expense ON fin_expense_details(expense_id) WHERE is_deleted = FALSE; CREATE INDEX idx_expd_invoice ON fin_expense_details(invoice_id) WHERE is_deleted = FALSE; CREATE TRIGGER trg_expd_updated BEFORE UPDATE ON fin_expense_details FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- 完成:输出建表结果摘要 -- ============================================================ -- 共创建 13 张业务表: -- RBAC 权限域: sys_departments, sys_roles, sys_users -- CRM 客户域: crm_customers, crm_follow_up_logs -- ERP 供应链域: erp_product_categories, erp_product_skus, erp_inventory_flows -- ERP 交易域: erp_orders, erp_order_items -- ERP 物流域: erp_shipping_records, erp_shipping_items -- 财务票据域: fin_invoice_pool, fin_expense_records, fin_expense_details -- -- 全局规范落地: -- ✓ 主键统一 UUID (uuid_generate_v4) -- ✓ 每表必带 created_at / updated_at / is_deleted 审计三件套 -- ✓ updated_at 自动触发器 (update_updated_at_column) -- ✓ 灵活字段采用 JSONB (menu_keys, ai_extracted_data) -- ✓ 外键关联完整,部分索引 (WHERE is_deleted=FALSE) 优化查询