246 lines
34 KiB
Markdown
246 lines
34 KiB
Markdown
# 物料管理系统数据库表说明
|
||
|
||
更新时间: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 用户确认),本次没有武汉历史副本检查或授权回填对象;空库初始化及合成历史夹具升级分别验证。部署、验收证据及回退限制见 [公司隔离验收与交付](company-master-data-isolation-acceptance.md)。
|