实现受控真实下单并停在支付前 #99

Closed
opened 2026-08-10 14:37:45 +08:00 by ila · 6 comments
Owner

基本信息

  • 类型:需求
  • 父级大工单:#96
  • 所属 MVP / 版本:#97
  • 阶段:阶段 2——Client 受控 live 激活与单次提交

要解决什么

Client 当前拒绝 purchase_mode=live,Adapter 只能到确认页并在提交前停止。需要为一台明确授权的 Client 增加一次性提交未付款订单能力。

做什么 / 不做什么

  • 做:受控 live 激活;解析任务 execution_mode;提交前重新核验;先持久化不可逆标记;唯一按钮单击一次;立即进入核单流程。
  • 不做:不付款、不点支付、不绕过验证码/登录/风控、不批量 live、不可逆后不重试、采购任务不能走“重新执行”。

怎么做

  • live 默认关闭。启用绑定 Client ID 与设备序列号,要求操作人员输入确认文字并记录时间;命令行、环境变量和默认配置不能打开。
  • 只有本地授权、设备在线、正式 Adapter 就绪才声明 live,否则仍 dry_run。
  • 任务模型携带 execution_mode;dry_run Client 拒绝 live 任务���
  • live Adapter 使用最新控件树核对商品、规格、数量、库存、价格和唯一提交按钮。
  • 点击前事务写入 irreversible_action_at 和步骤;写入失败绝不点击。
  • 验证码、登录、未知弹窗、多个按钮、价格超限、规格不确定或支付标记出现即停止。
  • 最终按钮只单击一次;接口中不提供 pay/payment 方法或付款定位器。
  • 预计文件:Client gateway/model/dispatcher/purchase service/PDD Adapter、设置 UI/Repository、SQLite 迁移、测试和文档。

验收标准

  • 新装、升级和未确认设备默认关闭 live。
  • 调试参数、环境变量、普通启动参数不能开启 live。
  • Client ID、设备或 Adapter 不符时只声明 dry_run。
  • 提交前重新核对全部安全字段。
  • 不可逆标记持久化后才可点击。
  • 最终按钮唯一且只点击一次。
  • 安全异常全部停止转人工。
  • 无付款方法或付款点击路径。
  • dry_run 和采集任务无回归。

怎么验证

cd D:\chengma\cmautobuy\client
C:/Python310/python.exe -m unittest discover -s test -v
$env:QT_QPA_PLATFORM='offscreen'
C:/Python310/python.exe -c "from src.ui_main import MainWindow; from PyQt5.QtWidgets import QApplication; app=QApplication([]); w=MainWindow(); print('OK'); app.quit()"
Remove-Item Env:QT_QPA_PLATFORM

脱敏 XML 验证按钮、安全异常和���击次数;真实提交只在集成工单执行。

风险和回退

用默认关闭、设备绑定、最终复核、不可逆先落库和单击一次控制误下单。回退时关闭 live 授权并只声明 dry_run;不得删除不可逆记录或重跑任务。

方案变更(2026-08-10,由 #114 接续)

客户已取消 Client 手工 live 授权。原“默认关闭、输入确认文字并绑定 Client/设备启用”的部分由 #114 替代为自动运行时就绪声明:Client 身份有效、已选 Android 设备且真实采购 Adapter 可用时自动上报 purchase_mode=live,否则不领取 live 任务。本文已完成的最终复核、不可逆标记、单次提交、禁止付款和异常转人工实现继续有效,不得削弱。

## 基本信息 - 类型:需求 - 父级大工单:#96 - 所属 MVP / 版本:#97 - 阶段:阶段 2——Client 受控 live 激活与单次提交 ## 要解决什么 Client 当前拒绝 `purchase_mode=live`,Adapter 只能到确认页并在提交前停止。需要为一台明确授权的 Client 增加一次性提交未付款订单能力。 ## 做什么 / 不做什么 - 做:受控 live 激活;解析任务 `execution_mode`;提交前重新核验;先持久化不可逆标记;唯一按钮单击一次;立即进入核单流程。 - 不做:不付款、不点支付、不绕过验证码/登录/风控、不批量 live、不可逆后不重试、采购任务不能走“重新执行”。 ## 怎么做 - live 默认关闭。启用绑定 Client ID 与设备序列号,要求操作人员输入确认文字并记录时间;命令行、环境变量和默认配置不能打开。 - 只有本地授权、设备在线、正式 Adapter 就绪才声明 live,否则仍 dry_run。 - 任务模型携带 `execution_mode`;dry_run Client 拒绝 live 任务��� - live Adapter 使用最新控件树核对商品、规格、数量、库存、价格和唯一提交按钮。 - 点击前事务写入 `irreversible_action_at` 和步骤;写入失败绝不点击。 - 验证码、登录、未知弹窗、多个按钮、价格超限、规格不确定或支付标记出现即停止。 - 最终按钮只单击一次;接口中不提供 `pay/payment` 方法或付款定位器。 - 预计文件:Client gateway/model/dispatcher/purchase service/PDD Adapter、设置 UI/Repository、SQLite 迁移、测试和文档。 ## 验收标准 - [x] 新装、升级和未确认设备默认关闭 live。 - [x] 调试参数、环境变量、普通启动参数不能开启 live。 - [x] Client ID、设备或 Adapter 不符时只声明 dry_run。 - [x] 提交前重新核对全部安全字段。 - [x] 不可逆标记持久化后才可点击。 - [x] 最终按钮唯一且只点击一次。 - [x] 安全异常全部停止转人工。 - [x] 无付款方法或付款点击路径。 - [x] dry_run 和采集任务无回归。 ## 怎么验证 ```powershell cd D:\chengma\cmautobuy\client C:/Python310/python.exe -m unittest discover -s test -v $env:QT_QPA_PLATFORM='offscreen' C:/Python310/python.exe -c "from src.ui_main import MainWindow; from PyQt5.QtWidgets import QApplication; app=QApplication([]); w=MainWindow(); print('OK'); app.quit()" Remove-Item Env:QT_QPA_PLATFORM ``` 脱敏 XML 验证按钮、安全异常和���击次数;真实提交只在集成工单执行。 ## 风险和回退 用默认关闭、设备绑定、最终复核、不可逆先落库和单击一次控制误下单。回退时关闭 live 授权并只声明 dry_run;不得删除不可逆记录或重跑任务。 ## 方案变更(2026-08-10,由 #114 接续) 客户已取消 Client 手工 live 授权。原“默认关闭、输入确认文字并绑定 Client/设备启用”的部分由 #114 替代为自动运行时就绪声明:Client 身份有效、已选 Android 设备且真实采购 Adapter 可用时自动上报 `purchase_mode=live`,否则不领取 live 任务。本文已完成的最终复核、不可逆标记、单次提交、禁止付款和异常转人工实现继续有效,不得削弱。
Author
Owner

开始实施 #99。前置 #98 已验收关闭。范围严格保持:live 默认关闭,只在本地明确授权且 Client/设备/正式 Adapter 一致时声明能力;最终提交前重新核验并先持久化不可逆标记;最终按钮只单击一次;不付款、不绕过验证码/登录/风控,不可逆后不重试。实现和验证阶段不执行真实下单。

开始实施 #99。前置 #98 已验收关闭。范围严格保持:live 默认关闭,只在本地明确授权且 Client/设备/正式 Adapter 一致时声明能力;最终提交前重新核验并先持久化不可逆标记;最终按钮只单击一次;不付款、不绕过验证码/登录/风控,不可逆后不重试。实现和验证阶段不执行真实下单。
Author
Owner

实施前代码审查与细化

现有基础:#71/#72/#73/#75 已提供 dry-run 流程、价格校验、irreversible_action_at 字段、崩溃恢复和正式 uiautomator2 演练 Adapter。

本次按以下边界实施:

  1. Admin execution_mode 进入 Client 的 AdminTask、领取校验和 SQLite v3 规范化字段;缺省及旧任务仍为 dry_run,采集任务禁止 live。
  2. 新建本地 live 授权服务。默认缺少设置即关闭;启用必须精确输入确认短语,并绑定已保存 Client ID、Android 设备序列号和确认时间。环境变量、命令行和默认配置不参与启用。
  3. 保留 PddPurchaseAdapter 为无提交方法的演练接口;另建 PddLivePurchaseAdapter,只增加一次性 submit_order_once(),不增加 pay/payment/cancel 方法。TaskDispatcher 只有同时满足本地授权、绑定一致和 live factory 就绪才声明 purchase_mode=live。
  4. live 最终点击前重新读取控件树,精确核对商品、完整规格、数量、价格、库存及唯一提交按钮;先用 Repository 事务写入不可逆时间和步骤,成功后才允许调用一次提交。点击调用无论返回还是异常都进入 reconcile_purchase,不得生成第二次提交路径。
  5. #99 不执行真机真实下单,也不完成订单匹配;只建立单次提交后转只读核单的边界。订单唯一匹配和结果上报由 #100 完成,真机外部操作只在 #101 经当次授权执行。

预计新增/修改:Admin Gateway/HTTP/Mock、task model/schema/repository/dispatcher、live 授权服务、设置 UI/event、采购 service、独立 live Adapter/uiautomator2 实现、详情中文步骤、测试和 Client 基线文档。

## 实施前代码审查与细化 现有基础:#71/#72/#73/#75 已提供 dry-run 流程、价格校验、`irreversible_action_at` 字段、崩溃恢复和正式 uiautomator2 演练 Adapter。 本次按以下边界实施: 1. Admin `execution_mode` 进入 Client 的 `AdminTask`、领取校验和 SQLite v3 规范化字段;缺省及旧任务仍为 `dry_run`,采集任务禁止 live。 2. 新建本地 live 授权服务。默认缺少设置即关闭;启用必须精确输入确认短语,并绑定已保存 Client ID、Android 设备序列号和确认时间。环境变量、命令行和默认配置不参与启用。 3. 保留 `PddPurchaseAdapter` 为无提交方法的演练接口;另建 `PddLivePurchaseAdapter`,只增加一次性 `submit_order_once()`,不增加 pay/payment/cancel 方法。TaskDispatcher 只有同时满足本地授权、绑定一致和 live factory 就绪才声明 `purchase_mode=live`。 4. live 最终点击前重新读取控件树,精确核对商品、完整规格、数量、价格、库存及唯一提交按钮;先用 Repository 事务写入不可逆时间和步骤,成功后才允许调用一次提交。点击调用无论返回还是异常都进入 `reconcile_purchase`,不得生成第二次提交路径。 5. #99 不执行真机真实下单,也不完成订单匹配;只建立单次提交后转只读核单的边界。订单唯一匹配和结果上报由 #100 完成,真机外部操作只在 #101 经当次授权执行。 预计新增/修改:Admin Gateway/HTTP/Mock、task model/schema/repository/dispatcher、live 授权服务、设置 UI/event、采购 service、独立 live Adapter/uiautomator2 实现、详情中文步骤、测试和 Client 基线文档。
Author
Owner

实现进度更新(待提交):

  • 已完成 SQLite v3 迁移,任务落库保存不可变 execution_mode,历史任务安全默认为 dry_run。
  • 设置页新增默认关闭的真实下单授权,绑定 Client ID 与已保存 Android 设备;仅精确输入确认文字后启用,环境变量和调试参数不能开启。
  • dry_run 与 live Adapter 分离;live 最终复核规格、数量、价格、库存和唯一提交目标。
  • 点击前先以事务写入 irreversible_action_at;最终提交最多点击一次,无论返回或异常都只转订单核对,不提供付款或取消路径。
  • 不可逆采购优先于 Outbox 和其他任务执行,避免继续下单。
  • 已更新 Client 架构、数据、接口、UI 和安全基线文档。

验证:在 client 目录执行 C:\Python310\python.exe -m pytest -q --disable-warnings,结果 286 passed。未执行真实手机下单;Wi-Fi 设备留待独立真机验收工单按当次授权验证。

实现进度更新(待提交): - 已完成 SQLite v3 迁移,任务落库保存不可变 execution_mode,历史任务安全默认为 dry_run。 - 设置页新增默认关闭的真实下单授权,绑定 Client ID 与已保存 Android 设备;仅精确输入确认文字后启用,环境变量和调试参数不能开启。 - dry_run 与 live Adapter 分离;live 最终复核规格、数量、价格、库存和唯一提交目标。 - 点击前先以事务写入 irreversible_action_at;最终提交最多点击一次,无论返回或异常都只转订单核对,不提供付款或取消路径。 - 不可逆采购优先于 Outbox 和其他任务执行,避免继续下单。 - 已更新 Client 架构、数据、接口、UI 和安全基线文档。 验证:在 client 目录执行 C:\Python310\python.exe -m pytest -q --disable-warnings,结果 286 passed。未执行真实手机下单;Wi-Fi 设备留待独立真机验收工单按当次授权验证。
Author
Owner

已完成实现并进入待验收:

  • 实现提交:e960cab(feat: 实现受控真实下单安全边界 (#99))
  • 归档提交:16107aa(docs: 归档任务 #99)
  • 本地归档:docs/task/99-受控真实下单安全边界.md
  • 全量测试:286 passed

未执行真实 PDD 下单。当前已有 Wi-Fi Android 设备不等于获得真实提交授权;真机最终提交仍按独立验收工单,在当次明确授权后执行。请按 #99 验收标准验收,本工单保持打开。

已完成实现并进入待验收: - 实现提交:e960cab(feat: 实现受控真实下单安全边界 (#99)) - 归档提交:16107aa(docs: 归档任务 #99) - 本地归档:docs/task/99-受控真实下单安全边界.md - 全量测试:286 passed 未执行真实 PDD 下单。当前已有 Wi-Fi Android 设备不等于获得真实提交授权;真机最终提交仍按独立验收工单,在当次明确授权后执行。请按 #99 验收标准验收,本工单保持打开。
Author
Owner

关联范围变更:#112 将 Admin 新建采购任务固定为 live,但不取消本工单已实现的 Client 本地授权、Client ID/设备绑定、最终复核、不可逆标记和单次提交边界。#99 的实现历史不重写;Admin 默认策略由 #112 单独实施和回退。

关联范围变更:#112 将 Admin 新建采购任务固定为 live,但不取消本工单已实现的 Client 本地授权、Client ID/设备绑定、最终复核、不可逆标记和单次提交边界。#99 的实现历史不重写;Admin 默认策略由 #112 单独实施和回退。
Author
Owner

用户已于 2026-08-11 明确验收通过。

  • 本地归档状态已更新为“已完成,用户验收通过”
  • 验收记录提交:eca9289
  • 本工单按项目流程关闭
用户已于 2026-08-11 明确验收通过。 - 本地归档状态已更新为“已完成,用户验收通过” - 验收记录提交:`eca9289` - 本工单按项目流程关闭
ila closed this issue 2026-08-11 10:58:23 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#99