diff --git a/docs/superpowers/specs/2026-07-27-crm-product-brand-alias-design.md b/docs/superpowers/specs/2026-07-27-crm-product-brand-alias-design.md new file mode 100644 index 000000000..d906f22f0 --- /dev/null +++ b/docs/superpowers/specs/2026-07-27-crm-product-brand-alias-design.md @@ -0,0 +1,220 @@ +# 产品品牌与别名设计(含运输计划归档按品牌记账) + +> 日期:2026-07-27 +> 状态:待用户审阅 +> 范围:web-admin CRM 产品 / 报价 / 合同 + PL 运输计划归档与库存 +> 选定方案:方案 1 — 约定在单据行,实绩在归档拆品牌 + +## 1. 背景与目标 + +### 1.1 现状 + +- CRM 管理下已有「产品管理」(`web-admin/src/views/crm/product/index.vue`,路由 `crm/product`)。 +- `crm_product` 无品牌、别名字段;部分产品把品牌写进名称(如「片碱(君正)」「纯碱(红四方)」)。 +- 报价 / 合同 / 计划明细均快照 `product_name`:`crm_quote_product` → `crm_contract_product` → `pl_plan_product`。 +- 库存 `pl_inventory` 以 `product_id` 唯一,出入库流水无品牌维度。 + +### 1.2 业务诉求 + +1. **品牌**:采购有品牌;报价/合同可「指定品牌」或「不限品牌」。不限时可混品牌发货;指定则按该品牌发货。 +2. **别名**:客户希望合同展示名与内部标准名不同(如内部「烧碱」、合同写「氢氧化钠」),对内仍是同一产品。 +3. **库存**:本期即按品牌记库存、出入库与盘点;运输计划**归档时**,有品牌的产品按品牌分别填写入库量 / 出库量。 + +### 1.3 非目标(首期不做) + +- 全局品牌字典、客户专属别名 +- 计划创建阶段按品牌拆行 +- 库位 / 批次 / 完整 WMS +- 地磅或并列 CRM 仓库联动 +- 线索 / 商机意向产品结构化品牌 +- 多套复杂打印模板(仅在现有模板增加品牌字段) + +## 2. 决策摘要 + +| 议题 | 决策 | +|------|------| +| 产品 vs 品牌 | 一条产品多品牌,不按品牌拆成多条产品 | +| 品牌主数据 | 各产品独立维护品牌列表,无全局品牌字典 | +| 别名 | 挂在产品上;开单时选用标准名或别名写入行快照 | +| 品牌约定落点 | 报价 / 合同行:`指定` / `不限` | +| 实际品牌落点 | 运输计划归档时按品牌填量 | +| 库存粒度 | `产品 + 品牌`;与归档实绩一起做 | +| 出库库存不足 | 首期强校验拦截 | + +## 3. 数据模型 + +### 3.1 产品品牌子表 `crm_product_brand` + +| 字段 | 说明 | +|------|------| +| id | UUID 主键 | +| product_id | 所属产品 | +| brand_name | 品牌名称 | +| status | 启用 / 停用(或等价字段) | +| order_num 等公共字段 | 按 database-conventions | + +- 子表为空 = 无品牌产品。 +- 品牌仅属于该产品。 + +### 3.2 产品别名子表 `crm_product_alias` + +| 字段 | 说明 | +|------|------| +| id | UUID 主键 | +| product_id | 所属产品 | +| alias_name | 别名 | +| 公共字段 | 按规范 | + +- 开单可选:标准 `product_name` 或任一别名,选中值写入单据行 `product_name` 快照。 + +### 3.3 报价 / 合同行扩展 + +表:`crm_quote_product`、`crm_contract_product` 增加: + +| 字段 | 说明 | +|------|------| +| brand_mode | `required` 指定品牌 / `any` 不限品牌;无品牌产品可不写或空 | +| brand_id | 指定时有值;不限为空 | +| brand_name | 指定时的品牌名快照 | +| product_name | 现有字段,存对外展示名(标准名或选用别名) | + +合同从报价生成时上述字段一并拷贝。 + +### 3.4 计划行扩展 `pl_plan_product` + +增加同样的 `brand_mode` / `brand_id` / `brand_name`(从合同带入)。 +计划创建 / 编辑阶段**不按品牌拆行**,仅展示约束。 + +### 3.5 归档品牌实绩 `pl_plan_product_brand_qty` + +| 字段 | 说明 | +|------|------| +| plan_product_id | 计划产品行 | +| brand_id / brand_name | 实际品牌 | +| inbound_qty / outbound_qty | 按计划类型使用对应字段 | + +规则: + +- `brand_mode=required`:仅允许该品牌一行有量。 +- `brand_mode=any`:可多品牌多行;有量合计 = 该产品行应归档总量。 +- 产品无品牌:不写本表,沿用行上原入/出库量字段。 + +### 3.6 库存 + +- `pl_inventory`:唯一键改为 `(tenant_no, product_id, brand_id)`;无品牌使用空品牌键(`brand_id=''`)。 +- `pl_inventory_transaction`:增加 `brand_id` / `brand_name`。 +- 预警按「产品 + 品牌」维度维护。 + +## 4. 业务流转 + +```text +产品维护品牌/别名 + → 报价行:展示名 + 品牌约定(指定/不限) + → 合同行:快照拷贝 + → 计划行:带入约束(不拆行) + → 归档:按品牌填入/出库量 + → 按品牌写库存流水与台账 +``` + +### 4.1 产品管理 + +- 维护品牌列表、别名列表(均可空)。 +- 有品牌 → 后续单据才出现品牌控件。 +- 有别名 → 开单可选展示名。 + +### 4.2 报价 + +1. 选产品,带出标准属性。 +2. 有别名:选择展示名 → 写入行 `product_name`。 +3. 有品牌:选择「指定品牌」(必选品牌)或「不限品牌」。 +4. 打印/导出:指定显示品牌;不限显示「不限品牌」或不印具体品牌(全系统统一一种文案)。 + +### 4.3 合同 + +- 从报价带入含展示名与品牌约定。 +- 手工加行交互同报价。 +- 已落库快照不随主数据更名/改品牌而变。 + +### 4.4 运输计划 + +- 展示产品名 + 品牌约束(指定品牌名或「不限」)。 +- 不在此阶段选择实际发货品牌,不扣库存。 + +### 4.5 归档 + +| 情况 | 填写方式 | +|------|----------| +| 无品牌 | 现有单行填量 | +| 指定品牌 | 仅该品牌一行填量 | +| 不限品牌 | 按该产品品牌列表分行填量;合计必须等于应归档总量 | + +校验失败不可完成归档。 + +### 4.6 库存记账 + +- 归档成功后按品牌明细生成 inbound/outbound 流水并更新台账。 +- 台账默认「产品 + 品牌」;支持按产品汇总。 +- 出库:某品牌填写量 > 该品牌库存 → **强校验拦截**。 +- 入库:不拦截。 + +## 5. 界面要点 + +对齐 Fresh Mint 与现有 CRM/PL 列表、弹窗模式。 + +- **产品**:弹窗内品牌、别名可编辑列表;列表可展示品牌摘要列。 +- **报价/合同行**:有别名则可选展示名;有品牌则「指定/不限」+ 指定时品牌下拉。默认建议「不限品牌」。 +- **计划**:增加品牌约束列。 +- **归档**:产品行下展开按品牌填量;合计校验。 +- **库存台账 / 流水 / 入出库单**:展示品牌;无品牌显示「—」。 + +## 6. 校验与主数据变更 + +- 指定品牌必须选自该产品启用中的品牌。 +- 无品牌产品不得出现品牌控件。 +- 删除品牌:存在库存或未归档计划引用时禁止删除(可先停用)。 +- 停用品牌:新单据不可选;在途单据按快照执行。 +- 改名/改别名/删品牌不回写历史报价、合同、计划快照。 + +## 7. 历史数据迁移 + +1. 现有 `pl_inventory` 一行/产品 → 迁移为 `brand_id=''` 的无品牌库存行;唯一键切换前完成。 +2. 名称含「(品牌)」的产品:提供清洗策略(拆标准名 + 写入 `crm_product_brand`);**旧单据文字快照保持不变**。 +3. 预警阈值:原产品级阈值落到无品牌行,或由业务在上线后按品牌重设。 + +## 8. 影响模块清单 + +| 模块 | 调整要点 | +|------|----------| +| CRM 产品管理 | 品牌/别名子表 CRUD、UI | +| 报价单 | 行字段、选择交互、打印 | +| 合同 | 行字段、从报价拷贝、打印 | +| 运输计划 | 约束展示、从合同带入 | +| 计划归档 | 按品牌填量 UI + 校验 + 触发库存 | +| 库存台账/流水/预警 | 唯一键与维度升级 | +| 入库单/出库单 | 明细展示实际品牌 | +| 公共组件/API | 产品选择、字段透传、类型定义 | +| docs/sql | 表结构与迁移脚本 | + +## 9. 测试要点 + +- 无品牌产品:全链路与现网行为一致。 +- 指定品牌:报价→合同→计划展示正确;归档只能填该品牌;出库扣对应品牌库存。 +- 不限品牌:归档多品牌分摊;合计校验;库存分品牌增减。 +- 别名:行上展示名正确;主数据标准名不变;历史单据不回写。 +- 库存不足出库归档被拦截;入库正常。 +- 停用/删除品牌的边界行为。 +- 旧库存迁移后台账可查、可继续出入库。 + +## 10. 实现分期建议 + +可在同一变更内按任务拆分,但上线应具备库存维度升级 + 归档落账,避免「有品牌约定却仍按产品总量记账」的中间态长期存在。 + +建议任务序: + +1. DDL:子表 + 单据行字段 + 归档品牌量表 + 库存唯一键迁移 +2. 产品 API/UI(品牌、别名) +3. 报价/合同 API/UI + 打印字段 +4. 计划带入与展示 +5. 归档按品牌填量 + 库存记账改造 +6. 台账/流水/入出库单展示与回归 +7. 历史名称清洗(可并行,需业务确认)