feat: 完善 SYB 蝦皮主数据与软删除 (#203 #204 #205)

This commit is contained in:
chengma
2026-08-13 10:39:21 +08:00
parent 3af9bf245a
commit ad1ccc2c60
23 changed files with 864 additions and 90 deletions
+22 -5
View File
@@ -116,6 +116,11 @@ v13(#172)新增 `task_sequences`,把存量 `tasks.task_id` 按类型和创
v14(#196)新增 `syb_allowed_shops` 全局店铺准入表;`syb_sync_runs` 增加
`accepted_stock_count`、`shop_skipped_count` 和 `shop_filter_hash`。旧同步记录回填为
“接受数=原始货运单数、店铺跳过=0”;历史顺运宝货运单不删除。
v15(#203)把历史 `syb_orders` 中每个蝦皮商品最新的非空店铺和图片,以
`source='syb'` 的字段级低优先级来源补入 `shopee_products`。v16(#204)确定性解析
“颜色,尺码【建议】”格式,并为历史数据补建无真实外部 ID 的低优先级蝦皮 SKU;
不明确格式只保留原文。v17(#205)为蝦皮商品增加 `deleted_at`、
`deleted_by_user_id` 和删除状态索引,删除改为可恢复的软删除。
**v3 为什么丢弃旧 `sku_mappings` 数据(见 #20):** 新主键需要 `pdd_option_key`,
这是 Go 的 `service.OptionKey()` 用 `json.Marshal` 算出来的规范化键,SQL 语句
@@ -175,6 +180,8 @@ CREATE TABLE shopee_products (
-- 下面两个是我们自己维护的,报表里没有,导入时绝不能覆盖
pdd_goods_url TEXT, -- ★ 人工填写的 PDD 链接原文
pdd_goods_id TEXT, -- 从 url 解析,指向 pdd_products.goods_id
deleted_at VARCHAR(35), -- 软删除时间;非空时默认业务查询不可见
deleted_by_user_id VARCHAR(191), -- 执行删除的管理员
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
@@ -184,6 +191,7 @@ ALTER TABLE shopee_products ADD CONSTRAINT chk_shopee_products_source
CHECK (source IN ('report', 'syb', 'api'));
CREATE INDEX idx_shopee_products_pdd ON shopee_products(pdd_goods_id);
CREATE INDEX idx_shopee_products_deleted ON shopee_products(deleted_at, updated_at, goods_id);
```
`[必须]` **采集结果和采集状态不在这张表里**,它们属于 PDD 商品,见 §4。
@@ -193,6 +201,11 @@ CREATE INDEX idx_shopee_products_pdd ON shopee_products(pdd_goods_id);
后续 Excel 导入同一 `goods_id` 时必须补全商品信息并把来源提升为 `report`;
导入不得覆盖人工维护的 PDD 关联。
顺运宝同步只把非空店铺和图片补到空字段,或更新同样来自 `syb` 的字段;人工值和
目录接口值不覆盖。后续目录接口可把 `syb` 低优先级值提升为权威来源。软删除商品
不会因顺运宝同步或目录导入自动恢复,SKU、PDD 关联和历史记录全部保留;只能由
管理员显式恢复。存在 `pending/assigned/claimed` 采集或采购任务时禁止软删除。
`pdd_goods_id` 表示"这个蝦皮商品**当前**对应哪个 PDD 商品"。
PDD 商品下架换代时改这里,是一个随时会变的关联,不是永久绑定。
@@ -225,7 +238,8 @@ CREATE INDEX idx_shopee_skus_parse ON shopee_skus(parse_ok);
再按 [商品目录接口契约](10-商品目录接入接口.md) 提交结构化商品、SKU、PDD 和关联。
- `[必须]` 整批只做 upsert,不清空表,也不删除批次中缺席的数据。
- `[必须]` `spec_raw` 原样保留;解析失败由上游明确提交 `parse_ok=false`,Admin 不猜。
- `[必须]` `spec_raw` 原样保留。商品目录解析结果由上游提交;SYB 只对明确的
“颜色,尺码【建议】”二维格式做确定性解析,未知尺码、额外维度和不完整括号均不猜。
- `[必须]` 商品更新不覆盖 `pdd_goods_url` / `pdd_goods_id`,SKU 更新不覆盖 `is_manual`。
- `[必须]` 较旧 `observed_at` 不覆盖较新接口数据。
- 空 PDD 关联可以建立;相同关联幂等;不同关联返回冲突,不静默换品。
@@ -466,13 +480,16 @@ v10 幂等重放 v8、v9 的逐项建列、空值回填、约束和唯一索引
MySQL schema v11(工单 #151)为 `syb_orders` 增加可空 `VARCHAR(500)` 的
`shop_name`,并从合法原始 JSON 的 `$.stock.shopName` 回填历史数据。迁移可重放,
只填仍为空的列;新同步直接更新该列,不把它写入或覆盖蝦皮商品主数据。
只填仍为空的列;新同步直接更新该列。v15(#203)在此基础上把非空店铺和图片作为
`syb` 低优先级字段补入蝦皮商品主数据,但仍不得覆盖人工或目录接口字段。
蝦皮详情把 `syb_orders` 按 `(shopee_goods_id, spec_key)` 聚合为“顺运宝观测规格”:
订单数按唯一 `syb_id` 行计数,累计数量求和,最近一行提供历史台币售价和图片。
该读模型不写入 `shopee_skus`。只有同一商品下恰好一条正式 SKU 的 `spec_raw`
经 `SpecKey()` 后相等时才展示关联;零条或多条都不猜测、不写回。重复同步同一个
`syb_id` 只更新原行,因此不会重复累计。
从 v16 起,同步会把格式明确的规格以 `source='syb'` 写入 `shopee_skus`:内部主键
由商品 ID 和 `spec_key` 确定性生成,真实 `shopee_sku_id` 保持 `NULL`。目录接口后到时
按同一规格身份补上真实 ID,并可替换字段来源为权威来源;人工行永不覆盖。不明确格式
仍只存在于观测读模型中,不创建 SKU。重复同步同一个 `syb_id` 只更新原行,因此不会
重复累计。
`[必须]` 一行对应顺运宝一张货运单的**一个商品明细**(`details[]` 的一项),
不是一张货运单——一张货运单可以有多个商品,各占一行,`syb_id` 用的是