@youzan-cloud/zan-saas-cli 0.0.0-stage → 0.1.0-beta.4

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.
Files changed (329) hide show
  1. package/DEPENDENCIES.json +50 -0
  2. package/INSTALL.md +79 -0
  3. package/LICENSE +21 -0
  4. package/NOTICE +1 -0
  5. package/README.md +151 -2
  6. package/THIRD_PARTY_NOTICES.txt +162 -0
  7. package/bin/zan-saas-cli.js +28 -0
  8. package/internal/registry/index.js +123 -0
  9. package/internal/registry/manifest.json +424 -0
  10. package/npm-shrinkwrap.json +86 -0
  11. package/package.json +33 -4
  12. package/skills/README.md +30 -0
  13. package/skills/zan-saas/SKILL.md +54 -0
  14. package/skills/zan-saas/references/host-entry.md +25 -0
  15. package/skills/zan-saas-access/SKILL.md +37 -0
  16. package/skills/zan-saas-access/references/role-list.md +11 -0
  17. package/skills/zan-saas-access/references/staff-perms-get.md +11 -0
  18. package/skills/zan-saas-aftersale/SKILL.md +31 -0
  19. package/skills/zan-saas-aftersale/references/case-list.md +13 -0
  20. package/skills/zan-saas-aftersale/references/case-scan.md +31 -0
  21. package/skills/zan-saas-benefit/SKILL.md +46 -0
  22. package/skills/zan-saas-benefit/references/card-get.md +7 -0
  23. package/skills/zan-saas-benefit/references/card-grant-list.md +11 -0
  24. package/skills/zan-saas-benefit/references/card-list.md +7 -0
  25. package/skills/zan-saas-benefit/references/customer-card-get.md +7 -0
  26. package/skills/zan-saas-benefit/references/customer-card-list.md +7 -0
  27. package/skills/zan-saas-coupon/SKILL.md +41 -0
  28. package/skills/zan-saas-coupon/references/activity-get.md +11 -0
  29. package/skills/zan-saas-coupon/references/activity-list.md +15 -0
  30. package/skills/zan-saas-coupon/references/voucher-get.md +13 -0
  31. package/skills/zan-saas-coupon/references/voucher-list.md +25 -0
  32. package/skills/zan-saas-customer/SKILL.md +73 -0
  33. package/skills/zan-saas-customer/references/customer-scan.md +11 -0
  34. package/skills/zan-saas-customer/references/segment-list.md +22 -0
  35. package/skills/zan-saas-fulfillment/SKILL.md +36 -0
  36. package/skills/zan-saas-fulfillment/references/delivery-get.md +11 -0
  37. package/skills/zan-saas-fulfillment/references/shipment-list.md +11 -0
  38. package/skills/zan-saas-fulfillment/references/waybill-get.md +9 -0
  39. package/skills/zan-saas-interaction/SKILL.md +37 -0
  40. package/skills/zan-saas-interaction/references/lottery-get.md +11 -0
  41. package/skills/zan-saas-interaction/references/lottery-list.md +19 -0
  42. package/skills/zan-saas-item/SKILL.md +61 -0
  43. package/skills/zan-saas-item/references/attribute-list.md +11 -0
  44. package/skills/zan-saas-item/references/brand-list.md +7 -0
  45. package/skills/zan-saas-item/references/classification-get.md +7 -0
  46. package/skills/zan-saas-item/references/classification-list.md +7 -0
  47. package/skills/zan-saas-item/references/group-list.md +9 -0
  48. package/skills/zan-saas-item/references/item-content.md +9 -0
  49. package/skills/zan-saas-item/references/item-get.md +9 -0
  50. package/skills/zan-saas-item/references/item-search.md +23 -0
  51. package/skills/zan-saas-item/references/product-identity.md +11 -0
  52. package/skills/zan-saas-member/SKILL.md +41 -0
  53. package/skills/zan-saas-member/references/customer-level-get.md +7 -0
  54. package/skills/zan-saas-member/references/growth-log-list.md +17 -0
  55. package/skills/zan-saas-member/references/membership-get.md +7 -0
  56. package/skills/zan-saas-order/SKILL.md +56 -0
  57. package/skills/zan-saas-order/references/order-get.md +26 -0
  58. package/skills/zan-saas-order/references/order-list.md +25 -0
  59. package/skills/zan-saas-order/references/order-scan.md +35 -0
  60. package/skills/zan-saas-org/SKILL.md +37 -0
  61. package/skills/zan-saas-org/references/staff-get.md +15 -0
  62. package/skills/zan-saas-org/references/staff-role-get.md +11 -0
  63. package/skills/zan-saas-org/references/unit-get.md +11 -0
  64. package/skills/zan-saas-org/references/unit-list.md +15 -0
  65. package/skills/zan-saas-points/SKILL.md +42 -0
  66. package/skills/zan-saas-points/references/account-get.md +7 -0
  67. package/skills/zan-saas-points/references/log-list.md +17 -0
  68. package/skills/zan-saas-points/references/rule-list.md +2 -0
  69. package/skills/zan-saas-privacy/SKILL.md +30 -0
  70. package/skills/zan-saas-privacy/references/field-decrypt.md +19 -0
  71. package/skills/zan-saas-shared/SKILL.md +94 -0
  72. package/skills/zan-saas-shared/references/authentication.md +52 -0
  73. package/skills/zan-saas-shared/references/value-processing.md +27 -0
  74. package/skills/zan-saas-stock/SKILL.md +28 -0
  75. package/skills/zan-saas-stock/references/log-list.md +11 -0
  76. package/skills/zan-saas-valuecard/SKILL.md +37 -0
  77. package/skills/zan-saas-valuecard/references/card-get.md +13 -0
  78. package/skills/zan-saas-valuecard/references/card-list.md +11 -0
  79. package/src/auth/browser.js +28 -0
  80. package/src/auth/callback-server.js +99 -0
  81. package/src/auth/config.js +53 -0
  82. package/src/auth/credential-store.js +109 -0
  83. package/src/auth/oauth-client.js +105 -0
  84. package/src/auth/pkce.js +28 -0
  85. package/src/auth/session.js +178 -0
  86. package/src/auth/tool.js +25 -0
  87. package/src/cli/command-paths.js +126 -0
  88. package/src/cli/context-help.js +102 -0
  89. package/src/cli/diagnostic-command.js +57 -0
  90. package/src/cli/domain-catalog.js +42 -0
  91. package/src/cli/help-text.js +32 -0
  92. package/src/cli/native-loader.js +120 -0
  93. package/src/cli/native-path.js +22 -0
  94. package/src/cli/parser-policy.js +141 -0
  95. package/src/cli/program.js +134 -0
  96. package/src/cli/skill-catalog.js +241 -0
  97. package/src/commands/native/access/commands.index.json +24 -0
  98. package/src/commands/native/access/domain.json +3 -0
  99. package/src/commands/native/access/role/list/command.js +141 -0
  100. package/src/commands/native/access/role/list/schema.json +393 -0
  101. package/src/commands/native/access/staff-perms/get/command.js +119 -0
  102. package/src/commands/native/access/staff-perms/get/schema.json +703 -0
  103. package/src/commands/native/aftersale/case/get/command.js +104 -0
  104. package/src/commands/native/aftersale/case/get/exact-json.js +52 -0
  105. package/src/commands/native/aftersale/case/get/money.js +28 -0
  106. package/src/commands/native/aftersale/case/get/projection.js +120 -0
  107. package/src/commands/native/aftersale/case/get/query.js +72 -0
  108. package/src/commands/native/aftersale/case/get/schema.json +134 -0
  109. package/src/commands/native/aftersale/case/list/command.js +135 -0
  110. package/src/commands/native/aftersale/case/list/schema.json +1095 -0
  111. package/src/commands/native/aftersale/case/scan/command.js +110 -0
  112. package/src/commands/native/aftersale/case/scan/query.js +62 -0
  113. package/src/commands/native/aftersale/case/scan/scan.js +78 -0
  114. package/src/commands/native/aftersale/case/scan/schema.json +964 -0
  115. package/src/commands/native/aftersale/case/scan/search.js +108 -0
  116. package/src/commands/native/aftersale/commands.index.json +42 -0
  117. package/src/commands/native/aftersale/domain.json +3 -0
  118. package/src/commands/native/aftersale/refund/list/command.js +97 -0
  119. package/src/commands/native/aftersale/refund/list/money.js +25 -0
  120. package/src/commands/native/aftersale/refund/list/projection.js +50 -0
  121. package/src/commands/native/aftersale/refund/list/query.js +73 -0
  122. package/src/commands/native/aftersale/refund/list/schema.json +130 -0
  123. package/src/commands/native/aftersale/shared/query.js +58 -0
  124. package/src/commands/native/aftersale/shared/search.js +128 -0
  125. package/src/commands/native/benefit/card-definition/get/command.js +110 -0
  126. package/src/commands/native/benefit/card-definition/get/schema.json +545 -0
  127. package/src/commands/native/benefit/card-definition/list/command.js +106 -0
  128. package/src/commands/native/benefit/card-definition/list/schema.json +690 -0
  129. package/src/commands/native/benefit/card-grant/list/command.js +135 -0
  130. package/src/commands/native/benefit/card-grant/list/schema.json +758 -0
  131. package/src/commands/native/benefit/commands.index.json +51 -0
  132. package/src/commands/native/benefit/customer-card/get/command.js +110 -0
  133. package/src/commands/native/benefit/customer-card/get/schema.json +340 -0
  134. package/src/commands/native/benefit/customer-card/list/command.js +103 -0
  135. package/src/commands/native/benefit/customer-card/list/schema.json +731 -0
  136. package/src/commands/native/benefit/domain.json +3 -0
  137. package/src/commands/native/coupon/activity/get/command.js +183 -0
  138. package/src/commands/native/coupon/activity/get/schema.json +624 -0
  139. package/src/commands/native/coupon/activity/list/command.js +169 -0
  140. package/src/commands/native/coupon/activity/list/schema.json +845 -0
  141. package/src/commands/native/coupon/commands.index.json +42 -0
  142. package/src/commands/native/coupon/domain.json +3 -0
  143. package/src/commands/native/coupon/shared/query.js +15 -0
  144. package/src/commands/native/coupon/voucher/get/command.js +113 -0
  145. package/src/commands/native/coupon/voucher/get/schema.json +147 -0
  146. package/src/commands/native/coupon/voucher/list/command.js +155 -0
  147. package/src/commands/native/coupon/voucher/list/schema.json +772 -0
  148. package/src/commands/native/customer/commands.index.json +96 -0
  149. package/src/commands/native/customer/customer/get/adapter.js +82 -0
  150. package/src/commands/native/customer/customer/get/command.js +106 -0
  151. package/src/commands/native/customer/customer/get/schema.json +958 -0
  152. package/src/commands/native/customer/customer/list/command.js +78 -0
  153. package/src/commands/native/customer/customer/list/input.js +145 -0
  154. package/src/commands/native/customer/customer/list/query.js +103 -0
  155. package/src/commands/native/customer/customer/list/schema.json +969 -0
  156. package/src/commands/native/customer/customer/scan/command.js +80 -0
  157. package/src/commands/native/customer/customer/scan/scan.js +92 -0
  158. package/src/commands/native/customer/customer/scan/schema.json +211 -0
  159. package/src/commands/native/customer/customer-tag/get/command.js +166 -0
  160. package/src/commands/native/customer/customer-tag/get/schema.json +317 -0
  161. package/src/commands/native/customer/customer-tag/list/command.js +143 -0
  162. package/src/commands/native/customer/customer-tag/list/schema.json +259 -0
  163. package/src/commands/native/customer/domain.json +3 -0
  164. package/src/commands/native/customer/segment/list/command.js +96 -0
  165. package/src/commands/native/customer/segment/list/query.js +98 -0
  166. package/src/commands/native/customer/segment/list/schema.json +135 -0
  167. package/src/commands/native/customer/segment-customer/list/command.js +171 -0
  168. package/src/commands/native/customer/segment-customer/list/schema.json +123 -0
  169. package/src/commands/native/customer/shared/search-input.js +179 -0
  170. package/src/commands/native/customer/shared/search-page.js +54 -0
  171. package/src/commands/native/customer/tag/get/command.js +73 -0
  172. package/src/commands/native/customer/tag/get/schema.json +339 -0
  173. package/src/commands/native/customer/tagcategory/get/command.js +80 -0
  174. package/src/commands/native/customer/tagcategory/get/query.js +98 -0
  175. package/src/commands/native/customer/tagcategory/get/schema.json +339 -0
  176. package/src/commands/native/customer/tagcategory/list/command.js +127 -0
  177. package/src/commands/native/customer/tagcategory/list/schema.json +394 -0
  178. package/src/commands/native/fulfillment/commands.index.json +33 -0
  179. package/src/commands/native/fulfillment/delivery/get/command.js +107 -0
  180. package/src/commands/native/fulfillment/delivery/get/projection.js +142 -0
  181. package/src/commands/native/fulfillment/delivery/get/schema.json +173 -0
  182. package/src/commands/native/fulfillment/domain.json +3 -0
  183. package/src/commands/native/fulfillment/shipment/list/command.js +83 -0
  184. package/src/commands/native/fulfillment/shipment/list/projection.js +130 -0
  185. package/src/commands/native/fulfillment/shipment/list/schema.json +752 -0
  186. package/src/commands/native/fulfillment/waybill/get/command.js +193 -0
  187. package/src/commands/native/fulfillment/waybill/get/response.js +68 -0
  188. package/src/commands/native/fulfillment/waybill/get/schema.json +190 -0
  189. package/src/commands/native/interaction/commands.index.json +24 -0
  190. package/src/commands/native/interaction/domain.json +3 -0
  191. package/src/commands/native/interaction/lottery/get/command.js +61 -0
  192. package/src/commands/native/interaction/lottery/get/query.js +152 -0
  193. package/src/commands/native/interaction/lottery/get/schema.json +1004 -0
  194. package/src/commands/native/interaction/lottery/list/command.js +176 -0
  195. package/src/commands/native/interaction/lottery/list/schema.json +898 -0
  196. package/src/commands/native/item/attribute/list/command.js +122 -0
  197. package/src/commands/native/item/attribute/list/schema.json +727 -0
  198. package/src/commands/native/item/brand/list/command.js +114 -0
  199. package/src/commands/native/item/brand/list/schema.json +725 -0
  200. package/src/commands/native/item/classification/get/command.js +87 -0
  201. package/src/commands/native/item/classification/get/schema.json +596 -0
  202. package/src/commands/native/item/classification/list/command.js +105 -0
  203. package/src/commands/native/item/classification/list/schema.json +676 -0
  204. package/src/commands/native/item/commands.index.json +87 -0
  205. package/src/commands/native/item/domain.json +1 -0
  206. package/src/commands/native/item/group/list/command.js +122 -0
  207. package/src/commands/native/item/group/list/schema.json +809 -0
  208. package/src/commands/native/item/item/get/command.js +122 -0
  209. package/src/commands/native/item/item/get/schema.json +3799 -0
  210. package/src/commands/native/item/item/list/command.js +7 -0
  211. package/src/commands/native/item/item/list/schema.json +1118 -0
  212. package/src/commands/native/item/item/scan/command.js +7 -0
  213. package/src/commands/native/item/item/scan/schema.json +1046 -0
  214. package/src/commands/native/item/item-content/get/command.js +54 -0
  215. package/src/commands/native/item/item-content/get/schema.json +677 -0
  216. package/src/commands/native/item/shared/api.js +31 -0
  217. package/src/commands/native/item/shared/content.js +20 -0
  218. package/src/commands/native/item/shared/diagnostics.js +61 -0
  219. package/src/commands/native/item/shared/h5.js +63 -0
  220. package/src/commands/native/item/shared/identity.js +62 -0
  221. package/src/commands/native/item/shared/normalize.js +49 -0
  222. package/src/commands/native/item/shared/scope.js +22 -0
  223. package/src/commands/native/item/shared/search-command.js +61 -0
  224. package/src/commands/native/item/shared/search-options.js +150 -0
  225. package/src/commands/native/item/shared/search.js +158 -0
  226. package/src/commands/native/member/commands.index.json +60 -0
  227. package/src/commands/native/member/customer-level/get/command.js +122 -0
  228. package/src/commands/native/member/customer-level/get/schema.json +300 -0
  229. package/src/commands/native/member/domain.json +3 -0
  230. package/src/commands/native/member/growth/get/command.js +64 -0
  231. package/src/commands/native/member/growth/get/schema.json +283 -0
  232. package/src/commands/native/member/growth-log/list/command.js +203 -0
  233. package/src/commands/native/member/growth-log/list/schema.json +695 -0
  234. package/src/commands/native/member/level/get/command.js +70 -0
  235. package/src/commands/native/member/level/get/query.js +125 -0
  236. package/src/commands/native/member/level/get/schema.json +339 -0
  237. package/src/commands/native/member/level/list/command.js +50 -0
  238. package/src/commands/native/member/level/list/query.js +109 -0
  239. package/src/commands/native/member/level/list/schema.json +104 -0
  240. package/src/commands/native/member/membership/get/command.js +78 -0
  241. package/src/commands/native/member/membership/get/schema.json +283 -0
  242. package/src/commands/native/order/commands.index.json +33 -0
  243. package/src/commands/native/order/domain.json +3 -0
  244. package/src/commands/native/order/order/get/command.js +155 -0
  245. package/src/commands/native/order/order/get/schema.json +1167 -0
  246. package/src/commands/native/order/order/list/command.js +230 -0
  247. package/src/commands/native/order/order/list/schema.json +1363 -0
  248. package/src/commands/native/order/order/scan/command.js +148 -0
  249. package/src/commands/native/order/order/scan/scan.js +89 -0
  250. package/src/commands/native/order/order/scan/schema.json +1445 -0
  251. package/src/commands/native/order/shared/projection.js +183 -0
  252. package/src/commands/native/order/shared/query.js +84 -0
  253. package/src/commands/native/order/shared/search.js +112 -0
  254. package/src/commands/native/org/commands.index.json +42 -0
  255. package/src/commands/native/org/domain.json +3 -0
  256. package/src/commands/native/org/shared/single-staff.js +115 -0
  257. package/src/commands/native/org/staff/get/command.js +148 -0
  258. package/src/commands/native/org/staff/get/schema.json +114 -0
  259. package/src/commands/native/org/staff-role/get/command.js +45 -0
  260. package/src/commands/native/org/staff-role/get/schema.json +93 -0
  261. package/src/commands/native/org/unit/get/command.js +131 -0
  262. package/src/commands/native/org/unit/get/schema.json +478 -0
  263. package/src/commands/native/org/unit/list/command.js +187 -0
  264. package/src/commands/native/org/unit/list/schema.json +828 -0
  265. package/src/commands/native/points/account/get/command.js +65 -0
  266. package/src/commands/native/points/account/get/schema.json +303 -0
  267. package/src/commands/native/points/commands.index.json +33 -0
  268. package/src/commands/native/points/domain.json +3 -0
  269. package/src/commands/native/points/log/list/command.js +141 -0
  270. package/src/commands/native/points/log/list/schema.json +761 -0
  271. package/src/commands/native/points/rule/list/command.js +82 -0
  272. package/src/commands/native/points/rule/list/schema.json +294 -0
  273. package/src/commands/native/privacy/commands.index.json +15 -0
  274. package/src/commands/native/privacy/domain.json +3 -0
  275. package/src/commands/native/privacy/field/decrypt/command.js +185 -0
  276. package/src/commands/native/privacy/field/decrypt/schema.json +656 -0
  277. package/src/commands/native/privacy/shared/order-source.js +33 -0
  278. package/src/commands/native/stock/commands.index.json +15 -0
  279. package/src/commands/native/stock/domain.json +3 -0
  280. package/src/commands/native/stock/log/list/command.js +207 -0
  281. package/src/commands/native/stock/log/list/schema.json +922 -0
  282. package/src/commands/native/valuecard/card/get/command.js +107 -0
  283. package/src/commands/native/valuecard/card/get/schema.json +683 -0
  284. package/src/commands/native/valuecard/card/list/command.js +136 -0
  285. package/src/commands/native/valuecard/card/list/pagination.js +23 -0
  286. package/src/commands/native/valuecard/card/list/schema.json +780 -0
  287. package/src/commands/native/valuecard/commands.index.json +24 -0
  288. package/src/commands/native/valuecard/domain.json +3 -0
  289. package/src/commands/native/valuecard/shared/projection.js +57 -0
  290. package/src/commands/system/api.js +47 -0
  291. package/src/commands/system/auth.js +118 -0
  292. package/src/commands/system/contracts.js +373 -0
  293. package/src/commands/system/doctor.js +24 -0
  294. package/src/commands/system/install.js +41 -0
  295. package/src/commands/system/printer.js +16 -0
  296. package/src/commands/system/schema.js +162 -0
  297. package/src/commands/system/shop-guidance.js +9 -0
  298. package/src/commands/system/shop.js +237 -0
  299. package/src/commands/system/skills.js +49 -0
  300. package/src/execution/beijing-date-time.js +29 -0
  301. package/src/execution/beijing-time.js +21 -0
  302. package/src/execution/bounded-input.js +42 -0
  303. package/src/execution/command-io.js +137 -0
  304. package/src/execution/command-policy.js +41 -0
  305. package/src/execution/command-schema.js +131 -0
  306. package/src/execution/datetime.js +83 -0
  307. package/src/execution/error-details.js +399 -0
  308. package/src/execution/error-model.js +82 -0
  309. package/src/execution/exact-json.js +80 -0
  310. package/src/execution/list-total.js +10 -0
  311. package/src/execution/money.js +59 -0
  312. package/src/execution/parser-error.js +66 -0
  313. package/src/execution/privacy.js +197 -0
  314. package/src/execution/public-schema.js +52 -0
  315. package/src/execution/query-api.js +101 -0
  316. package/src/execution/range.js +84 -0
  317. package/src/execution/request-state.js +55 -0
  318. package/src/execution/schema-completeness.js +116 -0
  319. package/src/execution/shop-query.js +54 -0
  320. package/src/execution/target-shop-default.js +23 -0
  321. package/src/execution/target-shop.js +49 -0
  322. package/src/identity/context-store.js +54 -0
  323. package/src/identity/context.js +38 -0
  324. package/src/installation/install.js +158 -0
  325. package/src/installation/npm-error.js +93 -0
  326. package/src/installation/skill.js +113 -0
  327. package/src/transport/account-api.js +152 -0
  328. package/src/transport/api.js +199 -0
  329. package/src/transport/shop-app.js +63 -0
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ const { withTargetShopDefault } = require('../../../../../execution/target-shop-default');
4
+
5
+ const { Command, Option } = require('commander');
6
+ const { contextInput } = require('../../../../../identity/context-store');
7
+ const { validateCommandValue } = require('../../../../../execution/command-schema');
8
+ const { parseIncludeModules } = require('../../../../../execution/command-io');
9
+ const { bindingPath, reject, targetScope, createQuery, serialize } = require('./query');
10
+ const projection = require('./projection');
11
+ const schema = require('./schema.json');
12
+
13
+ const command = 'aftersale.case.get';
14
+
15
+ function buildInput(options, context) {
16
+ const target = targetScope(options, context, command);
17
+ let caseId;
18
+ try { caseId = projection.identifier(options.caseId); }
19
+ catch { throw reject(command, 'validation', 'input', target); }
20
+ const scope = Object.freeze({ ...target, caseId });
21
+ try {
22
+ const input = { scope, include: [...parseIncludeModules(options.include, ['consultation'])] };
23
+ validateCommandValue(schema, 'input', input);
24
+ return input;
25
+ } catch { throw reject(command, 'validation', 'input', scope); }
26
+ }
27
+
28
+ function preview(input) {
29
+ const body = { refund_id: input.scope.caseId };
30
+ if (input.include.includes('consultation')) body.query_option = JSON.stringify({ include_all_consult_message: true });
31
+ const result = { requests: [{ method: 'POST', path: bindingPath, body: {} },
32
+ { method: 'POST', path: schema.api.path, body }] };
33
+ validateCommandValue(schema, 'preview', result);
34
+ return result;
35
+ }
36
+
37
+ function adapt(source, input, facts) {
38
+ const { scope } = input;
39
+ try {
40
+ const record = projection.caseRecord(source);
41
+ if (record.caseId !== scope.caseId || record.kdtId !== scope.kdtId) {
42
+ throw reject(command, 'scope_unresolved', 'case', scope, 'sent', facts);
43
+ }
44
+ const data = { case: record, items: projection.items(source.refund_order_item, scope) };
45
+ const logistics = projection.logistics(source);
46
+ if (logistics) data.logistics = logistics;
47
+ if (Object.hasOwn(source, 'refund_fund_list')) data.refunds = projection.refunds(source.refund_fund_list);
48
+ if (input.include.includes('consultation')) data.consultation = projection.consultation(source.consult_message, record);
49
+ const output = { data };
50
+ validateCommandValue(schema, 'output', output);
51
+ return output;
52
+ } catch (error) {
53
+ if (error.cliDetails) throw error;
54
+ throw reject(command, 'protocol', 'output-model', scope, 'sent', facts);
55
+ }
56
+ }
57
+
58
+ function createCommand({ context } = {}) {
59
+ const parser = new Command('get')
60
+ .description('按目标店铺和售后单号读取售后详情、商品行及已有运输和资金引用')
61
+ .allowExcessArguments(false)
62
+ .exitOverride(error => {
63
+ if (['commander.helpDisplayed', 'commander.version'].includes(error.code)) throw error;
64
+ throw reject(command, 'validation', 'input');
65
+ })
66
+ .option('--kdt-id <id>', '目标店铺规范十进制正安全整数;省略时使用当前上下文店铺')
67
+ .requiredOption('--case-id <id>', '必填:售后单号,1..128 字符,无空白和控制符,保留前导零')
68
+ .option('--include <modules>', '追加 consultation 请求完整协商;逗号分隔去重')
69
+ .addOption(new Option('--format <format>', '仅 JSON 缩进不同').choices(['json', 'pretty']).default('json'))
70
+ .option('--dry-run', '仅本地校验和两步请求计划,不读凭证、不联网')
71
+ .addHelpText('after', `
72
+ 默认返回售后、订单商品行及响应已有的运输和资金引用;只有请求 consultation 才校验并输出协商。
73
+ 只允许同店 shop 位置,执行需要有效四字段上下文。先核验凭证绑定店铺,再核对售后号和返回店铺。
74
+ 售后状态不是资金状态;缺资金数组不能证明没有退款,运单引用不证明签收或商家确认收货。
75
+ 默认 CNY,金额为元字符串、固定两位;时间为北京时间 YYYY-MM-DD HH:mm:ss.SSS。
76
+ 每次最多两请求,不重试、重定向、切店、换身份、解密或下载附件。
77
+ 累计响应 10MiB,传输读取时取消超限响应;最终输出含换行 5MiB,超限不裁切。
78
+ 缺可选字段省略,null/错型失败,实际零、false、空文本和空数组保留。未知状态保留不推断。
79
+ 失败 stdout 为空,stderr 一份安全 JSON;应用 token 测试不证明员工 OAuth 或权限隔离。
80
+ 示例:zan-saas aftersale case get --kdt-id 63077 --case-id 000123 --include consultation --dry-run
81
+ 字段及状态字典见 zan-saas schema aftersale.case.get。
82
+ `)
83
+ .action(async options => {
84
+ const input = buildInput(options, context === undefined ? contextInput() : context);
85
+ const plan = preview(input);
86
+ let output = plan;
87
+ if (!options.dryRun) {
88
+ const read = await createQuery(input.scope, command);
89
+ const request = plan.requests[1];
90
+ const { data, facts } = await read(request.path, request.body, 'case');
91
+ output = adapt(data, input, facts);
92
+ }
93
+ console.log(serialize(output, options.format, command, input.scope));
94
+ });
95
+ for (const name of ['kdtId', 'caseId', 'include', 'format', 'dryRun']) {
96
+ let occurrences = 0;
97
+ parser.on(`option:${name === 'dryRun' ? 'dry-run' : name === 'kdtId' ? 'kdt-id' : name === 'caseId' ? 'case-id' : name}`, () => {
98
+ if (++occurrences > 1) throw reject(command, 'validation', 'input');
99
+ });
100
+ }
101
+ return parser;
102
+ }
103
+
104
+ module.exports = { kind: 'atomic', risk: 'read', at: 'shop', createCommand: withTargetShopDefault(createCommand), buildInput, preview, adapt };
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ const { parseExactJson } = require('../../../../../execution/exact-json');
4
+
5
+ function parseLongJson(text) {
6
+ JSON.parse(text);
7
+ let index = 0;
8
+ const stack = [];
9
+ let root;
10
+ const numberPattern = /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y;
11
+ function append(value) {
12
+ const parent = stack[stack.length - 1];
13
+ if (!parent) { root = value; return; }
14
+ if (Array.isArray(parent.value)) parent.value.push(value);
15
+ else Object.defineProperty(parent.value, parent.key, { value, enumerable: true, configurable: true, writable: true });
16
+ parent.key = null;
17
+ }
18
+ while (index < text.length) {
19
+ const token = text[index++];
20
+ if (token.charCodeAt(0) <= 32 || token === ':' || token === ',') continue;
21
+ if (token === '{' || token === '[') {
22
+ const value = token === '{' ? {} : [];
23
+ append(value);
24
+ stack.push({ value, key: null });
25
+ } else if (token === '}' || token === ']') {
26
+ stack.pop();
27
+ } else if (token === '"') {
28
+ const start = index - 1;
29
+ while (index < text.length) {
30
+ const character = text[index++];
31
+ if (character === '\\') index++;
32
+ else if (character === '"') break;
33
+ }
34
+ const parent = stack[stack.length - 1];
35
+ if (parent && !Array.isArray(parent.value) && parent.key === null) {
36
+ parent.key = JSON.parse(text.slice(start, index));
37
+ } else append(JSON.parse(text.slice(start, index)));
38
+ } else if (token === 't' || token === 'f' || token === 'n') {
39
+ index += token === 'f' ? 4 : 3;
40
+ append(token === 't' ? true : token === 'f' ? false : null);
41
+ } else {
42
+ numberPattern.lastIndex = index - 1;
43
+ const source = numberPattern.exec(text)[0];
44
+ index = numberPattern.lastIndex;
45
+ const value = Number(source);
46
+ append(/^-?\d+$/.test(source) && !Number.isSafeInteger(value) ? BigInt(source) : parseExactJson(source));
47
+ }
48
+ }
49
+ return root;
50
+ }
51
+
52
+ module.exports = { parseLongJson };
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ const MAX_CENTS = 9223372036854775807n;
4
+
5
+ function formatCents(value) {
6
+ if (value < 0n || value > MAX_CENTS) throw new Error('amount outside long range');
7
+ return `${value / 100n}.${String(value % 100n).padStart(2, '0')}`;
8
+ }
9
+
10
+ function cents(value) {
11
+ if (typeof value === 'bigint') return formatCents(value);
12
+ if (!Number.isSafeInteger(value)) throw new Error('invalid integer cents');
13
+ return formatCents(BigInt(value));
14
+ }
15
+
16
+ function centsText(value) {
17
+ if (typeof value !== 'string' || !/^\d+$/.test(value)) throw new Error('invalid cents text');
18
+ return formatCents(BigInt(value));
19
+ }
20
+
21
+ function yuan(value) {
22
+ if (typeof value !== 'string' || !/^\d+(?:\.\d+)?$/.test(value)) throw new Error('invalid yuan');
23
+ const [whole, fraction = ''] = value.split('.');
24
+ if (/[1-9]/.test(fraction.slice(2))) throw new Error('inexact yuan');
25
+ return formatCents(BigInt(whole) * 100n + BigInt(fraction.slice(0, 2).padEnd(2, '0')));
26
+ }
27
+
28
+ module.exports = { cents, centsText, yuan };
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ const { object } = require('../../../../../execution/query-api');
4
+ const { formatDateTime, parseDateTime } = require('../../../../../execution/datetime');
5
+ const { cents, centsText, yuan } = require('./money');
6
+
7
+ function text(value) {
8
+ if (typeof value !== 'string') throw new Error('invalid text');
9
+ return value;
10
+ }
11
+ function nonempty(value) {
12
+ if (!text(value).trim()) throw new Error('empty identity');
13
+ return value;
14
+ }
15
+ function identifier(value) {
16
+ if (!/^[^\s\x00-\x1f\x7f-\x9f]{1,128}$/u.test(text(value))) throw new Error('invalid identifier');
17
+ return value;
18
+ }
19
+ function integer(value) {
20
+ if (!Number.isSafeInteger(value)) throw new Error('invalid integer');
21
+ return value;
22
+ }
23
+ function nonnegative(value) {
24
+ if (integer(value) < 0) throw new Error('negative value');
25
+ return value;
26
+ }
27
+ function shop(value) {
28
+ if (integer(value) < 1) throw new Error('invalid shop');
29
+ return value;
30
+ }
31
+ function boolean(value) {
32
+ if (typeof value !== 'boolean') throw new Error('invalid boolean');
33
+ return value;
34
+ }
35
+ function version(value) {
36
+ if (typeof value !== 'bigint') integer(value);
37
+ if (value < -9223372036854775808n || value > 9223372036854775807n) throw new Error('invalid version');
38
+ return String(value);
39
+ }
40
+ function time(value, alternate = false) {
41
+ text(value);
42
+ if (alternate && /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$/.test(value)) {
43
+ value = `${value.slice(0, 10)} ${value.slice(11).replaceAll('-', ':')}`;
44
+ }
45
+ if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value)) throw new Error('invalid source time');
46
+ return formatDateTime(parseDateTime(value));
47
+ }
48
+ function project(source, fields, required = []) {
49
+ if (!object(source)) throw new Error('invalid object');
50
+ const result = {};
51
+ for (const [target, [field, convert]] of Object.entries(fields)) {
52
+ if (Object.hasOwn(source, field)) result[target] = convert(source[field]);
53
+ else if (required.includes(target)) throw new Error('missing field');
54
+ }
55
+ return result;
56
+ }
57
+ function array(source, convert) {
58
+ if (!Array.isArray(source)) throw new Error('invalid array');
59
+ return source.map(convert);
60
+ }
61
+ function caseRecord(source) {
62
+ return project(source, {
63
+ caseId: ['refund_id', identifier], orderNo: ['tid', nonempty], kdtId: ['kdt_id', shop],
64
+ status: ['status', nonempty], demand: ['demand', integer], demandText: ['demand_desc', text],
65
+ type: ['refund_type', nonempty], amount: ['refund_fee', yuan], postage: ['refund_postage', yuan],
66
+ partType: ['part_type', integer], description: ['desc', text], hasReturnGoods: ['return_goods', boolean],
67
+ isNewExchange: ['is_new_exchange', boolean], serviceStatus: ['cs_status', integer], version: ['version', version],
68
+ createdAt: ['created', value => time(value, true)], updatedAt: ['modified', value => time(value, true)],
69
+ succeededAt: ['refund_success_time', time]
70
+ }, ['caseId', 'orderNo', 'kdtId', 'status', 'demand', 'amount']);
71
+ }
72
+ function items(source, scope) {
73
+ return array(source, entry => {
74
+ const item = project(entry, { orderItemId: ['oid', nonempty], kdtId: ['kdt_id', shop],
75
+ quantity: ['item_num', nonnegative], amount: ['refund_fee', cents], weightGrams: ['weight', nonnegative] },
76
+ ['orderItemId', 'quantity']);
77
+ if (Object.hasOwn(item, 'kdtId') && item.kdtId !== scope.kdtId) throw new Error('item shop mismatch');
78
+ return item;
79
+ });
80
+ }
81
+ function refunds(source) {
82
+ const seen = new Set();
83
+ return array(source, entry => {
84
+ const refund = project(entry, { refundNo: ['refund_no', identifier], refundId: ['refund_id', nonempty],
85
+ amount: ['refund_fee', cents], status: ['status', integer], mode: ['refund_mode', integer],
86
+ message: ['message', text], payWayText: ['pay_way_desc', text], payWayLabel: ['pay_way_str', text] },
87
+ ['refundNo', 'amount', 'status']);
88
+ if (seen.has(refund.refundNo)) throw new Error('duplicate refund');
89
+ seen.add(refund.refundNo);
90
+ return refund;
91
+ });
92
+ }
93
+ function logistics(source) {
94
+ const result = {};
95
+ for (const [direction, field] of [['return', 'logistics'], ['exchange', 'exgLogistics']]) {
96
+ const entry = source[field];
97
+ if (entry === undefined || entry === null) continue;
98
+ if (!object(entry)) throw new Error('invalid logistics');
99
+ if (!Object.hasOwn(entry, 'logistics_no')) continue;
100
+ text(entry.logistics_no);
101
+ if (entry.logistics_no === '') continue;
102
+ result[direction] = project(entry, { waybillNo: ['logistics_no', nonempty], carrierId: ['company_code', text] }, ['waybillNo']);
103
+ }
104
+ return Object.keys(result).length ? result : undefined;
105
+ }
106
+ function consultation(source, parent) {
107
+ return array(source, entry => {
108
+ const result = project(entry, { orderNo: ['order_no', nonempty], kdtId: ['kdt_id', shop], role: ['role', integer],
109
+ stage: ['stage', nonempty], demand: ['demand', integer], content: ['content', text],
110
+ createdAt: ['create_time', time], attachments: ['attachment', value => array(value, nonempty)],
111
+ detail: ['message_detail', value => project(value, { reasonText: ['refund_reason', text],
112
+ refusalCause: ['refusal_cause', text], demandText: ['refund_demand', text], amount: ['refund_fee', centsText],
113
+ suggestedAmount: ['suggest_refund_fee', centsText], quantity: ['num', nonnegative] })] }, ['role']);
114
+ if ((Object.hasOwn(result, 'orderNo') && result.orderNo !== parent.orderNo) ||
115
+ (Object.hasOwn(result, 'kdtId') && result.kdtId !== parent.kdtId)) throw new Error('consultation scope mismatch');
116
+ return result;
117
+ });
118
+ }
119
+
120
+ module.exports = { identifier, caseRecord, items, refunds, logistics, consultation };
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ const { resolveTargetShop } = require('../../../../../execution/target-shop');
4
+ const { readContext } = require('../../../../../identity/context');
5
+ const { bindingPath, failure } = require('../../../../../execution/shop-query');
6
+ const { readApiEnvelope, assertApiSuccess, object } = require('../../../../../execution/query-api');
7
+ const { snapshotApiEnvironment } = require('../../../../../transport/api');
8
+ const { parseLongJson } = require('./exact-json');
9
+
10
+ const RESPONSE_LIMIT = 10 * 1024 * 1024;
11
+ const OUTPUT_LIMIT = 5 * 1024 * 1024;
12
+
13
+ function reject(command, category, stage, scope = {}, requestState = 'not_sent', facts = {}) {
14
+ const error = failure(command, category, stage, scope, requestState, facts);
15
+ error.cliDetails.nextStep = stage === 'shop-binding' ?
16
+ '详情请求尚未发送。核对原凭证绑定店铺与显式目标,不自动重试、切店或换身份。' :
17
+ category === 'limit' ? '结果超出预算,未输出部分记录。可取消协商展开;不自动重试。' :
18
+ '核对原店铺与售后单号、上下文及服务端授权,不自动重试、切店或换身份。';
19
+ return error;
20
+ }
21
+
22
+ function targetScope(options, context, command) {
23
+ try {
24
+ const scope = resolveTargetShop(options, context, command);
25
+ if (readContext(context).context?.orgType === 'hq') throw reject(command, 'permission', 'context', scope);
26
+ return scope;
27
+ } catch (error) {
28
+ if (!error.cliDetails) throw error;
29
+ const details = error.cliDetails;
30
+ throw reject(command, details.category, ['scope', 'validation'].includes(details.stage) ? 'input' : details.stage,
31
+ details.targetScope);
32
+ }
33
+ }
34
+
35
+ async function createQuery(scope, command, { responseLimit = RESPONSE_LIMIT, onRequest } = {}) {
36
+ let env;
37
+ try { env = await snapshotApiEnvironment(undefined, scope.kdtId); }
38
+ catch { throw reject(command, 'configuration', 'configuration', scope); }
39
+ let bytes = 0;
40
+ async function read(path, body, stage) {
41
+ const received = await readApiEnvelope(path, body,
42
+ (category, facts, state, at) => reject(command, category, at === 'configuration' ? at : stage, scope, state, facts),
43
+ env, response => { bytes += response.responseBytes; },
44
+ { onRequest, maxResponseBytes: () => responseLimit - bytes });
45
+ const { facts } = received;
46
+ const result = parseLongJson(received.rawBody);
47
+ assertApiSuccess(result, category => {
48
+ const code = String(facts.businessCode);
49
+ if (category === 'business_rejected' && stage === 'case' &&
50
+ path === 'youzan.trade.refund.get/3.0.1' && !Object.hasOwn(result, 'gw_err_resp')) {
51
+ if (code === '103011024') category = 'not_found';
52
+ if (code === '103010054') category = 'permission';
53
+ }
54
+ throw reject(command, category, stage, scope, 'sent', facts);
55
+ }, stage === 'shop-binding' ? [200] : [200, '200']);
56
+ return { data: result.data, facts };
57
+ }
58
+ const { data, facts } = await read(bindingPath, {}, 'shop-binding');
59
+ if (!object(data) || !Number.isSafeInteger(data.sid) || data.sid < 1) {
60
+ throw reject(command, 'protocol', 'shop-binding', scope, 'sent', facts);
61
+ }
62
+ if (data.sid !== scope.kdtId) throw reject(command, 'scope_unresolved', 'shop-binding', scope, 'sent', facts);
63
+ return read;
64
+ }
65
+
66
+ function serialize(output, format, command, scope, limit = OUTPUT_LIMIT) {
67
+ const json = JSON.stringify(output, null, format === 'pretty' ? 2 : 0);
68
+ if (Buffer.byteLength(`${json}\n`) > limit) throw reject(command, 'limit', 'output-model', scope, 'sent');
69
+ return json;
70
+ }
71
+
72
+ module.exports = { bindingPath, reject, targetScope, createQuery, serialize, RESPONSE_LIMIT, OUTPUT_LIMIT };
@@ -0,0 +1,134 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "input": {
4
+ "type": "object", "additionalProperties": false, "required": ["scope", "include"],
5
+ "description": "argv 解析后的业务输入;format 和 dry-run 是展示及执行模式,不在业务输入内。",
6
+ "properties": {
7
+ "scope": {"$ref": "#/definitions/scope"},
8
+ "include": {"type": "array", "uniqueItems": true, "items": {"type": "string", "enum": ["consultation"]}, "description": "可选模块 consultation 请求完整协商;逗号分隔,裁首尾空白并去重;空项和未知值拒绝,默认空数组。"}
9
+ }
10
+ },
11
+ "output": {
12
+ "type": "object", "additionalProperties": false, "required": ["data"],
13
+ "properties": {"data": {
14
+ "type": "object", "additionalProperties": false, "required": ["case", "items"],
15
+ "properties": {
16
+ "case": {"$ref": "#/definitions/case"},
17
+ "items": {"type": "array", "items": {"$ref": "#/definitions/item"}, "description": "本次响应实际返回的订单商品行,保留顺序;实际空数组才输出空数组。"},
18
+ "logistics": {"type": "object", "additionalProperties": false, "minProperties": 1, "properties": {
19
+ "return": {"$ref": "#/definitions/waybill"}, "exchange": {"$ref": "#/definitions/waybill"}
20
+ }, "description": "仅返回可识别运单引用;缺失、null、空对象或只有公司和地址时省略该方向,不证明未寄件。"},
21
+ "refunds": {"type": "array", "items": {"$ref": "#/definitions/refund"}, "description": "本次返回的资金条目;源缺失省略,不表示零笔退款或全生命周期流水。重复 refundNo 整体失败。"},
22
+ "consultation": {"type": "array", "items": {"$ref": "#/definitions/consultation"}, "description": "仅显式请求 consultation 时必需;请求全部协商,不额外保证服务端保留期限。"}
23
+ }
24
+ }}
25
+ },
26
+ "preview": {
27
+ "type": "object", "additionalProperties": false, "required": ["requests"],
28
+ "properties": {"requests": {
29
+ "type": "array", "minItems": 2, "maxItems": 2,
30
+ "items": {"type": "object", "additionalProperties": false, "required": ["method", "path", "body"],
31
+ "properties": {"method": {"const": "POST"}, "path": {"type": "string", "enum": ["youzan.shop.basic.get/3.0.0", "youzan.trade.refund.get/3.0.1"]},
32
+ "body": {"oneOf": [
33
+ {"type": "object", "additionalProperties": false, "maxProperties": 0},
34
+ {"type": "object", "additionalProperties": false, "required": ["refund_id"], "properties": {
35
+ "refund_id": {"$ref": "#/definitions/identifier"},
36
+ "query_option": {"const": "{\"include_all_consult_message\":true}", "description": "请求协商时出现的准确 JSON 编码文本。"}
37
+ }}
38
+ ]}
39
+ }}
40
+ }}
41
+ },
42
+ "error": {
43
+ "type": "object", "additionalProperties": false, "required": ["success", "code", "message"],
44
+ "properties": {
45
+ "success": {"const": false}, "code": {"const": -10001}, "message": {"type": "string", "minLength": 1},
46
+ "details": {"type": "object", "additionalProperties": false,
47
+ "required": ["category", "stage", "command", "targetScope", "requestState", "nextStep"],
48
+ "properties": {
49
+ "category": {"type": "string", "enum": ["validation", "configuration", "authentication", "permission", "scope_unresolved", "http", "business_rejected", "not_found", "protocol", "transport", "limit"]},
50
+ "stage": {"type": "string", "enum": ["input", "context", "configuration", "shop-binding", "case", "cases", "refunds", "output-model", "transport", "response"]},
51
+ "command": {"const": "aftersale.case.get"},
52
+ "targetScope": {"type": "object", "additionalProperties": false, "properties": {"kdtId": {"$ref": "#/definitions/shopId"}, "caseId": {"$ref": "#/definitions/identifier"}}},
53
+ "requestState": {"type": "string", "enum": ["not_sent", "sent", "unknown"]}, "nextStep": {"type": "string", "minLength": 1},
54
+ "api": {"type": "string", "pattern": "^youzan\\.[a-z.]+/[0-9]+\\.[0-9]+\\.[0-9]+$"},
55
+ "httpStatus": {"type": "integer", "minimum": 100, "maximum": 599},
56
+ "businessCode": {"$ref": "#/definitions/diagnosticCode"}, "gatewayCode": {"$ref": "#/definitions/diagnosticCode"},
57
+ "trace_id": {"type": "string", "pattern": "^[a-zA-Z0-9_-]{1,128}$"}, "request_id": {"type": "string", "pattern": "^[a-zA-Z0-9_-]{1,128}$"}
58
+ }
59
+ }
60
+ }
61
+ },
62
+ "definitions": {
63
+ "scope": {"type": "object", "additionalProperties": false, "required": ["kdtId", "caseId"], "properties": {"kdtId": {"$ref": "#/definitions/shopId"}, "caseId": {"$ref": "#/definitions/identifier"}}},
64
+ "shopId": {"type": "integer", "minimum": 1, "maximum": 9007199254740991, "description": "正安全整数店铺 ID;argv 为规范十进制文本且必须显式提供。"},
65
+ "identifier": {"type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[^\\s\\u0000-\\u001f\\u007f-\\u009f]+$", "description": "售后号或资金流水号,保留前导零,不含空白和 C0/C1 控制符;128 是 CLI 预算。"},
66
+ "text": {"type": "string", "description": "上游明确返回的文本,允许空串。"},
67
+ "nonempty": {"type": "string", "minLength": 1, "pattern": "\\S", "description": "非空白文本,保留源值。"},
68
+ "integer": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991},
69
+ "quantity": {"type": "integer", "minimum": 0, "maximum": 9007199254740991},
70
+ "money": {"type": "string", "pattern": "^(?:0|[1-9][0-9]*)\\.[0-9]{2}$", "description": "默认人民币 CNY,元,固定两位小数。非负且精确分值不超过 9223372036854775807;拒绝舍入、空串和类型错误。"},
71
+ "time": {"type": "string", "format": "beijing-date-time-ms", "$comment": "upstream-time:text", "description": "固定北京时间 YYYY-MM-DD HH:mm:ss.SSS;仅源字段已证实的秒精度文本,校验实际日历。"},
72
+ "diagnosticCode": {"oneOf": [{"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991}, {"type": "string", "pattern": "^-?[0-9]{1,12}$"}]},
73
+ "case": {
74
+ "type": "object", "additionalProperties": false, "required": ["caseId", "orderNo", "kdtId", "status", "demand", "amount"],
75
+ "properties": {
76
+ "caseId": {"$ref": "#/definitions/identifier"}, "orderNo": {"$ref": "#/definitions/nonempty"}, "kdtId": {"$ref": "#/definitions/shopId"},
77
+ "status": {"type": "string", "minLength": 1, "pattern": "\\S", "description": "售后处理状态,不等于资金状态。WAIT_SELLER_AGREE 等待卖家同意;WAIT_BUYER_RETURN_GOODS 等待买家退货;WAIT_SELLER_CONFIRM_GOODS 等待确认收货;SELLER_REFUSE_BUYER 卖家拒绝退款;SELLER_REFUSE_BUYER_RETURN_GOODS 未收到货拒绝退款;SELLER_RETURN_GOODS 商家确认收货并发送换货;CLOSED 售后关闭;SUCCESS 售后成功。未知非空字符串保留,不推断到账。"},
78
+ "demand": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "当前诉求:1 仅退款,2 退货退款,3 换货。未知安全整数保留。"},
79
+ "demandText": {"$ref": "#/definitions/text"},
80
+ "type": {"type": "string", "minLength": 1, "pattern": "\\S", "description": "BUYER_APPLY_REFUND 买家申请;SELLER_REFUND 商家主动退款;EXCHANGE_GOODS 线上普通或跨 SKU 换货;SYSTEM_REFUND 一键退款及超卖、支付回调超时等特殊退款;OFFLINE_EXCHANGE_GOODS 线下或零售换货。未知非空值保留。"},
81
+ "amount": {"$ref": "#/definitions/money", "$comment": "upstream-money:yuan", "description": "含邮费的售后申请退款金额,不是已到账金额。"},
82
+ "postage": {"$ref": "#/definitions/money", "$comment": "upstream-money:yuan", "description": "退还邮费。"},
83
+ "partType": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "0 全额退,1 部分退;未知安全整数保留。"},
84
+ "description": {"$ref": "#/definitions/text"}, "hasReturnGoods": {"type": "boolean", "description": "上游是否有退货,不推导库存结果。"}, "isNewExchange": {"type": "boolean", "description": "是否跨 SKU 换货。"},
85
+ "serviceStatus": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "1 未介入,2 介入中,3 介入结束;未知安全整数保留。"},
86
+ "version": {"type": "string", "pattern": "^-?[0-9]+$", "description": "精确十进制 long 版本号,范围 -9223372036854775808 至 9223372036854775807;不表示写入授权。"},
87
+ "createdAt": {"$ref": "#/definitions/time"}, "updatedAt": {"$ref": "#/definitions/time"}, "succeededAt": {"$ref": "#/definitions/time", "description": "售后成功时间,不是逐笔资金到账时间。"}
88
+ }
89
+ },
90
+ "item": {"type": "object", "additionalProperties": false, "required": ["orderItemId", "quantity"], "properties": {
91
+ "orderItemId": {"$ref": "#/definitions/nonempty", "description": "订单商品行 oid,不用商品 ID 或顶层首行代替。"}, "kdtId": {"$ref": "#/definitions/shopId"}, "quantity": {"$ref": "#/definitions/quantity"},
92
+ "amount": {"$ref": "#/definitions/money", "$comment": "upstream-money:cents", "description": "该行含邮费退款金额。"}, "weightGrams": {"$ref": "#/definitions/quantity", "description": "退款商品重量,单位克。"}
93
+ }},
94
+ "waybill": {"type": "object", "additionalProperties": false, "required": ["waybillNo"], "properties": {"waybillNo": {"$ref": "#/definitions/nonempty"}, "carrierId": {"$ref": "#/definitions/text", "description": "有赞物流公司标识,不转换其他平台编码。"}}, "description": "已返回运单引用,不证明签收、入库或商家确认收货。"},
95
+ "refund": {"type": "object", "additionalProperties": false, "required": ["refundNo", "amount", "status"], "properties": {
96
+ "refundNo": {"$ref": "#/definitions/identifier"}, "refundId": {"$ref": "#/definitions/nonempty", "description": "资金条目自带 ID,不证明等于父售后号。"},
97
+ "amount": {"$ref": "#/definitions/money", "$comment": "upstream-money:cents", "description": "本资金条目含邮费退款金额。"},
98
+ "status": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "0 退款中,可能包含失败回写延迟;1 退款失败;2 退款成功。未知安全整数保留,不推断到账。"},
99
+ "mode": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "0 原路退,1 现金退,2 标记退;3 已观察但含义未证实;未知安全整数保留。"},
100
+ "message": {"$ref": "#/definitions/text"}, "payWayText": {"$ref": "#/definitions/text"}, "payWayLabel": {"$ref": "#/definitions/text"}
101
+ }},
102
+ "consultation": {"type": "object", "additionalProperties": false, "required": ["role"], "properties": {
103
+ "orderNo": {"$ref": "#/definitions/nonempty", "description": "出现时必须匹配父售后订单。"}, "kdtId": {"$ref": "#/definitions/shopId"},
104
+ "role": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "1 系统,2 买家,3 卖家,4 客服;未知安全整数保留。"},
105
+ "stage": {"type": "string", "minLength": 1, "pattern": "\\S", "description": "RefundCreate 申请;RefundReject 商家拒绝;RefundCancel 买家撤销;RefundFinish 商家同意退款;RefundReturnGoodsAgree 同意退货;RefundReset 修改重发;RefundReturnGoods 买家填退货物流;RefundReturnGoodsReject 拒绝退货;RefundIntervene 客满介入;MessageAdd 留言;SellerReturnGoods 确认收货并发换货;RefundBuyerAgree 买家同意修改。未知非空字符串保留。"},
106
+ "demand": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "该记录时诉求:1 仅退款,2 退货退款,3 换货;可与当前诉求不同,未知安全整数保留。"},
107
+ "content": {"$ref": "#/definitions/text"}, "createdAt": {"$ref": "#/definitions/time"},
108
+ "attachments": {"type": "array", "items": {"$ref": "#/definitions/nonempty"}, "description": "凭证链接,未下载,不证明可访问。"},
109
+ "detail": {"type": "object", "additionalProperties": false, "properties": {
110
+ "reasonText": {"$ref": "#/definitions/text"}, "refusalCause": {"$ref": "#/definitions/text"}, "demandText": {"$ref": "#/definitions/text"},
111
+ "amount": {"$ref": "#/definitions/money", "$comment": "upstream-money:cents-text"}, "suggestedAmount": {"$ref": "#/definitions/money", "$comment": "upstream-money:cents-text"}, "quantity": {"$ref": "#/definitions/quantity"}
112
+ }}
113
+ }}
114
+ },
115
+ "modules": {
116
+ "case": {"base": true, "upstreamPath": "data", "required": true, "description": "售后核心及已取得的可选字段。"},
117
+ "items": {"base": true, "upstreamPath": "data.refund_order_item", "required": true, "description": "默认订单商品行,必须为数组。"},
118
+ "logistics": {"base": true, "upstreamPath": "data.logistics,data.exgLogistics", "required": false, "description": "默认已有的有限运单引用,不是轨迹或收货确认。"},
119
+ "refunds": {"base": true, "upstreamPath": "data.refund_fund_list", "required": false, "description": "默认本次已返回的资金条目,缺失省略。"},
120
+ "consultation": {"base": false, "upstreamPath": "data.consult_message", "required": true, "description": "请求完整协商后必需;只改变主请求选项,不增加请求。"}
121
+ },
122
+ "api": {"method": "POST", "path": "youzan.trade.refund.get/3.0.1"},
123
+ "success": {"description": "同凭证店铺核验通过,售后号及店铺匹配,核心售后、商品行和所有默认已返回字段及显式协商模型均通过,才一次输出。"},
124
+ "errors": {"description": "缺失必需字段、null、错型、身份冲突、重复资金流水、金额不精确及时间非法整体失败。103011024 不存在;103010021/103010052 售后号无效;103010002 店铺缺失;103010054 权限拒绝。失败 stdout 为空,stderr 安全 JSON;断连 unknown,不自动重试。"},
125
+ "notes": [
126
+ "--kdt-id 省略时使用本次有效上下文 shopId;显式提供的非法值不回退。两者都缺失时拒绝;目标范围、同店核验和服务端权限仍按本命令校验。",
127
+ "接受售后号和目标店铺;省略店铺时使用当前上下文,显式非法值不回退;执行上下文必须为 shop 且目标等于 context.shopId;总部拒绝。缺上下文只可本地预览,无效上下文始终拒绝。应用身份不证明员工 OAuth 或权限隔离。",
128
+ "业务输入仅 scope/include。format 默认为 json,可选 pretty;dry-run 默认 false,二者不进入业务 input 或请求。",
129
+ "可选字段仅源缺失时省略,null 或错型失败;运输 null 及未取得可识别运单引用是省略例外。实际零、false、空文本和空数组保留。未知字段不透传,未请求协商不校验或输出。",
130
+ "默认 CNY,金额按准确来源单位转换到两位元字符串,不求和或分摊。时间固定北京时间;申请与修改时间兼容文案连字符及正式示例空格格式。",
131
+ "每次最多两请求,无重试、重定向、身份切换、自动解密或附件下载。累计原始响应 10MiB,读取时取消超限流;最终 UTF-8 输出含换行 5MiB,超限不裁切。",
132
+ "售后成功不代表每笔资金到账。缺资金数组不证明无退款;资金 mode 3 含义未证实,资金集合不保证全生命周期,未公开到账时间及储值拆分。"
133
+ ]
134
+ }