2026-10-21-pl-archive-export-brand-split-design.md 4.6 KB

运输归档导出:按归档品牌拆行 Design

日期: 2026-10-21
状态: 已实现
背景单例: PO20261015009(计划产品 brand_mode=any,归档明细为君正;原导出品牌列为空)

背景与目标

运输归档 / 计划列表导出中,「品牌」列当前取自计划产品约定:仅 brand_mode=required 时写出 brand_name。
「不限品牌」(any)时产品表品牌显示为 —,但归档弹窗会填写「品牌归档明细」并落库 pl_plan_product_brand_qty。客户要求导出品牌列按归档实际品牌填充;多品牌时按品牌拆行。

决策摘要

项 决策
多品牌 方案 B:一行一个归档品牌(qty > 0)
范围 计划列表导出(运输计划 / 危化品证 / 运输归档列表)+ 计划归档专用导出(含 ZIP);合同完善导出无品牌列,不改
已归档(archive_status=archived) 按归档品牌明细拆行;无明细则品牌留空
未归档 / 已暂存(draft) 用产品指定品牌(brand_mode=required 的 brand_name);不限品牌则留空;不拆行
实际量 已归档拆行后 = 该品牌归档数量;未归档/暂存 = 原产品/段实际量
计划量 仍用产品计划量(多品牌行重复同一计划量)

行粒度

段次 × 产品  →  段次 × 产品 × 归档品牌(qty>0)

无有效品牌明细时保持:

段次 × 产品(一行;brandName 空)

数据来源

表:pl_plan_product_brand_qty(del_flag=0 且 qty > 0)。

优先级(与查看弹窗「品牌归档明细」一致):

  1. 段级:stop_product_id = 当前装货/送货产品行 ID(有则用之,不再读计划级)
  2. 回退计划级:该 plan_product_id 下 stop_product_id 为空的计划级正数量行
    • 仅当该段产品行没有任何段级正数量明细时回退
    • 多段同时回退时,各段各自完整列出计划级明细(不做跨段贪心拆分;与归档查看旧数据回退可略有差异,以导出可解释、实现简单为准)

本变更不再使用 _format_plan_list_export_brand / _format_export_brand_name 的「仅 required 写品牌」规则作为导出品牌来源。

字段映射(拆行后)

字段 规则
brandName 归档品牌名;无明细则 ""
actualQty 有品牌明细:该品牌 qty;无明细:沿用原产品/段实际量
planQty 原产品计划量(拆行时各品牌行相同)
单价/金额(归档导出若有) 优先品牌行 unit_price;否则沿用段产品单价;金额 = 实际量 × 单价(与现网金额口径一致处沿用)
其余列 与现网段次×产品行相同,随行复制

影响面

路径 入口 改动点
列表导出 export_plans 默认 / 运输归档页 planApi.export → 计划列表_*.xlsx backend/app/api/pl/plan.py:_build_plan_list_export_rows 及段产品填充;批量加载 brand_qty
归档导出 export_format=archive / archive_zip → 计划归档_*.xlsx backend/app/services/pl_plan_archive_export.py:_build_archive_segment_row 等展开逻辑

建议抽共享辅助(如 resolve_export_brand_qty_rows(stop_product, plan_product_id, stop_type, brand_qty_index)),避免两套导出规则漂移。

合并单元格 sheet(export_plan_list_xlsx_response「计划列表(合并)」):按现有合并键继续合并;品牌拆行后,同一计划号下未参与合并的列(含品牌、实际量)保持分行显示,不强制把多品牌合并进同一单元格。

非目标

  • 不改归档录入 UI / 校验
  • 不改列表页「品牌」列展示(仍为约定标签 formatBrandConstraintLabel)
  • 不迁历史数据;不写回 pl_plan_product.brand_mode
  • 不做「按品牌拆行后重算计划量分摊」

测试

  • 单品牌归档:any + 明细君正 32 → 导出行品牌=君正,实际量=32
  • 多品牌:君正 20 + 红四方 12 → 两行,实际量分别为 20 / 12,计划量均为产品计划量
  • 无明细:品牌空,一行,实际量=原产品实际量
  • required 但归档明细为其他品牌:以归档明细为准(可多行)
  • 装货/送货各自段级明细独立展开
  • 列表导出与归档导出对同一夹具行为一致
  • 回归:现有段次/合同/别名导出用例仍通过;更新依赖「仅 required 出品牌」的单测

风险

  • 导出行数增加(多品牌 × 多段);仍受 EXPORT_MAX_ROWS 限制
  • 合并 sheet 视觉上计划头合并、品牌分行,需手工抽一眼验收