# 数据库约定 本目录的 `.sql` 是表结构的设计稿,供评审和后续 Laravel migration 对照。不要把这些文件当作生产迁移直接执行,也不要一次把尚未开工的 Phase 全部做成 migration。 ## 库与字符集 - MySQL 8、InnoDB、`utf8mb4`、`utf8mb4_0900_ai_ci` - 时间用 `DATETIME(3)`,由应用写入租户或仓库时区换算后的时刻,库内不存时区 ## 命名 - 表名使用单数,统一 `wms_` 前缀,例如 `wms_sku`、`wms_stock_log` - 每张表一个文件,文件名即表名,放在对应领域目录 - 字段 snake_case。业务编码以 `_code` 或 `_no` 结尾 ## 公共字段 - `id`:`BIGINT UNSIGNED` 自增,只做内部主键和加锁顺序 - `tenant_code`:核心业务表必有。例外只有两张全局目录:`wms_tenant`、`wms_permission` - `created_at`、`updated_at`:每张表都有 - 单据头有 `created_by`、`updated_by`,存 `user_code` - 不使用 `deleted_at`。主数据用 `status=disabled` 停用;流水和日志只追加,禁止修改和删除 ## 类型 - 数量:`DECIMAL(16,4)`,禁止 `FLOAT` / `DOUBLE` - 金额:`DECIMAL(16,4)`,币种 `CHAR(3)` - 重量:千克,`DECIMAL(12,4)`;尺寸:厘米 - 状态:`VARCHAR(32)`,取值写在字段注释里。应用层用 Enum 和集中定义的合法迁移,禁止散落比较魔法字符串 ## 关联 - 表与表用业务编码关联,不建外键。编码的唯一约束都包含 `tenant_code` - 需要「允许多个空值」的可选单号(外部订单号、入库参考号、非销售出库的订单号)使用 `NULL`,不要用空字符串,否则唯一索引会撞车 - 参与库存唯一键的可选编码(库位、批次)使用空字符串,保证唯一索引生效 - Laravel 的 `personal_access_tokens`、队列表、缓存表由框架 migration 维护,不在这里重复 ## 库存 余额行的粒度是:租户 + 仓库 + 货主 + 库位 + SKU + 批次。 库存状态不另做一行维度,由数量桶表达: | 字段 | 含义 | | --- | --- | | available_qty | 可用 | | reserved_qty | 已分配、未拣货 | | picked_qty | 已拣货、未出库 | | hold_qty | 冻结 | | damaged_qty | 残损 | | in_transit_qty | 在途,只放在库位编码为空的行 | 待检、待上架的实物放在收货或质检库位,仍记在 `available_qty`,靠库位策略排除出可分配范围。 任何余额变化必须和 `wms_stock_log` 在同一事务。扣减用带数量条件的原子更新。一次动作跨两个桶或两个库位时写多行流水,共用 `biz_type` 和 `biz_no`。打包不改数量桶。 ## 订单和出库 - `wms_order` 是统一履约订单,不包含任何平台专用列 - `wms_outbound` 是仓库作业单。一笔订单可以按仓库拆成多张出库单 - 平台差异留在 `wms_platform_shop` 和连接器 ## 不单独建表的概念 | 概念 | 落点 | | --- | --- | | 库位容量 | `wms_location` 的容量列 | | 收货差异 | `wms_inbound_receipt_item` 的差异列 | | 入库流水 | `wms_stock_log`,`biz_type` 为入库相关 | | 库存锁定 / 预占 | `wms_allocation` | | 复核 | `wms_outbound.review_status` | | 报废单 | 退货明细的处置加 `wms_stock_log` | | 订单渠道、来源、外部单号、状态 | `wms_order` 的列,不是独立表 | | 报表、AI 分析结果 | 查询或 Python 服务返回,不落核心业务表 |