34 KiB
物料管理系统数据库表说明
更新时间:2026-10-09。本文前半部分保留已有库的结构说明;第 11 节说明公司隔离升级后的运行结构。表数量随升级增加审计、迁移版本及对账表,以目标库 information_schema 查询为准。
本文按照“表、保存什么、主要字段”介绍每张表的作用,后面单独列出表之间的关系。公司隔离发布使用 scripts/init.sql(空库)或 scripts/upgrades/2026-10-08-company-master-data-isolation.sql(已有库),不以旧库快照代替升级后的结构。
通用字段:id 为记录主键;organization_id 为本方经营组织 ID;created_at、updated_at 分别为创建、更新时间。表已创建与对应业务功能已完整实现是两件事,未接入当前业务流程的结构在第 9 节说明。
1. 本方组织、用户与权限
| 表 | 保存什么 | 主要字段 |
|---|---|---|
organizations |
本方公司或核算主体,例如北京公司、武汉公司;用于确定业务数据归属。 | 组织ID(id)、组织编码(code)、组织名称(name)、状态(status)、默认时区(default_timezone)、created_at、updated_at |
users |
系统登录账号和用户说明。 | 用户ID(id)、用户名(username)、密码哈希(password)、用户说明(description)、created_at |
roles |
超级管理员、仓库管理员、采购、技术、生产、销售等角色定义。 | 角色ID(id)、角色编码(code)、角色名称(name)、是否启用(enabled)、created_at、updated_at |
permissions |
查看物料、维护供应商、维护出入库等可授权的操作能力。 | 权限ID(id)、权限编码(code)、权限名称(name)、created_at |
user_roles |
用户拥有哪些角色。 | 用户ID(user_id)、角色ID(role_id)、分配时间(created_at) |
role_permissions |
角色拥有哪些权限。 | 角色ID(role_id)、权限ID(permission_id)、授权时间(created_at) |
user_organizations |
用户可访问的组织范围及默认组织。 | 用户ID(user_id)、组织ID(organization_id)、默认组织标记(is_default)、created_at |
user_warehouses |
用户可访问的仓库范围。 | 用户ID(user_id)、仓库ID(warehouse_id)、created_at |
revoked_tokens |
被撤销令牌的登记结构,供令牌失效机制使用。 | 令牌标识(jti,主键)、用户ID(user_id)、原到期时间(expires_at)、撤销时间(revoked_at) |
2. 物料与基础字典
| 表 | 保存什么 | 主要字段 |
|---|---|---|
materials |
物料基础资料,用于识别和描述物料;库存余额另存。 | 物料ID(id)、所属组织(organization_id)、物料编码(material_code)、名称(name)、图片(material_image)、规格(spec)、厂商型号(manufacturer_model)、分类ID(category_id)、基本单位ID(base_unit_id)、单位文本(unit)、状态(status)、资料版本(version)、created_at、updated_at |
material_categories |
物料大类、子类及分类定义,形成分类树。 | 分类ID(id)、所属组织(organization_id)、编码(code)、名称(name)、分类说明(description)、父分类ID(parent_id)、状态(status) |
units |
个、瓶、包、升等计量单位字典及数量精度。 | 单位ID(id)、所属组织(organization_id)、单位编码(code)、单位名称(name)、小数位数(precision_scale)、状态(status) |
code_rules |
按组织和物料分类配置的编码生成规则。 | 规则ID(id)、所属组织(organization_id)、分类ID(category_id)、编码前缀(prefix)、流水号长度(sequence_length)、下一个流水号(next_sequence)、状态(status) |
material_unit_conversions |
特定物料在两个计量单位之间的换算系数及有效期。 | 规则ID(id)、所属组织(organization_id)、物料ID(material_id)、来源单位ID(from_unit_id)、目标单位ID(to_unit_id)、换算系数(conversion_rate)、生效日期(effective_from)、失效日期(effective_to) |
tags |
物料关联的唯一码或标签,用于按标签查找物料。 | 标签ID(id)、物料ID(material_id)、标签编码(tag_code)、created_at |
3. 客户、供应商与供货关系
| 表 | 保存什么 | 主要字段 |
|---|---|---|
business_partners |
企业基本资料,多个本方组织可以共用。 | 企业ID(id)、企业名称(legal_name)、统一社会信用代码(unified_credit_code)、联系人(contact_name)、电话(contact_phone)、地址(address)、created_at、updated_at |
organization_partners |
当前组织如何与这家企业合作。 | 关系ID(id)、所属组织(organization_id)、企业ID(business_partner_id)、伙伴编码(partner_code)、供应商身份(is_supplier)、客户身份(is_customer)、供应商状态(supplier_status)、客户状态(customer_status)、供应商分类(supplier_categories)、客户分类(customer_categories)、结算币种(settlement_currency)、付款条款(payment_terms)、created_at、updated_at |
material_suppliers |
某个物料由哪个供应商供货,以及报价和供货条件。 | 记录ID(id)、所属组织(organization_id)、物料ID(material_id)、组织伙伴关系ID(organization_partner_id)、价格(price)、币种(currency)、最小订购量(minimum_order_quantity)、供货周期天数(lead_time_days)、首选标记(is_preferred)、生效日期(effective_from)、失效日期(effective_to)、状态(status) |
同一外部企业可以与北京、武汉分别建立合作关系。企业名称、联系人、地址等基础资料共用;客户/供应商身份、状态和分类按组织分别保存。同一关系可同时具有客户和供应商身份。
supplier_categories 与 customer_categories 均支持多选:material 表示“物料级(生产)”,finished_product 表示“成品级(经营买卖)”;空集合表示未分类。
4. 仓库、库位与库存
| 表 | 保存什么 | 主要字段 |
|---|---|---|
warehouses |
本方组织的仓库资料。 | 仓库ID(id)、所属组织(organization_id)、仓库编码(code)、名称(name)、状态(status)、created_at、updated_at |
warehouse_locations |
某个仓库内部的存放位置。 | 库位ID(id)、所属仓库(warehouse_id)、库位编码(code)、名称(name)、状态(status)、created_at、updated_at |
inventory_balances |
某物料在某组织、仓库、库位的当前库存余额。 | 余额ID(id)、组织ID(organization_id)、仓库ID(warehouse_id)、库位ID(location_id)、物料ID(material_id)、现存量(on_hand)、预留量(reserved)、锁定量(locked)、在途量(in_transit)、库存版本(version)、updated_at |
stock_warning_rules |
某组织、仓库、物料的库存预警规则。 | 规则ID(id)、组织ID(organization_id)、仓库ID(warehouse_id)、物料ID(material_id)、预警阈值(minimum_available)、是否启用(enabled)、created_at、updated_at |
库位通过所属仓库确定组织。库存余额按库位保存,预警规则按仓库保存。当前预警查询使用现存量口径,启用且现存量小于等于阈值时预警,阈值为 0 也有效。
5. 入库与出库单据
| 表 | 保存什么 | 主要字段 |
|---|---|---|
inbound_orders |
一次入库操作的公共信息,即入库单表头。 | 单据ID(id)、所属组织(organization_id)、仓库ID(warehouse_id)、库位ID(location_id)、入库单号(inbound_no)、操作人(operator)、入库时间(inbound_date)、经手人(handler)、供应商文本(supplier)、备注(remark)、created_at、updated_at |
inbound_items |
入库单中逐项入库的物料和数量。 | 明细ID(id)、入库单ID(inbound_order_id)、物料ID(material_id)、数量(quantity)、created_at |
outbound_orders |
一次出库操作的公共信息,即出库单表头。 | 单据ID(id)、所属组织(organization_id)、仓库ID(warehouse_id)、库位ID(location_id)、出库单号(outbound_no)、操作人(operator)、出库时间(outbound_date)、经手人(handler)、接收方文本(receiver)、备注(remark)、旧库状态字段(status)、created_at、updated_at |
outbound_items |
出库单中逐项出库的物料和数量。 | 明细ID(id)、出库单ID(outbound_order_id)、物料ID(material_id)、数量(quantity)、created_at |
一张单据可以有多条物料明细;当前仓库、库位保存在表头,明细没有独立库位。supplier、receiver、operator、handler 均为文本,不是伙伴或用户表外键。
6. 物料申请与审批
| 表 | 保存什么 | 主要字段 |
|---|---|---|
material_applications |
一次物料领用申请的申请人、用途和审批结果。 | 申请ID(id)、申请人ID(user_id)、用途(purpose)、申请状态(status)、驳回原因(rejection_reason)、审批人ID(approved_by)、created_at、updated_at |
application_items |
申请中需要领用的物料和数量。 | 明细ID(id)、申请ID(application_id)、物料ID(material_id)、申请数量(quantity) |
申请状态为 pending(待审批)、approved(已通过)、rejected(已驳回)、cancelled(已取消)。当前申请明细引用已有物料;新增物料生成编码属于另一条主数据流程。
审批选择自动出库时,当前代码生成出库单和明细、扣减库存并记录流水;仅审批模式只更新审批状态。申请表没有直接指向生成出库单的字段,也没有 organization_id 或个人库存字段。
7. 物料变更日志与库存流水
| 表 | 保存什么 | 主要字段 |
|---|---|---|
material_logs |
物料资料新增、修改等操作及修改前后快照。 | 日志ID(id)、操作类型(operation_type)、物料ID(material_id)、旧值快照(old_value)、新值快照(new_value)、操作人(operator)、说明(description)、created_at |
stock_logs |
库存增减数量、方向和来源单据。 | 流水ID(id)、物料ID(material_id)、方向(type)、数量(quantity)、来源类型(related_order_type)、来源记录ID(related_order_id)、created_at |
material_logs 描述资料变化,stock_logs 描述数量变化。库存流水的 type 为 in 或 out;来源类型包含 inbound、outbound、application,分别指向入库单、出库单、申请主键。
8. 表之间的关系
8.1 关系如何理解
| 关系 | 保存方式 | 例子 |
|---|---|---|
| 一对多 | 多的一方保存主表ID。 | 一个入库单对应多个入库明细:inbound_items.inbound_order_id → inbound_orders.id。 |
| 多对多 | 中间表同时保存两边的ID。 | 用户与角色通过 user_roles 关联;组织与企业通过 organization_partners 关联。 |
| 自关联 | 记录引用同一张表的另一条记录。 | material_categories.parent_id → material_categories.id,表示分类父子关系。 |
| 逻辑关联 | 代码按字段查询,数据库未设置外键。 | 申请人ID关联用户、库存流水按来源类型及ID关联单据。 |
8.2 当前实际存在的外键
以下按数据库元数据逐项列出。外键确保引用记录存在;记录是否同属一个组织,还需要业务层校验。
| 子表字段 | 引用主表字段 |
|---|---|
application_items.application_id |
material_applications.id |
application_items.material_id |
materials.id |
code_rules.category_id |
material_categories.id |
code_rules.organization_id |
organizations.id |
inbound_items.material_id |
materials.id |
inbound_items.inbound_order_id |
inbound_orders.id |
inbound_orders.location_id |
warehouse_locations.id |
inbound_orders.organization_id |
organizations.id |
inbound_orders.warehouse_id |
warehouses.id |
inventory_balances.location_id |
warehouse_locations.id |
inventory_balances.material_id |
materials.id |
inventory_balances.organization_id |
organizations.id |
inventory_balances.warehouse_id |
warehouses.id |
material_categories.organization_id |
organizations.id |
material_categories.parent_id |
material_categories.id |
material_suppliers.material_id |
materials.id |
material_suppliers.organization_id |
organizations.id |
material_suppliers.organization_partner_id |
organization_partners.id |
material_unit_conversions.from_unit_id |
units.id |
material_unit_conversions.material_id |
materials.id |
material_unit_conversions.organization_id |
organizations.id |
material_unit_conversions.to_unit_id |
units.id |
materials.base_unit_id |
units.id |
materials.category_id |
material_categories.id |
materials.organization_id |
organizations.id |
organization_partners.organization_id |
organizations.id |
organization_partners.business_partner_id |
business_partners.id |
outbound_items.material_id |
materials.id |
outbound_items.outbound_order_id |
outbound_orders.id |
outbound_orders.location_id |
warehouse_locations.id |
outbound_orders.organization_id |
organizations.id |
outbound_orders.warehouse_id |
warehouses.id |
revoked_tokens.user_id |
users.id |
role_permissions.permission_id |
permissions.id |
role_permissions.role_id |
roles.id |
stock_logs.material_id |
materials.id |
stock_warning_rules.material_id |
materials.id |
stock_warning_rules.organization_id |
organizations.id |
stock_warning_rules.warehouse_id |
warehouses.id |
tags.material_id |
materials.id |
units.organization_id |
organizations.id |
user_organizations.organization_id |
organizations.id |
user_organizations.user_id |
users.id |
user_roles.role_id |
roles.id |
user_roles.user_id |
users.id |
user_warehouses.user_id |
users.id |
user_warehouses.warehouse_id |
warehouses.id |
warehouse_locations.warehouse_id |
warehouses.id |
warehouses.organization_id |
organizations.id |
8.3 逻辑关联及间接关联
| 表之间的关系 | 关联字段 | 说明 |
|---|---|---|
| 申请 → 申请人 | material_applications.user_id → users.id |
当前实际库未设置用户外键,代码查询申请人资料。 |
| 申请 → 审批人 | material_applications.approved_by → users.id |
当前无外键;未审批时通常为 0。 |
| 物料日志 → 物料 | material_logs.material_id → materials.id |
当前实际库无外键。 |
| 库存流水 → 入库单 | related_order_type = inbound 时,related_order_id → inbound_orders.id |
按类型和ID配对查询。 |
| 库存流水 → 出库单 | related_order_type = outbound 时,related_order_id → outbound_orders.id |
按类型和ID配对查询。 |
| 库存流水 → 申请 | related_order_type = application 时,related_order_id → material_applications.id |
自动出库流水保存的是申请ID,不是生成的出库单ID。 |
| 库位 → 组织 | warehouse_locations.warehouse_id → warehouses.organization_id |
通过仓库间接确定组织。 |
| 物料 → 编码规则 | 组织及分类对应 code_rules |
物料只保存生成的编码文本,没有编码规则ID字段。 |
| 申请 → 自动生成的出库单 | 当前没有直接关联字段 | 属于业务生成过程,不能按现有表头字段直接定位关联单据。 |
8.4 主要唯一约束
| 表 | 唯一字段或组合 | 含义 |
|---|---|---|
organizations、roles、permissions |
code |
各自表内编码唯一。 |
users |
username |
用户名唯一。 |
business_partners |
unified_credit_code |
已填写的信用代码唯一,允许为空;企业名称没有唯一约束。 |
organization_partners |
(organization_id, business_partner_id);(organization_id, partner_code) |
同一组织与同一企业只有一条合作关系;伙伴编码在组织内唯一。 |
materials |
(organization_id, material_code) |
物料编码在组织内唯一。 |
material_categories、units、warehouses |
(organization_id, code) |
分类、单位、仓库编码分别在组织内唯一。 |
warehouse_locations |
(warehouse_id, code) |
库位编码在仓库内唯一。 |
code_rules |
(organization_id, category_id) |
同一组织同一分类只有一条编码规则。 |
inventory_balances |
(organization_id, warehouse_id, location_id, material_id) |
同一库存维度只有一条余额。 |
stock_warning_rules |
(organization_id, warehouse_id, material_id) |
同一仓库同一物料只有一条预警规则。 |
tags |
tag_code |
标签编码全表唯一。 |
inbound_orders、outbound_orders |
inbound_no、outbound_no |
各自单据表内单号唯一。 |
user_roles |
(user_id, role_id) 联合主键 |
同一用户不会重复分配同一角色。 |
role_permissions |
(role_id, permission_id) 联合主键 |
同一角色不会重复分配同一权限。 |
user_organizations |
(user_id, organization_id) 联合主键 |
同一组织授权不会重复。 |
user_warehouses |
(user_id, warehouse_id) 联合主键 |
同一仓库授权不会重复。 |
9. 当前结构与使用范围
| 项目 | 当前情况 |
|---|---|
| 令牌撤销 | revoked_tokens 结构已建,当前认证代码未查询该表;退出登录主要由客户端清除令牌。 |
| 物料单位换算 | material_unit_conversions 结构已建,当前后端未见该表业务读写路径;库存余额支持小数,但出入库、申请明细及流水数量仍为 INT。 |
| 物料供应商条件 | material_suppliers 结构已建,用于供货、报价等需求;当前后端未见完整维护路径。 |
| 实物追踪 | tags 只有物料和标签关系,没有库位、单据明细或实物流转状态;物料表没有序列号开关。 |
| 组织范围 | 多数业务表有组织字段;当前申请表、库存流水和物料日志没有直接组织字段。角色分配也没有按组织分别保存。 |
| 伙伴资料共享 | 多个组织引用同一企业ID时,修改企业名称、联系人等基础资料会影响共享记录;合作身份、分类、状态分别保存。当前新建接口仍直接新增企业记录。 |
| 库存口径 | 结构支持现存、预留、锁定、在途数量;当前主要出入库代码修改默认组织、默认仓库、主库位的现存量。 |
| 可用库存 | 设计口径为 on_hand - reserved - locked;当前预警查询使用现存量,不能仅根据阈值字段名推断已使用可用量。 |
| 日志口径 | 物料日志实际库快照为JSON、操作类型为ENUM;库存流水编辑单据时可能重建,不是不可修改的完整审计日志。 |
| 出库状态 | 当前库保留 outbound_orders.status,但现有代码未按此列维护状态;初始化脚本没有该列。 |
| 物料类型 | 初始化脚本另有 material_types 和 materials.material_type_id;当前实际库及当前物料模型没有这两项。该表未计入本文的30张现有表。 |
| 申请单号 | 页面字段 application_no 由申请主键派生,申请表没有该列。 |
| 后续模块 | 当前库没有BOM专用表、盘点单专用表、周期提醒专用表或申请人个人库存表。 |
10. 数据库初始化
| 文件 | 用途 |
|---|---|
scripts/init.sql |
空库首次初始化,包含表结构、客户和供应商分类字段、物料分类及编码规则,以及明确标注的20家虚构企业示例数据。 |
初始化脚本直接建立分类说明字段、6 个大类和 28 个子类、父子分类关系,以及“子类编码 + 4 位流水号”的编码规则。出入库表直接包含单据编号、操作人和备注字段。
库存预警阈值为 0 是有效配置,表示库存降到 0 时预警;新库没有需要清理的历史预警规则。
已有数据库需要保留数据时,应先备份,再根据实际结构差异准备并验证增量 SQL;不要直接重复执行完整初始化脚本。
11. 公司隔离发布结构与升级(2026-10-09)
本节更新第 9 节的旧库观察:当前申请和库存流水已有显式组织字段,库存业务不再使用默认组织/仓库/库位兜底。物料日志通过所属物料限制公司;功能角色仍是全局角色,公司授权不新增公司级角色。本期公司授权覆盖唯一仓库,user_warehouses 不作为额外授权配置入口。
| 表/约束 | 发布后要求 |
|---|---|
user_organizations.default_user_id |
根据 is_default 生成,唯一键限制每个用户至多一个默认公司;服务层验证默认公司属于启用授权列表 |
warehouses |
UNIQUE(organization_id),停用仓库仍占名额 |
warehouse_locations |
UNIQUE(warehouse_id),停用库位仍占名额 |
inventory_balances |
余额以 (organization_id, warehouse_id, location_id, material_id) 唯一,事务锁定完整维度并条件扣减 |
inbound_orders、outbound_orders |
三个库存维度为非空归属字段;创建由后端解析,修改/删除锁定本公司原单并按原库存维度恢复原单造成的库存变化 |
stock_logs |
保存非空 organization_id/warehouse_id/location_id,索引 (organization_id, material_id, created_at);关联单据和物料均校验公司 |
material_applications |
非空 organization_id;索引 (organization_id,user_id,created_at)、(organization_id,status,created_at);状态更新携带原状态条件 |
organization_audit_logs |
actor_user_id、可空 organization_id、action、JSON old_value/new_value、created_at;按公司/时间和操作者/时间建索引 |
schema_migrations |
增量升级记录版本、running/completed/failed、起止时间和 JSON 说明;DDL 部分提交后禁止盲目重跑 |
schema_migration_reconciliations |
增量升级按公司保存 before/after 余额四种数量、单据/申请/流水数量,主键 (version,phase,organization_id) |
数据库普通外键只保证引用存在,不代替同公司校验。分类父级、物料分类/基本单位、编码规则分类、单据/申请物料及库存仓库/库位都由服务层验证归属,读写 SQL 同时限制公司。编码唯一范围保持组织内;出入库单号保持现有全表唯一规则。
自动出库审批在一个事务内锁定申请、扣减该公司余额、插入该公司出库单和流水、更新申请状态;库存不足、流水写入故障均回滚。服务启动只检查申请所需组织列,缺列报升级错误,不使用旧定义自动创建申请表。
scripts/checks/company-master-data-integrity.sql 是独立检查的权威来源,结果列出异常和普通用户授权回填清单。它使用临时表,不修改永久业务数据;严格只读账户若无临时表权限,应在副本派生的隔离库执行。scripts/sync-company-integrity.ps1 -Check 检查增量脚本中的内嵌检查与此文件一致。
升级发现多个仓库/库位、多个默认公司、跨组织引用、未确认授权或无法确定流水来源时先阻断,禁止自动删除、合并或猜测归属。授权清单经业务确认后显式回填,不自动给普通用户授权所有公司。新公司分类/单位/规则默认为空,独立配置。
武汉目前没有历史数据(2026-10-09 用户确认),本次没有武汉历史副本检查或授权回填对象;空库初始化及合成历史夹具升级分别验证。部署、验收证据及回退限制见 公司隔离验收与交付。