feat(warehouse): 库位按公司隔离,并重做批量生成与库位管理
隔离(db_migrations/phase15_warehouse_location_company.sql) - sys_warehouse_location 新增 company_name,NULL = 全局共享 - 存量 3371 行按 full_path 顶段首字母回填:Y*→IRIS(500),L*/C*→LICA(2871) - 读范围 = 本公司 + 全局;写范围 = 仅本公司 删除/改名/批量生成都加归属校验 —— 只隔离读接口等于没隔离, 否则 LICA 一条 DELETE 就能删掉 IRIS 整棵库位树 - /tree 与 /children 补上缺失的 @jwt_required() - 公司名走白名单校验,非法值 400(拼错会造出谁都看不见的库位,且无从排查) - 超管可改归属,级联整棵子树(归属撕裂会让父子可见性错乱) 改名补偿 - 级联重写子孙 full_path(原实现只改自己一行,子孙仍挂旧前缀, 而库存快照存的正是 full_path,改一次名整棵子树就和台账对不上) - 同事务改写在库台账 stock_buy/semi/product/adjustment 的快照, 以及未结束盘点会话的 scope_config.locations - 刻意不含 trans_outbound / trans_borrow 等历史单据(改历史 = 篡改操作记录), 也不含 trans_repair.customer_location(那是客户地址不是库位) 批量生成 - 起点支持三种:勾选的一批库位 / 某子树下所有末级 / 单个父级 - 已存在同名跳过 —— full_path 上有唯一约束 uniq_full_path, 不跳过会整单 500 并整体回滚,连本该新建的也一并丢失 - 数量上限改按实际创建数(各层之和 × 起点数),不再是各层相乘 (旧口径低估,3000 的上限因此能被悄悄突破) - 前端加生成结构预览:逐层数量 + 完整路径示例,边填边看 前端清理 - 删除 utils/warehouseCompany.ts 前缀白名单,WarehouseSelector 与三个 入库页改为纯渲染后端数据(隔离已下沉到后端) - 盘点页 loadLocationTree 必须带 company_name:跨域角色在后端返回 None, 不带就会拉全量、盘点范围脱离所选公司 - 盘点页切公司时清库位树缓存(原来会继续沿用上一个公司的树) - 修复批量删除只取叶子导致中间层节点残留成孤儿
This commit is contained in:
@ -172,6 +172,12 @@ class SysWarehouseLocation(db.Model):
|
||||
full_path = db.Column(db.String(500)) # 完整路径,如 "A区/货架1/第3层"
|
||||
level = db.Column(db.Integer, default=0) # 层级深度,顶级为0
|
||||
is_enabled = db.Column(db.Boolean, default=True)
|
||||
# [新增] 公司归属:NULL = 全局共享(两司均可见)。
|
||||
# ★ 这是「归属」不是「任意公司名」,取值域只有 IRIS / LICA / NULL 三态。
|
||||
# 切勿写入 'System' —— 超管的 JWT company_name 正是 'System',一旦落库,
|
||||
# 这批库位对**所有**公司都不可见且无从排查。写入前统一过
|
||||
# warehouse.py 的 _normalize_company()。
|
||||
company_name = db.Column(db.String(50), index=True, comment='公司归属: IRIS/LICA,NULL=全局共享')
|
||||
created_at = db.Column(db.DateTime, default=beijing_time)
|
||||
# 注意:数据库表中没有 updated_at 字段,不要添加!
|
||||
|
||||
@ -190,5 +196,6 @@ class SysWarehouseLocation(db.Model):
|
||||
'full_path': self.full_path,
|
||||
'level': self.level,
|
||||
'is_enabled': self.is_enabled,
|
||||
'company_name': self.company_name,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None
|
||||
}
|
||||
Reference in New Issue
Block a user