3.3 KiB
3.3 KiB
Context
合同与调价函已强制作废原因。报价单仅有可选 remark 拼写;运输/车辆/结算/地磅的 cancel/void 无 body、无专用字段。用户确认采用独立字段三元组(方案 A),覆盖所列全部作废入口(含小程序);并明确:作废原因非必填,有则落库展示,无则可直接作废。
Goals / Non-Goals
Goals:
- 作废支持填写原因并持久化独立字段,详情可展示(有则显示)。
- 原因可选:留空不阻塞作废。
- CRM 报价单对齐合同/调价函命名(
invalid_*)。 - PL 业务对齐
/cancel语义(cancel_*)。 - 地磅对齐
is_voided//void(void_*)。 - Web + 小程序相关入口行为一致。
Non-Goals:
- 不改造合同、调价函既有「必填原因」流程。
- 不改造公开页出入库单状态改「已作废」(本变更范围外)。
- 不作废原因字典(自由文本即可)。
- 不回填历史已作废单据的原因。
Decisions
D1 — 字段命名分域
| 域 | 字段 | 理由 |
|---|---|---|
| CRM 报价单 | invalid_reason / invalid_time / invalid_by |
与合同、调价函一致 |
| PL(计划、加油、充值、维保、尿素、结算) | cancel_reason / cancel_time / cancel_by |
与 /cancel、cancelled 一致 |
地磅 db_weighing_slip |
void_reason / void_time / void_by |
与 is_voided、POST .../void 一致 |
*_reason:varchar(500),nullable。
*_time / *_by:作废成功时写入(即使原因为空,仍记录何时、何人作废)。
D2 — 原因可选(产品确认)
- 前端弹窗提供「作废原因」输入框,不设 required;可直接确认作废。
- API body 中原因字段 Optional;trim 后为空则存 NULL,不返回 400。
- 非 BREAKING(相对「仅确认」的旧客户端):无 body / 无原因字段仍可作废;建议新客户端传 body 以便扩展。
D3 — API 契约
- 报价单 invalid:可选
invalidReason→ 写invalid_*(原因可空;时间/人必写)。 - PL cancel:可选 body
{ "cancelReason": "..." }。 - 地磅 void:可选 body
{ "voidReason": "..." }。
D4 — 报价单迁移行为
- 新作废写入
invalid_*,不再向remark追加【作废原因】。 - 历史 remark 拼接不自动迁移。
D5 — 加油作废恢复
restore 时清空 cancel_reason / cancel_time / cancel_by。
D6 — UI
- Web:作废对话框含可选 textarea(placeholder 提示「选填」);列表与详情共用。
- 小程序:可输入原因的弹层;允许空提交。
- 查看态:有原因则展示;时间、操作人有则展示。
D7 — SQL 交付
- 增量迁移 + 更新
docs/sql/shanxia2.0.sql与 models。
Risks / Trade-offs
- [原因常空] → 接受;至少有
*_time/*_by可追溯操作。 - [三套字段前缀] → 文档与 DTO 写清;UI 文案统一「作废原因」。
- [公开出入库未纳入] → 另开变更。
Migration Plan
- ALTER 加列(均可 NULL)。
- 部署后端(接受可选原因)。
- 部署 web-admin + miniprogram(弹窗选填)。
- 回滚:列可保留;UI 可退回仅确认。
Open Questions
- (无)地磅命名
void_*;原因非必填已确认。