Initial commit

This commit is contained in:
汤学会
2026-06-12 16:00:56 +08:00
commit c927886888
337 changed files with 160396 additions and 0 deletions
@@ -0,0 +1,192 @@
# 发货入口统一设计
## 背景
当前系统同时存在两个发货相关入口:
- `嘉恒仓库 -> 成品库 -> 销售出库`
- `发货与售后 -> 发货管理`
两个入口都会影响发货单、成品库存和后续退货追溯,容易让用户不知道应该在哪里执行发货,也容易造成业务口径重复。
## 目标
采用方案 A:将发货执行入口统一到 `嘉恒仓库 -> 成品库 -> 销售出库`,将 `发货与售后 -> 发货管理` 调整为发货台账/交付查询。
目标效果:
- 新增发货只允许从成品库的销售出库入口办理。
- 发货与售后模块不再新增发货,只查看、筛选、追溯发货记录。
- 销售订单发货和直接客户发货都能扣减成品库存。
- 任意发货明细都能追溯到成品库存批次和来源原材料库存批次号。
- 客户退货继续以发货批次为来源,保持退货库、废料库的追溯能力。
## 业务入口
### 成品库销售出库
`嘉恒仓库 -> 成品库 -> 销售出库` 是唯一新增发货入口。
该入口支持两种模式:
- `销售订单发货`:选择销售订单和销售订单明细,系统带出客户、产品、未发数量、收货人、电话、地址,并按成品库存批次自动拆分出库。
- `直接客户发货`:不绑定销售订单,选择客户、产品和发货数量,系统同样按成品库存批次自动拆分出库。
销售出库需要填写或维护:
- 发货模式
- 销售订单和订单明细,仅销售订单发货时必填
- 收货客户
- 发货人
- 收货人、联系电话、送货地址
- 发货产品
- 发货数量
- 运单号或订单照片
- 运费
- 自动拆分出的成品库存批次明细
- 自动拆分明细中必须直接展示成品批次、来源原材料库存批次号、来源材料摘要,方便发货前确认这批货来自哪批材料
### 发货管理
`发货与售后 -> 发货管理` 调整为发货台账/交付查询。
该页面保留:
- 发货列表
- 发货明细抽屉
- 发货单号、客户、产品、销售订单号、发货时间、发货数量、状态
- 运单号、运费、订单照片
- 成品批次、来源原材料库存批次号、来源材料信息
- 搜索、排序、分页
该页面去除:
- 新增发货按钮
- 新增发货抽屉
- 任何直接创建发货单的入口
## 数据流
成品库销售出库创建成功后统一写入:
- 发货单
- 发货明细
- 成品库存批次扣减
- 成品库库存余额扣减
- 库存流水,类型为 `SALES_OUT`
- 销售订单已发数量,仅销售订单发货时回写
- 发货批次追溯数据,供退货库和废料库使用
销售订单发货链路:
```text
销售订单
-> 销售订单明细
-> 成品库销售出库
-> 发货单
-> 发货明细
-> 成品库存批次
-> 来源原材料库存批次号
```
直接客户发货链路:
```text
客户
-> 成品库销售出库
-> 发货单
-> 发货明细
-> 成品库存批次
-> 来源原材料库存批次号
```
## 追溯规则
每条发货明细必须绑定实际扣减的成品库存批次。
成品库销售出库的自动拆分明细,在提交前就要直接展示追溯字段,而不是只在提交后的台账里展示。
成品库存批次应保留以下来源信息:
- 成品库存批次号
- 来源原材料库存批次号
- 来源材料摘要
- 完工入库或委外入库来源
- 成本相关信息
因此无论是否绑定销售订单,都可以从发货明细倒查:
```text
发货单
-> 发货明细
-> 成品库存批次
-> 来源原材料库存批次号
-> 原材料物料
-> 原材料入库批次
-> 入库成本或采购来源
```
## 退货联动
客户退货继续从发货批次选择来源。
- 可返工的客户退货进入 `退货库 -> 退货入库`。
- 判定报废的客户退货进入 `废料库 -> 退货废料入库`。
- 两种退货都应能通过发货明细追溯到成品批次和来源原材料库存批次号。
直接客户发货也必须支持退货,因为直接客户发货同样生成发货单和发货明细。
## 校验规则
成品库销售出库需要校验:
- 必须选择成品库仓库。
- 必须选择客户。
- 必须选择产品。
- 发货数量必须大于 0。
- 自动拆分出的成品批次数量合计必须等于本次发货数量。
- 成品库存不足时禁止提交。
- 销售订单发货时,发货数量不能超过订单明细未发数量。
- 运单号和订单照片至少填写或上传一个。
- 运费字段保留,允许为 0。
发货管理台账需要保证:
- 不产生库存变更。
- 不产生发货单。
- 仅展示已有发货单、明细、追溯链路和物流信息。
## UI 调整
成品库销售出库抽屉增加发货模式选择:
- 销售订单发货
- 直接客户发货
销售订单发货时展示销售订单和订单明细选择。
直接客户发货时隐藏销售订单相关字段,允许手动选择客户和产品。
自动销售出库明细表建议展示以下列:
- 成品库存批次号
- 来源原材料库存批次号
- 来源材料摘要
- 可发数量
- 本次发货数量
- 本次发货重量
发货管理页面标题建议改为 `发货台账`,页面说明调整为交付查询和批次追溯,不再出现新增发货入口。
## 测试重点
- 成品库销售出库可以创建销售订单发货。
- 成品库销售出库可以创建直接客户发货。
- 发货后成品库存正确扣减。
- 发货后生成 `SALES_OUT` 库存流水。
- 销售订单发货后订单已发数量正确回写。
- 直接客户发货不影响销售订单数量。
- 成品库销售出库自动拆分明细能在提交前展示来源原材料库存批次号。
- 发货管理页面没有新增发货入口。
- 发货管理明细能展示来源原材料库存批次号。
- 退货库和废料库仍能从发货批次选择来源。
@@ -0,0 +1,27 @@
# Dictionary Localization Design
## Goal
Eliminate visible English enum/dictionary values from ERP business screens by translating status, type, source, role, warehouse, inventory, stocktake, and maintenance codes to Chinese at the display layer.
## Scope
- Keep database and API enum values unchanged, such as `ACTIVE`, `RAW`, `PURCHASE_IN`, and `STOCKTAKE_LOSS`.
- Centralize frontend translations in `frontend/src/utils/dictionaries.js`.
- Update pages that currently render enum values directly, especially inventory, equipment, employee, purchase, stocktake, and dashboard-style views.
- Unknown enum codes should not be shown raw in business UI. They should display a Chinese fallback while retaining the raw code in `title` where useful for diagnosis.
## Design
- Expand dictionary maps for common business enum groups: status, quality status, inventory transaction type, source document type, warehouse type, item type, purchase source, maintenance type, miniapp role, and stocktake row status.
- Add formatter functions such as `formatWarehouseTypeLabel`, `formatItemTypeLabel`, `formatPurchaseSourceTypeLabel`, `formatMaintenanceTypeLabel`, `formatMiniappRoleLabel`, and `formatStocktakeRowStatusLabel`.
- Replace direct template output like `{{ order.maintenance_type }}` and `{{ person.role_names.join(" / ") }}` where values may be English enum codes.
- Keep user-entered free text unchanged. Only known internal enum/code fields are localized.
## Verification
- Add a frontend static check to verify key enum maps and high-risk views use formatter functions.
- Run existing inventory static checks.
- Run frontend build.
- Run targeted backend compile or tests only if backend files are changed.
@@ -0,0 +1,19 @@
# Operation Report Date Filter Design
## Goal
05-2 工序报工不再默认从小程序全量拉取报工数据,而是默认拉取最近 15 天,并允许用户在页面右上角按报工日期筛选。
## Design
- 后端 `/production/miniapp-operation-reports` 增加 `start_date`、`end_date` 查询参数,按 `production_reports.report_date` 闭区间过滤。
- 如果 `start_date > end_date`,接口返回 400,提示开始日期不能晚于结束日期。
- 前端 `OperationReportView.vue` 初始化日期范围为最近 15 天,含今天,例如 2026-06-01 默认 `2026-05-18` 到 `2026-06-01`。
- 05-2 页面右上角显示开始日期、结束日期和刷新按钮;刷新请求带上日期参数。
- 05-3 报废处理暂不套默认半个月筛选,避免隐藏历史未处理报废。
## Verification
- 后端测试覆盖日期范围过滤和非法日期范围。
- 前端静态回归覆盖默认 15 天、日期输入控件和请求参数。
- 运行相关后端测试、前端静态脚本和生产构建。
@@ -0,0 +1,270 @@
# 嘉恒仓库库级出入库流水设计
## 背景
嘉恒仓库已经承载原材料库、半成品库、成品库、辅料库、废料库、退货库六类库存。当前页面支持点击某个物料查看该物料的批次台账和库存流水,但缺少“站在某一个仓库整体视角查看所有出入库流水”的入口。
本设计在仓库页新增库级流水入口。入口跟随当前选中的仓库 tab,用于查看当前仓库下所有物料、批次和业务单据产生的出入库流水。
## 目标
- 在嘉恒仓库页面的出入库操作区右侧新增一个“流水”图标按钮,位置对应用户截图红框区域。
- 当前选中哪个仓库 tab,点击按钮就查看该仓库的出入库流水。
- 六大仓库都支持库级流水:原材料库、半成品库、成品库、辅料库、废料库、退货库。
- 流水数据来自统一库存流水表 `wh_inventory_txn`,不新增另一套流水记录体系。
- 库级流水和现有物料级“库存流水”并存,形成“仓库总览 -> 物料明细 -> 批次追溯”的层级。
## 非目标
- 本次不新增复杂趋势图、库存金额图表或 BI 看板。
- 本次不替代物料详情抽屉中的批次台账和物料流水。
- 本次不改变现有出入库业务的入账逻辑。
- 本次不新增导出功能;可在后续版本增加“导出当前筛选流水”。
## 页面入口
在嘉恒仓库页面的出入库操作区右侧新增一个图标按钮。
按钮要求:
- 图标使用符合当前 Ruoyi 风格的“流水/列表/票据”类图标。
- 鼠标悬停显示提示:`查看当前仓库出入库流水`。
- 按钮文本可显示为 `流水`,避免只有图标导致用户不理解。
- 按钮始终跟随当前选中仓库 tab,不在每个仓库 tab 内重复放置。
示例:
```text
仓库 tab:原材料库 / 半成品库 / 成品库 / 辅料库 / 废料库 / 退货库
出入库操作区:
入库 [+ 期初入库] [+ 客料入库] ...
出库 [- 生产出库] [- 委外出库] ...
[流水]
```
## 抽屉交互
点击“流水”按钮后,从右侧弹出大抽屉。
抽屉标题格式:
```text
{当前仓库名} · 出入库流水
```
例如:
```text
原材料库 · 出入库流水
成品库 · 出入库流水
退货库 · 出入库流水
```
抽屉内容分为三块:
1. 顶部汇总卡片
2. 筛选区
3. 流水明细表
抽屉滚动遵循全局抽屉规则:鼠标滚动只控制抽屉,不滚动底层主页面;抽屉必须完整显示在屏幕可视范围内。
## 顶部汇总
汇总数据按当前仓库和当前筛选条件计算。
建议展示:
- 入库笔数
- 出库笔数
- 入库重量(kg)
- 出库重量(kg)
- 最近一笔流水时间
数量口径:
- 原材料库、辅料库、废料库以重量为主,数量不作为核心汇总。
- 半成品库、成品库、退货库同时展示数量和重量。
如果汇总接口暂不单独返回,可前端基于当前分页结果做轻量展示,但最终推荐由后端返回全量筛选条件下的汇总,避免分页导致汇总不完整。
## 筛选与排序
筛选区保留系统全局业务列表筛选规则:
- 搜索框支持任意文字模糊搜索。
- 搜索范围包括物料编码、物料名称、批次号、流水类型、来源单据、运单号、备注。
- 重要业务字段支持排序,字段名旁显示上下箭头。
筛选项:
- 日期范围:按 `biz_time` 过滤。
- 出入库方向:全部、入库、出库、调整。
- 业务类型:采购入库、销售出库、退货入库、返工出库等。
- 物料:可选当前仓库内出现过的物料。
- 批次号:支持输入模糊匹配。
排序字段:
- 流水时间
- 业务类型
- 物料编码
- 批次号
- 变动重量
- 变动数量
- 金额
默认排序:
```text
流水时间倒序,最新流水在最上方。
```
## 流水表字段
通用字段:
- 流水时间
- 方向
- 业务类型
- 物料编码 / 物料名称
- 批次号
- 变动数量
- 变动重量(kg)
- 单价
- 金额
- 来源单据
- 经办人
- 运单号 / 订单照片
- 备注
不同仓库展示口径:
- 原材料库:隐藏或置空数量列,突出重量。
- 辅料库:隐藏或置空数量列,突出重量。
- 废料库:隐藏或置空数量列,突出重量和金额。
- 半成品库:展示数量和重量。
- 成品库:展示数量和重量。
- 退货库:展示数量和重量,并突出发货批次、退货单、返工出库来源。
方向判断:
- `weight_change_kg > 0` 或 `qty_change > 0` 为入库。
- `weight_change_kg < 0` 或 `qty_change < 0` 为出库。
- 盘库造成的正负调整显示为调整,也保留原始正负数。
## 数据接口
新增后端分页接口:
```http
GET /inventory/transaction-ledger
```
参数:
- `warehouse_type`: 必填,枚举 `RAW | SEMI | FINISHED | AUX | SCRAP | RETURN`
- `warehouse_id`: 可选,指定具体仓库 ID
- `keyword`: 可选,模糊搜索
- `direction`: 可选,`IN | OUT | ADJUST | ALL`
- `txn_type`: 可选,业务类型
- `item_id`: 可选,物料 ID
- `lot_no`: 可选,批次号模糊搜索
- `start_date`: 可选
- `end_date`: 可选
- `page`: 默认 1
- `page_size`: 默认 10
- `sort_key`: 默认 `biz_time`
- `sort_direction`: 默认 `desc`
返回:
```json
{
"items": [],
"total": 0,
"summary": {
"in_count": 0,
"out_count": 0,
"adjust_count": 0,
"in_qty": 0,
"out_qty": 0,
"in_weight_kg": 0,
"out_weight_kg": 0,
"latest_biz_time": null
}
}
```
接口内部使用 `wh_inventory_txn` 作为主表,关联:
- `md_item`
- `wh_warehouse`
- `wh_location`
- `wh_stock_lot`
- 操作人表,如果当前流水已有 `operator_user_id`
## 与现有功能关系
库级流水:
- 入口位于出入库操作区。
- 查询当前仓库所有物料和批次的流水。
- 用于回答“这个仓库最近发生了哪些出入库”。
物料级流水:
- 入口是点击库存列表中的某个物料。
- 查询该物料在当前仓库下的流水。
- 用于回答“这个物料为什么变成当前库存”。
批次台账:
- 入口同样是点击库存列表中的物料。
- 查询该物料下面每个批次的现存状态。
- 用于回答“当前还剩哪些批次,批次来源是什么”。
三者保留并互补,不互相替代。
## 错误与空状态
- 当前仓库没有流水时显示空状态:`暂无{仓库名}出入库流水`。
- 接口失败时使用右上角全局提示,几秒后自动收回,鼠标悬停时保持不收。
- 筛选结果为空时显示:`没有符合条件的流水`。
- 如果仓库正在盘库锁库,流水仍可查看,但出入库动作不可操作。
## 测试方案
后端测试:
- 按仓库类型过滤只返回对应仓库流水。
- 方向过滤能区分入库、出库、调整。
- 关键词搜索覆盖物料、批次、来源、备注。
- 分页返回 `items`、`total` 和 `summary`。
- 原材料库流水数量口径保持重量优先,不恢复原材料数量概念。
前端静态测试:
- 嘉恒仓库页面存在“流水”入口。
- 六大仓库 tab 都可打开同一流水抽屉。
- 请求使用 `/inventory/transaction-ledger`。
- 旧物料级库存流水仍保留。
前端构建:
- `npm run build` 通过。
浏览器冒烟:
- 登录后进入嘉恒仓库。
- 切换任意仓库 tab。
- 点击“流水”按钮。
- 抽屉标题和当前仓库一致。
- 搜索、日期筛选、分页能正常工作。
## 后续可选增强
- 增加“导出当前筛选流水”。
- 增加流水趋势图。
- 增加来源单据点击跳转。
- 增加按业务类型聚合的迷你统计。
@@ -0,0 +1,290 @@
# 生产日结与材料闭环设计
## 背景
真实生产不是一次领料后必须按参考生产数量一次性全部做完。常见场景是:今天领料生产一部分,下班前把已完成成品入成品库,把剩余原材料还回原材料库,第二天再次领料或继续生产。现有逻辑偏向“参考生产数量未做完则生产出库任务未结束”,会让 DAG 看起来像领料一直悬挂,无法表达阶段性生产和阶段性结算。
本设计目标是把生产出库从“一次性完工工单”改造为“可多次日结的生产任务”,用材料去向闭环替代计划数量闭环。
## 核心业务原则
1. 生产出库代表一次领料任务,不代表必须一次性完成全部参考生产数量。
2. 每次生产结束可以做一次“生产日结”,记录本次报工、成品入库、余料归还、废料/报废和差异原因。
3. 任务是否结束,不再只看 `完工数 >= 参考生产数量`,而是看领出的材料是否已经有明确去向。
4. 成品入库、生产余料入库、生产废料入库都要能挂到同一次生产日结下。
5. DAG 要展示“领料任务 -> 多次生产日结 -> 各类入库/报废 -> 任务结清”的真实链路。
## 新增概念
### 生产出库任务
沿用现有生产出库/工单主体,语义调整为“领料任务”。它记录:
- 生产跟踪号
- 产品
- 领用原材料库存批次
- 领用重量
- 参考生产数量
- 当前材料闭环状态
参考生产数量仍保留,但只作为参考值,不再是唯一闭环标准。
### 生产日结单
新增一个业务对象,建议表名为 `pp_production_settlement`,用于记录某个生产出库任务的一次阶段性结算。
建议字段:
- `settlement_no`:日结单号
- `work_order_id`:生产出库任务 ID
- `settlement_date`:结算日期
- `reported_qty`:本次报工数量
- `finished_qty`:本次合格成品数量
- `scrap_qty`:本次报废数量
- `standard_consumed_weight_kg`:标准消耗重量
- `expected_surplus_weight_kg`:标准应归还余料重量
- `actual_surplus_weight_kg`:实际余料归还重量
- `site_carryover_weight_kg`:现场留存重量,用于记录当天不还仓、继续留在生产现场的材料重量
- `scrap_weight_kg`:废料或报废折算重量
- `variance_weight_kg`:差异重量
- `variance_rate`:差异率
- `variance_reason`:偏差原因
- `status`:草稿、已确认、异常确认、已撤销
标准消耗公式:
```text
标准消耗重量 = 本次报工数量 × 产品毛重
```
标准应归还余料:
```text
标准应归还余料 = 结算前未闭环现场余额 - 标准消耗重量 - 废料/报废折算重量 - 现场留存重量
```
偏差率:
```text
偏差率 = abs(实际余料归还重量 - 标准应归还余料) / 标准应归还余料
```
当标准应归还余料为 0 时,使用差异重量是否为 0 判断;如存在差异,要求填写原因。
## 状态规则
生产出库任务建议状态:
- `已领料`:已经完成生产出库,还没有日结。
- `生产中`:已有小程序报工或工序进度,但尚未结算。
- `部分结算`:至少存在一张已确认生产日结单,但材料尚未全部闭环。
- `待结清`:理论上仍有未处理材料、未入库成品或未解释差异。
- `已结清`:领料重量已经通过成品、余料、废料、允许损耗和差异原因完成闭环。
- `异常结清`:偏差超过阈值,用户填写原因后确认结清。
偏差阈值默认使用 10%。超过 10% 时,必须填写偏差原因才能确认日结。
## 材料闭环判断
一个生产出库任务的材料闭环按重量判断:
```text
领料总重量
= 已结算标准消耗重量
+ 已归还余料重量
+ 已入废料/报废重量
+ 允许损耗重量
+ 已解释差异重量
+ 未结清现场余额
```
系统展示时要明确区分:
- 已生产消耗
- 已余料归还
- 已报废/废料入库
- 已解释差异
- 未结清现场余额
只有未结清现场余额为 0,且所有超过阈值的差异都有原因时,任务才能进入已结清或异常结清。
如果用户当天不把剩余材料全部还仓,而是留在现场第二天继续生产,则在生产日结中填写“现场留存重量”。这部分重量不会形成余料入库流水,也不会让任务结清;它会作为下一次生产日结的结算前未闭环现场余额。
## 出入库联动
### 成品入库
成品入库从生产日结单发起或关联生产日结单。每张生产日结单可以对应一张或多张成品入库记录,但推荐前端默认合并为一次成品入库操作。
成品批次要记录:
- 生产出库任务
- 生产日结单
- 原材料库存批次来源
- 入库数量
- 入库重量
- 入库材料成本
### 生产余料入库
生产余料入库必须关联生产日结单和来源库存批次。归还逻辑仍然是回到原库存批次,不新建库存批次。
页面展示:
- 来源库存批次号,多选
- 每个来源库存批次的归还重量
- 标准应归还重量
- 实际归还重量
- 现场留存重量
- 偏差率
- 超过 10% 时填写原因
### 生产废料入库
生产废料入库可以关联生产日结单。用于记录边角料、废料和报废折算进入废料库。
如果废料入库重量来自报废数量折算,系统应显示计算依据;如果用户直接称重录入,则以称重为准。
## DAG 展示设计
DAG 从当前“生产出库后直接挂工序、报工、成品入库”调整为分层展示:
```mermaid
flowchart LR
A["原材料库存批次"] --> B["生产出库任务"]
B --> C1["生产日结 2026-06-02"]
B --> C2["生产日结 2026-06-03"]
C1 --> D1["成品入库"]
C1 --> E1["生产余料入库"]
C1 --> F1["生产废料入库"]
C2 --> D2["成品入库"]
C2 --> E2["生产余料入库"]
C2 --> F2["生产废料入库"]
B --> G["任务结清状态"]
```
节点层级:
- Level 0:原材料库存批次
- Level 1:生产出库任务
- Level 2:生产日结单
- Level 3:工序报工汇总、成品入库、余料入库、废料入库
- Level 4:销售出库或后续追溯节点
DAG 节点指标:
- 生产出库任务节点:领料重量、参考生产数量、累计日结数量、未结清现场余额、状态。
- 生产日结节点:本次报工、合格品、报废、标准消耗、标准余料、实际余料、偏差率。
- 未结清现场余额节点或指标:展示仍留在现场、尚未还仓或尚未解释去向的材料重量。
- 成品入库节点:入库数量、来源库存批次、材料成本。
- 余料入库节点:归还库存批次、归还重量、偏差说明。
- 废料入库节点:废料重量、来源日结、处理状态。
DAG 视觉规则:
- 未结清任务用黄色状态。
- 偏差超过阈值且未写原因用红色状态。
- 已结清任务用绿色状态。
- 生产日结节点按日期从上到下排列。
- 点击生产出库任务时,高亮所有关联日结和出入库链路。
- 点击某个生产日结时,只高亮该日结对应的成品、余料和废料链路。
## 前端交互
### 生产出库列表
新增或调整列:
- 生产跟踪号
- 产品
- 领料重量
- 参考生产数量
- 累计报工数量
- 累计成品入库
- 累计余料归还
- 未结清现场余额
- 状态
操作:
- 查看 DAG
- 新增生产日结
- 查看日结记录
- 结清任务
### 新增生产日结抽屉
用户选择生产出库任务后,系统自动带出:
- 产品
- 产品毛重
- 领料来源库存批次
- 当前未结清重量
- 小程序报工汇总
- 可入库成品数量
用户填写或确认:
- 本次报工数量
- 本次成品入库数量
- 本次报废数量
- 本次余料归还重量
- 本次现场留存重量
- 本次废料入库重量
- 偏差原因
系统实时计算:
- 标准消耗重量
- 标准应归还重量
- 结算后未结清现场余额
- 实际归还偏差
- 偏差率
- 是否必须填写原因
## 后端接口
建议新增接口:
- `GET /production/work-orders/{id}/settlement-preview`
- `POST /production/work-orders/{id}/settlements`
- `GET /production/work-orders/{id}/settlements`
- `POST /production/settlements/{id}/confirm`
- `POST /production/work-orders/{id}/close`
现有接口调整:
- 成品入库接口支持传入 `settlement_id`。
- 生产余料入库接口支持传入 `settlement_id`。
- 生产废料入库接口支持传入 `settlement_id`。
- DAG 生命周期接口返回生产日结节点和日结关联的入库/报废节点。
## 数据迁移
已有历史生产出库可以不强制补日结单。迁移策略:
- 已完工且已有成品入库的生产出库,DAG 可继续按旧链路展示。
- 新增生产日结功能上线后,新生产出库默认走日结链路。
- 对历史未完成生产出库,可允许用户手工创建一张“历史补录日结单”进行结清。
## 测试要点
后端测试:
- 领料 200kg,报工 200 件,毛重 0.6kg,标准应归还 80kg。
- 偏差不超过 10% 时允许确认日结。
- 偏差超过 10% 且无原因时禁止确认。
- 多次日结累计后,未结清现场余额正确减少。
- 成品入库、余料入库、废料入库均能关联同一日结单。
- 任务结清不再依赖 `完工数 >= 参考生产数量`。
前端测试:
- 生产日结抽屉实时计算标准余料和偏差率。
- 超过 10% 时偏差原因必填。
- DAG 展示生产日结节点和多条出入库链路。
- 点击生产出库任务和点击日结节点的高亮范围不同。
## 非目标
本次设计不引入复杂 APS 排产,不管理员工排班,不强制要求每道工序都每日结算。小程序报工仍作为生产数量和报废数量来源,ERP 负责生产日结和库存闭环。
@@ -0,0 +1,177 @@
# 成品库返工入库设计
> 状态:已暂停,后续版本再做。
>
> 2026-06-03 业务决策:本版本不实现 `成品库 -> 返工入库`,也不切换为普通返工入库方案。本文仅保留为后续版本讨论参考,当前不可作为实施依据。
## 背景
当前 `退货库 -> 返工出库` 已经能把客户退回且可返工的产品从退货库出库,并生成退货处置记录和返工工单。但 `成品库` 还没有对应的 `返工入库` 入口,返工完成后的成品无法在仓库端形成明确闭环。
本设计采用方案 A:`成品库 -> 返工入库` 必须关联一条已经完成 `退货库 -> 返工出库` 的返工记录。这样能把客户退货、返工出库、返工完成回库、成品库存和原材料库存批次追溯串成一条完整链路。
## 目标
- 在 `嘉恒仓库 -> 成品库` 的入库区新增 `返工入库`。
- `返工入库` 必须选择产品,并关联该产品未完成回库的返工出库记录。
- 选择产品后,系统带出该产品对应的原材料库存批次号多选框,用 `JH...` 原材料库存批次号做追溯。
- 成品库仍以数量为主维度,重量只作为辅助信息或追溯信息,不作为主要库存口径。
- 入库后如果成品库已有该产品,则更新该产品库存余额;同时新增本次返工入库的库存明细和库存流水。
- 避免展示每个仓库自己的无业务意义内部批次号,前端展示时优先展示原材料库存批次号。
## 业务入口
`嘉恒仓库 -> 成品库 -> 入库 -> 返工入库`
该入口建议复用当前普通仓库入库抽屉样式,不另起一个完全不同的页面。字段建议为:
- 产品,必填。
- 返工出库记录,必填,只展示当前产品已返工出库且尚未完成返工入库的记录。
- 原材料库存批次号,可多选,选择范围按产品需规清单中该产品使用的原材料匹配库存批次。
- 入库数量,必填,必须大于 0。
- 入库材料成本,默认可按选中原材料库存批次成本和产品毛重计算,也允许用户按现有成品入库规则调整。
- 入库仓库和库位,默认成品库默认库位。
- 来源/提供方,可选,用于记录返工执行方或内部返工班组。
- 备注,可选。
## 数据流
返工闭环链路:
```text
发货明细
-> 退货库退货入库
-> 退货库返工出库
-> 退货返工处置记录
-> 成品库返工入库
-> 成品库存余额
-> 成品库存流水
-> 原材料库存批次号追溯
```
`返工入库` 创建成功后写入:
- 成品库库存批次明细,业务类型为 `返工入库`。
- 成品库库存余额,按产品数量累加。
- 成品库库存流水,流水类型为 `REWORK_IN` 或对应中文展示 `返工入库`。
- 返工处置记录关联的回库数量派生数据,来源于本次成品库库存批次和库存流水。
- 来源原材料库存批次号字段,用于后续成品库明细、销售出库、发货台账、退货追溯展示。
## 返工记录状态
返工出库记录不新增独立状态字段。本次通过 `成品库返工入库` 关联的库存批次和库存流水汇总已回库数量,并派生以下展示状态:
- `待回库`:已从退货库返工出库,但尚未做成品库返工入库。
- `部分回库`:返工入库数量小于返工出库数量。
- `已回库`:返工入库数量达到返工出库数量。
返工入库的库存批次和库存流水必须记录:
- `source_doc_type = RETURN_DISPOSITION`
- `source_doc_id = 返工处置记录ID`
- `source_line_id = 退货明细ID或返工处置记录ID`
待回库和部分回库列表按 `返工出库数量 - 已返工入库数量` 计算,避免额外维护一套容易不同步的状态字段。
## 数量规则
成品库返工入库以数量为主。
校验规则:
- 必须选择成品库。
- 必须选择产品。
- 必须选择返工出库记录。
- 返工出库记录的产品必须和入库产品一致。
- 入库数量必须大于 0。
- 入库数量不能超过该返工出库记录的剩余可回库数量。
- 原材料库存批次号可以多选;如果用户未选择,允许保存,但追溯信息会显示为空或未指定。
- 如果选择了原材料库存批次号,只记录追溯关系,不扣减原材料库存。
## 原材料库存批次追溯
返工入库的原材料库存批次号用于说明该返工成品来源于哪些原材料库存批次,不代表本次重新消耗原材料。
选择逻辑:
- 用户先选择产品。
- 系统根据产品需规清单找到该产品使用的原材料。
- 下拉多选框列出这些原材料在原材料库中的库存批次号。
- 可用批次优先展示,不可用批次置灰排后;是否允许勾选不可用批次按现有追溯选择组件规则执行。
- 保存后写入 `source_material_lot_id`、`source_material_sub_batch_no`、`source_material_summary` 等现有追溯字段。
展示规则:
- 成品库库存明细和流水中,`库存批次号` 展示应优先使用来源原材料库存批次号。
- 如果多个原材料库存批次号参与追溯,显示为 `JH...、JH...`。
- 不把成品库内部批次号作为主要业务展示字段。
## 成本规则
成品库页面中的成本字段沿用当前成品库口径:成品按件管理,成本按每件辅助展示。
返工入库建议默认成本:
```text
入库材料成本(毛重;元/件) = 选中原材料库存批次成本加权单价 × 产品毛重
```
如果没有选择原材料库存批次,或无法取到产品毛重,则默认成本为 0,并允许用户按现有成品入库规则手动填写或后续补录。
返工产生的额外人工成本仍保留在退货处置记录中,不在本次返工入库中重复计算,避免成本重复归集。
## UI 设计
成品库入库区新增一个 `返工入库` 操作按钮,和 `生产入库`、`委外入库`、`期初入库` 保持同一套风格。
抽屉交互:
1. 用户点击 `返工入库`。
2. 选择产品。
3. 返工出库记录下拉框刷新,只显示该产品待回库或部分回库记录。
4. 系统展示返工摘要,例如退货单、客户、返工出库数量、已回库数量、剩余可回库数量。
5. 原材料库存批次号使用标签多选框。
6. 用户填写入库数量、来源/提供方、备注。
7. 保存后关闭抽屉并刷新成品库库存、流水和返工记录状态。
## 接口与字典
建议新增入库业务类型:
- 内部值:`REWORK_IN`
- 中文展示:`返工入库`
- 允许仓库:`FINISHED`
- 库存流水类型:`REWORK_IN`
前端字典、状态展示和库存流水展示必须使用中文,不展示英文内部值。
## 错误提示
错误提示使用明确中文:
- `请选择返工出库记录`
- `该返工记录不属于当前产品`
- `返工入库数量必须大于0`
- `返工入库数量不能超过剩余可回库数量`
- `成品库不允许执行该入库业务`
## 测试重点
- 成品库入库区出现 `返工入库` 操作。
- 返工入库必须选择返工出库记录。
- 产品选择后,只列出该产品的待回库返工记录。
- 入库数量大于 0 才能提交。
- 入库数量超过剩余可回库数量时后端拒绝。
- 保存后成品库库存余额按数量增加。
- 保存后生成 `返工入库` 库存流水。
- 保存后返工记录状态更新为部分回库或已回库。
- 成品库库存明细和流水展示原材料库存批次号,而不是内部批次号。
- 原材料库存批次号只做追溯,不扣减原材料库存。
- 前端字典和值展示不出现英文 `REWORK_IN`。
## 非目标
- 本次不改小程序报工流程。
- 本次不把返工入库纳入普通生产工单完工入库结单逻辑。
- 本次不重做退货库返工出库,只补齐其在成品库的回库闭环。
- 本次不引入新的仓库维度或新的独立批次展示体系。
@@ -0,0 +1,480 @@
# 原材料库存批次驱动的生产工单与入库闭环设计
## 背景
当前 ERP 已经保留“工单台账”,小程序报工也已经能按生产相关标识回写 ERP。用户希望现场员工不要再理解复杂的“生产工单号”概念,而是围绕“材料库存批次号”报工:员工只要知道这批产品用的是哪一批材料,系统就能追溯到材料入库成本、成品入库、发货和利润。
本设计保留 ERP 内部的生产工单台账,但把生产执行入口和小程序选择语义调整为“材料库存批次号驱动”。ERP 工单继续承担生产过程容器的职责,负责承接领料、报工、成品入库、余料入库、废料入库和结单。
## 目标
- 原材料库存批次号改为原材料库全库统一递增,不再按物料分别递增。
- 原材料库存批次号默认格式为 `YL0001`,前缀从“系统拓展”配置,不配置默认 `YL`。
- 批次数字不足 4 位补 0,超过 `9999` 后自然扩展为 5 位及以上,例如 `YL9999 -> YL10000`。
- 原材料库“生产出库”强制一次只能选择一个原材料库存批次。
- 生产工单号改为 `YYYYMMDD-库存批次号-产品名称`,例如 `20260607-YL0001-钢制碗`。
- 同一天、同一个库存批次号、同一个产品的生产出库合并为同一张未结单工单。
- 小程序原“工单号”业务语义调整为“材料库存批次号”,员工按材料库存批次号报工。
- 嘉恒仓库“流水”按钮旁新增“生产工单入库”入口,统一处理成品入库、生产余料入库、生产废料入库。
- “生产工单入库”中系统计算理论成品、理论余料、理论废料作为辅助默认值,用户可修改。
- 当用户修改余料或废料后,与理论值偏差超过上下 15%,必须弹窗填写说明,但不禁止入库。
- “生产工单入库”不默认结单。只有用户主动勾选“本次入库后结单”才结单,并且提交前必须二次确认。
## 非目标
- 不取消工单台账。
- 不把 ERP 内部所有生产关系改成只靠字符串批次号追溯,核心追溯仍依赖数据库主键和外键关系。
- 不在初版强制限制理论成品、理论余料、理论废料的入库上限,只做偏差说明。
- 不在初版重构所有历史成品批次号、废料批次号、半成品批次号的编号规则。
- 不在初版做复杂的多原材料批次混合生产。生产出库阶段先强制单原材料库存批次。
## 编号规则
### 原材料库存批次号
新增系统拓展配置项:
```text
配置项名称:原材料库存批次号前缀
配置项编码:RAW_MATERIAL_LOT_PREFIX
默认值:YL
```
生成规则:
```text
批次号 = 前缀 + 序号
```
序号规则:
- 在原材料库范围内统一递增。
- 只统计符合“当前前缀 + 纯数字”的原材料库存批次号。
- 数字不足 4 位时左侧补 0。
- 数字达到 10000 后不截断、不回卷,直接显示完整数字。
示例:
```text
YL0001
YL0002
YL9999
YL10000
YL10001
```
如果后续把前缀从 `YL` 改成 `RM`,则新批次按 `RM0001` 重新从该前缀的最大序号递增。历史 `YL` 批次不改号。
### 生产工单号
生产工单号格式:
```text
YYYYMMDD-库存批次号-产品名称
```
示例:
```text
20260607-YL0001-钢制碗
```
日期按服务器业务时间所在日期生成,使用当前项目部署时区。产品名称做长度截断,保证不超过数据库字段长度。
## 生产出库规则
原材料库“生产出库”从多选库存批次改为单选库存批次。
提交校验:
- 必须选择产品。
- 必须选择且只能选择一个原材料库存批次。
- 选择的库存批次必须属于该产品需规清单默认用料。
- 选择的库存批次必须属于原材料库。
- 选择的库存批次必须可用且质检合格。
- 本次出库重量必须大于 0,且不能超过该批次可用重量。
### 同日同批同产品合并
提交生产出库时,系统按以下条件查找工单:
```text
工单日期 = 当天
产品 = 当前产品
来源原材料库存批次 = 当前选择批次
状态 != 已结单
```
如果找到,则本次生产出库合并到已有工单:
- 追加一条工单领料明细。
- 扣减该库存批次剩余重量。
- 增加工单领料重量。
- 按 BOM 单件毛重重新计算参考计划生产数。
- 工单号不变。
如果未找到,则新建工单:
- 工单号按 `YYYYMMDD-库存批次号-产品名称` 生成。
- 新建工单物料、工序路线。
- 写入工单领料明细。
- 扣减原材料库存批次。
如果同日同批同产品的工单已结单,本次不合并旧工单,直接拦截:
```text
该库存批次今日对应产品的生产工单已结单,不能继续合并生产出库。
```
这样避免结单后再次追加领料,造成闭环记录不可信。
## 小程序报工语义
小程序界面原“工单号”业务语义调整为:
```text
材料库存批次号
```
为降低上线风险,接口字段名可以先保持原字段,例如继续使用小程序现有的 `raw_material_batch_no` 或原“工单号”字段承载值,但页面展示文案和业务解释改为“材料库存批次号”。
小程序报工传回 ERP 时,ERP 后端按以下信息匹配生产工单:
```text
产品
工序
材料库存批次号
未结单状态
```
匹配逻辑:
- 先通过材料库存批次号找到原材料库存批次。
- 再找该产品、该批次关联的未结单生产工单。
- 再按小程序扫码上下文中的工序名称匹配工单工序。
- 匹配成功后报工写入该工单和该工序。
- 匹配失败时返回清晰错误,提示 ERP 还没有为该产品和该材料批次创建生产出库工单。
结单后的工单不再参与小程序待选项,也不再接收小程序报工。
## 生产工单入库入口
在嘉恒仓库页面,“流水”按钮旁新增:
```text
生产工单入库
```
入口跟随嘉恒仓库整体,不放在某一个具体仓库的入库/出库行里。因为这个操作一次会同时影响成品库、原材料库和废料库。
点击后打开较宽抽屉,避免表格和计算字段拥挤。该入口不使用小弹窗承载主流程。
## 生产工单入库交互
第一步选择生产工单:
- 下拉只显示未结单生产工单。
- 显示格式建议为 `工单号 · 产品 · 领料重量kg · 已入库成品数`。
- 支持搜索工单号、产品、材料库存批次号。
选择工单后展示工单摘要:
- 工单号
- 产品名称
- 材料库存批次号
- 领料重量
- 单件毛重
- 单件净重
- 参考计划生产数
- 当前已报工成品数
- 当前已报工废品数
- 已入库成品数
- 已归还余料重量
- 已入库废料重量
用户填写:
- 成品入库数量
- 余料入库重量
- 废料入库重量
- 备注
- 本次入库后结单,默认不勾选
当用户输入“成品入库数量”后,系统自动计算并填入:
- 理论余料入库重量
- 理论废料重量
用户可以直接修改系统填入的值。
## 理论值计算
设:
```text
领料重量 = L
成品入库数量 = Q
产品单件毛重 = G
产品单件净重 = N
当前工单累计报废数量 = S
已归还余料重量 = R
已入库废料重量 = W
```
理论已用材料重量:
```text
Q * G
```
理论本次余料入库重量:
```text
max(L - R - Q * G, 0)
```
理论本次废料重量:
```text
max(Q * (G - N) + S * G - W, 0)
```
说明:
- 初版理论值只作为辅助默认值。
- 不作为硬性库存上限。
- 用户可以自由修改。
- 如果理论值为 0,而用户填写了大于 0 的值,应视为超过 15% 偏差,需要填写说明。
## 15% 偏差说明
当用户提交时,系统比较实际填写值和理论值。
需要校验的字段:
- 余料入库重量
- 废料入库重量
偏差公式:
```text
偏差率 = abs(实际值 - 理论值) / 理论值
```
规则:
- 理论值大于 0,偏差率超过 15%,必须填写说明。
- 理论值等于 0,实际值大于 0,必须填写说明。
- 理论值等于 0,实际值等于 0,不需要说明。
弹窗文案示例:
```text
本次入库数据与理论值存在较大偏差
余料入库:
理论值:80kg
实际值:100kg
偏差:+25%
废料入库:
理论值:12kg
实际值:10kg
偏差:-16.67%
请填写偏差说明后继续入库。
```
用户填写说明后,可以继续提交。说明必须写入相关库存流水和工单备注/扩展记录中,保证后续可查。
## 结单确认
“本次入库后结单”默认不勾选。
只有用户主动勾选后才结单。勾选后提交,必须弹出二次确认框。
确认框展示:
```text
请确认本次生产工单入库
工单:20260607-YL0001-钢制碗
成品入库:xxx 件
余料入库:xxx kg
废料入库:xxx kg
偏差说明:xxx
勾选结单后:
1. 该工单状态将变为已结单
2. 小程序不再显示该工单对应的材料库存批次号
3. 后续不能再对该工单做生产工单入库
4. 该工单对应的成品、余料、废料流水将作为最终闭环记录
```
用户确认后才提交。
## 入库落账
生产工单入库提交后,根据用户填写值分别落账。
### 成品库
如果成品入库数量大于 0:
- 生成成品库生产入库流水。
- 增加成品库存数量。
- 重量作为辅助信息,可按成品数量和单件毛重/净重计算或记录为辅助重量。
- 成品批次必须记录来源原材料库存批次号。
- 成品入库关联生产工单。
### 原材料库
如果余料入库重量大于 0:
- 生成原材料库生产余料入库流水。
- 余料归还到原材料原库存批次,不新建独立余料批次。
- 增加该库存批次剩余重量。
- 流水备注写明“生产余料入库”和偏差说明。
- 更新工单已归还余料重量。
### 废料库
如果废料重量大于 0:
- 生成废料库生产废料入库流水。
- 废料明细记录来源原材料库存批次号。
- 增加废料库存重量。
- 流水备注写明“生产废料入库”和偏差说明。
- 更新工单已入库废料重量。
## 工单台账展示
工单台账保留,并强化以下字段:
- 生产工单号
- 产品名称
- 材料库存批次号
- 领料重量
- 参考计划生产数
- 各工序累计成品报工
- 各工序累计废品报工
- 已入库最终成品数
- 已归还余料重量
- 已入库废料重量
- 状态
状态至少包含:
- 进行中
- 已结单
工单台账中的材料库存批次号应显示短批次号,例如 `YL0001`,并在详情里展示对应原材料名称、规格、单价、来源入库单等追溯信息。
## 数据结构影响
初步涉及以下数据:
- `wh_stock_lot.lot_no`:原材料库存批次号生成规则改变。
- `pp_work_order.work_order_no`:生产工单号生成规则改变。
- `pp_work_order_material_issue.source_lot_id`:继续作为工单和原材料库存批次的核心关联。
- `pp_work_order_material_issue.material_sub_batch_no`:后续语义应等同于来源原材料库存批次号,值保存短批次号。
- `wh_inventory_txn`:继续记录所有库存流水。
- 系统拓展配置表:新增原材料库存批次号前缀配置。
如果现有配置表不适合存储该项,可沿用项目当前“系统拓展”模块已有配置结构,不新增独立配置系统。
## 兼容与历史数据
历史原材料库存批次号不强制立即改号,除非用户明确要求清理测试环境或迁移展示效果。
新入库批次使用新规则。
历史工单号不强制改号。新生产出库产生或合并的工单使用新规则。
小程序同步报工在过渡期应兼容旧值:
- 如果传入值是新材料库存批次号,按新逻辑匹配工单。
- 如果传入值是旧工单短码或旧工单号,可保留兼容一段时间,避免线上历史报工数据无法同步。
正式切换后,小程序展示文案应统一为“材料库存批次号”。
## 错误处理
生产出库常见错误:
- 未选择库存批次:提示“生产出库必须选择一个材料库存批次号”。
- 选择多个库存批次:提示“一次生产出库只能选择一个材料库存批次号”。
- 批次不可用:提示具体批次号和不可用原因。
- 批次不属于产品需规用料:提示“该材料库存批次不属于当前产品需规默认用料”。
- 同日同批同产品工单已结单:提示不能继续合并。
生产工单入库常见错误:
- 未选择工单:提示“请选择生产工单”。
- 工单已结单:提示“该生产工单已结单,不能继续入库”。
- 成品、余料、废料均为 0:提示“本次至少填写一项入库数据”。
- 偏差超过 15% 且无说明:弹窗要求填写说明。
小程序报工常见错误:
- 材料库存批次号不存在。
- 当前产品和材料库存批次没有未结单生产工单。
- 当前工序不属于匹配到的生产工单。
错误提示必须使用中文,不允许暴露英文状态码或内部字段名。
## 测试策略
后端测试:
- 原材料库存批次号默认从 `YL0001` 开始。
- 自定义前缀生效。
- `YL9999` 后生成 `YL10000`。
- 不同物料共用同一个原材料库递增序列。
- 生产出库选择多个库存批次被拒绝。
- 同日同批同产品重复生产出库合并到同一工单。
- 同日同批同产品已结单后再次生产出库被拒绝。
- 生产工单入库能同时写成品库、原材料库、废料库流水。
- 余料/废料偏差超过 15% 时必须填写说明。
- 勾选结单后工单状态变为已结单。
- 未勾选结单时工单保持进行中。
前端测试:
- 原材料库生产出库 UI 只能选择一个材料库存批次号。
- 生产出库提交 payload 只包含一个库存批次。
- 嘉恒仓库流水按钮旁显示“生产工单入库”。
- 生产工单入库选择工单后自动填理论值。
- 修改成品数量后自动重算余料和废料理论值。
- 偏差超过 15% 时弹出说明框。
- 未勾选结单时不弹结单影响确认。
- 勾选结单时弹出结单影响确认。
集成测试:
- 原材料入库生成 `YL0001`。
- 原材料生产出库生成 `20260607-YL0001-产品名称`。
- 小程序报工传 `YL0001` 能同步到对应工单和工序。
- 生产工单入库后,成品批次能追溯到 `YL0001`。
- 销售出库后,发货台账能看到来源原材料库存批次号和材料成本。
## 实施顺序建议
1. 新增系统拓展配置和原材料库存批次号生成规则。
2. 调整采购入库、客料入库、特殊入库等原材料入库路径,统一使用新批次号生成。
3. 调整生产出库为单库存批次,并实现同日同批同产品工单合并。
4. 调整小程序报工同步逻辑,按材料库存批次号匹配未结单工单。
5. 新增生产工单入库后端接口。
6. 新增嘉恒仓库“生产工单入库”前端入口和交互。
7. 联调工单台账、成品入库、余料入库、废料入库、发货追溯。
8. 补齐自动化测试和启动检查。
## 待用户确认后进入计划
本设计已按用户确认规则固定:
- 原材料库存批次号默认格式为 `YL0001`。
- “生产工单入库”不默认勾选“本次入库后结单”。
- 只有用户主动勾选结单,并确认结单影响后,才执行结单。
用户确认本设计文档后,再拆分具体实现计划并进入代码实现。
@@ -0,0 +1,108 @@
# 系统权限管理组织视图与人员授权设计
## 背景
系统权限管理当前已经具备组织脑图、人员绑定、系统人员、角色维护等能力,但“人员与角色维护”把账号维护和角色维护放在同一页签内,页面职责混杂。用户要求把系统账号创建与角色授权回收到组织架构里的人员节点上完成,同时在组织脑图旁增加“脑图 / 组织树”两种组织展示方式。
## 目标
- `组织脑图`页签调整为更准确的`组织架构`页签。
- `组织架构`页签内增加视图切换:`脑图模式`与`组织树模式`。
- `人员与角色维护`重命名为`角色维护`,只保留角色新增、编辑、菜单权限配置。
- 系统账号创建与人员角色授权不再通过单独“系统人员”表维护,而是在组织架构中的人员节点上完成。
- 两种组织视图共用同一套组织数据、人员绑定数据、角色数据、系统账号接口。
## 组织架构视图
### 脑图模式
脑图模式沿用现有 `OrgMindMap` 组件。组织节点继续通过右键菜单维护:
- 总公司:重命名、新增分公司节点、添加该节点的主管。
- 分公司:重命名、新增部门节点、添加该节点的主管、删除节点。
- 部门:重命名、新增小组节点、新增人员、添加该节点的主管、删除节点。
- 小组:重命名、新增人员、添加该节点的主管、删除节点。
人员叶子节点右键菜单只保留两项:
- `授权`:打开人员授权抽屉。
- `移除`:从当前组织节点移除该人员,不删除基础资料人员主数据,不删除已有系统账号。
### 组织树模式
组织树模式采用左树右表布局:
- 左侧为组织节点树,显示总公司、分公司、部门、小组,节点支持展开、收起、选中。
- 左侧组织节点同样支持右键菜单,与脑图模式的组织节点菜单一致。
- 右侧显示当前选中组织节点下直接绑定的人员列表。
- 人员列表使用项目全局表格风格和 `PaginationBar` 分页。
- 人员列表行操作提供`授权`、`移除`。
- 右侧提供`新增人员`入口,将基础资料人员绑定到当前组织节点。
## 授权抽屉
人员授权抽屉由脑图人员节点右键`授权`和组织树人员行`授权`共同打开。抽屉展示:
- 人员姓名。
- 电话号码 / 账号。
- 所属组织。
- 当前系统账号状态。
- 角色多选。
- 密码输入框。
保存规则:
- 如果人员没有电话号码,禁止创建系统账号,提示“该人员没有电话号码,不能作为账号”。
- 如果人员已有系统账号,密码不必填;保存时只调用系统账号角色更新接口。
- 如果人员没有系统账号,密码必填且最少 6 位;保存时先创建系统账号,账号为人员电话号码,再绑定所选角色。
- 角色必须至少选择一个。
- 保存成功后刷新组织树、角色、系统人员缓存,使人员节点展示的角色信息同步更新。
## 角色维护页签
`人员与角色维护`改为`角色维护`,移除内层子页签。该页只展示角色表格、角色分页和新增角色按钮。角色抽屉继续负责:
- 角色编码。
- 角色名称。
- 角色范围。
- 状态。
- 备注。
- 菜单权限树。
系统人员列表、重置密码、账号启停不再作为主页面入口。本次只移除独立维护入口;已有后端接口保留,供授权抽屉复用。
## 数据与接口
本次优先复用现有接口,不新增表结构:
- `GET /system-permissions/org-tree` 获取组织节点与人员叶子。
- `POST /system-permissions/org-nodes/{node_id}/employees` 绑定人员。
- `DELETE /system-permissions/org-nodes/{node_id}/employees/{employee_id}` 移除人员。
- `GET /system-permissions/employee-options` 获取基础资料人员。
- `GET /system-permissions/users` 获取系统账号,用于判断人员是否已有账号。
- `POST /system-permissions/users` 创建系统账号。
- `PUT /system-permissions/users/{user_id}/roles` 更新系统账号角色。
- `GET /system-permissions/roles` 获取角色。
- `POST /system-permissions/roles` 创建角色。
- `PUT /system-permissions/roles/{role_id}` 更新角色与菜单权限。
## 测试与验收
- 静态 UI 测试应覆盖:顶层页签重命名、组织视图切换、组织树模式、人员授权入口、角色维护独立化、系统人员独立表移除。
- 前端构建必须通过 `npm run build`。
- 现有后端权限测试必须继续通过,证明复用接口没有被破坏。
- 浏览器检查应覆盖脑图模式右键授权、组织树模式人员行授权、角色维护页签三个主路径。
## 非目标
- 不新增复杂的部门独立维护页面。
- 不删除系统账号后端接口。
- 不改变基础资料人员管理和小程序人员主数据。
- 不做权限登录体系的大改造,本次只调整权限管理页的组织授权交互。
## 自检
- 无占位符。
- 两种组织视图共用同一套接口,没有产生双业务流。
- 账号创建入口已经从独立系统人员表迁移到人员节点授权。
- 角色维护保留原有菜单权限能力。
@@ -0,0 +1,439 @@
# 嘉恒仓库全出入库单据纸质化与归档设计
## 背景
嘉恒仓库已经有 6 大库:原材料库、半成品库、成品库、辅料库、废料库、退货库。当前出入库业务主要通过抽屉表单完成,保存后形成库存流水。用户已经认可 `原材料库 · 客料入库` 的纸质填单样板,但该样板目前只完成填写 UI,没有生成 PDF 归档,也没有预览和下载入口。
现有归档体系已覆盖销售订单、采购订单、到货入库单、质量校验单、生产领料出库单、生产入库结算单。仓库里大量非生产分支仍未纳入正式单据化:客料、委外、销售、退货、返工、特殊出入库、期初等。为避免后续继续碎片化,本方案把“所有仓库出入库填单纸质化、保存后 PDF 归档、流水入口预览下载、流水 Excel 导出”作为统一仓库单据化工程。
## 目标
1. 6 大库所有入库、出库填单页面改造成正式纸质化单据风格。
2. 每次出入库保存后生成 PDF 归档,业务保存成功但 PDF 失败不回滚业务。
3. 保存成功提示区提供 `预览PDF`、`下载PDF` 快捷入口。
4. 各库流水抽屉中每条流水展示 `单据留档`,支持预览、下载、重新生成。
5. 物料/库存批次明细中的库存流水也能看到对应 PDF 留档入口。
6. `生产台账入库` 这类一次生成多个仓库流水的动作,使用一张 `生产入库结算单`,多条流水共用同一归档。
7. 各库流水模块支持按当前筛选条件,尤其是时间范围,导出 Excel 清单。
8. PDF 和 Excel 中不使用前端省略号逻辑,长字段完整换行或完整输出。
## 范围
### 覆盖仓库
- 原材料库
- 半成品库
- 成品库
- 辅料库
- 废料库
- 退货库
### 覆盖入口
原材料库:
- 期初入库
- 客料入库
- 生产余料入库
- 委外余料入库
- 特殊入库
- 生产出库
- 委外出库
- 退货出库
- 报废出库
- 特殊出库
半成品库:
- 产中入库
- 期初入库
- 委外入库
- 特殊入库
- 产中出库
- 委外出库
- 特殊出库
成品库:
- 生产入库
- 返工入库
- 委外入库
- 期初入库
- 特殊入库
- 销售出库
- 特殊出库
辅料库:
- 期初入库
- 特殊入库
- 生产出库
- 特殊出库
废料库:
- 生产废料入库
- 返工废料入库
- 期初入库
- 委外废料入库
- 退货废料入库
- 特殊入库
- 售卖出库
- 特殊出库
退货库:
- 期初入库
- 退货入库
- 特殊入库
- 返工出库
- 特殊出库
跨库工具:
- 生产台账入库
## 单据归档类型
### 生产专用单据
保持现有设计:
- `生产领料出库单`
- `生产入库结算单`
这些单据用于生产主链路,不再重复映射到通用仓库作业单,避免一笔生产业务出现两套 PDF。
### 通用仓库作业单
新增通用归档类型:
- `仓库出入库单`
该类型覆盖除生产专用单据外的所有仓库出入库按钮。PDF 标题根据仓库和业务类型动态生成,例如:
- `客料入库单`
- `委外余料入库单`
- `委外出库单`
- `销售出库单`
- `退货入库单`
- `返工出库单`
- `特殊入库单`
- `售卖出库单`
通用类型的好处是后端只需一个归档收集器和一个路由 key,所有仓库业务通过配置映射生成不同标题与字段。
## 归档业务主键
### 单条库存流水动作
以本次业务动作形成的主 `wh_inventory_txn.id` 作为 `business_id`。
适用:
- 客料入库
- 委外出库
- 报废出库
- 售卖出库
- 期初入库
- 大多数普通入库/出库
### 多条库存流水动作
以主库存流水 ID 作为 `business_id`,同一动作产生的其它库存流水通过 `document_batch_no` 或关联表映射到同一归档。
适用:
- `生产台账入库`:使用现有 `生产入库结算单`,主流水优先级为成品入库、余料入库、废料入库。
- 后续若某个普通仓库动作一次形成多条流水,也沿用同样主流水规则。
### 特殊出入库
特殊出入库要保留“必须填写说明”的业务约束。若特殊调整有主表,则优先以特殊调整主表 ID 作为归档业务主键;若当前实现只有库存流水,则以本次特殊调整的主库存流水 ID 作为归档业务主键。PDF 必须完整展示调整说明和每条明细的调整前后数量/重量。
### 已有关联业务单据
如果某个仓库动作本质已经有更上游单据:
- 采购到货入库保留 `到货入库单`
- 销售订单保留 `销售订单`
- 生产主链路保留生产专用单据
但仓库内实际发生出库/入库时,仍应能从仓库流水看到该次仓库作业的留档。如果该仓库动作已有专用归档,则流水指向专用归档;否则指向 `仓库出入库单`。
## 纸质填单 UI 规则
### 通用结构
所有仓库出入库抽屉采用统一纸质单据底座:
- 抬头:嘉恒仓库、单据标题、单据编号或提交后生成提示。
- 基础信息区:仓库、库位、业务类型、来源/去向、经办人、时间。
- 明细区:物料/产品/半成品/废料/退货品、库存批次号、来源库存批次号、数量、重量、单价、金额。
- 辅助信息区:运单号、运费、辅助照片、用途、包装备注、退货/返工/委外方、说明。
- 备注区:用户备注和系统生成说明。
- 签核区:制单、仓库确认、业务确认、复核。
- 底部固定操作区:保存按钮、保存中状态。
### 业务字段不删减
纸质化只是表现层升级,不改变原有业务字段和校验。已有字段必须保留,只调整布局、标题、分区和视觉样式。此前用户明确要求去掉的字段除外。
### 保存后反馈
保存成功后显示:
- 业务保存结果
- PDF 归档状态
- `预览PDF`
- `下载PDF`
如果 PDF 失败:
- 显示 `PDF归档失败`
- 显示中文失败原因
- 提供 `重新生成`
- 不回滚库存流水
## PDF 内容规则
PDF 是业务快照,以保存后的数据库事实为准,不从前端表单重新计算。
PDF 必须包含:
- 单据标题
- 单据编号
- 业务时间
- 仓库和库位
- 业务类型
- 经办人
- 物料/产品/半成品/废料/退货品信息
- 库存批次号
- 来源库存批次号
- 数量/重量
- 单价/金额
- 运单号、运费、辅助照片链接或照片存在标记
- 业务说明和备注
- 关联采购单、销售单、生产台账、发货批次、退货处置等追溯信息
PDF 不得出现:
- 英文状态值
- 前端省略号
- 超出单元格的长文本
- 无业务意义的每库内部批次号
## 流水预览与下载入口
### 各库流水抽屉
在 `嘉恒仓库 -> 工具 -> 流水` 中新增 `单据留档` 列。
每条流水根据后端返回的归档字段展示:
- `未生成`
- `已归档`
- `归档失败`
- `预览PDF`
- `下载PDF`
- `重新生成`
### 库存明细右侧流水
物料/批次详情抽屉中的库存流水也新增 `单据留档`,行为与仓库流水一致。
### 生产台账入库
`生产台账入库` 保存后若一次生成成品、余料、废料多条流水,这几条流水的 `单据留档` 指向同一张 `生产入库结算单`。
## 流水 Excel 导出
### 入口位置
在各库流水抽屉顶部筛选区增加 `导出Excel` 按钮,放在 `查询` 按钮旁边。
### 导出范围
导出使用当前流水筛选条件:
- 当前仓库类型
- 当前仓库 ID
- 关键词
- 流水方向
- 流水类型
- 物料
- 库存批次号
- 开始日期
- 结束日期
- 排序字段
- 排序方向
如果用户没有选择时间范围,允许导出当前筛选条件下所有流水,但前端需要轻提示“当前未选择时间范围,将导出全部匹配流水”。第一版不强制时间范围,避免阻塞真实查账场景。
### Excel 字段
导出的 Excel 至少包含:
- 业务时间
- 仓库
- 库位
- 方向
- 流水类型
- 物料/产品编码
- 物料/产品名称
- 库存批次号
- 来源库存批次号
- 数量变化
- 重量变化
- 单价
- 金额
- 来源单据
- 经办人
- 运单号
- 运费
- 辅助照片
- 备注
- PDF归档状态
- PDF归档业务ID
Excel 需使用中文表头,冻结表头,自动筛选,合理列宽。
## 后端设计
### 归档服务
在 `document_archives.py` 中新增:
- `DOCUMENT_TYPE_WAREHOUSE_OPERATION = "仓库出入库单"`
- `collect_warehouse_operation_archive_context`
通用收集器根据主库存流水读取:
- 主库存流水
- 相关库存流水
- 库存批次
- 来源库存批次
- 仓库和库位
- 关联采购/销售/退货/发货/生产台账信息
- 物流字段
- 特殊调整说明
### 路由
`/document-archives/{document_type_key}/{business_id}/...` 增加:
- `warehouse-operation`
### 仓库保存接口
所有普通仓库出入库保存成功后:
1. 完成库存业务事务。
2. 提交业务数据。
3. 生成 PDF 归档。
4. 返回归档状态。
生产专用动作保持现有生产归档类型。
### 流水接口
`GET /inventory/transaction-ledger` 返回每行归档字段:
- `archive_status`
- `archive_business_id`
- `archive_document_type`
- `archive_error_message`
### Excel 导出接口
新增:
- `GET /inventory/transaction-ledger/export`
该接口接收与流水查询一致的筛选参数,返回 `.xlsx` 文件。
## 前端设计
### 单据化表单
抽出通用仓库纸质表单组件:
- `WarehouseDocumentFormShell`
- `WarehouseDocumentGrid`
- `WarehouseDocumentActionBar`
- `WarehouseArchiveShortcut`
`原材料库 · 客料入库` 样板迁移到通用组件上,其它表单逐步替换。
### PDF 操作组件
复用现有 `DocumentArchiveActions`,不再做第二套预览/下载按钮。
### Excel 导出
仓库流水抽屉筛选区新增 `导出Excel`。
导出时:
- 按钮显示 `导出中...`
- 禁止重复点击
- 使用 `downloadResource`
- 文件名格式:`{仓库名}出入库流水_{开始日期或全部}_{结束日期或全部}.xlsx`
## 实施分期
### Phase 1:底座和入口
- 新增通用 `仓库出入库单` 归档类型。
- 仓库流水接口返回归档字段。
- 仓库流水新增预览/下载/重新生成。
- 流水 Excel 导出。
- 客料入库补齐 PDF 归档。
### Phase 2:通用表单纸质化
- 期初入库
- 客料入库
- 委外余料入库
- 委外出库
- 报废出库
- 售卖出库
- 辅料生产出库
- 半成品产中/委外入出库
### Phase 3:专用业务表单纸质化
- 销售出库
- 退货入库
- 退货废料入库
- 返工出库
- 返工入库
- 返工废料入库
- 特殊出入库
### Phase 4:生产主链路统一入口
- 生产出库、生产台账入库、生产入库、生产余料入库、生产废料入库沿用生产专用 PDF。
- 仓库流水和生产台账详情统一指向同一份归档。
## 验收标准
1. 所有仓库出入库入口打开后都是纸质化单据风格。
2. 客料入库保存后能生成 `仓库出入库单` PDF,并可预览和下载。
3. 任意仓库流水行能看到归档状态;已归档可预览和下载。
4. `生产台账入库` 一次产生多条流水时,多条流水打开同一张 `生产入库结算单`。
5. PDF 失败不影响库存保存,页面显示失败并允许重新生成。
6. 各库流水可按时间范围导出 Excel。
7. Excel 内容符合当前筛选范围,中文表头完整,数值和备注不丢失。
8. PDF 和 Excel 均不出现英文状态值或截断省略号。
## 设计结论
全仓库单据化采用“通用仓库作业单 + 生产专用单据”的双轨方案:
- 普通仓库出入库统一归档为 `仓库出入库单`。
- 生产领料和生产入库结算继续使用生产专用单据。
- 所有单据都通过仓库流水、库存明细流水、保存成功反馈提供预览和下载入口。
- 各库流水导出 Excel 与当前筛选条件保持一致。
该方案能覆盖 6 大库所有出入库入口,又避免为每个按钮单独造一套 PDF 逻辑。
@@ -0,0 +1,93 @@
# Miniapp Operation Report Sync Design
## Goal
解决“生产执行 · 工序报工”每次刷新都要等待十几秒的问题。页面刷新只负责查看小程序报工列表,ERP 同步改成显式按钮触发;同步范围由系统固定为“从上次同步成功时间起自动补齐”,不允许用户手工选择同步时间,避免漏同步。
## Problem
当前前端进入页面或点击刷新时,请求 `/production/miniapp-operation-reports` 会带上 `sync_to_erp=true` 和 `limit=800`。后端接口默认也会执行同步逻辑,对每条小程序报工逐条匹配生产台账或旧工单、工序、员工、ERP 报工记录,并更新累计值。数据库在远程 MySQL 上,逐条查询和写入会被网络往返延迟放大,所以一次刷新可能需要十几秒。
## Business Rules
- `刷新列表` 只读取小程序报工数据,使用页面日期筛选范围,不能创建或更新 ERP 报工。
- `同步到 ERP` 不使用页面日期筛选范围。
- 同步范围固定为“上次同步成功时间之后,到本次同步开始时间止”。
- 如果没有上次同步成功时间,首次同步从现有小程序报工数据中最早的记录开始。
- 同步成功后更新上次同步成功时间。
- 同步失败时不更新上次同步成功时间,下次点击同步继续从旧时间补齐。
- 同步按钮在同步过程中显示加载状态并禁用,防止用户连续点击造成重复请求。
- 同一条小程序报工重复同步必须幂等,不能重复累计 ERP 报工数量。
- 页面日期筛选只影响“看哪些数据”,绝不影响“同步哪些数据”。
## Backend Design
新增一个明确的同步接口:
```text
POST /production/miniapp-operation-reports/sync
```
该接口不接受用户传入的开始日期和结束日期。服务端读取系统配置中的上次同步成功时间,计算本次同步窗口:
```text
sync_from = 上次同步成功时间,如果不存在则为空
sync_to = 当前服务端时间
```
查询范围使用小程序报工的更新时间或创建时间,保证历史日期的补报、修改、驳回也能被纳入同步。接口循环调用现有 `_sync_miniapp_item_to_erp()`,复用当前 ERP 报工幂等差额逻辑。同步全部成功后,更新上次同步成功时间为 `sync_to`。
同步状态存储复用 `sys_system_config`:
```text
config_code: MINIAPP_OPERATION_REPORT_LAST_SYNCED_AT
config_name: 小程序报工上次同步成功时间
config_value: 2026-06-11 10:30:00
```
为了降低重复请求风险,同步接口在更新配置前对该配置行加数据库锁。前端禁用按钮解决正常用户重复点击,后端锁解决异常并发请求。
## Frontend Design
工序报工页面顶部保留日期筛选和刷新按钮,并新增同步区:
- `刷新列表`:请求 `/production/miniapp-operation-reports?sync_to_erp=false`,只读加载当前日期范围内的小程序报工。
- `同步到 ERP`:请求 `POST /production/miniapp-operation-reports/sync`,按钮进入 `同步中...` 状态并禁用。
- 同步完成后自动调用 `刷新列表`。
- 页面显示上次同步成功时间。
- 成功提示展示本次同步范围和结果数量。
- 失败提示说明“同步失败,上次同步成功时间未更新,可稍后重试”。
## Response Shape
同步接口返回:
```json
{
"sync_from": "2026-06-01 10:00:00",
"sync_to": "2026-06-11 15:30:00",
"last_synced_at": "2026-06-11 15:30:00",
"total": 120,
"synced": 115,
"skipped": 5,
"failed": 0
}
```
`skipped` 表示小程序报工无法匹配有效生产台账、旧工单、有效工序,或没有有效数量。`failed` 初版只在单条同步被捕获为可恢复失败时使用;如果发生数据库级错误,接口直接失败并不更新同步时间。
## Error Handling
- 同步过程中出现数据库异常时,事务回滚,不更新 `MINIAPP_OPERATION_REPORT_LAST_SYNCED_AT`。
- 如果没有需要同步的数据,接口返回 `total=0`,并仍可更新上次同步成功时间为本次 `sync_to`,表示系统已经确认这一段时间没有新变化。
- 如果小程序报工被驳回,沿用现有 `_sync_miniapp_item_to_erp()` 对已同步报工的解绑逻辑。
- 前端同步失败时解除按钮禁用,并展示错误提示。
## Verification
- 后端测试覆盖列表接口 `sync_to_erp=false` 时不写 ERP。
- 后端测试覆盖同步接口从上次同步成功时间自动补齐,且不接受前端筛选范围。
- 后端测试覆盖同步成功后更新上次同步成功时间,失败时不更新。
- 前端静态测试覆盖列表刷新传 `sync_to_erp=false`。
- 前端静态测试覆盖同步按钮调用独立同步接口、同步中禁用、同步完成后刷新列表。
- 运行后端相关测试、前端静态脚本和前端构建。
@@ -0,0 +1,370 @@
# 生产主链路仓库单据化与 PDF 归档设计
## 背景
系统已经完成销售订单、采购订单、到货入库单、质量校验单的正式单据化与 PDF 归档。嘉恒仓库仍以业务抽屉和库存流水为主,用户在办理生产出库、生产入库、生产余料入库、生产废料入库时,缺少一张可预览、可下载、可留档的正式业务单据。
仓库业务入口很多,6 大库中存在采购、生产、委外、退货、销售、特殊调整等多条链路。如果一次性把所有出入库按钮都接入 PDF,容易形成重复模板和重复归档逻辑。本次先以生产主链路作为第一期样板,抽出仓库作业单通用底座,后续再扩展到委外、退货、销售出库、特殊出入库。
## 本期目标
1. 将生产主链路的仓库作业改造成“保存即归档”的正式业务单据。
2. 不改变现有库存、生产台账、生产工单的核心业务计算逻辑。
3. 后端基于业务保存后的真实数据生成 PDF 归档快照。
4. PDF 失败不阻断业务保存,但必须能在界面看到归档失败并重新生成。
5. 前端保持现有操作入口,只把相关弹窗和归档操作升级为正式单据体验。
6. 第一版先不做批量下载,待仓库单据类型稳定后再统一扩展。
## 本期范围
本期只覆盖生产主链路:
- 原材料库 · 生产出库
- 生产台账入口 · 生产工单入库
- 成品库 · 生产入库
- 原材料库 · 生产余料入库
- 废料库 · 生产废料入库
本期不覆盖:
- 委外入库、委外出库、委外余料入库、委外废料入库
- 销售出库
- 客料入库
- 退货出库、退货入库、退货废料入库、返工出库
- 特殊入库、特殊出库
- 盘库单
- 批量归档下载
## 单据类型
后端归档类型先新增两类:
1. `生产领料出库单`
2. `生产入库结算单`
### 生产领料出库单
对应原材料库的生产出库。
业务含义:把某个原材料库存批次号中的材料领出,用于生产某个产品。由于系统已经限制生产出库一次只能选择一个原材料库存批次,本单据天然对应“材料库存批次号 + 产品”的生产台账维度。
### 生产入库结算单
对应生产过程中的入库结算动作。
业务含义:围绕某个在生产的材料库存批次号和产品,登记本次成品入库、余料入库、废料入库。无论用户从“生产工单入库”合并入口办理,还是从成品库、原材料库、废料库的分支入口单独办理,都归档为同一种结算单。
这样可以避免同一件生产结算业务因为入口不同而生成不同结构的单据。
## 归档业务主键
现有 `document_archives` 表通过 `document_type + business_id + archive_version` 管理归档。生产主链路需要明确 `business_id` 的来源。
### 生产领料出库单
推荐以生产台账记录 ID 作为 `business_id`。
原因:
- 生产出库会形成或更新“材料库存批次号 + 产品”的生产台账。
- 同一天同一库存批次同一产品允许多次生产出库,但业务上累计到同一条生产台账。
- 生产领料出库单应该表达这条生产台账当前的领料出库快照,而不是某一条孤立库存流水。
归档版本规则:
- 每次生产出库后,对同一生产台账生成新版本 `生产领料出库单`。
- 列表和详情默认展示最新版本。
- 历史版本保留,用于追溯每次领料变化后的快照。
### 生产入库结算单
推荐以本次入库动作形成的主库存流水 ID 作为 `business_id`。
原因:
- 生产工单入库合并入口一次可同时产生成品入库、余料入库、废料入库三类库存流水。
- 分支入口按入口类型只产生对应的一类库存流水。
- 归档单要代表“本次保存动作”,而不是覆盖整条生产台账。
对于合并入口,如果一次保存产生多条库存流水,需要在后端确定一条“主流水”:
- 优先使用成品入库流水。
- 如果没有成品入库流水,使用余料入库流水。
- 如果没有余料入库流水,使用废料入库流水。
归档内容中仍要列出本次保存产生的全部相关流水。
## 单据内容
### 生产领料出库单字段
单据抬头:
- 单据编号
- 单据日期
- 仓库:原材料库
- 业务类型:生产出库
- 生产台账号
- 生产工单号或材料生产编号
- 材料库存批次号
- 产品名称
- 产品编码
- 状态
- 操作人
明细字段:
- 序号
- 原材料编码
- 原材料名称
- 规格
- 库存批次号
- 本次领料重量
- 累计领料重量
- 单位成本
- 本次材料成本
- 来源仓库
- 备注
汇总字段:
- 本次领料重量合计
- 累计领料重量
- 本次材料成本合计
- 生产台账状态
签字栏:
- 领料人
- 仓库复核
- 生产确认
- 制单人
### 生产入库结算单字段
单据抬头:
- 单据编号
- 单据日期
- 生产台账号
- 生产工单号或材料生产编号
- 材料库存批次号
- 产品名称
- 产品编码
- 业务入口:生产工单入库、生产入库、生产余料入库、生产废料入库
- 是否结单
- 生产台账状态
- 操作人
明细字段:
- 序号
- 入库类型:成品入库、生产余料入库、生产废料入库
- 入库仓库
- 入库物料或产品
- 原材料库存批次号
- 本次数量
- 本次重量
- 理论数量或理论重量
- 偏差百分比
- 偏差说明
- 备注
汇总字段:
- 本次成品入库数量合计
- 本次余料入库重量合计
- 本次废料入库重量合计
- 该生产台账累计成品入库数量
- 该生产台账累计余料入库重量
- 该生产台账累计废料入库重量
签字栏:
- 入库确认
- 仓库复核
- 生产确认
- 制单人
## 前端交互
### 操作弹窗
生产主链路现有入口保留,不改变用户从嘉恒仓库进入业务的习惯。
本期只做两类升级:
1. 表单内部逐步向 `DocumentPaper`、`DocumentGrid`、`DocumentLineTable` 的正式单据形态靠拢。
2. 保存成功后明确提示 PDF 归档结果。
如果业务保存成功但 PDF 失败,提示示例:
`生产入库已保存,但 PDF 归档失败,可在归档操作中重新生成。`
### 列表与详情归档操作
本期优先在生产台账或相关仓库流水明细中展示归档操作。
展示内容:
- 归档状态:未生成、已归档、归档失败
- 预览 PDF
- 下载 PDF
- 重新生成
第一版不做批量下载,避免在仓库单据类型尚未全部稳定时扩大复杂度。
## 后端设计
### 文档归档服务扩展
在现有 `document_archives.py` 基础上新增:
- `DOCUMENT_TYPE_PRODUCTION_MATERIAL_OUT = "生产领料出库单"`
- `DOCUMENT_TYPE_PRODUCTION_INBOUND_SETTLEMENT = "生产入库结算单"`
- `collect_production_material_out_archive_context`
- `collect_production_inbound_settlement_archive_context`
现有 `collect_archive_context` 增加两类分支。
现有 `/document-archives/{document_type_key}/{business_id}/...` 通用路由增加 key:
- `production-material-out`
- `production-inbound-settlement`
### 仓库接口触发
生产出库保存成功后:
- 完成库存扣减。
- 完成生产台账更新。
- 提交业务事务。
- 调用归档生成。
- 如果归档失败,不回滚生产出库。
- 返回结果携带归档状态。
生产工单入库、生产入库、生产余料入库、生产废料入库保存成功后:
- 完成库存变更。
- 完成生产台账或生产工单联动。
- 提交业务事务。
- 以本次动作主流水 ID 生成 `生产入库结算单`。
- 如果归档失败,不回滚入库业务。
- 返回结果携带归档状态。
### PDF 模板
第一版沿用现有纸面归档 PDF 风格:
- 米白纸张底色
- 黑色表格线
- 单据标题居中
- 右上显示 `ERP留存联` 和 `PDF归档`
- 表格内容完整换行,不使用省略号
- 状态、备注、偏差说明全部使用中文
生产主链路字段比销售/采购更偏业务追溯,PDF 表格需要允许多行换行,不能因为库存批次号或备注过长而超格。
## 数据流
生产出库:
```mermaid
flowchart LR
A["原材料库 · 生产出库"] --> B["扣减原材料库存批次"]
B --> C["创建库存流水"]
C --> D["创建或更新生产台账"]
D --> E["生成生产领料出库单 PDF"]
E --> F["写入 document_archives"]
```
生产入库结算:
```mermaid
flowchart LR
A["生产工单入库或分支入库"] --> B["创建成品/余料/废料库存流水"]
B --> C["联动生产台账累计量"]
C --> D["确定本次动作主流水"]
D --> E["生成生产入库结算单 PDF"]
E --> F["写入 document_archives"]
```
## 错误处理
业务保存失败:
- 不生成 PDF。
- 返回原有业务错误。
PDF 生成失败:
- 不回滚业务保存。
- 写入或返回 `归档失败` 状态。
- 前端提示用户可重新生成。
重新生成失败:
- 不影响已有归档版本。
- 保留错误信息。
- 前端显示失败原因。
历史数据:
- 本期不强制自动补档。
- 已存在的生产台账和库存流水在列表中显示 `未生成`。
- 用户可以点 `重新生成` 补 PDF。
## 测试策略
后端测试:
- 生产出库后生成 `生产领料出库单` 归档记录。
- 同一生产台账多次生产出库后归档版本递增。
- 生产工单入库后生成 `生产入库结算单` 归档记录。
- 分支成品入库、余料入库、废料入库后生成 `生产入库结算单`。
- PDF 生成失败不回滚库存和生产台账。
- 归档服务能通过 `production-material-out` 和 `production-inbound-settlement` key 预览、下载、重新生成。
前端测试:
- 生产主链路保存成功后显示归档状态反馈。
- 相关列表或详情出现归档操作。
- 归档操作调用正确 document type key。
- PDF 相关文案不出现英文状态。
人工验证:
- 原材料库生产出库后可预览生产领料出库单。
- 生产工单入库后可预览生产入库结算单。
- 分支入口入库后可预览生产入库结算单。
- PDF 中长库存批次号、备注、偏差说明完整显示且不超格。
## 风险与边界
1. 生产台账和旧生产工单逻辑仍处在并存状态,实施时要按当前代码真实入口分别接入,不能只接其中一条。
2. 合并入口一次产生多条库存流水时,必须稳定确定主流水,否则归档 business_id 会不稳定。
3. 第一版不做批量下载,避免过早扩大接口和 UI 范围。
4. 本次只做生产主链路,不顺手改委外、退货、特殊调整。
5. PDF 是业务快照,不是重新计算入口;归档时以保存后的数据库事实为准。
## 验收标准
1. 原材料库生产出库保存后生成 `生产领料出库单` PDF 归档。
2. 生产工单入库保存后生成 `生产入库结算单` PDF 归档。
3. 成品库生产入库、原材料库生产余料入库、废料库生产废料入库保存后生成 `生产入库结算单` PDF 归档。
4. 业务保存成功但归档失败时,业务数据仍保留,页面能看到归档失败并重新生成。
5. 生产台账或相关流水详情能预览、下载、重新生成 PDF。
6. PDF 内容不使用省略号,长字段自动换行。
7. 用户可通过 PDF 看清材料库存批次号、产品、领料、成品入库、余料、废料、偏差说明、结单状态。
## 设计结论
第一期采用“生产主链路优先”的仓库单据化方案:
- 用 `生产领料出库单` 覆盖原材料库生产出库。
- 用 `生产入库结算单` 覆盖生产工单入库和成品/余料/废料分支入库。
- 后端复用现有 `document_archives` 通用归档表和路由。
- PDF 失败不阻断业务保存。
- 第一版先不做批量下载和全仓库入口覆盖。
该方案能先把最核心的生产闭环打造成正式单据样板,同时为后续 6 大库所有出入库单据化留下统一扩展路径。
@@ -0,0 +1,236 @@
# 销售/采购订单单据化与 PDF 归档设计
## 背景
当前销售订单、采购订单新增页面主要是抽屉内的卡片式数据录入表单。它能完成业务数据提交,但视觉上更像后台管理系统,不像正式业务单据。
本次先按方案 B 试点:只改造“销售订单”和“采购订单”。目标是验证“真实单据填写 + 保存即归档”的产品方向,跑通后再扩展到到货入库单、仓库出入库单、质检单、盘库单等其他单据。
## 设计目标
1. 销售订单、采购订单新增表单改为真实“单据”形态,用户感觉是在填写正式业务单。
2. 外层仍沿用当前系统抽屉,不改变用户从列表点击新增的入口习惯。
3. 内层采用 v3 效果图方向:工厂联单/归档单风格,而不是普通网页卡片拟纸。
4. 单据保存成功时,后端基于当时业务数据生成不可变 PDF 归档快照。
5. PDF 作为主归档文件,Word 只作为按需辅助导出,不作为原始留档依据。
6. 列表支持单据归档状态展示、单份预览、单份下载、多选批量下载。
## 视觉方向
采用“工厂联单/归档单嵌入系统抽屉”的风格。
已确认的 v3 效果图文件:
- `outputs/document-form-mockups/sales-order-document-form-mockup-v3-real-paper.png`
- `outputs/document-form-mockups/purchase-order-document-form-mockup-v3-real-paper.png`
关键视觉特征:
- 真实纸张底色,偏米白而不是冷白网页卡片。
- 纸张纹理轻量保留,避免影响阅读。
- 外层有档案板/叠纸阴影,体现这是一张正式归档单。
- 顶部使用金属夹/装订元素,增强真实“夹在文件板上”的感觉。
- 单据标题使用黑色居中大字,例如“销售订单”“采购订单”。
- 单据编号使用右上红/绿编号章,不再放在普通卡片角标里。
- 表单字段使用真实单据表格格线,减少圆角输入框感。
- 明细使用表格行,表现为“纸上填写格”,不再使用多张卡片堆叠。
- 底部保留签字/确认栏,例如销售确认、客户确认、财务复核、制单人。
- PDF 归档章弱化为纸面印章,不能遮挡核心数据。
## 交互范围
### 销售订单新增
保持现有字段和业务逻辑,不删字段、不改变提交语义。
单据结构:
1. 单据头部:公司名、销售订单标题、销售订单号、归档联标记。
2. 抬头信息:客户、销售人员、下单日期、交期、税率、送货地址。
3. 订单明细:产品、客户料号、订单数量、销售单价、明细交期、金额。
4. 汇总信息:订单总数、未税金额、含税金额、归档状态。
5. 备注与签字:备注、销售确认、客户确认、财务复核、制单人。
6. 操作区:保存草稿、保存并生成 PDF 归档。
### 采购订单新增
保持现有字段和业务逻辑,不删字段、不改变提交语义。
单据结构:
1. 单据头部:公司名、采购订单标题、采购单号、归档联标记。
2. 采购路径:到货库、采购方式、归档策略。
3. 抬头信息:供应商、采购人员、预计到货、提前预警、税率、关联销售订单。
4. 采购明细:原材料、性能要求、采购重量、辅助吨数、单价、元/吨、明细交期。
5. 汇总信息:采购总重量、折合吨数、含税金额、归档状态。
6. 备注与签字:采购确认、供应商确认、仓库接收、制单人。
7. 操作区:保存草稿、保存并生成 PDF 归档。
## 归档规则
### 主档格式
PDF 是主归档文件。
原因:
- PDF 更适合固定原始单据快照。
- PDF 不易被用户误编辑。
- 后续预览、下载、批量下载更稳定。
Word 只做辅助导出。
原因:
- Word 可编辑,不适合作为原始留档依据。
- 如果后续客户需要对外沟通版本,可以导出 Word,但系统内部追溯以 PDF 为准。
### 生成时机
第一版采用“保存成功后自动生成 PDF 归档”。
具体规则:
- 新增销售订单保存成功后,立即生成销售订单 PDF 归档。
- 新增采购订单保存成功后,立即生成采购订单 PDF 归档。
- 如果 PDF 生成失败,业务单据仍可保存,但列表显示“归档失败”,允许用户重新生成。
- 归档生成时要记录模板版本、生成时间、生成用户、文件路径、文件哈希。
### 编辑后的处理
第一版建议采用版本化归档。
规则:
- 每次关键字段编辑后重新生成新的 PDF 归档版本。
- 历史归档版本保留。
- 列表默认展示最新归档。
- 详情中可查看历史归档版本。
这样不会出现“数据改了,但原来 PDF 覆盖掉了”的追溯风险。
## 数据模型建议
新增通用单据归档表,例如 `document_archives`。
建议字段:
- `id`
- `document_type`:销售订单、采购订单等。
- `business_id`:业务主表 ID。
- `document_no`:业务单号。
- `archive_version`:归档版本号。
- `template_version`:模板版本。
- `file_format`:PDF 或 DOCX。
- `file_name`
- `file_path`
- `file_hash`
- `status`:已生成、生成失败。
- `error_message`
- `created_by`
- `created_at`
第一版只要求销售订单、采购订单接入。
## 前端列表调整
销售订单列表、采购订单列表增加归档相关操作。
列表列建议:
- 归档状态:未生成、已归档、归档失败。
- 操作:预览、下载、重新生成。
批量操作:
- 勾选多张销售订单后可批量下载 PDF。
- 勾选多张采购订单后可批量下载 PDF。
- 批量下载由后端打包 zip。
## 后端接口建议
销售订单:
- `POST /sales/orders/{id}/archive`
- `GET /sales/orders/{id}/archive/latest/preview`
- `GET /sales/orders/{id}/archive/latest/download`
- `POST /sales/orders/archives/batch-download`
采购订单:
- `POST /purchase/orders/{id}/archive`
- `GET /purchase/orders/{id}/archive/latest/preview`
- `GET /purchase/orders/{id}/archive/latest/download`
- `POST /purchase/orders/archives/batch-download`
也可以抽象成通用接口:
- `POST /document-archives/{document_type}/{business_id}/generate`
- `GET /document-archives/{document_type}/{business_id}/latest`
- `POST /document-archives/batch-download`
第一版建议后端服务层通用,路由层可以先按销售/采购分别暴露,便于前端调用和权限控制。
## 技术实现建议
### 前端
新增通用单据表单组件:
- `DocumentFormDrawer`
- `DocumentPaper`
- `DocumentGrid`
- `DocumentLineTable`
- `DocumentArchiveActions`
销售订单和采购订单分别提供字段配置,不建议完全硬编码到一个巨大组件里。
### 后端
新增归档服务:
- 收集业务数据。
- 渲染 HTML 模板。
- 生成 PDF。
- 写入归档记录。
- 提供预览、下载、批量 zip。
PDF 生成建议后端完成,不能只依赖浏览器 `window.print()`。
### 文件存储
第一版可以先存在服务器本地目录,例如:
- `outputs/document_archives/sales_order/`
- `outputs/document_archives/purchase_order/`
后续正式环境再迁移到对象存储也可以。
## 风险与边界
1. 这次不是全系统单据化,只试点销售订单和采购订单。
2. 不改变销售订单、采购订单现有业务字段和计算逻辑。
3. 不把合同生成逻辑和单据归档混在一起。合同是对外合同,订单归档是内部业务原始单据。
4. PDF 归档失败不能阻断核心业务保存,但必须明确提醒并允许补生成。
5. 真实纸张效果要服务阅读,不能为了拟物牺牲表格清晰度。
## 验收标准
1. 新增销售订单页面不再是卡片堆叠,而是 v3 风格单据填写。
2. 新增采购订单页面不再是卡片堆叠,而是 v3 风格单据填写。
3. 保存销售订单后生成 PDF 归档记录。
4. 保存采购订单后生成 PDF 归档记录。
5. 销售订单列表可预览、下载、批量下载归档 PDF。
6. 采购订单列表可预览、下载、批量下载归档 PDF。
7. PDF 归档中显示单据编号、公司名、关键抬头、明细、汇总、制单信息。
8. PDF 主归档、Word 辅助导出的规则在代码和界面文案中保持一致。
## 设计结论
采用方案 B 作为第一版试点:
- 销售订单、采购订单先单据化。
- 使用 v3 工厂联单/归档单视觉方向。
- PDF 作为主归档。
- Word 作为后续按需辅助导出。
- 归档能力做成通用底座,后续再推广到其他业务单据。