@pisell/pisellos 0.0.567 → 0.0.568

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 (228) hide show
  1. package/dist/core/index.js +6 -9
  2. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
  3. package/dist/model/strategy/adapter/walletPass/example.js +3 -26
  4. package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
  5. package/dist/model/strategy/strategy-example.js +5 -19
  6. package/dist/modules/Cart/index.js +0 -3
  7. package/dist/modules/Cart/utils/cartProduct.js +0 -1
  8. package/dist/modules/Date/index.js +1 -5
  9. package/dist/modules/Discount/index.js +1 -4
  10. package/dist/modules/OpenData/index.js +0 -2
  11. package/dist/modules/Order/index.d.ts +1 -1
  12. package/dist/modules/Order/index.js +14 -41
  13. package/dist/modules/Payment/index.js +142 -270
  14. package/dist/modules/Payment/walletpass.js +4 -5
  15. package/dist/modules/Rules/index.js +0 -7
  16. package/dist/modules/Schedule/utils.js +0 -1
  17. package/dist/modules/Step/index.js +0 -1
  18. package/dist/plugins/request.js +1 -4
  19. package/dist/plugins/window.js +2 -6
  20. package/dist/server/index.js +88 -121
  21. package/dist/server/modules/menu/index.js +32 -41
  22. package/dist/server/modules/products/index.js +29 -49
  23. package/dist/server/modules/quotation/index.js +29 -38
  24. package/dist/server/modules/resource/index.js +3 -4
  25. package/dist/server/modules/schedule/index.js +32 -40
  26. package/dist/server/utils/product.js +0 -1
  27. package/dist/solution/BookingByStep/index.d.ts +1 -1
  28. package/dist/solution/BookingByStep/index.js +7 -59
  29. package/dist/solution/BookingByStep/utils/capacity.js +1 -11
  30. package/dist/solution/BookingByStep/utils/resources.js +1 -3
  31. package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
  32. package/dist/solution/BookingTicket/index.d.ts +1 -1
  33. package/dist/solution/BookingTicket/index.js +5 -7
  34. package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
  35. package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
  36. package/dist/solution/BuyTickets/index.js +9 -12
  37. package/dist/solution/Checkout/index.js +177 -246
  38. package/dist/solution/Checkout/utils/index.js +4 -16
  39. package/dist/solution/RegisterAndLogin/index.js +30 -76
  40. package/dist/solution/ScanOrder/index.js +50 -60
  41. package/dist/solution/ShopDiscount/index.js +2 -7
  42. package/dist/solution/VenueBooking/index.d.ts +5 -0
  43. package/dist/solution/VenueBooking/index.js +364 -327
  44. package/dist/utils/task.js +15 -18
  45. package/dist/utils/watch.js +0 -1
  46. package/lib/apis/picoding.js +2 -0
  47. package/lib/core/index.js +130 -131
  48. package/lib/effects/index.js +46 -57
  49. package/lib/index.js +92 -53
  50. package/lib/model/index.js +14 -21
  51. package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
  52. package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
  53. package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
  54. package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
  55. package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
  56. package/lib/model/strategy/adapter/index.js +100 -64
  57. package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
  58. package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
  59. package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
  60. package/lib/model/strategy/adapter/itemRule/index.js +83 -57
  61. package/lib/model/strategy/adapter/itemRule/type.js +97 -36
  62. package/lib/model/strategy/adapter/promotion/adapter.js +84 -63
  63. package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
  64. package/lib/model/strategy/adapter/promotion/examples.js +139 -159
  65. package/lib/model/strategy/adapter/promotion/index.js +1 -49
  66. package/lib/model/strategy/adapter/promotion/type.js +199 -35
  67. package/lib/model/strategy/adapter/type.js +4 -16
  68. package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
  69. package/lib/model/strategy/adapter/walletPass/example.js +217 -190
  70. package/lib/model/strategy/adapter/walletPass/index.js +75 -51
  71. package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
  72. package/lib/model/strategy/adapter/walletPass/type.js +4 -16
  73. package/lib/model/strategy/adapter/walletPass/utils.js +652 -402
  74. package/lib/model/strategy/engine.js +270 -168
  75. package/lib/model/strategy/index.js +49 -34
  76. package/lib/model/strategy/strategy-example.js +243 -239
  77. package/lib/model/strategy/type.js +100 -40
  78. package/lib/modules/Account/index.js +39 -53
  79. package/lib/modules/Account/types.js +20 -33
  80. package/lib/modules/AccountList/index.js +116 -154
  81. package/lib/modules/AccountList/types.js +30 -31
  82. package/lib/modules/AccountList/utils.js +18 -30
  83. package/lib/modules/BaseModule.js +22 -45
  84. package/lib/modules/Cart/index.js +170 -124
  85. package/lib/modules/Cart/types.js +46 -51
  86. package/lib/modules/Cart/utils/cartAccount.js +40 -39
  87. package/lib/modules/Cart/utils/cartDate.js +56 -61
  88. package/lib/modules/Cart/utils/cartDiscount.js +28 -33
  89. package/lib/modules/Cart/utils/cartNote.js +27 -32
  90. package/lib/modules/Cart/utils/cartProduct.js +306 -241
  91. package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
  92. package/lib/modules/Cart/utils/cartResource.js +72 -78
  93. package/lib/modules/Cart/utils/changePrice.js +26 -62
  94. package/lib/modules/Cart/utils/index.js +106 -48
  95. package/lib/modules/Customer/constants.js +13 -34
  96. package/lib/modules/Customer/index.js +216 -153
  97. package/lib/modules/Customer/types.js +38 -35
  98. package/lib/modules/Date/index.js +116 -115
  99. package/lib/modules/Date/types.js +16 -28
  100. package/lib/modules/Date/utils.js +174 -123
  101. package/lib/modules/Discount/index.js +117 -113
  102. package/lib/modules/Discount/types.js +9 -31
  103. package/lib/modules/Guests/index.js +30 -56
  104. package/lib/modules/Guests/types.js +23 -33
  105. package/lib/modules/Holder/index.js +209 -189
  106. package/lib/modules/Holder/types.js +4 -16
  107. package/lib/modules/Holder/utils.js +20 -49
  108. package/lib/modules/OpenData/index.js +63 -74
  109. package/lib/modules/OpenData/types.js +4 -16
  110. package/lib/modules/OpenData/utils.js +44 -78
  111. package/lib/modules/Order/index.d.ts +1 -1
  112. package/lib/modules/Order/index.js +332 -320
  113. package/lib/modules/Order/types.js +24 -33
  114. package/lib/modules/Order/utils.js +350 -284
  115. package/lib/modules/Payment/cash.js +20 -33
  116. package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
  117. package/lib/modules/Payment/eftpos.js +16 -30
  118. package/lib/modules/Payment/index.js +566 -432
  119. package/lib/modules/Payment/mx51.js +1 -0
  120. package/lib/modules/Payment/types.js +216 -107
  121. package/lib/modules/Payment/utils.js +50 -47
  122. package/lib/modules/Payment/walletpass.js +221 -203
  123. package/lib/modules/Product/index.js +51 -46
  124. package/lib/modules/Product/types.js +4 -16
  125. package/lib/modules/Product/utils.js +32 -33
  126. package/lib/modules/ProductList/index.js +111 -110
  127. package/lib/modules/ProductList/types.js +9 -31
  128. package/lib/modules/Quotation/index.js +60 -82
  129. package/lib/modules/Quotation/types.js +4 -16
  130. package/lib/modules/Resource/index.js +27 -59
  131. package/lib/modules/Resource/types.js +22 -32
  132. package/lib/modules/Resource/utils.js +30 -38
  133. package/lib/modules/Rules/index.js +1172 -872
  134. package/lib/modules/Rules/types.js +17 -40
  135. package/lib/modules/SalesSummary/index.js +59 -68
  136. package/lib/modules/SalesSummary/types.js +4 -16
  137. package/lib/modules/SalesSummary/utils.js +176 -193
  138. package/lib/modules/ScanOrderLogger/index.js +59 -79
  139. package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
  140. package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
  141. package/lib/modules/ScanOrderLogger/types.js +4 -16
  142. package/lib/modules/Schedule/getDateIsInSchedule.js +334 -167
  143. package/lib/modules/Schedule/index.js +97 -107
  144. package/lib/modules/Schedule/type.js +4 -16
  145. package/lib/modules/Schedule/types.js +4 -16
  146. package/lib/modules/Schedule/utils.js +433 -291
  147. package/lib/modules/Step/index.js +40 -52
  148. package/lib/modules/Step/tyeps.js +4 -16
  149. package/lib/modules/Summary/index.js +66 -70
  150. package/lib/modules/Summary/types.js +4 -16
  151. package/lib/modules/Summary/utils.js +782 -429
  152. package/lib/modules/index.js +212 -57
  153. package/lib/plugins/app.js +4 -16
  154. package/lib/plugins/index.js +36 -25
  155. package/lib/plugins/request.js +137 -126
  156. package/lib/plugins/shopStore.js +4 -16
  157. package/lib/plugins/user.js +4 -16
  158. package/lib/plugins/window.js +171 -179
  159. package/lib/server/index.js +882 -623
  160. package/lib/server/modules/index.js +85 -59
  161. package/lib/server/modules/menu/index.js +146 -122
  162. package/lib/server/modules/menu/types.js +18 -31
  163. package/lib/server/modules/order/index.js +195 -231
  164. package/lib/server/modules/order/types.js +107 -32
  165. package/lib/server/modules/order/utils/filterBookings.js +174 -140
  166. package/lib/server/modules/order/utils/filterOrders.js +89 -60
  167. package/lib/server/modules/products/index.js +430 -335
  168. package/lib/server/modules/products/types.js +41 -34
  169. package/lib/server/modules/quotation/index.js +76 -77
  170. package/lib/server/modules/quotation/types.js +21 -31
  171. package/lib/server/modules/resource/index.js +216 -187
  172. package/lib/server/modules/resource/types.js +42 -33
  173. package/lib/server/modules/schedule/index.js +134 -119
  174. package/lib/server/modules/schedule/types.js +14 -21
  175. package/lib/server/modules/schedule/utils.js +334 -163
  176. package/lib/server/types.js +4 -16
  177. package/lib/server/utils/index.js +25 -23
  178. package/lib/server/utils/product.js +196 -139
  179. package/lib/server/utils/schedule.js +34 -41
  180. package/lib/server/utils/time.js +40 -49
  181. package/lib/solution/BookingByStep/index.d.ts +1 -1
  182. package/lib/solution/BookingByStep/index.js +1530 -1343
  183. package/lib/solution/BookingByStep/types.js +40 -99
  184. package/lib/solution/BookingByStep/utils/capacity.js +192 -160
  185. package/lib/solution/BookingByStep/utils/products.js +42 -52
  186. package/lib/solution/BookingByStep/utils/resources.js +527 -330
  187. package/lib/solution/BookingByStep/utils/stock.js +65 -44
  188. package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
  189. package/lib/solution/BookingTicket/index.d.ts +1 -1
  190. package/lib/solution/BookingTicket/index.js +147 -122
  191. package/lib/solution/BookingTicket/types.js +38 -64
  192. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
  193. package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
  194. package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
  195. package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
  196. package/lib/solution/BuyTickets/index.js +67 -70
  197. package/lib/solution/BuyTickets/types.js +22 -38
  198. package/lib/solution/Checkout/index.js +1451 -1158
  199. package/lib/solution/Checkout/types.js +91 -61
  200. package/lib/solution/Checkout/utils/index.js +227 -158
  201. package/lib/solution/PlaceOrder/index.js +55 -0
  202. package/lib/solution/RegisterAndLogin/config.js +493 -460
  203. package/lib/solution/RegisterAndLogin/index.js +633 -630
  204. package/lib/solution/RegisterAndLogin/types.js +189 -76
  205. package/lib/solution/RegisterAndLogin/utils.js +183 -125
  206. package/lib/solution/Sales/index.js +218 -200
  207. package/lib/solution/Sales/types.js +27 -33
  208. package/lib/solution/ScanOrder/index.js +803 -840
  209. package/lib/solution/ScanOrder/types.js +34 -34
  210. package/lib/solution/ScanOrder/utils.js +372 -331
  211. package/lib/solution/ShopDiscount/index.js +230 -236
  212. package/lib/solution/ShopDiscount/types.js +15 -37
  213. package/lib/solution/ShopDiscount/utils.js +309 -172
  214. package/lib/solution/VenueBooking/index.d.ts +5 -0
  215. package/lib/solution/VenueBooking/index.js +886 -929
  216. package/lib/solution/VenueBooking/types.js +20 -40
  217. package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
  218. package/lib/solution/VenueBooking/utils/resource.js +31 -54
  219. package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
  220. package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
  221. package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
  222. package/lib/solution/VenueBooking/utils.js +130 -67
  223. package/lib/solution/index.js +102 -37
  224. package/lib/store/createStore.js +32 -29
  225. package/lib/types/index.js +4 -16
  226. package/lib/utils/task.js +36 -36
  227. package/lib/utils/watch.js +81 -47
  228. package/package.json +2 -1
@@ -1,111 +1,134 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ "use strict";
28
2
 
29
- // src/modules/Order/utils.ts
30
- var utils_exports = {};
31
- __export(utils_exports, {
32
- buildSubmitPayload: () => buildSubmitPayload,
33
- composeLinePrice: () => composeLinePrice,
34
- createDefaultOrderRulesHooks: () => createDefaultOrderRulesHooks,
35
- createDefaultTempOrder: () => createDefaultTempOrder,
36
- createEmptySummary: () => import_utils3.createEmptySummary,
37
- createUuidV4: () => createUuidV4,
38
- ensureCartItemOriginHolder: () => ensureCartItemOriginHolder,
39
- filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
40
- formatDateTime: () => formatDateTime,
41
- formatV1Product: () => formatV1Product,
42
- generateDuration: () => generateDuration,
43
- getAllDiscountList: () => getAllDiscountList,
44
- isTempOrder: () => isTempOrder,
45
- mergeRelationForms: () => mergeRelationForms,
46
- normalizeSubmitBooking: () => normalizeSubmitBooking,
47
- normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
48
- resolveSubmitCollectPax: () => resolveSubmitCollectPax,
49
- sumOptionUnitPrice: () => sumOptionUnitPrice
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
50
5
  });
51
- module.exports = __toCommonJS(utils_exports);
52
- var import_dayjs = __toESM(require("dayjs"));
53
- var import_decimal = __toESM(require("decimal.js"));
54
- var import_utils = require("../Holder/utils");
55
- var import_utils2 = require("../../solution/ScanOrder/utils");
56
- var import_utils3 = require("../../solution/ScanOrder/utils");
6
+ exports.buildSubmitPayload = buildSubmitPayload;
7
+ exports.composeLinePrice = composeLinePrice;
8
+ exports.createDefaultOrderRulesHooks = createDefaultOrderRulesHooks;
9
+ exports.createDefaultTempOrder = createDefaultTempOrder;
10
+ Object.defineProperty(exports, "createEmptySummary", {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _utils2.createEmptySummary;
14
+ }
15
+ });
16
+ exports.createUuidV4 = createUuidV4;
17
+ exports.ensureCartItemOriginHolder = ensureCartItemOriginHolder;
18
+ exports.filterProductsForScanOrderMore = filterProductsForScanOrderMore;
19
+ exports.formatDateTime = formatDateTime;
20
+ exports.formatV1Product = formatV1Product;
21
+ exports.getAllDiscountList = exports.generateDuration = void 0;
22
+ exports.isTempOrder = isTempOrder;
23
+ exports.mergeRelationForms = void 0;
24
+ exports.normalizeSubmitBooking = normalizeSubmitBooking;
25
+ exports.normalizeSubmitCollectPaxValue = normalizeSubmitCollectPaxValue;
26
+ exports.resolveSubmitCollectPax = resolveSubmitCollectPax;
27
+ exports.sumOptionUnitPrice = sumOptionUnitPrice;
28
+ var _dayjs = _interopRequireDefault(require("dayjs"));
29
+ var _decimal = _interopRequireDefault(require("decimal.js"));
30
+ var _utils = require("../Holder/utils");
31
+ var _utils2 = require("../../solution/ScanOrder/utils");
32
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
+ /**
34
+ * 把"含 option 的主商品单价"与 bundle 合成"单行 composite 单价"。
35
+ *
36
+ * 新语义 v2 约定:
37
+ * - `mainPrice` 必须是**已经包含 option 的主商品单价**(即 `metadata.main_product_selling_price`
38
+ * 或 `metadata.main_product_original_price`),option 价格不由本函数叠加。
39
+ * - 套餐价:Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? bundle.quantity ?? 1))
40
+ * 当 `useOriginalBundle=true` 时,改用 `bundle.original_price ?? bundle.product_price ?? bundle.price`。
41
+ * - 返回值:保留 2 位小数的字符串,方便直接写回 `selling_price` / `original_price` 字段。
42
+ *
43
+ * 被 `normalizeOrderProduct`、Rules setProduct 钩子、各 Solution 的 setDiscountSelected 共用,
44
+ * 保证合成逻辑单点来源。
45
+ */
57
46
  function composeLinePrice(params) {
58
- const { mainPrice, bundle, useOriginalBundle } = params;
59
- let total = new import_decimal.default(Number(mainPrice) || 0);
47
+ const {
48
+ mainPrice,
49
+ bundle,
50
+ useOriginalBundle
51
+ } = params;
52
+ let total = new _decimal.default(Number(mainPrice) || 0);
60
53
  if (Array.isArray(bundle)) {
61
54
  for (const item of bundle) {
62
- const rawPrice = useOriginalBundle ? (item == null ? void 0 : item.original_price) ?? (item == null ? void 0 : item.product_price) ?? (item == null ? void 0 : item.price) : (item == null ? void 0 : item.bundle_selling_price) ?? (item == null ? void 0 : item.price);
63
- const price = new import_decimal.default(Number(rawPrice) || 0);
64
- const rawNum = (item == null ? void 0 : item.num) ?? (item == null ? void 0 : item.quantity) ?? 1;
65
- const num = new import_decimal.default(Number(rawNum) || 0);
55
+ const rawPrice = useOriginalBundle ? item?.original_price ?? item?.product_price ?? item?.price : item?.bundle_selling_price ?? item?.price;
56
+ const price = new _decimal.default(Number(rawPrice) || 0);
57
+ const rawNum = item?.num ?? item?.quantity ?? 1;
58
+ const num = new _decimal.default(Number(rawNum) || 0);
66
59
  total = total.plus(price.times(num));
67
60
  }
68
61
  }
69
62
  return total.toDecimalPlaces(2).toFixed(2);
70
63
  }
64
+
65
+ /**
66
+ * 计算 option 单价合计:Σ(option.price × option.num)。
67
+ * 在新语义 v2 下,main_product_original_price = source_product_price + 本函数结果。
68
+ */
71
69
  function sumOptionUnitPrice(options) {
72
- let total = new import_decimal.default(0);
73
- if (!Array.isArray(options))
74
- return total;
70
+ let total = new _decimal.default(0);
71
+ if (!Array.isArray(options)) return total;
75
72
  for (const opt of options) {
76
- const price = new import_decimal.default(Number(opt == null ? void 0 : opt.price) || 0);
77
- const num = new import_decimal.default(Number(opt == null ? void 0 : opt.num) || 0);
73
+ const price = new _decimal.default(Number(opt?.price) || 0);
74
+ const num = new _decimal.default(Number(opt?.num) || 0);
78
75
  total = total.plus(price.times(num));
79
76
  }
80
77
  return total;
81
78
  }
79
+
80
+ /**
81
+ * OrderModule 默认 Rules 钩子工厂。
82
+ *
83
+ * 价格语义约定(订单域,v2 composite 口径):
84
+ * - `selling_price`:券后 **行 composite 单价**
85
+ * = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
86
+ * - `original_price`:券前 **行 composite 单价**
87
+ * = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
88
+ * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
89
+ * 不含折扣。**权威源**。
90
+ * - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
91
+ * - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
92
+ * - `payment_price`:出站 payload 中由 `selling_price` 派生以兼容后端(composite)。
93
+ *
94
+ * Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
95
+ * - `getProduct.price` / `getProduct.original_price` 回传 **source-level 主价**
96
+ * (`metadata.source_product_price`)。Rules 内部 `getProductTotalPrice` /
97
+ * `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
98
+ * - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
99
+ * total(source + option + bundle)对齐。
100
+ * - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
101
+ * 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
102
+ * 优先级:
103
+ * 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
104
+ * 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
105
+ * 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
106
+ *
107
+ * 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
108
+ */
82
109
  function createDefaultOrderRulesHooks() {
83
110
  const toUnitPriceString = (totalLike, num) => {
84
111
  const effectiveNum = Number(num) > 0 ? Number(num) : 1;
85
- return new import_decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
112
+ return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
86
113
  };
87
114
  return {
88
- getProduct: (product) => {
89
- var _a, _b, _c, _d;
115
+ getProduct: product => {
116
+ // source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
90
117
  const metadataAny = product.metadata || {};
91
118
  const optionSum = sumOptionUnitPrice(product.product_option_item);
92
119
  let sourcePrice;
93
- if (metadataAny.source_product_price !== void 0) {
120
+ if (metadataAny.source_product_price !== undefined) {
94
121
  sourcePrice = String(metadataAny.source_product_price);
95
- } else if (metadataAny.main_product_selling_price !== void 0) {
96
- sourcePrice = new import_decimal.default(
97
- Number(metadataAny.main_product_selling_price) || 0
98
- ).minus(optionSum).toDecimalPlaces(2).toString();
122
+ } else if (metadataAny.main_product_selling_price !== undefined) {
123
+ sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString();
99
124
  } else {
100
125
  sourcePrice = String(product.selling_price ?? 0);
101
126
  }
102
127
  let sourceOriginalPrice;
103
- if (metadataAny.source_product_price !== void 0) {
128
+ if (metadataAny.source_product_price !== undefined) {
104
129
  sourceOriginalPrice = String(metadataAny.source_product_price);
105
- } else if (metadataAny.main_product_original_price !== void 0) {
106
- sourceOriginalPrice = new import_decimal.default(
107
- Number(metadataAny.main_product_original_price) || 0
108
- ).minus(optionSum).toDecimalPlaces(2).toString();
130
+ } else if (metadataAny.main_product_original_price !== undefined) {
131
+ sourceOriginalPrice = new _decimal.default(Number(metadataAny.main_product_original_price) || 0).minus(optionSum).toDecimalPlaces(2).toString();
109
132
  } else {
110
133
  sourceOriginalPrice = sourcePrice;
111
134
  }
@@ -115,40 +138,44 @@ function createDefaultOrderRulesHooks() {
115
138
  // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
116
139
  // 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证 identity_key 必存在;
117
140
  // 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
118
- _id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, import_utils2.buildProductLineFingerprint)(
119
- product.product_option_item,
120
- product.product_bundle
121
- )}`,
141
+ _id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, _utils2.buildProductLineFingerprint)(product.product_option_item, product.product_bundle)}`,
122
142
  // Rules 内部 getProductTotalPrice / getProductOriginTotalPrice 会各自再叠加 bundle + option,
123
143
  // 所以这里必须喂 source-level(不含 option、不含 bundle、不含折扣)单价,避免双加 option。
124
144
  price: sourcePrice,
125
145
  // total / origin_total 使用 composite × num,跟 Rules 内部产出的 total 对齐(含 option + bundle)。
126
- total: new import_decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
127
- origin_total: new import_decimal.default(
128
- product.original_price || product.selling_price || 0
129
- ).times(product.num || 1).toNumber(),
146
+ total: new _decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
147
+ origin_total: new _decimal.default(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
130
148
  original_price: sourceOriginalPrice,
131
149
  quantity: product.num || 1,
132
150
  num: product.num || 1,
133
151
  discount_list: product.discount_list || [],
134
152
  bundle: product.product_bundle || [],
135
- booking_id: ((_a = product._origin) == null ? void 0 : _a.booking_id) || null,
153
+ booking_id: product._origin?.booking_id || null,
136
154
  isClient: false,
137
- isManualDiscount: ((_b = product._origin) == null ? void 0 : _b.isManualDiscount) || false,
138
- holder_id: (_c = product._origin) == null ? void 0 : _c.holder_id,
139
- startDate: (_d = product._origin) == null ? void 0 : _d.startDate
155
+ isManualDiscount: product._origin?.isManualDiscount || false,
156
+ holder_id: product._origin?.holder_id,
157
+ startDate: product._origin?.startDate
140
158
  };
141
159
  },
142
160
  setProduct: (product, values) => {
143
161
  const nextNum = Number(values.quantity ?? product.num ?? 1) || 1;
144
162
  const metadataAny = product.metadata || {};
145
- const existedSource = metadataAny.source_product_price ?? product.selling_price ?? "0";
163
+ const existedSource = metadataAny.source_product_price ?? product.selling_price ?? '0';
146
164
  const nextOptions = product.product_option_item;
147
165
  const optionSum = sumOptionUnitPrice(nextOptions);
148
- const nextSourceSellingPrice = values.main_product_selling_price !== void 0 ? String(values.main_product_selling_price) : values.price !== void 0 ? String(values.price) : values.total !== void 0 ? toUnitPriceString(values.total, nextNum) : String(existedSource);
149
- const nextSourceOriginalPrice = values.original_price !== void 0 ? String(values.original_price) : String(existedSource);
150
- const nextMainSellingPrice = new import_decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
151
- const nextMainOriginalPrice = new import_decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
166
+
167
+ // Rules 返回的 main_product_selling_price / price / total 均为 source-level。
168
+ // 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
169
+ // total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
170
+ const nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
171
+
172
+ // 券前 source:values.original_price 是 source-level(Rules 层本就不含 option),
173
+ // 缺省时保留现有 source(券前 = 当前 source)。
174
+ const nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
175
+
176
+ // 含 option 的 main_product_*
177
+ const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
178
+ const nextMainOriginalPrice = new _decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
152
179
  const nextBundle = values.bundle ?? product.product_bundle;
153
180
  const composedSellingPrice = composeLinePrice({
154
181
  mainPrice: nextMainSellingPrice,
@@ -177,47 +204,73 @@ function createDefaultOrderRulesHooks() {
177
204
  }
178
205
  };
179
206
  }
180
- var generateDuration = (cartItem) => {
181
- const startDate = (0, import_dayjs.default)(`${cartItem.start_date} ${cartItem.start_time}`);
182
- const endDate = (0, import_dayjs.default)(`${cartItem.end_date} ${cartItem.end_time}`);
183
- const duration = endDate.diff(startDate, "minutes");
184
- return { duration, durationType: "minutes" };
207
+
208
+ /**
209
+ * 通过 session 类商品的开始时间结束时间生成商品的时长
210
+ * @param {CartItem} cartItem
211
+ * @return {*}
212
+ */
213
+ const generateDuration = cartItem => {
214
+ const startDate = (0, _dayjs.default)(`${cartItem.start_date} ${cartItem.start_time}`);
215
+ const endDate = (0, _dayjs.default)(`${cartItem.end_date} ${cartItem.end_time}`);
216
+ const duration = endDate.diff(startDate, 'minutes');
217
+ return {
218
+ duration,
219
+ durationType: 'minutes'
220
+ };
185
221
  };
186
- var mergeRelationForms = (relationForms) => {
187
- return Object.values(
188
- relationForms.reduce((acc, cur) => {
189
- const { form_id, form_record_ids } = cur;
190
- if (!acc[form_id]) {
191
- acc[form_id] = { form_id, form_record_ids: [] };
192
- }
193
- const ids = Array.isArray(form_record_ids) ? form_record_ids : [form_record_ids];
194
- const validIds = ids.filter((id) => id != null);
195
- acc[form_id].form_record_ids.push(...validIds);
196
- acc[form_id].form_record_ids = [...new Set(acc[form_id].form_record_ids)];
197
- return acc;
198
- }, {})
199
- ).filter((item) => item.form_record_ids.length > 0);
222
+
223
+ /**
224
+ * 合并关联表单
225
+ * @param relationForms 关联表单
226
+ * @returns 合并后的关联表单
227
+ */
228
+ exports.generateDuration = generateDuration;
229
+ const mergeRelationForms = relationForms => {
230
+ return Object.values(relationForms.reduce((acc, cur) => {
231
+ const {
232
+ form_id,
233
+ form_record_ids
234
+ } = cur;
235
+ // 如果 acc 中没有 form_id,则初始化一个空数组
236
+ if (!acc[form_id]) {
237
+ acc[form_id] = {
238
+ form_id,
239
+ form_record_ids: []
240
+ };
241
+ }
242
+
243
+ // 兼容 form_record_id 可能是数组或单个数字
244
+ const ids = Array.isArray(form_record_ids) ? form_record_ids : [form_record_ids];
245
+ // 过滤掉空值(null、undefined等)
246
+ const validIds = ids.filter(id => id != null);
247
+ acc[form_id].form_record_ids.push(...validIds);
248
+ // 去重
249
+ acc[form_id].form_record_ids = [...new Set(acc[form_id].form_record_ids)];
250
+ return acc;
251
+ }, {})).filter(item => item.form_record_ids.length > 0); // 过滤掉没有有效记录的表单
200
252
  };
253
+ exports.mergeRelationForms = mergeRelationForms;
201
254
  function getCustomerIdFromStorage(window) {
202
- var _a;
203
255
  try {
204
- const customer = JSON.parse(((_a = window == null ? void 0 : window.getLocalStorage) == null ? void 0 : _a.call(window, "customer")) || "{}");
205
- const customerId = Number(customer == null ? void 0 : customer.id);
206
- return Number.isFinite(customerId) && customerId > 0 ? customerId : void 0;
256
+ const customer = JSON.parse(window?.getLocalStorage?.('customer') || '{}');
257
+ const customerId = Number(customer?.id);
258
+ return Number.isFinite(customerId) && customerId > 0 ? customerId : undefined;
207
259
  } catch {
208
- return void 0;
260
+ return undefined;
209
261
  }
210
262
  }
263
+
264
+ /**
265
+ * 为购物车行补齐订单所需的 holder 信息(与 cartAccount 结构保持一致)
266
+ */
211
267
  function ensureCartItemOriginHolder(cartItem, window) {
212
- var _a;
213
- if ((_a = cartItem == null ? void 0 : cartItem._origin) == null ? void 0 : _a.holder) {
268
+ if (cartItem?._origin?.holder) {
214
269
  return;
215
270
  }
216
- const holderConfig = (0, import_utils.getProductHolderConfig)(
217
- (cartItem == null ? void 0 : cartItem._productInit) ?? (cartItem == null ? void 0 : cartItem._productOrigin)
218
- );
219
- const formRecordId = cartItem == null ? void 0 : cartItem.holder_id;
220
- if (!(holderConfig == null ? void 0 : holderConfig.resource_id) || formRecordId == null) {
271
+ const holderConfig = (0, _utils.getProductHolderConfig)(cartItem?._productInit ?? cartItem?._productOrigin);
272
+ const formRecordId = cartItem?.holder_id;
273
+ if (!holderConfig?.resource_id || formRecordId == null) {
221
274
  return;
222
275
  }
223
276
  cartItem._origin.holder = {
@@ -226,32 +279,33 @@ function ensureCartItemOriginHolder(cartItem, window) {
226
279
  form_record: [formRecordId]
227
280
  };
228
281
  }
229
- var getAllDiscountList = (cartItem) => {
230
- var _a, _b, _c, _d;
231
- let discountList = ((_b = (_a = cartItem == null ? void 0 : cartItem._origin) == null ? void 0 : _a.product) == null ? void 0 : _b.discount_list) || [];
232
- (((_d = (_c = cartItem == null ? void 0 : cartItem._origin) == null ? void 0 : _c.product) == null ? void 0 : _d.product_bundle) || []).forEach((item) => {
233
- discountList = [...discountList, ...(item == null ? void 0 : item.discount_list) || []];
234
- item.discount_list = void 0;
282
+ ;
283
+ const getAllDiscountList = cartItem => {
284
+ let discountList = cartItem?._origin?.product?.discount_list || [];
285
+ (cartItem?._origin?.product?.product_bundle || []).forEach(item => {
286
+ discountList = [...discountList, ...(item?.discount_list || [])];
287
+ item.discount_list = undefined;
235
288
  });
236
289
  return discountList;
237
290
  };
291
+
292
+ // ─── 以下为从 ScanOrder/utils.ts 迁入的 Order 专属工具函数 ───
293
+ exports.getAllDiscountList = getAllDiscountList;
238
294
  function createUuidV4() {
239
- const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
240
- return template.replace(/[xy]/g, (char) => {
295
+ const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
296
+ return template.replace(/[xy]/g, char => {
241
297
  const randomValue = Math.floor(Math.random() * 16);
242
- const value = char === "x" ? randomValue : randomValue & 3 | 8;
298
+ const value = char === 'x' ? randomValue : randomValue & 0x3 | 0x8;
243
299
  return value.toString(16);
244
300
  });
245
301
  }
246
302
  function isTempOrder(data) {
247
- if (!data || typeof data !== "object")
248
- return false;
249
- if (!Array.isArray(data.products))
250
- return false;
303
+ if (!data || typeof data !== 'object') return false;
304
+ if (!Array.isArray(data.products)) return false;
251
305
  return true;
252
306
  }
253
307
  function formatDateTime(date) {
254
- const pad = (value) => value.toString().padStart(2, "0");
308
+ const pad = value => value.toString().padStart(2, '0');
255
309
  const year = date.getFullYear();
256
310
  const month = pad(date.getMonth() + 1);
257
311
  const day = pad(date.getDate());
@@ -261,42 +315,51 @@ function formatDateTime(date) {
261
315
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
262
316
  }
263
317
  function normalizeSubmitPlatform(platform) {
264
- return (platform == null ? void 0 : platform.toLowerCase()) === "pc" ? "PC" : "H5";
318
+ return platform?.toLowerCase() === 'pc' ? 'PC' : 'H5';
265
319
  }
320
+
321
+ // 出站重命名:后端 checkout 协议字段 option_group_item_id;
322
+ // tempOrder / UI 运行时一律使用 product_option_item_id。仅保留后端契约字段,
323
+ // 与 src/modules/Cart/utils/cartProduct.ts#formatOptionsToOrigin 形状一致。
266
324
  function formatSubmitOptionItems(options) {
267
- if (!Array.isArray(options))
268
- return [];
269
- return options.map((d) => ({
270
- num: d == null ? void 0 : d.num,
271
- option_group_item_id: (d == null ? void 0 : d.option_group_item_id) ?? (d == null ? void 0 : d.product_option_item_id),
272
- option_group_id: d == null ? void 0 : d.option_group_id
325
+ if (!Array.isArray(options)) return [];
326
+ return options.map(d => ({
327
+ num: d?.num,
328
+ option_group_item_id: d?.option_group_item_id ?? d?.product_option_item_id,
329
+ option_group_id: d?.option_group_id
273
330
  }));
274
331
  }
275
332
  function toBundleNumber(value, fallback = 0) {
276
333
  const parsed = Number(value);
277
334
  return Number.isFinite(parsed) ? parsed : fallback;
278
335
  }
336
+ function toBundleCustomPriceString(value) {
337
+ const parsed = Number(value);
338
+ if (Number.isFinite(parsed)) return parsed.toFixed(2);
339
+ if (value === null || value === undefined || value === '') return '0.00';
340
+ return String(value);
341
+ }
342
+
343
+ // 出站补齐:以 additive 方式把 bundle 项补足为后端 checkout 协议所需的形状,
344
+ // 同时把 Summary / Rules 运行时写到 bundle 顶层的 surcharge_fee / relation_surcharge_ids
345
+ // 和来自 _origin 的 product_discount_difference 汇总到 metadata。
346
+ // 保留原对象上已有字段(如 discount_list、metadata.custom_product_bundle_map_id)
347
+ // 以兼容运行时 bundle 归一化、Rules、Summary 的消费。
279
348
  function formatSubmitBundleItems(bundle) {
280
- if (!Array.isArray(bundle))
281
- return [];
282
- return bundle.map((b) => {
283
- const rawBundle = b && typeof b === "object" ? b : {};
284
- const existedMetadata = rawBundle.metadata && typeof rawBundle.metadata === "object" ? rawBundle.metadata : {};
285
- const sellingPriceNum = toBundleNumber(
286
- rawBundle.bundle_selling_price ?? rawBundle.price,
287
- 0
288
- );
349
+ if (!Array.isArray(bundle)) return [];
350
+ return bundle.map(b => {
351
+ const rawBundle = b && typeof b === 'object' ? b : {};
352
+ const existedMetadata = rawBundle.metadata && typeof rawBundle.metadata === 'object' ? rawBundle.metadata : {};
353
+ const sellingPriceNum = toBundleNumber(rawBundle.bundle_selling_price ?? rawBundle.price, 0);
289
354
  const priceNum = toBundleNumber(rawBundle.price, sellingPriceNum);
290
- const priceType = rawBundle.price_type ?? "";
355
+ const priceType = rawBundle.price_type ?? '';
356
+ // const customPriceStr = toBundleCustomPriceString(
357
+ // rawBundle.custom_price ?? rawBundle.bundle_selling_price ?? rawBundle.price,
358
+ // );
359
+
291
360
  const relationSurchargeIds = Array.isArray(rawBundle.relation_surcharge_ids) ? rawBundle.relation_surcharge_ids : Array.isArray(existedMetadata.relation_surcharge_ids) ? existedMetadata.relation_surcharge_ids : [];
292
- const surchargeFee = toBundleNumber(
293
- rawBundle.surcharge_fee ?? existedMetadata.surcharge_fee,
294
- 0
295
- );
296
- const productDiscountDifference = toBundleNumber(
297
- existedMetadata.product_discount_difference,
298
- 0
299
- );
361
+ const surchargeFee = toBundleNumber(rawBundle.surcharge_fee ?? existedMetadata.surcharge_fee, 0);
362
+ const productDiscountDifference = toBundleNumber(existedMetadata.product_discount_difference, 0);
300
363
  return {
301
364
  ...rawBundle,
302
365
  is_charge_tax: rawBundle.is_charge_tax ?? 0,
@@ -304,16 +367,16 @@ function formatSubmitBundleItems(bundle) {
304
367
  bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
305
368
  num: toBundleNumber(rawBundle.num, 1),
306
369
  extension_id: rawBundle.extension_id ?? 0,
307
- extension_type: rawBundle.extension_type ?? "normal",
370
+ extension_type: rawBundle.extension_type ?? 'normal',
308
371
  price: priceNum,
309
372
  price_type: priceType,
310
- price_type_ext: rawBundle.price_type_ext ?? "",
373
+ price_type_ext: rawBundle.price_type_ext ?? '',
311
374
  // custom_price: customPriceStr,
312
- custom_price_type: rawBundle.custom_price_type ?? priceType ?? "",
375
+ custom_price_type: rawBundle.custom_price_type ?? priceType ?? '',
313
376
  bundle_selling_price: sellingPriceNum,
314
377
  option: formatSubmitOptionItems(rawBundle.option),
315
- bundle_group_id: rawBundle == null ? void 0 : rawBundle.group_id,
316
- bundle_id: rawBundle == null ? void 0 : rawBundle.id,
378
+ bundle_group_id: rawBundle?.group_id,
379
+ bundle_id: rawBundle?.id,
317
380
  metadata: {
318
381
  ...existedMetadata,
319
382
  surcharge_fee: surchargeFee,
@@ -323,34 +386,52 @@ function formatSubmitBundleItems(bundle) {
323
386
  };
324
387
  });
325
388
  }
389
+
390
+ /**
391
+ * 把 tempOrder product 打包成出站 submit payload。
392
+ *
393
+ * 价格字段语义(出站口径,v2 composite):
394
+ * - `selling_price`:**行 composite 券后单价**
395
+ * = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
396
+ * - `original_price`:**行 composite 券前单价**
397
+ * = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
398
+ * - `payment_price`:兼容后端的出站字段,直接从 `selling_price` 派生(composite)。
399
+ * - `metadata.source_product_price`:主商品/variant 基础价(不含 option、不含折扣),权威源。
400
+ * - `metadata.main_product_original_price`:含 option、不含折扣。
401
+ * - `metadata.main_product_selling_price`:含 option、含主商品折扣。
402
+ * - `metadata.price_schema_version`:schema 版本号(当前 = 2),用于跨端协商价格口径。
403
+ *
404
+ * 本函数不再改造价格字段形状,仅做字段/metadata 裁剪。
405
+ */
326
406
  function normalizeSubmitProduct(product) {
327
- const { _origin, identity_key, ...submitProduct } = product;
407
+ const {
408
+ _origin,
409
+ identity_key,
410
+ ...submitProduct
411
+ } = product;
328
412
  const rawMetadata = submitProduct.metadata || {};
329
413
  const bookingUid = rawMetadata.booking_uid;
330
414
  const cleanMetadata = {};
331
415
  if (rawMetadata.unique_identification_number) {
332
416
  cleanMetadata.unique_identification_number = rawMetadata.unique_identification_number;
333
417
  }
334
- const priceMetaKeys = [
335
- "main_product_original_price",
336
- "main_product_selling_price",
337
- "source_product_price",
338
- "price_schema_version"
339
- ];
418
+ const priceMetaKeys = ['main_product_original_price', 'main_product_selling_price', 'source_product_price', 'price_schema_version'];
340
419
  for (const key of priceMetaKeys) {
341
- if (rawMetadata[key] !== void 0) {
420
+ if (rawMetadata[key] !== undefined) {
342
421
  cleanMetadata[key] = rawMetadata[key];
343
422
  }
344
423
  }
345
424
  if (rawMetadata.price_breakdown) {
346
425
  cleanMetadata.price_breakdown = rawMetadata.price_breakdown;
347
426
  }
348
- if (rawMetadata.is_rule !== void 0) {
427
+ if (rawMetadata.is_rule !== undefined) {
349
428
  cleanMetadata.is_rule = rawMetadata.is_rule;
350
429
  }
351
430
  return {
352
431
  ...submitProduct,
353
- ...bookingUid ? { booking_uid: bookingUid } : {},
432
+ ...(bookingUid ? {
433
+ booking_uid: bookingUid
434
+ } : {}),
354
435
  product_option_item: formatSubmitOptionItems(submitProduct.product_option_item),
355
436
  discount_list: submitProduct.discount_list || [],
356
437
  product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
@@ -360,15 +441,12 @@ function normalizeSubmitProduct(product) {
360
441
  payment_price: submitProduct.selling_price
361
442
  };
362
443
  }
363
- var SUBMIT_BOOKING_METADATA_WHITELIST = [
364
- "unique_identification_number",
365
- "collect_pax"
366
- ];
444
+ const SUBMIT_BOOKING_METADATA_WHITELIST = ['unique_identification_number', 'collect_pax'];
367
445
  function normalizeSubmitBooking(booking) {
368
446
  const rawMetadata = booking.metadata || {};
369
447
  const cleanMetadata = {};
370
448
  for (const key of SUBMIT_BOOKING_METADATA_WHITELIST) {
371
- if (rawMetadata[key] !== void 0) {
449
+ if (rawMetadata[key] !== undefined) {
372
450
  cleanMetadata[key] = rawMetadata[key];
373
451
  }
374
452
  }
@@ -377,20 +455,10 @@ function normalizeSubmitBooking(booking) {
377
455
  metadata: cleanMetadata
378
456
  };
379
457
  }
380
- var DEFAULT_TABLE_OCCUPANCY_DURATION = 20;
458
+ const DEFAULT_TABLE_OCCUPANCY_DURATION = 20;
381
459
  function resolveTableOccupancyDuration(tempOrder) {
382
- var _a, _b, _c, _d;
383
460
  const metadata = tempOrder.metadata || {};
384
- const candidates = [
385
- metadata.table_occupancy_duration,
386
- metadata.booking_duration,
387
- metadata.table_duration,
388
- metadata.duration,
389
- (_a = metadata.table_config) == null ? void 0 : _a.occupancy_duration,
390
- (_b = metadata.tableConfig) == null ? void 0 : _b.occupancy_duration,
391
- (_c = metadata.resource_config) == null ? void 0 : _c.occupancy_duration,
392
- (_d = metadata.resourceConfig) == null ? void 0 : _d.occupancy_duration
393
- ];
461
+ const candidates = [metadata.table_occupancy_duration, metadata.booking_duration, metadata.table_duration, metadata.duration, metadata.table_config?.occupancy_duration, metadata.tableConfig?.occupancy_duration, metadata.resource_config?.occupancy_duration, metadata.resourceConfig?.occupancy_duration];
394
462
  for (const value of candidates) {
395
463
  const duration = Number(value);
396
464
  if (Number.isFinite(duration) && duration > 0) {
@@ -399,47 +467,50 @@ function resolveTableOccupancyDuration(tempOrder) {
399
467
  }
400
468
  return DEFAULT_TABLE_OCCUPANCY_DURATION;
401
469
  }
470
+
471
+ /** 提交用人数:有限且为正则向下取整,否则为 1 */
402
472
  function normalizeSubmitCollectPaxValue(value) {
403
473
  const n = Number(value);
404
474
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1;
405
475
  }
476
+
477
+ /** 从临时订单 metadata 解析合成 booking 的 collect_pax */
406
478
  function resolveSubmitCollectPax(tempOrder) {
407
- var _a;
408
- return normalizeSubmitCollectPaxValue((_a = tempOrder.metadata) == null ? void 0 : _a.collect_pax);
479
+ return normalizeSubmitCollectPaxValue(tempOrder.metadata?.collect_pax);
409
480
  }
410
481
  function createDefaultTempOrder(params) {
411
- const summary = params.summary || (0, import_utils2.createEmptySummary)();
482
+ const summary = params.summary || (0, _utils2.createEmptySummary)();
412
483
  return {
413
484
  order_id: null,
414
- relation_id: void 0,
415
- table_form_id: void 0,
416
- resource_id: void 0,
417
- order_number: "",
418
- shop_order_number: "",
419
- type: "appointment_booking",
420
- business_code: "appointment_booking",
421
- platform: "h5",
422
- sales_channel: "my_pisel",
423
- order_sales_channel: "online_store",
424
- status: "normal",
425
- payment_status: "payment_processing",
426
- shipping_status: "unfulfilled",
485
+ relation_id: undefined,
486
+ table_form_id: undefined,
487
+ resource_id: undefined,
488
+ order_number: '',
489
+ shop_order_number: '',
490
+ type: 'appointment_booking',
491
+ business_code: 'appointment_booking',
492
+ platform: 'h5',
493
+ sales_channel: 'my_pisel',
494
+ order_sales_channel: 'online_store',
495
+ status: 'normal',
496
+ payment_status: 'payment_processing',
497
+ shipping_status: 'unfulfilled',
427
498
  customer_id: null,
428
- customer_name: "",
429
- country_calling_code: "",
430
- phone: "",
431
- email: "",
499
+ customer_name: '',
500
+ country_calling_code: '',
501
+ phone: '',
502
+ email: '',
432
503
  is_price_include_tax: 1,
433
- tax_title: "",
434
- tax_country_code: "",
435
- currency_code: "",
436
- currency_symbol: "",
437
- currency_format: "symbol_first",
504
+ tax_title: '',
505
+ tax_country_code: '',
506
+ currency_code: '',
507
+ currency_symbol: '',
508
+ currency_format: 'symbol_first',
438
509
  is_deposit: 0,
439
- deposit_amount: "0.00",
440
- shop_discount: "0.00",
441
- surcharge_fee: "0.00",
442
- note: "",
510
+ deposit_amount: '0.00',
511
+ shop_discount: '0.00',
512
+ surcharge_fee: '0.00',
513
+ note: '',
443
514
  schedule_date: params.now,
444
515
  created_at: params.now,
445
516
  products: [],
@@ -459,7 +530,7 @@ function buildSubmitPayload(params) {
459
530
  const {
460
531
  tempOrder,
461
532
  cacheId,
462
- now = /* @__PURE__ */ new Date(),
533
+ now = new Date(),
463
534
  platform,
464
535
  businessCode,
465
536
  channel,
@@ -467,57 +538,62 @@ function buildSubmitPayload(params) {
467
538
  enhance
468
539
  } = params;
469
540
  const scheduleDate = tempOrder.schedule_date || tempOrder.created_at || formatDateTime(now);
470
- const summary = tempOrder.summary || (0, import_utils2.createEmptySummary)();
541
+ const summary = tempOrder.summary || (0, _utils2.createEmptySummary)();
471
542
  const relationId = tempOrder.relation_id;
472
543
  const tableFormId = tempOrder.table_form_id;
473
544
  const bookingUuid = createUuidV4();
474
- const bookingStart = (0, import_dayjs.default)(now);
545
+ const bookingStart = (0, _dayjs.default)(now);
475
546
  const bookingDuration = resolveTableOccupancyDuration(tempOrder);
476
- const bookingEnd = bookingStart.add(bookingDuration, "minute");
547
+ const bookingEnd = bookingStart.add(bookingDuration, 'minute');
477
548
  const bookings = relationId && tableFormId ? [{
478
549
  relation_id: 0,
479
550
  form_id: 0,
480
- start_time: bookingStart.format("HH:mm"),
481
- start_date: bookingStart.format("YYYY-MM-DD"),
482
- end_time: bookingEnd.format("HH:mm"),
483
- end_date: bookingEnd.format("YYYY-MM-DD"),
551
+ start_time: bookingStart.format('HH:mm'),
552
+ start_date: bookingStart.format('YYYY-MM-DD'),
553
+ end_time: bookingEnd.format('HH:mm'),
554
+ end_date: bookingEnd.format('YYYY-MM-DD'),
484
555
  duration: bookingDuration,
485
556
  metadata: {
486
557
  unique_identification_number: bookingUuid,
487
558
  collect_pax: resolveSubmitCollectPax(tempOrder)
488
559
  },
489
- select_date: bookingStart.format("YYYY-MM-DD"),
560
+ select_date: bookingStart.format('YYYY-MM-DD'),
490
561
  is_all: false,
491
- like_status: "common",
562
+ like_status: 'common',
492
563
  schedule_id: 0,
493
- relation_type: "",
564
+ relation_type: '',
494
565
  number: 1
495
566
  }] : tempOrder.bookings || [];
496
567
  const formRecordIds = relationId && tableFormId ? [{
497
568
  form_id: tableFormId,
498
569
  form_record_id: relationId
499
- }] : void 0;
500
- const { created_at: _createdAt, summary: _summary, surcharges: _surcharges, ...tempOrderRest } = tempOrder;
570
+ }] : undefined;
571
+ const {
572
+ created_at: _createdAt,
573
+ summary: _summary,
574
+ surcharges: _surcharges,
575
+ ...tempOrderRest
576
+ } = tempOrder;
501
577
  const payload = {
502
578
  ...tempOrderRest,
503
579
  platform: normalizeSubmitPlatform(platform ?? tempOrder.platform),
504
580
  request_unique_idempotency_token: cacheId,
505
- type: type ?? tempOrder.type ?? "table-order",
506
- business_code: businessCode ?? tempOrder.business_code ?? "table-order",
507
- sales_channel: tempOrder.sales_channel || "my_pisel",
508
- order_sales_channel: channel ?? tempOrder.order_sales_channel ?? "online_store",
509
- status: tempOrder.status || "normal",
510
- payment_status: tempOrder.payment_status || "payment_processing",
581
+ type: type ?? tempOrder.type ?? 'table-order',
582
+ business_code: businessCode ?? tempOrder.business_code ?? 'table-order',
583
+ sales_channel: tempOrder.sales_channel || 'my_pisel',
584
+ order_sales_channel: channel ?? tempOrder.order_sales_channel ?? 'online_store',
585
+ status: tempOrder.status || 'normal',
586
+ payment_status: tempOrder.payment_status || 'payment_processing',
511
587
  // shipping_status: tempOrder.shipping_status || 'unfulfilled',
512
588
  is_price_include_tax: tempOrder.is_price_include_tax ?? 1,
513
- currency_format: tempOrder.currency_format || "symbol_first",
589
+ currency_format: tempOrder.currency_format || 'symbol_first',
514
590
  is_deposit: tempOrder.is_deposit ?? 0,
515
- deposit_amount: tempOrder.deposit_amount || "0.00",
516
- shop_discount: tempOrder.shop_discount || "0.00",
517
- surcharge_fee: summary.surcharge_fee || tempOrder.surcharge_fee || "0.00",
518
- note: tempOrder.note || "",
591
+ deposit_amount: tempOrder.deposit_amount || '0.00',
592
+ shop_discount: tempOrder.shop_discount || '0.00',
593
+ surcharge_fee: summary.surcharge_fee || tempOrder.surcharge_fee || '0.00',
594
+ note: tempOrder.note || '',
519
595
  schedule_date: scheduleDate,
520
- bookings: bookings.map((booking) => normalizeSubmitBooking(booking)),
596
+ bookings: bookings.map(booking => normalizeSubmitBooking(booking)),
521
597
  payments: tempOrder.payments || [],
522
598
  // discount_list: tempOrder.discount_list || [],
523
599
  relation_forms: tempOrder.relation_forms || [],
@@ -532,22 +608,33 @@ function buildSubmitPayload(params) {
532
608
  table_occupancy_duration: _tableOccupancyDuration,
533
609
  ...rest
534
610
  } = tempOrder.metadata || {};
535
- return { ...rest };
611
+ return {
612
+ ...rest
613
+ };
536
614
  })(),
537
- products: (tempOrder.products || []).map(
538
- (product) => normalizeSubmitProduct(product)
539
- )
615
+ products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product))
540
616
  };
541
- return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
617
+ return enhance ? enhance(payload, {
618
+ tempOrder,
619
+ bookingUuid,
620
+ now
621
+ }) : payload;
542
622
  }
623
+
624
+ /** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
543
625
  function filterProductsForScanOrderMore(products) {
544
- return (products || []).filter((p) => {
545
- var _a;
546
- return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
547
- });
626
+ return (products || []).filter(p => p.metadata?.is_rule !== true);
548
627
  }
628
+
629
+ /**
630
+ * 历史 V1 加餐结构映射器。
631
+ *
632
+ * @deprecated 加餐(`PUT /order/order/product/:id`)已改为与正常 checkout 共用
633
+ * `ScanOrderSubmitProduct` 新结构(见 `OrderModule.submitTempOrder` 的加餐分支)。
634
+ * 本函数仅保留以兼容历史接入方,未来会移除。新代码请勿再调用。
635
+ */
549
636
  function formatV1Product(products) {
550
- return products.map((product) => {
637
+ return products.map(product => {
551
638
  return {
552
639
  bundle: product.product_bundle,
553
640
  key: product.product_id,
@@ -555,31 +642,10 @@ function formatV1Product(products) {
555
642
  product_id: product.product_id,
556
643
  product_variant_id: product.product_variant_id,
557
644
  num: product.num,
558
- note: String(product.note ?? ""),
645
+ note: String(product.note ?? ''),
559
646
  rowKey: product.product_id,
560
647
  session: null,
561
648
  unique: createUuidV4()
562
649
  };
563
650
  });
564
- }
565
- // Annotate the CommonJS export names for ESM import in node:
566
- 0 && (module.exports = {
567
- buildSubmitPayload,
568
- composeLinePrice,
569
- createDefaultOrderRulesHooks,
570
- createDefaultTempOrder,
571
- createEmptySummary,
572
- createUuidV4,
573
- ensureCartItemOriginHolder,
574
- filterProductsForScanOrderMore,
575
- formatDateTime,
576
- formatV1Product,
577
- generateDuration,
578
- getAllDiscountList,
579
- isTempOrder,
580
- mergeRelationForms,
581
- normalizeSubmitBooking,
582
- normalizeSubmitCollectPaxValue,
583
- resolveSubmitCollectPax,
584
- sumOptionUnitPrice
585
- });
651
+ }