docs(pl): record approved v3 and sequence implementation with regression checks

This commit is contained in:
wuzilong committed 2026-11-01 20:52:47 +08:00
1 parent 3a3cafc2c5
commit 771f2d7566
3 files changed
+89 -3

No files matched your search

@@ -0,0 +1,86 @@
# 段次用证与合同双视角实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 实现已确认v3的五视图、合同双Tab、装送各段累计额度与逐段产品证明。
**Architecture:** 延续证件共享余额和现有使用明细账,以服务端确定的计量版本选择旧单侧或新全段来源。新增独立段产品资料与分页查询,合同详情复用管理页组件,保存和安排仍由单事务入口处理。
**Tech Stack:** Python 3.9/FastAPI/SQLAlchemy/Pydantic v2、MySQL 5.7、Vue 3/Element Plus、pytest、pnpm。
---
## 已确认边界与执行顺序
用户已明确“采用v3,继续实现”。分支`codex/pl-stop-cert-management`,集成目标`V3.0`。使用现有隔离worktree,不触碰主目录未提交文件。先后端计量,再资料及统计,再Web;任务间规格审查后质量审查。Agent执行合成数据测试;不启动MySQL容器,不连接业务库验证、不执行SQL、不部署。主目录项目配置允许任务分支推送/工单回写,不允许合并。本任务不扩大手机UI范围,但共享API保持兼容。
## Task 1: 服务器决定计量版本及各段独立来源
Files: `backend/app/services/pl_quota_sources.py`、`pl_quota_planning.py`、`pl_quota_business.py`、`pl_quota_usage_service.py`;`backend/app/schemas/pl/quota_planning.py`;`backend/tests/test_pl_quota_sources.py`、`test_pl_quota_planning.py`、`test_pl_quota_business.py`。
- [ ] 增加失败用例,复用现有SQLite合成fixture,将装货100、两送40/60分别关联不同合同产品,断言新来源三条且合计200;实际量独立取每段。保留显式legacy测试。
```python
assert sum(source.quantity for source in sources) == Decimal('200')
assert {source.source_id for source in sources} == {'load:lp', 'delivery:dp', 'delivery:dp2'}
assert {source.contract_id for source in sources} == {'purchase', 'sale', 'sale2'}
```
- [ ] 用主目录虚拟环境从本worktree的backend运行`python -m pytest tests/test_pl_quota_sources.py tests/test_pl_quota_planning.py -q`,记录预期失败。
- [ ] 来源增加`measurement_version`选择;旧版本维持原算法,新版按所有易制毒段产品创建来源,不依赖客户端挑选计量侧。缺少段产品或合同身份拒绝;来源指纹含新版标识,legacy指纹不改变。配置接受`measurementVersion`用于显示,但服务端根据已持有账目/安排归档状态决定版本,拒绝客户端降级/切换;历史已产生账目缺版本视为legacy,新草稿/新安排固定per_stop_v2。新版本忽略旧客户端对侧配对选择,不允许借它少扣。
- [ ] 正式reserve/resize把服务端版本写回配置/账本快照;settle/release保持旧版可追溯,避免旧计划升级加扣。预览和正式提交共用版本决策。get返回版本及来源主体、段序、合同、产品。
- [ ] 运行来源、planning、business、usage、allocation、supplement相关pytest;验证旧单侧100、新版200、跨合同匹配、不可降级、0实际量和缺失实际量。提交本任务。
## Task 2: 段产品证明与合同范围分页
Files: 新增`backend/app/services/pl_stop_legal_document.py`、`backend/tests/test_pl_stop_legal_document.py`;修改`backend/app/models/pl_quota_models.py`、`backend/app/schemas/pl/legal_use_document.py`、`backend/app/api/pl/quota_cert.py`;新增`docs/sql/2026-11-01-pl-stop-legal-document.sql`。
- [ ] 写合成用例:一装两送只传第二段,结果1/3;按第二段合同查询为1/1;另租户、另合同、重复段身份拒绝;遗漏集合不变、空附件清空单行、旧计划附件不会标记新段完成。运行看到缺失功能失败。
- [ ] 新表`pl_stop_legal_document`使用完整公共字段、软删除、唯一`tenant_no/plan_id/stop_type/stop_product_id`;增加MySQL5.7可执行建表脚本,不自动执行。以有效计划/父段/段产品/计划产品联查判定易制爆适用范围;合同权限和计划权限均过滤。保存按稳定段产品身份差量更新,全部校验后写入;上传权限和MinIO新附件授权沿用旧逻辑;删除段产品下游引用保护包含新资料。
- [ ] 独立新API避免旧端混淆:`GET /transport/legal-use-documents/stops`分页`{list,total,page,pageSize}`;`GET/PATCH /stops/{plan_id}`获取/保存。查询`contractId`限定当前合同;PATCH载荷`{items:[{stopType,stopProductId,legalUseCertUrl}]}`,不得批量套用同一附件。
```json
{"id":"plan", "planNo":"PL001", "uploadedCount":1,"requiredCount":3,
"items":[{"stopType":"delivery","stopProductId":"dp","productName":"双氧水","contractId":"sale","contractNo":"XS001","legalUseCertUrl":"","documentStatus":"pending"}],
"legacyProducts":[]}
```
- [ ] 保留旧计划级端点和旧附件查看,清楚标为历史;回归旧端点测试,运行新权限/保存/统计测试。提交本任务。
## Task 3: 合同与证件统计、建档原子绑定
Files: 新增`backend/app/services/pl_quota_statistics.py`、`backend/app/services/pl_quota_cert_bindings.py`和对应tests;修改`backend/app/api/pl/quota_cert.py`,按需扩展已有schemas。
- [ ] 写失败用例:核定300、两合同预占100/80、已用20得到共享100;无权合同不出现在列表;两证不合并;分页按合同/证件而非明细。原子保存中第二合同非法整个事务回滚,原有链接及产品ID保持、其他证件不被移除。
- [ ] API固定为`GET /statistics/contracts`、`GET /statistics/certificates`返回分页主对象,`GET /contracts/{id}/statistics`返回合同及`certificates`,每证`certType/certId/certNo/productNames/quantityUnit/totalQty/reservedQty/usedQty/availableQty/contractReservedQty/contractUsedQty/products`;`GET /{kind}/{id}/statistics`返回证件及`contracts`及当前权限内`usageItems`。查询当前租户、软删除、CRM和PL范围;余额为授权可见证的全局缓存,合同使用聚合只取授权计划,不泄漏不可见合同明细。
- [ ] 在证件save payload增加可选`contractBindings:[{contractId,products:[{id?,contractProductId,scopeStatus?}],id?,linkStatus?}]`,get返回同字段。遗漏不修改,空集合申请清空当前证件可见范围并执行引用保护;不允许隐藏范围被静默删除。共享事务调用已有证件save与合同绑定服务;先固定完整锁序/全部验证,维护其他证件关系和原ID,失败不commit。
- [ ] 运行新统计/原子保存测试以及contract_scope、cert_archive、api回归。提交本任务。
## Task 4: 五Tab容器和复用统计面板
Files: `web-admin/src/api/pl/quota-cert.ts`;新`web-admin/src/views/pl/cert-management/index.vue`、`ContractQuotaPanel.vue`、`CertificateUsagePanel.vue`;修改router和`ContractDetailDialog.vue`。
- [ ] 增加API类型和请求方法与Task2/3一致,分页保留数值字符串。用组件行为测试覆盖Tab切换正确视图、合同固定id、切换合同清空旧响应、统计不相加共享余额。
- [ ] 容器五Tab按已确认顺序,仅有合法证明菜单权限时不请求额度API。旧Web菜单URL进入对应Tab,移动路由保持原组件;主Tab挂载已有建档/计划组件,补`embedded`支持避免双标题/双padding。
```ts
const tabs = ['archive', 'contracts', 'certificates', 'plans', 'documents'] as const
```
- [ ] 统计面板使用ListQuickSearchInput/ListToolbarEndActions/ColumnHeaderFilter、服务端分页、展开按需取明细。合同面板prop`contractId?: string`固定范围,复用ContractScopeDialog维护绑定;证件面板按证种展示全局数量和各合同明细,展开段产品用量。
- [ ] 合同详情运输计划后插入两个lazy Tab,按菜单权限显示,分别挂载ContractQuotaPanel和段证明页面固定contractId,切换合同销毁旧状态。
- [ ] 定向tsx/node:test及类型检查(区分历史错误);提交。
## Task 5: 建档绑定、段次与安排UI
Files: `web-admin/src/views/pl/quota-cert/index.vue`、`model.ts`、`ContractScopeDialog.vue`;`web-admin/src/views/pl/plan-quota/index.vue`;`web-admin/src/components/business/pl-plan-quota-dialog/index.vue`及model/test。
- [ ] 行为测试覆盖多合同产品选择后一次save、保存失败保留输入、单附件解析、编辑ID往返和旧版本配对显示。
- [ ] 建档表单在1200px三列现有区后增加合同产品绑定编辑,加载编辑已有绑定,不由客户端多请求分步保存。建档方式/类型同行,绿色分组竖条保持。
- [ ] 新版配置展示所有装送段产品、合同/单位/需用量;隐藏唯一侧选择,不提交旧配对。保留legacy配置用于旧计划。计划页展开get_plan_quota,列出各段绑定证件及预占/已用,标注缺配、无需两证、原口径。
- [ ] 安排沿用后端原子校验,把手填齐备改为两证条件/余额预检,缺证明不阻断;拒绝返回定位段产品。实际库存、法定证明、两证状态互不替代。
- [ ] 定向tsx/node:test和已有H5/小程序共享配置测试,修正兼容而不新增手机五Tab。提交。
## Task 6: 段次证明Web与最终验证
Files: 新`web-admin/src/views/pl/legal-use-document/StopDocuments.vue`;API types;合同详情及五Tab挂载;相关node:test。
- [ ] 测试合同范围上传1/1、全局1/3、逐段附件操作、上传中禁止保存、失败保留输入、切租户/合同丢弃过时响应。
- [ ] 使用服务端分页和状态过滤,展开计划显示每个装送段产品及附件;每行单独上传/保存,上传控件与MinIO沿用AttachmentUploadField。历史计划级附件单独只读,不能当作段已上传。
- [ ] 使用主目录venv运行受影响后端pytest;Web运行定向tsx/node:test、pnpm build与类型检查,已知历史错误单列;共享手机API测试。审查固定base/head,规格合格后质量审查;修复所有阻塞。
- [ ] 在允许的本地测试环境以合成响应验证页面/弹窗及合同切换、加载失败、保存状态;未获服务启动授权则使用不启动业务后端的组件浏览器测试,缺口如实记录。MySQL真实事务验证保留未执行,不以SQLite冒充。
- [ ] 更新OpenSpec/tasks、SQL执行指引、工单和提交证据,按已授权推送任务分支,保持工单开放至验收;不自动合并或执行SQL。
@@ -4,13 +4,13 @@
- 工单:[#9 用证管理按段次计量及合同双视角](https://gitea.aichengyan.com/cykj/shanxia2.0/issues/9)。
- 分支:`codex/pl-stop-cert-management`。
- [Figma v3 总览](https://www.figma.com/design/ImDcikQnCX5GiJQLwUHwDC/shanxia2.0?node-id=26-3),状态:待用户确认。
- [Figma v3 总览](https://www.figma.com/design/ImDcikQnCX5GiJQLwUHwDC/shanxia2.0?node-id=26-3),状态:用户已确认采用v3。
- 合同详情独立视图:[合同证件与额度](https://www.figma.com/design/ImDcikQnCX5GiJQLwUHwDC/shanxia2.0?node-id=26-445)、[运输计划合法使用证明](https://www.figma.com/design/ImDcikQnCX5GiJQLwUHwDC/shanxia2.0?node-id=26-513)。
- 原型包含五个管理视图、两个合同面板、建档绑定及安排校验,共九个1440px可编辑画面。原型为静态设计,页签跳转、上传与保存尚非可运行功能;交互状态以说明呈现,业务实现后须实际验证。
- 复用现有文件字体及导入的Body样式,局部复用表格单元格、页签、按钮实例;采用Fresh Mint规范色。建档画面说明新增绑定区,实际弹窗仍沿用现有1200px及三列布局,不按原型画布宽度扩大到1440px。
- 当前只提交规格;未修改业务代码、执行SQL或重算历史额度。
- 设计检查:首轮总览截图发现文本过早换行,调整复用组件的文本宽度后,通过Plugin API截图复查九画面布局;298个组件实例、无图片铺底。常规截图接口复查超时,改用节点截图完成。该检查仅针对静态原型,不代表浏览器功能、响应式或交互状态验收。
- 规格检查:`openspec validate pl-stop-cert-management --strict`通过。已向用户提交v3选择题;未收到具体版本确认前不开始依赖原型的实现。
- 规格检查:`openspec validate pl-stop-cert-management --strict`通过。用户已回复“采用 v3,继续实现(推荐)”,原型状态更新为已确认;按实施计划进入开发。
## 用户确认
@@ -2,7 +2,7 @@
- [x] 核对现有实现与用户决定,明确各段分别累计、资料分别上传、合同详情两个独立Tab。
- [x] 建立proposal/design/specs并记录历史兼容、统计和权限边界。
- [x] 关联独立工单#9,制作并检查可编辑Figma v3(九个静态画面)。
- [ ] 用户确认具体新版原型后开始依赖它的业务界面实现。
- [x] 用户明确“采用 v3,继续实现”,已允许按新版原型开发。
## 2. 后端与迁移
- [ ] 先写新规则100+40+60=200及旧版100不变的失败回归,再扩展版本化来源提取及分配入口。