diff --git a/Integrations-shunyunbao-contract.-.md b/Integrations-shunyunbao-contract.-.md new file mode 100644 index 0000000..a78756e --- /dev/null +++ b/Integrations-shunyunbao-contract.-.md @@ -0,0 +1,102 @@ + +> 同步来源:[`docs/integrations/shunyunbao-contract.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/integrations/shunyunbao-contract.md) · commit `afc651f75a3a` + +# 顺运宝 ERP 字段契约 + +> 本文只记录协议结构和字段语义,不保存真实账号、Cookie、JWT、订单号、收件人、 +> 电话、地址、商品内容或原始响应。私有 HAR/响应只允许位于被 Git 忽略的本地目录。 + +## 已确认请求链 + +1. 同一 HTTP Session 获取 `GET /api/p/code1` 验证码。 +2. `POST /am/auth/login` 提交环境变量提供的账号/密码和受控验证码。 +3. 从登录 `data.user` 读取正整数 `id` 和非空 `username`,以同一 Cookie Session 调用 + `GET /am/user/get?id=`;返回身份必须完全一致。 +4. `POST /am/stock/listTotal` 与 `/am/stock/list` 使用“全部单号”条件查询。 +5. `POST /am/stock/detail/listByStock?hist=0` 使用列表 `stock.id` 批量读取详情。 + +本地 HAR 结构确认: + +- “全部单号”查询输入匹配列表 `code`,不保证等于 `orderCode`。 +- 列表 `id` 等于详情请求 `ids[]` 使用的 stock id,也等于详情头 `id`。 +- 详情头 `details[]` 是商品级集合,一个货运单可以有多条商品。 +- 日期区间使用 `t_stock.created`、`op=0`、`type=3`、`optType=0`;具体增量规则属于 + T-224。 + +接口来自 ERP 页面协议,不是已确认的开放 API。生产使用前必须确认厂商授权、请求 +频率、服务账号和个人信息处理规则。 + +## Go 直连迁移契约(T-225) + +T-225 至 T-227 在 `backend-api/internal/platform/shunyunbao` 用脱敏 fixture 固定以下 +内容,并由 API 进程内的 Go source 直接执行: + +- 基础请求 header 固定 `Accept`、`Origin`、`Referer`、`User-Agent` 和 + `X-Requested-With`;base URL 必须是无 userinfo、query、fragment 或路径的 origin。 +- 单号条件为 `t_stock.allcode`、`op=6`、`type=0`、`optType=1`;日期范围为 + `t_stock.created`、`op=0`、`type=3`、`optType=0`,单个 ERP 窗口最多 7 个自然日。 +- `listTotal`、`list` 共享 `history=0`、`length`、`start`、`pageIndex`、`store=false`、 + 已验证 columns 和单一 `queries`;运行时每页固定 20 条、单次最多 100 条。 +- `listByStock?hist=0` 每批最多 100 个去重后的正整数 stock id,详情 `id` 必须与列表 + `stock.id` 一致。 +- 所有结果必须经 Go allowlist 归一化;fixture 专门含收件信息、Cookie/JWT 标记值, + 测试断言它们不会出现在输出或错误里。 + +Go 直连的验证码、登录、Cookie jar 和查询 source 都在 API 进程内。T-230 在未认证时只可将 +验证码图片提交给受控本机/HTTPS OCR endpoint,结果只用于当前登录请求;不得写入 Redis、 +SQLite、普通日志或浏览器。T-236 仅在 ERP 登录精确返回“图片验证码不正确”时,在首次失败后 +额外重试最多 6 次;每次重新获取验证码和调用 OCR,最多 7 次登录且认证总预算为 20 秒。其他 +登录拒绝、OCR、网络或协议错误不重试。T-234 仅允许显式 diagnostics 进程短时输出有效 OCR +文本和固定登录尝试分类;T-235 仅在受锁内存中保存已核验 user id/username,不保存登录 token。 +HTTP 401/403 或 ERP code `-2` 才代表会话失效;其他非登录接口 `status=false` 是协议错误。 +真实线上请求不属于自动化测试。 + +## 身份和规范字段 + +### 货运单 + +| 规范字段 | ERP 来源 | 规则 | +| --- | --- | --- | +| `external_stock_id` | `stock.id` / `detail.id` | 必填正整数,字符串化保存;唯一外部身份 | +| `source_code` | `stock.code` | 受控展示;查询输入不作为主键 | +| `platform_order_no` | `stock.orderCode` | 可空,不进入 URL/普通日志 | +| `shop_name` | `detail.shopName`,回退 `stock.shopName` | 可空,限制长度 | +| `source_created_at` | `detail.created`,回退 `stock.created` | 必须可解析为 ERP 本地时间 | +| `order_status` | `stock.orderStatus` / `detail.status` | 原值字符串化,不猜测数字语义 | +| `purchase_status` | `stock.purchaseStatus` | 原值字符串化,不自动决定采购 | +| `is_canceled` | `stock.isCancel` | 只接受明确布尔/已确认枚举 | + +### 商品明细 + +| 规范字段 | ERP 来源 | 规则 | +| --- | --- | --- | +| `external_item_id` | `detail.details[].id` | 必填正整数;在货运单内唯一 | +| `title` | `productTitle`,可核对回退 `detailProductName` | 去首尾空白;空值进入复核 | +| `product_spec` | `productSpec` | 原样保留,不由 VLM 改写 | +| `sku` | 非空 `sku`,否则 `variationSku` | 仍需 Admin 复核;两者都空时阻塞 | +| `quantity` | `productQty` | 必须为正整数,不能使用货运头总数量代替 | +| `product_thumb_ref` | `productThumb` | 当前确认可能为数字 ERP 引用,不是 URL | +| `purchase_status` | `purchaseStatus` | 原值字符串化,允许值另行确认 | + +`productThumb` 未解析为可鉴权图片内容前,商品状态必须是 `NEEDS_IMAGE`。系统不得把 +数字引用拼接成 URL、抓取未知主机或用其他商品图片补位。 + +## 规范化与版本 + +- canonical JSON 固定 UTF-8、字段顺序和空值规则;对最小化对象计算 SHA-256。 +- `(creator, SHUNYUNBAO, external_stock_id)` 唯一确定货运单。 +- `(freight_order_id, external_item_id)` 唯一确定商品。 +- hash 不变是幂等重放;hash 变化递增 revision,不覆盖已生成采购任务。 +- 同一响应含重复 external item id 且内容不一致时整批失败,不选择其中一条。 +- 缺失详情头、`details` 不是数组或任一商品没有外部 ID时整批失败,不保存半批。 + +## 数据最小化 + +以下字段不得进入本项目数据库、业务响应、普通日志、任务、VLM 或 Git: + +- `receiver`、`receiverTel`、`receiverAddr` 和其他收件个人信息。 +- ERP username/password、验证码、Cookie、JWT、权限和完整用户资料。 +- 未裁剪的 `stock`、`detail`、HAR、HTTP body 和 Redis session JSON。 + +允许保存的审计信息是:source system、外部 ID、规范字段 hash、同步状态、稳定错误码、 +数量和时间。错误信息不得拼接 ERP 原始 body。