feat(#67): add Shopee order snapshots to purchase tasks
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Business-Rules-and-Glossary
|
||||
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Business-Rules-and-Glossary.-
|
||||
wiki_revision: 092d7df7156b270dbb2528eb8f28f40640b23cd2
|
||||
synchronized_at: 2026-08-22T02:10:40Z
|
||||
wiki_revision: 1e8dff56860d92c22cba44b2e9c966e58f67d721
|
||||
synchronized_at: 2026-08-22T02:37:22Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# 业务规则与术语
|
||||
@@ -36,7 +36,7 @@ synchronized_at: 2026-08-22T02:10:40Z
|
||||
|
||||
## SYB 商品明细
|
||||
|
||||
- 一行对应 SYB 一条明确的商品/颜色/尺码/数量明细;唯一键为「货运单 `code` + 来源明细 `id`」组合,不是全局唯一 ID(未在多货运单样本中验证过全局唯一性)。
|
||||
- 一行对应 SYB 一条明确的商品/颜色/尺码/数量明细;唯一键为「蝦皮订单号 `code` + 来源明细 `id`」组合,不是全局唯一 ID(未在多货运单样本中验证过全局唯一性)。
|
||||
- `productSpec` 自由文本解析:按最后一个逗号切分为颜色/尺码 → 剥离【】备注 → 判断残留分隔符;解析状态分 `success`/`uncertain`/`failed`,永不猜测原文中不存在的颜色或尺码。
|
||||
- 只有 `success` 状态的解析结果会合并进虾皮商品档案的规格值(来源标记 `import`);`uncertain`/`failed` 只停留在明细行上供人工复核,不污染共享档案。
|
||||
- 金额单位按接口分别定义:`/am/stock/detail/listByStock` 的 `productPrice` 是十进制金额,与 `/am/stock/list` 的 `amtOrder`(×100 整数)不是同一套换算,不可共用。
|
||||
@@ -58,7 +58,7 @@ synchronized_at: 2026-08-22T02:10:40Z
|
||||
|
||||
- 导入由管理员创建,创建成功后立即转入后台执行;页面关闭不取消任务。采购员等其他已登录角色可以查看同步记录,不能开始导入。
|
||||
- 系统同一时刻只运行一个 SYB 导入任务。`syb_sync_run` 的唯一执行槽负责跨进程互斥,内存锁减少同一进程内的竞争;服务重启后遗留的执行中记录标记为“已中断”。
|
||||
- 导入失败或中断时保留已写入商品,记录明确的失败原因和已处理进度;重新导入相同范围按「货运单号 + 明细 ID」覆盖,不产生重复商品。
|
||||
- 导入失败或中断时保留已写入商品,记录明确的失败原因和已处理进度;重新导入相同范围按「订单号 + 明细 ID」覆盖,不产生重复商品。
|
||||
- 每条同步记录保存本次启用店铺集合的 SHA-256 哈希以及各店铺“已导入/已跳过”数量,不保存账号、密码、Cookie、验证码图片或 SYB 原始响应。
|
||||
- 后台任务创建前的内部失败仍向普通用户显示“服务端处理失败”,但使用稳定错误码区分阶段:店铺预检为 `SYNC_SHOP_PREFLIGHT_FAILED`,同步记录创建为 `SYNC_RUN_CREATE_FAILED`。服务端只记录阶段和经过脱敏、截断的底层原因,不记录请求体、凭据、Cookie、Token、验证码或原始响应。
|
||||
|
||||
@@ -109,7 +109,7 @@ synchronized_at: 2026-08-22T02:10:40Z
|
||||
|
||||
- 采购域使用独立的 `purchase_task`、`purchase_task_attempt` 和可选 `pdd_account` 引用;PDD、虾皮和 SYB 商品表不保存采购订单、支付、物流或回填字段。
|
||||
- 正式任务必须引用一条 SYB 商品明细;演练任务可以从 PDD 商品人工创建且不引用 SYB。
|
||||
- 创建时固化三个商品身份、目标和映射规格、数量、价格区间、币种、URL、`goods_id`、规则、设备和可选账号引用。商品档案后续修改不改变任务解释。
|
||||
- 创建时固化三个商品身份、蝦皮订单号、目标和映射规格、数量、价格区间、币种、URL、`goods_id`、规则、设备和可选账号引用。商品档案后续修改不改变任务解释。正式任务的蝦皮订单号来自 SYB 商品 `order_code`,同一订单号可以对应多条商品和多个采购任务,不作为唯一键。
|
||||
- Android 无法可靠识别登录中的 PDD 账号,因此账号引用可空;已知账号才参与账号级串行,未知账号不会阻止采购任务。
|
||||
- 同一 SYB 明细可以保留多个历史采购任务,但最多只能有一个活动任务。重新采购新建任务,旧订单不删除、不覆盖。
|
||||
- `execution_mode` 创建后不可变:`rehearsal` 只能完成商品、规格、数量和价格复核;`live` 才可能获得改地址和创建订单能力。任何模式永远禁止支付。
|
||||
@@ -133,7 +133,7 @@ synchronized_at: 2026-08-22T02:10:40Z
|
||||
- 已创建订单默认禁止再次采购;管理员或采购员可以做一次性重新采购授权,新任务创建成功时在同一事务消耗授权,旧任务和旧订单保留。已标记为已支付的订单不能授权或创建重新采购任务。
|
||||
- 人工回填候选只允许从已支付订单选择;同一 SYB 明细后来选择的订单覆盖旧候选,但不删除旧订单事实。
|
||||
- Admin 采购管理只查看和处理已有任务,不提供创建入口或支付按钮;单条和批量采购任务都从 SYB 商品列表发起。订单结果未知时必须先人工核对并解除;处于该状态时页面不提供重新采购授权。
|
||||
- 采购失败任务可在采购管理当前页批量勾选重试,最多 100 条。重试不修改旧任务,而是用当前 SYB/PDD 档案、当前规格映射、当前价格保护和最新内置采购规则创建新的 `pending` 任务,并生成新任务编号与地址后缀。
|
||||
- 采购失败任务可在采购管理当前页批量勾选重试,最多 100 条。重试不修改旧任务,而是用当前 SYB/PDD 档案、当前规格映射、当前价格保护和最新内置采购规则创建新的 `pending` 任务,并生成新任务编号与地址后缀;来源蝦皮订单号沿用失败任务的不可变快照。
|
||||
- 只有正式采购、未进入不可逆边界、没有订单号或下单时间、且仍是同一 SYB 最新记录的 `failed` 任务可重试。原设备离线、停用、忙碌或能力不足时该项失败且不自动换机;未指定设备时仍由空闲设备领取。
|
||||
- 批量重试逐项处理并允许部分成功;同一请求幂等重放不会重复创建。失败任务不再使用一次性重新采购授权,该授权只保留给已经创建过订单且满足条件的任务。
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Android-Agent-API-Contract
|
||||
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Android-Agent-API-Contract.-
|
||||
wiki_revision: 092d7df7156b270dbb2528eb8f28f40640b23cd2
|
||||
synchronized_at: 2026-08-22T02:10:40Z
|
||||
wiki_revision: 47ecaff133f837394c3d14a9819c37e90855d801
|
||||
synchronized_at: 2026-08-22T02:37:41Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# MVP 共享 API 契约
|
||||
@@ -74,7 +74,7 @@ PATCH /api/admin/v1/syb-products/{productId}/correction
|
||||
|
||||
`sync-runs` 列表支持 `page`、`pageSize`、`status`、`dateFrom`、`dateTo`,详情返回日期范围、状态(`running` / `succeeded` / `failed` / `interrupted`)、处理天数、货运单/明细/新增/覆盖数量、店铺准入与跳过数量、店铺筛选快照哈希、按店铺的 `accepted` / `skipped` 统计、操作人和起止时间。列表和详情对已登录角色只读开放。服务启动时遗留的 `running` 任务改为 `interrupted`;中途失败或中断已经写入的数据保留,重新导入仍按唯一键覆盖。
|
||||
|
||||
列表返回结构化字段(`orderCode`、`shopeeItemId`、`productTitle`、`targetColor`、`targetSize`、`quantity`、`unitPriceCent`、`imageUrl`、`parseStatus`、`parseNote`、`manuallyConfirmed`),不含原始 JSON;`keyword` 匹配货运单号、虾皮商品ID 或商品标题,`parseStatus` 筛选 `success`/`uncertain`/`failed`。详情额外返回 `rawJson`(原始 `details[]` 元素,未做任何改写)。
|
||||
列表返回结构化字段(`orderCode`、`shopeeItemId`、`productTitle`、`targetColor`、`targetSize`、`quantity`、`unitPriceCent`、`imageUrl`、`parseStatus`、`parseNote`、`manuallyConfirmed`),不含原始 JSON;`keyword` 匹配订单号、虾皮商品ID 或商品标题,`parseStatus` 筛选 `success`/`uncertain`/`failed`。详情额外返回 `rawJson`(原始 `details[]` 元素,未做任何改写)。
|
||||
|
||||
`reparse` 与 `reparse-batch` 只读取已保存的 `rawJson` 重新执行解析规则,不请求 SYB 接口;请求体 `force` 为 `true` 时才覆盖 `manuallyConfirmed` 的行,默认跳过并在批量结果中标记 `skipped_manual`。批量结果逐条返回 `outcome`(`reparsed` / `skipped_manual` / `unchanged`)与解析状态变化,`ids` 中任何一个不存在都会使整个请求返回错误(与虾皮商品批量删除的"部分成功"语义不同:ID 不存在通常是操作员选错了页面)。
|
||||
|
||||
@@ -386,7 +386,7 @@ POST /api/agent/v1/tasks/{taskId}/fail
|
||||
| `DEVICE_BUSY` | 设备已有活动任务 | 否 |
|
||||
| `DEVICE_CAPABILITY_MISMATCH` | 设备缺少任务规则要求的版本化能力 | 否 |
|
||||
|
||||
## 采购任务共享契约(#33、#34、#36、#42、#44、#53)
|
||||
## 采购任务共享契约(#33、#34、#36、#42、#44、#53、#67)
|
||||
|
||||
本节固定采购域的数据和接口边界;`purchase_task`、`purchase_task_attempt`、规则校验、服务端 HTTP 状态机、Admin 已有任务管理、SYB 创建入口、Android 演练执行及 #36 正式地址/订单动作已经落地。#36 尚未获得真机创建订单授权和验收。任何实现都不得扩展为自动支付。
|
||||
|
||||
@@ -394,7 +394,7 @@ POST /api/agent/v1/tasks/{taskId}/fail
|
||||
|
||||
- `executionMode` 只能是 `rehearsal` 或 `live`,创建后不可修改。
|
||||
- 正式 `live` 任务必须引用一条 `syb_product`;无副作用的 `rehearsal` 可以不引用 SYB。
|
||||
- 创建时固化 SYB、虾皮商品、PDD 商品、目标规格、映射规格、数量、价格区间、币种、URL、`goods_id`、规则和可选 PDD 账号引用。以后商品档案修改不会改写任务。
|
||||
- 创建时固化 SYB、蝦皮订单号、虾皮商品、PDD 商品、目标规格、映射规格、数量、价格区间、币种、URL、`goods_id`、规则和可选 PDD 账号引用。正式任务的 `shopeeOrderNoSnapshot` 来自创建时的 `syb_product.order_code`;同一订单号可对应多条任务,之后来源商品修改不会改写任务快照。
|
||||
- Android 无法可靠读取当前 PDD 账号,因此 `pddAccountId` 和 `pddAccountRefSnapshot` 均可空。已知账号时参与账号级串行,未知时不阻止任务。
|
||||
- 地址后缀由任务 ID 唯一确定为 `_cg{taskId}`;#34 创建任务时必须在同一事务内回写快照。
|
||||
- 一个任务最多对应一个 PDD 订单;重新采购必须新建任务,旧任务和旧订单保留。
|
||||
@@ -477,7 +477,7 @@ POST /api/agent/v1/tasks/{taskId}/fail
|
||||
|
||||
| 方法 | 路径 | 幂等键 / 说明 |
|
||||
|---|---|---|
|
||||
| `GET` | `/api/admin/v1/purchase-tasks` | 分页列表;可按任务 ID、状态、模式、SYB 商品 ID 和 PDD 订单号筛选 |
|
||||
| `GET` | `/api/admin/v1/purchase-tasks` | 分页列表;可按任务 ID、蝦皮订单号 `shopeeOrderNo`、状态、模式、SYB 商品 ID 和 PDD 订单号筛选 |
|
||||
| `GET` | `/api/admin/v1/purchase-tasks/{taskId}` | 只读任务详情与 attempt 历史;不返回规则原文、Token、凭据、完整地址、控件树或截图 |
|
||||
| `POST` | `/api/admin/v1/purchase-tasks` | `requestId`;单条创建 |
|
||||
| `POST` | `/api/admin/v1/purchase-tasks/batch-preview` | `sybProductIds`(1~100)和可选 `deviceId`;逐条返回是否可创建、价格区间、原因和下一步,不创建任务 |
|
||||
@@ -489,7 +489,7 @@ POST /api/agent/v1/tasks/{taskId}/fail
|
||||
| `POST` | `/api/admin/v1/purchase-tasks/{taskId}/resolve-unknown` | 人工把结果未知解除为已创建订单或已取消 |
|
||||
| `POST` | `/api/admin/v1/purchase-tasks/{taskId}/spec-decision` | 固化第一趟规格探测决策;同一 attempt 不可改写 |
|
||||
|
||||
Admin 列表与详情由 #35 实现;#44 在 SYB 商品列表提供单条/当前页批量创建入口。页面预检只负责提前解释,`batch` 提交时仍逐条执行现有单任务事务和活动任务、订单、支付、设备能力门禁;返回项包含任务号,或失败原因与下一步建议。只有管理员和采购员可以调用。
|
||||
Admin 列表与详情由 #35 实现;#67 增加 `shopeeOrderNoSnapshot` 的列表/详情返回和 `shopeeOrderNo` 筛选,空快照返回空字符串并由页面显示“—”,不与 `pddOrderNo` 混用;#44 在 SYB 商品列表提供单条/当前页批量创建入口。页面预检只负责提前解释,`batch` 提交时仍逐条执行现有单任务事务和活动任务、订单、支付、设备能力门禁;返回项包含任务号,或失败原因与下一步建议。只有管理员和采购员可以调用。
|
||||
|
||||
创建请求的价格保护使用整数分:`referenceUnitPriceCent`、`minUnitPriceCent`、`maxUnitPriceCent` 和 `currency`。执行时以 PDD App 实际单价校验;低于最小值或高于最大值均返回普通人可理解的价格越界错误,不考虑优惠券,不以订单总价替代单价判断。 #44 批量创建不接受浏览器提交价格:服务端从 PDD 颜色规格价格生成 CNY 快照,已映射颜色按该颜色的 0.2~1.5 倍,待规格探测时按全部可用颜色最低价的 0.2 倍到最高价的 1.5 倍;没有可用颜色价格时逐条拒绝。SYB/Shopee 的 TWD 售价不参与 PDD 采购价格保护。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user