@pisell/pisellos 2.2.310 → 2.2.312-vm.0

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 (314) hide show
  1. package/dist/apis/picoding.d.ts.map +1 -0
  2. package/dist/core/index.d.ts.map +1 -0
  3. package/dist/effects/index.d.ts.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/inventory/index.d.ts +92 -0
  8. package/dist/inventory/index.d.ts.map +1 -0
  9. package/dist/inventory/index.js +509 -0
  10. package/dist/model/index.d.ts.map +1 -0
  11. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts.map +1 -0
  12. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts.map +1 -0
  13. package/dist/model/strategy/adapter/dataVariant/examples.d.ts.map +1 -0
  14. package/dist/model/strategy/adapter/dataVariant/index.d.ts.map +1 -0
  15. package/dist/model/strategy/adapter/dataVariant/type.d.ts.map +1 -0
  16. package/dist/model/strategy/adapter/index.d.ts.map +1 -0
  17. package/dist/model/strategy/adapter/itemRule/adapter.d.ts.map +1 -0
  18. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts.map +1 -0
  19. package/dist/model/strategy/adapter/itemRule/examples.d.ts.map +1 -0
  20. package/dist/model/strategy/adapter/itemRule/index.d.ts.map +1 -0
  21. package/dist/model/strategy/adapter/itemRule/type.d.ts.map +1 -0
  22. package/dist/model/strategy/adapter/promotion/adapter.d.ts.map +1 -0
  23. package/dist/model/strategy/adapter/promotion/evaluator.d.ts.map +1 -0
  24. package/dist/model/strategy/adapter/promotion/examples.d.ts.map +1 -0
  25. package/dist/model/strategy/adapter/promotion/index.d.ts.map +1 -0
  26. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  27. package/dist/model/strategy/adapter/promotion/type.d.ts.map +1 -0
  28. package/dist/model/strategy/adapter/type.d.ts.map +1 -0
  29. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts.map +1 -0
  30. package/dist/model/strategy/adapter/walletPass/example.d.ts.map +1 -0
  31. package/dist/model/strategy/adapter/walletPass/index.d.ts.map +1 -0
  32. package/dist/model/strategy/adapter/walletPass/locales.d.ts.map +1 -0
  33. package/dist/model/strategy/adapter/walletPass/type.d.ts.map +1 -0
  34. package/dist/model/strategy/adapter/walletPass/utils.d.ts.map +1 -0
  35. package/dist/model/strategy/engine.d.ts.map +1 -0
  36. package/dist/model/strategy/index.d.ts.map +1 -0
  37. package/dist/model/strategy/strategy-example.d.ts.map +1 -0
  38. package/dist/model/strategy/type.d.ts.map +1 -0
  39. package/dist/modules/Account/index.d.ts.map +1 -0
  40. package/dist/modules/Account/types.d.ts.map +1 -0
  41. package/dist/modules/AccountList/index.d.ts.map +1 -0
  42. package/dist/modules/AccountList/types.d.ts.map +1 -0
  43. package/dist/modules/AccountList/utils.d.ts.map +1 -0
  44. package/dist/modules/BaseModule.d.ts.map +1 -0
  45. package/dist/modules/BookingContext/index.d.ts.map +1 -0
  46. package/dist/modules/BookingContext/types.d.ts.map +1 -0
  47. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts.map +1 -0
  48. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts.map +1 -0
  49. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts.map +1 -0
  50. package/dist/modules/BookingContext/utils/flexible.d.ts.map +1 -0
  51. package/dist/modules/BookingContext/utils/formatResourceList.d.ts.map +1 -0
  52. package/dist/modules/BookingContext/utils/index.d.ts.map +1 -0
  53. package/dist/modules/BookingContext/utils/noResource.d.ts.map +1 -0
  54. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts.map +1 -0
  55. package/dist/modules/BookingContext/utils/productExtend.d.ts.map +1 -0
  56. package/dist/modules/BookingContext/utils/resourceErrors.d.ts.map +1 -0
  57. package/dist/modules/BookingContext/utils/resourceSelection.d.ts.map +1 -0
  58. package/dist/modules/BookingContext/utils/resources.d.ts.map +1 -0
  59. package/dist/modules/BookingContext/utils/serviceTimes.d.ts.map +1 -0
  60. package/dist/modules/BookingContext/utils/timeSlices.d.ts.map +1 -0
  61. package/dist/modules/Cart/index.d.ts.map +1 -0
  62. package/dist/modules/Cart/types.d.ts.map +1 -0
  63. package/dist/modules/Cart/utils/cartAccount.d.ts.map +1 -0
  64. package/dist/modules/Cart/utils/cartDate.d.ts.map +1 -0
  65. package/dist/modules/Cart/utils/cartDiscount.d.ts.map +1 -0
  66. package/dist/modules/Cart/utils/cartNote.d.ts.map +1 -0
  67. package/dist/modules/Cart/utils/cartProduct.d.ts.map +1 -0
  68. package/dist/modules/Cart/utils/cartRelationForms.d.ts.map +1 -0
  69. package/dist/modules/Cart/utils/cartResource.d.ts.map +1 -0
  70. package/dist/modules/Cart/utils/changePrice.d.ts.map +1 -0
  71. package/dist/modules/Cart/utils/index.d.ts.map +1 -0
  72. package/dist/modules/Customer/constants.d.ts.map +1 -0
  73. package/dist/modules/Customer/index.d.ts.map +1 -0
  74. package/dist/modules/Customer/types.d.ts.map +1 -0
  75. package/dist/modules/Date/index.d.ts.map +1 -0
  76. package/dist/modules/Date/types.d.ts.map +1 -0
  77. package/dist/modules/Date/utils.d.ts.map +1 -0
  78. package/dist/modules/Discount/availability.d.ts.map +1 -0
  79. package/dist/modules/Discount/entitlementPass.d.ts.map +1 -0
  80. package/dist/modules/Discount/index.d.ts.map +1 -0
  81. package/dist/modules/Discount/index.js +1 -0
  82. package/dist/modules/Discount/types.d.ts.map +1 -0
  83. package/dist/modules/Guests/index.d.ts.map +1 -0
  84. package/dist/modules/Guests/types.d.ts.map +1 -0
  85. package/dist/modules/Holder/index.d.ts.map +1 -0
  86. package/dist/modules/Holder/types.d.ts.map +1 -0
  87. package/dist/modules/Holder/utils.d.ts.map +1 -0
  88. package/dist/modules/OpenData/index.d.ts.map +1 -0
  89. package/dist/modules/OpenData/types.d.ts.map +1 -0
  90. package/dist/modules/OpenData/utils.d.ts.map +1 -0
  91. package/dist/modules/Order/index.d.ts +25 -3
  92. package/dist/modules/Order/index.d.ts.map +1 -0
  93. package/dist/modules/Order/index.js +1647 -1211
  94. package/dist/modules/Order/payment-utils.d.ts.map +1 -0
  95. package/dist/modules/Order/salesNotes.d.ts.map +1 -0
  96. package/dist/modules/Order/types.d.ts +7 -0
  97. package/dist/modules/Order/types.d.ts.map +1 -0
  98. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts.map +1 -0
  99. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts.map +1 -0
  100. package/dist/modules/Order/utils/discountProductLineIdentity.js +2 -2
  101. package/dist/modules/Order/utils/manualProductDiscount.d.ts.map +1 -0
  102. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts.map +1 -0
  103. package/dist/modules/Order/utils/productVoucherGroups.d.ts +15 -0
  104. package/dist/modules/Order/utils/productVoucherGroups.d.ts.map +1 -0
  105. package/dist/modules/Order/utils/productVoucherGroups.js +115 -0
  106. package/dist/modules/Order/utils/virtualSettlement.d.ts.map +1 -0
  107. package/dist/modules/Order/utils/weighedProduct.d.ts.map +1 -0
  108. package/dist/modules/Order/utils.d.ts +5 -3
  109. package/dist/modules/Order/utils.d.ts.map +1 -0
  110. package/dist/modules/Order/utils.js +32 -11
  111. package/dist/modules/Payment/cash.d.ts.map +1 -0
  112. package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts.map +1 -0
  113. package/dist/modules/Payment/eftpos.d.ts.map +1 -0
  114. package/dist/modules/Payment/index.d.ts.map +1 -0
  115. package/dist/modules/Payment/mx51.d.ts.map +1 -0
  116. package/dist/modules/Payment/types.d.ts.map +1 -0
  117. package/dist/modules/Payment/utils.d.ts.map +1 -0
  118. package/dist/modules/Payment/walletpass.d.ts.map +1 -0
  119. package/dist/modules/Product/index.d.ts.map +1 -0
  120. package/dist/modules/Product/types.d.ts.map +1 -0
  121. package/dist/modules/Product/utils.d.ts.map +1 -0
  122. package/dist/modules/ProductList/clientDataVariants.d.ts.map +1 -0
  123. package/dist/modules/ProductList/index.d.ts.map +1 -0
  124. package/dist/modules/ProductList/index.js +33 -12
  125. package/dist/modules/ProductList/types.d.ts.map +1 -0
  126. package/dist/modules/Quotation/index.d.ts.map +1 -0
  127. package/dist/modules/Quotation/types.d.ts.map +1 -0
  128. package/dist/modules/Resource/index.d.ts.map +1 -0
  129. package/dist/modules/Resource/types.d.ts.map +1 -0
  130. package/dist/modules/Resource/utils.d.ts.map +1 -0
  131. package/dist/modules/ResourcePlanner/index.d.ts.map +1 -0
  132. package/dist/modules/ResourcePlanner/localClock.d.ts.map +1 -0
  133. package/dist/modules/ResourcePlanner/planner.d.ts.map +1 -0
  134. package/dist/modules/ResourcePlanner/types.d.ts.map +1 -0
  135. package/dist/modules/Rules/index.d.ts +2 -0
  136. package/dist/modules/Rules/index.d.ts.map +1 -0
  137. package/dist/modules/Rules/index.js +29 -21
  138. package/dist/modules/Rules/types.d.ts.map +1 -0
  139. package/dist/modules/SalesSummary/index.d.ts.map +1 -0
  140. package/dist/modules/SalesSummary/types.d.ts.map +1 -0
  141. package/dist/modules/SalesSummary/utils.d.ts.map +1 -0
  142. package/dist/modules/ScanOrderLogger/index.d.ts.map +1 -0
  143. package/dist/modules/ScanOrderLogger/providers/feishu.d.ts.map +1 -0
  144. package/dist/modules/ScanOrderLogger/providers/grafana.d.ts.map +1 -0
  145. package/dist/modules/ScanOrderLogger/types.d.ts.map +1 -0
  146. package/dist/modules/Schedule/getDateIsInSchedule.d.ts.map +1 -0
  147. package/dist/modules/Schedule/index.d.ts.map +1 -0
  148. package/dist/modules/Schedule/type.d.ts.map +1 -0
  149. package/dist/modules/Schedule/types.d.ts.map +1 -0
  150. package/dist/modules/Schedule/utils.d.ts.map +1 -0
  151. package/dist/modules/Step/index.d.ts.map +1 -0
  152. package/dist/modules/Step/tyeps.d.ts.map +1 -0
  153. package/dist/modules/Summary/index.d.ts.map +1 -0
  154. package/dist/modules/Summary/types.d.ts.map +1 -0
  155. package/dist/modules/Summary/utils.d.ts.map +1 -0
  156. package/dist/modules/SurchargeList/index.d.ts.map +1 -0
  157. package/dist/modules/SurchargeList/types.d.ts.map +1 -0
  158. package/dist/modules/index.d.ts.map +1 -0
  159. package/dist/plugins/app.d.ts.map +1 -0
  160. package/dist/plugins/index.d.ts.map +1 -0
  161. package/dist/plugins/request.d.ts.map +1 -0
  162. package/dist/plugins/shopStore.d.ts.map +1 -0
  163. package/dist/plugins/user.d.ts.map +1 -0
  164. package/dist/plugins/window.d.ts.map +1 -0
  165. package/dist/server/index.d.ts.map +1 -0
  166. package/dist/server/modules/floor-plan/index.d.ts.map +1 -0
  167. package/dist/server/modules/floor-plan/index.js +34 -3
  168. package/dist/server/modules/floor-plan/types.d.ts.map +1 -0
  169. package/dist/server/modules/index.d.ts.map +1 -0
  170. package/dist/server/modules/menu/index.d.ts.map +1 -0
  171. package/dist/server/modules/menu/types.d.ts.map +1 -0
  172. package/dist/server/modules/order/index.d.ts.map +1 -0
  173. package/dist/server/modules/order/types.d.ts.map +1 -0
  174. package/dist/server/modules/order/utils/filterBookings.d.ts.map +1 -0
  175. package/dist/server/modules/order/utils/filterOrders.d.ts.map +1 -0
  176. package/dist/server/modules/payment/index.d.ts.map +1 -0
  177. package/dist/server/modules/payment/types.d.ts.map +1 -0
  178. package/dist/server/modules/products/index.d.ts.map +1 -0
  179. package/dist/server/modules/products/types.d.ts.map +1 -0
  180. package/dist/server/modules/quotation/index.d.ts.map +1 -0
  181. package/dist/server/modules/quotation/types.d.ts.map +1 -0
  182. package/dist/server/modules/resource/index.d.ts.map +1 -0
  183. package/dist/server/modules/resource/types.d.ts.map +1 -0
  184. package/dist/server/modules/schedule/index.d.ts.map +1 -0
  185. package/dist/server/modules/schedule/types.d.ts.map +1 -0
  186. package/dist/server/modules/schedule/utils.d.ts.map +1 -0
  187. package/dist/server/types.d.ts.map +1 -0
  188. package/dist/server/utils/index.d.ts.map +1 -0
  189. package/dist/server/utils/product.d.ts.map +1 -0
  190. package/dist/server/utils/schedule.d.ts.map +1 -0
  191. package/dist/server/utils/small-ticket.d.ts.map +1 -0
  192. package/dist/server/utils/time.d.ts.map +1 -0
  193. package/dist/solution/BaseSales/index.d.ts +16 -1
  194. package/dist/solution/BaseSales/index.d.ts.map +1 -0
  195. package/dist/solution/BaseSales/index.js +1363 -1176
  196. package/dist/solution/BaseSales/types.d.ts.map +1 -0
  197. package/dist/solution/BaseSales/utils/cartPromotion.d.ts.map +1 -0
  198. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts.map +1 -0
  199. package/dist/solution/BaseSales/utils/quotationPrice.d.ts.map +1 -0
  200. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts.map +1 -0
  201. package/dist/solution/BaseSales/utils.d.ts.map +1 -0
  202. package/dist/solution/BookingByStep/index.d.ts +1 -1
  203. package/dist/solution/BookingByStep/index.d.ts.map +1 -0
  204. package/dist/solution/BookingByStep/types.d.ts.map +1 -0
  205. package/dist/solution/BookingByStep/utils/capacity.d.ts.map +1 -0
  206. package/dist/solution/BookingByStep/utils/products.d.ts.map +1 -0
  207. package/dist/solution/BookingByStep/utils/resources.d.ts.map +1 -0
  208. package/dist/solution/BookingByStep/utils/stock.d.ts.map +1 -0
  209. package/dist/solution/BookingByStep/utils/timeslots.d.ts.map +1 -0
  210. package/dist/solution/BookingTicket/index.d.ts +1 -1
  211. package/dist/solution/BookingTicket/index.d.ts.map +1 -0
  212. package/dist/solution/BookingTicket/index.js +198 -108
  213. package/dist/solution/BookingTicket/types.d.ts +14 -2
  214. package/dist/solution/BookingTicket/types.d.ts.map +1 -0
  215. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
  216. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts.map +1 -0
  217. package/dist/solution/BookingTicket/utils/addProductDecision.js +4 -3
  218. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts.map +1 -0
  219. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts.map +1 -0
  220. package/dist/solution/BookingTicket/utils/cartView.d.ts.map +1 -0
  221. package/dist/solution/BookingTicket/utils/exampleData.d.ts.map +1 -0
  222. package/dist/solution/BookingTicket/utils/orderCustomer.d.ts.map +1 -0
  223. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts.map +1 -0
  224. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts.map +1 -0
  225. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +94 -58
  226. package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts +10 -0
  227. package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts.map +1 -0
  228. package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.js +117 -0
  229. package/dist/solution/BookingTicket/utils/scan/cloudSearch.d.ts.map +1 -0
  230. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
  231. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts.map +1 -0
  232. package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts.map +1 -0
  233. package/dist/solution/BookingTicket/utils/scan/handleScan.js +2 -1
  234. package/dist/solution/BookingTicket/utils/scan/index.d.ts.map +1 -0
  235. package/dist/solution/BookingTicket/utils/scan/scanCache.d.ts.map +1 -0
  236. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts.map +1 -0
  237. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts.map +1 -0
  238. package/dist/solution/BookingTicket/utils/weighingProductSku.d.ts.map +1 -0
  239. package/dist/solution/BuyTickets/index.d.ts.map +1 -0
  240. package/dist/solution/BuyTickets/types.d.ts.map +1 -0
  241. package/dist/solution/Checkout/index.d.ts.map +1 -0
  242. package/dist/solution/Checkout/types.d.ts.map +1 -0
  243. package/dist/solution/Checkout/utils/index.d.ts.map +1 -0
  244. package/dist/solution/PlaceOrder/index.d.ts.map +1 -0
  245. package/dist/solution/RegisterAndLogin/config.d.ts.map +1 -0
  246. package/dist/solution/RegisterAndLogin/index.d.ts.map +1 -0
  247. package/dist/solution/RegisterAndLogin/types.d.ts.map +1 -0
  248. package/dist/solution/RegisterAndLogin/utils.d.ts.map +1 -0
  249. package/dist/solution/Sales/index.d.ts.map +1 -0
  250. package/dist/solution/Sales/types.d.ts.map +1 -0
  251. package/dist/solution/ScanOrder/index.d.ts.map +1 -0
  252. package/dist/solution/ScanOrder/types.d.ts.map +1 -0
  253. package/dist/solution/ScanOrder/utils.d.ts.map +1 -0
  254. package/dist/solution/ShopDiscount/index.d.ts.map +1 -0
  255. package/dist/solution/ShopDiscount/types.d.ts.map +1 -0
  256. package/dist/solution/ShopDiscount/utils.d.ts.map +1 -0
  257. package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
  258. package/dist/solution/UnifiedBookingSales/index.d.ts.map +1 -0
  259. package/dist/solution/UnifiedBookingSales/index.js +63 -43
  260. package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts.map +1 -0
  261. package/dist/solution/UnifiedBookingSales/types.d.ts.map +1 -0
  262. package/dist/solution/VenueBooking/index.d.ts.map +1 -0
  263. package/dist/solution/VenueBooking/types.d.ts.map +1 -0
  264. package/dist/solution/VenueBooking/utils/dateSummary.d.ts.map +1 -0
  265. package/dist/solution/VenueBooking/utils/resource.d.ts.map +1 -0
  266. package/dist/solution/VenueBooking/utils/slotMerge.d.ts.map +1 -0
  267. package/dist/solution/VenueBooking/utils/timeSlot.d.ts.map +1 -0
  268. package/dist/solution/VenueBooking/utils.d.ts.map +1 -0
  269. package/dist/solution/index.d.ts.map +1 -0
  270. package/dist/store/createStore.d.ts.map +1 -0
  271. package/dist/types/index.d.ts.map +1 -0
  272. package/dist/utils/os-private-payload.d.ts.map +1 -0
  273. package/dist/utils/payment-number.d.ts.map +1 -0
  274. package/dist/utils/platform.d.ts +2 -0
  275. package/dist/utils/platform.d.ts.map +1 -0
  276. package/dist/utils/platform.js +6 -0
  277. package/dist/utils/task.d.ts.map +1 -0
  278. package/dist/utils/watch.d.ts.map +1 -0
  279. package/lib/index.d.ts +1 -0
  280. package/lib/index.js +12 -0
  281. package/lib/inventory/index.d.ts +92 -0
  282. package/lib/inventory/index.js +287 -0
  283. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  284. package/lib/modules/Discount/index.js +1 -0
  285. package/lib/modules/Order/index.d.ts +25 -3
  286. package/lib/modules/Order/index.js +145 -11
  287. package/lib/modules/Order/types.d.ts +7 -0
  288. package/lib/modules/Order/utils/discountProductLineIdentity.js +1 -1
  289. package/lib/modules/Order/utils/productVoucherGroups.d.ts +15 -0
  290. package/lib/modules/Order/utils/productVoucherGroups.js +64 -0
  291. package/lib/modules/Order/utils.d.ts +5 -3
  292. package/lib/modules/Order/utils.js +29 -10
  293. package/lib/modules/ProductList/index.js +15 -0
  294. package/lib/modules/Rules/index.d.ts +2 -0
  295. package/lib/modules/Rules/index.js +6 -0
  296. package/lib/server/modules/floor-plan/index.js +29 -1
  297. package/lib/solution/BaseSales/index.d.ts +16 -1
  298. package/lib/solution/BaseSales/index.js +89 -9
  299. package/lib/solution/BookingByStep/index.d.ts +1 -1
  300. package/lib/solution/BookingTicket/index.d.ts +1 -1
  301. package/lib/solution/BookingTicket/index.js +36 -2
  302. package/lib/solution/BookingTicket/types.d.ts +14 -2
  303. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
  304. package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -3
  305. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +14 -2
  306. package/lib/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts +10 -0
  307. package/lib/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.js +71 -0
  308. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
  309. package/lib/solution/BookingTicket/utils/scan/handleScan.js +2 -1
  310. package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
  311. package/lib/solution/UnifiedBookingSales/index.js +14 -3
  312. package/lib/utils/platform.d.ts +2 -0
  313. package/lib/utils/platform.js +7 -0
  314. package/package.json +4 -2
@@ -11,6 +11,7 @@ var _utils2 = require("../Product/utils");
11
11
  var _weighedProduct = require("./utils/weighedProduct");
12
12
  var _dayjs = _interopRequireDefault(require("dayjs"));
13
13
  var _availability = require("../Discount/availability");
14
+ var _productVoucherGroups = require("./utils/productVoucherGroups");
14
15
  var _osPrivatePayload = require("../../utils/os-private-payload");
15
16
  var _salesNotes = require("./salesNotes");
16
17
  var _paymentUtils = require("./payment-utils");
@@ -137,6 +138,62 @@ class OrderModule extends _BaseModule.BaseModule {
137
138
  rulesHooksOverride;
138
139
  moduleHooksOverride;
139
140
  orderHooks;
141
+ cartCommandQueue = Promise.resolve();
142
+ queueCartCommand(run) {
143
+ if (!this.orderHooks?.onBeforeCartCommit && !this.store.tempOrder?._extend?.productVoucherGroups?.length) return run();
144
+ const pending = this.cartCommandQueue.then(run, run);
145
+ this.cartCommandQueue = pending.catch(() => undefined);
146
+ return pending;
147
+ }
148
+
149
+ /** Use the exact Order normalizers/merge rules on a private draft, not a second projection. */
150
+ beginCartMutation() {
151
+ const current = this.ensureTempOrder();
152
+ const guard = this.orderHooks?.onBeforeCartCommit;
153
+ if (!guard && !current._extend?.productVoucherGroups?.length) return {
154
+ draft: current,
155
+ commit: undefined
156
+ };
157
+ const before = (0, _lodashEs.cloneDeep)(current);
158
+ const draft = (0, _lodashEs.cloneDeep)(current);
159
+ return {
160
+ draft,
161
+ commit: async () => {
162
+ (0, _productVoucherGroups.validateProductVoucherGroups)(draft, this.getDiscountList(), before);
163
+ await guard?.({
164
+ currentItems: (0, _lodashEs.cloneDeep)(before.products),
165
+ proposedItems: (0, _lodashEs.cloneDeep)(draft.products)
166
+ });
167
+ if (this.store.tempOrder !== current || guard !== this.orderHooks?.onBeforeCartCommit || !(0, _lodashEs.isEqual)(current, before)) {
168
+ throw Object.assign(new Error('The cart changed. Please try again.'), {
169
+ code: 'SALES_GUARD_REJECTED'
170
+ });
171
+ }
172
+ Object.assign(current, draft);
173
+ return current;
174
+ }
175
+ };
176
+ }
177
+
178
+ /** Serializes checkout preparation with local cart commands; hydration remains outside this guard. */
179
+ async prepareCheckout(prepare) {
180
+ const run = async () => {
181
+ const order = this.ensureTempOrder();
182
+ (0, _productVoucherGroups.validateProductVoucherGroups)(order, this.getDiscountList(), undefined, true);
183
+ const items = (0, _lodashEs.cloneDeep)(order.products);
184
+ const result = await prepare(items);
185
+ if (this.store.tempOrder !== order || !(0, _lodashEs.isEqual)(order.products, items)) {
186
+ throw Object.assign(new Error('The cart changed. Please try again.'), {
187
+ code: 'SALES_GUARD_REJECTED'
188
+ });
189
+ }
190
+ (0, _productVoucherGroups.validateProductVoucherGroups)(order, this.getDiscountList(), undefined, true);
191
+ return result;
192
+ };
193
+ const pending = this.cartCommandQueue.then(run, run);
194
+ this.cartCommandQueue = pending.catch(() => undefined);
195
+ return pending;
196
+ }
140
197
  otherParams;
141
198
  // ─── 促销/赠品 ────────────────────────────────────
142
199
  /** 评估器引用;由 SalesSdkProvider 注入,未注入时 applyPromotion 静默跳过 */
@@ -424,8 +481,11 @@ class OrderModule extends _BaseModule.BaseModule {
424
481
  * @example
425
482
  * orderModule.updateOtherParams({ cacheId: 'cache-2', channel: 'pos' });
426
483
  */
427
- updateOtherParams(params) {
484
+ updateOtherParams(params, options) {
428
485
  const otherParams = params || {};
486
+ if (options && Object.prototype.hasOwnProperty.call(options, 'hooks')) {
487
+ this.moduleHooksOverride = options.hooks;
488
+ }
429
489
  this.syncSessionStorageOptions(otherParams);
430
490
  this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
431
491
  this.rulesHooksOverride = otherParams.rules?.hooks;
@@ -509,6 +569,26 @@ class OrderModule extends _BaseModule.BaseModule {
509
569
  hooks: this.rulesHooksOverride || this.createDefaultRulesHooks()
510
570
  });
511
571
  this.store.rules = rules;
572
+ rules.setDiscountScope((product, discount) => (0, _productVoucherGroups.allowsProductVoucher)(this.store.tempOrder, product, discount));
573
+ }
574
+ setProductVoucherGroups(groups) {
575
+ const order = this.ensureTempOrder();
576
+ const ids = new Set();
577
+ const keys = new Set();
578
+ const known = new Map(this.getDiscountList().map(discount => [String(discount.id), discount]));
579
+ for (const group of groups) {
580
+ if (!group.key || keys.has(group.key)) throw (0, _productVoucherGroups.voucherGroupError)();
581
+ keys.add(group.key);
582
+ for (const id of group.discountIds) {
583
+ const discount = known.get(String(id));
584
+ if (!discount || (discount.tag || discount.type) !== 'good_pass' || ids.has(String(id))) throw (0, _productVoucherGroups.voucherGroupError)();
585
+ ids.add(String(id));
586
+ }
587
+ }
588
+ this.ensureExtend(order).productVoucherGroups = (0, _lodashEs.cloneDeep)(groups);
589
+ }
590
+ validateProductVoucherSelection() {
591
+ (0, _productVoucherGroups.validateProductVoucherGroups)(this.ensureTempOrder(), this.getDiscountList(), undefined, true);
512
592
  }
513
593
  createDefaultRulesHooks() {
514
594
  return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || []);
@@ -660,7 +740,7 @@ class OrderModule extends _BaseModule.BaseModule {
660
740
  apply: false
661
741
  });
662
742
  }
663
- async scanCode(code, customerId) {
743
+ async scanCode(code, customerId, options) {
664
744
  if (this.isActiveVirtualSettlementOrder(this.store.tempOrder)) {
665
745
  return {
666
746
  type: 'clientCalc',
@@ -671,16 +751,22 @@ class OrderModule extends _BaseModule.BaseModule {
671
751
  unavailableReason: _types2.UnavailableReason.ProductNotApplicable
672
752
  };
673
753
  }
754
+ const scanOrderKey = this.getDiscountConfigOrderIdentityKey(this.store.tempOrder);
674
755
  const resultDiscountWithReason = (await this.store.discount?.batchSearch(code, {
675
756
  customerId
676
757
  })) || {
677
758
  discountList: [],
678
759
  unavailableReasonKey: null
679
760
  };
761
+ if (scanOrderKey !== this.getDiscountConfigOrderIdentityKey(this.store.tempOrder)) {
762
+ throw Object.assign(new Error('The scan session ended.'), {
763
+ code: 'SALES_GUARD_REJECTED'
764
+ });
765
+ }
680
766
  const {
681
- discountList: resultDiscountList,
682
767
  unavailableReasonKey
683
768
  } = resultDiscountWithReason;
769
+ const resultDiscountList = resultDiscountWithReason.discountList.filter(discount => !options?.productVouchersOnly || (discount.tag || discount.type) === 'good_pass');
684
770
  const rulesModule = this.store.rules;
685
771
  if (!rulesModule) {
686
772
  return {
@@ -707,7 +793,7 @@ class OrderModule extends _BaseModule.BaseModule {
707
793
  isScan: true
708
794
  }));
709
795
  const currentSelected = this.getDiscountList().filter(n => n.isSelected);
710
- if (currentSelected.length && currentSelected.some(n => withScanList.some(m => m.id === n.id))) {
796
+ if (currentSelected.length && (options?.productVouchersOnly ? withScanList.every(scanned => currentSelected.some(selected => selected.id === scanned.id)) : currentSelected.some(n => withScanList.some(m => m.id === n.id)))) {
711
797
  await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
712
798
  return {
713
799
  type: 'clientCalc',
@@ -2196,8 +2282,12 @@ class OrderModule extends _BaseModule.BaseModule {
2196
2282
  ...existed,
2197
2283
  ...(origin !== undefined ? {
2198
2284
  origin
2285
+ } : {}),
2286
+ ...(rawProduct._productVoucherGroupKey ? {
2287
+ productVoucherGroupKey: rawProduct._productVoucherGroupKey
2199
2288
  } : {})
2200
2289
  };
2290
+ delete normalizedProduct._productVoucherGroupKey;
2201
2291
  delete normalizedProduct._origin;
2202
2292
  delete normalizedProduct.unique_identification_number;
2203
2293
  }
@@ -3463,6 +3553,7 @@ class OrderModule extends _BaseModule.BaseModule {
3463
3553
  const isIncomingCustomItem = productToAdd.metadata?.origin?.isCustomItem === true || productToAdd._origin?.isCustomItem === true;
3464
3554
  const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
3465
3555
  const matchedIndex = shouldForceNewLine ? -1 : tempOrder.products.findIndex(item => {
3556
+ if ((0, _productVoucherGroups.productVoucherGroupKey)(tempOrder, item) !== productToAdd._productVoucherGroupKey) return false;
3466
3557
  if (this.hasGoodPassDiscount(item)) return false;
3467
3558
  const isRuntimeEntitlementPass = this.isRuntimeEntitlementAppend(item, tempOrder);
3468
3559
  if (isIncomingEntitlementAppend !== isRuntimeEntitlementPass) {
@@ -3642,7 +3733,18 @@ class OrderModule extends _BaseModule.BaseModule {
3642
3733
  * // → tempOrder.products 新增 3 行,每行 num=1,bookings 3 条
3643
3734
  */
3644
3735
  async addProductToOrder(product, booking, options) {
3645
- const tempOrder = this.ensureTempOrder();
3736
+ return this.queueCartCommand(() => this.addProductToOrderDraft(product, booking, options));
3737
+ }
3738
+ async addProductToOrderDraft(product, booking, options) {
3739
+ const mutation = this.beginCartMutation();
3740
+ let tempOrder = mutation.draft;
3741
+ if (options?.productVoucherGroupKey) {
3742
+ if (!tempOrder._extend?.productVoucherGroups?.some(group => group.key === options.productVoucherGroupKey)) throw (0, _productVoucherGroups.voucherGroupError)();
3743
+ product = {
3744
+ ...product,
3745
+ _productVoucherGroupKey: options.productVoucherGroupKey
3746
+ };
3747
+ }
3646
3748
  const salesNoteDrafts = (options?.salesNotes || []).map(draft => ({
3647
3749
  note_type: String(draft.note_type || '').trim(),
3648
3750
  text: {
@@ -3736,6 +3838,7 @@ class OrderModule extends _BaseModule.BaseModule {
3736
3838
  rollbackProductAndNotesMutation();
3737
3839
  throw error;
3738
3840
  }
3841
+ if (mutation.commit) tempOrder = await mutation.commit();
3739
3842
  await this.finalizeProductOrderMutation(tempOrder);
3740
3843
  this.logInfo('addProductToOrder success', {
3741
3844
  product_id: product.product_id,
@@ -3754,7 +3857,11 @@ class OrderModule extends _BaseModule.BaseModule {
3754
3857
  * ]);
3755
3858
  */
3756
3859
  async addProductsToOrder(items, options) {
3757
- const tempOrder = this.ensureTempOrder();
3860
+ return this.queueCartCommand(() => this.addProductsToOrderDraft(items, options));
3861
+ }
3862
+ async addProductsToOrderDraft(items, options) {
3863
+ const mutation = this.beginCartMutation();
3864
+ let tempOrder = mutation.draft;
3758
3865
  if (!Array.isArray(items) || items.length === 0) return tempOrder.products;
3759
3866
  for (const item of items || []) {
3760
3867
  const {
@@ -3777,6 +3884,7 @@ class OrderModule extends _BaseModule.BaseModule {
3777
3884
  const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking);
3778
3885
  if (appendResult) await appendResult;
3779
3886
  }
3887
+ if (mutation.commit) tempOrder = await mutation.commit();
3780
3888
  await this.finalizeProductOrderMutation(tempOrder, options);
3781
3889
  this.logInfo('addProductsToOrder success', {
3782
3890
  itemsCount: items.length
@@ -4109,9 +4217,14 @@ class OrderModule extends _BaseModule.BaseModule {
4109
4217
  return tempOrder.products[productIndex].metadata?.unique_identification_number;
4110
4218
  }
4111
4219
  async updateOrderProduct(params) {
4112
- const tempOrder = this.ensureTempOrder();
4220
+ return this.queueCartCommand(() => this.updateOrderProductDraft(params));
4221
+ }
4222
+ async updateOrderProductDraft(params) {
4223
+ const mutation = this.beginCartMutation();
4224
+ let tempOrder = mutation.draft;
4113
4225
  const reapplyWeighedDiscountProductUids = [];
4114
4226
  const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params, reapplyWeighedDiscountProductUids);
4227
+ if (mutation.commit) tempOrder = await mutation.commit();
4115
4228
  const promotionPayload = await this.evaluatePromotion();
4116
4229
  this.applyDiscount({
4117
4230
  reapplyWeighedDiscountProductUids,
@@ -4129,7 +4242,11 @@ class OrderModule extends _BaseModule.BaseModule {
4129
4242
  return tempOrder.products;
4130
4243
  }
4131
4244
  async updateOrderProducts(paramsList) {
4132
- const tempOrder = this.ensureTempOrder();
4245
+ return this.queueCartCommand(() => this.updateOrderProductsDraft(paramsList));
4246
+ }
4247
+ async updateOrderProductsDraft(paramsList) {
4248
+ const mutation = this.beginCartMutation();
4249
+ let tempOrder = mutation.draft;
4133
4250
  if (!paramsList.length) {
4134
4251
  return tempOrder.products;
4135
4252
  }
@@ -4142,6 +4259,7 @@ class OrderModule extends _BaseModule.BaseModule {
4142
4259
  }
4143
4260
  return acc;
4144
4261
  }, []);
4262
+ if (mutation.commit) tempOrder = await mutation.commit();
4145
4263
  await this.finalizeAfterProductsMutation(tempOrder, {
4146
4264
  reapplyWeighedDiscountProductUids,
4147
4265
  reapplyBookingDiscountProductUids: reapplyBookingDiscountProductUids.length ? reapplyBookingDiscountProductUids : undefined
@@ -4152,6 +4270,9 @@ class OrderModule extends _BaseModule.BaseModule {
4152
4270
  return tempOrder.products;
4153
4271
  }
4154
4272
  async updateOrderProductQuantity(params) {
4273
+ return this.queueCartCommand(() => this.updateOrderProductQuantityDraft(params));
4274
+ }
4275
+ async updateOrderProductQuantityDraft(params) {
4155
4276
  const {
4156
4277
  product_id,
4157
4278
  product_variant_id,
@@ -4161,7 +4282,8 @@ class OrderModule extends _BaseModule.BaseModule {
4161
4282
  product_sku,
4162
4283
  product_bundle
4163
4284
  } = params;
4164
- const tempOrder = this.ensureTempOrder();
4285
+ const mutation = this.beginCartMutation();
4286
+ let tempOrder = mutation.draft;
4165
4287
  this.repairDuplicateProductLineIdentities(tempOrder);
4166
4288
  const identityLookup = {
4167
4289
  product_id,
@@ -4218,6 +4340,7 @@ class OrderModule extends _BaseModule.BaseModule {
4218
4340
  }
4219
4341
  }
4220
4342
  tempOrder.products[productIndex] = normalizedProduct;
4343
+ if (mutation.commit) tempOrder = await mutation.commit();
4221
4344
  this.prepareVirtualSettlementTempOrder(tempOrder);
4222
4345
  const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
4223
4346
  const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
@@ -4294,7 +4417,11 @@ class OrderModule extends _BaseModule.BaseModule {
4294
4417
  * await order.removeProductsFromOrder([identityA, identityB]);
4295
4418
  */
4296
4419
  async removeProductsFromOrder(identities, options) {
4297
- const tempOrder = this.ensureTempOrder();
4420
+ return this.queueCartCommand(() => this.removeProductsFromOrderDraft(identities, options));
4421
+ }
4422
+ async removeProductsFromOrderDraft(identities, options) {
4423
+ const mutation = this.beginCartMutation();
4424
+ let tempOrder = mutation.draft;
4298
4425
  if (!identities.length) {
4299
4426
  return tempOrder.products;
4300
4427
  }
@@ -4361,6 +4488,7 @@ class OrderModule extends _BaseModule.BaseModule {
4361
4488
  }
4362
4489
  }
4363
4490
  this.removeSalesNotesForMissingProductLines(tempOrder);
4491
+ if (mutation.commit) tempOrder = await mutation.commit();
4364
4492
  await this.finalizeAfterProductsMutation(tempOrder);
4365
4493
  this.logInfo('removeProductsFromOrder success', {
4366
4494
  identities
@@ -4376,7 +4504,11 @@ class OrderModule extends _BaseModule.BaseModule {
4376
4504
  * 普通整单 note 保持不变;以商品行为主体的 Sales Notes 同步删除。
4377
4505
  */
4378
4506
  async clearOrderCartLines() {
4379
- const tempOrder = this.ensureTempOrder();
4507
+ return this.queueCartCommand(() => this.clearOrderCartLinesDraft());
4508
+ }
4509
+ async clearOrderCartLinesDraft() {
4510
+ const mutation = this.beginCartMutation();
4511
+ let tempOrder = mutation.draft;
4380
4512
  this.ensureSalesNotesLoadedForMutation(tempOrder);
4381
4513
  tempOrder.products = [];
4382
4514
  tempOrder.bookings = [];
@@ -4389,6 +4521,7 @@ class OrderModule extends _BaseModule.BaseModule {
4389
4521
  productsByUid: {}
4390
4522
  };
4391
4523
  }
4524
+ if (mutation.commit) tempOrder = await mutation.commit();
4392
4525
  const promotionPayload = await this.evaluatePromotion();
4393
4526
  this.applyDiscount();
4394
4527
  this.sanitizeTempOrderProducts(tempOrder);
@@ -4525,6 +4658,7 @@ class OrderModule extends _BaseModule.BaseModule {
4525
4658
  }
4526
4659
  async runSubmitTempOrder(params) {
4527
4660
  const tempOrder = this.ensureTempOrder();
4661
+ (0, _productVoucherGroups.validateProductVoucherGroups)(tempOrder, this.getDiscountList(), undefined, true);
4528
4662
  this.prepareVirtualSettlementTempOrder(tempOrder);
4529
4663
  const isOnlineStorePlatform = this.isOnlineStorePlatform();
4530
4664
  const shouldConfirmPendingVoucherPayments = params?.confirmPendingVoucherPayments !== false;
@@ -438,6 +438,8 @@ export type AddProductBookingInput = Record<string, any>;
438
438
  * 避免步进器修改数量改变该组展示位置。
439
439
  */
440
440
  export interface AddProductToOrderOptions {
441
+ /** Associates a selection with an existing runtime voucher group. */
442
+ productVoucherGroupKey?: string;
441
443
  insertAfterProductUid?: string;
442
444
  /** 跳过同商品/规格匹配,始终新增购物车行。 */
443
445
  disableMerge?: boolean;
@@ -517,6 +519,11 @@ export type OrderProductMergeDecisionResult = boolean | {
517
519
  [key: string]: any;
518
520
  };
519
521
  export interface OrderHooksConfig {
522
+ /** Awaited before a local cart draft is published. Reject to leave the live order unchanged. */
523
+ onBeforeCartCommit?: (context: {
524
+ currentItems: readonly OrderProduct[];
525
+ proposedItems: readonly OrderProduct[];
526
+ }) => void | Promise<void>;
520
527
  onBeforeMergeProductToOrder?: (context: OrderProductMergeDecisionContext) => OrderProductMergeDecisionResult | Promise<OrderProductMergeDecisionResult>;
521
528
  }
522
529
  /**
@@ -192,7 +192,7 @@ function consolidateDiscountFreeProductLines(tempOrder) {
192
192
  bundle_selling_price: String(bundle?.bundle_selling_price ?? '')
193
193
  }))
194
194
  });
195
- const mergeKey = [discountSplitOriginUid, product.product_id, product.product_variant_id ?? 0, fingerprint, priceSignature].join('#');
195
+ const mergeKey = [discountSplitOriginUid, productUid ? tempOrder._extend?.productsByUid?.[productUid]?.productVoucherGroupKey ?? '' : '', product.product_id, product.product_variant_id ?? 0, fingerprint, priceSignature].join('#');
196
196
  const matchedIndex = productIndexByKey.get(mergeKey);
197
197
 
198
198
  // 当前拆分来源 + 商品结构组合第一次出现时,保留该行作为回并目标。
@@ -0,0 +1,15 @@
1
+ import type { Discount } from '../../Discount/types';
2
+ import type { OrderTempOrder } from '../types';
3
+ /** Runtime-only allocation constraints. Never copied into order/product metadata. */
4
+ export interface ProductVoucherGroup {
5
+ key: string;
6
+ discountIds: Array<number | string>;
7
+ }
8
+ export declare function productVoucherGroupKey(order: OrderTempOrder, product: any): string | undefined;
9
+ export declare function isUsableProductVoucher(discount: Discount): boolean;
10
+ export declare function voucherGroupError(): Error & {
11
+ code: string;
12
+ };
13
+ export declare function allowsProductVoucher(order: OrderTempOrder | null | undefined, product: any, discount: Discount): boolean;
14
+ /** Reductions stay possible when a voucher expires; checkout always requires full coverage. */
15
+ export declare function validateProductVoucherGroups(order: OrderTempOrder, discounts: Discount[], previous?: OrderTempOrder, requireCoverage?: boolean): void;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.allowsProductVoucher = allowsProductVoucher;
7
+ exports.isUsableProductVoucher = isUsableProductVoucher;
8
+ exports.productVoucherGroupKey = productVoucherGroupKey;
9
+ exports.validateProductVoucherGroups = validateProductVoucherGroups;
10
+ exports.voucherGroupError = voucherGroupError;
11
+ var _availability = require("../../Discount/availability");
12
+ var _dayjs = _interopRequireDefault(require("dayjs"));
13
+ var _utils = require("../../../solution/ShopDiscount/utils");
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ /** Runtime-only allocation constraints. Never copied into order/product metadata. */
16
+
17
+ function productVoucherGroupKey(order, product) {
18
+ const uid = product?.metadata?.unique_identification_number ?? product?.unique_identification_number;
19
+ return order._extend?.productsByUid?.[String(uid)]?.productVoucherGroupKey;
20
+ }
21
+ function isUsableProductVoucher(discount) {
22
+ return (discount.tag || discount.type) === 'good_pass' && !discount.isEditMode && !discount.isDisabled && !(0, _availability.getDiscountUsageBlockReason)(discount) && !(0, _utils.getDiscountTimeUnavailableReason)(discount, (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss'));
23
+ }
24
+ function voucherGroupError() {
25
+ return Object.assign(new Error('The selected items no longer match the available vouchers. Please adjust your selection.'), {
26
+ code: 'PRODUCT_VOUCHER_GROUP_INVALID'
27
+ });
28
+ }
29
+ function allowsProductVoucher(order, product, discount) {
30
+ const groups = order?._extend?.productVoucherGroups;
31
+ if (!order || !groups?.length) return true;
32
+ const key = productVoucherGroupKey(order, product);
33
+ if (!key) return !groups.some(group => group.discountIds.some(id => String(id) === String(discount.id)));
34
+ return (discount.tag || discount.type) === 'good_pass' && Boolean(groups.find(group => group.key === key)?.discountIds.some(id => String(id) === String(discount.id)));
35
+ }
36
+
37
+ /** Reductions stay possible when a voucher expires; checkout always requires full coverage. */
38
+ function validateProductVoucherGroups(order, discounts, previous, requireCoverage = false) {
39
+ const groups = order._extend?.productVoucherGroups;
40
+ if (!groups?.length) return;
41
+ const usedIds = new Set();
42
+ const byId = new Map(discounts.filter(isUsableProductVoucher).map(discount => [String(discount.id), discount]));
43
+ const quantity = item => Number(item.num ?? item.product_quantity ?? 0);
44
+ for (const group of groups) {
45
+ const items = order.products.filter(item => productVoucherGroupKey(order, item) === group.key);
46
+ const selected = items.reduce((sum, item) => sum + quantity(item), 0);
47
+ const before = previous?.products.filter(item => productVoucherGroupKey(previous, item) === group.key).reduce((sum, item) => sum + quantity(item), 0) ?? 0;
48
+ if (!requireCoverage && previous && selected <= before) continue;
49
+ const ids = new Set(group.discountIds.map(String).filter(id => byId.has(id)));
50
+ if (!Number.isInteger(selected) || selected < 0 || selected > ids.size) throw voucherGroupError();
51
+ if (!requireCoverage) continue;
52
+ for (const item of items) {
53
+ const applied = (item.discount_list || []).filter(entry => (entry.type || entry.tag) === 'good_pass');
54
+ // Rules splits a good_pass allocation into one physical line per instance.
55
+ const id = String(applied[0]?.discount?.resource_id ?? '');
56
+ const voucher = byId.get(id);
57
+ if (quantity(item) !== 1 || applied.length !== 1 || !ids.has(id) || !voucher?.isAvailable || voucher.config?.isAvailable === false || usedIds.has(id)) throw voucherGroupError();
58
+ usedIds.add(id);
59
+ }
60
+ }
61
+ if (order.products.some(item => !groups.some(group => group.key === productVoucherGroupKey(order, item)))) {
62
+ throw voucherGroupError();
63
+ }
64
+ }
@@ -121,8 +121,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
121
121
  * = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
122
122
  * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
123
123
  * 不含折扣。**权威源**。
124
- * - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
125
- * - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
124
+ * - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
125
+ * - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
126
+ * - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
126
127
  * - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
127
128
  *
128
129
  * Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
@@ -131,8 +132,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
131
132
  * `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
132
133
  * - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
133
134
  * total(source + option + bundle)对齐。
135
+ * - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
134
136
  * - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
135
- * 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
137
+ * 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
136
138
  * 优先级:
137
139
  * 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
138
140
  * 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
@@ -632,8 +632,9 @@ function getBundleSellingMagnitude(bundle) {
632
632
  * = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
633
633
  * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
634
634
  * 不含折扣。**权威源**。
635
- * - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
636
- * - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
635
+ * - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
636
+ * - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
637
+ * - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
637
638
  * - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
638
639
  *
639
640
  * Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
@@ -642,8 +643,9 @@ function getBundleSellingMagnitude(bundle) {
642
643
  * `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
643
644
  * - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
644
645
  * total(source + option + bundle)对齐。
646
+ * - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
645
647
  * - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
646
- * 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
648
+ * 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
647
649
  * 优先级:
648
650
  * 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
649
651
  * 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
@@ -842,6 +844,14 @@ function createDefaultOrderRulesHooks(getBookings) {
842
844
  const effectiveNum = Number(num) > 0 ? Number(num) : 1;
843
845
  return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
844
846
  };
847
+
848
+ // optionDiscountAmount 已是每件主商品内的单规格优惠合计,不再乘商品数量。
849
+ const getOptionDiscountAmount = discountList => {
850
+ return (discountList || []).reduce((total, discount) => {
851
+ if (discount?.metadata?.custom_product_bundle_map_id) return total;
852
+ return total.plus(Number(discount?.metadata?.optionDiscountAmount) || 0);
853
+ }, new _decimal.default(0));
854
+ };
845
855
  const getBundleIdentity = bundle => {
846
856
  return [bundle.bundle_id ?? bundle.id ?? '', bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? '', bundle.bundle_variant_id ?? bundle.variant_id ?? bundle.product_variant_id ?? 0, bundle.bundle_group_id ?? bundle.group_id ?? ''].join('|');
847
857
  };
@@ -884,12 +894,14 @@ function createDefaultOrderRulesHooks(getBookings) {
884
894
  getProduct: product => {
885
895
  // source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
886
896
  const metadataAny = product.metadata || {};
887
- const optionSum = sumOptionUnitPrice(getProductSkuOptions(product));
897
+ const productOptions = getProductSkuOptions(product);
898
+ const optionSum = sumOptionUnitPrice(productOptions);
899
+ const optionSellingSum = optionSum.minus(getOptionDiscountAmount(product.discount_list));
888
900
  let sourcePrice;
889
901
  if (metadataAny.source_product_price !== undefined) {
890
902
  sourcePrice = String(metadataAny.source_product_price);
891
903
  } else if (metadataAny.main_product_selling_price !== undefined) {
892
- sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString();
904
+ sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString();
893
905
  } else {
894
906
  sourcePrice = String(product.selling_price ?? 0);
895
907
  }
@@ -919,6 +931,11 @@ function createDefaultOrderRulesHooks(getBookings) {
919
931
  num: product.num || 1,
920
932
  discount_list: product.discount_list || [],
921
933
  bundle: product.product_bundle || [],
934
+ // 仅在 Rules 入参中映射 price,避免折后价污染订单的 add_price。
935
+ options: productOptions.map(option => ({
936
+ ...option,
937
+ price: option.add_price
938
+ })),
922
939
  booking_id: product.metadata?.booking_id || null,
923
940
  isClient: false,
924
941
  // 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
@@ -926,7 +943,7 @@ function createDefaultOrderRulesHooks(getBookings) {
926
943
  isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
927
944
  holder_id: product.metadata?.holder_id,
928
945
  startDate: getProductStartDate(product),
929
- main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString() : undefined,
946
+ main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString() : undefined,
930
947
  inPromotion: metadataAny._promotion?.inPromotion === true,
931
948
  _promotion: metadataAny._promotion
932
949
  };
@@ -937,8 +954,10 @@ function createDefaultOrderRulesHooks(getBookings) {
937
954
  const existedSource = metadataAny.source_product_price ?? product.selling_price ?? '0';
938
955
  const nextOptions = getProductSkuOptions(product);
939
956
  const optionSum = sumOptionUnitPrice(nextOptions);
957
+ const nextDiscountList = values.discount_list ?? product.discount_list;
958
+ const optionSellingSum = optionSum.minus(getOptionDiscountAmount(nextDiscountList));
940
959
 
941
- // Rules 返回的 main_product_selling_price / price / total 均为 source-level。
960
+ // Rules 返回的 main_product_selling_price / price 为不含 option 的主商品价。
942
961
  // 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
943
962
  // total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
944
963
  const nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
@@ -947,8 +966,8 @@ function createDefaultOrderRulesHooks(getBookings) {
947
966
  // 缺省时保留现有 source(券前 = 当前 source)。
948
967
  const nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
949
968
 
950
- // 含 option 的 main_product_*
951
- const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
969
+ // 成交价只加回 option 折后合计;原价仍使用订单中保存的 option 原价。
970
+ const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSellingSum).toDecimalPlaces(2).toFixed(2);
952
971
  const nextMainOriginalPrice = new _decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
953
972
  const nextBundle = values.bundle !== undefined ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
954
973
  const composedSellingPrice = composeLinePrice({
@@ -969,7 +988,7 @@ function createDefaultOrderRulesHooks(getBookings) {
969
988
  ...product,
970
989
  selling_price: composedSellingPrice,
971
990
  original_price: finalOriginalPrice,
972
- discount_list: values.discount_list ?? product.discount_list,
991
+ discount_list: nextDiscountList,
973
992
  num: values.quantity ?? product.num,
974
993
  product_bundle: nextBundle,
975
994
  metadata: {
@@ -66,7 +66,13 @@ class ProductList extends _BaseModule.BaseModule {
66
66
  * productList.updateOtherParams({ channel: 'pos' });
67
67
  */
68
68
  updateOtherParams(params) {
69
+ const previousScope = this.otherParams.catalogScopeKey;
69
70
  this.otherParams = params || {};
71
+ if (previousScope !== this.otherParams.catalogScopeKey && (previousScope || this.otherParams.catalogScopeKey)) {
72
+ this.store.list = [];
73
+ this.rawProductPriceSources.clear();
74
+ this.core.effects.emit(`${this.name}:changed`, this.store.list);
75
+ }
70
76
  }
71
77
  async storeChange(path, value) {
72
78
  // No longer needed - products are stored as plain objects instead of Product instances
@@ -101,6 +107,12 @@ class ProductList extends _BaseModule.BaseModule {
101
107
  status = 'published',
102
108
  strategy_context
103
109
  } = {}, options) {
110
+ const scope = this.otherParams.catalogScopeKey;
111
+ const assertScope = () => {
112
+ if (scope !== this.otherParams.catalogScopeKey) throw Object.assign(new Error('Product catalog context changed'), {
113
+ name: 'AbortError'
114
+ });
115
+ };
104
116
  // // 如果 schedule_ids 为空,则需要尝试从 schedule 模块里获取
105
117
  // if (!schedule_ids?.length) {
106
118
  // const schedule_ids_data = this.store.schedule
@@ -180,6 +192,7 @@ class ProductList extends _BaseModule.BaseModule {
180
192
  const handledByOsServer = (0, _clientDataVariants.isProductQueryHandledByOsServer)(this.core, this.request);
181
193
  const originalCallback = options?.callback;
182
194
  const subscriptionCallback = typeof originalCallback === 'function' ? async result => {
195
+ if (scope !== this.otherParams.catalogScopeKey) return;
183
196
  const callbackList = result?.data?.list;
184
197
  if (!Array.isArray(callbackList)) {
185
198
  originalCallback(result);
@@ -197,6 +210,7 @@ class ProductList extends _BaseModule.BaseModule {
197
210
  queryPayload,
198
211
  handledByOsServer
199
212
  });
213
+ assertScope();
200
214
  await this.addProduct(products);
201
215
  originalCallback(handledByOsServer ? result : {
202
216
  ...result,
@@ -212,6 +226,7 @@ class ProductList extends _BaseModule.BaseModule {
212
226
  subscriberId: options?.subscriberId,
213
227
  customToast: () => {}
214
228
  });
229
+ assertScope();
215
230
  if (!handledByOsServer && Array.isArray(productsData.data.list)) {
216
231
  this.replaceRawProductQueryResult(productsData.data.list, product_ids);
217
232
  }
@@ -9,6 +9,8 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
9
9
  private store;
10
10
  window: WindowPlugin;
11
11
  private hooks;
12
+ private discountScope?;
13
+ setDiscountScope(scope: (product: any, discount: Discount) => boolean): void;
12
14
  constructor(name?: string, version?: string);
13
15
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
14
16
  setRulesList(rulesList: Rules[]): Promise<void>;