@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,88 +1,97 @@
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);
28
-
29
- // src/solution/ShopDiscount/utils.ts
30
- var utils_exports = {};
31
- __export(utils_exports, {
32
- calculateOrderLevelDiscountAllocation: () => calculateOrderLevelDiscountAllocation,
33
- filterDiscountListByBookingTime: () => filterDiscountListByBookingTime,
34
- getDateIsInSchedule: () => getDateIsInSchedule,
35
- getDiscountAmount: () => getDiscountAmount,
36
- getDiscountListAmount: () => getDiscountListAmount,
37
- getDiscountListAmountTotal: () => getDiscountListAmountTotal,
38
- isAllNormalProduct: () => isAllNormalProduct,
39
- isNormalProductByDurationSchedule: () => isNormalProductByDurationSchedule,
40
- isOrderLevelFixedAmountDiscount: () => isOrderLevelFixedAmountDiscount,
41
- uniqueById: () => uniqueById
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
42
5
  });
43
- module.exports = __toCommonJS(utils_exports);
44
- var import_decimal = __toESM(require("decimal.js"));
45
- var import_dayjs = __toESM(require("dayjs"));
46
- var uniqueById = (arr, key = "id") => {
47
- const seen = /* @__PURE__ */ new Set();
48
- return arr.filter((item) => !seen.has(item[key]) && seen.add(item[key]));
6
+ exports.uniqueById = exports.isOrderLevelFixedAmountDiscount = exports.isNormalProductByDurationSchedule = exports.isAllNormalProduct = exports.getDiscountListAmountTotal = exports.getDiscountListAmount = exports.getDiscountAmount = exports.getDateIsInSchedule = exports.filterDiscountListByBookingTime = exports.calculateOrderLevelDiscountAllocation = void 0;
7
+ var _decimal = _interopRequireDefault(require("decimal.js"));
8
+ var _dayjs = _interopRequireDefault(require("dayjs"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ const uniqueById = (arr, key = 'id') => {
11
+ const seen = new Set();
12
+ return arr.filter(item => !seen.has(item[key]) && seen.add(item[key]));
49
13
  };
50
- var isNormalProductByDurationSchedule = (item) => {
51
- var _a, _b;
52
- return !(item == null ? void 0 : item.duration) && !((_a = item == null ? void 0 : item.schedules) == null ? void 0 : _a.length) && !((_b = item == null ? void 0 : item["schedule.ids"]) == null ? void 0 : _b.length);
14
+
15
+ // 非预约商品 通过时长和日程判断是否是普通商品
16
+ exports.uniqueById = uniqueById;
17
+ const isNormalProductByDurationSchedule = item => {
18
+ return !item?.duration && !item?.schedules?.length && !item?.['schedule.ids']?.length;
53
19
  };
54
- var isAllNormalProduct = (items) => {
55
- return items.every((item) => isNormalProductByDurationSchedule(item));
20
+
21
+ // 是否全部是普通商品
22
+ exports.isNormalProductByDurationSchedule = isNormalProductByDurationSchedule;
23
+ const isAllNormalProduct = items => {
24
+ return items.every(item => isNormalProductByDurationSchedule(item));
56
25
  };
57
- var getDiscountAmount = (discount, total, price) => {
58
- var _a;
59
- if (discount.tag === "good_pass") {
60
- return new import_decimal.default(price).minus(new import_decimal.default(price || 0)).toNumber();
26
+
27
+ /**
28
+ * 获取折扣金额 基于折扣卡类型计算
29
+ * 商品券:直接返回商品价格
30
+ * 折扣卡:根据折扣卡类型计算 固定金额:直接返回折扣卡金额 百分比:根据折扣卡金额计算
31
+ * @param discount
32
+ * @param total
33
+ * @param price
34
+ * @returns
35
+ */
36
+ /**
37
+ * 获取折扣金额 基于折扣卡类型计算
38
+ * 商品券:直接返回商品价格
39
+ * 折扣卡:根据折扣卡类型计算 固定金额:直接返回折扣卡金额 百分比:根据折扣卡金额计算
40
+ * @param discount
41
+ * @param total
42
+ * @param price
43
+ * @returns
44
+ */
45
+ exports.isAllNormalProduct = isAllNormalProduct;
46
+ const getDiscountAmount = (discount, total, price) => {
47
+ // 商品券
48
+ if (discount.tag === 'good_pass') {
49
+ return new _decimal.default(price).minus(new _decimal.default(price || 0)).toNumber();
61
50
  }
62
- const isFixedAmount = ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.discount_card_type) === "fixed_amount";
51
+
52
+ // 判断是否是固定金额
53
+ const isFixedAmount = discount?.metadata?.discount_card_type === 'fixed_amount';
54
+
55
+ // 固定金额 小于0时返回0
63
56
  if (isFixedAmount) {
64
- return Math.max(new import_decimal.default(price).minus(new import_decimal.default((discount.amount ?? discount.par_value) || 0)).toNumber(), 0);
57
+ return Math.max(new _decimal.default(price).minus(new _decimal.default((discount.amount ?? discount.par_value) || 0)).toNumber(), 0);
65
58
  }
66
- return new import_decimal.default(100).minus(discount.par_value || 0).div(100).mul(new import_decimal.default(price)).toNumber();
59
+
60
+ // 百分比:根据折扣卡金额计算
61
+ return new _decimal.default(100).minus(discount.par_value || 0).div(100).mul(new _decimal.default(price)).toNumber();
67
62
  };
68
- var getDiscountListAmountTotal = (discount) => {
63
+ exports.getDiscountAmount = getDiscountAmount;
64
+ const getDiscountListAmountTotal = discount => {
69
65
  return discount.reduce((acc, cur) => {
70
- return new import_decimal.default(acc).plus(new import_decimal.default(cur.num || 1).mul(new import_decimal.default(cur.amount || 0))).toNumber();
71
- }, new import_decimal.default(0));
66
+ return new _decimal.default(acc).plus(new _decimal.default(cur.num || 1).mul(new _decimal.default(cur.amount || 0))).toNumber();
67
+ }, new _decimal.default(0));
72
68
  };
73
- var getDiscountListAmount = (discount) => {
69
+
70
+ /**
71
+ * 获取折扣金额 计算每个折扣的金额
72
+ * @param discount
73
+ * @returns
74
+ */
75
+ exports.getDiscountListAmountTotal = getDiscountListAmountTotal;
76
+ const getDiscountListAmount = discount => {
74
77
  return discount.reduce((acc, cur) => {
75
- return new import_decimal.default(acc).plus(new import_decimal.default(cur.amount || 0)).toNumber();
76
- }, new import_decimal.default(0));
78
+ return new _decimal.default(acc).plus(new _decimal.default(cur.amount || 0)).toNumber();
79
+ }, new _decimal.default(0));
77
80
  };
78
- var getDateIsInSchedule = (dateTime, scheduleList) => {
81
+
82
+ // 日程项接口定义
83
+ exports.getDiscountListAmount = getDiscountListAmount;
84
+ // 获取时间是否在日程范围内
85
+ const getDateIsInSchedule = (dateTime, scheduleList) => {
79
86
  if (!dateTime || !scheduleList || scheduleList.length === 0) {
80
87
  return false;
81
88
  }
82
- const targetDate = (0, import_dayjs.default)(dateTime);
89
+ const targetDate = (0, _dayjs.default)(dateTime);
83
90
  if (!targetDate.isValid()) {
84
91
  return false;
85
92
  }
93
+
94
+ // 遍历所有日程项
86
95
  for (const schedule of scheduleList) {
87
96
  if (isTimeInScheduleItem(dateTime, schedule)) {
88
97
  return true;
@@ -90,284 +99,422 @@ var getDateIsInSchedule = (dateTime, scheduleList) => {
90
99
  }
91
100
  return false;
92
101
  };
93
- var isTimeInScheduleItem = (dateTime, schedule) => {
94
- const targetDate = (0, import_dayjs.default)(dateTime);
95
- const targetDateString = dateTime.split(" ")[0];
96
- const targetTimeString = dateTime.split(" ")[1] || "00:00:00";
102
+
103
+ // 判断时间是否在单个日程项范围内
104
+ exports.getDateIsInSchedule = getDateIsInSchedule;
105
+ const isTimeInScheduleItem = (dateTime, schedule) => {
106
+ const targetDate = (0, _dayjs.default)(dateTime);
107
+ const targetDateString = dateTime.split(' ')[0]; // YYYY-MM-DD
108
+ const targetTimeString = dateTime.split(' ')[1] || '00:00:00'; // HH:mm:ss
109
+
97
110
  switch (schedule.type) {
98
- case "standard":
111
+ case 'standard':
99
112
  return isInStandardSchedule(targetDate, targetDateString, targetTimeString, schedule);
100
- case "time-slots":
113
+ case 'time-slots':
101
114
  return isInTimeSlotsSchedule(targetDate, targetDateString, targetTimeString, schedule);
102
- case "designation":
115
+ case 'designation':
103
116
  return isInDesignationSchedule(targetDate, targetDateString, targetTimeString, schedule);
104
117
  default:
105
118
  return false;
106
119
  }
107
120
  };
108
- var isInStandardSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
121
+
122
+ // 处理标准类型日程
123
+ const isInStandardSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
109
124
  if (!schedule.start_time || !schedule.end_time) {
110
125
  return false;
111
126
  }
112
- const startDate = (0, import_dayjs.default)(schedule.start_time);
113
- const endDate = (0, import_dayjs.default)(schedule.end_time);
127
+ const startDate = (0, _dayjs.default)(schedule.start_time);
128
+ const endDate = (0, _dayjs.default)(schedule.end_time);
129
+
130
+ // 先检查是否在基础时间范围内(不考虑重复)
114
131
  const isInBasicRange = targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate);
115
- if (schedule.repeat_type === "none") {
132
+ if (schedule.repeat_type === 'none') {
116
133
  return isInBasicRange;
117
134
  }
135
+
136
+ // 处理重复日程
118
137
  return isInRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule, startDate, endDate);
119
138
  };
120
- var isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
139
+
140
+ // 处理时间段类型日程
141
+ const isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
121
142
  if (!schedule.start_time) {
122
143
  return false;
123
144
  }
124
- if (schedule.repeat_type === "none") {
125
- const scheduleDate = schedule.start_time.split(" ")[0];
145
+
146
+ // 如果不重复,使用原有逻辑
147
+ if (schedule.repeat_type === 'none') {
148
+ const scheduleDate = schedule.start_time.split(' ')[0];
149
+
150
+ // 检查日期是否匹配
126
151
  if (targetDateString !== scheduleDate) {
127
152
  return false;
128
153
  }
154
+
155
+ // 检查是否在任一时间段内
129
156
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
130
157
  }
158
+
159
+ // 处理重复日程
131
160
  return isInTimeSlotsRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule);
132
161
  };
133
- var isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
162
+
163
+ // 处理指定类型日程
164
+ const isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
134
165
  if (!schedule.designation) {
135
166
  return false;
136
167
  }
137
168
  for (const designation of schedule.designation) {
138
169
  const startDateTime = `${designation.start_date} ${designation.start_time}:00`;
139
170
  const endDateTime = `${designation.end_date} ${designation.end_time}:00`;
140
- const startDate = (0, import_dayjs.default)(startDateTime);
141
- const endDate = (0, import_dayjs.default)(endDateTime);
171
+ const startDate = (0, _dayjs.default)(startDateTime);
172
+ const endDate = (0, _dayjs.default)(endDateTime);
142
173
  if (targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate)) {
143
174
  return true;
144
175
  }
145
176
  }
146
177
  return false;
147
178
  };
148
- var isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule, startDate, endDate) => {
179
+
180
+ // 处理重复日程逻辑
181
+ const isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule, startDate, endDate) => {
149
182
  if (!schedule.repeat_rule) {
150
183
  return false;
151
184
  }
152
- const { repeat_rule, repeat_type } = schedule;
153
- const targetDateOnly = (0, import_dayjs.default)(targetDateString);
185
+ const {
186
+ repeat_rule,
187
+ repeat_type
188
+ } = schedule;
189
+ const targetDateOnly = (0, _dayjs.default)(targetDateString); // 只取日期部分
190
+
191
+ // 首先检查是否在包含日期中(包含日期是额外增加的有效日期)
154
192
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
155
193
  for (const includedDate of repeat_rule.included_date) {
156
- const includeStartDate = (0, import_dayjs.default)(includedDate.start);
157
- const includeEndDate = (0, import_dayjs.default)(includedDate.end);
158
- if (targetDateOnly.isSameOrAfter(includeStartDate, "day") && targetDateOnly.isSameOrBefore(includeEndDate, "day")) {
194
+ const includeStartDate = (0, _dayjs.default)(includedDate.start);
195
+ const includeEndDate = (0, _dayjs.default)(includedDate.end);
196
+ if (targetDateOnly.isSameOrAfter(includeStartDate, 'day') && targetDateOnly.isSameOrBefore(includeEndDate, 'day')) {
197
+ // 在包含日期中,直接返回true,无需检查其他条件
159
198
  return true;
160
199
  }
161
200
  }
162
201
  }
202
+
203
+ // 检查是否在排除日期中
163
204
  for (const excludedDate of repeat_rule.excluded_date) {
164
- const excludeStartDate = (0, import_dayjs.default)(excludedDate.start);
165
- const excludeEndDate = (0, import_dayjs.default)(excludedDate.end);
166
- if (targetDateOnly.isSameOrAfter(excludeStartDate, "day") && targetDateOnly.isSameOrBefore(excludeEndDate, "day")) {
205
+ const excludeStartDate = (0, _dayjs.default)(excludedDate.start);
206
+ const excludeEndDate = (0, _dayjs.default)(excludedDate.end);
207
+ // 检查目标日期是否在排除范围内(包含边界)
208
+ if (targetDateOnly.isSameOrAfter(excludeStartDate, 'day') && targetDateOnly.isSameOrBefore(excludeEndDate, 'day')) {
167
209
  return false;
168
210
  }
169
211
  }
170
- if (repeat_rule.end.type === "date" && repeat_rule.end.end_date) {
171
- const ruleEndDate = (0, import_dayjs.default)(repeat_rule.end.end_date);
212
+
213
+ // 检查重复规则的结束条件
214
+ if (repeat_rule.end.type === 'date' && repeat_rule.end.end_date) {
215
+ const ruleEndDate = (0, _dayjs.default)(repeat_rule.end.end_date);
172
216
  if (targetDate.isAfter(ruleEndDate)) {
173
217
  return false;
174
218
  }
175
219
  }
220
+
221
+ // 根据重复类型检查
176
222
  switch (repeat_type) {
177
- case "daily":
223
+ case 'daily':
178
224
  return isInDailyRepeat(targetDate, startDate, endDate, repeat_rule);
179
- case "weekly":
225
+ case 'weekly':
180
226
  return isInWeeklyRepeat(targetDate, startDate, endDate, repeat_rule);
181
227
  default:
182
228
  return false;
229
+ // 不支持月和年重复
183
230
  }
184
231
  };
185
- var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
186
- const daysDiff = targetDate.diff(startDate, "day");
232
+
233
+ // 每日重复逻辑
234
+ const isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
235
+ const daysDiff = targetDate.diff(startDate, 'day');
187
236
  if (daysDiff < 0) {
188
237
  return false;
189
238
  }
239
+
240
+ // 检查频率
190
241
  if (daysDiff % repeatRule.frequency !== 0) {
191
242
  return false;
192
243
  }
244
+
245
+ // 检查时间是否在日程的时间范围内
193
246
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
194
247
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
195
248
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
249
+
250
+ // 每日重复:每天都在相同的时间段内有效
251
+ // 例如:01:00:00 - 16:00:00,每天都是这个时间段
196
252
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
197
253
  };
198
- var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
199
- const targetDayOfWeek = targetDate.day();
254
+
255
+ // 每周重复逻辑
256
+ const isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
257
+ const targetDayOfWeek = targetDate.day(); // 0=周日, 1=周一, ..., 6=周六
258
+
259
+ // 检查是否在指定的星期几内
200
260
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
201
261
  return false;
202
262
  }
203
- const weeksDiff = targetDate.diff(startDate, "week");
263
+
264
+ // 计算周差
265
+ const weeksDiff = targetDate.diff(startDate, 'week');
204
266
  if (weeksDiff < 0) {
205
267
  return false;
206
268
  }
269
+
270
+ // 检查频率
207
271
  if (weeksDiff % repeatRule.frequency !== 0) {
208
272
  return false;
209
273
  }
274
+
275
+ // 检查时间是否在日程的时间范围内
210
276
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
211
277
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
212
278
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
213
279
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
214
280
  };
215
- var isInTimeSlotsRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
281
+
282
+ // 处理 time-slots 类型的重复日程
283
+ const isInTimeSlotsRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
216
284
  if (!schedule.repeat_rule || !schedule.start_time) {
217
285
  return false;
218
286
  }
219
- const { repeat_rule, repeat_type } = schedule;
220
- const startDate = (0, import_dayjs.default)(schedule.start_time);
221
- const targetDateOnly = (0, import_dayjs.default)(targetDateString);
287
+ const {
288
+ repeat_rule,
289
+ repeat_type
290
+ } = schedule;
291
+ const startDate = (0, _dayjs.default)(schedule.start_time);
292
+ const targetDateOnly = (0, _dayjs.default)(targetDateString);
293
+
294
+ // 检查包含日期
222
295
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
223
296
  for (const includedDate of repeat_rule.included_date) {
224
- const includeStartDate = (0, import_dayjs.default)(includedDate.start);
225
- const includeEndDate = (0, import_dayjs.default)(includedDate.end);
226
- if (targetDateOnly.isSameOrAfter(includeStartDate, "day") && targetDateOnly.isSameOrBefore(includeEndDate, "day")) {
297
+ const includeStartDate = (0, _dayjs.default)(includedDate.start);
298
+ const includeEndDate = (0, _dayjs.default)(includedDate.end);
299
+ if (targetDateOnly.isSameOrAfter(includeStartDate, 'day') && targetDateOnly.isSameOrBefore(includeEndDate, 'day')) {
300
+ // 在包含日期中,检查时间段
227
301
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
228
302
  }
229
303
  }
230
304
  }
305
+
306
+ // 检查排除日期
231
307
  for (const excludedDate of repeat_rule.excluded_date) {
232
- const excludeStartDate = (0, import_dayjs.default)(excludedDate.start);
233
- const excludeEndDate = (0, import_dayjs.default)(excludedDate.end);
234
- if (targetDateOnly.isSameOrAfter(excludeStartDate, "day") && targetDateOnly.isSameOrBefore(excludeEndDate, "day")) {
308
+ const excludeStartDate = (0, _dayjs.default)(excludedDate.start);
309
+ const excludeEndDate = (0, _dayjs.default)(excludedDate.end);
310
+ if (targetDateOnly.isSameOrAfter(excludeStartDate, 'day') && targetDateOnly.isSameOrBefore(excludeEndDate, 'day')) {
235
311
  return false;
236
312
  }
237
313
  }
238
- if (repeat_rule.end.type === "date" && repeat_rule.end.end_date) {
239
- const ruleEndDate = (0, import_dayjs.default)(repeat_rule.end.end_date);
240
- if (targetDateOnly.isAfter(ruleEndDate, "day")) {
314
+
315
+ // 检查重复规则的结束条件
316
+ if (repeat_rule.end.type === 'date' && repeat_rule.end.end_date) {
317
+ const ruleEndDate = (0, _dayjs.default)(repeat_rule.end.end_date);
318
+ if (targetDateOnly.isAfter(ruleEndDate, 'day')) {
241
319
  return false;
242
320
  }
243
321
  }
322
+
323
+ // 检查目标日期是否在重复规则范围内
244
324
  let isDateValid = false;
245
325
  switch (repeat_type) {
246
- case "daily":
326
+ case 'daily':
247
327
  isDateValid = isInDailyRepeatForDate(targetDateOnly, startDate, repeat_rule);
248
328
  break;
249
- case "weekly":
329
+ case 'weekly':
250
330
  isDateValid = isInWeeklyRepeatForDate(targetDateOnly, startDate, repeat_rule);
251
331
  break;
252
332
  default:
253
333
  return false;
254
334
  }
335
+
336
+ // 如果日期有效,检查时间段
255
337
  if (isDateValid) {
256
338
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
257
339
  }
258
340
  return false;
259
341
  };
260
- var checkTimeSlotsForDate = (targetDate, targetDateString, timeSlots) => {
342
+
343
+ // 检查目标时间是否在某个时间段内(使用目标日期 + time_slot 时间)
344
+ const checkTimeSlotsForDate = (targetDate, targetDateString, timeSlots) => {
261
345
  for (const timeSlot of timeSlots) {
262
346
  const slotStart = `${targetDateString} ${timeSlot.start_time}:00`;
263
347
  const slotEnd = `${targetDateString} ${timeSlot.end_time}:00`;
264
- const slotStartDate = (0, import_dayjs.default)(slotStart);
265
- const slotEndDate = (0, import_dayjs.default)(slotEnd);
348
+ const slotStartDate = (0, _dayjs.default)(slotStart);
349
+ const slotEndDate = (0, _dayjs.default)(slotEnd);
266
350
  if (targetDate.isSameOrAfter(slotStartDate) && targetDate.isSameOrBefore(slotEndDate)) {
267
351
  return true;
268
352
  }
269
353
  }
270
354
  return false;
271
355
  };
272
- var isInDailyRepeatForDate = (targetDate, startDate, repeatRule) => {
273
- const daysDiff = targetDate.diff(startDate, "day");
356
+
357
+ // 检查日期是否满足每日重复规则(只检查日期,不检查时间)
358
+ const isInDailyRepeatForDate = (targetDate, startDate, repeatRule) => {
359
+ const daysDiff = targetDate.diff(startDate, 'day');
274
360
  if (daysDiff < 0) {
275
361
  return false;
276
362
  }
363
+
364
+ // 检查频率
277
365
  return daysDiff % repeatRule.frequency === 0;
278
366
  };
279
- var isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
280
- const targetDayOfWeek = targetDate.day();
367
+
368
+ // 检查日期是否满足每周重复规则(只检查日期,不检查时间)
369
+ const isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
370
+ const targetDayOfWeek = targetDate.day(); // 0=周日, 1=周一, ..., 6=周六
371
+
372
+ // 检查是否在指定的星期几内
281
373
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
282
374
  return false;
283
375
  }
284
- const weeksDiff = targetDate.diff(startDate, "week");
376
+
377
+ // 计算周差
378
+ const weeksDiff = targetDate.diff(startDate, 'week');
285
379
  if (weeksDiff < 0) {
286
380
  return false;
287
381
  }
382
+
383
+ // 检查频率
288
384
  return weeksDiff % repeatRule.frequency === 0;
289
385
  };
290
- var filterDiscountListByBookingTime = (discountList, bookingTime) => {
386
+
387
+ /**
388
+ * 根据预约时间过滤优惠券列表
389
+ * @param discountList 优惠券列表
390
+ * @param bookingTime 预约时间 (格式: YYYY-MM-DD HH:mm:ss)
391
+ * @returns 过滤后的优惠券列表
392
+ */
393
+ const filterDiscountListByBookingTime = (discountList, bookingTime) => {
291
394
  if (!bookingTime) {
292
395
  return discountList;
293
396
  }
294
- return discountList.filter((discount) => {
295
- var _a, _b;
296
- if (((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.validity_type) === "custom_schedule_validity") {
297
- return getDateIsInSchedule(bookingTime, ((_b = discount.custom_schedule_snapshot) == null ? void 0 : _b.data) || []);
397
+ return discountList.filter(discount => {
398
+ if (discount?.metadata?.validity_type === "custom_schedule_validity") {
399
+ return getDateIsInSchedule(bookingTime, discount.custom_schedule_snapshot?.data || []);
298
400
  }
299
401
  try {
300
402
  const isHasStart = !!discount.start_date && !!discount.start_time;
301
- const startDate = (0, import_dayjs.default)(`${discount.start_date} ${discount.start_time}`);
302
- const bookingTimeDayjs = (0, import_dayjs.default)(bookingTime);
403
+ const startDate = (0, _dayjs.default)(`${discount.start_date} ${discount.start_time}`);
404
+ const bookingTimeDayjs = (0, _dayjs.default)(bookingTime);
405
+
406
+ // 判断预约时间是否在开始时间之后
303
407
  const isAfterStart = isHasStart ? bookingTimeDayjs.isSameOrAfter(startDate) : true;
304
- const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, import_dayjs.default)(discount.expire_time)) : true;
408
+
409
+ // 判断预约时间是否在过期时间之前(expire_time 为空时为长期有效)
410
+ const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, _dayjs.default)(discount.expire_time)) : true;
305
411
  return isAfterStart && isBeforeExpire;
306
412
  } catch (error) {
307
413
  return true;
308
414
  }
309
415
  });
310
416
  };
311
- var isOrderLevelFixedAmountDiscount = (discount) => {
312
- var _a, _b;
313
- return discount.tag === "product_discount_card" && ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.discount_card_type) === "fixed_amount" && ((_b = discount == null ? void 0 : discount.metadata) == null ? void 0 : _b.discount_calculation_mode) === "order_level";
417
+ /**
418
+ * 判断是否是订单级别的固定金额折扣卡
419
+ * @param discount 折扣
420
+ * @returns 是否是订单级别的固定金额折扣卡
421
+ */
422
+ exports.filterDiscountListByBookingTime = filterDiscountListByBookingTime;
423
+ const isOrderLevelFixedAmountDiscount = discount => {
424
+ return discount.tag === 'product_discount_card' && discount?.metadata?.discount_card_type === 'fixed_amount' && discount?.metadata?.discount_calculation_mode === 'order_level';
314
425
  };
315
- var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
316
- const result = /* @__PURE__ */ new Map();
426
+
427
+ /**
428
+ * 计算订单级别固定金额折扣卡的分摊结果
429
+ * @param discount 折扣卡
430
+ * @param applicableProducts 适用商品列表 { productId, amount, quantity, parentQuantity }
431
+ * @returns 分摊结果 Map<productId, { discountAmount, difference }>
432
+ * 注意:
433
+ * - discountAmount 是单价折扣金额(不是总折扣金额)
434
+ * - difference(总差值)优先直接加到数量为1的单商品折扣上,如果没有则存储在metadata中
435
+ */
436
+ exports.isOrderLevelFixedAmountDiscount = isOrderLevelFixedAmountDiscount;
437
+ const calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
438
+ const result = new Map();
317
439
  if (applicableProducts.length === 0) {
318
440
  return result;
319
441
  }
442
+
443
+ // 计算适用商品的总金额(数量 × 单价)
320
444
  const totalAmount = applicableProducts.reduce((acc, product) => {
321
- return new import_decimal.default(acc).plus(new import_decimal.default(product.amount).mul(product.quantity)).toNumber();
445
+ return new _decimal.default(acc).plus(new _decimal.default(product.amount).mul(product.quantity)).toNumber();
322
446
  }, 0);
323
447
  if (totalAmount <= 0) {
324
448
  return result;
325
449
  }
326
- const fixedAmount = new import_decimal.default(discount.par_value || 0).toNumber();
450
+
451
+ // 固定减免金额
452
+ const fixedAmount = new _decimal.default(discount.par_value || 0).toNumber();
453
+
454
+ // 如果固定金额 >= 商品总金额,折扣最高为商品金额(免费)
327
455
  const actualDiscountTotal = Math.min(fixedAmount, totalAmount);
328
- let allocatedTotal = new import_decimal.default(0);
329
- applicableProducts.forEach((product) => {
330
- const rawDiscountPerItem = new import_decimal.default(product.amount).div(totalAmount).mul(actualDiscountTotal);
331
- const discountAmountPerItem = rawDiscountPerItem.toDecimalPlaces(2, import_decimal.default.ROUND_DOWN).toNumber();
456
+
457
+ // 计算每个商品的单价折扣金额
458
+ let allocatedTotal = new _decimal.default(0);
459
+ applicableProducts.forEach(product => {
460
+ // 🔥 分摊公式改为:(单价 / 适用商品总金额) × 固定金额
461
+ // 这样只有一次取整,避免精度损失
462
+ const rawDiscountPerItem = new _decimal.default(product.amount).div(totalAmount).mul(actualDiscountTotal);
463
+
464
+ // 保留两位小数,向下取整(单价折扣)
465
+ const discountAmountPerItem = rawDiscountPerItem.toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
332
466
  result.set(product.productId, {
333
467
  discountAmount: discountAmountPerItem,
334
468
  // 单价折扣金额
335
- difference: 0
336
- // 默认差值为0
469
+ difference: 0 // 默认差值为0
337
470
  });
338
- allocatedTotal = allocatedTotal.plus(
339
- new import_decimal.default(discountAmountPerItem).mul(product.quantity)
340
- );
471
+
472
+ // 累加实际分配的总折扣金额(单价折扣 × 数量)
473
+ allocatedTotal = allocatedTotal.plus(new _decimal.default(discountAmountPerItem).mul(product.quantity));
341
474
  });
342
- const totalDifference = new import_decimal.default(actualDiscountTotal).minus(allocatedTotal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
475
+
476
+ // 🔥 计算总差值
477
+ // 总差值 = 固定金额 - 所有商品的 (单价折扣 × 数量) 之和
478
+ const totalDifference = new _decimal.default(actualDiscountTotal).minus(allocatedTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
343
479
  if (totalDifference > 0) {
344
- const isSingleQuantity = (product) => {
345
- if (product.parentQuantity !== void 0) {
480
+ // 🔥 判断商品是否是真正的"数量为1"
481
+ // 主商品:quantity === 1
482
+ // 子商品:quantity === 1 且 parentQuantity === 1
483
+ const isSingleQuantity = product => {
484
+ if (product.parentQuantity !== undefined) {
485
+ // 子商品:需要同时满足自身数量为1且主商品数量为1
346
486
  return product.quantity === 1 && product.parentQuantity === 1;
347
487
  }
488
+ // 主商品:只需要自身数量为1
348
489
  return product.quantity === 1;
349
490
  };
491
+
492
+ // 🔥 筛选出数量为1的商品
350
493
  const singleQuantityProducts = applicableProducts.filter(isSingleQuantity);
351
494
  if (singleQuantityProducts.length > 0) {
352
- const productsWithEnoughSpace = singleQuantityProducts.filter((product) => {
495
+ // 🔥 优先级1:找到有足够剩余空间且金额最大的商品
496
+ // 剩余空间 = 商品价格 - 当前折扣金额 >= 差值
497
+ const productsWithEnoughSpace = singleQuantityProducts.filter(product => {
353
498
  const allocation = result.get(product.productId);
354
- if (!allocation)
355
- return false;
356
- const remainingSpace = new import_decimal.default(product.amount).minus(allocation.discountAmount).toNumber();
499
+ if (!allocation) return false;
500
+ const remainingSpace = new _decimal.default(product.amount).minus(allocation.discountAmount).toNumber();
357
501
  return remainingSpace >= totalDifference;
358
502
  });
359
503
  if (productsWithEnoughSpace.length > 0) {
504
+ // 按金额降序排序,选择金额最大的
360
505
  productsWithEnoughSpace.sort((a, b) => b.amount - a.amount);
361
506
  const targetProduct = productsWithEnoughSpace[0];
362
507
  const targetAllocation = result.get(targetProduct.productId);
363
508
  if (targetAllocation) {
509
+ // 差值直接加到折扣金额上
364
510
  result.set(targetProduct.productId, {
365
- discountAmount: new import_decimal.default(targetAllocation.discountAmount).plus(totalDifference).toNumber(),
366
- difference: 0
367
- // 不需要存储差值
511
+ discountAmount: new _decimal.default(targetAllocation.discountAmount).plus(totalDifference).toNumber(),
512
+ difference: 0 // 不需要存储差值
368
513
  });
369
514
  }
370
515
  } else {
516
+ // 🔥 优先级2:所有数量为1的商品都没有足够剩余空间
517
+ // 选择金额最大的商品,差值存储在metadata中
371
518
  singleQuantityProducts.sort((a, b) => b.amount - a.amount);
372
519
  const targetProduct = singleQuantityProducts[0];
373
520
  const targetAllocation = result.get(targetProduct.productId);
@@ -379,6 +526,8 @@ var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
379
526
  }
380
527
  }
381
528
  } else {
529
+ // 🔥 优先级3:没有数量为1的商品,走原有逻辑
530
+ // 差值存储在最后一个商品的metadata中
382
531
  const lastProduct = applicableProducts[applicableProducts.length - 1];
383
532
  const lastProductAllocation = result.get(lastProduct.productId);
384
533
  if (lastProductAllocation) {
@@ -391,16 +540,4 @@ var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
391
540
  }
392
541
  return result;
393
542
  };
394
- // Annotate the CommonJS export names for ESM import in node:
395
- 0 && (module.exports = {
396
- calculateOrderLevelDiscountAllocation,
397
- filterDiscountListByBookingTime,
398
- getDateIsInSchedule,
399
- getDiscountAmount,
400
- getDiscountListAmount,
401
- getDiscountListAmountTotal,
402
- isAllNormalProduct,
403
- isNormalProductByDurationSchedule,
404
- isOrderLevelFixedAmountDiscount,
405
- uniqueById
406
- });
543
+ exports.calculateOrderLevelDiscountAllocation = calculateOrderLevelDiscountAllocation;