@pisell/pisellos 0.0.567 → 0.0.569

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