@pisell/pisellos 2.3.74 → 2.3.76

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 (283) 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.d.ts +1 -1
  11. package/dist/modules/Order/index.js +75 -91
  12. package/dist/modules/Order/types.d.ts +3 -1
  13. package/dist/modules/Payment/index.js +97 -162
  14. package/dist/modules/Rules/index.js +1 -4
  15. package/dist/modules/Schedule/index.js +0 -1
  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 +97 -129
  21. package/dist/server/modules/menu/index.js +32 -41
  22. package/dist/server/modules/order/index.js +2 -4
  23. package/dist/server/modules/products/index.js +24 -42
  24. package/dist/server/modules/quotation/index.js +29 -38
  25. package/dist/server/modules/resource/index.js +3 -4
  26. package/dist/server/modules/schedule/index.js +27 -35
  27. package/dist/server/utils/product.js +0 -1
  28. package/dist/solution/BaseSales/index.js +100 -72
  29. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
  30. package/dist/solution/BaseSales/utils/cartPromotion.js +15 -6
  31. package/dist/solution/BookingByStep/index.js +7 -59
  32. package/dist/solution/BookingByStep/utils/capacity.js +1 -11
  33. package/dist/solution/BookingByStep/utils/resources.js +1 -3
  34. package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
  35. package/dist/solution/BookingTicket/index.js +0 -2
  36. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
  37. package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
  38. package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
  39. package/dist/solution/BuyTickets/index.js +9 -12
  40. package/dist/solution/Checkout/index.js +177 -252
  41. package/dist/solution/Checkout/utils/index.js +4 -16
  42. package/dist/solution/RegisterAndLogin/index.js +30 -76
  43. package/dist/solution/ScanOrder/index.js +50 -60
  44. package/dist/solution/ShopDiscount/index.js +2 -7
  45. package/dist/solution/VenueBooking/index.js +45 -55
  46. package/dist/utils/task.js +15 -18
  47. package/dist/utils/watch.js +0 -1
  48. package/lib/apis/picoding.js +2 -0
  49. package/lib/core/index.js +134 -134
  50. package/lib/effects/index.js +46 -57
  51. package/lib/index.js +82 -49
  52. package/lib/model/index.js +14 -21
  53. package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
  54. package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
  55. package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
  56. package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
  57. package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
  58. package/lib/model/strategy/adapter/index.js +100 -64
  59. package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
  60. package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
  61. package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
  62. package/lib/model/strategy/adapter/itemRule/index.js +83 -57
  63. package/lib/model/strategy/adapter/itemRule/type.js +97 -36
  64. package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
  65. package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
  66. package/lib/model/strategy/adapter/promotion/examples.js +222 -234
  67. package/lib/model/strategy/adapter/promotion/index.js +1 -0
  68. package/lib/model/strategy/adapter/promotion/type.js +243 -36
  69. package/lib/model/strategy/adapter/type.js +4 -16
  70. package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
  71. package/lib/model/strategy/adapter/walletPass/example.js +217 -190
  72. package/lib/model/strategy/adapter/walletPass/index.js +75 -51
  73. package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
  74. package/lib/model/strategy/adapter/walletPass/type.js +4 -16
  75. package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
  76. package/lib/model/strategy/engine.js +270 -168
  77. package/lib/model/strategy/index.js +49 -34
  78. package/lib/model/strategy/strategy-example.js +243 -239
  79. package/lib/model/strategy/type.js +100 -40
  80. package/lib/modules/Account/index.js +39 -53
  81. package/lib/modules/Account/types.js +20 -33
  82. package/lib/modules/AccountList/index.js +116 -154
  83. package/lib/modules/AccountList/types.js +30 -31
  84. package/lib/modules/AccountList/utils.js +18 -30
  85. package/lib/modules/BaseModule.js +23 -42
  86. package/lib/modules/BookingContext/index.js +158 -136
  87. package/lib/modules/BookingContext/types.js +46 -32
  88. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
  89. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
  90. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
  91. package/lib/modules/BookingContext/utils/flexible.js +38 -55
  92. package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
  93. package/lib/modules/BookingContext/utils/index.js +124 -41
  94. package/lib/modules/BookingContext/utils/noResource.js +58 -70
  95. package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
  96. package/lib/modules/BookingContext/utils/productExtend.js +202 -155
  97. package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
  98. package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
  99. package/lib/modules/BookingContext/utils/resources.js +209 -167
  100. package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
  101. package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
  102. package/lib/modules/Cart/index.js +170 -124
  103. package/lib/modules/Cart/types.js +46 -51
  104. package/lib/modules/Cart/utils/cartAccount.js +40 -39
  105. package/lib/modules/Cart/utils/cartDate.js +56 -61
  106. package/lib/modules/Cart/utils/cartDiscount.js +28 -33
  107. package/lib/modules/Cart/utils/cartNote.js +27 -32
  108. package/lib/modules/Cart/utils/cartProduct.js +321 -251
  109. package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
  110. package/lib/modules/Cart/utils/cartResource.js +70 -78
  111. package/lib/modules/Cart/utils/changePrice.js +22 -50
  112. package/lib/modules/Cart/utils/index.js +106 -48
  113. package/lib/modules/Customer/constants.js +13 -34
  114. package/lib/modules/Customer/index.js +235 -172
  115. package/lib/modules/Customer/types.js +38 -35
  116. package/lib/modules/Date/index.js +116 -115
  117. package/lib/modules/Date/types.js +16 -28
  118. package/lib/modules/Date/utils.js +174 -123
  119. package/lib/modules/Discount/index.js +122 -127
  120. package/lib/modules/Discount/types.js +9 -31
  121. package/lib/modules/Guests/index.js +30 -56
  122. package/lib/modules/Guests/types.js +23 -33
  123. package/lib/modules/Holder/index.js +209 -189
  124. package/lib/modules/Holder/types.js +4 -16
  125. package/lib/modules/Holder/utils.js +20 -49
  126. package/lib/modules/OpenData/index.js +70 -76
  127. package/lib/modules/OpenData/types.js +4 -16
  128. package/lib/modules/OpenData/utils.js +44 -78
  129. package/lib/modules/Order/index.d.ts +1 -1
  130. package/lib/modules/Order/index.js +1733 -2121
  131. package/lib/modules/Order/payment-utils.js +77 -120
  132. package/lib/modules/Order/types.d.ts +3 -1
  133. package/lib/modules/Order/types.js +88 -35
  134. package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
  135. package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
  136. package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
  137. package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
  138. package/lib/modules/Order/utils.js +814 -647
  139. package/lib/modules/Payment/cash.js +20 -33
  140. package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
  141. package/lib/modules/Payment/eftpos.js +16 -30
  142. package/lib/modules/Payment/index.js +532 -399
  143. package/lib/modules/Payment/mx51.js +1 -0
  144. package/lib/modules/Payment/types.js +230 -108
  145. package/lib/modules/Payment/utils.js +52 -51
  146. package/lib/modules/Payment/walletpass.js +485 -660
  147. package/lib/modules/Product/index.js +51 -46
  148. package/lib/modules/Product/types.js +4 -16
  149. package/lib/modules/Product/utils.js +32 -33
  150. package/lib/modules/ProductList/index.js +113 -123
  151. package/lib/modules/ProductList/types.js +9 -31
  152. package/lib/modules/Quotation/index.js +81 -118
  153. package/lib/modules/Quotation/types.js +4 -16
  154. package/lib/modules/Resource/index.js +27 -59
  155. package/lib/modules/Resource/types.js +22 -32
  156. package/lib/modules/Resource/utils.js +30 -38
  157. package/lib/modules/ResourcePlanner/index.js +25 -23
  158. package/lib/modules/ResourcePlanner/localClock.js +54 -119
  159. package/lib/modules/ResourcePlanner/planner.js +589 -770
  160. package/lib/modules/ResourcePlanner/types.js +10 -29
  161. package/lib/modules/Rules/index.js +1218 -959
  162. package/lib/modules/Rules/types.js +17 -40
  163. package/lib/modules/SalesSummary/index.js +85 -90
  164. package/lib/modules/SalesSummary/types.js +4 -16
  165. package/lib/modules/SalesSummary/utils.js +355 -430
  166. package/lib/modules/ScanOrderLogger/index.js +59 -79
  167. package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
  168. package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
  169. package/lib/modules/ScanOrderLogger/types.js +4 -16
  170. package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
  171. package/lib/modules/Schedule/index.js +100 -114
  172. package/lib/modules/Schedule/type.js +4 -16
  173. package/lib/modules/Schedule/types.js +4 -16
  174. package/lib/modules/Schedule/utils.js +433 -291
  175. package/lib/modules/Step/index.js +40 -52
  176. package/lib/modules/Step/tyeps.js +4 -16
  177. package/lib/modules/Summary/index.js +66 -71
  178. package/lib/modules/Summary/types.js +4 -16
  179. package/lib/modules/Summary/utils.js +773 -418
  180. package/lib/modules/SurchargeList/index.js +46 -60
  181. package/lib/modules/SurchargeList/types.js +4 -16
  182. package/lib/modules/index.js +245 -63
  183. package/lib/plugins/app.js +4 -16
  184. package/lib/plugins/index.js +36 -25
  185. package/lib/plugins/request.js +137 -126
  186. package/lib/plugins/shopStore.js +4 -16
  187. package/lib/plugins/user.js +4 -16
  188. package/lib/plugins/window.js +171 -179
  189. package/lib/server/index.js +3050 -2665
  190. package/lib/server/modules/floor-plan/index.js +118 -134
  191. package/lib/server/modules/floor-plan/types.js +15 -30
  192. package/lib/server/modules/index.js +106 -68
  193. package/lib/server/modules/menu/index.js +142 -122
  194. package/lib/server/modules/menu/types.js +18 -31
  195. package/lib/server/modules/order/index.js +784 -1002
  196. package/lib/server/modules/order/types.js +122 -33
  197. package/lib/server/modules/order/utils/filterBookings.js +219 -194
  198. package/lib/server/modules/order/utils/filterOrders.js +118 -92
  199. package/lib/server/modules/payment/index.js +59 -83
  200. package/lib/server/modules/payment/types.js +4 -16
  201. package/lib/server/modules/products/index.js +583 -471
  202. package/lib/server/modules/products/types.js +44 -34
  203. package/lib/server/modules/quotation/index.js +137 -172
  204. package/lib/server/modules/quotation/types.js +21 -31
  205. package/lib/server/modules/resource/index.js +220 -186
  206. package/lib/server/modules/resource/types.js +42 -33
  207. package/lib/server/modules/schedule/index.js +135 -123
  208. package/lib/server/modules/schedule/types.js +14 -21
  209. package/lib/server/modules/schedule/utils.js +334 -163
  210. package/lib/server/types.js +4 -16
  211. package/lib/server/utils/index.js +25 -23
  212. package/lib/server/utils/product.js +196 -139
  213. package/lib/server/utils/schedule.js +34 -41
  214. package/lib/server/utils/small-ticket.js +479 -456
  215. package/lib/server/utils/time.js +40 -49
  216. package/lib/solution/BaseSales/index.js +1220 -1412
  217. package/lib/solution/BaseSales/types.js +42 -38
  218. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
  219. package/lib/solution/BaseSales/utils/cartPromotion.js +652 -498
  220. package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
  221. package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
  222. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
  223. package/lib/solution/BaseSales/utils.js +158 -143
  224. package/lib/solution/BookingByStep/index.js +1527 -1340
  225. package/lib/solution/BookingByStep/types.js +40 -99
  226. package/lib/solution/BookingByStep/utils/capacity.js +192 -160
  227. package/lib/solution/BookingByStep/utils/products.js +42 -52
  228. package/lib/solution/BookingByStep/utils/resources.js +527 -330
  229. package/lib/solution/BookingByStep/utils/stock.js +65 -44
  230. package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
  231. package/lib/solution/BookingTicket/index.js +607 -522
  232. package/lib/solution/BookingTicket/types.js +99 -77
  233. package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
  234. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
  235. package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
  236. package/lib/solution/BookingTicket/utils/cartView.js +114 -99
  237. package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
  238. package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
  239. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
  240. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
  241. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
  242. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
  243. package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
  244. package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
  245. package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
  246. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
  247. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
  248. package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
  249. package/lib/solution/BuyTickets/index.js +67 -70
  250. package/lib/solution/BuyTickets/types.js +22 -38
  251. package/lib/solution/Checkout/index.js +1451 -1158
  252. package/lib/solution/Checkout/types.js +91 -61
  253. package/lib/solution/Checkout/utils/index.js +228 -156
  254. package/lib/solution/PlaceOrder/index.js +55 -0
  255. package/lib/solution/RegisterAndLogin/config.js +493 -460
  256. package/lib/solution/RegisterAndLogin/index.js +633 -630
  257. package/lib/solution/RegisterAndLogin/types.js +189 -76
  258. package/lib/solution/RegisterAndLogin/utils.js +183 -125
  259. package/lib/solution/Sales/index.js +328 -324
  260. package/lib/solution/Sales/types.js +27 -33
  261. package/lib/solution/ScanOrder/index.js +832 -864
  262. package/lib/solution/ScanOrder/types.js +33 -34
  263. package/lib/solution/ScanOrder/utils.js +409 -374
  264. package/lib/solution/ShopDiscount/index.js +226 -232
  265. package/lib/solution/ShopDiscount/types.js +15 -37
  266. package/lib/solution/ShopDiscount/utils.js +300 -172
  267. package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
  268. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
  269. package/lib/solution/UnifiedBookingSales/types.js +10 -32
  270. package/lib/solution/VenueBooking/index.js +811 -879
  271. package/lib/solution/VenueBooking/types.js +19 -39
  272. package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
  273. package/lib/solution/VenueBooking/utils/resource.js +31 -54
  274. package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
  275. package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
  276. package/lib/solution/VenueBooking/utils.js +130 -67
  277. package/lib/solution/index.js +124 -41
  278. package/lib/store/createStore.js +32 -29
  279. package/lib/types/index.js +4 -16
  280. package/lib/utils/payment-number.js +26 -46
  281. package/lib/utils/task.js +36 -36
  282. package/lib/utils/watch.js +81 -47
  283. package/package.json +2 -1
@@ -1,58 +1,32 @@
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/modules/Rules/index.ts
30
- var Rules_exports = {};
31
- __export(Rules_exports, {
32
- RulesModule: () => RulesModule
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
33
5
  });
34
- module.exports = __toCommonJS(Rules_exports);
35
- var import_BaseModule = require("../BaseModule");
36
- var import_types = require("./types");
37
- var import_utils = require("../../solution/ShopDiscount/utils");
38
- var import_utils2 = require("../Cart/utils");
39
- var import_decimal = __toESM(require("decimal.js"));
40
- var import_lodash_es = require("lodash-es");
41
- var import_dayjs = __toESM(require("dayjs"));
42
- var import_utils3 = require("../../solution/ShopDiscount/utils");
43
- var import_utils4 = require("../../solution/ShopDiscount/utils");
44
- var RulesModule = class extends import_BaseModule.BaseModule {
6
+ exports.RulesModule = void 0;
7
+ var _BaseModule = require("../BaseModule");
8
+ var _types = require("./types");
9
+ var _utils = require("../../solution/ShopDiscount/utils");
10
+ var _utils2 = require("../Cart/utils");
11
+ var _decimal = _interopRequireDefault(require("decimal.js"));
12
+ var _lodashEs = require("lodash-es");
13
+ var _dayjs = _interopRequireDefault(require("dayjs"));
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ class RulesModule extends _BaseModule.BaseModule {
16
+ defaultName = 'rules';
17
+ defaultVersion = '1.0.0';
18
+ store;
19
+ window; // WindowPlugin 实例
20
+ hooks;
45
21
  constructor(name, version) {
46
22
  super(name, version);
47
- this.defaultName = "rules";
48
- this.defaultVersion = "1.0.0";
49
23
  this.hooks = {};
50
24
  }
51
25
  async initialize(core, options) {
52
26
  this.core = core;
53
- this.hooks = options == null ? void 0 : options.hooks;
54
- this.store = options == null ? void 0 : options.store;
55
- this.window = core.getPlugin("window");
27
+ this.hooks = options?.hooks;
28
+ this.store = options?.store;
29
+ this.window = core.getPlugin('window');
56
30
  }
57
31
  async setRulesList(rulesList) {
58
32
  this.store.rulesList = rulesList;
@@ -62,22 +36,25 @@ var RulesModule = class extends import_BaseModule.BaseModule {
62
36
  return this.store.rulesList;
63
37
  }
64
38
  getWalletPassEvaluator() {
65
- var _a, _b;
66
- return (_b = (_a = this.window).getWalletPassEvaluator) == null ? void 0 : _b.call(_a);
39
+ return this.window.getWalletPassEvaluator?.();
67
40
  }
41
+
68
42
  // 商品不需要holder,则不需要判断,直接返回true,商品需要holder但是还没填写,那么暂时不使用带有holder的券,直到填写才去匹配
69
43
  checkHolderMatch(discount, product, holders) {
70
- var _a;
71
- if (((_a = discount.holder) == null ? void 0 : _a.holder_type) !== "form")
72
- return true;
73
- const orderHolderId = Array.isArray(holders) && holders.length > 0 ? holders[0].form_record_id || holders[0] : void 0;
44
+ // 非表单类型 holder 视为匹配
45
+ if (discount.holder?.holder_type !== 'form') return true;
46
+ // 主预约holder, 目前(20251124)默认只考虑单个holder的情况
47
+ // 旧版 holders[0].form_record_id 新版 holders[0]
48
+ const orderHolderId = Array.isArray(holders) && holders.length > 0 ? holders[0].form_record_id || holders[0] : undefined;
74
49
  const productHolderId = Array.isArray(product.holder_id) ? product.holder_id[0] : product.holder_id;
75
- if (!product.isNeedHolder)
76
- return true;
77
- if (!orderHolderId && !productHolderId)
78
- return false;
50
+ // 商品不需要选holder,则不对比holder,直接返回true,
51
+ if (!product.isNeedHolder) return true;
52
+ // 商品需要holder,但父预约及商品都无holder,返回false
53
+ if (!orderHolderId && !productHolderId) return false;
54
+ // 最终直接匹配 holder 是否相同
79
55
  return (productHolderId || orderHolderId) === discount.holder.holder_id;
80
56
  }
57
+
81
58
  // 判断discountList 是否可以对当前productList生效
82
59
  isDiscountListAvailable({
83
60
  oldDiscountList,
@@ -87,6 +64,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
87
64
  holders,
88
65
  isFormSubject
89
66
  }) {
67
+ // 首先检查是否有新的优惠券可应用
90
68
  if (!newDiscountList || newDiscountList.length === 0) {
91
69
  return {
92
70
  isAvailable: false,
@@ -94,57 +72,58 @@ var RulesModule = class extends import_BaseModule.BaseModule {
94
72
  productList
95
73
  };
96
74
  }
97
- if (productList.length > 0 && productList.every((item) => {
98
- var _a;
75
+
76
+ // 编辑商品已有商品券
77
+ if (productList.length > 0 && productList.every(item => {
99
78
  const product = this.hooks.getProduct(item);
100
- return product.booking_id && (((_a = product.discount_list) == null ? void 0 : _a.length) || product.total == 0);
79
+ return product.booking_id && (product.discount_list?.length || product.total == 0);
101
80
  })) {
102
81
  return {
103
82
  isAvailable: false,
104
83
  discountList: oldDiscountList,
105
84
  productList,
106
- unavailableReason: import_types.UnavailableReason.AlreadyUsed
85
+ unavailableReason: _types.UnavailableReason.AlreadyUsed
107
86
  };
108
87
  }
109
- const filteredOldDiscountList = oldDiscountList.filter(
110
- (discount) => !discount.isEditMode && (discount.tag !== "good_pass" || discount.isScan)
111
- );
112
- const mergedDiscountList = (0, import_utils.uniqueById)([
113
- ...filteredOldDiscountList,
114
- ...newDiscountList
115
- ]);
116
- const result = this.calcDiscount(
117
- {
118
- discountList: mergedDiscountList,
119
- productList: [...productList],
120
- orderTotalAmount,
121
- holders,
122
- isFormSubject
123
- },
124
- {
125
- scan: true
126
- }
127
- );
88
+
89
+ // 合并新旧折扣列表,并计算折扣结果,注意,如果旧折扣里有 isEditMode true 的优惠券,则不合并
90
+ // 保留之前扫码得到的商品券(isScan: true)
91
+ const filteredOldDiscountList = oldDiscountList.filter(discount => !discount.isEditMode && (discount.tag !== 'good_pass' || discount.isScan));
92
+ const mergedDiscountList = (0, _utils.uniqueById)([...filteredOldDiscountList, ...newDiscountList]);
93
+ const result = this.calcDiscount({
94
+ discountList: mergedDiscountList,
95
+ productList: [...productList],
96
+ orderTotalAmount,
97
+ holders,
98
+ isFormSubject
99
+ }, {
100
+ scan: true
101
+ });
102
+
103
+ // 检查是否有产品使用了新折扣
128
104
  let hasApplicableDiscount = false;
129
- const newDiscountIds = newDiscountList.map((discount) => discount.id);
130
- result.productList.forEach((product) => {
131
- const { discount_list, bundle } = this.hooks.getProduct(product);
132
- const allDiscountList = [...discount_list || []];
133
- (bundle || []).forEach((item) => {
134
- allDiscountList.push(...(item == null ? void 0 : item.discount_list) || []);
105
+ const newDiscountIds = newDiscountList.map(discount => discount.id);
106
+
107
+ // 遍历处理后的产品列表,检查是否有产品使用了新折扣
108
+ result.productList.forEach(product => {
109
+ const {
110
+ discount_list,
111
+ bundle
112
+ } = this.hooks.getProduct(product);
113
+ const allDiscountList = [...(discount_list || [])];
114
+ (bundle || []).forEach(item => {
115
+ allDiscountList.push(...(item?.discount_list || []));
135
116
  });
136
117
  if (allDiscountList && allDiscountList.length > 0) {
137
- const usedNewDiscount = allDiscountList.some(
138
- (discount) => {
139
- var _a;
140
- return newDiscountIds.includes((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id);
141
- }
142
- );
118
+ // 检查是否有使用新折扣的情况
119
+ const usedNewDiscount = allDiscountList.some(discount => newDiscountIds.includes(discount?.discount?.resource_id));
143
120
  if (usedNewDiscount) {
144
121
  hasApplicableDiscount = true;
145
122
  }
146
123
  }
147
124
  });
125
+
126
+ // 如果券不可用,判断不可用原因
148
127
  let unavailableReason;
149
128
  if (!hasApplicableDiscount) {
150
129
  unavailableReason = this.getUnavailableReason(newDiscountList, productList);
@@ -158,61 +137,58 @@ var RulesModule = class extends import_BaseModule.BaseModule {
158
137
  };
159
138
  }
160
139
  filterDiscountListByType(discountList, type) {
161
- return (discountList || []).filter((item) => item.type === type || item.tag === type);
140
+ return (discountList || []).filter(item => item.type === type || item.tag === type);
162
141
  }
142
+
163
143
  /** 剔除指定 type/tag 的折扣项,保留手动改价(type=product) / 券等 */
164
144
  excludeDiscountListByType(discountList, type) {
165
- return (discountList || []).filter((item) => item.type !== type && item.tag !== type);
145
+ return (discountList || []).filter(item => item.type !== type && item.tag !== type);
166
146
  }
147
+
167
148
  /** 手动改价场景:去掉 promotion,保留 type=product 等行内折扣 */
168
149
  resolveDiscountListForManualOverride(discountList) {
169
- return this.excludeDiscountListByType(discountList, "promotion");
150
+ return this.excludeDiscountListByType(discountList, 'promotion');
170
151
  }
171
152
  isItemRewardProductDiscount(product) {
172
- var _a;
173
- const discountList = Array.isArray(product == null ? void 0 : product.discount_list) ? product.discount_list : [];
174
- return ((_a = product == null ? void 0 : product._promotion) == null ? void 0 : _a.actionType) === "ITEM_REWARD" && discountList.some(
175
- (item) => {
176
- var _a2, _b;
177
- return (item == null ? void 0 : item.type) === "product" && ((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.source) === "promotion" && ((_b = item == null ? void 0 : item.metadata) == null ? void 0 : _b.actionType) === "ITEM_REWARD";
178
- }
179
- );
153
+ const discountList = Array.isArray(product?.discount_list) ? product.discount_list : [];
154
+ return product?._promotion?.actionType === 'ITEM_REWARD' && discountList.some(item => item?.type === 'product' && item?.metadata?.source === 'promotion' && item?.metadata?.actionType === 'ITEM_REWARD');
180
155
  }
156
+
181
157
  // 获取券不可用的原因
182
158
  getUnavailableReason(discountList, productList) {
183
- var _a;
159
+ // 检查时间限制
184
160
  for (const discount of discountList) {
185
- const bookingTimes = productList.length ? productList.map((item) => {
161
+ const bookingTimes = productList.length ? productList.map(item => {
186
162
  const product = this.hooks.getProduct(item);
187
- return ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format(
188
- "YYYY-MM-DD HH:mm:ss"
189
- );
190
- }) : [(0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")];
163
+ return (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss');
164
+ }) : [(0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss')];
191
165
  for (const bookingTime of bookingTimes) {
192
- const filteredList = (0, import_utils.filterDiscountListByBookingTime)([discount], bookingTime);
166
+ const filteredList = (0, _utils.filterDiscountListByBookingTime)([discount], bookingTime);
193
167
  if (filteredList.length === 0) {
194
- return import_types.UnavailableReason.TimeLimit;
168
+ return _types.UnavailableReason.TimeLimit;
195
169
  }
196
170
  }
197
171
  }
172
+
173
+ // 检查商品适用性
198
174
  for (const discount of discountList) {
199
175
  const limitedData = discount.limited_relation_product_data;
200
176
  let hasApplicableProduct = false;
201
177
  for (const item of productList) {
202
178
  const product = this.hooks.getProduct(item);
203
- if (limitedData.type === "product_all") {
179
+ if (limitedData.type === 'product_all') {
204
180
  hasApplicableProduct = true;
205
181
  break;
206
- } else if ((_a = limitedData.product_ids) == null ? void 0 : _a.includes(product.id)) {
182
+ } else if (limitedData.product_ids?.includes(product.id)) {
207
183
  hasApplicableProduct = true;
208
184
  break;
209
185
  }
210
186
  }
211
187
  if (!hasApplicableProduct) {
212
- return import_types.UnavailableReason.ProductNotApplicable;
188
+ return _types.UnavailableReason.ProductNotApplicable;
213
189
  }
214
190
  }
215
- return import_types.UnavailableReason.Unknown;
191
+ return _types.UnavailableReason.Unknown;
216
192
  }
217
193
  calcDiscount({
218
194
  discountList,
@@ -221,83 +197,84 @@ var RulesModule = class extends import_BaseModule.BaseModule {
221
197
  isFormSubject,
222
198
  orderTotalAmount
223
199
  }, options) {
224
- var _a;
225
- const resolveIsFormSubject = (product) => typeof isFormSubject === "function" ? Boolean(isFormSubject(product)) : Boolean(isFormSubject);
226
- const isEditModeAddNewProduct = productList.find((n) => n.booking_id) && productList.find((n) => !n.booking_id);
227
- const reapplyBookingDiscountProductUids = new Set(
228
- ((options == null ? void 0 : options.reapplyBookingDiscountProductUids) || []).filter((uid) => uid !== void 0 && uid !== null && uid !== "").map(String)
229
- );
230
- const getOriginProductUid = (originProduct) => {
231
- var _a2;
232
- const uid = ((_a2 = originProduct == null ? void 0 : originProduct.metadata) == null ? void 0 : _a2.unique_identification_number) ?? (originProduct == null ? void 0 : originProduct.unique_identification_number);
233
- if (uid === void 0 || uid === null || uid === "")
234
- return void 0;
200
+ const resolveIsFormSubject = product => typeof isFormSubject === 'function' ? Boolean(isFormSubject(product)) : Boolean(isFormSubject);
201
+
202
+ // 识别出来是不是在编辑的界面里又新增了商品
203
+ // 这种情况下,如果有可用的优惠券,也会自动勾选上
204
+ const isEditModeAddNewProduct = productList.find(n => n.booking_id) && productList.find(n => !n.booking_id);
205
+ const reapplyBookingDiscountProductUids = new Set((options?.reapplyBookingDiscountProductUids || []).filter(uid => uid !== undefined && uid !== null && uid !== '').map(String));
206
+ const getOriginProductUid = originProduct => {
207
+ const uid = originProduct?.metadata?.unique_identification_number ?? originProduct?.unique_identification_number;
208
+ if (uid === undefined || uid === null || uid === '') return undefined;
235
209
  return String(uid);
236
210
  };
237
211
  const shouldReapplyBookingDiscount = (originProduct, selectedDiscount) => {
238
- if (!selectedDiscount)
239
- return false;
212
+ if (!selectedDiscount) return false;
240
213
  const uid = getOriginProductUid(originProduct);
241
- if (!uid || !reapplyBookingDiscountProductUids.has(uid))
242
- return false;
214
+ if (!uid || !reapplyBookingDiscountProductUids.has(uid)) return false;
243
215
  const discountType = selectedDiscount.tag || selectedDiscount.type;
244
- return selectedDiscount.isEditMode === true && selectedDiscount.isSelected === true && ["good_pass", "discount_card", "product_discount_card"].includes(discountType);
216
+ return selectedDiscount.isEditMode === true && selectedDiscount.isSelected === true && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType);
245
217
  };
246
218
  const resolveReapplyBookingDiscountPercent = (originProduct, selectedDiscount) => {
247
- var _a2;
248
- if (!shouldReapplyBookingDiscount(originProduct, selectedDiscount))
249
- return void 0;
250
- const discountType = (selectedDiscount == null ? void 0 : selectedDiscount.tag) || (selectedDiscount == null ? void 0 : selectedDiscount.type);
251
- if (discountType !== "discount_card" && discountType !== "product_discount_card") {
252
- return void 0;
219
+ if (!shouldReapplyBookingDiscount(originProduct, selectedDiscount)) return undefined;
220
+ const discountType = selectedDiscount?.tag || selectedDiscount?.type;
221
+ if (discountType !== 'discount_card' && discountType !== 'product_discount_card') {
222
+ return undefined;
253
223
  }
254
- const percent = Number((_a2 = selectedDiscount.discount) == null ? void 0 : _a2.percent);
255
- return Number.isFinite(percent) ? percent : void 0;
224
+ const percent = Number(selectedDiscount.discount?.percent);
225
+ return Number.isFinite(percent) ? percent : undefined;
256
226
  };
257
227
  const editModeDiscount = [];
258
228
  const addModeDiscount = [];
259
- discountList.forEach((discount) => {
229
+ discountList.forEach(discount => {
260
230
  if (discount.isEditMode) {
261
231
  editModeDiscount.push(discount);
262
232
  } else {
263
233
  addModeDiscount.push(discount);
264
234
  }
265
235
  });
266
- const editModeOrderLevelProductIds = /* @__PURE__ */ new Set();
267
- editModeDiscount.forEach((discount) => {
268
- var _a2, _b;
269
- if (((_a2 = discount.discount) == null ? void 0 : _a2.discount_calculation_mode) === "order_level") {
270
- editModeOrderLevelProductIds.add((_b = discount == null ? void 0 : discount.discount) == null ? void 0 : _b.discount_product_id);
236
+
237
+ // 🔥 检查 editModeDiscount 中是否有订单级别的折扣,如果有则禁用 addModeDiscount 中相同 product_id 的折扣卡
238
+ const editModeOrderLevelProductIds = new Set();
239
+ editModeDiscount.forEach(discount => {
240
+ if (discount.discount?.discount_calculation_mode === 'order_level') {
241
+ editModeOrderLevelProductIds.add(discount?.discount?.discount_product_id);
271
242
  }
272
243
  });
244
+
245
+ // 如果存在订单级别的编辑模式折扣,禁用 addModeDiscount 中相同 product_id 的折扣卡
273
246
  if (editModeOrderLevelProductIds.size > 0) {
274
- addModeDiscount.forEach((discount) => {
247
+ addModeDiscount.forEach(discount => {
275
248
  if (editModeOrderLevelProductIds.has(discount.product_id)) {
276
249
  discount.isDisabled = true;
277
250
  }
278
251
  });
279
252
  }
280
- const hasDiscountInput = editModeDiscount.length > 0 || addModeDiscount.length > 0 || Boolean(options == null ? void 0 : options.discountId) || Boolean((_a = options == null ? void 0 : options.selectedList) == null ? void 0 : _a.length) || Boolean(options == null ? void 0 : options.scan);
253
+ const hasDiscountInput = editModeDiscount.length > 0 || addModeDiscount.length > 0 || Boolean(options?.discountId) || Boolean(options?.selectedList?.length) || Boolean(options?.scan);
281
254
  if (!hasDiscountInput) {
282
255
  return {
283
256
  discountList,
284
257
  productList
285
258
  };
286
259
  }
287
- const canUseEditModeDiscountForReapply = (discount) => {
260
+ const canUseEditModeDiscountForReapply = discount => {
288
261
  const discountType = discount.tag || discount.type;
289
- return reapplyBookingDiscountProductUids.size > 0 && discount.isEditMode === true && discount.isSelected === true && ["good_pass", "discount_card", "product_discount_card"].includes(discountType);
262
+ return reapplyBookingDiscountProductUids.size > 0 && discount.isEditMode === true && discount.isSelected === true && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType);
290
263
  };
291
- const filteredDiscountList = [
292
- ...addModeDiscount.filter((discount) => !discount.isManualSelect),
293
- ...editModeDiscount.filter(canUseEditModeDiscountForReapply)
294
- ];
295
- const flattenProductsWithBundle = (productList2) => {
264
+
265
+ // 过滤掉手动取消false的优惠券,但仅用于应用优惠逻辑。
266
+ // Change time 重报价需要把已选编辑态折扣卡重新放入候选,再由目标 uid 限定作用范围。
267
+ const filteredDiscountList = [...addModeDiscount.filter(discount => !discount.isManualSelect), ...editModeDiscount.filter(canUseEditModeDiscountForReapply)];
268
+
269
+ // 🔥 扁平化商品列表:将 bundle 子商品展开为虚拟商品
270
+ const flattenProductsWithBundle = productList => {
296
271
  const flattened = [];
297
- productList2.forEach((originProduct) => {
272
+ productList.forEach(originProduct => {
298
273
  const product = this.hooks.getProduct(originProduct);
274
+
275
+ // 1. 添加主商品
299
276
  flattened.push({
300
- type: "main",
277
+ type: 'main',
301
278
  originProduct,
302
279
  product,
303
280
  price: Number(product.price || 0),
@@ -308,10 +285,12 @@ var RulesModule = class extends import_BaseModule.BaseModule {
308
285
  num: product.num,
309
286
  booking_id: product.booking_id
310
287
  });
288
+
289
+ // 2. 展开 bundle 子商品
311
290
  if (product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0) {
312
291
  product.bundle.forEach((bundleItem, bundleIndex) => {
313
292
  flattened.push({
314
- type: "bundle",
293
+ type: 'bundle',
315
294
  originProduct,
316
295
  parentProduct: product,
317
296
  bundleItem,
@@ -326,8 +305,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
326
305
  parentId: product._id,
327
306
  num: bundleItem.num || 1,
328
307
  quantity: bundleItem.num || 1,
329
- total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
330
- origin_total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
308
+ total: new _decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
309
+ origin_total: new _decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
331
310
  original_price: bundleItem.original_price,
332
311
  // 继承主商品属性
333
312
  booking_id: bundleItem.booking_id,
@@ -338,120 +317,157 @@ var RulesModule = class extends import_BaseModule.BaseModule {
338
317
  });
339
318
  return flattened;
340
319
  };
320
+
321
+ // 优惠力度排序,传进来的数据里可能有商品券,也可能有优惠券
322
+ // 新的优先级排序规则(从高到低):
323
+ // 1. 带有Holder的商品券(metadata?.holder?.type === 'custom' && tag === 'good_pass')
324
+ // 2. 带有Holder的商品级折扣卡(metadata?.holder?.type === 'custom' && tag === 'product_discount_card' && discount_calculation_mode !== 'order_level')
325
+ // 3. 带有Holder的订单级折扣卡(metadata?.holder?.type === 'custom' && tag === 'product_discount_card' && discount_calculation_mode === 'order_level')
326
+ // 4. Customer商品券(metadata?.holder?.type !== 'custom' && tag === 'good_pass')
327
+ // 5. Customer商品级折扣卡(metadata?.holder?.type !== 'custom' && tag === 'product_discount_card' && discount_calculation_mode !== 'order_level')
328
+ // 6. Customer订单级固定金额折扣(metadata?.holder?.type !== 'custom' && tag === 'product_discount_card' && discount_calculation_mode === 'order_level')
329
+ // 同一优先级内部:固定金额优先于百分比,金额/折扣力度越大越优先,最后按过期时间排序
341
330
  const sortedDiscountList = [...filteredDiscountList].sort((a, b) => {
342
- const isHolderDiscount = (discount) => {
343
- var _a2, _b;
344
- return ((_b = (_a2 = discount.metadata) == null ? void 0 : _a2.holder) == null ? void 0 : _b.type) === "custom";
345
- };
346
- const isGoodPass = (discount) => discount.tag === "good_pass";
347
- const isOrderLevelDiscount = (discount) => {
348
- var _a2;
349
- return discount.tag === "product_discount_card" && ((_a2 = discount.metadata) == null ? void 0 : _a2.discount_calculation_mode) === "order_level";
350
- };
351
- const isItemLevelDiscount = (discount) => {
352
- var _a2;
353
- return discount.tag === "product_discount_card" && ((_a2 = discount.metadata) == null ? void 0 : _a2.discount_calculation_mode) !== "order_level";
354
- };
355
- const getPriority = (discount) => {
331
+ // 辅助函数:判断是否是带有Holder的优惠券
332
+ const isHolderDiscount = discount => discount.metadata?.holder?.type === 'custom';
333
+
334
+ // 辅助函数:判断是否是商品券
335
+ const isGoodPass = discount => discount.tag === 'good_pass';
336
+
337
+ // 辅助函数:判断是否是订单级折扣卡
338
+ const isOrderLevelDiscount = discount => discount.tag === 'product_discount_card' && discount.metadata?.discount_calculation_mode === 'order_level';
339
+
340
+ // 辅助函数:判断是否是商品级折扣卡
341
+ const isItemLevelDiscount = discount => discount.tag === 'product_discount_card' && discount.metadata?.discount_calculation_mode !== 'order_level';
342
+
343
+ // 辅助函数:获取优先级(数字越小优先级越高)
344
+ const getPriority = discount => {
356
345
  const isHolder = isHolderDiscount(discount);
357
346
  if (isHolder) {
358
- if (isGoodPass(discount))
359
- return 1;
360
- if (isItemLevelDiscount(discount))
361
- return 2;
362
- if (isOrderLevelDiscount(discount))
363
- return 3;
347
+ if (isGoodPass(discount)) return 1; // 带有Holder的商品券
348
+ if (isItemLevelDiscount(discount)) return 2; // 带有Holder的商品级折扣卡
349
+ if (isOrderLevelDiscount(discount)) return 3; // 带有Holder的订单级折扣卡
364
350
  } else {
365
- if (isGoodPass(discount))
366
- return 4;
367
- if (isItemLevelDiscount(discount))
368
- return 5;
369
- if (isOrderLevelDiscount(discount))
370
- return 6;
351
+ if (isGoodPass(discount)) return 4; // Customer商品券
352
+ if (isItemLevelDiscount(discount)) return 5; // Customer商品级折扣卡
353
+ if (isOrderLevelDiscount(discount)) return 6; // Customer订单级固定金额折扣
371
354
  }
372
- return 7;
355
+ return 7; // 其他情况
373
356
  };
357
+
358
+ // 辅助函数:按过期时间比较
374
359
  function compareByExpireTime(itemA, itemB) {
375
360
  if (itemA.expire_time && itemB.expire_time) {
376
361
  const timeA = new Date(itemA.expire_time).getTime();
377
362
  const timeB = new Date(itemB.expire_time).getTime();
378
363
  return timeA - timeB;
379
364
  }
365
+ // 有过期时间的优先级高于永久的
380
366
  return itemA.expire_time ? -1 : itemB.expire_time ? 1 : 0;
381
367
  }
368
+
369
+ // 辅助函数:同类型折扣卡内部排序(固定金额优先于百分比,金额/折扣力度排序)
382
370
  function compareDiscountCardValue(itemA, itemB) {
383
- var _a2, _b;
384
- const typeA = ((_a2 = itemA.metadata) == null ? void 0 : _a2.discount_card_type) || "percent";
385
- const typeB = ((_b = itemB.metadata) == null ? void 0 : _b.discount_card_type) || "percent";
386
- if (typeA === "fixed_amount" && typeB === "percent")
387
- return -1;
388
- if (typeA === "percent" && typeB === "fixed_amount")
389
- return 1;
390
- if (typeA === "fixed_amount" && typeB === "fixed_amount") {
371
+ const typeA = itemA.metadata?.discount_card_type || 'percent';
372
+ const typeB = itemB.metadata?.discount_card_type || 'percent';
373
+
374
+ // 1. 固定金额优先于百分比
375
+ if (typeA === 'fixed_amount' && typeB === 'percent') return -1;
376
+ if (typeA === 'percent' && typeB === 'fixed_amount') return 1;
377
+
378
+ // 2. 都是固定金额时,金额越大越优先
379
+ if (typeA === 'fixed_amount' && typeB === 'fixed_amount') {
391
380
  if (itemA.par_value !== itemB.par_value) {
392
- const valueA = new import_decimal.default(itemA.par_value || 0);
393
- const valueB = new import_decimal.default(itemB.par_value || 0);
394
- return valueB.minus(valueA).toNumber();
381
+ const valueA = new _decimal.default(itemA.par_value || 0);
382
+ const valueB = new _decimal.default(itemB.par_value || 0);
383
+ return valueB.minus(valueA).toNumber(); // 金额大的在前
395
384
  }
396
385
  }
397
- if (typeA === "percent" && typeB === "percent") {
386
+
387
+ // 3. 都是百分比时,折扣越大越优先(par_value越大越优先)
388
+ if (typeA === 'percent' && typeB === 'percent') {
398
389
  if (itemA.par_value !== itemB.par_value) {
399
- const valueA = new import_decimal.default(100).minus(itemA.par_value || 0);
400
- const valueB = new import_decimal.default(100).minus(itemB.par_value || 0);
401
- return valueA.minus(valueB).toNumber();
390
+ const valueA = new _decimal.default(100).minus(itemA.par_value || 0);
391
+ const valueB = new _decimal.default(100).minus(itemB.par_value || 0);
392
+ return valueA.minus(valueB).toNumber(); // 折扣大的在前
402
393
  }
403
394
  }
404
395
  return 0;
405
396
  }
397
+
398
+ // 1. 先按优先级排序
406
399
  const priorityA = getPriority(a);
407
400
  const priorityB = getPriority(b);
408
401
  if (priorityA !== priorityB) {
409
402
  return priorityA - priorityB;
410
403
  }
404
+
405
+ // 2. 同一优先级内部排序
406
+ // 如果是商品券(优先级1或4),按过期时间排序
411
407
  if (isGoodPass(a) && isGoodPass(b)) {
412
408
  return compareByExpireTime(a, b);
413
409
  }
414
- if (a.tag === "product_discount_card" && b.tag === "product_discount_card") {
410
+
411
+ // 如果是折扣卡(优先级2、3、5、6),按折扣力度排序,然后按过期时间
412
+ if (a.tag === 'product_discount_card' && b.tag === 'product_discount_card') {
415
413
  const valueCompare = compareDiscountCardValue(a, b);
416
- if (valueCompare !== 0)
417
- return valueCompare;
414
+ if (valueCompare !== 0) return valueCompare;
418
415
  return compareByExpireTime(a, b);
419
416
  }
417
+
418
+ // 3. 其他情况按照过期时间排序
420
419
  return compareByExpireTime(a, b);
421
420
  });
421
+
422
+ // const newProductList = [];
423
+ //
424
+ // productList.forEach(item => {
425
+ // const product = this.hooks.getProduct(item);
426
+ // if (product.quantity > 1) {
427
+ // for (let i = 1; i < product.quantity; i++) {
428
+ // newProductList.push(product)
429
+ // }
430
+ // } else {
431
+ // newProductList.push(item)
432
+ // }
433
+ // })
434
+
435
+ // 🔥 扁平化商品列表(包含主商品和bundle子商品)
422
436
  const flattenedList = flattenProductsWithBundle(productList);
437
+
438
+ // 对扁平化后的列表按价格降序排序(用于应用优惠券时优先选择高价商品)
423
439
  const sortedFlattenedList = flattenedList.sort((a, b) => {
424
- var _a2, _b;
425
- const priceA = new import_decimal.default(
426
- a.type === "bundle" ? a.original_price ?? a.price ?? "0" : a.price || "0"
427
- );
428
- const priceB = new import_decimal.default(
429
- b.type === "bundle" ? b.original_price ?? b.price ?? "0" : b.price || "0"
430
- );
440
+ // 子商品优先使用 original_price,主商品使用 price
441
+ const priceA = new _decimal.default(a.type === 'bundle' ? a.original_price ?? a.price ?? '0' : a.price || '0');
442
+ const priceB = new _decimal.default(b.type === 'bundle' ? b.original_price ?? b.price ?? '0' : b.price || '0');
431
443
  if (priceA.equals(priceB)) {
444
+ // 价格相同时,主商品优先
432
445
  if (a.type !== b.type) {
433
- return a.type === "main" ? -1 : 1;
446
+ return a.type === 'main' ? -1 : 1;
434
447
  }
435
- if (a.type === "main" && b.type === "main") {
448
+ // 都是主商品时,按原有逻辑排序
449
+ if (a.type === 'main' && b.type === 'main') {
436
450
  if (a.product.quantity === b.product.quantity) {
437
- return (((_a2 = b.product.discount_list) == null ? void 0 : _a2.length) || 0) - (((_b = a.product.discount_list) == null ? void 0 : _b.length) || 0);
451
+ return (b.product.discount_list?.length || 0) - (a.product.discount_list?.length || 0);
438
452
  }
439
453
  return a.product.quantity - b.product.quantity;
440
454
  }
441
- if (a.type === "bundle" && b.type === "bundle") {
455
+ // 都是bundle时,按数量排序
456
+ if (a.type === 'bundle' && b.type === 'bundle') {
442
457
  return (a.num || 1) - (b.num || 1);
443
458
  }
444
459
  }
445
460
  return priceB.minus(priceA).toNumber();
446
461
  });
462
+
463
+ // 🔥 为每个折扣卡/商品券执行策略检查并附加config
447
464
  const evaluator = this.getWalletPassEvaluator();
448
465
  if (evaluator) {
449
- addModeDiscount.forEach((discount) => {
450
- var _a2, _b;
466
+ addModeDiscount.forEach(discount => {
451
467
  const discountType = discount.tag || discount.type;
452
- if (["good_pass", "discount_card", "product_discount_card"].includes(
453
- discountType
454
- )) {
468
+ // 只对 good_pass discount_card 类型执行策略检查
469
+ if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
470
+ // 转换 discount 为 Voucher 格式
455
471
  const voucher = {
456
472
  id: discount.id,
457
473
  amount: Number(discount.par_value || 0),
@@ -459,24 +475,27 @@ var RulesModule = class extends import_BaseModule.BaseModule {
459
475
  type: discountType,
460
476
  product_id: discount.product_id,
461
477
  unified_available_status: 1,
462
- available_product_type: (_a2 = discount.limited_relation_product_data) == null ? void 0 : _a2.type,
463
- available_product_ids: (_b = discount.limited_relation_product_data) == null ? void 0 : _b.product_ids
478
+ available_product_type: discount.limited_relation_product_data?.type,
479
+ available_product_ids: discount.limited_relation_product_data?.product_ids
464
480
  };
465
- const productsForEvaluate = sortedFlattenedList.map((item) => {
466
- var _a3;
467
- return {
468
- product_id: item.id,
469
- price: item.price || 0,
470
- quantity: item.quantity || item.num || 1,
471
- selling_price: item.price || 0,
472
- product_options: item.type === "main" ? (_a3 = item.product) == null ? void 0 : _a3.options : void 0
473
- };
474
- });
481
+
482
+ // 转换 sortedFlattenedList 为 Product 格式
483
+ const productsForEvaluate = sortedFlattenedList.map(item => ({
484
+ product_id: item.id,
485
+ price: item.price || 0,
486
+ quantity: item.quantity || item.num || 1,
487
+ selling_price: item.price || 0,
488
+ product_options: item.type === 'main' ? item.product?.options : undefined
489
+ }));
490
+
491
+ // 调用策略检查
475
492
  const result = evaluator.checkVoucherAvailability({
476
- orderTotalAmount,
493
+ orderTotalAmount: orderTotalAmount,
477
494
  products: productsForEvaluate,
478
495
  vouchers: [voucher]
479
496
  });
497
+
498
+ // 将 config 附加到 discount 对象
480
499
  if (result.isAvailable) {
481
500
  discount.config = {
482
501
  ...result.config,
@@ -490,21 +509,56 @@ var RulesModule = class extends import_BaseModule.BaseModule {
490
509
  }
491
510
  });
492
511
  }
493
- const usedDiscounts = /* @__PURE__ */ new Map();
494
- const usedProductIdCounts = /* @__PURE__ */ new Map();
495
- const discountApplicability = /* @__PURE__ */ new Map();
496
- const discountApplicableProducts = /* @__PURE__ */ new Map();
497
- addModeDiscount.forEach((discount) => {
512
+
513
+ /**
514
+ // 对productList按价格降序排序(用于应用优惠券时优先选择高价商品) 价格相同时使用quantity 排序
515
+ const sortedProductList = [...productList].sort((a, b) => {
516
+ const aProduct = this.hooks.getProduct(a);
517
+ const bProduct = this.hooks.getProduct(b);
518
+ const priceA = new Decimal((aProduct.price as string) || '0');
519
+ const priceB = new Decimal((bProduct.price as string) || '0');
520
+ if (priceA.toNumber() === priceB.toNumber()) {
521
+ if (aProduct.quantity === bProduct.quantity) {
522
+ return bProduct.discount_list?.length - aProduct.discount_list?.length;
523
+ }
524
+ return aProduct.quantity - bProduct.quantity;
525
+ }
526
+ return priceB.toNumber() - priceA.toNumber();
527
+ });
528
+ */
529
+
530
+ // 标记已使用的优惠券
531
+ const usedDiscounts = new Map();
532
+
533
+ // 🔥 统计每个 product_id(商品券商品id)已使用的数量,用于 maxUsagePerOrder 限制
534
+ const usedProductIdCounts = new Map();
535
+
536
+ // 记录每个优惠券适用的商品ID
537
+ const discountApplicability = new Map();
538
+
539
+ // 记录每个优惠券适用的商品详细信息
540
+ const discountApplicableProducts = new Map();
541
+
542
+ // 初始化每个优惠券的适用性和可抵扣商品
543
+ addModeDiscount.forEach(discount => {
498
544
  discountApplicability.set(discount.id, []);
499
545
  discountApplicableProducts.set(discount.id, []);
500
546
  });
501
- const orderLevelDiscountAllocations = /* @__PURE__ */ new Map();
502
- const orderLevelDiscountApplicableItems = /* @__PURE__ */ new Map();
503
- const itemApplicableDiscounts = /* @__PURE__ */ new Map();
547
+
548
+ // 预处理 order_level 固定金额折扣卡的分摊信息
549
+ // Map<discountId, Map<productId, { discountAmount, difference }>>
550
+ const orderLevelDiscountAllocations = new Map();
551
+
552
+ // 第一步:收集所有被勾选的 order_level 折扣卡及其适用商品
553
+ // Map<discountId, Set<flatItemId>> - 记录每个折扣卡适用的商品
554
+ const orderLevelDiscountApplicableItems = new Map();
555
+ // Map<flatItemId, Set<discountId>> - 记录每个商品可以被哪些折扣卡使用
556
+ const itemApplicableDiscounts = new Map();
557
+
558
+ // 辅助函数:检查商品是否对某个折扣卡可用
504
559
  const checkItemApplicableForDiscount = (flatItem, discount) => {
505
- var _a2, _b, _c, _d, _e, _f, _g, _h;
506
560
  let product;
507
- if (flatItem.type === "main") {
561
+ if (flatItem.type === 'main') {
508
562
  product = flatItem.product;
509
563
  } else {
510
564
  product = {
@@ -515,30 +569,41 @@ var RulesModule = class extends import_BaseModule.BaseModule {
515
569
  num: flatItem.num,
516
570
  booking_id: flatItem.booking_id,
517
571
  discount_list: flatItem.discount_list || [],
518
- startDate: (_a2 = flatItem.parentProduct) == null ? void 0 : _a2.startDate
572
+ startDate: flatItem.parentProduct?.startDate
519
573
  };
520
574
  }
521
575
  if (this.isItemRewardProductDiscount(product)) {
522
576
  return false;
523
577
  }
524
- const isAvailableProduct = flatItem.type === "main" ? !((product == null ? void 0 : product.booking_id) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.length) && ((_c = product == null ? void 0 : product.discount_list) == null ? void 0 : _c.every((d) => d.id && ["good_pass", "discount_card", "product_discount_card"].includes(d.tag || d.type)))) : !((flatItem == null ? void 0 : flatItem.booking_id) && !!((_e = (_d = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _d.discount_list) == null ? void 0 : _e.length) && ((_g = (_f = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _f.discount_list) == null ? void 0 : _g.every((d) => d.id)));
578
+
579
+ // 编辑的商品使用了优惠券不可用
580
+ const isAvailableProduct = flatItem.type === 'main' ? !(product?.booking_id && product?.discount_list?.length && product?.discount_list?.every(d => d.id && ['good_pass', 'discount_card', 'product_discount_card'].includes(d.tag || d.type))) : !(flatItem?.booking_id && !!flatItem?.bundleItem?.discount_list?.length && flatItem?.bundleItem?.discount_list?.every(d => d.id));
525
581
  if (!isAvailableProduct) {
526
582
  return false;
527
583
  }
528
- if ((0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
584
+
585
+ // vouchersApplicable 为 false 的商品不参与订单级别折扣均摊
586
+ if ((0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
529
587
  return false;
530
588
  }
589
+
590
+ // 商品价格为0时不可用
531
591
  if (Number(product.price) <= 0 || !product.price) {
532
592
  return false;
533
593
  }
534
594
  const limitedData = discount.limited_relation_product_data;
535
- const timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length;
595
+
596
+ // 时间限制检查
597
+ const timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
536
598
  if (!timeLimit) {
537
599
  return false;
538
600
  }
601
+
602
+ // 判断商品是否适用
539
603
  let isLimitedProduct = false;
540
- if (limitedData.type === "product_all") {
541
- if (limitedData.filter === 1 && ((_h = limitedData.exclude_product_ids) == null ? void 0 : _h.includes(product.id))) {
604
+ if (limitedData.type === 'product_all') {
605
+ // 全品类,但需要检查是否被排除
606
+ if (limitedData.filter === 1 && limitedData.exclude_product_ids?.includes(product.id)) {
542
607
  isLimitedProduct = false;
543
608
  } else {
544
609
  isLimitedProduct = true;
@@ -546,33 +611,51 @@ var RulesModule = class extends import_BaseModule.BaseModule {
546
611
  } else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) {
547
612
  isLimitedProduct = true;
548
613
  }
614
+
615
+ // 套餐规则检查
549
616
  const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem);
550
617
  return isLimitedProduct && isBundleAvailable;
551
618
  };
552
- const selectedOrderLevelDiscounts = sortedDiscountList.filter((discount) => {
553
- return (0, import_utils3.isOrderLevelFixedAmountDiscount)(discount) && discount.isSelected !== false;
619
+
620
+ // 收集所有被勾选的 order_level 折扣卡及其适用商品
621
+ const selectedOrderLevelDiscounts = sortedDiscountList.filter(discount => {
622
+ return (0, _utils.isOrderLevelFixedAmountDiscount)(discount) && discount.isSelected !== false;
554
623
  });
555
- selectedOrderLevelDiscounts.forEach((discount) => {
556
- const applicableItemIds = /* @__PURE__ */ new Set();
557
- sortedFlattenedList.forEach((flatItem) => {
624
+
625
+ // 遍历所有被勾选的 order_level 折扣卡,建立双向映射
626
+ selectedOrderLevelDiscounts.forEach(discount => {
627
+ const applicableItemIds = new Set();
628
+ sortedFlattenedList.forEach(flatItem => {
558
629
  if (checkItemApplicableForDiscount(flatItem, discount)) {
559
630
  applicableItemIds.add(flatItem._id);
631
+
632
+ // 记录商品可以被哪些折扣卡使用
560
633
  if (!itemApplicableDiscounts.has(flatItem._id)) {
561
- itemApplicableDiscounts.set(flatItem._id, /* @__PURE__ */ new Set());
634
+ itemApplicableDiscounts.set(flatItem._id, new Set());
562
635
  }
563
636
  itemApplicableDiscounts.get(flatItem._id).add(discount.id);
564
637
  }
565
638
  });
566
639
  orderLevelDiscountApplicableItems.set(discount.id, applicableItemIds);
567
640
  });
568
- const occupiedItems = /* @__PURE__ */ new Map();
569
- selectedOrderLevelDiscounts.forEach((discount) => {
641
+
642
+ // 专属折扣卡定义:限定了特定商品(product_ids),而不是全品类(product_all)的折扣卡
643
+ // 如果专属折扣卡被勾选,它适用的商品会被占用,其他折扣卡均摊时应排除这些商品
644
+ // Map<flatItemId, discountId> - 记录被占用的商品及其对应的折扣卡
645
+ const occupiedItems = new Map();
646
+
647
+ // 按排序顺序遍历折扣卡,判断哪些是专属折扣卡
648
+ selectedOrderLevelDiscounts.forEach(discount => {
570
649
  const limitedData = discount.limited_relation_product_data;
571
- const isExclusiveDiscount = limitedData.type !== "product_all";
650
+
651
+ // 判断是否是专属折扣卡(只能用于特定商品,而不是全品类)
652
+ const isExclusiveDiscount = limitedData.type !== 'product_all';
572
653
  if (isExclusiveDiscount) {
654
+ // 专属折扣卡:它适用的所有商品都会被它占用
573
655
  const applicableItems = orderLevelDiscountApplicableItems.get(discount.id);
574
656
  if (applicableItems) {
575
- applicableItems.forEach((itemId) => {
657
+ applicableItems.forEach(itemId => {
658
+ // 如果商品还没被占用,则标记为被当前折扣卡占用
576
659
  if (!occupiedItems.has(itemId)) {
577
660
  occupiedItems.set(itemId, discount.id);
578
661
  }
@@ -580,22 +663,27 @@ var RulesModule = class extends import_BaseModule.BaseModule {
580
663
  }
581
664
  }
582
665
  });
583
- sortedDiscountList.forEach((discount) => {
584
- if (!(0, import_utils3.isOrderLevelFixedAmountDiscount)(discount)) {
666
+
667
+ // 🔥 第三步:识别 order_level 折扣卡并预计算分摊(排除被其他专属折扣卡占用的商品)
668
+ sortedDiscountList.forEach(discount => {
669
+ if (!(0, _utils.isOrderLevelFixedAmountDiscount)(discount)) {
585
670
  return;
586
671
  }
672
+
673
+ // 收集该折扣卡适用的商品(排除被其他专属折扣卡占用的商品)
587
674
  const applicableProducts = [];
588
- sortedFlattenedList.forEach((flatItem) => {
589
- var _a2, _b, _c;
675
+ sortedFlattenedList.forEach(flatItem => {
676
+ // 🔥 检查该商品是否被其他专属折扣卡占用
590
677
  const occupyingDiscountId = occupiedItems.get(flatItem._id);
591
- if (occupyingDiscountId !== void 0 && occupyingDiscountId !== discount.id) {
678
+ if (occupyingDiscountId !== undefined && occupyingDiscountId !== discount.id) {
679
+ // 该商品被其他专属折扣卡占用,跳过
592
680
  return;
593
681
  }
594
682
  if (!checkItemApplicableForDiscount(flatItem, discount)) {
595
683
  return;
596
684
  }
597
685
  let product;
598
- if (flatItem.type === "main") {
686
+ if (flatItem.type === 'main') {
599
687
  product = flatItem.product;
600
688
  } else {
601
689
  product = {
@@ -606,32 +694,51 @@ var RulesModule = class extends import_BaseModule.BaseModule {
606
694
  num: flatItem.num
607
695
  };
608
696
  }
609
- const quantity = flatItem.type === "main" ? product.num || product.quantity || 1 : (product.num || product.quantity || 1) * (((_a2 = flatItem.parentProduct) == null ? void 0 : _a2.num) || ((_b = flatItem.parentProduct) == null ? void 0 : _b.quantity) || 1);
610
- const originalAmount = flatItem.type === "main" ? Number(product.price ?? 0) : Number(flatItem.original_price ?? flatItem.price ?? 0);
697
+
698
+ // 对于 bundle 子商品,quantity 需要乘以主商品的购买数量
699
+ const quantity = flatItem.type === 'main' ? product.num || product.quantity || 1 : (product.num || product.quantity || 1) * (flatItem.parentProduct?.num || flatItem.parentProduct?.quantity || 1);
700
+
701
+ // 对于主商品:使用 price
702
+ // 对于子商品:优先使用 flatItem.original_price,否则使用 flatItem.price
703
+ const originalAmount = flatItem.type === 'main' ? Number(product.price ?? 0) : Number(flatItem.original_price ?? flatItem.price ?? 0);
704
+
705
+ // 传递 parentQuantity 用于差值处理时判断是否是真正的"数量为1"
611
706
  const productData = {
612
707
  productId: flatItem._id,
613
708
  amount: originalAmount,
614
- quantity
709
+ quantity: quantity
615
710
  };
616
- if (flatItem.type === "bundle") {
617
- productData.parentQuantity = ((_c = flatItem.parentProduct) == null ? void 0 : _c.quantity) || 1;
711
+
712
+ // 子商品需要传递主商品数量
713
+ if (flatItem.type === 'bundle') {
714
+ productData.parentQuantity = flatItem.parentProduct?.quantity || 1;
618
715
  }
619
716
  applicableProducts.push(productData);
620
717
  });
718
+
719
+ // 计算分摊
621
720
  if (applicableProducts.length > 0) {
622
- const allocation = (0, import_utils4.calculateOrderLevelDiscountAllocation)(discount, applicableProducts);
721
+ const allocation = (0, _utils.calculateOrderLevelDiscountAllocation)(discount, applicableProducts);
623
722
  orderLevelDiscountAllocations.set(discount.id, allocation);
624
723
  }
625
724
  });
626
- const processedProductsMap = /* @__PURE__ */ new Map();
627
- const appliedDiscountProducts = /* @__PURE__ */ new Map();
628
- sortedFlattenedList.forEach((flatItem) => {
629
- var _a2;
725
+
726
+ // 处理后的商品列表(按排序后的顺序处理,记录优惠信息)
727
+ const processedProductsMap = new Map();
728
+
729
+ // 记录已应用优惠券的商品信息
730
+ const appliedDiscountProducts = new Map();
731
+
732
+ // 首先遍历所有商品和所有优惠券,确定每个优惠券的适用范围,包括isSelected为false的优惠券
733
+ // 🔥 使用扁平化后的列表,包含主商品和bundle子商品
734
+ sortedFlattenedList.forEach(flatItem => {
735
+ // 获取商品数据
630
736
  let product, originProduct;
631
- if (flatItem.type === "main") {
737
+ if (flatItem.type === 'main') {
632
738
  product = flatItem.product;
633
739
  originProduct = flatItem.originProduct;
634
740
  } else {
741
+ // bundle子商品:构造虚拟商品对象
635
742
  product = {
636
743
  _id: flatItem._id,
637
744
  id: flatItem.id,
@@ -642,48 +749,50 @@ var RulesModule = class extends import_BaseModule.BaseModule {
642
749
  origin_total: flatItem.origin_total,
643
750
  booking_id: flatItem.booking_id,
644
751
  discount_list: flatItem.discount_list || [],
645
- startDate: (_a2 = flatItem.parentProduct) == null ? void 0 : _a2.startDate
752
+ startDate: flatItem.parentProduct?.startDate
646
753
  };
647
754
  originProduct = flatItem.originProduct;
648
755
  }
649
756
  const isItemRewardProductDiscount = this.isItemRewardProductDiscount(product);
650
- addModeDiscount.forEach((discount) => {
651
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
652
- const limitedData = discount == null ? void 0 : discount.limited_relation_product_data;
653
- const _tempVar = (flatItem == null ? void 0 : flatItem.type) === "bundle" ? flatItem == null ? void 0 : flatItem.parentProduct : flatItem == null ? void 0 : flatItem.product;
654
- const isHolderMatch = this.checkHolderMatch(
655
- discount,
656
- {
657
- isNeedHolder: resolveIsFormSubject(_tempVar) && !(_tempVar == null ? void 0 : _tempVar.isNormalProduct),
658
- holder_id: (_tempVar == null ? void 0 : _tempVar.holder_id) || product.holder_id
659
- },
660
- holders
661
- );
757
+ addModeDiscount.forEach(discount => {
758
+ const limitedData = discount?.limited_relation_product_data;
759
+ // 拿到discount配置的holder信息 product信息 product.holder 加在 isLimitedProduct
760
+ const _tempVar = flatItem?.type === 'bundle' ? flatItem?.parentProduct : flatItem?.product;
761
+ const isHolderMatch = this.checkHolderMatch(discount, {
762
+ isNeedHolder: resolveIsFormSubject(_tempVar) && !_tempVar?.isNormalProduct,
763
+ holder_id: _tempVar?.holder_id || product.holder_id
764
+ }, holders);
662
765
  let timeLimit = true;
663
- timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length;
664
- const isLimitedProduct = (limitedData.type === "product_all" && limitedData.filter !== 1 || limitedData.type === "product_all" && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
665
- const isAvailableProduct = flatItem.type === "main" ? !((product == null ? void 0 : product.booking_id) && ((_a3 = product == null ? void 0 : product.discount_list) == null ? void 0 : _a3.length) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.every(
666
- (discount2) => discount2.id && [
667
- "good_pass",
668
- "discount_card",
669
- "product_discount_card"
670
- ].includes(discount2.tag || discount2.type)
671
- ))) : !((flatItem == null ? void 0 : flatItem.booking_id) && !!((_d = (_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.discount_list) == null ? void 0 : _d.length) && ((_f = (_e = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _e.discount_list) == null ? void 0 : _f.every((discount2) => discount2.id)));
766
+ timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
767
+ // 是符合折扣的商品
768
+ const isLimitedProduct = (limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
769
+
770
+ // 编辑的商品 使用了优惠券不可用
771
+ const isAvailableProduct = flatItem.type === 'main' ? !(product?.booking_id && product?.discount_list?.length && product?.discount_list?.every(discount => discount.id && ['good_pass', 'discount_card', 'product_discount_card'].includes(discount.tag || discount.type))) : !(flatItem?.booking_id && !!flatItem?.bundleItem?.discount_list?.length && flatItem?.bundleItem?.discount_list?.every(discount => discount.id));
772
+
773
+ // 套餐是否可用判断
672
774
  const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem);
673
- if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && ((_g = discount.config) == null ? void 0 : _g.isAvailable)) {
674
- (_h = discountApplicability.get(discount.id)) == null ? void 0 : _h.push(product.id);
775
+
776
+ // 判断优惠券是否适用于该商品
777
+ if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && discount.config?.isAvailable) {
778
+ // 记录此优惠券适用的商品
779
+ discountApplicability.get(discount.id)?.push(product.id);
780
+
781
+ // 记录可抵扣的商品详情
675
782
  const applicableProducts = discountApplicableProducts.get(discount.id) || [];
676
783
  const discountType = discount.tag || discount.type;
677
- const isGoodPass = discountType === "good_pass";
678
- const num = isGoodPass || (flatItem == null ? void 0 : flatItem.type) === "main" ? 1 : product.num;
784
+ const isGoodPass = discountType === 'good_pass';
785
+
786
+ // 使用数量
787
+ const num = isGoodPass || flatItem?.type === 'main' ? 1 : product.num;
679
788
  const productData = {
680
789
  amount: product.price * num,
681
790
  type: discountType,
682
791
  tag: discountType,
683
792
  discount: {
684
- discount_card_type: (_i = discount == null ? void 0 : discount.metadata) == null ? void 0 : _i.discount_card_type,
793
+ discount_card_type: discount?.metadata?.discount_card_type,
685
794
  fixed_amount: product.price,
686
- discount_calculation_mode: (_j = discount == null ? void 0 : discount.metadata) == null ? void 0 : _j.discount_calculation_mode,
795
+ discount_calculation_mode: discount?.metadata?.discount_calculation_mode,
687
796
  resource_id: discount.id,
688
797
  title: discount.format_title,
689
798
  original_amount: product.price || product.origin_total,
@@ -692,8 +801,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
692
801
  discount_product_id: discount.product_id
693
802
  },
694
803
  metadata: {
695
- num,
696
- discount_rule_uncheck_flag: discount == null ? void 0 : discount.discount_rule_uncheck_flag
804
+ num: num,
805
+ discount_rule_uncheck_flag: discount?.discount_rule_uncheck_flag
697
806
  }
698
807
  };
699
808
  applicableProducts.push(productData);
@@ -701,58 +810,79 @@ var RulesModule = class extends import_BaseModule.BaseModule {
701
810
  }
702
811
  });
703
812
  });
704
- const processedFlatItemsMap = /* @__PURE__ */ new Map();
705
- const applyDiscountToOptions = (options2, discount) => {
706
- if (!(options2 == null ? void 0 : options2.length))
707
- return { discountedOptions: options2, optionDiscountAmount: 0 };
813
+
814
+ // 🔥 用于存储扁平化商品处理结果的Map
815
+ const processedFlatItemsMap = new Map();
816
+
817
+ // 🔥 Option 折扣辅助函数
818
+ const applyDiscountToOptions = (options, discount) => {
819
+ if (!options?.length) return {
820
+ discountedOptions: options,
821
+ optionDiscountAmount: 0
822
+ };
708
823
  let optionDiscountAmount = 0;
709
- const discountedOptions = options2.map((option) => {
824
+ const discountedOptions = options.map(option => {
825
+ // 折前单价:优先 price,缺失再 add_price;已写回折后价时用 _original_price(或旧字段 _original_add_price)
710
826
  const rawUnit = option._original_price ?? option._original_add_price ?? option.price ?? option.add_price;
711
827
  const baseUnitNum = Number(rawUnit ?? 0);
712
- if (baseUnitNum <= 0)
713
- return option;
714
- const discountedPrice = (0, import_utils.getDiscountAmount)(discount, baseUnitNum, baseUnitNum);
828
+ if (baseUnitNum <= 0) return option;
829
+ const discountedPrice = (0, _utils.getDiscountAmount)(discount, baseUnitNum, baseUnitNum);
715
830
  const optQty = Number(option.num ?? option.quantity ?? 1);
716
- optionDiscountAmount = new import_decimal.default(optionDiscountAmount).plus(new import_decimal.default(baseUnitNum).minus(discountedPrice).mul(optQty)).toNumber();
717
- const { _original_add_price, ...rest } = option;
831
+ optionDiscountAmount = new _decimal.default(optionDiscountAmount).plus(new _decimal.default(baseUnitNum).minus(discountedPrice).mul(optQty)).toNumber();
832
+ const {
833
+ _original_add_price,
834
+ ...rest
835
+ } = option;
718
836
  const tmpl = rest.price ?? rest.add_price;
719
- const nextPrice = typeof tmpl === "string" ? String(discountedPrice) : discountedPrice;
837
+ const nextPrice = typeof tmpl === 'string' ? String(discountedPrice) : discountedPrice;
720
838
  return {
721
839
  ...rest,
722
- _original_price: option._original_price ?? (_original_add_price !== void 0 ? _original_add_price : rawUnit),
840
+ _original_price: option._original_price ?? (_original_add_price !== undefined ? _original_add_price : rawUnit),
723
841
  price: nextPrice
724
842
  };
725
843
  });
726
- return { discountedOptions, optionDiscountAmount };
844
+ return {
845
+ discountedOptions,
846
+ optionDiscountAmount
847
+ };
727
848
  };
728
- const restoreOptionPrices = (options2) => {
729
- if (!(options2 == null ? void 0 : options2.length))
730
- return options2;
731
- return options2.map((option) => {
732
- const orig = option._original_price !== void 0 ? option._original_price : option._original_add_price;
733
- if (orig !== void 0) {
734
- const { _original_price, _original_add_price, ...rest } = option;
735
- return { ...rest, price: orig };
849
+ const restoreOptionPrices = options => {
850
+ if (!options?.length) return options;
851
+ return options.map(option => {
852
+ const orig = option._original_price !== undefined ? option._original_price : option._original_add_price;
853
+ if (orig !== undefined) {
854
+ const {
855
+ _original_price,
856
+ _original_add_price,
857
+ ...rest
858
+ } = option;
859
+ return {
860
+ ...rest,
861
+ price: orig
862
+ };
736
863
  }
737
864
  return option;
738
865
  });
739
866
  };
740
- const getOptionTotal = (options2) => {
741
- if (!(options2 == null ? void 0 : options2.length))
742
- return 0;
743
- return options2.reduce((sum, opt) => {
867
+ const getOptionTotal = options => {
868
+ if (!options?.length) return 0;
869
+ return options.reduce((sum, opt) => {
744
870
  const unit = Number(opt.price ?? opt.add_price ?? 0);
745
871
  const n = Number(opt.num ?? opt.quantity ?? 1);
746
- return new import_decimal.default(sum).plus(new import_decimal.default(unit).mul(n)).toNumber();
872
+ return new _decimal.default(sum).plus(new _decimal.default(unit).mul(n)).toNumber();
747
873
  }, 0);
748
874
  };
875
+
876
+ // 然后再处理应用哪些优惠券,此时只考虑filteredDiscountList中的优惠券
877
+ // 🔥 使用扁平化后的列表进行处理
749
878
  sortedFlattenedList.forEach((flatItem, index) => {
750
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;
879
+ // 获取商品数据
751
880
  let product, originProduct;
752
- if (flatItem.type === "main") {
881
+ if (flatItem.type === 'main') {
753
882
  product = flatItem.product;
754
883
  originProduct = flatItem.originProduct;
755
884
  } else {
885
+ // bundle子商品
756
886
  product = {
757
887
  _id: flatItem._id,
758
888
  id: flatItem.id,
@@ -760,64 +890,64 @@ var RulesModule = class extends import_BaseModule.BaseModule {
760
890
  quantity: flatItem.quantity,
761
891
  num: flatItem.num,
762
892
  total: flatItem.total,
763
- original_price: (_a2 = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _a2.original_price,
764
- origin_total: (_b = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _b.original_price,
893
+ original_price: flatItem?.bundleItem?.original_price,
894
+ origin_total: flatItem?.bundleItem?.original_price,
765
895
  booking_id: flatItem.booking_id,
766
- discount_list: ((_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.discount_list) || [],
767
- startDate: (_d = flatItem.parentProduct) == null ? void 0 : _d.startDate
896
+ discount_list: flatItem?.bundleItem?.discount_list || [],
897
+ startDate: flatItem.parentProduct?.startDate
768
898
  };
769
899
  originProduct = flatItem.originProduct;
770
900
  }
771
- const isPersistedProduct = (product == null ? void 0 : product.booking_id) || (originProduct == null ? void 0 : originProduct.order_detail_id) || (originProduct == null ? void 0 : originProduct.orderDetailId) || (originProduct == null ? void 0 : originProduct.booking_id);
772
- const hasExistingWalletDiscount = ((_e = product.discount_list) == null ? void 0 : _e.length) && ((_f = product == null ? void 0 : product.discount_list) == null ? void 0 : _f.every((discount) => {
773
- var _a3;
774
- const discountIdentity = discount.id ?? ((_a3 = discount.discount) == null ? void 0 : _a3.resource_id);
901
+ const isPersistedProduct = product?.booking_id || originProduct?.order_detail_id || originProduct?.orderDetailId || originProduct?.booking_id;
902
+ const hasExistingWalletDiscount = product.discount_list?.length && product?.discount_list?.every(discount => {
903
+ const discountIdentity = discount.id ?? discount.discount?.resource_id;
775
904
  const discountType = discount.tag || discount.type;
776
- return Boolean(
777
- discountIdentity && ["good_pass", "discount_card", "product_discount_card"].includes(
778
- discountType
779
- )
780
- );
781
- }));
905
+ return Boolean(discountIdentity && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType));
906
+ });
907
+
908
+ // 已持久化且已有钱包券/折扣卡的商品行跳过,保留后端历史折扣结果。
782
909
  if (isPersistedProduct && hasExistingWalletDiscount) {
783
- if (flatItem.type === "main") {
910
+ if (flatItem.type === 'main') {
784
911
  processedProductsMap.set(product._id, [originProduct]);
785
912
  }
913
+ // bundle 虚拟项没有携带完整的历史价格字段。这里不写入 processed map,
914
+ // 重组阶段会直接保留原始 bundleItem,避免把 bundle_selling_price
915
+ // 覆盖为未折扣的 price,导致已支付金额再次进入应付。
786
916
  return;
787
917
  }
788
- const applicableDiscounts = sortedDiscountList.filter((discount) => {
789
- var _a3, _b2, _c2, _d2;
790
- if (this.isItemRewardProductDiscount(product))
791
- return false;
918
+
919
+ // 找到适用于此商品的所有优惠券,仅考虑isSelected不为false的优惠券
920
+ const applicableDiscounts = sortedDiscountList.filter(discount => {
921
+ if (this.isItemRewardProductDiscount(product)) return false;
922
+ // 🔥 检查策略可用性(针对 good_pass 和折扣卡)
792
923
  const discountType = discount.tag || discount.type;
793
924
  const currentOriginUid = getOriginProductUid(originProduct);
794
925
  const isReapplyEditModeDiscountForProduct = discount.isEditMode && reapplyBookingDiscountProductUids.size > 0 && currentOriginUid && reapplyBookingDiscountProductUids.has(String(currentOriginUid)) && discount.isSelected === true;
795
926
  if (discount.isEditMode && reapplyBookingDiscountProductUids.size > 0) {
796
927
  const uid = currentOriginUid;
797
- if (!uid || !reapplyBookingDiscountProductUids.has(uid))
798
- return false;
799
- if (!discount.isSelected)
800
- return false;
928
+ if (!uid || !reapplyBookingDiscountProductUids.has(uid)) return false;
929
+ if (!discount.isSelected) return false;
801
930
  }
802
- if (["good_pass", "discount_card", "product_discount_card"].includes(
803
- discountType
804
- ) && !isReapplyEditModeDiscountForProduct) {
805
- if (discount.config === void 0 || !((_a3 = discount == null ? void 0 : discount.config) == null ? void 0 : _a3.isAvailable)) {
931
+ if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType) && !isReapplyEditModeDiscountForProduct) {
932
+ // 如果策略检查后没有config,说明不可用
933
+ if (discount.config === undefined || !discount?.config?.isAvailable) {
806
934
  return false;
807
935
  }
808
936
  }
809
- if ((Number(product.price) <= 0 || !product.price) && !((_b2 = product.discount_list) == null ? void 0 : _b2.length) && (discount.tag || discount.type) === "good_pass")
810
- return false;
811
- if ((Number(product.price) <= 0 || !product.price) && !((_c2 = product.discount_list) == null ? void 0 : _c2.find((n) => {
812
- var _a4;
813
- return ((_a4 = n.discount) == null ? void 0 : _a4.resource_id) === discount.id;
814
- })) && (discount.tag || discount.type) !== "good_pass")
815
- return false;
937
+
938
+ // 如果商品价格为 0,其实不需要使用任何优惠券,直接 return true
939
+ // 商品券时主商品价格为0不可用
940
+ if ((Number(product.price) <= 0 || !product.price) && !product.discount_list?.length && (discount.tag || discount.type) === 'good_pass') return false;
941
+
942
+ // 折扣卡商品价格为0时不可用
943
+ if ((Number(product.price) <= 0 || !product.price) && !product.discount_list?.find(n => n.discount?.resource_id === discount.id) && (discount.tag || discount.type) !== 'good_pass') return false;
944
+ // 如果优惠券已被使用,则跳过
816
945
  const targetUsedDiscounts = usedDiscounts.get(discount.id);
817
- if (targetUsedDiscounts && (discount.tag || discount.type) === "good_pass")
818
- return false;
819
- if ((discount.tag || discount.type) === "good_pass") {
820
- const maxUsagePerOrder = (_d2 = discount.config) == null ? void 0 : _d2.maxUsagePerOrder;
946
+ if (targetUsedDiscounts && (discount.tag || discount.type) === 'good_pass') return false;
947
+
948
+ // 🔥 检查 maxUsagePerOrder 限制:同一 product_id 的商品券使用数量不能超过配置值
949
+ if ((discount.tag || discount.type) === 'good_pass') {
950
+ const maxUsagePerOrder = discount.config?.maxUsagePerOrder;
821
951
  if (maxUsagePerOrder && maxUsagePerOrder > 0) {
822
952
  const currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0;
823
953
  if (currentUsedCount >= maxUsagePerOrder) {
@@ -826,31 +956,33 @@ var RulesModule = class extends import_BaseModule.BaseModule {
826
956
  }
827
957
  }
828
958
  const limitedData = discount.limited_relation_product_data;
829
- const _tempVar = (flatItem == null ? void 0 : flatItem.type) === "bundle" ? flatItem == null ? void 0 : flatItem.parentProduct : flatItem == null ? void 0 : flatItem.product;
830
- const isHolderMatch = this.checkHolderMatch(
831
- discount,
832
- {
833
- isNeedHolder: resolveIsFormSubject(_tempVar) && !(_tempVar == null ? void 0 : _tempVar.isNormalProduct),
834
- holder_id: (_tempVar == null ? void 0 : _tempVar.holder_id) || product.holder_id
835
- },
836
- holders
837
- );
838
- if (!isHolderMatch)
839
- return false;
959
+
960
+ // 拿到discount配置的holder信息 product信息 product.holder 不可用return false
961
+ const _tempVar = flatItem?.type === 'bundle' ? flatItem?.parentProduct : flatItem?.product;
962
+ const isHolderMatch = this.checkHolderMatch(discount, {
963
+ isNeedHolder: resolveIsFormSubject(_tempVar) && !_tempVar?.isNormalProduct,
964
+ holder_id: _tempVar?.holder_id || product.holder_id
965
+ }, holders);
966
+ // 如果 holder 不匹配,则不适用
967
+ if (!isHolderMatch) return false;
840
968
  let timeLimit = true;
841
- timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], (product.startDate || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length;
969
+ timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
842
970
  if (!timeLimit) {
843
971
  return false;
844
972
  }
845
- if (limitedData.type === "product_all") {
973
+
974
+ // 判断优惠券是否适用于该商品
975
+ if (limitedData.type === 'product_all') {
846
976
  if (limitedData.filter === 1 && limitedData.exclude_product_ids.includes(product.id)) {
847
977
  return false;
848
978
  }
979
+ // 检查 package_sub_item_usage_rules
849
980
  if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
850
981
  return false;
851
982
  }
852
983
  return true;
853
984
  } else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) {
985
+ // 检查 package_sub_item_usage_rules
854
986
  if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
855
987
  return false;
856
988
  }
@@ -858,198 +990,135 @@ var RulesModule = class extends import_BaseModule.BaseModule {
858
990
  }
859
991
  return false;
860
992
  });
861
- const explicitlySelectedDiscount = (options == null ? void 0 : options.isSelected) === true && options.discountId !== void 0 ? applicableDiscounts.find((discount) => {
993
+
994
+ // 用户显式点击某张卡券时,本次选择优先于自动排序和扫码默认选择。
995
+ // 目标仍必须在当前商品的 applicableDiscounts 中,因此不会绕过 Holder、时间或商品范围校验。
996
+ const explicitlySelectedDiscount = options?.isSelected === true && options.discountId !== undefined ? applicableDiscounts.find(discount => {
862
997
  const discountType = discount.tag || discount.type;
863
- return String(discount.id) === String(options.discountId) && ["good_pass", "discount_card", "product_discount_card"].includes(
864
- discountType
865
- );
866
- }) : void 0;
867
- const explicitlySelectedDiscountCard = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) !== "good_pass" ? explicitlySelectedDiscount : void 0;
868
- const appliedDiscountCardIds = new Set(
869
- (product.discount_list || []).filter(
870
- (item) => ["discount_card", "product_discount_card"].includes(
871
- (item == null ? void 0 : item.tag) || (item == null ? void 0 : item.type)
872
- )
873
- ).map(
874
- (item) => {
875
- var _a3;
876
- return ((_a3 = item == null ? void 0 : item.discount) == null ? void 0 : _a3.resource_id) ?? (item == null ? void 0 : item.resource_id) ?? (item == null ? void 0 : item.id);
877
- }
878
- ).filter((id) => id !== void 0 && id !== null).map(String)
879
- );
880
- const appliedDiscountCard = (options == null ? void 0 : options.scan) ? void 0 : applicableDiscounts.find((discount) => {
998
+ return String(discount.id) === String(options.discountId) && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType);
999
+ }) : undefined;
1000
+ // 折扣卡会复用于整条商品行;商品券必须继续按单张拆分,不能复用该分支。
1001
+ const explicitlySelectedDiscountCard = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) !== 'good_pass' ? explicitlySelectedDiscount : undefined;
1002
+
1003
+ // 商品数量等变化会触发无 discountId 的重算。只要当前行已应用的折扣卡仍在
1004
+ // applicableDiscounts 中,就应保留该行选择,避免被自动排序中力度更大的卡替换。
1005
+ const appliedDiscountCardIds = new Set((product.discount_list || []).filter(item => ['discount_card', 'product_discount_card'].includes(item?.tag || item?.type)).map(item => item?.discount?.resource_id ?? item?.resource_id ?? item?.id).filter(id => id !== undefined && id !== null).map(String));
1006
+ const appliedDiscountCard = options?.scan ? undefined : applicableDiscounts.find(discount => {
881
1007
  const discountType = discount.tag || discount.type;
882
- return discount.isSelected === true && ["discount_card", "product_discount_card"].includes(discountType) && appliedDiscountCardIds.has(String(discount.id));
1008
+ return discount.isSelected === true && ['discount_card', 'product_discount_card'].includes(discountType) && appliedDiscountCardIds.has(String(discount.id));
883
1009
  });
884
- const scannedSelectedDiscountCard = applicableDiscounts.find(
885
- (n) => n.isScan && n.isSelected && (n.tag || n.type) !== "good_pass"
886
- );
1010
+
1011
+ // 优先级:本次显式选择 > 当前行既有选择 > 扫码选择 > 自动排序第一项。
1012
+ const scannedSelectedDiscountCard = applicableDiscounts.find(n => n.isScan && n.isSelected && (n.tag || n.type) !== 'good_pass');
887
1013
  const selectedDiscountCard = explicitlySelectedDiscountCard || appliedDiscountCard || scannedSelectedDiscountCard;
888
1014
  const selectedDiscount = explicitlySelectedDiscount || selectedDiscountCard || applicableDiscounts[0];
889
- const prioritizedApplicableDiscounts = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) === "good_pass" ? [
890
- explicitlySelectedDiscount,
891
- ...applicableDiscounts.filter(
892
- (discount) => {
893
- const discountType = discount.tag || discount.type;
894
- return discountType === "good_pass" && String(discount.id) !== String(explicitlySelectedDiscount.id);
895
- }
896
- ),
897
- ...applicableDiscounts.filter(
898
- (discount) => (discount.tag || discount.type) !== "good_pass"
899
- )
900
- ] : applicableDiscounts;
1015
+ const prioritizedApplicableDiscounts = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) === 'good_pass' ? [explicitlySelectedDiscount, ...applicableDiscounts.filter(discount => {
1016
+ const discountType = discount.tag || discount.type;
1017
+ return discountType === 'good_pass' && String(discount.id) !== String(explicitlySelectedDiscount.id);
1018
+ }), ...applicableDiscounts.filter(discount => (discount.tag || discount.type) !== 'good_pass')] : applicableDiscounts;
1019
+
1020
+ // 如果是手动折扣,则不适用优惠券
901
1021
  let isManualDiscount = false;
902
1022
  let isItemRewardProductDiscount = false;
903
- if (flatItem.type === "main") {
904
- isManualDiscount = typeof product.isManualDiscount === "boolean" ? product.isManualDiscount : ((_g = product.discount_list) == null ? void 0 : _g.some((item) => item.type === "product")) || product.total != product.origin_total && (product.bundle || []).every(
905
- (item) => {
906
- var _a3;
907
- return !((_a3 = item.discount_list || []) == null ? void 0 : _a3.length);
908
- }
909
- ) && (!((_h = product.discount_list) == null ? void 0 : _h.length) || ((_j = (_i = product == null ? void 0 : product.discount_list) == null ? void 0 : _i.every) == null ? void 0 : _j.call(
910
- _i,
911
- (item) => item.type === "product"
912
- )));
1023
+ if (flatItem.type === 'main') {
1024
+ // 主商品:判断自身是否手动折扣
1025
+ isManualDiscount = typeof product.isManualDiscount === 'boolean' ? product.isManualDiscount : product.discount_list?.some(item => item.type === 'product') || product.total != product.origin_total && (product.bundle || []).every(item => !(item.discount_list || [])?.length) && (!product.discount_list?.length || product?.discount_list?.every?.(item => item.type === 'product'));
913
1026
  isItemRewardProductDiscount = this.isItemRewardProductDiscount(product);
914
1027
  if (product.inPromotion && !isItemRewardProductDiscount) {
915
1028
  isManualDiscount = false;
916
1029
  }
917
1030
  } else {
1031
+ // bundle子商品:判断父主商品是否手动折扣
918
1032
  const parentProduct = flatItem.parentProduct;
919
1033
  if (parentProduct) {
920
- isManualDiscount = typeof parentProduct.isManualDiscount === "boolean" ? parentProduct.isManualDiscount : ((_k = parentProduct.discount_list) == null ? void 0 : _k.some((item) => item.type === "product")) || parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(
921
- (item) => {
922
- var _a3;
923
- return !((_a3 = item.discount_list || []) == null ? void 0 : _a3.length);
924
- }
925
- ) && (!((_l = parentProduct.discount_list) == null ? void 0 : _l.length) || ((_n = (_m = parentProduct == null ? void 0 : parentProduct.discount_list) == null ? void 0 : _m.every) == null ? void 0 : _n.call(
926
- _m,
927
- (item) => item.type === "product"
928
- )));
1034
+ isManualDiscount = typeof parentProduct.isManualDiscount === 'boolean' ? parentProduct.isManualDiscount : parentProduct.discount_list?.some(item => item.type === 'product') || parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(item => !(item.discount_list || [])?.length) && (!parentProduct.discount_list?.length || parentProduct?.discount_list?.every?.(item => item.type === 'product'));
929
1035
  }
930
1036
  }
931
- if (options == null ? void 0 : options.discountId) {
932
- if (flatItem.type === "main" && ((_o = product.discount_list) == null ? void 0 : _o.some(
933
- (item) => {
934
- var _a3;
935
- return ((_a3 = item.discount) == null ? void 0 : _a3.resource_id) === options.discountId;
936
- }
937
- ))) {
1037
+
1038
+ // 勾选时覆盖手动折扣
1039
+ if (options?.discountId) {
1040
+ // 主商品:检查自己的 discount_list
1041
+ if (flatItem.type === 'main' && product.discount_list?.some(item => item.discount?.resource_id === options.discountId)) {
938
1042
  isManualDiscount = false;
939
1043
  }
940
- if (flatItem.type === "bundle") {
941
- if (((_p = product.discount_list) == null ? void 0 : _p.some(
942
- (item) => {
943
- var _a3;
944
- return ((_a3 = item.discount) == null ? void 0 : _a3.resource_id) === options.discountId;
945
- }
946
- )) || ((_r = (_q = flatItem.parentProduct) == null ? void 0 : _q.discount_list) == null ? void 0 : _r.some(
947
- (item) => {
948
- var _a3;
949
- return ((_a3 = item.discount) == null ? void 0 : _a3.resource_id) === options.discountId;
950
- }
951
- ))) {
1044
+ // bundle子商品:检查自己的 discount_list 或父主商品的 discount_list
1045
+ if (flatItem.type === 'bundle') {
1046
+ if (product.discount_list?.some(item => item.discount?.resource_id === options.discountId) || flatItem.parentProduct?.discount_list?.some(item => item.discount?.resource_id === options.discountId)) {
952
1047
  isManualDiscount = false;
953
1048
  }
954
1049
  }
955
1050
  }
956
- if (options == null ? void 0 : options.selectedList) {
957
- if (flatItem.type === "main" && ((_s = product.discount_list) == null ? void 0 : _s.some(
958
- (item) => {
959
- var _a3;
960
- return (_a3 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a3.some(
961
- (n) => {
962
- var _a4;
963
- return n.discountId === ((_a4 = item.discount) == null ? void 0 : _a4.resource_id);
964
- }
965
- );
966
- }
967
- ))) {
1051
+ if (options?.selectedList) {
1052
+ // 主商品:检查自己的 discount_list
1053
+ if (flatItem.type === 'main' && product.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id))) {
968
1054
  isManualDiscount = false;
969
1055
  }
970
- if (flatItem.type === "bundle") {
971
- if (((_t = product.discount_list) == null ? void 0 : _t.some(
972
- (item) => {
973
- var _a3;
974
- return (_a3 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a3.some(
975
- (n) => {
976
- var _a4;
977
- return n.discountId === ((_a4 = item.discount) == null ? void 0 : _a4.resource_id);
978
- }
979
- );
980
- }
981
- )) || ((_v = (_u = flatItem.parentProduct) == null ? void 0 : _u.discount_list) == null ? void 0 : _v.some(
982
- (item) => {
983
- var _a3;
984
- return (_a3 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a3.some(
985
- (n) => {
986
- var _a4;
987
- return n.discountId === ((_a4 = item.discount) == null ? void 0 : _a4.resource_id);
988
- }
989
- );
990
- }
991
- ))) {
1056
+ // bundle子商品:检查自己的 discount_list 或父主商品的 discount_list
1057
+ if (flatItem.type === 'bundle') {
1058
+ if (product.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id)) || flatItem.parentProduct?.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id))) {
992
1059
  isManualDiscount = false;
993
1060
  }
994
1061
  }
995
1062
  }
996
- if (applicableDiscounts.length === 0 || isManualDiscount || (0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
997
- if (flatItem.type === "main") {
1063
+
1064
+ // 如果没有适用的优惠券,或者手动折扣,则不适用优惠券
1065
+ if (applicableDiscounts.length === 0 || isManualDiscount || (0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
1066
+ if (flatItem.type === 'main') {
1067
+ // 主商品:保持原有逻辑,还原 option 价格
998
1068
  const restoredOptions = restoreOptionPrices(product.options);
999
1069
  if (product.isClient) {
1000
- processedProductsMap.set(product._id, [
1001
- this.hooks.setProduct(originProduct, {
1002
- ...isManualDiscount ? {} : {
1003
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
1004
- product: {
1005
- original_price: product.original_price
1006
- },
1007
- bundle: product.bundle,
1008
- options: restoredOptions
1009
- }),
1010
- variant: originProduct._productInit.variant,
1011
- original_price: originProduct._productInit.original_price,
1012
- total: (0, import_utils2.getProductTotalPrice)({
1013
- product: {
1014
- price: product.price
1015
- },
1016
- bundle: product.bundle,
1017
- options: restoredOptions
1018
- }),
1019
- price: product.price,
1070
+ processedProductsMap.set(product._id, [this.hooks.setProduct(originProduct, {
1071
+ ...(isManualDiscount ? {} : {
1072
+ origin_total: (0, _utils2.getProductOriginTotalPrice)({
1073
+ product: {
1074
+ original_price: product.original_price
1075
+ },
1076
+ bundle: product.bundle,
1020
1077
  options: restoredOptions
1021
- },
1022
- discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(product.discount_list) : this.filterDiscountListByType(product.discount_list, "promotion")
1023
- })
1024
- ]);
1078
+ }),
1079
+ variant: originProduct._productInit.variant,
1080
+ original_price: originProduct._productInit.original_price,
1081
+ total: (0, _utils2.getProductTotalPrice)({
1082
+ product: {
1083
+ price: product.price
1084
+ },
1085
+ bundle: product.bundle,
1086
+ options: restoredOptions
1087
+ }),
1088
+ price: product.price,
1089
+ options: restoredOptions
1090
+ }),
1091
+ discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(product.discount_list) : this.filterDiscountListByType(product.discount_list, 'promotion')
1092
+ })]);
1025
1093
  } else {
1026
- let total = product.inPromotion ? ((_w = product == null ? void 0 : product._promotion) == null ? void 0 : _w.finalPrice) ?? product.origin_total ?? product.total : product.origin_total ?? product.total;
1094
+ let total = product.inPromotion ? product?._promotion?.finalPrice ?? product.origin_total ?? product.total : product.origin_total ?? product.total;
1027
1095
  let main_product_selling_price = product.price;
1028
- if ((product.discount_list || []).some((item) => item.type === "promotion") || isItemRewardProductDiscount || (0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
1096
+ if ((product.discount_list || []).some(item => item.type === 'promotion') || isItemRewardProductDiscount || (0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
1029
1097
  total = product.total ?? product.origin_total;
1030
1098
  main_product_selling_price = product.main_product_selling_price ?? main_product_selling_price;
1031
1099
  }
1032
- processedProductsMap.set(product._id, [
1033
- this.hooks.setProduct(originProduct, {
1034
- ...isManualDiscount ? {
1035
- price: product.price,
1036
- main_product_selling_price: isItemRewardProductDiscount ? main_product_selling_price : product.price,
1037
- ...isItemRewardProductDiscount ? { total } : {}
1038
- } : {
1039
- _id: product._id.split("___")[0] + "___" + index,
1040
- total,
1041
- price: product.price,
1042
- main_product_selling_price,
1043
- options: restoredOptions
1044
- },
1045
- discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(product.discount_list) : this.filterDiscountListByType(product.discount_list, "promotion")
1046
- })
1047
- ]);
1100
+ processedProductsMap.set(product._id, [this.hooks.setProduct(originProduct, {
1101
+ ...(isManualDiscount ? {
1102
+ price: product.price,
1103
+ main_product_selling_price: isItemRewardProductDiscount ? main_product_selling_price : product.price,
1104
+ ...(isItemRewardProductDiscount ? {
1105
+ total
1106
+ } : {})
1107
+ } : {
1108
+ _id: product._id.split('___')[0] + '___' + index,
1109
+ total,
1110
+ price: product.price,
1111
+ main_product_selling_price,
1112
+ options: restoredOptions
1113
+ }),
1114
+ discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(product.discount_list) : this.filterDiscountListByType(product.discount_list, 'promotion')
1115
+ })]);
1048
1116
  }
1049
1117
  } else {
1118
+ // bundle子商品:保存到扁平化Map
1050
1119
  processedFlatItemsMap.set(flatItem._id, [{
1051
1120
  ...flatItem,
1052
- discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(((_x = flatItem.bundleItem) == null ? void 0 : _x.discount_list) || []) : this.filterDiscountListByType(((_y = flatItem.bundleItem) == null ? void 0 : _y.discount_list) || [], "promotion"),
1121
+ discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(flatItem.bundleItem?.discount_list || []) : this.filterDiscountListByType(flatItem.bundleItem?.discount_list || [], 'promotion'),
1053
1122
  price: isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price,
1054
1123
  processed: true
1055
1124
  }]);
@@ -1057,45 +1126,45 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1057
1126
  return;
1058
1127
  }
1059
1128
  const shouldReapplyBookingDiscountForProduct = shouldReapplyBookingDiscount(originProduct, selectedDiscount);
1060
- if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === "undefined" && !(options == null ? void 0 : options.scan) && !isEditModeAddNewProduct && !shouldReapplyBookingDiscountForProduct) {
1129
+ if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === 'undefined' && !options?.scan && !isEditModeAddNewProduct && !shouldReapplyBookingDiscountForProduct) {
1061
1130
  return;
1062
1131
  }
1063
- const isNeedSplit = (selectedDiscount.tag || selectedDiscount.type) === "good_pass";
1132
+
1133
+ // 是否需要拆分(商品券需要拆分)
1134
+ const isNeedSplit = (selectedDiscount.tag || selectedDiscount.type) === 'good_pass';
1135
+
1136
+ // 需要拆分出来的数量
1064
1137
  const totalQuantity = product.quantity || product.num || 1;
1065
- const availableGoodPassCount = applicableDiscounts.filter(
1066
- (item) => (item.tag || item.type) === "good_pass"
1067
- ).length;
1138
+ const availableGoodPassCount = applicableDiscounts.filter(item => (item.tag || item.type) === 'good_pass').length;
1139
+
1140
+ // 🔥 如果selectedDiscount有config配置,则使用config.maxUsagePerOrder限制使用次数
1068
1141
  let maxUsageLimit = availableGoodPassCount;
1069
1142
  if (selectedDiscount.config && selectedDiscount.config.maxUsagePerOrder) {
1070
- maxUsageLimit = Math.min(
1071
- availableGoodPassCount,
1072
- selectedDiscount.config.maxUsagePerOrder
1073
- );
1143
+ maxUsageLimit = Math.min(availableGoodPassCount, selectedDiscount.config.maxUsagePerOrder);
1074
1144
  }
1075
1145
  const splitCount = isNeedSplit ? Math.min(product.quantity || product.num || 1, maxUsageLimit) : 1;
1076
1146
  const arr = [];
1077
- if (flatItem.type === "main") {
1147
+
1148
+ // 🔥 主商品和bundle子商品分别处理
1149
+ if (flatItem.type === 'main') {
1150
+ // 主商品:保持原有逻辑
1078
1151
  if (splitCount < totalQuantity && isNeedSplit) {
1079
1152
  const remainingQuantity = totalQuantity - splitCount;
1080
- const applicableNonGoodPassById = new Map(
1081
- applicableDiscounts.filter((discount) => (discount.tag || discount.type) !== "good_pass").map((discount) => [String(discount.id), discount])
1082
- );
1083
- const remainderDiscountList = (product.discount_list || []).filter((discount) => {
1084
- var _a3;
1153
+ const applicableNonGoodPassById = new Map(applicableDiscounts.filter(discount => (discount.tag || discount.type) !== 'good_pass').map(discount => [String(discount.id), discount]));
1154
+ const remainderDiscountList = (product.discount_list || []).filter(discount => {
1085
1155
  const discountType = discount.tag || discount.type;
1086
- if (discountType === "promotion")
1087
- return true;
1088
- if (discountType === "good_pass")
1089
- return false;
1090
- const resourceId = ((_a3 = discount.discount) == null ? void 0 : _a3.resource_id) ?? discount.id;
1091
- return resourceId !== void 0 && resourceId !== null && applicableNonGoodPassById.has(String(resourceId));
1092
- }).map((discount) => {
1093
- var _a3;
1094
- if ((discount.tag || discount.type) === "promotion")
1095
- return discount;
1096
- const resourceId = ((_a3 = discount.discount) == null ? void 0 : _a3.resource_id) ?? discount.id;
1156
+ if (discountType === 'promotion') return true;
1157
+ if (discountType === 'good_pass') return false;
1158
+ const resourceId = discount.discount?.resource_id ?? discount.id;
1159
+ return resourceId !== undefined && resourceId !== null && applicableNonGoodPassById.has(String(resourceId));
1160
+ }).map(discount => {
1161
+ if ((discount.tag || discount.type) === 'promotion') return discount;
1162
+ const resourceId = discount.discount?.resource_id ?? discount.id;
1097
1163
  const matchedDiscount = applicableNonGoodPassById.get(String(resourceId));
1098
1164
  if (matchedDiscount) {
1165
+ // 实际场景:3 件折扣卡商品中拆出 1 件改用商品券后,
1166
+ // 剩余 2 件仍在使用原折扣卡;必须同步登记折扣卡的使用状态,
1167
+ // 否则 updatedDiscountList 会把它改成未选中并清空 savedAmount。
1099
1168
  usedDiscounts.set(matchedDiscount.id, true);
1100
1169
  const appliedProducts = appliedDiscountProducts.get(matchedDiscount.id) || [];
1101
1170
  appliedProducts.push({
@@ -1110,48 +1179,57 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1110
1179
  _num: remainingQuantity
1111
1180
  };
1112
1181
  });
1113
- const hasRetainedWalletDiscount = remainderDiscountList.some(
1114
- (discount) => !["promotion", "good_pass"].includes(discount.tag || discount.type)
1115
- );
1182
+ const hasRetainedWalletDiscount = remainderDiscountList.some(discount => !['promotion', 'good_pass'].includes(discount.tag || discount.type));
1116
1183
  let total = product.origin_total ?? product.total;
1117
- if ((product.discount_list || []).some((item) => item.type === "promotion")) {
1184
+ if ((product.discount_list || []).some(item => item.type === 'promotion')) {
1118
1185
  total = product.total ?? product.origin_total;
1119
1186
  }
1120
- arr.push(
1121
- this.hooks.setProduct(originProduct, {
1122
- // 商品券只替换被拆出的 splitCount 件。余量行原本仍有效的折扣卡
1123
- // 不能随 good_pass 拆分一起清除;已取消或已失效的折扣不会进入此列表。
1124
- discount_list: remainderDiscountList,
1125
- quantity: remainingQuantity,
1126
- _id: product._id.split("___")[0],
1127
- total,
1128
- // 保留余量行当前的折后主价;Order.applyProductDiscountPrices 随后会基于
1129
- // source_product_price + discount_list 再归一化,避免出现重复折扣。
1130
- ...hasRetainedWalletDiscount ? {
1131
- main_product_selling_price: product.main_product_selling_price ?? product.price
1132
- } : {}
1133
- })
1134
- );
1187
+ arr.push(this.hooks.setProduct(originProduct, {
1188
+ // 商品券只替换被拆出的 splitCount 件。余量行原本仍有效的折扣卡
1189
+ // 不能随 good_pass 拆分一起清除;已取消或已失效的折扣不会进入此列表。
1190
+ discount_list: remainderDiscountList,
1191
+ quantity: remainingQuantity,
1192
+ _id: product._id.split('___')[0],
1193
+ total,
1194
+ // 保留余量行当前的折后主价;Order.applyProductDiscountPrices 随后会基于
1195
+ // source_product_price + discount_list 再归一化,避免出现重复折扣。
1196
+ ...(hasRetainedWalletDiscount ? {
1197
+ main_product_selling_price: product.main_product_selling_price ?? product.price
1198
+ } : {})
1199
+ }));
1135
1200
  }
1136
1201
  for (let i = 0; i < splitCount; i++) {
1137
- const selectedDiscount2 = isNeedSplit ? prioritizedApplicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[i];
1138
- usedDiscounts.set(selectedDiscount2.id, true);
1139
- if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
1140
- const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
1141
- usedProductIdCounts.set(selectedDiscount2.product_id, currentCount + 1);
1202
+ const selectedDiscount = isNeedSplit ? prioritizedApplicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[i];
1203
+ // 标记优惠券为已使用
1204
+ usedDiscounts.set(selectedDiscount.id, true);
1205
+ // 🔥 更新 product_id 使用计数
1206
+ if ((selectedDiscount.tag || selectedDiscount.type) === 'good_pass') {
1207
+ const currentCount = usedProductIdCounts.get(selectedDiscount.product_id) || 0;
1208
+ usedProductIdCounts.set(selectedDiscount.product_id, currentCount + 1);
1142
1209
  }
1143
- const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
1210
+
1211
+ // 记录实际应用了优惠券的商品信息
1212
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount.id) || [];
1213
+
1214
+ // 优先从 origin_total拿,可能会拿不到(比如用户端预约在没有配置 original_price 的情况下)
1144
1215
  let productOriginTotal = product.origin_total || product.total || 0;
1145
- if (this.filterDiscountListByType(product.discount_list, "promotion").length && product.origin_total) {
1216
+ // 如果当前 product discount_list,则先从 origin_total
1217
+ if (this.filterDiscountListByType(product.discount_list, 'promotion').length && product.origin_total) {
1146
1218
  productOriginTotal = product.origin_total;
1147
1219
  }
1148
- if (Number(((_z = originProduct == null ? void 0 : originProduct._productInit) == null ? void 0 : _z.original_price) || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) {
1220
+ // 如果originProduct?._productInit?.original_price 0product.origin_total可能为空,此时取 product.total
1221
+ if (Number(originProduct?._productInit?.original_price || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) {
1149
1222
  productOriginTotal = product.total;
1150
1223
  }
1151
- const isOrderLevel = (0, import_utils3.isOrderLevelFixedAmountDiscount)(selectedDiscount2);
1152
- const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount2.id) : null;
1153
- const productAllocation = orderLevelAllocation == null ? void 0 : orderLevelAllocation.get(flatItem._id);
1154
- const isDeductOptionPrice = !!((_A = selectedDiscount2.config) == null ? void 0 : _A.deductOptionPrice);
1224
+
1225
+ // 计算使用折扣卡/商品券以后,单个商品的总 total
1226
+ // 🔥 检查是否是 order_level 固定金额折扣卡
1227
+ const isOrderLevel = (0, _utils.isOrderLevelFixedAmountDiscount)(selectedDiscount);
1228
+ const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
1229
+ const productAllocation = orderLevelAllocation?.get(flatItem._id);
1230
+ const isDeductOptionPrice = !!selectedDiscount.config?.deductOptionPrice;
1231
+
1232
+ // 主商品折后价(不含 option);勿与 option 合计混在同一变量,否则 main_product_selling_price 错误
1155
1233
  let mainProductSellingPrice;
1156
1234
  let amount;
1157
1235
  let productDiscountDifference;
@@ -1159,146 +1237,154 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1159
1237
  let optionDiscountAmount = 0;
1160
1238
  let reapplyDiscountPercent;
1161
1239
  if (isOrderLevel && productAllocation) {
1240
+ // order_level:使用预计算的分摊金额
1162
1241
  amount = productAllocation.discountAmount;
1163
1242
  productDiscountDifference = productAllocation.difference;
1164
- mainProductSellingPrice = Math.max(new import_decimal.default(product.price).minus(amount).toNumber(), 0);
1165
- } else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2) !== void 0) {
1166
- const percent = resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2);
1167
- reapplyDiscountPercent = new import_decimal.default(percent).toFixed(2);
1168
- mainProductSellingPrice = new import_decimal.default(product.price || 0).mul(new import_decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1169
- amount = new import_decimal.default(product.price).minus(mainProductSellingPrice).toNumber();
1243
+ mainProductSellingPrice = Math.max(new _decimal.default(product.price).minus(amount).toNumber(), 0);
1244
+ } else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount) !== undefined) {
1245
+ // Change time 重套编辑态折扣卡时,历史 par_value 不是运行时折扣口径,优先使用后端快照里的 percent。
1246
+ const percent = resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount);
1247
+ reapplyDiscountPercent = new _decimal.default(percent).toFixed(2);
1248
+ mainProductSellingPrice = new _decimal.default(product.price || 0).mul(new _decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1249
+ amount = new _decimal.default(product.price).minus(mainProductSellingPrice).toNumber();
1170
1250
  } else {
1171
- mainProductSellingPrice = (0, import_utils.getDiscountAmount)(
1172
- selectedDiscount2,
1173
- product.price,
1174
- product.price
1175
- );
1176
- amount = new import_decimal.default(product.price).minus(new import_decimal.default(mainProductSellingPrice)).toNumber();
1251
+ // item_level 或其他类型:使用原有逻辑
1252
+ mainProductSellingPrice = (0, _utils.getDiscountAmount)(selectedDiscount, product.price, product.price);
1253
+ amount = new _decimal.default(product.price).minus(new _decimal.default(mainProductSellingPrice)).toNumber();
1177
1254
  }
1178
- if (isDeductOptionPrice && ((_B = product.options) == null ? void 0 : _B.length)) {
1179
- const optionResult = applyDiscountToOptions(
1180
- product.options,
1181
- selectedDiscount2
1182
- );
1255
+ if (isDeductOptionPrice && product.options?.length) {
1256
+ const optionResult = applyDiscountToOptions(product.options, selectedDiscount);
1183
1257
  discountedOptions = optionResult.discountedOptions;
1184
1258
  optionDiscountAmount = optionResult.optionDiscountAmount;
1185
1259
  }
1186
- const optionsForLineTotal = isDeductOptionPrice && ((_C = product.options) == null ? void 0 : _C.length) ? discountedOptions : product.options;
1260
+
1261
+ // total = 主商品折后 + option 行合计;开启 option 抵扣时必须用 discountedOptions,不能用未折扣的 product.options 再算一遍
1262
+ const optionsForLineTotal = isDeductOptionPrice && product.options?.length ? discountedOptions : product.options;
1187
1263
  const optionsLineTotal = getOptionTotal(optionsForLineTotal || []);
1188
- const total = new import_decimal.default(mainProductSellingPrice).plus(optionsLineTotal).toNumber();
1264
+ const total = new _decimal.default(mainProductSellingPrice).plus(optionsLineTotal).toNumber();
1265
+
1266
+ // discount_list.amount / fixed_amount:行级总优惠 = 主商品优惠 + option 优惠(与 total 变化一致)
1189
1267
  const mainProductDiscountAmount = amount;
1190
- const lineDiscountAmount = new import_decimal.default(mainProductDiscountAmount).plus(optionDiscountAmount).toNumber();
1191
- const discountType = selectedDiscount2.tag || selectedDiscount2.type;
1192
- const isGoodPass = discountType === "good_pass";
1268
+ const lineDiscountAmount = new _decimal.default(mainProductDiscountAmount).plus(optionDiscountAmount).toNumber();
1269
+ const discountType = selectedDiscount.tag || selectedDiscount.type;
1270
+ const isGoodPass = discountType === 'good_pass';
1193
1271
  const discountDetail = {
1194
1272
  amount: lineDiscountAmount,
1195
- type: selectedDiscount2.tag === "product_discount_card" ? "discount_card" : discountType,
1273
+ type: selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : discountType,
1196
1274
  discount: {
1197
- discount_card_type: (_D = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _D.discount_card_type,
1275
+ discount_card_type: selectedDiscount?.metadata?.discount_card_type,
1198
1276
  fixed_amount: lineDiscountAmount,
1199
- discount_calculation_mode: (_E = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _E.discount_calculation_mode,
1200
- resource_id: selectedDiscount2.id,
1201
- title: selectedDiscount2.format_title,
1277
+ discount_calculation_mode: selectedDiscount?.metadata?.discount_calculation_mode,
1278
+ resource_id: selectedDiscount.id,
1279
+ title: selectedDiscount.format_title,
1202
1280
  original_amount: product.price,
1203
1281
  product_id: originProduct.id || originProduct.product_id,
1204
- percent: reapplyDiscountPercent ?? selectedDiscount2.par_value,
1205
- discount_product_id: selectedDiscount2.product_id
1282
+ percent: reapplyDiscountPercent ?? selectedDiscount.par_value,
1283
+ discount_product_id: selectedDiscount.product_id
1206
1284
  },
1207
1285
  // 前端使用的num数量,为了计算优惠金额
1208
1286
  _num: isGoodPass ? 1 : product.num,
1209
- config: selectedDiscount2 == null ? void 0 : selectedDiscount2.config,
1287
+ config: selectedDiscount?.config,
1210
1288
  metadata: {
1211
1289
  num: 1,
1212
- discount_rule_uncheck_flag: selectedDiscount2 == null ? void 0 : selectedDiscount2.discount_rule_uncheck_flag,
1290
+ discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
1213
1291
  // 🔥 order_level 分摊差值
1214
- ...productDiscountDifference !== void 0 && { product_discount_difference: productDiscountDifference },
1292
+ ...(productDiscountDifference !== undefined && {
1293
+ product_discount_difference: productDiscountDifference
1294
+ }),
1215
1295
  /** 仅主商品上的优惠金额(不含 option) */
1216
1296
  mainProductDiscountAmount,
1217
1297
  optionDiscountAmount
1218
1298
  }
1219
1299
  };
1220
1300
  appliedProducts.push(discountDetail);
1221
- appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
1301
+ appliedDiscountProducts.set(selectedDiscount.id, appliedProducts);
1302
+
1303
+ // 记录应用了优惠券的商品
1304
+ // 后续更新价格改为 getProductTotalPrice getProductOriginTotalPrice逻辑
1222
1305
  if (product.isClient) {
1223
- arr.push(
1224
- this.hooks.setProduct(originProduct, {
1225
- discount_list: [discountDetail],
1226
- // good_pass:主商品价以折后价为准;勿用 product.price - amount(amount option 优惠时会算错)
1227
- price: isGoodPass ? mainProductSellingPrice : product.price,
1228
- quantity: isNeedSplit ? 1 : product.quantity,
1229
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
1230
- product: {
1231
- original_price: product.original_price
1232
- },
1233
- bundle: product.bundle,
1234
- options: restoreOptionPrices(product.options)
1235
- }),
1236
- variant: originProduct._productInit.variant,
1237
- original_price: new import_decimal.default(product.price || 0).toNumber(),
1238
- total,
1239
- options: discountedOptions
1240
- })
1241
- );
1306
+ arr.push(this.hooks.setProduct(originProduct, {
1307
+ discount_list: [discountDetail],
1308
+ // good_pass:主商品价以折后价为准;勿用 product.price - amount(amount 含 option 优惠时会算错)
1309
+ price: isGoodPass ? mainProductSellingPrice : product.price,
1310
+ quantity: isNeedSplit ? 1 : product.quantity,
1311
+ origin_total: (0, _utils2.getProductOriginTotalPrice)({
1312
+ product: {
1313
+ original_price: product.original_price
1314
+ },
1315
+ bundle: product.bundle,
1316
+ options: restoreOptionPrices(product.options)
1317
+ }),
1318
+ variant: originProduct._productInit.variant,
1319
+ original_price: new _decimal.default(product.price || 0).toNumber(),
1320
+ total: total,
1321
+ options: discountedOptions
1322
+ }));
1242
1323
  } else {
1243
- arr.push(
1244
- this.hooks.setProduct(originProduct, {
1245
- discount_list: this.filterDiscountListByType(product.discount_list, "promotion").concat([discountDetail]),
1246
- _id: product._id.split("___")[0] + "___" + selectedDiscount2.id + index,
1247
- price: selectedDiscount2.tag === "good_pass" ? 0 : product.price,
1248
- quantity: isNeedSplit ? 1 : product.quantity,
1249
- total,
1250
- origin_total: productOriginTotal,
1251
- main_product_selling_price: mainProductSellingPrice,
1252
- options: discountedOptions
1253
- })
1254
- );
1324
+ arr.push(this.hooks.setProduct(originProduct, {
1325
+ discount_list: this.filterDiscountListByType(product.discount_list, 'promotion').concat([discountDetail]),
1326
+ _id: product._id.split('___')[0] + '___' + selectedDiscount.id + index,
1327
+ price: selectedDiscount.tag === 'good_pass' ? 0 : product.price,
1328
+ quantity: isNeedSplit ? 1 : product.quantity,
1329
+ total: total,
1330
+ origin_total: productOriginTotal,
1331
+ main_product_selling_price: mainProductSellingPrice,
1332
+ options: discountedOptions
1333
+ }));
1255
1334
  }
1256
1335
  }
1257
1336
  processedProductsMap.set(product._id, arr);
1258
1337
  } else {
1338
+ // 🔥 bundle子商品:支持拆分
1259
1339
  const processedItems = [];
1260
1340
  if (isNeedSplit) {
1341
+ // 商品券:需要拆分数量
1261
1342
  const discountNum = splitCount;
1262
1343
  const normalNum = totalQuantity - discountNum;
1344
+
1345
+ // 生成有折扣的商品(每张商品券对应 num: 1)
1263
1346
  for (let i = 0; i < discountNum; i++) {
1264
- const selectedDiscount2 = prioritizedApplicableDiscounts[i];
1265
- usedDiscounts.set(selectedDiscount2.id, true);
1266
- if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
1267
- const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
1268
- usedProductIdCounts.set(selectedDiscount2.product_id, currentCount + 1);
1347
+ const selectedDiscount = prioritizedApplicableDiscounts[i];
1348
+ usedDiscounts.set(selectedDiscount.id, true);
1349
+ // 🔥 更新 product_id 使用计数
1350
+ if ((selectedDiscount.tag || selectedDiscount.type) === 'good_pass') {
1351
+ const currentCount = usedProductIdCounts.get(selectedDiscount.product_id) || 0;
1352
+ usedProductIdCounts.set(selectedDiscount.product_id, currentCount + 1);
1269
1353
  }
1354
+
1355
+ // 🔥 生成唯一的 _id
1270
1356
  const uniqueId = `${flatItem._id}_split_${i}`;
1271
- const discountedPrice = (0, import_utils.getDiscountAmount)(
1272
- selectedDiscount2,
1273
- product.origin_total,
1274
- product.origin_total
1275
- );
1276
- const bundleDiscountAmount = new import_decimal.default(product.origin_total || 0).minus(discountedPrice).toNumber();
1357
+
1358
+ // 计算折扣后的价格(使用 getDiscountAmount,内部已处理 maxDeductionAmount)
1359
+ const discountedPrice = (0, _utils.getDiscountAmount)(selectedDiscount, product.origin_total, product.origin_total);
1360
+ const bundleDiscountAmount = new _decimal.default(product.origin_total || 0).minus(discountedPrice).toNumber();
1277
1361
  debugger;
1278
1362
  const discountDetail = {
1279
1363
  amount: bundleDiscountAmount,
1280
- type: "good_pass",
1364
+ type: 'good_pass',
1281
1365
  discount: {
1282
1366
  fixed_amount: product.origin_total,
1283
- discount_calculation_mode: (_F = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _F.discount_calculation_mode,
1284
- resource_id: selectedDiscount2.id,
1285
- title: selectedDiscount2.format_title,
1367
+ discount_calculation_mode: selectedDiscount?.metadata?.discount_calculation_mode,
1368
+ resource_id: selectedDiscount.id,
1369
+ title: selectedDiscount.format_title,
1286
1370
  original_amount: product.origin_total,
1287
1371
  product_id: product.id || product.product_id,
1288
- discount_product_id: selectedDiscount2.product_id
1372
+ discount_product_id: selectedDiscount.product_id
1289
1373
  },
1290
1374
  metadata: {
1291
1375
  // 🔥 使用拆分后的唯一 _id
1292
1376
  custom_product_bundle_map_id: uniqueId,
1293
- discount_rule_uncheck_flag: selectedDiscount2 == null ? void 0 : selectedDiscount2.discount_rule_uncheck_flag,
1377
+ discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
1294
1378
  num: 1
1295
1379
  },
1296
1380
  _num: 1,
1297
- config: selectedDiscount2 == null ? void 0 : selectedDiscount2.config
1381
+ config: selectedDiscount?.config
1298
1382
  };
1299
- const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
1383
+
1384
+ // 记录实际应用的折扣
1385
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount.id) || [];
1300
1386
  appliedProducts.push(discountDetail);
1301
- appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
1387
+ appliedDiscountProducts.set(selectedDiscount.id, appliedProducts);
1302
1388
  processedItems.push({
1303
1389
  ...flatItem,
1304
1390
  // 🔥 使用唯一的 _id
@@ -1310,9 +1396,11 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1310
1396
  total: discountedPrice,
1311
1397
  discount_list: [discountDetail],
1312
1398
  processed: true,
1313
- _discountId: selectedDiscount2.id
1399
+ _discountId: selectedDiscount.id
1314
1400
  });
1315
1401
  }
1402
+
1403
+ // 生成无折扣的商品(剩余数量)
1316
1404
  if (normalNum > 0) {
1317
1405
  processedItems.push({
1318
1406
  ...flatItem,
@@ -1320,99 +1408,111 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1320
1408
  _id: `${flatItem._id}_split_rest`,
1321
1409
  num: normalNum,
1322
1410
  quantity: normalNum,
1323
- discount_list: this.filterDiscountListByType(flatItem.discount_list, "promotion"),
1411
+ discount_list: this.filterDiscountListByType(flatItem.discount_list, 'promotion'),
1324
1412
  processed: true
1325
1413
  });
1326
1414
  }
1327
1415
  } else {
1328
- const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[0];
1329
- usedDiscounts.set(selectedDiscount2.id, true);
1330
- if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
1331
- const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
1332
- usedProductIdCounts.set(selectedDiscount2.product_id, currentCount + 1);
1416
+ // 折扣卡:不拆分数量,直接应用
1417
+ const selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
1418
+ usedDiscounts.set(selectedDiscount.id, true);
1419
+ // 🔥 更新 product_id 使用计数(虽然此处主要是折扣卡,但保持一致性)
1420
+ if ((selectedDiscount.tag || selectedDiscount.type) === 'good_pass') {
1421
+ const currentCount = usedProductIdCounts.get(selectedDiscount.product_id) || 0;
1422
+ usedProductIdCounts.set(selectedDiscount.product_id, currentCount + 1);
1333
1423
  }
1334
1424
  const productOriginTotal = product.original_price || product.price || 0;
1335
- const isOrderLevel = (0, import_utils3.isOrderLevelFixedAmountDiscount)(selectedDiscount2);
1336
- const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount2.id) : null;
1337
- const productAllocation = orderLevelAllocation == null ? void 0 : orderLevelAllocation.get(flatItem._id);
1425
+
1426
+ // 🔥 检查是否是 order_level 固定金额折扣卡
1427
+ const isOrderLevel = (0, _utils.isOrderLevelFixedAmountDiscount)(selectedDiscount);
1428
+ const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
1429
+ const productAllocation = orderLevelAllocation?.get(flatItem._id);
1338
1430
  let targetProductTotal;
1339
1431
  let fixedAmountPerItem;
1340
1432
  let productDiscountDifference;
1341
1433
  let reapplyDiscountPercent;
1342
1434
  if (isOrderLevel && productAllocation) {
1435
+ // order_level:使用预计算的单价折扣金额(已经是单价,无需再除以数量)
1343
1436
  fixedAmountPerItem = productAllocation.discountAmount;
1344
1437
  productDiscountDifference = productAllocation.difference;
1345
- targetProductTotal = Math.max(new import_decimal.default(productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
1346
- } else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2) !== void 0) {
1347
- const percent = resolveReapplyBookingDiscountPercent(
1348
- originProduct,
1349
- selectedDiscount2
1350
- );
1351
- reapplyDiscountPercent = new import_decimal.default(percent).toFixed(2);
1352
- targetProductTotal = new import_decimal.default(productOriginTotal).mul(new import_decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1353
- fixedAmountPerItem = new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
1438
+ targetProductTotal = Math.max(new _decimal.default(productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
1439
+ } else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount) !== undefined) {
1440
+ // hydrate par_value 可能是余额/原值(例如 3500),百分比口径以
1441
+ // 后端折扣快照 discount.percent 为准,与主商品重套逻辑保持一致。
1442
+ const percent = resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount);
1443
+ reapplyDiscountPercent = new _decimal.default(percent).toFixed(2);
1444
+ targetProductTotal = new _decimal.default(productOriginTotal).mul(new _decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1445
+ fixedAmountPerItem = new _decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
1354
1446
  } else {
1355
- targetProductTotal = (0, import_utils.getDiscountAmount)(
1356
- selectedDiscount2,
1357
- productOriginTotal,
1358
- productOriginTotal
1359
- );
1360
- fixedAmountPerItem = new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
1447
+ // item_level 或其他类型:使用原有逻辑
1448
+ targetProductTotal = (0, _utils.getDiscountAmount)(selectedDiscount, productOriginTotal, productOriginTotal);
1449
+ fixedAmountPerItem = new _decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
1361
1450
  }
1451
+
1452
+ // 🔥 使用当前的 _id 作为唯一标识
1362
1453
  const uniqueId = flatItem._id;
1363
1454
  debugger;
1364
1455
  const discountDetail = {
1365
1456
  amount: fixedAmountPerItem * (product.num || 1),
1366
- type: selectedDiscount2.tag === "product_discount_card" ? "discount_card" : selectedDiscount2.tag,
1457
+ type: selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : selectedDiscount.tag,
1367
1458
  discount: {
1368
- discount_card_type: (_G = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _G.discount_card_type,
1459
+ discount_card_type: selectedDiscount?.metadata?.discount_card_type,
1369
1460
  fixed_amount: fixedAmountPerItem,
1370
- discount_calculation_mode: (_H = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _H.discount_calculation_mode,
1371
- resource_id: selectedDiscount2.id,
1372
- title: selectedDiscount2.format_title,
1461
+ discount_calculation_mode: selectedDiscount?.metadata?.discount_calculation_mode,
1462
+ resource_id: selectedDiscount.id,
1463
+ title: selectedDiscount.format_title,
1373
1464
  original_amount: product.original_price,
1374
1465
  product_id: product.id || product.product_id,
1375
- percent: reapplyDiscountPercent ?? selectedDiscount2.par_value,
1376
- discount_product_id: selectedDiscount2.product_id
1466
+ percent: reapplyDiscountPercent ?? selectedDiscount.par_value,
1467
+ discount_product_id: selectedDiscount.product_id
1377
1468
  },
1378
1469
  metadata: {
1379
1470
  // 🔥 使用唯一的 _id
1380
1471
  custom_product_bundle_map_id: uniqueId,
1381
- discount_rule_uncheck_flag: selectedDiscount2 == null ? void 0 : selectedDiscount2.discount_rule_uncheck_flag,
1472
+ discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
1382
1473
  num: product.num || 1,
1383
1474
  // 🔥 order_level 分摊差值
1384
- ...productDiscountDifference !== void 0 && { product_discount_difference: productDiscountDifference }
1475
+ ...(productDiscountDifference !== undefined && {
1476
+ product_discount_difference: productDiscountDifference
1477
+ })
1385
1478
  },
1386
- config: selectedDiscount2 == null ? void 0 : selectedDiscount2.config,
1387
- _num: (product.num || 1) * (((_I = flatItem == null ? void 0 : flatItem.parentProduct) == null ? void 0 : _I.num) || 1)
1479
+ config: selectedDiscount?.config,
1480
+ _num: (product.num || 1) * (flatItem?.parentProduct?.num || 1)
1388
1481
  };
1389
- const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
1482
+
1483
+ // 记录实际应用的折扣
1484
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount.id) || [];
1390
1485
  appliedProducts.push(discountDetail);
1391
- appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
1486
+ appliedDiscountProducts.set(selectedDiscount.id, appliedProducts);
1392
1487
  processedItems.push({
1393
1488
  ...flatItem,
1394
1489
  total: targetProductTotal,
1395
- price: new import_decimal.default(productOriginTotal || 0).minus(fixedAmountPerItem).toNumber(),
1396
- discount_list: this.filterDiscountListByType(flatItem.discount_list, "promotion").concat([discountDetail]),
1490
+ price: new _decimal.default(productOriginTotal || 0).minus(fixedAmountPerItem).toNumber(),
1491
+ discount_list: this.filterDiscountListByType(flatItem.discount_list, 'promotion').concat([discountDetail]),
1397
1492
  processed: true
1398
1493
  });
1399
1494
  }
1400
1495
  processedFlatItemsMap.set(flatItem._id, processedItems);
1401
1496
  }
1402
1497
  });
1403
- const reconstructProductsWithBundle = (processedProductsMap2, processedFlatItemsMap2, originalProductList) => {
1498
+
1499
+ // 🔥 重组:将处理后的bundle子商品重新组装回主商品
1500
+ const reconstructProductsWithBundle = (processedProductsMap, processedFlatItemsMap, originalProductList) => {
1404
1501
  const result = [];
1405
- originalProductList.forEach((originProduct) => {
1502
+ originalProductList.forEach(originProduct => {
1406
1503
  const product = this.hooks.getProduct(originProduct);
1407
- const mainProductArr = processedProductsMap2.get(product._id);
1504
+
1505
+ // 获取主商品处理结果
1506
+ const mainProductArr = processedProductsMap.get(product._id);
1408
1507
  if (!mainProductArr || mainProductArr.length === 0) {
1508
+ // 如果没有处理结果,返回默认商品(还原 option 价格)
1409
1509
  const getDefaultProduct = () => {
1410
1510
  const restoredOptions = restoreOptionPrices(product.options);
1411
1511
  if (product.isClient) {
1412
1512
  return this.hooks.setProduct(originProduct, {
1413
- discount_list: this.filterDiscountListByType(product.discount_list, "promotion"),
1513
+ discount_list: this.filterDiscountListByType(product.discount_list, 'promotion'),
1414
1514
  price: product.price,
1415
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
1515
+ origin_total: (0, _utils2.getProductOriginTotalPrice)({
1416
1516
  product: {
1417
1517
  original_price: product.original_price
1418
1518
  },
@@ -1421,7 +1521,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1421
1521
  }),
1422
1522
  variant: originProduct._productInit.variant,
1423
1523
  original_price: originProduct._productInit.original_price,
1424
- total: (0, import_utils2.getProductTotalPrice)({
1524
+ total: (0, _utils2.getProductTotalPrice)({
1425
1525
  product: {
1426
1526
  price: product.price
1427
1527
  },
@@ -1432,7 +1532,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1432
1532
  });
1433
1533
  } else {
1434
1534
  return this.hooks.setProduct(originProduct, {
1435
- discount_list: this.filterDiscountListByType(product.discount_list, "promotion"),
1535
+ discount_list: this.filterDiscountListByType(product.discount_list, 'promotion'),
1436
1536
  total: product.total,
1437
1537
  origin_total: product.origin_total,
1438
1538
  price: product.price,
@@ -1443,325 +1543,357 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1443
1543
  result.push(getDefaultProduct());
1444
1544
  return;
1445
1545
  }
1546
+
1547
+ // 检查是否有bundle子商品需要重组
1446
1548
  const hasBundle = product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0;
1447
1549
  if (!hasBundle) {
1550
+ // 没有bundle,直接使用主商品处理结果
1448
1551
  result.push(...mainProductArr);
1449
1552
  } else {
1450
- const bundleProcessingInfo = /* @__PURE__ */ new Map();
1451
- let hasGoodPassApplied = false;
1553
+ // 🔥 有bundle,需要检查子商品是否应用了商品券
1554
+ // 1. 先收集所有bundle子商品的处理结果
1555
+ const bundleProcessingInfo = new Map();
1556
+ let hasGoodPassApplied = false; // 标记是否有子商品应用了商品券
1557
+
1452
1558
  if (product.bundle && Array.isArray(product.bundle)) {
1453
1559
  product.bundle.forEach((bundleItem, bundleIndex) => {
1454
1560
  const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
1455
- const processedBundleItems = processedFlatItemsMap2.get(bundleItemId);
1561
+ const processedBundleItems = processedFlatItemsMap.get(bundleItemId);
1456
1562
  if (!processedBundleItems || processedBundleItems.length === 0) {
1563
+ // 未处理的bundle item,保持原样
1457
1564
  bundleProcessingInfo.set(bundleIndex, [bundleItem]);
1458
1565
  } else {
1566
+ // 处理过的bundle item
1459
1567
  bundleProcessingInfo.set(bundleIndex, processedBundleItems);
1460
- const hasGoodPass = processedBundleItems.some(
1461
- (item) => {
1462
- var _a2;
1463
- return (_a2 = item.discount_list) == null ? void 0 : _a2.some(
1464
- (discount) => discount.type === "good_pass" || discount.tag === "good_pass"
1465
- );
1466
- }
1467
- );
1568
+ // 🔥 检查是否应用了商品券(good_pass)
1569
+ const hasGoodPass = processedBundleItems.some(item => item.discount_list?.some(discount => discount.type === 'good_pass' || discount.tag === 'good_pass'));
1468
1570
  if (hasGoodPass) {
1469
1571
  hasGoodPassApplied = true;
1470
1572
  }
1471
1573
  }
1472
1574
  });
1473
1575
  }
1576
+
1577
+ // 🔥 2. 如果有子商品应用了商品券,且主商品数量大于1,需要拆分主商品
1474
1578
  const mainProductQuantity = mainProductArr[0] ? this.hooks.getProduct(mainProductArr[0]).quantity : 1;
1475
1579
  if (hasGoodPassApplied && mainProductArr.length === 1 && mainProductQuantity > 1) {
1476
1580
  const mainProduct = mainProductArr[0];
1477
1581
  const mainProductData = this.hooks.getProduct(mainProduct);
1582
+
1583
+ // 🔥 方案:拆分成2个主商品
1584
+ // 1. 一个主商品(qty=1)包含拆分后的bundle
1585
+ // 2. 一个主商品(qty=原quantity-1)包含原始未拆分的bundle
1586
+
1587
+ // 第一个:包含拆分后的bundle (qty=1)
1478
1588
  const newBundleWithDiscount = [];
1479
- (product.bundle || []).forEach(
1480
- (bundleItem, bundleIndex) => {
1481
- const processedItems = bundleProcessingInfo.get(
1482
- bundleIndex
1483
- ) || [bundleItem];
1484
- if (processedItems.length > 1) {
1485
- processedItems.forEach((item) => {
1486
- const updatedDiscountList2 = (item.discount_list || []).map((discount) => {
1487
- var _a2;
1488
- return {
1489
- ...discount,
1490
- metadata: {
1491
- ...discount.metadata,
1492
- num: item.num,
1493
- custom_product_bundle_map_id: (_a2 = item.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id
1494
- }
1495
- // num: item.num, // 使用拆分后的 num
1496
- };
1497
- });
1498
- newBundleWithDiscount.push({
1499
- ...bundleItem,
1500
- _id: item._id,
1501
- product_id: bundleItem.product_id,
1502
- price: item.price,
1589
+ (product.bundle || []).forEach((bundleItem, bundleIndex) => {
1590
+ const processedItems = bundleProcessingInfo.get(bundleIndex) || [bundleItem];
1591
+ if (processedItems.length > 1) {
1592
+ // 被拆分的子商品,添加所有拆分项
1593
+ processedItems.forEach(item => {
1594
+ // 🔥 更新 discount_list 中的 num,使其与拆分后的 item.num 一致
1595
+ const updatedDiscountList = (item.discount_list || []).map(discount => ({
1596
+ ...discount,
1597
+ metadata: {
1598
+ ...discount.metadata,
1503
1599
  num: item.num,
1504
- discount_list: updatedDiscountList2
1505
- });
1600
+ custom_product_bundle_map_id: item.metadata?.custom_product_bundle_map_id
1601
+ }
1602
+ // num: item.num, // 使用拆分后的 num
1603
+ }));
1604
+ newBundleWithDiscount.push({
1605
+ ...bundleItem,
1606
+ _id: item._id,
1607
+ product_id: bundleItem.product_id,
1608
+ price: item.price,
1609
+ num: item.num,
1610
+ discount_list: updatedDiscountList
1506
1611
  });
1507
- } else {
1508
- const item = processedItems[0];
1509
- if (item.processed) {
1510
- const updatedDiscountList2 = (item.discount_list || []).map((discount) => {
1511
- var _a2;
1512
- return {
1513
- ...discount,
1514
- metadata: {
1515
- ...discount.metadata,
1516
- num: item.num,
1517
- custom_product_bundle_map_id: (_a2 = item.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id
1518
- }
1519
- // num: item.num, // 使用当前的 num
1520
- };
1521
- });
1522
- newBundleWithDiscount.push({
1523
- ...bundleItem,
1524
- _id: item._id,
1525
- product_id: bundleItem.product_id,
1526
- price: item.price,
1612
+ });
1613
+ } else {
1614
+ // 未拆分的子商品,保持原样
1615
+ const item = processedItems[0];
1616
+ if (item.processed) {
1617
+ // 🔥 同样需要更新 discount_list 中的 num
1618
+ const updatedDiscountList = (item.discount_list || []).map(discount => ({
1619
+ ...discount,
1620
+ metadata: {
1621
+ ...discount.metadata,
1527
1622
  num: item.num,
1528
- discount_list: updatedDiscountList2
1529
- });
1530
- } else {
1531
- newBundleWithDiscount.push(item);
1532
- }
1623
+ custom_product_bundle_map_id: item.metadata?.custom_product_bundle_map_id
1624
+ }
1625
+ // num: item.num, // 使用当前的 num
1626
+ }));
1627
+ newBundleWithDiscount.push({
1628
+ ...bundleItem,
1629
+ _id: item._id,
1630
+ product_id: bundleItem.product_id,
1631
+ price: item.price,
1632
+ num: item.num,
1633
+ discount_list: updatedDiscountList
1634
+ });
1635
+ } else {
1636
+ newBundleWithDiscount.push(item);
1533
1637
  }
1534
1638
  }
1535
- );
1639
+ });
1640
+
1641
+ // 计算第一个主商品的总价(包含拆分后的bundle)
1536
1642
  let newTotalWithDiscount = Number(mainProductData.price || 0);
1537
- let newOriginTotalWithDiscount = Number(
1538
- mainProductData.original_price || mainProductData.price || 0
1539
- );
1540
- const updatedMainDiscountList = mainProductData.discount_list.map((discount) => {
1541
- var _a2, _b;
1542
- if ((_a2 = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id) {
1643
+ let newOriginTotalWithDiscount = Number(mainProductData.original_price || mainProductData.price || 0);
1644
+
1645
+ // 🔥 更新主商品自己的 discount_list 中的 num(quantity=1)
1646
+ const updatedMainDiscountList = mainProductData.discount_list.map(discount => {
1647
+ if (discount?.metadata?.custom_product_bundle_map_id) {
1648
+ // bundle的discount_list保持不变
1543
1649
  return discount;
1544
1650
  }
1651
+ // 主商品自己的discount,更新num为1
1545
1652
  return {
1546
1653
  ...discount,
1547
1654
  // num: 1,
1548
1655
  metadata: {
1549
1656
  ...discount.metadata,
1550
- custom_product_bundle_map_id: (_b = discount == null ? void 0 : discount.metadata) == null ? void 0 : _b.custom_product_bundle_map_id,
1657
+ custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id,
1551
1658
  num: 1
1552
1659
  }
1553
1660
  };
1554
1661
  });
1555
- const mainDiscountList = updatedMainDiscountList.filter(
1556
- (item) => {
1557
- var _a2;
1558
- return !((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id);
1559
- }
1560
- );
1662
+
1663
+ // 🔥 使用更新后的列表计算折扣金额
1664
+ const mainDiscountList = updatedMainDiscountList.filter(item => !item?.metadata?.custom_product_bundle_map_id);
1561
1665
  if (mainDiscountList && mainDiscountList.length > 0) {
1562
- const allDiscountAmount = (0, import_utils.getDiscountListAmountTotal)(mainDiscountList);
1563
- newTotalWithDiscount = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalWithDiscount;
1666
+ const allDiscountAmount = (0, _utils.getDiscountListAmountTotal)(mainDiscountList);
1667
+ newTotalWithDiscount = new _decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalWithDiscount;
1564
1668
  newOriginTotalWithDiscount = mainProductData.origin_total ?? newOriginTotalWithDiscount;
1565
1669
  }
1670
+
1671
+ // 累加bundle的价格(只累加一次)
1566
1672
  if (newBundleWithDiscount.length > 0) {
1567
- newBundleWithDiscount.forEach((item) => {
1673
+ newBundleWithDiscount.forEach(item => {
1568
1674
  newTotalWithDiscount += Number(item.price) * Number(item.num);
1569
1675
  });
1570
- newBundleWithDiscount.forEach((item) => {
1571
- var _a2, _b, _c;
1572
- const originalPrice = ((_c = (_b = (_a2 = item.discount_list) == null ? void 0 : _a2[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
1676
+ newBundleWithDiscount.forEach(item => {
1677
+ const originalPrice = item.discount_list?.[0]?.discount?.original_amount || item.price;
1573
1678
  newOriginTotalWithDiscount += Number(originalPrice) * Number(item.num);
1574
1679
  });
1575
1680
  }
1576
- if (product == null ? void 0 : product.options) {
1681
+
1682
+ // 累加options的价格(options不参与折扣,在最终设置total时处理)
1683
+ if (product?.options) {
1577
1684
  newTotalWithDiscount = product.options.reduce((accumulator, currentValue) => {
1578
- const currentPrice = new import_decimal.default(currentValue.price || 0);
1579
- const currentNum = new import_decimal.default(currentValue.num || 0);
1685
+ const currentPrice = new _decimal.default(currentValue.price || 0);
1686
+ const currentNum = new _decimal.default(currentValue.num || 0);
1580
1687
  return accumulator.add(currentPrice.mul(currentNum));
1581
- }, new import_decimal.default(newTotalWithDiscount)).toNumber();
1688
+ }, new _decimal.default(newTotalWithDiscount)).toNumber();
1582
1689
  }
1583
- result.push(
1584
- this.hooks.setProduct(mainProduct, {
1585
- ...mainProductData,
1586
- _id: `${mainProductData._id.split("___")[0]}___split_discount`,
1587
- quantity: 1,
1588
- discount_list: updatedMainDiscountList,
1589
- bundle: newBundleWithDiscount,
1590
- total: new import_decimal.default(newTotalWithDiscount).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber(),
1591
- origin_total: new import_decimal.default(newOriginTotalWithDiscount).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber()
1592
- })
1593
- );
1690
+
1691
+ // 添加第一个主商品:qty=1,包含拆分后的bundle
1692
+ result.push(this.hooks.setProduct(mainProduct, {
1693
+ ...mainProductData,
1694
+ _id: `${mainProductData._id.split('___')[0]}___split_discount`,
1695
+ quantity: 1,
1696
+ discount_list: updatedMainDiscountList,
1697
+ bundle: newBundleWithDiscount,
1698
+ total: new _decimal.default(newTotalWithDiscount).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber(),
1699
+ origin_total: new _decimal.default(newOriginTotalWithDiscount).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber()
1700
+ }));
1701
+
1702
+ // 第二个:包含原始bundle (qty=原quantity-1)
1594
1703
  if (mainProductQuantity > 1) {
1595
1704
  const newBundleOriginal = [];
1596
- (product.bundle || []).forEach(
1597
- (bundleItem, bundleIndex) => {
1598
- newBundleOriginal.push({
1599
- ...bundleItem,
1600
- discount_list: []
1601
- });
1602
- }
1603
- );
1705
+ (product.bundle || []).forEach((bundleItem, bundleIndex) => {
1706
+ // 使用原始的bundle配置,不包含拆分
1707
+ newBundleOriginal.push({
1708
+ ...bundleItem,
1709
+ discount_list: []
1710
+ });
1711
+ });
1712
+
1713
+ // 计算第二个主商品的总价
1604
1714
  let newTotalOriginal = Number(mainProductData.price || 0);
1605
- let newOriginTotalOriginal = Number(
1606
- mainProductData.original_price || mainProductData.price || 0
1607
- );
1608
- const updatedMainDiscountListOriginal = mainProductData.discount_list.map((discount) => {
1609
- var _a2, _b;
1610
- if ((_a2 = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id) {
1715
+ let newOriginTotalOriginal = Number(mainProductData.original_price || mainProductData.price || 0);
1716
+
1717
+ // 🔥 更新主商品自己的 discount_list 中的 num(quantity=原quantity-1)
1718
+ const updatedMainDiscountListOriginal = mainProductData.discount_list.map(discount => {
1719
+ if (discount?.metadata?.custom_product_bundle_map_id) {
1720
+ // bundle的discount_list保持不变
1611
1721
  return discount;
1612
1722
  }
1723
+ // 主商品自己的discount,更新num为 mainProductQuantity - 1
1613
1724
  return {
1614
1725
  ...discount,
1615
1726
  metadata: {
1616
1727
  ...discount.metadata,
1617
1728
  num: mainProductQuantity - 1,
1618
- custom_product_bundle_map_id: (_b = discount == null ? void 0 : discount.metadata) == null ? void 0 : _b.custom_product_bundle_map_id
1729
+ custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id
1619
1730
  }
1620
1731
  // num: mainProductQuantity - 1,
1621
1732
  };
1622
1733
  });
1623
- const mainDiscountListOriginal = updatedMainDiscountListOriginal.filter(
1624
- (item) => {
1625
- var _a2;
1626
- return !((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id);
1627
- }
1628
- );
1734
+
1735
+ // 🔥 使用更新后的列表计算折扣金额
1736
+ const mainDiscountListOriginal = updatedMainDiscountListOriginal.filter(item => !item?.metadata?.custom_product_bundle_map_id);
1629
1737
  if (mainDiscountListOriginal && mainDiscountListOriginal.length > 0) {
1630
- const allDiscountAmount = (0, import_utils.getDiscountListAmount)(
1631
- mainDiscountListOriginal
1632
- );
1633
- newTotalOriginal = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalOriginal;
1738
+ const allDiscountAmount = (0, _utils.getDiscountListAmount)(mainDiscountListOriginal);
1739
+ newTotalOriginal = new _decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalOriginal;
1634
1740
  newOriginTotalOriginal = mainProductData.origin_total ?? newOriginTotalOriginal;
1635
1741
  }
1742
+
1743
+ // 累加bundle的价格(只累加一次)
1636
1744
  if (newBundleOriginal.length > 0) {
1637
- newBundleOriginal.forEach((item) => {
1745
+ newBundleOriginal.forEach(item => {
1638
1746
  newTotalOriginal += Number(item.price) * Number(item.num);
1639
1747
  newOriginTotalOriginal += Number(item.price) * Number(item.num);
1640
1748
  });
1641
1749
  }
1642
- if (product == null ? void 0 : product.options) {
1750
+
1751
+ // 累加options的价格(options不参与折扣,在最终设置total时处理)
1752
+ if (product?.options) {
1643
1753
  newTotalOriginal = product.options.reduce((accumulator, currentValue) => {
1644
- const currentPrice = new import_decimal.default(currentValue.price || 0);
1645
- const currentNum = new import_decimal.default(currentValue.num || 0);
1754
+ const currentPrice = new _decimal.default(currentValue.price || 0);
1755
+ const currentNum = new _decimal.default(currentValue.num || 0);
1646
1756
  return accumulator.add(currentPrice.mul(currentNum));
1647
- }, new import_decimal.default(newTotalOriginal)).toNumber();
1757
+ }, new _decimal.default(newTotalOriginal)).toNumber();
1648
1758
  }
1649
- newTotalOriginal = new import_decimal.default(newTotalOriginal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
1650
- newOriginTotalOriginal = new import_decimal.default(newOriginTotalOriginal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
1651
- result.push(
1652
- this.hooks.setProduct(mainProduct, {
1653
- ...mainProductData,
1654
- _id: `${mainProductData._id.split("___")[0]}___split_normal`,
1655
- quantity: mainProductQuantity - 1,
1656
- discount_list: updatedMainDiscountListOriginal,
1657
- bundle: newBundleOriginal,
1658
- total: newTotalOriginal,
1659
- origin_total: newOriginTotalOriginal
1660
- })
1661
- );
1759
+ newTotalOriginal = new _decimal.default(newTotalOriginal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
1760
+ newOriginTotalOriginal = new _decimal.default(newOriginTotalOriginal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
1761
+
1762
+ // 添加第二个主商品:qty=原quantity-1,包含原始bundle
1763
+ result.push(this.hooks.setProduct(mainProduct, {
1764
+ ...mainProductData,
1765
+ _id: `${mainProductData._id.split('___')[0]}___split_normal`,
1766
+ quantity: mainProductQuantity - 1,
1767
+ discount_list: updatedMainDiscountListOriginal,
1768
+ bundle: newBundleOriginal,
1769
+ total: newTotalOriginal,
1770
+ origin_total: newOriginTotalOriginal
1771
+ }));
1662
1772
  }
1663
1773
  } else {
1664
- mainProductArr.forEach((mainProduct) => {
1665
- var _a2, _b, _c;
1774
+ // 🔥 没有子商品被拆分,使用原有逻辑
1775
+ mainProductArr.forEach(mainProduct => {
1666
1776
  const mainProductData = this.hooks.getProduct(mainProduct);
1777
+
1778
+ // 重组bundle
1667
1779
  const newBundle = [];
1668
1780
  if (product.bundle && Array.isArray(product.bundle)) {
1669
1781
  product.bundle.forEach((bundleItem, bundleIndex) => {
1670
1782
  const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
1671
- const processedBundleItems = processedFlatItemsMap2.get(bundleItemId);
1783
+ const processedBundleItems = processedFlatItemsMap.get(bundleItemId);
1672
1784
  if (!processedBundleItems || processedBundleItems.length === 0) {
1785
+ // 未处理的bundle item,保持原样
1673
1786
  newBundle.push(bundleItem);
1674
1787
  } else {
1675
- processedBundleItems.forEach((item) => {
1788
+ // 🔥 关键:拆分后的bundle item
1789
+ processedBundleItems.forEach(item => {
1676
1790
  const nextBundlePrice = item.price ?? bundleItem.price;
1677
1791
  const nextBundleSellingPrice = item.bundle_selling_price ?? item.price ?? bundleItem.bundle_selling_price;
1678
- const updatedDiscountList2 = (item.discount_list || []).map((discount) => {
1679
- var _a3;
1680
- return {
1681
- ...discount,
1682
- metadata: {
1683
- ...discount.metadata,
1684
- num: item.num,
1685
- custom_product_bundle_map_id: (_a3 = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a3.custom_product_bundle_map_id
1686
- }
1687
- // num: item.num, // 使用拆分后的 num
1688
- };
1689
- });
1792
+ // 🔥 更新 discount_list 中的 num,使其与拆分后的 item.num 一致
1793
+ const updatedDiscountList = (item.discount_list || []).map(discount => ({
1794
+ ...discount,
1795
+ metadata: {
1796
+ ...discount.metadata,
1797
+ num: item.num,
1798
+ custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id
1799
+ }
1800
+ // num: item.num, // 使用拆分后的 num
1801
+ }));
1690
1802
  newBundle.push({
1691
1803
  ...bundleItem,
1692
1804
  _id: item._id,
1693
1805
  product_id: bundleItem.product_id,
1694
1806
  price: nextBundlePrice,
1695
1807
  num: item.num,
1696
- discount_list: updatedDiscountList2,
1697
- bundle_selling_price: bundleItem.bundle_selling_price !== void 0 ? nextBundleSellingPrice : void 0
1808
+ discount_list: updatedDiscountList,
1809
+ bundle_selling_price: bundleItem.bundle_selling_price !== undefined ? nextBundleSellingPrice : undefined
1698
1810
  });
1699
1811
  });
1700
1812
  }
1701
1813
  });
1702
1814
  }
1815
+
1816
+ // 主商品已经在前面的 setProduct 中应用过折扣;这里只替换 bundle,
1817
+ // 避免把主商品 discount_list 再扣一次。
1703
1818
  const mainSellingPrice = mainProductData.main_product_selling_price ?? mainProductData.price ?? 0;
1704
1819
  let newTotal = Number(mainSellingPrice || 0);
1705
1820
  let newOriginTotal = Number(mainProductData.original_price || mainProductData.price || 0);
1706
- const isManualDiscount = typeof mainProductData.isManualDiscount === "boolean" ? mainProductData.isManualDiscount : mainProductData.total != mainProductData.origin_total && (!((_a2 = mainProductData.discount_list) == null ? void 0 : _a2.length) || ((_c = (_b = mainProductData == null ? void 0 : mainProductData.discount_list) == null ? void 0 : _b.every) == null ? void 0 : _c.call(_b, (item) => item.type === "product")));
1821
+
1822
+ // 判断是否是手动折扣
1823
+ const isManualDiscount = typeof mainProductData.isManualDiscount === 'boolean' ? mainProductData.isManualDiscount : mainProductData.total != mainProductData.origin_total && (!mainProductData.discount_list?.length || mainProductData?.discount_list?.every?.(item => item.type === 'product'));
1824
+
1825
+ // 如果是手动折扣,使用原有的total和origin_total,不重新计算
1707
1826
  if (isManualDiscount) {
1708
1827
  newTotal = mainProductData.total ?? newTotal;
1709
1828
  newOriginTotal = mainProductData.origin_total ?? newOriginTotal;
1710
1829
  } else {
1830
+ // 累加 bundle 的折后价格(只累加一次)
1711
1831
  if (newBundle.length > 0) {
1712
- newBundle.forEach((item) => {
1832
+ newBundle.forEach(item => {
1713
1833
  const bundleSellingPrice = item.bundle_selling_price ?? item.price;
1714
1834
  newTotal += Number(bundleSellingPrice) * Number(item.num);
1715
1835
  });
1716
- newBundle.forEach((item) => {
1717
- var _a3, _b2, _c2;
1718
- const originalPrice = ((_c2 = (_b2 = (_a3 = item.discount_list) == null ? void 0 : _a3[0]) == null ? void 0 : _b2.discount) == null ? void 0 : _c2.original_amount) || item.price;
1836
+
1837
+ // 计算原始总价(不考虑折扣)
1838
+ newBundle.forEach(item => {
1839
+ const originalPrice = item.discount_list?.[0]?.discount?.original_amount || item.price;
1719
1840
  newOriginTotal += Number(originalPrice) * Number(item.num);
1720
1841
  });
1721
1842
  }
1722
1843
  }
1723
- if (product == null ? void 0 : product.options) {
1844
+
1845
+ // 累加options的价格(options不参与折扣,在最终设置total时处理)
1846
+ if (product?.options) {
1724
1847
  newTotal = product.options.reduce((accumulator, currentValue) => {
1725
- const currentPrice = new import_decimal.default(currentValue.price || 0);
1726
- const currentNum = new import_decimal.default(currentValue.num || 0);
1848
+ const currentPrice = new _decimal.default(currentValue.price || 0);
1849
+ const currentNum = new _decimal.default(currentValue.num || 0);
1727
1850
  return accumulator.add(currentPrice.mul(currentNum));
1728
- }, new import_decimal.default(newTotal)).toNumber();
1851
+ }, new _decimal.default(newTotal)).toNumber();
1729
1852
  }
1730
- newTotal = new import_decimal.default(newTotal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
1731
- newOriginTotal = new import_decimal.default(newOriginTotal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
1732
- result.push(
1733
- this.hooks.setProduct(mainProduct, {
1734
- ...mainProductData,
1735
- bundle: newBundle,
1736
- total: newTotal,
1737
- origin_total: newOriginTotal
1738
- })
1739
- );
1853
+ newTotal = new _decimal.default(newTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
1854
+ newOriginTotal = new _decimal.default(newOriginTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
1855
+
1856
+ // 生成最终的主商品
1857
+ result.push(this.hooks.setProduct(mainProduct, {
1858
+ ...mainProductData,
1859
+ bundle: newBundle,
1860
+ total: newTotal,
1861
+ origin_total: newOriginTotal
1862
+ }));
1740
1863
  });
1741
1864
  }
1742
1865
  }
1743
1866
  });
1744
1867
  return result;
1745
1868
  };
1746
- const processedProductList = reconstructProductsWithBundle(
1747
- processedProductsMap,
1748
- processedFlatItemsMap,
1749
- productList
1750
- );
1751
- const updatedDiscountList = addModeDiscount.map((discount) => {
1869
+
1870
+ // 按原始顺序构建处理后的商品列表
1871
+ const processedProductList = reconstructProductsWithBundle(processedProductsMap, processedFlatItemsMap, productList);
1872
+
1873
+ // 按原始顺序更新优惠券列表,标记已使用和可用的优惠券
1874
+ const updatedDiscountList = addModeDiscount.map(discount => {
1875
+ // 获取此优惠券适用的商品列表
1752
1876
  const applicableProducts = discountApplicability.get(discount.id) || [];
1877
+
1878
+ // 获取此优惠券适用的商品详情
1753
1879
  const applicableProductDetails = discountApplicableProducts.get(discount.id) || [];
1880
+
1881
+ // 获取此优惠券实际应用的商品详情
1754
1882
  const appliedProductDetails = appliedDiscountProducts.get(discount.id) || [];
1883
+
1884
+ // 根据是否有适用商品决定isAvailable
1755
1885
  const isAvailable = applicableProducts.length > 0;
1756
- if (typeof discount.isSelected === "boolean" && discount.isSelected === false && discount.isManualSelect) {
1886
+
1887
+ // 如果此优惠券被明确设置为不选中,保持其状态,但正确设置isAvailable
1888
+ if (typeof discount.isSelected === 'boolean' && discount.isSelected === false && discount.isManualSelect) {
1757
1889
  return {
1758
1890
  ...discount,
1759
1891
  isSelected: false,
1760
- isAvailable,
1892
+ isAvailable: isAvailable,
1761
1893
  // 正确设置可用性
1762
1894
  applicableProductIds: applicableProducts,
1763
1895
  // 添加可抵扣的商品详情
1764
- applicableProductDetails,
1896
+ applicableProductDetails: applicableProductDetails,
1765
1897
  // 添加实际抵扣的商品详情(对于未选中的优惠券,为空数组)
1766
1898
  appliedProductDetails: []
1767
1899
  };
@@ -1770,18 +1902,20 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1770
1902
  return {
1771
1903
  ...discount,
1772
1904
  isSelected: true,
1773
- isManualSelect: (options == null ? void 0 : options.scan) ? false : discount.isManualSelect,
1905
+ isManualSelect: options?.scan ? false : discount.isManualSelect,
1774
1906
  // 标记为可用,因为它已被应用
1775
1907
  isAvailable: true,
1776
1908
  // 记录适用的商品IDs
1777
1909
  applicableProductIds: applicableProducts,
1778
1910
  // 添加可抵扣的商品详情
1779
- applicableProductDetails,
1911
+ applicableProductDetails: applicableProductDetails,
1780
1912
  // 添加实际抵扣的商品详情
1781
- appliedProductDetails
1913
+ appliedProductDetails: appliedProductDetails
1782
1914
  };
1783
1915
  }
1784
- let isSelected = typeof discount.isSelected === "boolean" ? discount.isSelected : void 0;
1916
+ let isSelected = typeof discount.isSelected === 'boolean' ? discount.isSelected : undefined;
1917
+
1918
+ // 如果是可用的 并且没有手动标记 则设置为选中
1785
1919
  if (isAvailable && appliedProductDetails.length && !discount.isManualSelect) {
1786
1920
  isSelected = true;
1787
1921
  } else if (!appliedProductDetails.length) {
@@ -1790,14 +1924,14 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1790
1924
  return {
1791
1925
  ...discount,
1792
1926
  // 如果有适用的商品,标记为可用
1793
- isAvailable,
1927
+ isAvailable: isAvailable,
1794
1928
  isSelected,
1795
1929
  // 如果是扫码进来的,要手动设置为手动选择:false
1796
- isManualSelect: (options == null ? void 0 : options.scan) ? false : discount.isManualSelect,
1930
+ isManualSelect: options?.scan ? false : discount.isManualSelect,
1797
1931
  // 记录适用的商品IDs
1798
1932
  applicableProductIds: applicableProducts,
1799
1933
  // 添加可抵扣的商品详情
1800
- applicableProductDetails,
1934
+ applicableProductDetails: applicableProductDetails,
1801
1935
  // 添加实际抵扣的商品详情(对于未使用的优惠券,为空数组)
1802
1936
  appliedProductDetails: []
1803
1937
  };
@@ -1807,6 +1941,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1807
1941
  discountList: [...editModeDiscount, ...updatedDiscountList]
1808
1942
  };
1809
1943
  }
1944
+
1810
1945
  /**
1811
1946
  * 检查优惠是否符合 PackageSubItemUsageRules 配置
1812
1947
  * @param discount 优惠券
@@ -1814,105 +1949,229 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1814
1949
  * @returns 是否可用
1815
1950
  */
1816
1951
  checkPackageSubItemUsageRules(discount, flatItem) {
1817
- var _a, _b, _c, _d, _e, _f, _g, _h;
1818
1952
  const limitedData = discount.limited_relation_product_data;
1819
- const usageRules = limitedData == null ? void 0 : limitedData.package_sub_item_usage_rules;
1820
- const rules = ["original_price", ...(usageRules == null ? void 0 : usageRules.rules) || []];
1953
+ const usageRules = limitedData?.package_sub_item_usage_rules;
1954
+ const rules = ['original_price', ...(usageRules?.rules || [])];
1955
+
1956
+ // 如果没有配置 package_sub_item_usage_rules,则默认可用
1821
1957
  if (!usageRules) {
1822
1958
  return true;
1823
1959
  }
1824
1960
  const ruleType = usageRules.type;
1825
- const packageScope = usageRules == null ? void 0 : usageRules.package_scope;
1826
- const { type: scopeType, exclude_bundle_product_ids = [], include_bundle_product_ids = [], filter = 0 } = packageScope || {};
1827
- const isMainProduct = flatItem.type === "main";
1828
- const isBundleItem = flatItem.type === "bundle";
1829
- const bundleMainProductId = (_a = flatItem.product) == null ? void 0 : _a.product_id;
1961
+ // 套餐适用范围配置
1962
+ const packageScope = usageRules?.package_scope;
1963
+ const {
1964
+ type: scopeType,
1965
+ exclude_bundle_product_ids = [],
1966
+ include_bundle_product_ids = [],
1967
+ filter = 0
1968
+ } = packageScope || {};
1969
+ const isMainProduct = flatItem.type === 'main'; // 单独购买
1970
+ const isBundleItem = flatItem.type === 'bundle'; // 套餐中购买
1971
+ const bundleMainProductId = flatItem.product?.product_id;
1972
+
1973
+ // 主商品直接可用
1830
1974
  if (isMainProduct) {
1831
1975
  return true;
1832
1976
  }
1833
- if (ruleType === "universal_discount") {
1977
+
1978
+ // universal_discount: 单独购买和套餐中(子商品为原价)均可使用
1979
+ if (ruleType === 'universal_discount') {
1834
1980
  if (isMainProduct) {
1835
- return true;
1981
+ return true; // 单独购买时可用
1836
1982
  }
1837
1983
  if (isBundleItem) {
1838
- const priceType = (_b = flatItem.bundleItem) == null ? void 0 : _b.price_type;
1839
- const priceTypeExt = (_c = flatItem.bundleItem) == null ? void 0 : _c.price_type_ext;
1840
- const mainProductId = ((_e = (_d = flatItem == null ? void 0 : flatItem.originProduct) == null ? void 0 : _d._productOrigin) == null ? void 0 : _e.id) || ((_f = flatItem == null ? void 0 : flatItem.parentProduct) == null ? void 0 : _f.id) || 0;
1841
- const isOriginalPrice = priceType === "markup" && priceTypeExt === "product_price";
1842
- const isMarkupPrice = priceType === "markup" && (priceTypeExt === "" || !priceTypeExt);
1984
+ // 套餐中购买时,判断是否为原价
1985
+ const priceType = flatItem.bundleItem?.price_type;
1986
+ const priceTypeExt = flatItem.bundleItem?.price_type_ext;
1987
+ // 主商品id
1988
+ const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
1989
+ // original_price 对应:
1990
+ // 1. price_type: "markup" && price_type_ext: "product_price"
1991
+ // markup_price 对应:
1992
+ // price_type: "markup" && price_type_ext: ""
1993
+ /** 原价 */
1994
+ const isOriginalPrice = priceType === 'markup' && priceTypeExt === 'product_price';
1995
+ /** 加价 */
1996
+ const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
1997
+
1998
+ // 检查 rules
1843
1999
  if (rules.length > 0) {
1844
- const _isOriginalPrice = isOriginalPrice && rules.includes("original_price");
1845
- const _isMarkupPrice = isMarkupPrice && rules.includes("markup_price");
2000
+ const _isOriginalPrice = isOriginalPrice && rules.includes('original_price');
2001
+ const _isMarkupPrice = isMarkupPrice && rules.includes('markup_price');
2002
+ // 价格是否符合规则:原价或加价
1846
2003
  const isPriceValid = _isOriginalPrice || _isMarkupPrice;
2004
+ // 套餐适用范围校验
1847
2005
  let isScopeValid = false;
1848
- if (scopeType === "all_packages" || scopeType === "product_all") {
2006
+
2007
+ // 排除套餐判断, product_all值兼容旧数据
2008
+ if (scopeType === 'all_packages' || scopeType === 'product_all') {
2009
+ // 所有套餐可用
1849
2010
  if (!filter) {
1850
2011
  isScopeValid = true;
1851
2012
  } else {
1852
2013
  isScopeValid = !exclude_bundle_product_ids.includes(Number(bundleMainProductId));
1853
2014
  }
1854
2015
  }
1855
- if (scopeType === "specific_packages" || scopeType === "products") {
2016
+
2017
+ // 包含套餐判断, products值兼容旧数据
2018
+ if (scopeType === 'specific_packages' || scopeType === 'products') {
1856
2019
  isScopeValid = include_bundle_product_ids.includes(Number(bundleMainProductId));
1857
2020
  }
2021
+
2022
+ // 价格和套餐适用范围都符合,则可用
1858
2023
  if (isPriceValid && isScopeValid) {
1859
2024
  return true;
1860
2025
  }
2026
+
2027
+ // 检查原价
2028
+ // if (isOriginalPrice && rules.includes('original_price')) {
2029
+ // return true;
2030
+ // }
2031
+
2032
+ // 检查加价
2033
+ // if (isMarkupPrice && rules.includes('markup_price')) {
2034
+ // return true;
2035
+ // }
2036
+
2037
+ // 如果都不匹配,则不可用
1861
2038
  return false;
1862
2039
  }
2040
+
2041
+ // 原价包括:price_type: "markup" && price_type_ext: "product_price"
1863
2042
  return isOriginalPrice;
1864
2043
  }
1865
2044
  return true;
1866
2045
  }
1867
- if (ruleType === "package_exclusive") {
2046
+
2047
+ // package_exclusive: 仅在套餐中(子商品为原价)时可使用
2048
+ if (ruleType === 'package_exclusive') {
1868
2049
  if (isMainProduct) {
1869
- return false;
2050
+ return false; // 单独购买时不可用
1870
2051
  }
1871
2052
  if (isBundleItem) {
1872
- const priceType = (_g = flatItem.bundleItem) == null ? void 0 : _g.price_type;
1873
- const priceTypeExt = (_h = flatItem.bundleItem) == null ? void 0 : _h.price_type_ext;
1874
- const isOriginalPrice = priceType === "markup" && priceTypeExt === "product_price";
1875
- const isMarkupPrice = priceType === "markup" && (priceTypeExt === "" || !priceTypeExt);
2053
+ // 套餐中购买时,判断是否为原价
2054
+ const priceType = flatItem.bundleItem?.price_type;
2055
+ const priceTypeExt = flatItem.bundleItem?.price_type_ext;
2056
+
2057
+ // original_price 对应:
2058
+ // 1. price_type: "markup" && price_type_ext: "product_price"
2059
+ // markup_price 对应:
2060
+ // price_type: "markup" && price_type_ext: ""
2061
+ /** 原价 */
2062
+ const isOriginalPrice = priceType === 'markup' && priceTypeExt === 'product_price';
2063
+ /** 加价 */
2064
+ const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
2065
+
2066
+ // 检查 rules
1876
2067
  if (rules.length > 0) {
1877
- const _isOriginalPrice = isOriginalPrice && rules.includes("original_price");
1878
- const _isMarkupPrice = isMarkupPrice && rules.includes("markup_price");
2068
+ const _isOriginalPrice = isOriginalPrice && rules.includes('original_price');
2069
+ const _isMarkupPrice = isMarkupPrice && rules.includes('markup_price');
2070
+ // 价格是否符合规则:原价或加价
1879
2071
  const isPriceValid = _isOriginalPrice || _isMarkupPrice;
2072
+ // 套餐适用范围校验
1880
2073
  let isScopeValid = false;
1881
- if (scopeType === "all_packages" || scopeType === "product_all") {
2074
+
2075
+ // 排除套餐判断, product_all值兼容旧数据
2076
+ if (scopeType === 'all_packages' || scopeType === 'product_all') {
2077
+ // 所有套餐可用
1882
2078
  if (!filter) {
1883
2079
  isScopeValid = true;
1884
2080
  } else {
1885
2081
  isScopeValid = !exclude_bundle_product_ids.includes(Number(bundleMainProductId));
1886
2082
  }
1887
2083
  }
1888
- if (scopeType === "specific_packages" || scopeType === "products") {
2084
+
2085
+ // 包含套餐判断, products值兼容旧数据
2086
+ if (scopeType === 'specific_packages' || scopeType === 'products') {
1889
2087
  isScopeValid = include_bundle_product_ids.includes(Number(bundleMainProductId));
1890
2088
  }
2089
+
2090
+ // 价格和套餐适用范围都符合,则可用
1891
2091
  if (isPriceValid && isScopeValid) {
1892
2092
  return true;
1893
2093
  }
2094
+
2095
+ // 检查原价
2096
+ // if (isOriginalPrice && rules.includes('original_price')) {
2097
+ // return true;
2098
+ // }
2099
+
2100
+ // 检查加价
2101
+ // if (isMarkupPrice && rules.includes('markup_price')) {
2102
+ // return true;
2103
+ // }
2104
+
2105
+ // 如果都不匹配,则不可用
1894
2106
  return false;
1895
2107
  }
2108
+
2109
+ // 原价包括:price_type: "markup" && price_type_ext: "product_price"
1896
2110
  return isOriginalPrice;
1897
2111
  }
1898
2112
  return false;
1899
2113
  }
1900
- if (ruleType === "single_item_promo") {
1901
- return isMainProduct;
2114
+
2115
+ // single_item_promo: 仅在单独购买时可使用
2116
+ if (ruleType === 'single_item_promo') {
2117
+ return isMainProduct; // 只有单独购买时可用
2118
+ }
2119
+
2120
+ /*
2121
+ // custom_usage_rules: 根据自定义规则判断
2122
+ if (ruleType === 'custom_usage_rules') {
2123
+ const customRules = usageRules.custom_usage_rules;
2124
+ if (!customRules) {
2125
+ return true; // 如果没有自定义规则,默认可用
2126
+ }
2127
+ const { types, package_sub_item_rules } = customRules;
2128
+ // 判断商品类型是否在允许的类型中
2129
+ if (isMainProduct) {
2130
+ // 主商品对应 standalone_product
2131
+ if (!types.includes('standalone_product')) {
2132
+ return false;
2133
+ }
2134
+ return true; // 主商品不需要判断 package_sub_item_rules
2135
+ }
2136
+ if (isBundleItem) {
2137
+ // bundle子商品对应 package_sub_item
2138
+ if (!types.includes('package_sub_item')) {
2139
+ return false;
2140
+ }
2141
+ // 如果包含 package_sub_item,还需要判断 price_type
2142
+ const priceType = flatItem.bundleItem?.price_type;
2143
+ const priceTypeExt = flatItem.bundleItem?.price_type_ext;
2144
+ // 检查 package_sub_item_rules
2145
+ if (package_sub_item_rules && package_sub_item_rules.length > 0) {
2146
+ // original_price 对应:
2147
+ // 1. price_type: "markup" && price_type_ext: "product_price"
2148
+ // markup_price 对应:
2149
+ // price_type: "markup" && price_type_ext: ""
2150
+ const isOriginalPrice = (priceType === 'markup' && priceTypeExt === 'product_price');
2151
+ const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
2152
+ if (isOriginalPrice && package_sub_item_rules.includes('original_price')) {
2153
+ return true;
2154
+ }
2155
+ if (isMarkupPrice && package_sub_item_rules.includes('markup_price')) {
2156
+ return true;
2157
+ }
2158
+ // 如果都不匹配,则不可用
2159
+ return false;
2160
+ }
2161
+ return true; // 如果没有 package_sub_item_rules 配置,默认可用
2162
+ }
2163
+ return true;
1902
2164
  }
2165
+ * */
2166
+
2167
+ // 默认可用
1903
2168
  return true;
1904
2169
  }
1905
2170
  async destroy() {
1906
2171
  this.core.effects.offByModuleDestroy(this.name);
1907
2172
  await this.core.effects.emit(`${this.name}:onDestroy`, {});
1908
- console.log("[Rules] 已销毁");
1909
2173
  super.destroy();
1910
2174
  }
1911
- async clear() {
1912
- console.log("[Rules] clear");
1913
- }
1914
- };
1915
- // Annotate the CommonJS export names for ESM import in node:
1916
- 0 && (module.exports = {
1917
- RulesModule
1918
- });
2175
+ async clear() {}
2176
+ }
2177
+ exports.RulesModule = RulesModule;