@optima-chat/tiktok-cli 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.js +371 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,11 +21,12 @@ tiktok <domain> <verb> --shop <shopId> [--flags]
|
|
|
21
21
|
| `auth link` | 生成店铺绑定授权链接(无需 --shop) |
|
|
22
22
|
| `shops` | 查当前登录用户已授权店铺 |
|
|
23
23
|
| `orders list` | 订单列表(`--status --page-size --since`) |
|
|
24
|
-
| `orders get --id <id
|
|
24
|
+
| `orders get --id <id>[,<id>]` | 订单详情(多个用英文逗号连) |
|
|
25
25
|
| `analytics shop` | 店铺经营数据(`--from --to`,默认近30天) |
|
|
26
26
|
| `analytics products` | 商品维度数据(GMV 降序)。`--version` 默认 `202509`;`202605` 返回 `total_performance` + 分渠道 `*_performance` 组(**组是可选的、字段名三套变体、`overall_performance` 在新版不存在**,见 spec §3.0);未知版本本地拒,平台出新版可 `--force-version` 直接试;`--page-token` 翻页,**末页 `next_page_token` 为空串**(不是缺席) |
|
|
27
27
|
| `products list` | 商品列表 |
|
|
28
28
|
| `promotions list` | 促销活动。`--status` **省略 = 全部状态**(`ONGOING`/`NOT_START`/`EXPIRED`/`DEACTIVATED`;⚠️ 值写错平台**静默忽略并返回全部**,故 CLI **本地硬拒未知值**;平台将来新增值可用 `--force-status` 越过);`--page-size`(默认 20);`--page-token` 翻页,**末页无 `next_page_token`** |
|
|
29
|
+
| `promotions get` | 按 id 读单个促销活动(`--id`):类型、状态、时间窗、挂的商品与每个 SKU 的活动价(一口价 / 秒杀价读 `skus[].activity_price.amount`,百分比读 `skus[].discount`)。平台没回 `products` 时补成 `[]` |
|
|
29
30
|
| `finance statements` | 结算单 |
|
|
30
31
|
|
|
31
32
|
### 建品前置只读辅助(拼商品体用)
|
|
@@ -96,6 +97,8 @@ tiktok products set-price --shop <id> --product <pid> --sku <sid> --price 29.90
|
|
|
96
97
|
| `products set-price` | 改 SKU 售价(`--product --sku --price [--currency]`)。仅 `ACTIVATE` 商品,且不在进行中的促销里(`update-price-202309` 原文)。改价不触发商品重审、立即生效(依据是 `partial-edit-product-202309` 的「`price`/`inventory` 不需 reaudit」,**本端点自己的文档没写这句、也未单独实测**)。 | ✓ 改价+回读 |
|
|
97
98
|
| `products set-inventory` | 改 SKU 库存(`--product --sku --warehouse --quantity`)。只要商品不在 `FREEZE`/`DELETED` 状态都能改(`update-inventory-202309` 原文)。改库存不触发商品重审、立即生效(同上依据,未单独实测)。⚠️ `DRAFT` 商品**未实测** —— 官方只写了「非 `FREEZE`/`DELETED`」,没说 DRAFT 可以;且草稿 SKU 常常还没分仓,会撞 `12052096`。 | ✓ 49→55→49 可逆 |
|
|
98
99
|
| `promotions create-flashsale` | 建秒杀(`--title --product --sku --price [--limit --per-user --hours]`)。两步:建壳+加品 | ✓ 真实建成 |
|
|
100
|
+
| `promotions create-discount` | 建商品折扣活动:`--price` 一口价(`FIXED_PRICE`)或 `--percent` 减 N%(`DIRECT_DISCOUNT`;`85` = 减 85%、按原价 15% 卖,**打 85 折要传 15**),`--title [--product] [--days 180]`。两步:建壳+加品,可多商品;撞重名 / 加品失败时给可粘贴的下一步命令 | ✓ 真实建成(FP;--percent 待活体) |
|
|
101
|
+
| `promotions add-products` | 往已有折扣活动加新 SKU(`--id <activityId> --price|--percent … [--product]`)。预读先于 PUT:类型 / 状态 / 已在活动里的 SKU 都会被拦下;只加不改 | — |
|
|
99
102
|
| `promotions deactivate` | 终止促销活动(`--id`)。不可逆 | ✓ |
|
|
100
103
|
| `products create --body-file <json>` | **生产级建品**(完整商品体 JSON)。dry-run 内嵌 `listing_check` 预检 → `--apply` 建品 → 回读高亮 warnings。⚠️ `save_mode` 默认 `LISTING`:**不写就是建完直接上架送审**(#1958,见下方「送审语义」)。可在 body 里写 `"save_mode": "AS_DRAFT"` 留草稿(**未实测**)。 | ✓ 真实上架 V.V.Love(ACTIVATE) |
|
|
101
104
|
| `products add-variant --product <id> --body-file <json>` | 加规格 SKU(读现有 skus → merge → partial_edit;新 SKU 自动继承 sku_dimensions/sku_weight)。⚠️ **默认送审**(#1958,见下方「送审语义」)。本命令**自构 body**,body-file 里的 `save_mode` **不透传、写了也无效**;要留草稿只能用 `products partial-edit`。 | ✓ 真加变体成功 |
|
package/dist/index.js
CHANGED
|
@@ -134,8 +134,9 @@ function classify(status, body, shop) {
|
|
|
134
134
|
if (status === 0 || body?.code === 0) {
|
|
135
135
|
return { ok: true, data: body.data, meta };
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
if (status ===
|
|
137
|
+
const isBackendEnvelope = typeof body?.code !== "number" && typeof body?.error === "string";
|
|
138
|
+
if (status === 404 && isBackendEnvelope) return { ok: false, error: { code: "SHOP_NOT_AUTHORIZED", message: body.error, retryable: false }, meta };
|
|
139
|
+
if (status === 403 && isBackendEnvelope) return { ok: false, error: { code: "VALIDATION", message: body.error, retryable: false }, meta };
|
|
139
140
|
const tc = body?.code;
|
|
140
141
|
const msg = body?.message ?? body?.error ?? `HTTP ${status}`;
|
|
141
142
|
if (tc === 36009002 || status === 429) return { ok: false, error: { code: "RATE_LIMITED", message: msg, retryable: true, retry_after_s: 30 }, meta };
|
|
@@ -309,11 +310,12 @@ function commandUsage(cmd) {
|
|
|
309
310
|
const flags = cmd.flags?.length ? cmd.flags.map((f) => `--${f}`).join(" ") : "\uFF08\u6CA1\u6709\u4E13\u5C5E\u53C2\u6570\uFF09";
|
|
310
311
|
const shop = cmd.noShop ? "" : " --shop <shopId>";
|
|
311
312
|
const globals = cmd.noShop ? "--apply" : "--shop / --apply";
|
|
313
|
+
const dry = cmd.write ? "\u672C\u547D\u4EE4\u662F\u5199\u64CD\u4F5C\uFF1A\u9ED8\u8BA4 dry-run\uFF08\u53EA\u6253\u5370\u5C06\u53D1\u7684\u8BF7\u6C42\u3001\u4E0D\u53D1\uFF09\uFF0C\u52A0 --apply \u624D\u771F\u53D1\u3002\n" : "";
|
|
312
314
|
return `tiktok ${cmd.name}${shop} [--flags]
|
|
313
315
|
|
|
314
316
|
${cmd.summary}
|
|
315
317
|
|
|
316
|
-
\u8BA4\u7684\u53C2\u6570\uFF1A${flags}\uFF08\u53E6\u6709\u5168\u5C40 ${globals}\uFF09\uFF1B\u4E0D\u8BA4\u7684\u4F1A\u5F53\u573A\u62A5\u9519\u3002
|
|
318
|
+
${dry}\u8BA4\u7684\u53C2\u6570\uFF1A${flags}\uFF08\u53E6\u6709\u5168\u5C40 ${globals}\uFF09\uFF1B\u4E0D\u8BA4\u7684\u4F1A\u5F53\u573A\u62A5\u9519\u3002
|
|
317
319
|
`;
|
|
318
320
|
}
|
|
319
321
|
var today = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -321,6 +323,37 @@ var daysAgo = (n) => new Date(Date.now() - n * 864e5).toISOString().slice(0, 10)
|
|
|
321
323
|
var toEpoch = (v) => /^\d+$/.test(v) ? Number(v) : Math.floor(Date.parse(v) / 1e3);
|
|
322
324
|
var PROMOTION_STATUSES = /* @__PURE__ */ new Set(["ONGOING", "NOT_START", "EXPIRED", "DEACTIVATED"]);
|
|
323
325
|
var ANALYTICS_PRODUCT_VERSIONS = /* @__PURE__ */ new Set(["202509", "202605"]);
|
|
326
|
+
var ADD_TEXT = {
|
|
327
|
+
SUM_ADD: "\u5F80\u5DF2\u6709\u6298\u6263\u6D3B\u52A8\u52A0\u65B0 SKU\uFF08--id <activityId> --price <skuId>:<\u4E00\u53E3\u4EF7>|<productId>/<skuId>:<\u4E00\u53E3\u4EF7>[,...] \u6216 --percent <skuId>:<\u51CFN%>[,...] [--product]\uFF09\u3002\u5148\u8BFB\u6D3B\u52A8\u6838\u5BF9\u7C7B\u578B\u4E0E\u5DF2\u6709 SKU \u518D\u52A0\u54C1\u3001\u56DE\u8BFB\uFF1B\u53EA\u52A0\u4E0D\u6539\uFF0C\u5DF2\u5728\u6D3B\u52A8\u91CC\u7684 SKU \u4F1A\u88AB\u62E6\u4E0B\u3002--percent 85 = \u51CF85%\uFF08\u625385\u6298\u8981\u4F2015\uFF09",
|
|
328
|
+
SUM_GET: "\u6309 id \u8BFB\u5355\u4E2A\u4FC3\u9500\u6D3B\u52A8\uFF08--id <activityId>\uFF09\uFF1A\u7C7B\u578B\u3001\u72B6\u6001\u3001\u65F6\u95F4\u7A97\u3001\u6302\u7684\u5546\u54C1\u4E0E\u6BCF\u4E2A SKU \u7684\u6D3B\u52A8\u4EF7\uFF08\u4E00\u53E3\u4EF7 / \u79D2\u6740\u4EF7\u8BFB skus[].activity_price.amount\uFF0C\u767E\u5206\u6BD4\u8BFB skus[].discount\uFF09",
|
|
329
|
+
HUMAN_ADD: (id, list) => `\u5F80\u6D3B\u52A8 ${id} \u52A0\uFF1A${list}\u3002\u53EA\u52A0\u65B0 SKU\uFF1B\u5DF2\u5728\u6D3B\u52A8\u91CC\u7684\u4F1A\u5728 --apply \u9884\u8BFB\u65F6\u88AB\u62E6\u4E0B\u3002`,
|
|
330
|
+
AV2: "\u672C\u547D\u4EE4\u7528 --id \u4F20\u6D3B\u52A8 id\uFF08\u6CA1\u6709 --activity-id\uFF09\uFF0C\u5982 --id 7686081985965900001",
|
|
331
|
+
AV3: (rest, flag) => `\u591A\u4F59\u7684\u4F4D\u7F6E\u53C2\u6570\u300C${rest}\u300D\u2014\u2014\u6BCF\u4E2A\u53C2\u6570\u53EA\u80FD\u5E26\u4E00\u4E2A\u503C\u3002\u591A\u4E2A SKU \u8981\u7528\u9017\u53F7\u8FDE\u6210\u4E00\u4E2A --${flag}\uFF0C\u5982 --${flag} A:12,B:15\uFF08\u4E0D\u80FD\u7528\u7A7A\u683C\u5206\u9694\uFF09`,
|
|
332
|
+
GV3: (rest) => `\u591A\u4F59\u7684\u4F4D\u7F6E\u53C2\u6570\u300C${rest}\u300D\u2014\u2014\u6BCF\u4E2A\u53C2\u6570\u53EA\u80FD\u5E26\u4E00\u4E2A\u503C\u3002`,
|
|
333
|
+
AP1: (shop, id) => `\u6CA1\u8BFB\u5230\u6D3B\u52A8 ${id}\uFF0C\u672A\u52A0\u4EFB\u4F55\u5546\u54C1\uFF1B\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u786E\u8BA4\u6D3B\u52A8\u5B58\u5728\u3002`,
|
|
334
|
+
AP1N: (id) => `\u8BFB\u53D6\u6D3B\u52A8 ${id} \u5931\u8D25\uFF08\u7F51\u7EDC / \u670D\u52A1\u7AEF\u6682\u65F6\u6027\u9519\u8BEF\uFF09\uFF0C\u672A\u5199\u4EFB\u4F55\u4E1C\u897F\uFF0C\u53EF\u4EE5\u539F\u6837\u91CD\u8DD1\u672C\u547D\u4EE4\u3002`,
|
|
335
|
+
AP1M: (shop, id) => `\u9884\u8BFB\u5230\u7684\u6D3B\u52A8 ${id} \u5F62\u72B6\u5F02\u5E38\uFF08\u7F3A activity_type \u6216 products\uFF09\uFF0C\u672A\u5199\u4EFB\u4F55\u4E1C\u897F\uFF1B\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u770B\u6D3B\u52A8\u8BE6\u60C5\uFF08\u6CE8\u610F get \u4F1A\u628A\u5E73\u53F0\u6CA1\u56DE\u7684 products \u8865\u6210 []\uFF0C\u8981\u770B\u5E73\u53F0\u539F\u6837\u54CD\u5E94\u5F97\u76F4\u8FDE\uFF09\u3002`,
|
|
336
|
+
AT1: (id) => `\u6D3B\u52A8 ${id} \u662F FIXED_PRICE\uFF08\u4E00\u53E3\u4EF7\uFF09\uFF0C\u8981\u7528 --price <skuId>:<\u4E00\u53E3\u4EF7>\uFF1B--percent \u53EA\u7528\u4E8E DIRECT_DISCOUNT \u6D3B\u52A8\u3002`,
|
|
337
|
+
AT2: (id) => `\u6D3B\u52A8 ${id} \u662F DIRECT_DISCOUNT\uFF08\u767E\u5206\u6BD4\uFF09\uFF0C\u8981\u7528 --percent <skuId>:<\u51CFN%>\uFF1B--price \u53EA\u7528\u4E8E FIXED_PRICE \u6D3B\u52A8\u3002`,
|
|
338
|
+
AT3: (id) => `\u6D3B\u52A8 ${id} \u662F FLASHSALE\uFF08\u79D2\u6740\uFF09\uFF1A\u79D2\u6740\u6D3B\u52A8\u52A0\u54C1\u4E0D\u5728\u672C\u547D\u4EE4\u8303\u56F4\uFF0C\u53E6\u5EFA\u4E00\u573A\u7528 tiktok promotions create-flashsale\u3002`,
|
|
339
|
+
AT4: (id, type) => `\u6D3B\u52A8 ${id} \u7684\u7C7B\u578B\u662F ${type}\uFF0C\u672C\u547D\u4EE4\u53EA\u652F\u6301\u5F80 FIXED_PRICE / DIRECT_DISCOUNT \u6D3B\u52A8\u52A0\u54C1\u3002`,
|
|
340
|
+
AS1: (id, status, allowed) => `\u6D3B\u52A8 ${id} \u7684\u72B6\u6001\u662F ${status}\uFF0C\u53EA\u6709 ${allowed} \u7684\u6D3B\u52A8\u80FD\u7528\u672C\u547D\u4EE4\u52A0\u54C1\u3002`,
|
|
341
|
+
AL1: (id, level) => `\u6D3B\u52A8 ${id} \u7684 product_level \u662F ${level}\uFF0C\u672C\u547D\u4EE4\u53EA\u652F\u6301 VARIATION\uFF08\u6309 SKU \u5B9A\u4EF7\uFF09\u7684\u6D3B\u52A8\u3002`,
|
|
342
|
+
AD1: (id, sids) => `\u8FD9\u4E9B SKU \u5DF2\u5728\u6D3B\u52A8 ${id} \u91CC\u3001\u4F46\u503C\u4E0E\u672C\u6B21\u63D0\u4EA4\u4E0D\u540C\uFF1A${sids}\u3002\u6539\u5DF2\u5728\u6D3B\u52A8\u91CC\u7684 SKU \u7684\u4EF7 / \u6298\u6263\u4E0D\u5728\u672C\u547D\u4EE4\u8303\u56F4\uFF08\u91CD\u590D\u63D0\u4EA4\u7684\u5E73\u53F0\u884C\u4E3A\u672A\u5B9E\u6D4B\uFF09\uFF0C\u4ECD\u8D70\u6D4F\u89C8\u5668\u3002`,
|
|
343
|
+
AD1_REST: (addCmd) => `\u6CA1\u5728\u6D3B\u52A8\u91CC\u7684\u53EF\u4EE5\u8FD9\u6837\u52A0\uFF1A${addCmd}`,
|
|
344
|
+
AD2: (id, sids, addCmd) => `\u8FD9\u4E9B SKU \u5DF2\u6309\u672C\u6B21\u63D0\u4EA4\u7684\u503C\u5728\u6D3B\u52A8 ${id} \u91CC\uFF0C\u65E0\u9700\u518D\u52A0\uFF1A${sids}\u3002\u5176\u4F59\u7684\u8FD9\u6837\u52A0\uFF1A${addCmd}`,
|
|
345
|
+
AD3: (n, id) => `\u672C\u6B21\u63D0\u4EA4\u7684 ${n} \u4E2A SKU \u90FD\u5DF2\u6309\u63D0\u4EA4\u7684\u503C\u5728\u6D3B\u52A8 ${id} \u91CC\u2014\u2014\u65E0\u9700\u518D\u52A0\uFF0C\u522B\u91CD\u8DD1\u3002`,
|
|
346
|
+
AW1: (shop, id) => `\u5DF2\u63D0\u4EA4\u5230\u6D3B\u52A8 ${id}\uFF0C\u4F46\u56DE\u8BFB\u5931\u8D25\uFF0C\u672A\u80FD\u9A8C\u8BC1\u672C\u6B21\u7684 SKU \u662F\u5426\u6302\u4E0A\u2014\u2014\u4E0D\u8981\u91CD\u8DD1\u672C\u547D\u4EE4\uFF1B\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u6838\u5BF9\uFF0C\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u54EA\u4E9B SKU \u672A\u786E\u8BA4\u6302\u4E0A\u3002`,
|
|
347
|
+
AW2: (id, problems) => `\u5DF2\u63D0\u4EA4\u5230\u6D3B\u52A8 ${id}\uFF0C\u4F46\u56DE\u8BFB\u4E0E\u63D0\u4EA4\u4E0D\u4E00\u81F4\uFF1A${problems}\u2014\u2014\u4E0D\u8981\u91CD\u8DD1\u672C\u547D\u4EE4\uFF1B\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u54EA\u4E9B SKU \u672A\u786E\u8BA4\u6302\u4E0A\u3002`,
|
|
348
|
+
AW2_MISS: (addCmd) => `\u7F3A\u7684\u53EF\u4EE5\u8FD9\u6837\u8865\uFF1A${addCmd}`,
|
|
349
|
+
AW3: (shop, id, lost) => `\u26A0\uFE0F \u6D3B\u52A8 ${id} \u539F\u6709\u7684\u5546\u54C1\u5728\u56DE\u8BFB\u91CC\u5BF9\u4E0D\u4E0A\uFF1A${lost}\u2014\u2014\u52A0\u54C1\u53EF\u80FD\u8986\u76D6\u4E86\u539F\u6709\u5546\u54C1\u3002\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\uFF0C\u5E76\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u6838\u5BF9\u3002`,
|
|
350
|
+
AN1: (n, id) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u4F46\u56DE\u8BFB\u663E\u793A\u63D0\u4EA4\u7684 ${n} \u4E2A SKU \u90FD\u5DF2\u6302\u4E0A\u6D3B\u52A8 ${id}\u2014\u2014\u522B\u91CD\u8DD1\u3002`,
|
|
351
|
+
AN2: (id) => `\u52A0\u5546\u54C1\u5931\u8D25\uFF0C\u56DE\u8BFB\u663E\u793A\u672C\u6B21\u63D0\u4EA4\u7684 SKU \u4E00\u4E2A\u90FD\u6CA1\u6302\u4E0A\u6D3B\u52A8 ${id}\u3002\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u53C2\u6570\u540E\u91CD\u8DD1\u672C\u547D\u4EE4\u5373\u53EF\uFF08\u53EA\u6709\u9650\u6D41\u3001\u7F51\u7EDC\u7C7B\u62A5\u9519\u624D\u539F\u6837\u91CD\u8DD1\uFF09\u3002`,
|
|
352
|
+
AN3: (problems) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u56DE\u8BFB\u663E\u793A\u672C\u6B21\u63D0\u4EA4\u7684\u6CA1\u6709\u5168\u90E8\u6302\u4E0A\uFF1A${problems}\u3002`,
|
|
353
|
+
AN3_MISS: (addCmd) => `\u7F3A\u7684\u8865\u4E0A\uFF1A${addCmd}\uFF08\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u540E\u518D\u8865\uFF09\u3002`,
|
|
354
|
+
AN3_MIS: "\u503C\u4E0D\u7B26\u7684\u6309\u8BFB\u56DE\u7684\u503C\u751F\u6548\uFF0C\u6539\u4EF7 / \u6539\u6298\u6263\u4E0D\u5728\u672C\u547D\u4EE4\u8303\u56F4\u3002",
|
|
355
|
+
AN4: (shop, id) => `\u52A0\u5546\u54C1\u5931\u8D25\uFF0C\u56DE\u8BFB\u4E5F\u5931\u8D25\u4E86\uFF0C\u67E5\u4E0D\u5230\u6D3B\u52A8 ${id} \u91CC\u672C\u6B21\u7684 SKU \u6709\u6CA1\u6709\u6302\u4E0A\u3002\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u6838\u5BF9\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8DD1\uFF08\u5DF2\u6302\u4E0A\u7684\u4F1A\u5728\u9884\u8BFB\u90A3\u6B65\u88AB\u8BC6\u522B\uFF0C\u91CD\u8DD1\u4E0D\u4F1A\u91CD\u590D\u52A0\uFF09\u3002`
|
|
356
|
+
};
|
|
324
357
|
var COMMANDS = [
|
|
325
358
|
{
|
|
326
359
|
name: "orders list",
|
|
@@ -346,9 +379,11 @@ var COMMANDS = [
|
|
|
346
379
|
},
|
|
347
380
|
{
|
|
348
381
|
name: "orders get",
|
|
349
|
-
summary: "\u8BA2\u5355\u8BE6\u60C5\uFF08--id \u5FC5\u586B\uFF09",
|
|
382
|
+
summary: "\u8BA2\u5355\u8BE6\u60C5\uFF08--id \u5FC5\u586B\uFF0C\u591A\u4E2A\u7528\u82F1\u6587\u9017\u53F7\u8FDE\uFF09",
|
|
350
383
|
flags: ["id"],
|
|
351
|
-
|
|
384
|
+
// 🔴 Get Order Detail 是 GET /order/202309/orders?ids=a,b(#42:原来写成 …/orders/detail,
|
|
385
|
+
// 平台回 36009009 Invalid path;cn-stage 测试店 2026-09-20 实打本路径 200)
|
|
386
|
+
run: ({ shop, args: args2 }) => proxy("GET", shop, "/order/202309/orders", { query: { ids: args2.id } })
|
|
352
387
|
},
|
|
353
388
|
// ── 售后(退货/取消)只读 ──
|
|
354
389
|
{
|
|
@@ -950,20 +985,26 @@ var COMMANDS = [
|
|
|
950
985
|
},
|
|
951
986
|
{
|
|
952
987
|
name: "promotions create-discount",
|
|
953
|
-
summary: "\u5EFA\u5546\u54C1\u6298\u6263\u6D3B\u52A8 FIXED_PRICE\uFF08--title [--product] --price <skuId>:<\u4E00\u53E3\u4EF7>|<productId>/<skuId>:<\u4E00\u53E3\u4EF7>[,...] [--days 180]\uFF09\u3002\u4E24\u6B65:\u5EFA\u58F3+\u52A0\u54C1\uFF0C\u53EF\u591A\u5546\u54C1",
|
|
954
|
-
flags: ["days", "price", "product", "title"],
|
|
988
|
+
summary: "\u5EFA\u5546\u54C1\u6298\u6263\u6D3B\u52A8 FIXED_PRICE\uFF08--price \u4E00\u53E3\u4EF7\uFF09\u6216 DIRECT_DISCOUNT\uFF08--percent \u51CFN%\uFF09\uFF08--title [--product] --price <skuId>:<\u4E00\u53E3\u4EF7>|<productId>/<skuId>:<\u4E00\u53E3\u4EF7>[,...] \u6216 --percent <skuId>:<\u51CFN%>|<productId>/<skuId>:<\u51CFN%>[,...] [--days 180]\uFF09\u3002--percent 85 = \u51CF85%\u3001\u6309\u539F\u4EF715%\u5356\uFF08\u625385\u6298\u8981\u4F2015\uFF09\u3002\u4E24\u6B65:\u5EFA\u58F3+\u52A0\u54C1\uFF0C\u53EF\u591A\u5546\u54C1",
|
|
989
|
+
flags: ["days", "percent", "price", "product", "title"],
|
|
955
990
|
write: true,
|
|
956
991
|
validate: validateCreateDiscount,
|
|
957
992
|
preview: ({ args: args2 }) => {
|
|
958
993
|
const { begin, end } = discountWindow(args2);
|
|
959
994
|
return [
|
|
960
995
|
{ step: "1/2 \u5EFA\u6D3B\u52A8\u58F3", method: "POST", path: "/promotion/202309/activities", body: discountActivityBody(args2, begin, end) },
|
|
961
|
-
{ step: "2/2 \u52A0\u5546\u54C1+\u4E00\u53E3\u4EF7", method: "PUT", path: "/promotion/202309/activities/{activity_id}/products", body: discountProductsBody(args2), human: discountHuman(args2) }
|
|
996
|
+
{ step: discountValueFlag(args2) === "percent" ? "2/2 \u52A0\u5546\u54C1+\u51CFN%" : "2/2 \u52A0\u5546\u54C1+\u4E00\u53E3\u4EF7", method: "PUT", path: "/promotion/202309/activities/{activity_id}/products", body: discountProductsBody(args2), human: discountHuman(args2) }
|
|
962
997
|
];
|
|
963
998
|
},
|
|
964
999
|
run: async ({ shop, args: args2 }) => {
|
|
965
1000
|
const { begin, end } = discountWindow(args2);
|
|
966
1001
|
const submitted = submittedSkus(args2);
|
|
1002
|
+
const dd = discountValueFlag(args2) === "percent";
|
|
1003
|
+
const field = dd ? "discount" : "amount";
|
|
1004
|
+
const flag = discountValueFlag(args2);
|
|
1005
|
+
const rawVal = discountValueRaw(args2);
|
|
1006
|
+
const allItems = rawVal.split(",");
|
|
1007
|
+
const intent = { type: dd ? "DIRECT_DISCOUNT" : "FIXED_PRICE", flag, days: Number(args2.days ?? 180), addCmd: (aid) => addProductsCmd(shop, aid, args2.product, flag, allItems, true) };
|
|
967
1008
|
const created = await proxy("POST", shop, "/promotion/202309/activities", { body: discountActivityBody(args2, begin, end) });
|
|
968
1009
|
if (!created.ok) {
|
|
969
1010
|
const err = created.error;
|
|
@@ -971,7 +1012,7 @@ var COMMANDS = [
|
|
|
971
1012
|
case "maybe_landed":
|
|
972
1013
|
return { ...created, error: { ...err, message: `${err.message} ${DISCOUNT_TEXT.maybeLanded}` } };
|
|
973
1014
|
case "dup":
|
|
974
|
-
return { ...created, error: { ...err, message: `${err.message} ${await dupSelfCheck(shop, args2.title, submitted)}` } };
|
|
1015
|
+
return { ...created, error: { ...err, message: `${err.message} ${await dupSelfCheck(shop, args2.title, submitted, field, intent)}` } };
|
|
975
1016
|
case "rejected":
|
|
976
1017
|
return created;
|
|
977
1018
|
}
|
|
@@ -993,20 +1034,21 @@ var COMMANDS = [
|
|
|
993
1034
|
if (!withProducts.ok) {
|
|
994
1035
|
const { retry_after_s: _dropped, ...err } = withProducts.error;
|
|
995
1036
|
let note;
|
|
996
|
-
const c = rb.ok ? compareReadback(submitted, rb.data) : null;
|
|
1037
|
+
const c = rb.ok ? compareReadback(submitted, rb.data, field) : null;
|
|
997
1038
|
if (!c) note = DISCOUNT_TEXT.addFailReadbackFailed(shop, activityId);
|
|
998
1039
|
else {
|
|
999
|
-
if (c.missing.length === 0 && c.mismatched.length === 0) note = DISCOUNT_TEXT.addFailAllAttached(submitted.length, activityId);
|
|
1000
|
-
else if (c.missing.length === submitted.length && c.productCount === 0) note = DISCOUNT_TEXT.addFailNoneAttached(shop, activityId);
|
|
1001
|
-
else note = DISCOUNT_TEXT.
|
|
1040
|
+
if (c.missing.length === 0 && c.mismatched.length === 0) note = DISCOUNT_TEXT.addFailAllAttached(submitted.length, activityId, dd);
|
|
1041
|
+
else if (c.missing.length === submitted.length && c.productCount === 0) note = DISCOUNT_TEXT.addFailNoneAttached(shop, activityId, addProductsCmd(shop, activityId, args2.product, flag, allItems, false));
|
|
1042
|
+
else if (c.missing.length === 0) note = DISCOUNT_TEXT.addFailPartialMismatch(problemsText(c, field), shop, activityId, dd);
|
|
1043
|
+
else note = DISCOUNT_TEXT.addFailPartial(problemsText(c, field), shop, activityId, addProductsCmd(shop, activityId, args2.product, flag, rawItemsFor(rawVal, c.missing), false), dd);
|
|
1002
1044
|
}
|
|
1003
1045
|
return { ok: false, error: { ...err, retryable: false }, data: { activity_id: activityId, readback, note }, meta: withProducts.meta };
|
|
1004
1046
|
}
|
|
1005
1047
|
const ours = [];
|
|
1006
|
-
const diff = rb.ok ? compareReadback(submitted, rb.data) : null;
|
|
1007
|
-
if (!diff) ours.push(DISCOUNT_TEXT.readbackFailed(activityId));
|
|
1048
|
+
const diff = rb.ok ? compareReadback(submitted, rb.data, field) : null;
|
|
1049
|
+
if (!diff) ours.push(DISCOUNT_TEXT.readbackFailed(shop, activityId));
|
|
1008
1050
|
else {
|
|
1009
|
-
const problems = problemsText(diff);
|
|
1051
|
+
const problems = problemsText(diff, field);
|
|
1010
1052
|
if (problems) ours.push(DISCOUNT_TEXT.readbackDiffers(activityId, problems));
|
|
1011
1053
|
}
|
|
1012
1054
|
const putData = withProducts.data ?? {};
|
|
@@ -1015,6 +1057,25 @@ var COMMANDS = [
|
|
|
1015
1057
|
return { ok: true, data, meta: withProducts.meta };
|
|
1016
1058
|
}
|
|
1017
1059
|
},
|
|
1060
|
+
{
|
|
1061
|
+
name: "promotions add-products",
|
|
1062
|
+
summary: ADD_TEXT.SUM_ADD,
|
|
1063
|
+
flags: ["id", "percent", "price", "product"],
|
|
1064
|
+
write: true,
|
|
1065
|
+
validate: validateAddProducts,
|
|
1066
|
+
// 🔴 命令块只字面读 args.id / args.product,值旗标经 discountValueFlag / discountValueRaw(它们字面读 args.percent / args.price);
|
|
1067
|
+
// ⛔ 不得提到 discountHuman / validateCreateDiscount / discountActivityBody / discountWindow(它们读 days / title,本命令没有)
|
|
1068
|
+
preview: ({ args: args2 }) => addProductsPlan(args2.id, discountValueFlag(args2), discountValueRaw(args2), args2.product),
|
|
1069
|
+
run: ({ shop, args: args2 }) => runAddProducts(shop, args2.id, discountValueFlag(args2), discountValueRaw(args2), args2.product)
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
name: "promotions get",
|
|
1073
|
+
summary: ADD_TEXT.SUM_GET,
|
|
1074
|
+
flags: ["id"],
|
|
1075
|
+
listKey: "products",
|
|
1076
|
+
validate: validateGet,
|
|
1077
|
+
run: ({ shop, args: args2 }) => runGet(shop, args2.id)
|
|
1078
|
+
},
|
|
1018
1079
|
{
|
|
1019
1080
|
name: "promotions deactivate",
|
|
1020
1081
|
summary: "\u7EC8\u6B62/\u505C\u7528\u4FC3\u9500\u6D3B\u52A8\uFF08--id \u5FC5\u586B\uFF09\u3002\u4E0D\u53EF\u9006",
|
|
@@ -1463,27 +1524,41 @@ function findCommand(tokens) {
|
|
|
1463
1524
|
}
|
|
1464
1525
|
return null;
|
|
1465
1526
|
}
|
|
1466
|
-
var DISCOUNT_FLAGS = ["shop", "apply", "actor", "title", "product", "price", "days"];
|
|
1527
|
+
var DISCOUNT_FLAGS = ["shop", "apply", "actor", "title", "product", "price", "percent", "days"];
|
|
1528
|
+
function discountValueFlag(args2) {
|
|
1529
|
+
return "percent" in args2 ? "percent" : "price";
|
|
1530
|
+
}
|
|
1531
|
+
function discountValueRaw(args2) {
|
|
1532
|
+
return discountValueFlag(args2) === "percent" ? args2.percent ?? "" : args2.price ?? "";
|
|
1533
|
+
}
|
|
1467
1534
|
var PRICE_ITEM = /^(?:([^:,\s/]+)\/)?([^:,\s/]+):(0|[1-9]\d*)(?:\.(\d{1,2}))?$/;
|
|
1468
|
-
|
|
1535
|
+
var PCT_ITEM = /^(?:([^:,\s/]+)\/)?([^:,\s/]+):([1-9]\d?)$/;
|
|
1536
|
+
function parsePriceItems(raw, defaultProduct, flag = "price") {
|
|
1469
1537
|
const items = [];
|
|
1470
1538
|
const seen = /* @__PURE__ */ new Set();
|
|
1539
|
+
const unit = flag === "percent" ? "<\u51CFN%>" : "<\u4EF7>";
|
|
1471
1540
|
for (const part of raw.split(",")) {
|
|
1472
|
-
const m = PRICE_ITEM.exec(part);
|
|
1541
|
+
const m = (flag === "percent" ? PCT_ITEM : PRICE_ITEM).exec(part);
|
|
1473
1542
|
if (!m) {
|
|
1474
|
-
return { ok: false, message: `--price \u6BCF\u4E00\u9879\u5FC5\u987B\u662F <skuId>:<\u4E00\u53E3\u4EF7> \u6216 <productId>/<skuId>:<\u4E00\u53E3\u4EF7>\uFF08\u5341\u8FDB\u5236\u6570\u5B57\uFF0C\u6700\u591A\u4E24\u4F4D\u5C0F\u6570\u3001\u4E0D\u8981\u524D\u5BFC\u96F6\uFF0C\u5982 25.42\uFF09\uFF0C\u591A\u9879\u7528\u9017\u53F7\u8FDE\u63A5\u3001\u5404\u9879\u4E4B\u95F4\u4E0D\u8981\u6709\u7A7A\u683C\uFF0C\u5982 --price 173707:29.90,173708:32.00\uFF1B\u6536\u5230\u300C${part}\u300D` };
|
|
1543
|
+
return flag === "percent" ? { ok: false, message: `--percent \u6BCF\u4E00\u9879\u5FC5\u987B\u662F <skuId>:<N> \u6216 <productId>/<skuId>:<N>\uFF0CN \u662F 1\u201399 \u7684\u6574\u6570\uFF0C\u8868\u793A\u300C\u51CF N%\u300D\uFF0885 = \u51CF 85%\uFF0C\u6309\u539F\u4EF7 15% \u5356\uFF1B\u5E97\u4E3B\u8BF4\u300C\u6253 85 \u6298\u300D\u8981\u4F20 15\uFF09\uFF1B\u6536\u5230\u300C${part}\u300D` } : { ok: false, message: `--price \u6BCF\u4E00\u9879\u5FC5\u987B\u662F <skuId>:<\u4E00\u53E3\u4EF7> \u6216 <productId>/<skuId>:<\u4E00\u53E3\u4EF7>\uFF08\u5341\u8FDB\u5236\u6570\u5B57\uFF0C\u6700\u591A\u4E24\u4F4D\u5C0F\u6570\u3001\u4E0D\u8981\u524D\u5BFC\u96F6\uFF0C\u5982 25.42\uFF09\uFF0C\u591A\u9879\u7528\u9017\u53F7\u8FDE\u63A5\u3001\u5404\u9879\u4E4B\u95F4\u4E0D\u8981\u6709\u7A7A\u683C\uFF0C\u5982 --price 173707:29.90,173708:32.00\uFF1B\u6536\u5230\u300C${part}\u300D` };
|
|
1475
1544
|
}
|
|
1476
|
-
const [, explicitPid, sid
|
|
1545
|
+
const [, explicitPid, sid] = m;
|
|
1477
1546
|
if (explicitPid && defaultProduct && explicitPid !== defaultProduct) {
|
|
1478
|
-
return { ok: false, message:
|
|
1547
|
+
return { ok: false, message: `--${flag} \u7684\u300C${part}\u300D\u6307\u5B9A\u4E86\u5546\u54C1 ${explicitPid}\uFF0C\u4E0E --product ${defaultProduct} \u4E0D\u4E00\u81F4\uFF1B\u591A\u5546\u54C1\u8BF7\u628A --product \u53BB\u6389\u3001\u6BCF\u9879\u90FD\u5199\u6210 <productId>/<skuId>:${unit}` };
|
|
1479
1548
|
}
|
|
1480
1549
|
const pid = explicitPid ?? defaultProduct;
|
|
1481
1550
|
if (!pid) {
|
|
1482
|
-
return { ok: false, message:
|
|
1551
|
+
return { ok: false, message: `--${flag} \u7684\u300C${part}\u300D\u6CA1\u5E26 productId\uFF0C\u800C\u4F60\u4E5F\u6CA1\u4F20 --product\uFF1B\u8981\u4E48\u52A0 --product\uFF0C\u8981\u4E48\u5199\u6210 <productId>/<skuId>:${unit}` };
|
|
1552
|
+
}
|
|
1553
|
+
let amount;
|
|
1554
|
+
if (flag === "percent") {
|
|
1555
|
+
amount = m[3];
|
|
1556
|
+
} else {
|
|
1557
|
+
const [, , , intPart, frac] = m;
|
|
1558
|
+
amount = frac === void 0 ? intPart : `${intPart}.${frac}`;
|
|
1559
|
+
if (!(Number(amount) > 0)) return { ok: false, message: `--price \u7684\u4E00\u53E3\u4EF7\u5FC5\u987B\u5927\u4E8E 0\uFF1B\u6536\u5230\u300C${part}\u300D` };
|
|
1483
1560
|
}
|
|
1484
|
-
|
|
1485
|
-
if (!(Number(amount) > 0)) return { ok: false, message: `--price \u7684\u4E00\u53E3\u4EF7\u5FC5\u987B\u5927\u4E8E 0\uFF1B\u6536\u5230\u300C${part}\u300D` };
|
|
1486
|
-
if (seen.has(sid)) return { ok: false, message: `--price \u91CC\u540C\u4E00\u4E2A skuId \u91CD\u590D\u51FA\u73B0\uFF1A${sid}` };
|
|
1561
|
+
if (seen.has(sid)) return { ok: false, message: `--${flag} \u91CC\u540C\u4E00\u4E2A skuId \u91CD\u590D\u51FA\u73B0\uFF1A${sid}` };
|
|
1487
1562
|
seen.add(sid);
|
|
1488
1563
|
items.push({ pid, sid, amount });
|
|
1489
1564
|
}
|
|
@@ -1498,15 +1573,14 @@ function discountWindow(args2) {
|
|
|
1498
1573
|
function discountActivityBody(args2, begin, end) {
|
|
1499
1574
|
return {
|
|
1500
1575
|
title: args2.title,
|
|
1501
|
-
|
|
1576
|
+
// 🔴 由常量变条件 —— 正是 #9 的根因形态(字段写死);P1/P2 钉 DD、P9 钉 FP 逐字不变
|
|
1577
|
+
activity_type: discountValueFlag(args2) === "percent" ? "DIRECT_DISCOUNT" : "FIXED_PRICE",
|
|
1502
1578
|
product_level: "VARIATION",
|
|
1503
1579
|
begin_time: begin,
|
|
1504
1580
|
end_time: end
|
|
1505
1581
|
};
|
|
1506
1582
|
}
|
|
1507
|
-
function
|
|
1508
|
-
const parsed = parsePriceItems(args2.price ?? "", args2.product);
|
|
1509
|
-
const items = parsed.ok ? parsed.items : [];
|
|
1583
|
+
function productsBodyFromItems(items, flag, productLimits) {
|
|
1510
1584
|
const order = [];
|
|
1511
1585
|
const byPid = /* @__PURE__ */ new Map();
|
|
1512
1586
|
for (const it of items) {
|
|
@@ -1517,49 +1591,62 @@ function discountProductsBody(args2) {
|
|
|
1517
1591
|
byPid.get(it.pid).push({ sid: it.sid, amount: it.amount });
|
|
1518
1592
|
}
|
|
1519
1593
|
return {
|
|
1520
|
-
products: order.map((pid) =>
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
activity_price_amount: it.amount,
|
|
1527
|
-
// 🔴 写侧裸串;读回叫 activity_price.amount
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
}))
|
|
1531
|
-
}))
|
|
1594
|
+
products: order.map((pid) => {
|
|
1595
|
+
const [ql, qpu] = productLimits?.get(pid) ?? [-1, -1];
|
|
1596
|
+
return {
|
|
1597
|
+
id: pid,
|
|
1598
|
+
quantity_limit: ql,
|
|
1599
|
+
quantity_per_user: qpu,
|
|
1600
|
+
skus: byPid.get(pid).map((it) => flag === "percent" ? { id: it.sid, discount: it.amount, quantity_limit: -1, quantity_per_user: -1 } : { id: it.sid, activity_price_amount: it.amount, quantity_limit: -1, quantity_per_user: -1 })
|
|
1601
|
+
// 🔴 写侧裸串;读回叫 activity_price.amount
|
|
1602
|
+
};
|
|
1603
|
+
})
|
|
1532
1604
|
};
|
|
1533
1605
|
}
|
|
1606
|
+
function discountProductsBody(args2) {
|
|
1607
|
+
const flag = discountValueFlag(args2);
|
|
1608
|
+
const parsed = parsePriceItems(discountValueRaw(args2), args2.product, flag);
|
|
1609
|
+
return productsBodyFromItems(parsed.ok ? parsed.items : [], flag);
|
|
1610
|
+
}
|
|
1611
|
+
function discountItemsHuman(items, flag) {
|
|
1612
|
+
return items.map((it) => flag === "percent" ? `\u5546\u54C1 ${it.pid} \u7684 SKU ${it.sid} \u51CF ${it.amount}%\uFF08\u6309\u539F\u4EF7 ${100 - Number(it.amount)}% \u552E\u5356\uFF09` : `\u5546\u54C1 ${it.pid} \u7684 SKU ${it.sid} \u552E\u4EF7\u5B9A\u4E3A ${it.amount}`).join("\uFF1B");
|
|
1613
|
+
}
|
|
1534
1614
|
function discountHuman(args2) {
|
|
1535
|
-
const
|
|
1615
|
+
const flag = discountValueFlag(args2);
|
|
1616
|
+
const parsed = parsePriceItems(discountValueRaw(args2), args2.product, flag);
|
|
1536
1617
|
const days = Number(args2.days ?? 180);
|
|
1537
|
-
const list = parsed.ok ? parsed.items
|
|
1618
|
+
const list = parsed.ok ? discountItemsHuman(parsed.items, flag) : `\uFF08--${flag} \u89E3\u6790\u5931\u8D25\uFF09`;
|
|
1538
1619
|
return `${list}\u3002\u539F\u4EF7\u5C06\u663E\u793A\u4E3A\u5212\u7EBF\u4EF7\u3002\u6D3B\u52A8\u5171 ${days} \u5929\uFF0C\u4ECE 15 \u5206\u949F\u540E\u5F00\u59CB \u2014\u2014 \u521A\u5EFA\u5B8C\u53BB\u5546\u54C1\u9875\u770B\u4EF7\u683C\u6CA1\u53D8\u662F\u6B63\u5E38\u7684\uFF0C\u90A3\u65F6\u6D3B\u52A8\u8FD8\u662F NOT_START\u3002`;
|
|
1539
1620
|
}
|
|
1540
1621
|
function validateCreateDiscount(ctx2) {
|
|
1541
1622
|
const { args: args2, rest } = ctx2;
|
|
1542
1623
|
for (const k of Object.keys(args2)) {
|
|
1543
1624
|
if (DISCOUNT_FLAGS.includes(k)) continue;
|
|
1544
|
-
if (k === "percent") {
|
|
1545
|
-
return { ok: false, message: "\u672C\u7248\u4E0D\u652F\u6301\u767E\u5206\u6BD4\u6298\u6263\uFF08--percent\uFF09\u3002\u8BF7\u5148\u7528 tiktok products get --shop <id> --product <pid> \u53D6 SKU \u6302\u724C\u4EF7\uFF0C\u81EA\u884C\u6298\u7B97\uFF08\u4FDD\u7559\u4E24\u4F4D\u5C0F\u6570\uFF09\u540E\u8D70 --price <skuId>:<\u6298\u540E\u4EF7>" };
|
|
1546
|
-
}
|
|
1547
1625
|
if (k === "sku") {
|
|
1548
|
-
return { ok: false, message: "\u672C\u547D\u4EE4\u6CA1\u6709 --sku\uFF1AskuId \u5199\u5728 --price \u91CC\uFF0C\u5982 --price 173707:29.90\uFF08\u6CA1\u4F20 --product \u65F6\u6BCF\u9879\u90FD\u8981\u5E26 productId\uFF0C\u5982 --price 1737048/173707:29.90\uFF09" };
|
|
1626
|
+
return "percent" in args2 ? { ok: false, message: "\u672C\u547D\u4EE4\u6CA1\u6709 --sku\uFF1AskuId \u5199\u5728 --percent \u91CC\uFF0C\u5982 --percent 173707:15\uFF08\u6CA1\u4F20 --product \u65F6\u6BCF\u9879\u90FD\u8981\u5E26 productId\uFF0C\u5982 --percent 1737048/173707:15\uFF09" } : { ok: false, message: "\u672C\u547D\u4EE4\u6CA1\u6709 --sku\uFF1AskuId \u5199\u5728 --price \u91CC\uFF0C\u5982 --price 173707:29.90\uFF08\u6CA1\u4F20 --product \u65F6\u6BCF\u9879\u90FD\u8981\u5E26 productId\uFF0C\u5982 --price 1737048/173707:29.90\uFF09" };
|
|
1549
1627
|
}
|
|
1550
1628
|
const own = DISCOUNT_FLAGS.filter((f) => !GLOBAL_FLAGS.includes(f));
|
|
1551
1629
|
const hint = suggestFlag(k, own, args2[k], Date.now(), "promotions create-discount");
|
|
1552
1630
|
const tip = !hint ? "" : hint.startsWith("--") ? `\uFF08\u4F60\u662F\u60F3\u7528 ${hint} \u5417\uFF1F\uFF09` : `\uFF08${hint}\uFF09`;
|
|
1553
1631
|
return { ok: false, message: `\u4E0D\u652F\u6301\u7684\u53C2\u6570 --${k}${tip}\uFF1B\u672C\u547D\u4EE4\u53EA\u8BA4 ${DISCOUNT_FLAGS.map((f) => "--" + f).join(" ")}` };
|
|
1554
1632
|
}
|
|
1633
|
+
const v3flag = "price" in args2 ? "price" : discountValueFlag(args2);
|
|
1555
1634
|
if (rest && rest.length > 0) {
|
|
1556
|
-
return { ok: false, message: `\u591A\u4F59\u7684\u4F4D\u7F6E\u53C2\u6570\u300C${rest.join(" ")}\u300D\u2014\u2014\u6BCF\u4E2A\u53C2\u6570\u53EA\u80FD\u5E26\u4E00\u4E2A\u503C\u3002\u591A\u4E2A SKU \u8981\u7528\u9017\u53F7\u8FDE\u6210\u4E00\u4E2A
|
|
1635
|
+
return { ok: false, message: `\u591A\u4F59\u7684\u4F4D\u7F6E\u53C2\u6570\u300C${rest.join(" ")}\u300D\u2014\u2014\u6BCF\u4E2A\u53C2\u6570\u53EA\u80FD\u5E26\u4E00\u4E2A\u503C\u3002\u591A\u4E2A SKU \u8981\u7528\u9017\u53F7\u8FDE\u6210\u4E00\u4E2A --${v3flag}\uFF0C\u5982 --${v3flag} A:12,B:15\uFF08\u4E0D\u80FD\u7528\u7A7A\u683C\u5206\u9694\uFF09\uFF1B\u82E5\u662F\u6807\u9898\u7B49\u503C\u91CC\u542B\u7A7A\u683C\uFF0C\u7ED9\u6574\u4E2A\u503C\u52A0\u5F15\u53F7\uFF0C\u5982 --title "Momo Sale"` };
|
|
1557
1636
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
}
|
|
1637
|
+
if ("price" in args2 && "percent" in args2) {
|
|
1638
|
+
return { ok: false, message: "--price \u4E0E --percent \u53EA\u80FD\u4E8C\u9009\u4E00\uFF1A\u4E00\u53E3\u4EF7\u7528 --price\uFF0C\u767E\u5206\u6BD4\u6298\u6263\u7528 --percent\u3002" };
|
|
1639
|
+
}
|
|
1640
|
+
if (!("price" in args2) && !("percent" in args2)) {
|
|
1641
|
+
return { ok: false, message: `--price \u5FC5\u586B\uFF08\u767E\u5206\u6BD4\u6298\u6263\u6539\u7528 --percent\uFF0C\u4E24\u8005\u4E8C\u9009\u4E00\uFF09\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --price \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --price= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1642
|
+
}
|
|
1643
|
+
if (!args2.title || args2.title === "true" || !args2.title.trim()) {
|
|
1644
|
+
return { ok: false, message: `--title \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --title \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --title= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1645
|
+
}
|
|
1646
|
+
const flag = discountValueFlag(args2);
|
|
1647
|
+
const val = flag === "percent" ? args2.percent : args2.price;
|
|
1648
|
+
if (!val || val === "true" || !val.trim()) {
|
|
1649
|
+
return { ok: false, message: `--${flag} \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --${flag} \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --${flag}= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1563
1650
|
}
|
|
1564
1651
|
if (args2.title !== args2.title.trim()) {
|
|
1565
1652
|
return { ok: false, message: `--title \u9996\u5C3E\u4E0D\u80FD\u6709\u7A7A\u767D\uFF08\u6536\u5230\u300C${args2.title}\u300D\uFF09\uFF1A\u649E\u91CD\u540D\u65F6 CLI \u6309\u6807\u9898\u4E25\u683C\u76F8\u7B49\u67E5\u540C\u540D\u6D3B\u52A8\uFF0C\u5E73\u53F0\u82E5\u53BB\u6389\u9996\u5C3E\u7A7A\u767D\u5C31\u4F1A\u5BF9\u4E0D\u4E0A\u3002\u8BF7\u53BB\u6389\u9996\u5C3E\u7A7A\u767D\u540E\u91CD\u8DD1` };
|
|
@@ -1568,9 +1655,9 @@ function validateCreateDiscount(ctx2) {
|
|
|
1568
1655
|
return { ok: false, message: `--product \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --product \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --product= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1569
1656
|
}
|
|
1570
1657
|
if (args2.product?.includes(",")) {
|
|
1571
|
-
return { ok: false, message:
|
|
1658
|
+
return { ok: false, message: `--product \u53EA\u6536\u4E00\u4E2A\u5546\u54C1 id\uFF1B\u591A\u5546\u54C1\u8BF7\u5728 --${flag} \u91CC\u5199 <productId>/<skuId>:${flag === "percent" ? "<\u51CFN%>" : "<\u4EF7>"}` };
|
|
1572
1659
|
}
|
|
1573
|
-
const parsed = parsePriceItems(
|
|
1660
|
+
const parsed = parsePriceItems(val, args2.product, flag);
|
|
1574
1661
|
if (!parsed.ok) return parsed;
|
|
1575
1662
|
if ("days" in args2) {
|
|
1576
1663
|
const raw = args2.days;
|
|
@@ -1589,18 +1676,21 @@ var DISCOUNT_TEXT = {
|
|
|
1589
1676
|
noCreateId: (title) => `\u5EFA\u58F3\u8FD4\u56DE\u6210\u529F\u4F46\u6CA1\u62FF\u5230 activity_id \u2014\u2014 \u26A0\uFE0F \u5E73\u53F0\u4E0A\u5F88\u53EF\u80FD\u5DF2\u7ECF\u6709\u8FD9\u6761\u58F3\u4E86\uFF08\u6807\u9898\u300C${title}\u300D\uFF09\u3002\u522B\u6362\u6807\u9898\uFF0C\u76F4\u63A5\u7528\u539F\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\uFF1A\u91CD\u8DD1\u4F1A\u649E\u91CD\u540D\uFF0C\u90A3\u6761\u63D0\u793A\u4F1A\u544A\u8BC9\u4F60\u4E0B\u4E00\u6B65\u3002`,
|
|
1590
1677
|
// ⑦ 撞重名后自查的六种结论(前面由调用方拼上平台原文 + 一个半角空格)
|
|
1591
1678
|
dupSame: (title, aid, status) => `\u26A0\uFE0F \u540C\u540D\u6D3B\u52A8\u300C${title}\u300D\u5DF2\u5B58\u5728\uFF08\u6D3B\u52A8 ${aid}\uFF0C${status}\uFF09\uFF0C\u6302\u7684\u5546\u54C1\u4E0E\u672C\u6B21\u63D0\u4EA4\u5B8C\u5168\u4E00\u81F4\u2014\u2014\u8FD9\u5C31\u662F\u4F60\u8981\u7684\u6D3B\u52A8\uFF0C\u5DF2\u7ECF\u5EFA\u597D\u4E86\uFF1A\u522B\u91CD\u5EFA\u3002`,
|
|
1592
|
-
dupEmpty: (title, aid, status,
|
|
1679
|
+
dupEmpty: (title, aid, status, addCmd) => `\u26A0\uFE0F \u540C\u540D\u6D3B\u52A8\u300C${title}\u300D\u5DF2\u5B58\u5728\uFF08\u6D3B\u52A8 ${aid}\uFF0C${status}\uFF09\uFF0C\u4F46\u5B83\u662F\u4E00\u6761\u7A7A\u58F3\uFF08\u6CA1\u6709\u4EFB\u4F55\u5546\u54C1\uFF09\u2014\u2014\u76F4\u63A5\u628A\u5546\u54C1\u6302\u4E0A\u53BB\uFF1A${addCmd}\uFF1B\u522B\u91CD\u5EFA\u3002`,
|
|
1680
|
+
// v7 D4 / #36:否定分支 —— ⛔ 不指名具体哪一项(status 那格类型时长可能都对,写「类型或时长不符」是假原因);措辞由 create-discount 线二轮拍板
|
|
1681
|
+
dupEmptyOther: (title, aid, status, shop) => `\u26A0\uFE0F \u540C\u540D\u6D3B\u52A8\u300C${title}\u300D\u5DF2\u5B58\u5728\uFF08\u6D3B\u52A8 ${aid}\uFF0C${status}\uFF09\uFF0C\u5B83\u662F\u4E00\u6761\u7A7A\u58F3\uFF0C\u4F46\u4E0D\u662F\u4F60\u8FD9\u6B21\u8981\u5EFA\u7684\u90A3\u6761\uFF08\u7C7B\u578B\u3001\u65F6\u957F\u6216\u72B6\u6001\u6709\u51FA\u5165\uFF09\u2014\u2014\u522B\u5F80\u5B83\u91CC\u9762\u52A0\u54C1\uFF08\u6302\u8FDB\u53BB\u7684\u5546\u54C1\u4F1A\u8DDF\u7740\u5B83\u7684\u7C7B\u578B\u3001\u65F6\u957F\u548C\u751F\u6548\u72B6\u6001\u8D70\uFF0C\u4E0D\u662F\u4F60\u8FD9\u6B21\u8981\u7684\uFF09\uFF0C\u4E5F\u522B\u5148\u6E05\u7406\u518D\u7528\u539F\u6807\u9898\u91CD\u8DD1\uFF08\u6E05\u7406\u4E0D\u4F1A\u91CA\u653E\u6807\u9898\uFF09\uFF1A\u6362\u4E00\u4E2A\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\uFF1B\u4E0D\u8981\u8FD9\u6761\u58F3\u4E86\u518D\u6E05\u7406\uFF1A${deactivateCmd(shop, aid)}\u3002`,
|
|
1593
1682
|
dupOwner: (title, aid, status, problems) => `\u26A0\uFE0F \u540C\u540D\u6D3B\u52A8\u300C${title}\u300D\u5DF2\u5B58\u5728\uFF08\u6D3B\u52A8 ${aid}\uFF0C${status}\uFF09\uFF0C\u6302\u7684\u5546\u54C1\u4E0E\u672C\u6B21\u63D0\u4EA4\u4E0D\u4E00\u81F4\uFF1A${problems}\u2014\u2014\u522B\u52A8\u5B83\uFF0C\u4E5F\u5148\u522B\u91CD\u5EFA\uFF1A\u628A\u5B83\u544A\u8BC9\u5E97\u4E3B\uFF0C\u95EE\u662F\u5C31\u7528\u8FD9\u6761\uFF0C\u8FD8\u662F\u6362\u4E2A\u6807\u9898\u53E6\u5EFA\u3002`,
|
|
1594
1683
|
dupRetitle: (title) => `\u26A0\uFE0F \u672A\u5F00\u59CB / \u8FDB\u884C\u4E2D\u7684\u6D3B\u52A8\u91CC\u6CA1\u6709\u300C${title}\u300D\u2014\u2014\u8FD9\u4E2A\u6807\u9898\u88AB\u4E00\u6761\u5DF2\u7EC8\u6B62\u6216\u5DF2\u8FC7\u671F\u7684\u6D3B\u52A8\u5360\u7740\uFF0C\u6362\u4E2A\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\u3002`,
|
|
1595
1684
|
dupUnclear: (title, queryError) => `\u26A0\uFE0F \u540C\u540D\u6D3B\u52A8\u300C${title}\u300D\u5DF2\u5B58\u5728\uFF0C\u4F46\u6CA1\u80FD\u67E5\u6E05\u5B83\u7684\u72B6\u6001\uFF08${queryError}\uFF09\u2014\u2014\u522B\u6362\u6807\u9898\u3001\u522B\u91CD\u5EFA\uFF0C\u7A0D\u540E\u7528\u539F\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\u518D\u770B\uFF1B\u8FDE\u7EED\u4E24\u6B21\u90FD\u662F\u8FD9\u53E5\uFF0C\u5C31\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u300C\u6D3B\u52A8\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u4F46\u67E5\u4E0D\u6E05\u300D\u3002`,
|
|
1596
1685
|
dupMulti: (title, found) => `\u26A0\uFE0F \u672A\u5F00\u59CB / \u8FDB\u884C\u4E2D\u7684\u6D3B\u52A8\u91CC\u6709 ${found.length} \u6761\u53EB\u300C${title}\u300D\uFF08${found.map((a) => `${a.id}\uFF1A${a.status}`).join("\uFF1B")}\uFF09\u2014\u2014\u522B\u52A8\u5B83\u4EEC\uFF0C\u4E5F\u5148\u522B\u91CD\u5EFA\uFF1A\u628A\u5B83\u4EEC\u544A\u8BC9\u5E97\u4E3B\uFF0C\u95EE\u600E\u4E48\u5904\u7406\u3002`,
|
|
1597
1686
|
// ⑧ 加品失败后按回读下结论
|
|
1598
|
-
addFailAllAttached: (n, id) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u4F46\u56DE\u8BFB\u663E\u793A\u63D0\u4EA4\u7684 ${n} \u4E2A SKU \u90FD\u5DF2\u6309\u4EF7\u6302\u4E0A\uFF08\u6D3B\u52A8 ${id} \u7EA6 15 \u5206\u949F\u540E\u5F00\u59CB\uFF09\u2014\u2014\u522B\u6E05\u7406\uFF0C\u4E5F\u522B\u91CD\u8DD1\u672C\u547D\u4EE4\u3002`,
|
|
1599
|
-
addFailNoneAttached: (shop, id) => `\u52A0\u5546\u54C1\u5931\u8D25\uFF0C\u56DE\u8BFB\u663E\u793A\u6CA1\u6709\u4EFB\u4F55\u5546\u54C1\u6302\u4E0A\u2014\u2014\u6D3B\u52A8 ${id} \u662F\u4E00\u6761\u7A7A\u58F3\u3002\
|
|
1600
|
-
addFailPartial: (problems, shop, id) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u56DE\u8BFB\u663E\u793A\u6CA1\u6709\u5168\u90E8\u6302\u4E0A\uFF1A${problems}\u3002\
|
|
1601
|
-
|
|
1687
|
+
addFailAllAttached: (n, id, dd = false) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u4F46\u56DE\u8BFB\u663E\u793A\u63D0\u4EA4\u7684 ${n} \u4E2A SKU \u90FD\u5DF2\u6309${dd ? "\u6298\u6263" : "\u4EF7"}\u6302\u4E0A\uFF08\u6D3B\u52A8 ${id} \u7EA6 15 \u5206\u949F\u540E\u5F00\u59CB\uFF09\u2014\u2014\u522B\u6E05\u7406\uFF0C\u4E5F\u522B\u91CD\u8DD1\u672C\u547D\u4EE4\u3002`,
|
|
1688
|
+
addFailNoneAttached: (shop, id, addCmd) => `\u52A0\u5546\u54C1\u5931\u8D25\uFF0C\u56DE\u8BFB\u663E\u793A\u6CA1\u6709\u4EFB\u4F55\u5546\u54C1\u6302\u4E0A\u2014\u2014\u6D3B\u52A8 ${id} \u662F\u4E00\u6761\u7A7A\u58F3\u3002\u522B\u91CD\u8DD1\u672C\u547D\u4EE4\uFF08\u4F1A\u649E\u91CD\u540D\u6216\u518D\u5EFA\u4E00\u4E2A\u58F3\uFF09\uFF1A\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u53C2\u6570\u540E\uFF0C\u7528 ${addCmd} \u628A\u5546\u54C1\u6302\u5230\u8FD9\u6761\u6D3B\u52A8\u4E0A\uFF08\u53EA\u6709\u9650\u6D41\u3001\u7F51\u7EDC\u7C7B\u62A5\u9519\u624D\u539F\u6837\u91CD\u8BD5\uFF09\uFF1B\u4E0D\u6253\u7B97\u7528\u8FD9\u6761\u6D3B\u52A8\u4E86\u518D\u6E05\u7406\uFF1A${deactivateCmd(shop, id)}\u3002`,
|
|
1689
|
+
addFailPartial: (problems, shop, id, addCmd, dd = false) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u56DE\u8BFB\u663E\u793A\u6CA1\u6709\u5168\u90E8\u6302\u4E0A\uFF1A${problems}\u3002\u8BF7\u5E97\u4E3B\u4E09\u9009\u4E00\uFF1A\u8865\u6302\u7F3A\u7684 SKU\uFF1A${addCmd}\uFF08\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u540E\u518D\u8865\uFF09\uFF1B\u4FDD\u7559\u6D3B\u52A8 ${id}\uFF08\u7F3A\u7684 SKU \u4E0D\u6253\u6298\uFF0C${dd ? "\u6298\u6263\u4E0D\u7B26\u7684\u6309\u8BFB\u56DE\u7684\u6298\u6263\u751F\u6548" : "\u4EF7\u683C\u4E0D\u7B26\u7684\u6309\u8BFB\u56DE\u7684\u4EF7\u683C\u751F\u6548"}\uFF09\uFF1B\u6216\u6E05\u7406\u540E\u6574\u6761\u91CD\u5EFA\uFF1A${deactivateCmd(shop, id)}\uFF0C\u6E05\u7406\u540E\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u53C2\u6570\u3001\u6362\u4E00\u4E2A\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\uFF08\u26A0\uFE0F deactivate \u4E0D\u91CA\u653E\u6807\u9898\uFF0C\u7528\u539F\u6807\u9898\u91CD\u8DD1\u5FC5\u649E\u91CD\u540D\uFF09\u3002\u522B\u76F4\u63A5\u91CD\u8DD1\u672C\u547D\u4EE4\u3002`,
|
|
1690
|
+
addFailPartialMismatch: (problems, shop, id, dd = false) => `\u52A0\u5546\u54C1\u62A5\u4E86\u9519\uFF0C\u56DE\u8BFB\u663E\u793A\u5546\u54C1\u90FD\u6302\u4E0A\u4E86\uFF0C\u4F46\u503C\u4E0E\u63D0\u4EA4\u4E0D\u4E00\u81F4\uFF1A${problems}\u3002\u8BF7\u5E97\u4E3B\u4E8C\u9009\u4E00\uFF1A\u4FDD\u7559\u6D3B\u52A8 ${id}\uFF08${dd ? "\u6298\u6263\u4E0D\u7B26\u7684\u6309\u8BFB\u56DE\u7684\u6298\u6263\u751F\u6548" : "\u4EF7\u683C\u4E0D\u7B26\u7684\u6309\u8BFB\u56DE\u7684\u4EF7\u683C\u751F\u6548"}\uFF09\uFF0C\u6216\u6E05\u7406\u540E\u6574\u6761\u91CD\u5EFA\uFF1A${deactivateCmd(shop, id)}\uFF0C\u6E05\u7406\u540E\u6309\u4E0A\u9762\u7684\u5E73\u53F0\u62A5\u9519\u6539\u6B63\u53C2\u6570\u3001\u6362\u4E00\u4E2A\u6807\u9898\u91CD\u8DD1\u539F\u547D\u4EE4\uFF08\u26A0\uFE0F deactivate \u4E0D\u91CA\u653E\u6807\u9898\uFF0C\u7528\u539F\u6807\u9898\u91CD\u8DD1\u5FC5\u649E\u91CD\u540D\uFF09\u3002\u522B\u76F4\u63A5\u91CD\u8DD1\u672C\u547D\u4EE4\u3002`,
|
|
1691
|
+
addFailReadbackFailed: (shop, id) => `\u52A0\u5546\u54C1\u5931\u8D25\uFF0C\u56DE\u8BFB\u4E5F\u5931\u8D25\u4E86\uFF0C\u67E5\u4E0D\u5230\u6D3B\u52A8 ${id} \u91CC\u5546\u54C1\u6709\u6CA1\u6709\u6302\u4E0A\u3002\u522B\u91CD\u8DD1\u672C\u547D\u4EE4\uFF08\u4F1A\u518D\u5EFA\u4E00\u4E2A\u58F3\uFF09\uFF0C\u4E5F\u5148\u522B\u6E05\u7406\uFF1A\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u6838\u5BF9\uFF1B\u4ECD\u67E5\u4E0D\u6E05\u5C31\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u300C\u6D3B\u52A8\u5DF2\u5EFA\uFF0C\u5546\u54C1\u662F\u5426\u6302\u4E0A\u672A\u80FD\u786E\u8BA4\u300D\uFF1B\u786E\u8BA4\u6CA1\u6302\u4E0A\u518D\u6E05\u7406\uFF1A${deactivateCmd(shop, id)}\u3002`,
|
|
1602
1692
|
// ⑨ 成功路径的 warnings
|
|
1603
|
-
readbackFailed: (id) => `\u6D3B\u52A8 ${id} \u5DF2\u5EFA\u6210\u3001\u5546\u54C1\u5DF2\u63D0\u4EA4\uFF0C\u4F46\u56DE\u8BFB\u5931\u8D25\uFF0C\u672A\u80FD\u9A8C\u8BC1\u5546\u54C1\u662F\u5426\u6302\u4E0A\u2014\u2014\u4E0D\u8981\u91CD\u5EFA\u6D3B\u52A8\uFF1B\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u300C\u5DF2\u5EFA\uFF0C\u5546\u54C1\u662F\u5426\u6302\u4E0A\u672A\u80FD\u786E\u8BA4\u300D\u3002`,
|
|
1693
|
+
readbackFailed: (shop, id) => `\u6D3B\u52A8 ${id} \u5DF2\u5EFA\u6210\u3001\u5546\u54C1\u5DF2\u63D0\u4EA4\uFF0C\u4F46\u56DE\u8BFB\u5931\u8D25\uFF0C\u672A\u80FD\u9A8C\u8BC1\u5546\u54C1\u662F\u5426\u6302\u4E0A\u2014\u2014\u4E0D\u8981\u91CD\u5EFA\u6D3B\u52A8\uFF1B\u5148\u7528 \`tiktok promotions get --shop ${shop} --id ${id}\` \u6838\u5BF9\uFF0C\u4ECD\u67E5\u4E0D\u6E05\u518D\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u300C\u5DF2\u5EFA\uFF0C\u5546\u54C1\u662F\u5426\u6302\u4E0A\u672A\u80FD\u786E\u8BA4\u300D\u3002`,
|
|
1604
1694
|
readbackDiffers: (id, problems) => `\u6D3B\u52A8 ${id} \u5DF2\u5EFA\u6210\uFF0C\u4F46\u56DE\u8BFB\u4E0E\u63D0\u4EA4\u4E0D\u4E00\u81F4\uFF1A${problems}\u2014\u2014\u4E0D\u8981\u91CD\u5EFA\u6D3B\u52A8\uFF1B\u5982\u5B9E\u544A\u8BC9\u5E97\u4E3B\u54EA\u4E9B SKU \u672A\u786E\u8BA4\u6302\u4E0A\u3002`
|
|
1605
1695
|
};
|
|
1606
1696
|
var OBSERVED_REJECT_CODES = /* @__PURE__ */ new Set([
|
|
@@ -1634,9 +1724,10 @@ function createFailureVerdict(env2) {
|
|
|
1634
1724
|
return "maybe_landed";
|
|
1635
1725
|
}
|
|
1636
1726
|
function submittedSkus(args2) {
|
|
1637
|
-
|
|
1727
|
+
const dd = discountValueFlag(args2) === "percent";
|
|
1728
|
+
return discountProductsBody(args2).products.flatMap((p) => p.skus.map((s) => ({ sid: s.id, amount: dd ? s.discount : s.activity_price_amount })));
|
|
1638
1729
|
}
|
|
1639
|
-
function compareReadback(submitted, readback) {
|
|
1730
|
+
function compareReadback(submitted, readback, field = "amount") {
|
|
1640
1731
|
const products = readback?.products;
|
|
1641
1732
|
if (!Array.isArray(products)) return null;
|
|
1642
1733
|
const skus = products.flatMap((p) => Array.isArray(p?.skus) ? p.skus : []);
|
|
@@ -1655,17 +1746,19 @@ function compareReadback(submitted, readback) {
|
|
|
1655
1746
|
diff.missing.push(sid);
|
|
1656
1747
|
continue;
|
|
1657
1748
|
}
|
|
1658
|
-
const raw = hit.activity_price?.amount;
|
|
1749
|
+
const raw = field === "discount" ? hit.discount : hit.activity_price?.amount;
|
|
1659
1750
|
const got = raw === void 0 || raw === null || raw === "" ? void 0 : String(raw);
|
|
1660
1751
|
if (got === void 0 || Number(got) !== Number(amount)) diff.mismatched.push({ sid, submitted: amount, readback: got });
|
|
1661
1752
|
}
|
|
1662
1753
|
return diff;
|
|
1663
1754
|
}
|
|
1664
|
-
function problemsText(d) {
|
|
1755
|
+
function problemsText(d, field = "amount") {
|
|
1665
1756
|
const parts = [];
|
|
1666
1757
|
if (d.missing.length) parts.push(`\u7F3A ${d.missing.join("\u3001")}`);
|
|
1667
1758
|
if (d.mismatched.length) {
|
|
1668
|
-
|
|
1759
|
+
const label = field === "discount" ? "\u6298\u6263\u4E0D\u7B26" : "\u91D1\u989D\u4E0D\u7B26";
|
|
1760
|
+
const none = field === "discount" ? "\u65E0\u6298\u6263" : "\u65E0\u91D1\u989D";
|
|
1761
|
+
parts.push(`${label} ${d.mismatched.map((m) => `${m.sid}\uFF08\u63D0\u4EA4 ${m.submitted}\uFF0C\u8BFB\u56DE ${m.readback ?? none}\uFF09`).join("\u3001")}`);
|
|
1669
1762
|
}
|
|
1670
1763
|
return parts.join("\uFF1B");
|
|
1671
1764
|
}
|
|
@@ -1675,7 +1768,7 @@ function mergeWarnings(existing, ours) {
|
|
|
1675
1768
|
return [existing, ...ours];
|
|
1676
1769
|
}
|
|
1677
1770
|
var DUP_SEARCH_MAX_PAGES = 10;
|
|
1678
|
-
async function dupSelfCheck(shop, title, submitted) {
|
|
1771
|
+
async function dupSelfCheck(shop, title, submitted, field, intent) {
|
|
1679
1772
|
const found = /* @__PURE__ */ new Map();
|
|
1680
1773
|
for (const status of ["NOT_START", "ONGOING"]) {
|
|
1681
1774
|
let token;
|
|
@@ -1698,13 +1791,220 @@ async function dupSelfCheck(shop, title, submitted) {
|
|
|
1698
1791
|
const [hit] = found.values();
|
|
1699
1792
|
const g = await proxy("GET", shop, `/promotion/202309/activities/${hit.id}`, {});
|
|
1700
1793
|
if (!g.ok) return DISCOUNT_TEXT.dupUnclear(title, g.error.message);
|
|
1701
|
-
const d = compareReadback(submitted, g.data);
|
|
1794
|
+
const d = compareReadback(submitted, g.data, field);
|
|
1702
1795
|
if (!d) return DISCOUNT_TEXT.dupUnclear(title, "\u56DE\u8BFB\u7F3A products \u5B57\u6BB5");
|
|
1796
|
+
const gd = g.data;
|
|
1797
|
+
const shellType = gd?.activity_type;
|
|
1798
|
+
const typeNote = (shellType === "FIXED_PRICE" || shellType === "DIRECT_DISCOUNT") && shellType !== intent.type ? `\u7C7B\u578B\u4E0D\u7B26\uFF1A\u540C\u540D\u6D3B\u52A8\u662F ${shellType}\uFF0C\u672C\u6B21 --${intent.flag} \u5BF9\u5E94 ${intent.type}\uFF08\u4E0B\u9762\u7684\u4E0D\u4E00\u81F4\u662F\u7C7B\u578B\u5DEE\u5F02\u3001\u4E0D\u662F\u503C\u5DEE\u5F02\uFF09\uFF1B` : "";
|
|
1703
1799
|
if (d.missing.length === 0 && d.mismatched.length === 0 && d.total === submitted.length) {
|
|
1704
1800
|
return DISCOUNT_TEXT.dupSame(title, hit.id, hit.status);
|
|
1705
1801
|
}
|
|
1706
|
-
if (d.productCount === 0)
|
|
1707
|
-
|
|
1802
|
+
if (d.productCount === 0) {
|
|
1803
|
+
const fits = gd?.activity_type === intent.type && Number(gd?.end_time) - Number(gd?.begin_time) === intent.days * 86400 && gd?.status === "NOT_START";
|
|
1804
|
+
const echoStatus = String(gd?.status ?? hit.status);
|
|
1805
|
+
return fits ? DISCOUNT_TEXT.dupEmpty(title, hit.id, echoStatus, intent.addCmd(hit.id)) : DISCOUNT_TEXT.dupEmptyOther(title, hit.id, echoStatus, shop);
|
|
1806
|
+
}
|
|
1807
|
+
return DISCOUNT_TEXT.dupOwner(title, hit.id, hit.status, typeNote + (problemsText(d, field) || `\u591A\u51FA ${d.extra.join("\u3001")}`));
|
|
1808
|
+
}
|
|
1809
|
+
var GET_FLAGS = ["shop", "actor", "id"];
|
|
1810
|
+
function validateGet(ctx2) {
|
|
1811
|
+
const { args: args2, rest } = ctx2;
|
|
1812
|
+
for (const k of Object.keys(args2)) {
|
|
1813
|
+
if (k === "activity-id") return { ok: false, message: ADD_TEXT.AV2 };
|
|
1814
|
+
}
|
|
1815
|
+
for (const k of Object.keys(args2)) {
|
|
1816
|
+
if (GET_FLAGS.includes(k) || k === "help") continue;
|
|
1817
|
+
if (k === "apply") return { ok: false, message: "\u672C\u547D\u4EE4\u662F\u53EA\u8BFB\u547D\u4EE4\uFF0C\u6CA1\u6709 --apply\uFF08\u4E0D\u52A0 --apply \u4E5F\u4F1A\u76F4\u63A5\u8BFB\uFF09\uFF1B\u53BB\u6389\u5B83\u5373\u53EF" };
|
|
1818
|
+
const hint = suggestFlag(k, ["id"], args2[k], Date.now(), "promotions get");
|
|
1819
|
+
const tip = !hint ? "" : hint.startsWith("--") ? `\uFF08\u4F60\u662F\u60F3\u7528 ${hint} \u5417\uFF1F\uFF09` : `\uFF08${hint}\uFF09`;
|
|
1820
|
+
return { ok: false, message: `\u4E0D\u652F\u6301\u7684\u53C2\u6570 --${k}${tip}\uFF1B\u672C\u547D\u4EE4\u53EA\u8BA4 ${GET_FLAGS.map((f) => "--" + f).join(" ")}` };
|
|
1821
|
+
}
|
|
1822
|
+
if (rest && rest.length > 0) return { ok: false, message: ADD_TEXT.GV3(rest.join(" ")) };
|
|
1823
|
+
if (!args2.id || args2.id === "true" || !args2.id.trim()) {
|
|
1824
|
+
return { ok: false, message: `--id \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u6D3B\u52A8 id\uFF0C\u7EAF\u6570\u5B57\uFF0C\u5982 --id 7686081985965900001\uFF09` };
|
|
1825
|
+
}
|
|
1826
|
+
if (!/^\d+$/.test(args2.id)) return { ok: false, message: `--id \u5FC5\u987B\u662F\u7EAF\u6570\u5B57\u7684\u6D3B\u52A8 id\uFF08\u6536\u5230\u300C${args2.id}\u300D\uFF09` };
|
|
1827
|
+
return { ok: true };
|
|
1828
|
+
}
|
|
1829
|
+
async function runGet(shop, id) {
|
|
1830
|
+
return proxy("GET", shop, `/promotion/202309/activities/${id}`, {});
|
|
1831
|
+
}
|
|
1832
|
+
var ADD_PRODUCTS_FLAGS = ["shop", "apply", "actor", "id", "product", "price", "percent"];
|
|
1833
|
+
var ADD_ALLOWED_STATUS = ["NOT_START", "ONGOING"];
|
|
1834
|
+
var addProductsCmd = (shop, aid, product, flag, items, apply) => `\`tiktok promotions add-products --shop ${shop} --id ${aid}${product ? ` --product ${product}` : ""} --${flag} ${items.join(",")}${apply ? " --apply" : ""}\``;
|
|
1835
|
+
function rawItemsFor(raw, sids) {
|
|
1836
|
+
const want = new Set(sids);
|
|
1837
|
+
return raw.split(",").filter((part) => want.has(part.split(":")[0].split("/").pop() ?? ""));
|
|
1838
|
+
}
|
|
1839
|
+
function existingSkuValues(data, field) {
|
|
1840
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
1841
|
+
const products = data?.products;
|
|
1842
|
+
for (const p of Array.isArray(products) ? products : []) {
|
|
1843
|
+
for (const s of Array.isArray(p?.skus) ? p.skus : []) {
|
|
1844
|
+
const raw = field === "discount" ? s?.discount : s?.activity_price?.amount;
|
|
1845
|
+
const id = String(s?.id);
|
|
1846
|
+
if (!out2.has(id)) out2.set(id, raw === void 0 || raw === null || raw === "" ? void 0 : String(raw));
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return out2;
|
|
1850
|
+
}
|
|
1851
|
+
function productLimitsOf(data) {
|
|
1852
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
1853
|
+
const products = data?.products;
|
|
1854
|
+
for (const p of Array.isArray(products) ? products : []) {
|
|
1855
|
+
if (typeof p?.quantity_limit === "number" && typeof p?.quantity_per_user === "number") out2.set(String(p.id), [p.quantity_limit, p.quantity_per_user]);
|
|
1856
|
+
}
|
|
1857
|
+
return out2;
|
|
1858
|
+
}
|
|
1859
|
+
function lostText(pre, rb, field) {
|
|
1860
|
+
const parts = [];
|
|
1861
|
+
const rbProducts = Array.isArray(rb?.products) ? rb.products : [];
|
|
1862
|
+
const rbProd = new Map(rbProducts.map((p) => [String(p?.id), p]));
|
|
1863
|
+
const rbVals = existingSkuValues(rb, field);
|
|
1864
|
+
const rbHas = new Set(rbProducts.flatMap((p) => (Array.isArray(p?.skus) ? p.skus : []).map((s) => String(s?.id))));
|
|
1865
|
+
const preVals = existingSkuValues(pre, field);
|
|
1866
|
+
for (const p of Array.isArray(pre?.products) ? pre.products : []) {
|
|
1867
|
+
for (const s of Array.isArray(p?.skus) ? p.skus : []) {
|
|
1868
|
+
const sid = String(s?.id);
|
|
1869
|
+
if (!rbHas.has(sid)) {
|
|
1870
|
+
parts.push(`\u539F\u6709 ${sid} \u7F3A\u5931`);
|
|
1871
|
+
continue;
|
|
1872
|
+
}
|
|
1873
|
+
const was = preVals.get(sid), now = rbVals.get(sid);
|
|
1874
|
+
if (was !== void 0 && (now === void 0 || Number(now) !== Number(was))) parts.push(`\u539F\u6709 ${sid} \u503C\u53D8\u4E86\uFF08\u539F ${was}\uFF0C\u73B0 ${now ?? "\u65E0"}\uFF09`);
|
|
1875
|
+
}
|
|
1876
|
+
const q = rbProd.get(String(p?.id));
|
|
1877
|
+
if (!q) continue;
|
|
1878
|
+
if (typeof p?.quantity_limit === "number" && typeof p?.quantity_per_user === "number" && (q.quantity_limit !== p.quantity_limit || q.quantity_per_user !== p.quantity_per_user)) {
|
|
1879
|
+
parts.push(`\u539F\u6709\u5546\u54C1 ${p.id} \u9650\u8D2D\u53D8\u4E86\uFF08\u539F ${p.quantity_limit}/${p.quantity_per_user}\uFF0C\u73B0 ${q.quantity_limit}/${q.quantity_per_user}\uFF09`);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
return parts.join("\uFF1B");
|
|
1883
|
+
}
|
|
1884
|
+
function validateAddProducts(ctx2) {
|
|
1885
|
+
const { args: args2, rest } = ctx2;
|
|
1886
|
+
for (const k of Object.keys(args2)) {
|
|
1887
|
+
if (k === "activity-id") return { ok: false, message: ADD_TEXT.AV2 };
|
|
1888
|
+
}
|
|
1889
|
+
for (const k of Object.keys(args2)) {
|
|
1890
|
+
if (ADD_PRODUCTS_FLAGS.includes(k)) continue;
|
|
1891
|
+
const own = ADD_PRODUCTS_FLAGS.filter((f) => !GLOBAL_FLAGS.includes(f));
|
|
1892
|
+
const hint = suggestFlag(k, own, args2[k], Date.now(), "promotions add-products");
|
|
1893
|
+
const tip = !hint ? "" : hint.startsWith("--") ? `\uFF08\u4F60\u662F\u60F3\u7528 ${hint} \u5417\uFF1F\uFF09` : `\uFF08${hint}\uFF09`;
|
|
1894
|
+
return { ok: false, message: `\u4E0D\u652F\u6301\u7684\u53C2\u6570 --${k}${tip}\uFF1B\u672C\u547D\u4EE4\u53EA\u8BA4 ${ADD_PRODUCTS_FLAGS.map((f) => "--" + f).join(" ")}` };
|
|
1895
|
+
}
|
|
1896
|
+
const v3flag = "price" in args2 ? "price" : discountValueFlag(args2);
|
|
1897
|
+
if (rest && rest.length > 0) return { ok: false, message: ADD_TEXT.AV3(rest.join(" "), v3flag) };
|
|
1898
|
+
if ("price" in args2 && "percent" in args2) {
|
|
1899
|
+
return { ok: false, message: "--price \u4E0E --percent \u53EA\u80FD\u4E8C\u9009\u4E00\uFF1A\u4E00\u53E3\u4EF7\u7528 --price\uFF0C\u767E\u5206\u6BD4\u6298\u6263\u7528 --percent\u3002" };
|
|
1900
|
+
}
|
|
1901
|
+
if (!("price" in args2) && !("percent" in args2)) {
|
|
1902
|
+
return { ok: false, message: `--price \u5FC5\u586B\uFF08\u767E\u5206\u6BD4\u6298\u6263\u6539\u7528 --percent\uFF0C\u4E24\u8005\u4E8C\u9009\u4E00\uFF09\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --price \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --price= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1903
|
+
}
|
|
1904
|
+
if (!args2.id || args2.id === "true" || !args2.id.trim()) {
|
|
1905
|
+
return { ok: false, message: `--id \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u6D3B\u52A8 id\uFF0C\u7EAF\u6570\u5B57\uFF0C\u5982 --id 7686081985965900001\uFF09` };
|
|
1906
|
+
}
|
|
1907
|
+
if (!/^\d+$/.test(args2.id)) {
|
|
1908
|
+
return { ok: false, message: `--id \u5FC5\u987B\u662F\u7EAF\u6570\u5B57\u7684\u6D3B\u52A8 id\uFF08\u6536\u5230\u300C${args2.id}\u300D\uFF09` };
|
|
1909
|
+
}
|
|
1910
|
+
const flag = discountValueFlag(args2);
|
|
1911
|
+
const val = flag === "percent" ? args2.percent : args2.price;
|
|
1912
|
+
if (!val || val === "true" || !val.trim()) {
|
|
1913
|
+
return { ok: false, message: `--${flag} \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --${flag} \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --${flag}= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1914
|
+
}
|
|
1915
|
+
if ("product" in args2 && (!args2.product || args2.product === "true")) {
|
|
1916
|
+
return { ok: false, message: `--product \u5FC5\u586B\uFF0C\u4E14\u5FC5\u987B\u5E26\u503C\uFF08\u53EA\u5199 --product \u4E0D\u7ED9\u503C\u4F1A\u88AB\u89E3\u6790\u6210\u5B57\u7B26\u4E32 "true"\uFF0C\u5199\u6210 --product= \u5219\u662F\u7A7A\u503C\uFF0C\u4E24\u79CD\u90FD\u4E0D\u7B97\uFF09` };
|
|
1917
|
+
}
|
|
1918
|
+
if (args2.product?.includes(",")) {
|
|
1919
|
+
return { ok: false, message: `--product \u53EA\u6536\u4E00\u4E2A\u5546\u54C1 id\uFF1B\u591A\u5546\u54C1\u8BF7\u5728 --${flag} \u91CC\u5199 <productId>/<skuId>:${flag === "percent" ? "<\u51CFN%>" : "<\u4EF7>"}` };
|
|
1920
|
+
}
|
|
1921
|
+
const parsed = parsePriceItems(val, args2.product, flag);
|
|
1922
|
+
if (!parsed.ok) return parsed;
|
|
1923
|
+
return { ok: true };
|
|
1924
|
+
}
|
|
1925
|
+
function addProductsPlan(id, flag, raw, product) {
|
|
1926
|
+
const parsed = parsePriceItems(raw, product, flag);
|
|
1927
|
+
const items = parsed.ok ? parsed.items : [];
|
|
1928
|
+
return [
|
|
1929
|
+
{ step: "1/3 \u9884\u8BFB\u6D3B\u52A8", method: "GET", path: `/promotion/202309/activities/${id}` },
|
|
1930
|
+
{
|
|
1931
|
+
step: flag === "percent" ? "2/3 \u52A0\u5546\u54C1+\u51CFN%" : "2/3 \u52A0\u5546\u54C1+\u4E00\u53E3\u4EF7",
|
|
1932
|
+
method: "PUT",
|
|
1933
|
+
path: `/promotion/202309/activities/${id}/products`,
|
|
1934
|
+
body: { activity_id: id, ...productsBodyFromItems(items, flag) },
|
|
1935
|
+
human: ADD_TEXT.HUMAN_ADD(id, discountItemsHuman(items, flag))
|
|
1936
|
+
},
|
|
1937
|
+
{ step: "3/3 \u56DE\u8BFB", method: "GET", path: `/promotion/202309/activities/${id}` }
|
|
1938
|
+
];
|
|
1939
|
+
}
|
|
1940
|
+
async function runAddProducts(shop, id, flag, raw, product) {
|
|
1941
|
+
const parsed = parsePriceItems(raw, product, flag);
|
|
1942
|
+
const items = parsed.ok ? parsed.items : [];
|
|
1943
|
+
const field = flag === "percent" ? "discount" : "amount";
|
|
1944
|
+
const submitted = items.map((it) => ({ sid: it.sid, amount: it.amount }));
|
|
1945
|
+
const reject = (message, meta) => ({ ok: false, error: { code: "VALIDATION", message, retryable: false }, ...meta ? { meta } : {} });
|
|
1946
|
+
const pre = await proxy("GET", shop, `/promotion/202309/activities/${id}`, {});
|
|
1947
|
+
if (!pre.ok) {
|
|
1948
|
+
const err = pre.error;
|
|
1949
|
+
const status = pre.meta?.http_status;
|
|
1950
|
+
const transient = status === void 0 || status >= 500 || err.code === "RATE_LIMITED";
|
|
1951
|
+
return { ...pre, error: { ...err, message: `${err.message} ${transient ? ADD_TEXT.AP1N(id) : ADD_TEXT.AP1(shop, id)}` } };
|
|
1952
|
+
}
|
|
1953
|
+
const d = pre.data ?? {};
|
|
1954
|
+
if (typeof d.activity_type !== "string" || !Array.isArray(d.products)) return reject(ADD_TEXT.AP1M(shop, id), pre.meta);
|
|
1955
|
+
const type = String(d.activity_type);
|
|
1956
|
+
if (type === "FIXED_PRICE" && flag === "percent") return reject(ADD_TEXT.AT1(id), pre.meta);
|
|
1957
|
+
if (type === "DIRECT_DISCOUNT" && flag === "price") return reject(ADD_TEXT.AT2(id), pre.meta);
|
|
1958
|
+
if (type === "FLASHSALE") return reject(ADD_TEXT.AT3(id), pre.meta);
|
|
1959
|
+
if (type !== "FIXED_PRICE" && type !== "DIRECT_DISCOUNT") return reject(ADD_TEXT.AT4(id, type), pre.meta);
|
|
1960
|
+
if (!ADD_ALLOWED_STATUS.includes(String(d.status))) return reject(ADD_TEXT.AS1(id, String(d.status), ADD_ALLOWED_STATUS.join(" / ")), pre.meta);
|
|
1961
|
+
if (d.product_level !== "VARIATION") return reject(ADD_TEXT.AL1(id, String(d.product_level)), pre.meta);
|
|
1962
|
+
const existing = existingSkuValues(d, field);
|
|
1963
|
+
const same = [], diff = [];
|
|
1964
|
+
const rest = [];
|
|
1965
|
+
for (const it of items) {
|
|
1966
|
+
if (!existing.has(it.sid)) {
|
|
1967
|
+
rest.push(it);
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1970
|
+
const cur = existing.get(it.sid);
|
|
1971
|
+
if (cur !== void 0 && Number(cur) === Number(it.amount)) same.push(it.sid);
|
|
1972
|
+
else diff.push(it.sid);
|
|
1973
|
+
}
|
|
1974
|
+
const restCmd = addProductsCmd(shop, id, product, flag, rawItemsFor(raw, rest.map((r) => r.sid)), true);
|
|
1975
|
+
if (diff.length) return reject(ADD_TEXT.AD1(id, diff.join("\u3001")) + (rest.length ? ADD_TEXT.AD1_REST(restCmd) : ""), pre.meta);
|
|
1976
|
+
if (rest.length === 0) {
|
|
1977
|
+
return { ok: true, data: { activity_id: id, readback: pre.data, note: ADD_TEXT.AD3(items.length, id) }, meta: pre.meta };
|
|
1978
|
+
}
|
|
1979
|
+
if (same.length) return reject(ADD_TEXT.AD2(id, same.join("\u3001"), restCmd), pre.meta);
|
|
1980
|
+
const body = { activity_id: id, ...productsBodyFromItems(items, flag, productLimitsOf(d)) };
|
|
1981
|
+
const put = await proxy("PUT", shop, `/promotion/202309/activities/${id}/products`, { body });
|
|
1982
|
+
const rb = await proxy("GET", shop, `/promotion/202309/activities/${id}`, {});
|
|
1983
|
+
const readback = rb.ok ? rb.data : { error: rb.error };
|
|
1984
|
+
const c = rb.ok ? compareReadback(submitted, rb.data, field) : null;
|
|
1985
|
+
const lost = c ? lostText(d, rb.data, field) : "";
|
|
1986
|
+
const missingCmd = (apply) => addProductsCmd(shop, id, product, flag, rawItemsFor(raw, c?.missing ?? []), apply);
|
|
1987
|
+
if (!put.ok) {
|
|
1988
|
+
const { retry_after_s: _dropped, ...err } = put.error;
|
|
1989
|
+
let note;
|
|
1990
|
+
if (!c) note = ADD_TEXT.AN4(shop, id);
|
|
1991
|
+
else if (c.missing.length === 0 && c.mismatched.length === 0) note = ADD_TEXT.AN1(submitted.length, id);
|
|
1992
|
+
else if (c.missing.length === submitted.length) note = ADD_TEXT.AN2(id);
|
|
1993
|
+
else note = ADD_TEXT.AN3(problemsText(c, field)) + (c.missing.length ? ADD_TEXT.AN3_MISS(missingCmd(false)) : "") + (c.mismatched.length ? ADD_TEXT.AN3_MIS : "");
|
|
1994
|
+
if (lost) note += " " + ADD_TEXT.AW3(shop, id, lost);
|
|
1995
|
+
return { ok: false, error: { ...err, retryable: false }, data: { activity_id: id, readback, note }, meta: put.meta };
|
|
1996
|
+
}
|
|
1997
|
+
const ours = [];
|
|
1998
|
+
if (!c) ours.push(ADD_TEXT.AW1(shop, id));
|
|
1999
|
+
else {
|
|
2000
|
+
const problems = problemsText(c, field);
|
|
2001
|
+
if (problems) ours.push(ADD_TEXT.AW2(id, problems) + (c.missing.length ? ADD_TEXT.AW2_MISS(missingCmd(true)) : ""));
|
|
2002
|
+
if (lost) ours.push(ADD_TEXT.AW3(shop, id, lost));
|
|
2003
|
+
}
|
|
2004
|
+
const putData = put.data ?? {};
|
|
2005
|
+
const data = { ...putData, activity_id: id, readback };
|
|
2006
|
+
if (ours.length > 0) data.warnings = mergeWarnings(putData.warnings, ours);
|
|
2007
|
+
return { ok: true, data, meta: put.meta };
|
|
1708
2008
|
}
|
|
1709
2009
|
|
|
1710
2010
|
// src/index.ts
|