@pisell/pisellos 2.3.74 → 2.3.75

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 (276) hide show
  1. package/dist/core/index.js +6 -10
  2. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  3. package/dist/model/strategy/adapter/walletPass/example.js +3 -26
  4. package/dist/model/strategy/strategy-example.js +5 -19
  5. package/dist/modules/Cart/index.js +0 -3
  6. package/dist/modules/Cart/utils/cartProduct.js +0 -1
  7. package/dist/modules/Date/index.js +1 -5
  8. package/dist/modules/Discount/index.js +2 -4
  9. package/dist/modules/OpenData/index.js +0 -2
  10. package/dist/modules/Order/index.js +36 -64
  11. package/dist/modules/Payment/index.js +97 -162
  12. package/dist/modules/Rules/index.js +1 -4
  13. package/dist/modules/Schedule/index.js +0 -1
  14. package/dist/modules/Schedule/utils.js +0 -1
  15. package/dist/modules/Step/index.js +0 -1
  16. package/dist/plugins/request.js +1 -4
  17. package/dist/plugins/window.js +2 -6
  18. package/dist/server/index.js +97 -129
  19. package/dist/server/modules/menu/index.js +32 -41
  20. package/dist/server/modules/order/index.js +2 -4
  21. package/dist/server/modules/products/index.js +24 -42
  22. package/dist/server/modules/quotation/index.js +29 -38
  23. package/dist/server/modules/resource/index.js +3 -4
  24. package/dist/server/modules/schedule/index.js +27 -35
  25. package/dist/server/utils/product.js +0 -1
  26. package/dist/solution/BaseSales/index.js +38 -41
  27. package/dist/solution/BookingByStep/index.js +7 -59
  28. package/dist/solution/BookingByStep/utils/capacity.js +1 -11
  29. package/dist/solution/BookingByStep/utils/resources.js +1 -3
  30. package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
  31. package/dist/solution/BookingTicket/index.js +0 -2
  32. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
  33. package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
  34. package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
  35. package/dist/solution/BuyTickets/index.js +9 -12
  36. package/dist/solution/Checkout/index.js +177 -252
  37. package/dist/solution/Checkout/utils/index.js +4 -16
  38. package/dist/solution/RegisterAndLogin/index.js +30 -76
  39. package/dist/solution/ScanOrder/index.js +50 -60
  40. package/dist/solution/ShopDiscount/index.js +2 -7
  41. package/dist/solution/VenueBooking/index.js +45 -55
  42. package/dist/utils/task.js +15 -18
  43. package/dist/utils/watch.js +0 -1
  44. package/lib/apis/picoding.js +2 -0
  45. package/lib/core/index.js +134 -134
  46. package/lib/effects/index.js +46 -57
  47. package/lib/index.js +82 -49
  48. package/lib/model/index.js +14 -21
  49. package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
  50. package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
  51. package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
  52. package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
  53. package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
  54. package/lib/model/strategy/adapter/index.js +100 -64
  55. package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
  56. package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
  57. package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
  58. package/lib/model/strategy/adapter/itemRule/index.js +83 -57
  59. package/lib/model/strategy/adapter/itemRule/type.js +97 -36
  60. package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
  61. package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
  62. package/lib/model/strategy/adapter/promotion/examples.js +222 -234
  63. package/lib/model/strategy/adapter/promotion/index.js +1 -0
  64. package/lib/model/strategy/adapter/promotion/type.js +243 -36
  65. package/lib/model/strategy/adapter/type.js +4 -16
  66. package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
  67. package/lib/model/strategy/adapter/walletPass/example.js +217 -190
  68. package/lib/model/strategy/adapter/walletPass/index.js +75 -51
  69. package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
  70. package/lib/model/strategy/adapter/walletPass/type.js +4 -16
  71. package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
  72. package/lib/model/strategy/engine.js +270 -168
  73. package/lib/model/strategy/index.js +49 -34
  74. package/lib/model/strategy/strategy-example.js +243 -239
  75. package/lib/model/strategy/type.js +100 -40
  76. package/lib/modules/Account/index.js +39 -53
  77. package/lib/modules/Account/types.js +20 -33
  78. package/lib/modules/AccountList/index.js +116 -154
  79. package/lib/modules/AccountList/types.js +30 -31
  80. package/lib/modules/AccountList/utils.js +18 -30
  81. package/lib/modules/BaseModule.js +23 -42
  82. package/lib/modules/BookingContext/index.js +158 -136
  83. package/lib/modules/BookingContext/types.js +46 -32
  84. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
  85. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
  86. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
  87. package/lib/modules/BookingContext/utils/flexible.js +38 -55
  88. package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
  89. package/lib/modules/BookingContext/utils/index.js +124 -41
  90. package/lib/modules/BookingContext/utils/noResource.js +58 -70
  91. package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
  92. package/lib/modules/BookingContext/utils/productExtend.js +202 -155
  93. package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
  94. package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
  95. package/lib/modules/BookingContext/utils/resources.js +209 -167
  96. package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
  97. package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
  98. package/lib/modules/Cart/index.js +170 -124
  99. package/lib/modules/Cart/types.js +46 -51
  100. package/lib/modules/Cart/utils/cartAccount.js +40 -39
  101. package/lib/modules/Cart/utils/cartDate.js +56 -61
  102. package/lib/modules/Cart/utils/cartDiscount.js +28 -33
  103. package/lib/modules/Cart/utils/cartNote.js +27 -32
  104. package/lib/modules/Cart/utils/cartProduct.js +321 -251
  105. package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
  106. package/lib/modules/Cart/utils/cartResource.js +70 -78
  107. package/lib/modules/Cart/utils/changePrice.js +22 -50
  108. package/lib/modules/Cart/utils/index.js +106 -48
  109. package/lib/modules/Customer/constants.js +13 -34
  110. package/lib/modules/Customer/index.js +235 -172
  111. package/lib/modules/Customer/types.js +38 -35
  112. package/lib/modules/Date/index.js +116 -115
  113. package/lib/modules/Date/types.js +16 -28
  114. package/lib/modules/Date/utils.js +174 -123
  115. package/lib/modules/Discount/index.js +122 -127
  116. package/lib/modules/Discount/types.js +9 -31
  117. package/lib/modules/Guests/index.js +30 -56
  118. package/lib/modules/Guests/types.js +23 -33
  119. package/lib/modules/Holder/index.js +209 -189
  120. package/lib/modules/Holder/types.js +4 -16
  121. package/lib/modules/Holder/utils.js +20 -49
  122. package/lib/modules/OpenData/index.js +70 -76
  123. package/lib/modules/OpenData/types.js +4 -16
  124. package/lib/modules/OpenData/utils.js +44 -78
  125. package/lib/modules/Order/index.js +1713 -2118
  126. package/lib/modules/Order/payment-utils.js +77 -120
  127. package/lib/modules/Order/types.js +88 -35
  128. package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
  129. package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
  130. package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
  131. package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
  132. package/lib/modules/Order/utils.js +814 -647
  133. package/lib/modules/Payment/cash.js +20 -33
  134. package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
  135. package/lib/modules/Payment/eftpos.js +16 -30
  136. package/lib/modules/Payment/index.js +532 -399
  137. package/lib/modules/Payment/mx51.js +1 -0
  138. package/lib/modules/Payment/types.js +230 -108
  139. package/lib/modules/Payment/utils.js +52 -51
  140. package/lib/modules/Payment/walletpass.js +485 -660
  141. package/lib/modules/Product/index.js +51 -46
  142. package/lib/modules/Product/types.js +4 -16
  143. package/lib/modules/Product/utils.js +32 -33
  144. package/lib/modules/ProductList/index.js +113 -123
  145. package/lib/modules/ProductList/types.js +9 -31
  146. package/lib/modules/Quotation/index.js +81 -118
  147. package/lib/modules/Quotation/types.js +4 -16
  148. package/lib/modules/Resource/index.js +27 -59
  149. package/lib/modules/Resource/types.js +22 -32
  150. package/lib/modules/Resource/utils.js +30 -38
  151. package/lib/modules/ResourcePlanner/index.js +25 -23
  152. package/lib/modules/ResourcePlanner/localClock.js +54 -119
  153. package/lib/modules/ResourcePlanner/planner.js +589 -770
  154. package/lib/modules/ResourcePlanner/types.js +10 -29
  155. package/lib/modules/Rules/index.js +1218 -959
  156. package/lib/modules/Rules/types.js +17 -40
  157. package/lib/modules/SalesSummary/index.js +85 -90
  158. package/lib/modules/SalesSummary/types.js +4 -16
  159. package/lib/modules/SalesSummary/utils.js +355 -430
  160. package/lib/modules/ScanOrderLogger/index.js +59 -79
  161. package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
  162. package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
  163. package/lib/modules/ScanOrderLogger/types.js +4 -16
  164. package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
  165. package/lib/modules/Schedule/index.js +100 -114
  166. package/lib/modules/Schedule/type.js +4 -16
  167. package/lib/modules/Schedule/types.js +4 -16
  168. package/lib/modules/Schedule/utils.js +433 -291
  169. package/lib/modules/Step/index.js +40 -52
  170. package/lib/modules/Step/tyeps.js +4 -16
  171. package/lib/modules/Summary/index.js +66 -71
  172. package/lib/modules/Summary/types.js +4 -16
  173. package/lib/modules/Summary/utils.js +773 -418
  174. package/lib/modules/SurchargeList/index.js +46 -60
  175. package/lib/modules/SurchargeList/types.js +4 -16
  176. package/lib/modules/index.js +245 -63
  177. package/lib/plugins/app.js +4 -16
  178. package/lib/plugins/index.js +36 -25
  179. package/lib/plugins/request.js +137 -126
  180. package/lib/plugins/shopStore.js +4 -16
  181. package/lib/plugins/user.js +4 -16
  182. package/lib/plugins/window.js +171 -179
  183. package/lib/server/index.js +3050 -2665
  184. package/lib/server/modules/floor-plan/index.js +118 -134
  185. package/lib/server/modules/floor-plan/types.js +15 -30
  186. package/lib/server/modules/index.js +106 -68
  187. package/lib/server/modules/menu/index.js +142 -122
  188. package/lib/server/modules/menu/types.js +18 -31
  189. package/lib/server/modules/order/index.js +784 -1002
  190. package/lib/server/modules/order/types.js +122 -33
  191. package/lib/server/modules/order/utils/filterBookings.js +219 -194
  192. package/lib/server/modules/order/utils/filterOrders.js +118 -92
  193. package/lib/server/modules/payment/index.js +59 -83
  194. package/lib/server/modules/payment/types.js +4 -16
  195. package/lib/server/modules/products/index.js +583 -471
  196. package/lib/server/modules/products/types.js +44 -34
  197. package/lib/server/modules/quotation/index.js +137 -172
  198. package/lib/server/modules/quotation/types.js +21 -31
  199. package/lib/server/modules/resource/index.js +220 -186
  200. package/lib/server/modules/resource/types.js +42 -33
  201. package/lib/server/modules/schedule/index.js +135 -123
  202. package/lib/server/modules/schedule/types.js +14 -21
  203. package/lib/server/modules/schedule/utils.js +334 -163
  204. package/lib/server/types.js +4 -16
  205. package/lib/server/utils/index.js +25 -23
  206. package/lib/server/utils/product.js +196 -139
  207. package/lib/server/utils/schedule.js +34 -41
  208. package/lib/server/utils/small-ticket.js +479 -456
  209. package/lib/server/utils/time.js +40 -49
  210. package/lib/solution/BaseSales/index.js +1186 -1410
  211. package/lib/solution/BaseSales/types.js +42 -38
  212. package/lib/solution/BaseSales/utils/cartPromotion.js +642 -498
  213. package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
  214. package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
  215. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
  216. package/lib/solution/BaseSales/utils.js +158 -143
  217. package/lib/solution/BookingByStep/index.js +1527 -1340
  218. package/lib/solution/BookingByStep/types.js +40 -99
  219. package/lib/solution/BookingByStep/utils/capacity.js +192 -160
  220. package/lib/solution/BookingByStep/utils/products.js +42 -52
  221. package/lib/solution/BookingByStep/utils/resources.js +527 -330
  222. package/lib/solution/BookingByStep/utils/stock.js +65 -44
  223. package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
  224. package/lib/solution/BookingTicket/index.js +607 -522
  225. package/lib/solution/BookingTicket/types.js +99 -77
  226. package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
  227. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
  228. package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
  229. package/lib/solution/BookingTicket/utils/cartView.js +114 -99
  230. package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
  231. package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
  232. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
  233. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
  234. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
  235. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
  236. package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
  237. package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
  238. package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
  239. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
  240. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
  241. package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
  242. package/lib/solution/BuyTickets/index.js +67 -70
  243. package/lib/solution/BuyTickets/types.js +22 -38
  244. package/lib/solution/Checkout/index.js +1451 -1158
  245. package/lib/solution/Checkout/types.js +91 -61
  246. package/lib/solution/Checkout/utils/index.js +228 -156
  247. package/lib/solution/PlaceOrder/index.js +55 -0
  248. package/lib/solution/RegisterAndLogin/config.js +493 -460
  249. package/lib/solution/RegisterAndLogin/index.js +633 -630
  250. package/lib/solution/RegisterAndLogin/types.js +189 -76
  251. package/lib/solution/RegisterAndLogin/utils.js +183 -125
  252. package/lib/solution/Sales/index.js +328 -324
  253. package/lib/solution/Sales/types.js +27 -33
  254. package/lib/solution/ScanOrder/index.js +832 -864
  255. package/lib/solution/ScanOrder/types.js +33 -34
  256. package/lib/solution/ScanOrder/utils.js +409 -374
  257. package/lib/solution/ShopDiscount/index.js +226 -232
  258. package/lib/solution/ShopDiscount/types.js +15 -37
  259. package/lib/solution/ShopDiscount/utils.js +300 -172
  260. package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
  261. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
  262. package/lib/solution/UnifiedBookingSales/types.js +10 -32
  263. package/lib/solution/VenueBooking/index.js +811 -879
  264. package/lib/solution/VenueBooking/types.js +19 -39
  265. package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
  266. package/lib/solution/VenueBooking/utils/resource.js +31 -54
  267. package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
  268. package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
  269. package/lib/solution/VenueBooking/utils.js +130 -67
  270. package/lib/solution/index.js +124 -41
  271. package/lib/store/createStore.js +32 -29
  272. package/lib/types/index.js +4 -16
  273. package/lib/utils/payment-number.js +26 -46
  274. package/lib/utils/task.js +36 -36
  275. package/lib/utils/watch.js +81 -47
  276. package/package.json +2 -1
@@ -1,88 +1,88 @@
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
+ exports.isAllNormalProduct = isAllNormalProduct;
37
+ const getDiscountAmount = (discount, total, price) => {
38
+ // 商品券
39
+ if (discount.tag === 'good_pass') {
40
+ return new _decimal.default(price).minus(new _decimal.default(price || 0)).toNumber();
61
41
  }
62
- const isFixedAmount = ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.discount_card_type) === "fixed_amount";
42
+
43
+ // 判断是否是固定金额
44
+ const isFixedAmount = discount?.metadata?.discount_card_type === 'fixed_amount';
45
+
46
+ // 固定金额 小于0时返回0
63
47
  if (isFixedAmount) {
64
- return Math.max(new import_decimal.default(price).minus(new import_decimal.default((discount.amount ?? discount.par_value) || 0)).toNumber(), 0);
48
+ return Math.max(new _decimal.default(price).minus(new _decimal.default((discount.amount ?? discount.par_value) || 0)).toNumber(), 0);
65
49
  }
66
- return new import_decimal.default(100).minus(discount.par_value || 0).div(100).mul(new import_decimal.default(price)).toNumber();
50
+
51
+ // 百分比:根据折扣卡金额计算
52
+ return new _decimal.default(100).minus(discount.par_value || 0).div(100).mul(new _decimal.default(price)).toNumber();
67
53
  };
68
- var getDiscountListAmountTotal = (discount) => {
54
+ exports.getDiscountAmount = getDiscountAmount;
55
+ const getDiscountListAmountTotal = discount => {
69
56
  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));
57
+ return new _decimal.default(acc).plus(new _decimal.default(cur.num || 1).mul(new _decimal.default(cur.amount || 0))).toNumber();
58
+ }, new _decimal.default(0));
72
59
  };
73
- var getDiscountListAmount = (discount) => {
60
+
61
+ /**
62
+ * 获取折扣金额 计算每个折扣的金额
63
+ * @param discount
64
+ * @returns
65
+ */
66
+ exports.getDiscountListAmountTotal = getDiscountListAmountTotal;
67
+ const getDiscountListAmount = discount => {
74
68
  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));
69
+ return new _decimal.default(acc).plus(new _decimal.default(cur.amount || 0)).toNumber();
70
+ }, new _decimal.default(0));
77
71
  };
78
- var getDateIsInSchedule = (dateTime, scheduleList) => {
72
+
73
+ // 日程项接口定义
74
+ exports.getDiscountListAmount = getDiscountListAmount;
75
+ // 获取时间是否在日程范围内
76
+ const getDateIsInSchedule = (dateTime, scheduleList) => {
79
77
  if (!dateTime || !scheduleList || scheduleList.length === 0) {
80
78
  return false;
81
79
  }
82
- const targetDate = (0, import_dayjs.default)(dateTime);
80
+ const targetDate = (0, _dayjs.default)(dateTime);
83
81
  if (!targetDate.isValid()) {
84
82
  return false;
85
83
  }
84
+
85
+ // 遍历所有日程项
86
86
  for (const schedule of scheduleList) {
87
87
  if (isTimeInScheduleItem(dateTime, schedule)) {
88
88
  return true;
@@ -90,284 +90,422 @@ var getDateIsInSchedule = (dateTime, scheduleList) => {
90
90
  }
91
91
  return false;
92
92
  };
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";
93
+
94
+ // 判断时间是否在单个日程项范围内
95
+ exports.getDateIsInSchedule = getDateIsInSchedule;
96
+ const isTimeInScheduleItem = (dateTime, schedule) => {
97
+ const targetDate = (0, _dayjs.default)(dateTime);
98
+ const targetDateString = dateTime.split(' ')[0]; // YYYY-MM-DD
99
+ const targetTimeString = dateTime.split(' ')[1] || '00:00:00'; // HH:mm:ss
100
+
97
101
  switch (schedule.type) {
98
- case "standard":
102
+ case 'standard':
99
103
  return isInStandardSchedule(targetDate, targetDateString, targetTimeString, schedule);
100
- case "time-slots":
104
+ case 'time-slots':
101
105
  return isInTimeSlotsSchedule(targetDate, targetDateString, targetTimeString, schedule);
102
- case "designation":
106
+ case 'designation':
103
107
  return isInDesignationSchedule(targetDate, targetDateString, targetTimeString, schedule);
104
108
  default:
105
109
  return false;
106
110
  }
107
111
  };
108
- var isInStandardSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
112
+
113
+ // 处理标准类型日程
114
+ const isInStandardSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
109
115
  if (!schedule.start_time || !schedule.end_time) {
110
116
  return false;
111
117
  }
112
- const startDate = (0, import_dayjs.default)(schedule.start_time);
113
- const endDate = (0, import_dayjs.default)(schedule.end_time);
118
+ const startDate = (0, _dayjs.default)(schedule.start_time);
119
+ const endDate = (0, _dayjs.default)(schedule.end_time);
120
+
121
+ // 先检查是否在基础时间范围内(不考虑重复)
114
122
  const isInBasicRange = targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate);
115
- if (schedule.repeat_type === "none") {
123
+ if (schedule.repeat_type === 'none') {
116
124
  return isInBasicRange;
117
125
  }
126
+
127
+ // 处理重复日程
118
128
  return isInRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule, startDate, endDate);
119
129
  };
120
- var isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
130
+
131
+ // 处理时间段类型日程
132
+ const isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
121
133
  if (!schedule.start_time) {
122
134
  return false;
123
135
  }
124
- if (schedule.repeat_type === "none") {
125
- const scheduleDate = schedule.start_time.split(" ")[0];
136
+
137
+ // 如果不重复,使用原有逻辑
138
+ if (schedule.repeat_type === 'none') {
139
+ const scheduleDate = schedule.start_time.split(' ')[0];
140
+
141
+ // 检查日期是否匹配
126
142
  if (targetDateString !== scheduleDate) {
127
143
  return false;
128
144
  }
145
+
146
+ // 检查是否在任一时间段内
129
147
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
130
148
  }
149
+
150
+ // 处理重复日程
131
151
  return isInTimeSlotsRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule);
132
152
  };
133
- var isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
153
+
154
+ // 处理指定类型日程
155
+ const isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
134
156
  if (!schedule.designation) {
135
157
  return false;
136
158
  }
137
159
  for (const designation of schedule.designation) {
138
160
  const startDateTime = `${designation.start_date} ${designation.start_time}:00`;
139
161
  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);
162
+ const startDate = (0, _dayjs.default)(startDateTime);
163
+ const endDate = (0, _dayjs.default)(endDateTime);
142
164
  if (targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate)) {
143
165
  return true;
144
166
  }
145
167
  }
146
168
  return false;
147
169
  };
148
- var isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule, startDate, endDate) => {
170
+
171
+ // 处理重复日程逻辑
172
+ const isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule, startDate, endDate) => {
149
173
  if (!schedule.repeat_rule) {
150
174
  return false;
151
175
  }
152
- const { repeat_rule, repeat_type } = schedule;
153
- const targetDateOnly = (0, import_dayjs.default)(targetDateString);
176
+ const {
177
+ repeat_rule,
178
+ repeat_type
179
+ } = schedule;
180
+ const targetDateOnly = (0, _dayjs.default)(targetDateString); // 只取日期部分
181
+
182
+ // 首先检查是否在包含日期中(包含日期是额外增加的有效日期)
154
183
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
155
184
  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")) {
185
+ const includeStartDate = (0, _dayjs.default)(includedDate.start);
186
+ const includeEndDate = (0, _dayjs.default)(includedDate.end);
187
+ if (targetDateOnly.isSameOrAfter(includeStartDate, 'day') && targetDateOnly.isSameOrBefore(includeEndDate, 'day')) {
188
+ // 在包含日期中,直接返回true,无需检查其他条件
159
189
  return true;
160
190
  }
161
191
  }
162
192
  }
193
+
194
+ // 检查是否在排除日期中
163
195
  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")) {
196
+ const excludeStartDate = (0, _dayjs.default)(excludedDate.start);
197
+ const excludeEndDate = (0, _dayjs.default)(excludedDate.end);
198
+ // 检查目标日期是否在排除范围内(包含边界)
199
+ if (targetDateOnly.isSameOrAfter(excludeStartDate, 'day') && targetDateOnly.isSameOrBefore(excludeEndDate, 'day')) {
167
200
  return false;
168
201
  }
169
202
  }
170
- if (repeat_rule.end.type === "date" && repeat_rule.end.end_date) {
171
- const ruleEndDate = (0, import_dayjs.default)(repeat_rule.end.end_date);
203
+
204
+ // 检查重复规则的结束条件
205
+ if (repeat_rule.end.type === 'date' && repeat_rule.end.end_date) {
206
+ const ruleEndDate = (0, _dayjs.default)(repeat_rule.end.end_date);
172
207
  if (targetDate.isAfter(ruleEndDate)) {
173
208
  return false;
174
209
  }
175
210
  }
211
+
212
+ // 根据重复类型检查
176
213
  switch (repeat_type) {
177
- case "daily":
214
+ case 'daily':
178
215
  return isInDailyRepeat(targetDate, startDate, endDate, repeat_rule);
179
- case "weekly":
216
+ case 'weekly':
180
217
  return isInWeeklyRepeat(targetDate, startDate, endDate, repeat_rule);
181
218
  default:
182
219
  return false;
220
+ // 不支持月和年重复
183
221
  }
184
222
  };
185
- var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
186
- const daysDiff = targetDate.diff(startDate, "day");
223
+
224
+ // 每日重复逻辑
225
+ const isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
226
+ const daysDiff = targetDate.diff(startDate, 'day');
187
227
  if (daysDiff < 0) {
188
228
  return false;
189
229
  }
230
+
231
+ // 检查频率
190
232
  if (daysDiff % repeatRule.frequency !== 0) {
191
233
  return false;
192
234
  }
235
+
236
+ // 检查时间是否在日程的时间范围内
193
237
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
194
238
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
195
239
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
240
+
241
+ // 每日重复:每天都在相同的时间段内有效
242
+ // 例如:01:00:00 - 16:00:00,每天都是这个时间段
196
243
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
197
244
  };
198
- var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
199
- const targetDayOfWeek = targetDate.day();
245
+
246
+ // 每周重复逻辑
247
+ const isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
248
+ const targetDayOfWeek = targetDate.day(); // 0=周日, 1=周一, ..., 6=周六
249
+
250
+ // 检查是否在指定的星期几内
200
251
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
201
252
  return false;
202
253
  }
203
- const weeksDiff = targetDate.diff(startDate, "week");
254
+
255
+ // 计算周差
256
+ const weeksDiff = targetDate.diff(startDate, 'week');
204
257
  if (weeksDiff < 0) {
205
258
  return false;
206
259
  }
260
+
261
+ // 检查频率
207
262
  if (weeksDiff % repeatRule.frequency !== 0) {
208
263
  return false;
209
264
  }
265
+
266
+ // 检查时间是否在日程的时间范围内
210
267
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
211
268
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
212
269
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
213
270
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
214
271
  };
215
- var isInTimeSlotsRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
272
+
273
+ // 处理 time-slots 类型的重复日程
274
+ const isInTimeSlotsRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
216
275
  if (!schedule.repeat_rule || !schedule.start_time) {
217
276
  return false;
218
277
  }
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);
278
+ const {
279
+ repeat_rule,
280
+ repeat_type
281
+ } = schedule;
282
+ const startDate = (0, _dayjs.default)(schedule.start_time);
283
+ const targetDateOnly = (0, _dayjs.default)(targetDateString);
284
+
285
+ // 检查包含日期
222
286
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
223
287
  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")) {
288
+ const includeStartDate = (0, _dayjs.default)(includedDate.start);
289
+ const includeEndDate = (0, _dayjs.default)(includedDate.end);
290
+ if (targetDateOnly.isSameOrAfter(includeStartDate, 'day') && targetDateOnly.isSameOrBefore(includeEndDate, 'day')) {
291
+ // 在包含日期中,检查时间段
227
292
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
228
293
  }
229
294
  }
230
295
  }
296
+
297
+ // 检查排除日期
231
298
  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")) {
299
+ const excludeStartDate = (0, _dayjs.default)(excludedDate.start);
300
+ const excludeEndDate = (0, _dayjs.default)(excludedDate.end);
301
+ if (targetDateOnly.isSameOrAfter(excludeStartDate, 'day') && targetDateOnly.isSameOrBefore(excludeEndDate, 'day')) {
235
302
  return false;
236
303
  }
237
304
  }
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")) {
305
+
306
+ // 检查重复规则的结束条件
307
+ if (repeat_rule.end.type === 'date' && repeat_rule.end.end_date) {
308
+ const ruleEndDate = (0, _dayjs.default)(repeat_rule.end.end_date);
309
+ if (targetDateOnly.isAfter(ruleEndDate, 'day')) {
241
310
  return false;
242
311
  }
243
312
  }
313
+
314
+ // 检查目标日期是否在重复规则范围内
244
315
  let isDateValid = false;
245
316
  switch (repeat_type) {
246
- case "daily":
317
+ case 'daily':
247
318
  isDateValid = isInDailyRepeatForDate(targetDateOnly, startDate, repeat_rule);
248
319
  break;
249
- case "weekly":
320
+ case 'weekly':
250
321
  isDateValid = isInWeeklyRepeatForDate(targetDateOnly, startDate, repeat_rule);
251
322
  break;
252
323
  default:
253
324
  return false;
254
325
  }
326
+
327
+ // 如果日期有效,检查时间段
255
328
  if (isDateValid) {
256
329
  return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
257
330
  }
258
331
  return false;
259
332
  };
260
- var checkTimeSlotsForDate = (targetDate, targetDateString, timeSlots) => {
333
+
334
+ // 检查目标时间是否在某个时间段内(使用目标日期 + time_slot 时间)
335
+ const checkTimeSlotsForDate = (targetDate, targetDateString, timeSlots) => {
261
336
  for (const timeSlot of timeSlots) {
262
337
  const slotStart = `${targetDateString} ${timeSlot.start_time}:00`;
263
338
  const slotEnd = `${targetDateString} ${timeSlot.end_time}:00`;
264
- const slotStartDate = (0, import_dayjs.default)(slotStart);
265
- const slotEndDate = (0, import_dayjs.default)(slotEnd);
339
+ const slotStartDate = (0, _dayjs.default)(slotStart);
340
+ const slotEndDate = (0, _dayjs.default)(slotEnd);
266
341
  if (targetDate.isSameOrAfter(slotStartDate) && targetDate.isSameOrBefore(slotEndDate)) {
267
342
  return true;
268
343
  }
269
344
  }
270
345
  return false;
271
346
  };
272
- var isInDailyRepeatForDate = (targetDate, startDate, repeatRule) => {
273
- const daysDiff = targetDate.diff(startDate, "day");
347
+
348
+ // 检查日期是否满足每日重复规则(只检查日期,不检查时间)
349
+ const isInDailyRepeatForDate = (targetDate, startDate, repeatRule) => {
350
+ const daysDiff = targetDate.diff(startDate, 'day');
274
351
  if (daysDiff < 0) {
275
352
  return false;
276
353
  }
354
+
355
+ // 检查频率
277
356
  return daysDiff % repeatRule.frequency === 0;
278
357
  };
279
- var isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
280
- const targetDayOfWeek = targetDate.day();
358
+
359
+ // 检查日期是否满足每周重复规则(只检查日期,不检查时间)
360
+ const isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
361
+ const targetDayOfWeek = targetDate.day(); // 0=周日, 1=周一, ..., 6=周六
362
+
363
+ // 检查是否在指定的星期几内
281
364
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
282
365
  return false;
283
366
  }
284
- const weeksDiff = targetDate.diff(startDate, "week");
367
+
368
+ // 计算周差
369
+ const weeksDiff = targetDate.diff(startDate, 'week');
285
370
  if (weeksDiff < 0) {
286
371
  return false;
287
372
  }
373
+
374
+ // 检查频率
288
375
  return weeksDiff % repeatRule.frequency === 0;
289
376
  };
290
- var filterDiscountListByBookingTime = (discountList, bookingTime) => {
377
+
378
+ /**
379
+ * 根据预约时间过滤优惠券列表
380
+ * @param discountList 优惠券列表
381
+ * @param bookingTime 预约时间 (格式: YYYY-MM-DD HH:mm:ss)
382
+ * @returns 过滤后的优惠券列表
383
+ */
384
+ const filterDiscountListByBookingTime = (discountList, bookingTime) => {
291
385
  if (!bookingTime) {
292
386
  return discountList;
293
387
  }
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) || []);
388
+ return discountList.filter(discount => {
389
+ if (discount?.metadata?.validity_type === "custom_schedule_validity") {
390
+ return getDateIsInSchedule(bookingTime, discount.custom_schedule_snapshot?.data || []);
298
391
  }
299
392
  try {
300
393
  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);
394
+ const startDate = (0, _dayjs.default)(`${discount.start_date} ${discount.start_time}`);
395
+ const bookingTimeDayjs = (0, _dayjs.default)(bookingTime);
396
+
397
+ // 判断预约时间是否在开始时间之后
303
398
  const isAfterStart = isHasStart ? bookingTimeDayjs.isSameOrAfter(startDate) : true;
304
- const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, import_dayjs.default)(discount.expire_time)) : true;
399
+
400
+ // 判断预约时间是否在过期时间之前(expire_time 为空时为长期有效)
401
+ const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, _dayjs.default)(discount.expire_time)) : true;
305
402
  return isAfterStart && isBeforeExpire;
306
403
  } catch (error) {
307
404
  return true;
308
405
  }
309
406
  });
310
407
  };
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";
408
+ /**
409
+ * 判断是否是订单级别的固定金额折扣卡
410
+ * @param discount 折扣
411
+ * @returns 是否是订单级别的固定金额折扣卡
412
+ */
413
+ exports.filterDiscountListByBookingTime = filterDiscountListByBookingTime;
414
+ const isOrderLevelFixedAmountDiscount = discount => {
415
+ return discount.tag === 'product_discount_card' && discount?.metadata?.discount_card_type === 'fixed_amount' && discount?.metadata?.discount_calculation_mode === 'order_level';
314
416
  };
315
- var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
316
- const result = /* @__PURE__ */ new Map();
417
+
418
+ /**
419
+ * 计算订单级别固定金额折扣卡的分摊结果
420
+ * @param discount 折扣卡
421
+ * @param applicableProducts 适用商品列表 { productId, amount, quantity, parentQuantity }
422
+ * @returns 分摊结果 Map<productId, { discountAmount, difference }>
423
+ * 注意:
424
+ * - discountAmount 是单价折扣金额(不是总折扣金额)
425
+ * - difference(总差值)优先直接加到数量为1的单商品折扣上,如果没有则存储在metadata中
426
+ */
427
+ exports.isOrderLevelFixedAmountDiscount = isOrderLevelFixedAmountDiscount;
428
+ const calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
429
+ const result = new Map();
317
430
  if (applicableProducts.length === 0) {
318
431
  return result;
319
432
  }
433
+
434
+ // 计算适用商品的总金额(数量 × 单价)
320
435
  const totalAmount = applicableProducts.reduce((acc, product) => {
321
- return new import_decimal.default(acc).plus(new import_decimal.default(product.amount).mul(product.quantity)).toNumber();
436
+ return new _decimal.default(acc).plus(new _decimal.default(product.amount).mul(product.quantity)).toNumber();
322
437
  }, 0);
323
438
  if (totalAmount <= 0) {
324
439
  return result;
325
440
  }
326
- const fixedAmount = new import_decimal.default(discount.par_value || 0).toNumber();
441
+
442
+ // 固定减免金额
443
+ const fixedAmount = new _decimal.default(discount.par_value || 0).toNumber();
444
+
445
+ // 如果固定金额 >= 商品总金额,折扣最高为商品金额(免费)
327
446
  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();
447
+
448
+ // 计算每个商品的单价折扣金额
449
+ let allocatedTotal = new _decimal.default(0);
450
+ applicableProducts.forEach(product => {
451
+ // 🔥 分摊公式改为:(单价 / 适用商品总金额) × 固定金额
452
+ // 这样只有一次取整,避免精度损失
453
+ const rawDiscountPerItem = new _decimal.default(product.amount).div(totalAmount).mul(actualDiscountTotal);
454
+
455
+ // 保留两位小数,向下取整(单价折扣)
456
+ const discountAmountPerItem = rawDiscountPerItem.toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
332
457
  result.set(product.productId, {
333
458
  discountAmount: discountAmountPerItem,
334
459
  // 单价折扣金额
335
- difference: 0
336
- // 默认差值为0
460
+ difference: 0 // 默认差值为0
337
461
  });
338
- allocatedTotal = allocatedTotal.plus(
339
- new import_decimal.default(discountAmountPerItem).mul(product.quantity)
340
- );
462
+
463
+ // 累加实际分配的总折扣金额(单价折扣 × 数量)
464
+ allocatedTotal = allocatedTotal.plus(new _decimal.default(discountAmountPerItem).mul(product.quantity));
341
465
  });
342
- const totalDifference = new import_decimal.default(actualDiscountTotal).minus(allocatedTotal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
466
+
467
+ // 🔥 计算总差值
468
+ // 总差值 = 固定金额 - 所有商品的 (单价折扣 × 数量) 之和
469
+ const totalDifference = new _decimal.default(actualDiscountTotal).minus(allocatedTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
343
470
  if (totalDifference > 0) {
344
- const isSingleQuantity = (product) => {
345
- if (product.parentQuantity !== void 0) {
471
+ // 🔥 判断商品是否是真正的"数量为1"
472
+ // 主商品:quantity === 1
473
+ // 子商品:quantity === 1 且 parentQuantity === 1
474
+ const isSingleQuantity = product => {
475
+ if (product.parentQuantity !== undefined) {
476
+ // 子商品:需要同时满足自身数量为1且主商品数量为1
346
477
  return product.quantity === 1 && product.parentQuantity === 1;
347
478
  }
479
+ // 主商品:只需要自身数量为1
348
480
  return product.quantity === 1;
349
481
  };
482
+
483
+ // 🔥 筛选出数量为1的商品
350
484
  const singleQuantityProducts = applicableProducts.filter(isSingleQuantity);
351
485
  if (singleQuantityProducts.length > 0) {
352
- const productsWithEnoughSpace = singleQuantityProducts.filter((product) => {
486
+ // 🔥 优先级1:找到有足够剩余空间且金额最大的商品
487
+ // 剩余空间 = 商品价格 - 当前折扣金额 >= 差值
488
+ const productsWithEnoughSpace = singleQuantityProducts.filter(product => {
353
489
  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();
490
+ if (!allocation) return false;
491
+ const remainingSpace = new _decimal.default(product.amount).minus(allocation.discountAmount).toNumber();
357
492
  return remainingSpace >= totalDifference;
358
493
  });
359
494
  if (productsWithEnoughSpace.length > 0) {
495
+ // 按金额降序排序,选择金额最大的
360
496
  productsWithEnoughSpace.sort((a, b) => b.amount - a.amount);
361
497
  const targetProduct = productsWithEnoughSpace[0];
362
498
  const targetAllocation = result.get(targetProduct.productId);
363
499
  if (targetAllocation) {
500
+ // 差值直接加到折扣金额上
364
501
  result.set(targetProduct.productId, {
365
- discountAmount: new import_decimal.default(targetAllocation.discountAmount).plus(totalDifference).toNumber(),
366
- difference: 0
367
- // 不需要存储差值
502
+ discountAmount: new _decimal.default(targetAllocation.discountAmount).plus(totalDifference).toNumber(),
503
+ difference: 0 // 不需要存储差值
368
504
  });
369
505
  }
370
506
  } else {
507
+ // 🔥 优先级2:所有数量为1的商品都没有足够剩余空间
508
+ // 选择金额最大的商品,差值存储在metadata中
371
509
  singleQuantityProducts.sort((a, b) => b.amount - a.amount);
372
510
  const targetProduct = singleQuantityProducts[0];
373
511
  const targetAllocation = result.get(targetProduct.productId);
@@ -379,6 +517,8 @@ var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
379
517
  }
380
518
  }
381
519
  } else {
520
+ // 🔥 优先级3:没有数量为1的商品,走原有逻辑
521
+ // 差值存储在最后一个商品的metadata中
382
522
  const lastProduct = applicableProducts[applicableProducts.length - 1];
383
523
  const lastProductAllocation = result.get(lastProduct.productId);
384
524
  if (lastProductAllocation) {
@@ -391,16 +531,4 @@ var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
391
531
  }
392
532
  return result;
393
533
  };
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
- });
534
+ exports.calculateOrderLevelDiscountAllocation = calculateOrderLevelDiscountAllocation;