@pisell/pisellos 2.2.244 → 2.2.246

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 (316) hide show
  1. package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
  2. package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
  3. package/dist/modules/BookingContext/index.d.ts +48 -0
  4. package/dist/modules/BookingContext/index.js +566 -0
  5. package/dist/modules/BookingContext/types.d.ts +102 -0
  6. package/dist/modules/BookingContext/types.js +51 -0
  7. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +284 -0
  9. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  10. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +148 -0
  11. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  12. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +218 -0
  13. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  14. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  15. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  16. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  17. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  18. package/dist/modules/BookingContext/utils/index.js +11 -0
  19. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  20. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  21. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  22. package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
  23. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  24. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  25. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  26. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  27. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  28. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  29. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  30. package/dist/modules/BookingContext/utils/resources.js +486 -0
  31. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  32. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  33. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  34. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  35. package/dist/modules/Cart/utils/cartProduct.js +24 -3
  36. package/dist/modules/Cart/utils/changePrice.js +11 -11
  37. package/dist/modules/Customer/index.d.ts +20 -0
  38. package/dist/modules/Customer/index.js +172 -83
  39. package/dist/modules/Customer/types.d.ts +2 -0
  40. package/dist/modules/Discount/index.d.ts +1 -1
  41. package/dist/modules/Discount/index.js +13 -6
  42. package/dist/modules/Discount/types.d.ts +1 -0
  43. package/dist/modules/OpenData/index.d.ts +8 -0
  44. package/dist/modules/OpenData/index.js +37 -17
  45. package/dist/modules/Order/index.d.ts +277 -18
  46. package/dist/modules/Order/index.js +3581 -779
  47. package/dist/modules/Order/types.d.ts +286 -31
  48. package/dist/modules/Order/types.js +38 -0
  49. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  50. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  51. package/dist/modules/Order/utils.d.ts +147 -5
  52. package/dist/modules/Order/utils.js +750 -104
  53. package/dist/modules/Payment/index.d.ts +10 -13
  54. package/dist/modules/Payment/index.js +467 -837
  55. package/dist/modules/Payment/types.d.ts +2 -0
  56. package/dist/modules/Payment/utils.js +2 -1
  57. package/dist/modules/Payment/walletpass.js +41 -25
  58. package/dist/modules/ProductList/index.d.ts +16 -12
  59. package/dist/modules/ProductList/index.js +133 -59
  60. package/dist/modules/ProductList/types.d.ts +14 -0
  61. package/dist/modules/Quotation/index.d.ts +0 -1
  62. package/dist/modules/Quotation/index.js +25 -22
  63. package/dist/modules/Rules/index.d.ts +4 -0
  64. package/dist/modules/Rules/index.js +97 -70
  65. package/dist/modules/Rules/types.d.ts +1 -0
  66. package/dist/modules/SalesSummary/index.d.ts +8 -25
  67. package/dist/modules/SalesSummary/index.js +86 -35
  68. package/dist/modules/SalesSummary/types.d.ts +4 -1
  69. package/dist/modules/SalesSummary/utils.d.ts +2 -25
  70. package/dist/modules/SalesSummary/utils.js +794 -162
  71. package/dist/modules/Schedule/index.d.ts +7 -0
  72. package/dist/modules/Schedule/index.js +24 -2
  73. package/dist/modules/Summary/index.js +4 -3
  74. package/dist/modules/SurchargeList/index.d.ts +16 -0
  75. package/dist/modules/SurchargeList/index.js +162 -0
  76. package/dist/modules/SurchargeList/types.d.ts +11 -0
  77. package/dist/modules/SurchargeList/types.js +1 -0
  78. package/dist/modules/index.d.ts +2 -0
  79. package/dist/modules/index.js +3 -1
  80. package/dist/plugins/request.d.ts +1 -0
  81. package/dist/server/index.d.ts +204 -1
  82. package/dist/server/index.js +3654 -922
  83. package/dist/server/modules/index.d.ts +2 -0
  84. package/dist/server/modules/index.js +2 -0
  85. package/dist/server/modules/order/index.d.ts +120 -3
  86. package/dist/server/modules/order/index.js +1762 -448
  87. package/dist/server/modules/order/types.d.ts +32 -3
  88. package/dist/server/modules/order/types.js +8 -0
  89. package/dist/server/modules/order/utils/filterBookings.js +26 -3
  90. package/dist/server/modules/order/utils/filterOrders.js +23 -8
  91. package/dist/server/modules/payment/index.d.ts +28 -0
  92. package/dist/server/modules/payment/index.js +305 -0
  93. package/dist/server/modules/payment/types.d.ts +9 -0
  94. package/dist/server/modules/payment/types.js +1 -0
  95. package/dist/server/modules/products/index.d.ts +34 -7
  96. package/dist/server/modules/products/index.js +631 -317
  97. package/dist/server/modules/resource/index.d.ts +2 -0
  98. package/dist/server/modules/resource/index.js +29 -3
  99. package/dist/server/modules/schedule/index.d.ts +4 -4
  100. package/dist/server/modules/schedule/index.js +111 -88
  101. package/dist/server/test.json +713 -0
  102. package/dist/server/utils/small-ticket.d.ts +71 -0
  103. package/dist/server/utils/small-ticket.js +840 -0
  104. package/dist/solution/BaseSales/index.d.ts +133 -10
  105. package/dist/solution/BaseSales/index.js +1950 -447
  106. package/dist/solution/BaseSales/types.d.ts +82 -6
  107. package/dist/solution/BaseSales/types.js +5 -4
  108. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  109. package/dist/solution/BaseSales/utils/cartPromotion.js +1438 -0
  110. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  111. package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
  112. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  113. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +105 -24
  114. package/dist/solution/BaseSales/utils.d.ts +1 -1
  115. package/dist/solution/BaseSales/utils.js +62 -21
  116. package/dist/solution/BookingByStep/index.d.ts +1 -1
  117. package/dist/solution/BookingTicket/index.d.ts +271 -11
  118. package/dist/solution/BookingTicket/index.js +1777 -242
  119. package/dist/solution/BookingTicket/types.d.ts +118 -1
  120. package/dist/solution/BookingTicket/types.js +41 -2
  121. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  122. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  123. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  124. package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
  125. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  126. package/dist/solution/BookingTicket/utils/bookingStatus.js +70 -0
  127. package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
  128. package/dist/solution/BookingTicket/utils/cartView.js +94 -7
  129. package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  130. package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
  131. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  132. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
  133. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  134. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
  135. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  136. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
  137. package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  138. package/dist/solution/BookingTicket/utils/scan/index.js +20 -8
  139. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  140. package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
  141. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  142. package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
  143. package/dist/solution/Checkout/index.d.ts +1 -0
  144. package/dist/solution/Checkout/index.js +10 -9
  145. package/dist/solution/RegisterAndLogin/config.js +2 -10
  146. package/dist/solution/ScanOrder/index.d.ts +9 -3
  147. package/dist/solution/ScanOrder/index.js +241 -134
  148. package/dist/solution/ScanOrder/types.d.ts +9 -5
  149. package/dist/solution/ScanOrder/types.js +2 -3
  150. package/dist/solution/ScanOrder/utils.d.ts +1 -1
  151. package/dist/solution/ScanOrder/utils.js +84 -22
  152. package/dist/solution/VenueBooking/index.d.ts +5 -2
  153. package/dist/solution/VenueBooking/index.js +110 -59
  154. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  155. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  156. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
  157. package/dist/types/index.d.ts +10 -0
  158. package/lib/model/strategy/adapter/promotion/evaluator.js +2 -1
  159. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  160. package/lib/model/strategy/adapter/walletPass/utils.js +3 -2
  161. package/lib/modules/BookingContext/index.d.ts +48 -0
  162. package/lib/modules/BookingContext/index.js +368 -0
  163. package/lib/modules/BookingContext/types.d.ts +102 -0
  164. package/lib/modules/BookingContext/types.js +34 -0
  165. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  166. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
  167. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  168. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +154 -0
  169. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  170. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +201 -0
  171. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  172. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  173. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  174. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  175. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  176. package/lib/modules/BookingContext/utils/index.js +43 -0
  177. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  178. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  179. package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  180. package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
  181. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  182. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  183. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  184. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  185. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  186. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  187. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  188. package/lib/modules/BookingContext/utils/resources.js +377 -0
  189. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  190. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  191. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  192. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  193. package/lib/modules/Cart/utils/cartProduct.js +20 -3
  194. package/lib/modules/Cart/utils/changePrice.js +12 -20
  195. package/lib/modules/Customer/index.d.ts +20 -0
  196. package/lib/modules/Customer/index.js +64 -11
  197. package/lib/modules/Customer/types.d.ts +2 -0
  198. package/lib/modules/Discount/index.d.ts +1 -1
  199. package/lib/modules/Discount/index.js +9 -1
  200. package/lib/modules/Discount/types.d.ts +1 -0
  201. package/lib/modules/OpenData/index.d.ts +8 -0
  202. package/lib/modules/OpenData/index.js +19 -5
  203. package/lib/modules/Order/index.d.ts +277 -18
  204. package/lib/modules/Order/index.js +2317 -337
  205. package/lib/modules/Order/types.d.ts +286 -31
  206. package/lib/modules/Order/types.js +1 -0
  207. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  208. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  209. package/lib/modules/Order/utils.d.ts +147 -5
  210. package/lib/modules/Order/utils.js +615 -46
  211. package/lib/modules/Payment/index.d.ts +10 -13
  212. package/lib/modules/Payment/index.js +18 -150
  213. package/lib/modules/Payment/types.d.ts +2 -0
  214. package/lib/modules/Payment/utils.js +2 -1
  215. package/lib/modules/Payment/walletpass.js +16 -3
  216. package/lib/modules/ProductList/index.d.ts +16 -12
  217. package/lib/modules/ProductList/index.js +41 -4
  218. package/lib/modules/ProductList/types.d.ts +14 -0
  219. package/lib/modules/Quotation/index.d.ts +0 -1
  220. package/lib/modules/Quotation/index.js +19 -16
  221. package/lib/modules/Rules/index.d.ts +4 -0
  222. package/lib/modules/Rules/index.js +137 -120
  223. package/lib/modules/Rules/types.d.ts +1 -0
  224. package/lib/modules/SalesSummary/index.d.ts +8 -25
  225. package/lib/modules/SalesSummary/index.js +30 -4
  226. package/lib/modules/SalesSummary/types.d.ts +4 -1
  227. package/lib/modules/SalesSummary/utils.d.ts +2 -25
  228. package/lib/modules/SalesSummary/utils.js +645 -91
  229. package/lib/modules/Schedule/index.d.ts +7 -0
  230. package/lib/modules/Schedule/index.js +17 -1
  231. package/lib/modules/Summary/index.js +5 -4
  232. package/lib/modules/SurchargeList/index.d.ts +16 -0
  233. package/lib/modules/SurchargeList/index.js +89 -0
  234. package/lib/modules/SurchargeList/types.d.ts +11 -0
  235. package/lib/modules/SurchargeList/types.js +17 -0
  236. package/lib/modules/index.d.ts +2 -0
  237. package/lib/modules/index.js +5 -1
  238. package/lib/plugins/request.d.ts +1 -0
  239. package/lib/server/index.d.ts +204 -1
  240. package/lib/server/index.js +1891 -59
  241. package/lib/server/modules/index.d.ts +2 -0
  242. package/lib/server/modules/index.js +3 -0
  243. package/lib/server/modules/order/index.d.ts +120 -3
  244. package/lib/server/modules/order/index.js +887 -94
  245. package/lib/server/modules/order/types.d.ts +32 -3
  246. package/lib/server/modules/order/utils/filterBookings.js +24 -5
  247. package/lib/server/modules/order/utils/filterOrders.js +15 -6
  248. package/lib/server/modules/payment/index.d.ts +28 -0
  249. package/lib/server/modules/payment/index.js +192 -0
  250. package/lib/server/modules/payment/types.d.ts +9 -0
  251. package/lib/server/modules/payment/types.js +17 -0
  252. package/lib/server/modules/products/index.d.ts +34 -7
  253. package/lib/server/modules/products/index.js +189 -54
  254. package/lib/server/modules/resource/index.d.ts +2 -0
  255. package/lib/server/modules/resource/index.js +27 -3
  256. package/lib/server/modules/schedule/index.d.ts +4 -4
  257. package/lib/server/modules/schedule/index.js +47 -40
  258. package/lib/server/test.json +713 -0
  259. package/lib/server/utils/small-ticket.d.ts +71 -0
  260. package/lib/server/utils/small-ticket.js +800 -0
  261. package/lib/solution/BaseSales/index.d.ts +133 -10
  262. package/lib/solution/BaseSales/index.js +1111 -63
  263. package/lib/solution/BaseSales/types.d.ts +82 -6
  264. package/lib/solution/BaseSales/types.js +3 -1
  265. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  266. package/lib/solution/BaseSales/utils/cartPromotion.js +992 -0
  267. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  268. package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
  269. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  270. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +106 -18
  271. package/lib/solution/BaseSales/utils.d.ts +1 -1
  272. package/lib/solution/BaseSales/utils.js +54 -10
  273. package/lib/solution/BookingByStep/index.d.ts +1 -1
  274. package/lib/solution/BookingTicket/index.d.ts +271 -11
  275. package/lib/solution/BookingTicket/index.js +922 -29
  276. package/lib/solution/BookingTicket/types.d.ts +118 -1
  277. package/lib/solution/BookingTicket/types.js +11 -0
  278. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  279. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  280. package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  281. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
  282. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  283. package/lib/solution/BookingTicket/utils/bookingStatus.js +44 -2
  284. package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
  285. package/lib/solution/BookingTicket/utils/cartView.js +61 -6
  286. package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  287. package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
  288. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  289. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
  290. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  291. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
  292. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  293. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
  294. package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  295. package/lib/solution/BookingTicket/utils/scan/index.js +17 -3
  296. package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  297. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
  298. package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  299. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
  300. package/lib/solution/Checkout/index.d.ts +1 -0
  301. package/lib/solution/Checkout/index.js +1 -2
  302. package/lib/solution/RegisterAndLogin/config.js +2 -10
  303. package/lib/solution/ScanOrder/index.d.ts +9 -3
  304. package/lib/solution/ScanOrder/index.js +153 -70
  305. package/lib/solution/ScanOrder/types.d.ts +9 -5
  306. package/lib/solution/ScanOrder/utils.d.ts +1 -1
  307. package/lib/solution/ScanOrder/utils.js +83 -17
  308. package/lib/solution/VenueBooking/index.d.ts +5 -2
  309. package/lib/solution/VenueBooking/index.js +54 -17
  310. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  311. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  312. package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
  313. package/lib/types/index.d.ts +10 -0
  314. package/package.json +1 -1
  315. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  316. package/lib/solution/Checkout/appointmentDemo.json +0 -1
@@ -37,37 +37,157 @@ var import_types = require("./types");
37
37
  var import_utils = require("./utils");
38
38
  var import_utils2 = require("../Product/utils");
39
39
  var import_dayjs = __toESM(require("dayjs"));
40
+ var import_cartPromotion = require("../../solution/BaseSales/utils/cartPromotion");
40
41
  var import_utils3 = require("../../solution/ScanOrder/utils");
42
+ var import_manualProductDiscount = require("./utils/manualProductDiscount");
41
43
  var import_Discount = require("../Discount");
42
44
  var import_Rules = require("../Rules");
43
45
  var import_types2 = require("../Rules/types");
44
46
  var import_decimal = __toESM(require("decimal.js"));
45
47
  var import_lodash_es = require("lodash-es");
46
- var LOCAL_ORDER_STORE_NAME = "orders";
48
+ function normalizeDiscountListSignature(discountList) {
49
+ return (discountList || []).map((item) => ({
50
+ type: (item == null ? void 0 : item.type) ?? "",
51
+ discount_id: (item == null ? void 0 : item.discount_id) ?? null,
52
+ order_discount_id: (item == null ? void 0 : item.order_discount_id) ?? null,
53
+ amount: new import_decimal.default(Number(item == null ? void 0 : item.amount) || 0).toFixed(2)
54
+ }));
55
+ }
56
+ function isSameDiscountList(left, right) {
57
+ if (!Array.isArray(left) || !Array.isArray(right))
58
+ return false;
59
+ return JSON.stringify(normalizeDiscountListSignature(left)) === JSON.stringify(
60
+ normalizeDiscountListSignature(right)
61
+ );
62
+ }
63
+ function isManualProductDiscountProduct(product) {
64
+ var _a, _b;
65
+ return ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.is_manual_discount) === true || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.is_manual_discount) === 1 || ((product == null ? void 0 : product.discount_list) || []).some((item) => (item == null ? void 0 : item.type) === "product");
66
+ }
47
67
  var OrderModule = class extends import_BaseModule.BaseModule {
48
68
  constructor(name, version) {
49
69
  super(name || "order", version);
50
70
  this.defaultName = "order";
51
71
  this.defaultVersion = "1.0.0";
72
+ // ─── 促销/赠品 ────────────────────────────────────
73
+ /** 评估器引用;由 SalesSdkProvider 注入,未注入时 applyPromotion 静默跳过 */
74
+ this.promotionEvaluator = null;
75
+ /** 赠品选择 resolver;由 SDK host bridge 注入 */
76
+ this.giftSelectResolver = null;
77
+ /** applyPromotion 递归保护 flag(写路径同步调 applyPromotion,禁止重入) */
78
+ this.isApplyingPromotion = false;
79
+ /** 最近一次 applyPromotion 的未满足促销提示 */
80
+ this.lastUnfulfilledPromotions = [];
81
+ /** 最近一次 applyPromotion 的赠品操作 diff(debug / SDK 读取使用) */
82
+ this.lastGiftActions = null;
83
+ /**
84
+ * 是否将 tempOrder 写入 IndexedDB 草稿(orders store)。
85
+ * BigSale 弹窗等短生命周期场景通过 setEnableTempOrderPersist(false) 关闭。
86
+ */
87
+ this.draftPersistEnabled = true;
88
+ }
89
+ collectHydratedEditDiscounts(products) {
90
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
91
+ const discountMap = /* @__PURE__ */ new Map();
92
+ for (const product of products || []) {
93
+ for (const item of (product == null ? void 0 : product.discount_list) || []) {
94
+ const type = (item == null ? void 0 : item.type) ?? (item == null ? void 0 : item.tag);
95
+ if (!type || type === "product")
96
+ continue;
97
+ const resourceId = ((_a = item == null ? void 0 : item.discount) == null ? void 0 : _a.resource_id) ?? (item == null ? void 0 : item.resource_id) ?? (item == null ? void 0 : item.discount_id) ?? (item == null ? void 0 : item.order_discount_id);
98
+ if (resourceId === void 0 || resourceId === null || resourceId === "")
99
+ continue;
100
+ const id = Number(resourceId);
101
+ const key = Number.isFinite(id) ? id : String(resourceId);
102
+ const title = ((_b = item == null ? void 0 : item.discount) == null ? void 0 : _b.title) ?? {};
103
+ const amount = Number((item == null ? void 0 : item.amount) || 0);
104
+ const detail = {
105
+ amount: String((item == null ? void 0 : item.amount) ?? "0"),
106
+ type,
107
+ resource_id: key,
108
+ title,
109
+ original_amount: String(((_c = item == null ? void 0 : item.discount) == null ? void 0 : _c.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
110
+ num: Number(((_d = item == null ? void 0 : item.metadata) == null ? void 0 : _d.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1,
111
+ metadata: item == null ? void 0 : item.metadata,
112
+ discount: item == null ? void 0 : item.discount,
113
+ _num: Number(((_e = item == null ? void 0 : item.metadata) == null ? void 0 : _e.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1
114
+ };
115
+ discountMap.set(key, {
116
+ id: key,
117
+ product_name: "",
118
+ encoded: "",
119
+ code: "",
120
+ tag: type,
121
+ product_id: ((_f = item == null ? void 0 : item.discount) == null ? void 0 : _f.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
122
+ relation_type: "",
123
+ par_value: String(((_g = item == null ? void 0 : item.discount) == null ? void 0 : _g.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
124
+ used_par_value: String((item == null ? void 0 : item.amount) ?? "0"),
125
+ limit_status: "enable",
126
+ limited_relation_product_data: {
127
+ id: 0,
128
+ type: "products",
129
+ product_ids: [product == null ? void 0 : product.product_id].filter((value) => value !== void 0 && value !== null),
130
+ product_collection_id: [],
131
+ filter: 0,
132
+ exclude_product_ids: []
133
+ },
134
+ balance: String((item == null ? void 0 : item.amount) ?? "0"),
135
+ format_title: title,
136
+ product: {
137
+ id: (product == null ? void 0 : product.product_id) ?? 0,
138
+ title: "",
139
+ is_charge_tax: (product == null ? void 0 : product.is_charge_tax) ?? 0,
140
+ base_price: String((product == null ? void 0 : product.original_price) ?? (product == null ? void 0 : product.selling_price) ?? "0")
141
+ },
142
+ type,
143
+ resource_id: key,
144
+ isEditMode: true,
145
+ isSelected: true,
146
+ isAvailable: true,
147
+ isUsed: true,
148
+ isDisabled: true,
149
+ amount,
150
+ discount: {
151
+ ...(item == null ? void 0 : item.discount) || {},
152
+ resource_id: key,
153
+ discount_product_id: ((_h = item == null ? void 0 : item.discount) == null ? void 0 : _h.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
154
+ discount_calculation_mode: ((_i = item == null ? void 0 : item.discount) == null ? void 0 : _i.discount_calculation_mode) ?? "item_level"
155
+ },
156
+ applicableProductDetails: [detail],
157
+ appliedProductDetails: [detail]
158
+ });
159
+ }
160
+ }
161
+ return Array.from(discountMap.values());
52
162
  }
53
163
  /**
54
164
  * Populate `savedAmount` on each discount based on product-level discount details.
55
165
  * Only selected discounts get a non-zero value.
56
166
  */
57
167
  static populateSavedAmounts(productList, discountList) {
58
- var _a, _b;
59
168
  const savedMap = /* @__PURE__ */ new Map();
169
+ const addDiscountAmount = (discount, quantity) => {
170
+ var _a, _b;
171
+ const discountKey = ((_a = discount.discount) == null ? void 0 : _a.resource_id) || discount.id;
172
+ if (discountKey == null)
173
+ return;
174
+ const qty = Number(quantity) || 1;
175
+ const amount = new import_decimal.default(discount.amount || 0).times(qty).plus(((_b = discount.metadata) == null ? void 0 : _b.product_discount_difference) || 0);
176
+ savedMap.set(
177
+ discountKey,
178
+ (savedMap.get(discountKey) || new import_decimal.default(0)).plus(amount)
179
+ );
180
+ };
60
181
  for (const product of productList) {
61
182
  const qty = product.num || 1;
62
183
  for (const pd of product.discount_list || []) {
63
- const discountKey = ((_a = pd.discount) == null ? void 0 : _a.resource_id) || pd.id;
64
- if (discountKey == null)
65
- continue;
66
- const amount = new import_decimal.default(pd.amount || 0).times(qty).plus(((_b = pd.metadata) == null ? void 0 : _b.product_discount_difference) || 0);
67
- savedMap.set(
68
- discountKey,
69
- (savedMap.get(discountKey) || new import_decimal.default(0)).plus(amount)
70
- );
184
+ addDiscountAmount(pd, qty);
185
+ }
186
+ for (const bundle of product.product_bundle || []) {
187
+ const bundleQty = new import_decimal.default(Number(qty) || 1).times(Number((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity) ?? 1) || 1).toNumber();
188
+ for (const pd of (bundle == null ? void 0 : bundle.discount_list) || []) {
189
+ addDiscountAmount(pd, bundleQty);
190
+ }
71
191
  }
72
192
  }
73
193
  for (const d of discountList) {
@@ -75,6 +195,32 @@ var OrderModule = class extends import_BaseModule.BaseModule {
75
195
  d.savedAmount = d.isSelected && key != null && savedMap.has(key) ? savedMap.get(key).toNumber() : 0;
76
196
  }
77
197
  }
198
+ applyProductDiscountPrices(products) {
199
+ return (products || []).map((product) => {
200
+ var _a, _b;
201
+ if (isManualProductDiscountProduct(product))
202
+ return product;
203
+ const discountItems = Array.isArray(product.discount_list) ? product.discount_list : [];
204
+ const hasOnlyPersistedDiscountSnapshots = product.order_detail_id !== void 0 && product.order_detail_id !== null && discountItems.length > 0 && discountItems.every((discount) => (discount == null ? void 0 : discount.order_discount_id) !== void 0 && (discount == null ? void 0 : discount.order_discount_id) !== null);
205
+ if (hasOnlyPersistedDiscountSnapshots) {
206
+ return product;
207
+ }
208
+ const totalPerUnitDiscount = (0, import_utils.resolveEffectivePerUnitDiscount)(product);
209
+ const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
210
+ const sourcePrice = ((_a = product.metadata) == null ? void 0 : _a.source_product_price) ?? (((_b = product.metadata) == null ? void 0 : _b.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
211
+ const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
212
+ const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
213
+ if (product.metadata) {
214
+ product.metadata.main_product_selling_price = newMainSellingPrice;
215
+ product.metadata.price_schema_version = 2;
216
+ }
217
+ product.selling_price = (0, import_utils.composeLinePrice)({
218
+ mainPrice: newMainSellingPrice,
219
+ bundle: product.product_bundle
220
+ });
221
+ return product;
222
+ });
223
+ }
78
224
  async initialize(core, options) {
79
225
  var _a, _b, _c;
80
226
  this.core = core;
@@ -92,18 +238,54 @@ var OrderModule = class extends import_BaseModule.BaseModule {
92
238
  }
93
239
  const app = appPlugin.getApp();
94
240
  this.logger = app.logger;
95
- this.dbManager = app.sqlite;
96
241
  this.window = this.core.getPlugin("window");
97
242
  const otherParams = options.otherParams || {};
98
243
  this.cacheId = otherParams.cacheId;
99
244
  this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
100
245
  this.rulesHooksOverride = (_a = otherParams.rules) == null ? void 0 : _a.hooks;
101
- this.orderHooks = options.hooks || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
246
+ this.moduleHooksOverride = options.hooks;
247
+ this.orderHooks = this.moduleHooksOverride || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
102
248
  this.otherParams = otherParams;
103
249
  this.registerDiscountModules(options);
104
- this.restoreTempOrderFromStorage();
105
250
  this.logInfo("OrderModule initialized successfully");
106
251
  }
252
+ async destroy() {
253
+ var _a, _b;
254
+ const childModules = [(_a = this.store) == null ? void 0 : _a.discount, (_b = this.store) == null ? void 0 : _b.rules];
255
+ for (const childModule of childModules) {
256
+ if (!childModule || typeof childModule.destroy !== "function")
257
+ continue;
258
+ try {
259
+ await childModule.destroy();
260
+ } catch (error) {
261
+ const errorMessage = error instanceof Error ? error.message : String(error);
262
+ this.logWarning("Destroy child module failed", {
263
+ module: childModule.name,
264
+ error: errorMessage
265
+ });
266
+ }
267
+ }
268
+ if (this.store) {
269
+ this.store.discount = null;
270
+ this.store.rules = null;
271
+ }
272
+ super.destroy();
273
+ }
274
+ /**
275
+ * 更新父级解决方案透传的运行态参数,并同步 Order 内部依赖的派生字段。
276
+ *
277
+ * @example
278
+ * orderModule.updateOtherParams({ cacheId: 'cache-2', channel: 'pos' });
279
+ */
280
+ updateOtherParams(params) {
281
+ var _a, _b, _c;
282
+ const otherParams = params || {};
283
+ this.cacheId = otherParams.cacheId;
284
+ this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
285
+ this.rulesHooksOverride = (_a = otherParams.rules) == null ? void 0 : _a.hooks;
286
+ this.orderHooks = this.moduleHooksOverride || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
287
+ this.otherParams = otherParams;
288
+ }
107
289
  /**
108
290
  * 记录信息日志
109
291
  */
@@ -174,26 +356,57 @@ var OrderModule = class extends import_BaseModule.BaseModule {
174
356
  }
175
357
  // ─── Discount: 公共 API ───
176
358
  async loadDiscountConfig(params) {
177
- var _a, _b, _c, _d;
178
- const discountList = await ((_a = this.store.discount) == null ? void 0 : _a.loadPrepareConfig({
359
+ var _a, _b, _c, _d, _e, _f, _g;
360
+ const orderId = params.orderId || ((_a = this.store.tempOrder) == null ? void 0 : _a.order_id) || void 0;
361
+ const discountList = await ((_b = this.store.discount) == null ? void 0 : _b.loadPrepareConfig({
179
362
  customer_id: params.customerId,
180
- action: params.action || "create",
363
+ action: params.action || (orderId ? "edit" : "create"),
181
364
  with_good_pass: 1,
182
365
  with_discount_card: 1,
183
366
  with_wallet_pass_holder: 1,
184
- request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
367
+ request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
368
+ ...orderId ? { order_id: orderId } : {}
185
369
  }));
186
370
  if (discountList) {
187
- (_b = this.store.discount) == null ? void 0 : _b.setDiscountList(discountList);
371
+ const currentEditDiscounts = (((_c = this.store.discount) == null ? void 0 : _c.getDiscountList()) || []).filter((discount) => discount == null ? void 0 : discount.isEditMode);
372
+ const currentEditDiscountIds = new Set(
373
+ currentEditDiscounts.map((discount) => discount == null ? void 0 : discount.id)
374
+ );
375
+ const mergedDiscountList = [
376
+ ...currentEditDiscounts,
377
+ ...discountList.filter((discount) => !currentEditDiscountIds.has(discount == null ? void 0 : discount.id))
378
+ ];
379
+ await ((_d = this.store.discount) == null ? void 0 : _d.setOriginalDiscountList(mergedDiscountList));
380
+ await ((_e = this.store.discount) == null ? void 0 : _e.setDiscountList(mergedDiscountList));
188
381
  }
189
- if ((_d = (_c = this.store.tempOrder) == null ? void 0 : _c.products) == null ? void 0 : _d.length) {
382
+ if (params.apply !== false && ((_g = (_f = this.store.tempOrder) == null ? void 0 : _f.products) == null ? void 0 : _g.length)) {
190
383
  this.applyDiscount();
191
384
  }
385
+ return this.getDiscountList();
192
386
  }
193
387
  getDiscountList() {
194
388
  var _a;
195
389
  return ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList()) || [];
196
390
  }
391
+ async ensureEditDiscountConfigForProductChange(tempOrder) {
392
+ var _a, _b, _c, _d, _e, _f;
393
+ const orderId = tempOrder.order_id;
394
+ const customerId = Number(
395
+ tempOrder.customer_id || ((_a = tempOrder.customer) == null ? void 0 : _a.id) || ((_c = (_b = tempOrder._extend) == null ? void 0 : _b.customerSnapshot) == null ? void 0 : _c.id) || ((_e = (_d = tempOrder._extend) == null ? void 0 : _d.customerSnapshot) == null ? void 0 : _e.customer_id) || 0
396
+ );
397
+ if (!orderId || !customerId || customerId === 1)
398
+ return;
399
+ const currentDiscountList = ((_f = this.store.discount) == null ? void 0 : _f.getDiscountList()) || [];
400
+ const hasRuntimeDiscounts = currentDiscountList.some((discount) => !(discount == null ? void 0 : discount.isEditMode));
401
+ if (hasRuntimeDiscounts)
402
+ return;
403
+ await this.loadDiscountConfig({
404
+ customerId,
405
+ action: "edit",
406
+ orderId: Number(orderId),
407
+ apply: false
408
+ });
409
+ }
197
410
  async scanCode(code, customerId) {
198
411
  var _a, _b, _c, _d, _e;
199
412
  const resultDiscountWithReason = await ((_a = this.store.discount) == null ? void 0 : _a.batchSearch(code, { customerId })) || { discountList: [], unavailableReasonKey: null };
@@ -204,6 +417,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
204
417
  type: "clientCalc",
205
418
  isAvailable: false,
206
419
  discountList: this.getDiscountList(),
420
+ scannedDiscountList: resultDiscountList,
207
421
  unavailableReason: import_types2.UnavailableReason.Unknown
208
422
  };
209
423
  }
@@ -212,6 +426,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
212
426
  type: "server",
213
427
  isAvailable: false,
214
428
  discountList: this.getDiscountList(),
429
+ scannedDiscountList: resultDiscountList,
215
430
  unavailableReasonKey
216
431
  };
217
432
  }
@@ -224,7 +439,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
224
439
  return {
225
440
  type: "clientCalc",
226
441
  isAvailable: true,
227
- discountList: this.getDiscountList()
442
+ discountList: this.getDiscountList(),
443
+ scannedDiscountList: resultDiscountList
228
444
  };
229
445
  }
230
446
  const tempOrder = this.store.tempOrder;
@@ -245,6 +461,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
245
461
  type: "clientCalc",
246
462
  isAvailable: isAvailable || false,
247
463
  discountList: newDiscountList || this.getDiscountList(),
464
+ scannedDiscountList: resultDiscountList,
248
465
  unavailableReason
249
466
  };
250
467
  }
@@ -253,6 +470,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
253
470
  const tempOrder = this.store.tempOrder;
254
471
  if (!tempOrder)
255
472
  return;
473
+ delete tempOrder.discount_list;
256
474
  const rulesModule = this.store.rules;
257
475
  if (!rulesModule)
258
476
  return;
@@ -266,7 +484,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
266
484
  orderTotalAmount: Number(((_d = this.store.summary) == null ? void 0 : _d.total_amount) || 0)
267
485
  });
268
486
  if (result == null ? void 0 : result.productList) {
269
- tempOrder.products = result.productList;
487
+ const previousProductsByUid = (0, import_utils.indexOrderProductsByUid)(tempOrder.products);
488
+ tempOrder.products = this.applyProductDiscountPrices(
489
+ (result.productList || []).map((product, index) => {
490
+ const uid = (0, import_utils.getOrderProductLineUid)(product);
491
+ const previous = (uid ? previousProductsByUid.get(uid) : void 0) ?? previousProductsByUid.get(`__index__:${index}`);
492
+ if (isManualProductDiscountProduct(previous)) {
493
+ return previous;
494
+ }
495
+ const mergedProduct = previous ? (0, import_utils.mergeOrderProductDisplayFields)(previous, product) : product;
496
+ return {
497
+ ...mergedProduct,
498
+ discount_list: (0, import_utils.normalizeOrderProductDiscountList)(
499
+ (0, import_manualProductDiscount.syncManualProductDiscountProductNum)(
500
+ mergedProduct.discount_list,
501
+ mergedProduct.num
502
+ )
503
+ )
504
+ };
505
+ })
506
+ );
270
507
  }
271
508
  if (result == null ? void 0 : result.discountList) {
272
509
  OrderModule.populateSavedAmounts(
@@ -274,80 +511,201 @@ var OrderModule = class extends import_BaseModule.BaseModule {
274
511
  result.discountList
275
512
  );
276
513
  (_e = this.store.discount) == null ? void 0 : _e.setDiscountList(result.discountList);
277
- tempOrder.discount_list = result.discountList.filter(
278
- (d) => d.isSelected
279
- );
280
514
  }
281
515
  }
282
- // ─── TempOrder: 初始化入口 ───
283
- initTempOrder(params) {
284
- if (params.cacheId !== void 0)
285
- this.cacheId = params.cacheId;
286
- if (params.salesSummaryModuleName !== void 0)
287
- this.salesSummaryModuleName = params.salesSummaryModuleName;
288
- this.restoreTempOrderFromStorage();
516
+ // ─── 促销/赠品 ──────────────────────────────────────
517
+ /**
518
+ * 注入促销评估器。
519
+ *
520
+ * @example
521
+ * order.setPromotionEvaluator(appHelper.utils.promotionEvaluator);
522
+ */
523
+ setPromotionEvaluator(evaluator) {
524
+ this.promotionEvaluator = evaluator || null;
289
525
  }
290
- // ─── TempOrder: localStorage 持久化 ───
291
- getTempOrderStorageKey() {
292
- if (!this.cacheId)
293
- return null;
294
- return `scanOrder:tempOrder:${this.cacheId}`;
526
+ /**
527
+ * 注入赠品选择 resolver。OS 需要补赠品时会 await 调用 resolver;缺省时跳过新增并 console.warn。
528
+ *
529
+ * @example
530
+ * order.setGiftSelectResolver(async (ctx) => {
531
+ * // SDK 内部决定弹窗 or 自动选第一项,返回完整 OrderProduct[]
532
+ * return giftSelectBridge.request(ctx);
533
+ * });
534
+ */
535
+ setGiftSelectResolver(resolver) {
536
+ this.giftSelectResolver = resolver || null;
295
537
  }
296
- restoreTempOrderFromStorage() {
297
- var _a, _b;
298
- const key = this.getTempOrderStorageKey();
299
- if (!key)
538
+ /**
539
+ * 为商品目录追加促销标签,供上层 Sales 门面复用。
540
+ *
541
+ * @example
542
+ * const products = order.appendPromotionTags(catalogProducts);
543
+ */
544
+ appendPromotionTags(products) {
545
+ return (0, import_cartPromotion.appendPromotionTags)(products, this.promotionEvaluator);
546
+ }
547
+ /**
548
+ * 应用购物车促销:计算 → 差异化赠品 → 写回 tempOrder.products → emit onPromotionApplied。
549
+ *
550
+ * 调用时机:写路径(add/update/remove/clear/setCustomer)末尾自动触发;外部一般无需手动调。
551
+ *
552
+ * 关键约束:
553
+ * - 不调用任何公开 CRUD API(如 removeProductFromOrder),全部内部 mutate tempOrder.products,避免事件风暴;
554
+ * - 用 `isApplyingPromotion` 防递归;
555
+ * - 多选项赠品依赖 giftSelectResolver,未注入则跳过且 console.warn;
556
+ * - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进。
557
+ */
558
+ async applyPromotion() {
559
+ var _a;
560
+ if (this.isApplyingPromotion) {
300
561
  return;
301
- if (!this.window)
562
+ }
563
+ if (!this.promotionEvaluator) {
302
564
  return;
303
- const cachedData = this.window.localStorage.getItem(key);
304
- if (!cachedData)
565
+ }
566
+ const tempOrder = this.store.tempOrder;
567
+ if (!tempOrder) {
305
568
  return;
569
+ }
570
+ this.isApplyingPromotion = true;
306
571
  try {
307
- const parsedData = JSON.parse(cachedData);
308
- if (!(0, import_utils.isTempOrder)(parsedData)) {
309
- this.window.localStorage.removeItem(key);
310
- return;
572
+ const result = (0, import_cartPromotion.processCartPromotion)(
573
+ tempOrder.products,
574
+ this.promotionEvaluator
575
+ );
576
+ if (result.giftActions.toRemove.length > 0) {
577
+ const removeSet = new Set(result.giftActions.toRemove.map(String));
578
+ result.products = result.products.filter((p) => {
579
+ const uid = (0, import_cartPromotion.getOrderProductUid)(p);
580
+ return uid ? !removeSet.has(String(uid)) : true;
581
+ });
311
582
  }
312
- if (Array.isArray(parsedData.products)) {
313
- for (let i = 0; i < parsedData.products.length; i++) {
314
- const p = parsedData.products[i];
315
- if (!p || typeof p !== "object")
316
- continue;
317
- if (!Array.isArray(p.product_option_item)) {
318
- p.product_option_item = [];
319
- }
320
- if (!Array.isArray(p.product_bundle)) {
321
- p.product_bundle = [];
583
+ for (const reduce of result.giftActions.toReduce) {
584
+ for (const item of reduce.items) {
585
+ const product = result.products.find(
586
+ (p) => (0, import_cartPromotion.getOrderProductUid)(p) === item.uid
587
+ );
588
+ if (product) {
589
+ product.num = item.newQuantity;
322
590
  }
323
- const row = p;
324
- parsedData.products[i] = (0, import_utils3.normalizeOrderProduct)(row);
325
591
  }
326
592
  }
327
- const parsedRecord = parsedData;
328
- this.store.summary = parsedRecord.summary || (0, import_utils.createEmptySummary)();
329
- delete parsedData.summary;
330
- if (parsedRecord.lastOrderInfo) {
331
- this.store.lastOrderInfo = parsedRecord.lastOrderInfo;
332
- delete parsedData.lastOrderInfo;
333
- }
334
- if (!parsedData._extend || typeof parsedData._extend !== "object") {
335
- parsedData._extend = { productsByUid: {} };
336
- } else if (!parsedData._extend.productsByUid) {
337
- parsedData._extend.productsByUid = {};
593
+ if (result.giftActions.toAdd.length > 0) {
594
+ if (!this.giftSelectResolver) {
595
+ if (result.giftActions.toAdd.some((g) => g.giftOptions.length > 1)) {
596
+ console.warn(
597
+ "[OrderModule] giftSelectResolver not set, skip applying gifts",
598
+ result.giftActions.toAdd
599
+ );
600
+ } else {
601
+ console.warn(
602
+ "[OrderModule] giftSelectResolver not set, skip applying single-option gifts",
603
+ result.giftActions.toAdd
604
+ );
605
+ }
606
+ } else {
607
+ for (const addAction of result.giftActions.toAdd) {
608
+ if (addAction.giftOptions.length === 1) {
609
+ const sameStrategy = result.products.find(
610
+ (p) => {
611
+ var _a2, _b;
612
+ return ((_b = (_a2 = p.metadata) == null ? void 0 : _a2._giftInfo) == null ? void 0 : _b.strategyId) === addAction.strategyId;
613
+ }
614
+ );
615
+ if (sameStrategy && !sameStrategy.booking_uid && !((_a = sameStrategy.metadata) == null ? void 0 : _a.booking_uid)) {
616
+ sameStrategy.num = (Number(sameStrategy.num) || 0) + (addAction.giftCount || 1);
617
+ continue;
618
+ }
619
+ }
620
+ try {
621
+ const giftResult = await this.giftSelectResolver({
622
+ strategyId: addAction.strategyId,
623
+ strategyName: addAction.strategyName,
624
+ giftCount: addAction.giftCount,
625
+ giftOptions: addAction.giftOptions,
626
+ sourceProductIds: addAction.sourceProductIds
627
+ });
628
+ const giftProducts = Array.isArray(giftResult) ? giftResult : giftResult == null ? void 0 : giftResult.products;
629
+ const giftBookings = Array.isArray(giftResult) ? [] : (giftResult == null ? void 0 : giftResult.bookings) || [];
630
+ if (Array.isArray(giftProducts) && giftProducts.length > 0) {
631
+ for (const [index, gp] of giftProducts.entries()) {
632
+ if (!gp)
633
+ continue;
634
+ const booking = giftBookings[index];
635
+ if (booking) {
636
+ const linked = this.createLinkedProductAndBooking({
637
+ product: gp,
638
+ booking
639
+ });
640
+ result.products.push(linked.product);
641
+ tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
642
+ continue;
643
+ }
644
+ result.products.push(gp);
645
+ }
646
+ }
647
+ } catch (error) {
648
+ console.warn(
649
+ "[OrderModule] giftSelectResolver rejected, skip add gift",
650
+ addAction.strategyId,
651
+ error
652
+ );
653
+ }
654
+ }
655
+ }
338
656
  }
339
- this.store.tempOrder = parsedData;
340
- } catch {
341
- (_b = (_a = this.window) == null ? void 0 : _a.localStorage) == null ? void 0 : _b.removeItem(key);
657
+ tempOrder.products = result.products;
658
+ this.lastUnfulfilledPromotions = result.unfulfilledPromotions;
659
+ this.lastGiftActions = result.giftActions;
660
+ const payload = {
661
+ unfulfilledPromotions: result.unfulfilledPromotions,
662
+ giftActions: result.giftActions,
663
+ gifts: result.gifts.map((g) => ({
664
+ strategyId: g.strategyId,
665
+ strategyName: g.strategyName,
666
+ giftCount: g.giftCount,
667
+ giftOptions: g.giftOptions
668
+ })),
669
+ products: tempOrder.products
670
+ };
671
+ this.effectsEmit("onPromotionApplied", payload);
672
+ } catch (error) {
673
+ console.error("[OrderModule] applyPromotion failed", error);
674
+ } finally {
675
+ this.isApplyingPromotion = false;
342
676
  }
343
677
  }
678
+ /** 最近一次 applyPromotion 输出的未满足促销列表 */
679
+ getUnfulfilledPromotions() {
680
+ return this.lastUnfulfilledPromotions;
681
+ }
682
+ /** 最近一次 applyPromotion 输出的赠品操作 diff */
683
+ getLastGiftActions() {
684
+ return this.lastGiftActions;
685
+ }
686
+ // ─── TempOrder: 初始化入口 ───
687
+ initTempOrder(params) {
688
+ if (params.cacheId !== void 0)
689
+ this.cacheId = params.cacheId;
690
+ if (params.salesSummaryModuleName !== void 0)
691
+ this.salesSummaryModuleName = params.salesSummaryModuleName;
692
+ }
693
+ /**
694
+ * 控制 IndexedDB 草稿(saveDraft)是否写入。
695
+ * localStorage 版 tempOrder 持久化已废弃,此方法仅影响 saveDraft。
696
+ *
697
+ * @example
698
+ * order.setEnableTempOrderPersist(false); // BigSale 弹窗:跳过 ~1s 的 dbUpdate
699
+ */
700
+ setEnableTempOrderPersist(enabled) {
701
+ this.draftPersistEnabled = enabled;
702
+ }
703
+ /** 是否允许 saveDraft 写入 IndexedDB 草稿。 */
704
+ isTempOrderPersistEnabled() {
705
+ return this.draftPersistEnabled;
706
+ }
707
+ /** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化;草稿保存请使用 IndexedDB saveDraft。 */
344
708
  persistTempOrder() {
345
- const key = this.getTempOrderStorageKey();
346
- if (!key || !this.store.tempOrder)
347
- return;
348
- if (!this.window)
349
- return;
350
- this.window.localStorage.setItem(key, JSON.stringify(this.store.tempOrder));
351
709
  }
352
710
  // ─── TempOrder: 创建 & 获取 ───
353
711
  createDefaultTempOrderInstance() {
@@ -391,107 +749,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
391
749
  }
392
750
  return tempOrder.request_unique_idempotency_token;
393
751
  }
394
- hasLocalDatabase() {
395
- return !!this.dbManager;
396
- }
397
- buildLocalOrderRecord(tempOrder) {
398
- const externalSaleNumber = this.ensureExternalSaleNumber(tempOrder);
399
- return {
400
- ...tempOrder,
401
- id: tempOrder.order_id ?? externalSaleNumber,
402
- external_sale_number: externalSaleNumber,
403
- summary: this.store.summary || (0, import_utils.createEmptySummary)(),
404
- lastOrderInfo: this.store.lastOrderInfo
405
- };
406
- }
407
- async getLocalOrderByOrderId(orderId) {
408
- var _a, _b, _c, _d;
409
- if (!this.dbManager || orderId === void 0 || orderId === null)
410
- return null;
411
- try {
412
- const direct = await ((_b = (_a = this.dbManager).get) == null ? void 0 : _b.call(
413
- _a,
414
- LOCAL_ORDER_STORE_NAME,
415
- orderId
416
- ));
417
- if (direct)
418
- return direct;
419
- const orders = await ((_d = (_c = this.dbManager).getAll) == null ? void 0 : _d.call(_c, LOCAL_ORDER_STORE_NAME));
420
- return (orders || []).find(
421
- (order) => String(order == null ? void 0 : order.order_id) === String(orderId)
422
- ) || null;
423
- } catch (error) {
424
- this.logWarning("getLocalOrderByOrderId failed", {
425
- orderId,
426
- error: error instanceof Error ? error.message : String(error)
427
- });
428
- return null;
429
- }
430
- }
431
- async getLocalOrderByOrderNumber(orderNumber) {
432
- var _a, _b, _c, _d;
433
- if (!this.dbManager || !orderNumber)
434
- return null;
435
- try {
436
- const direct = await ((_b = (_a = this.dbManager).get) == null ? void 0 : _b.call(
437
- _a,
438
- LOCAL_ORDER_STORE_NAME,
439
- orderNumber
440
- ));
441
- if (direct)
442
- return direct;
443
- const orders = await ((_d = (_c = this.dbManager).getAll) == null ? void 0 : _d.call(_c, LOCAL_ORDER_STORE_NAME));
444
- return (orders || []).find(
445
- (order) => String(order == null ? void 0 : order.order_number) === String(orderNumber)
446
- ) || null;
447
- } catch (error) {
448
- this.logWarning("getLocalOrderByOrderNumber failed", {
449
- orderNumber,
450
- error: error instanceof Error ? error.message : String(error)
451
- });
452
- return null;
453
- }
454
- }
455
- async getLocalOrderByExternalSaleNumber(externalSaleNumber) {
456
- var _a, _b, _c, _d;
457
- if (!this.dbManager || !externalSaleNumber)
458
- return null;
459
- try {
460
- const direct = await ((_b = (_a = this.dbManager).get) == null ? void 0 : _b.call(
461
- _a,
462
- LOCAL_ORDER_STORE_NAME,
463
- externalSaleNumber
464
- ));
465
- if (direct)
466
- return direct;
467
- const orders = await ((_d = (_c = this.dbManager).getAll) == null ? void 0 : _d.call(_c, LOCAL_ORDER_STORE_NAME));
468
- return (orders || []).find(
469
- (order) => String(order == null ? void 0 : order.external_sale_number) === String(externalSaleNumber)
470
- ) || null;
471
- } catch (error) {
472
- this.logWarning("getLocalOrderByExternalSaleNumber failed", {
473
- externalSaleNumber,
474
- error: error instanceof Error ? error.message : String(error)
475
- });
476
- return null;
477
- }
752
+ buildPaymentSyncIdempotencyToken(tempOrder, payments) {
753
+ const baseToken = this.ensureRequestUniqueIdempotencyToken(tempOrder);
754
+ const paidPaymentsCount = (payments || []).filter((payment) => {
755
+ return String((payment == null ? void 0 : payment.status) || "").toLowerCase() === "paid";
756
+ }).length;
757
+ const paidCount = paidPaymentsCount > 0 ? paidPaymentsCount : payments.length;
758
+ return `${baseToken}_payment_${paidCount}`;
478
759
  }
479
760
  async saveDraft() {
480
- var _a, _b;
481
- if (!this.dbManager)
482
- return;
483
- const tempOrder = this.ensureTempOrder();
484
- const record = this.buildLocalOrderRecord(tempOrder);
485
- try {
486
- await ((_b = (_a = this.dbManager).update) == null ? void 0 : _b.call(_a, LOCAL_ORDER_STORE_NAME, record));
487
- } catch (error) {
488
- this.logWarning("saveDraft failed", {
489
- externalSaleNumber: tempOrder.external_sale_number,
490
- orderNumber: tempOrder.order_number,
491
- orderId: tempOrder.order_id,
492
- error: error instanceof Error ? error.message : String(error)
493
- });
494
- }
761
+ }
762
+ saveDraftInBackground() {
763
+ void this.saveDraft();
495
764
  }
496
765
  async hydrateTempOrderFromLocalRecord(record) {
497
766
  return this.hydrateTempOrderFromRecord(record);
@@ -500,15 +769,208 @@ var OrderModule = class extends import_BaseModule.BaseModule {
500
769
  var _a, _b;
501
770
  return ((_a = result == null ? void 0 : result.data) == null ? void 0 : _a.order_id) ?? (result == null ? void 0 : result.order_id) ?? ((_b = result == null ? void 0 : result.data) == null ? void 0 : _b.id) ?? (result == null ? void 0 : result.id) ?? null;
502
771
  }
772
+ calculatePaymentEffectiveAmount(payment) {
773
+ const amount = new import_decimal.default(payment.amount || 0).minus(new import_decimal.default(payment.service_fee || 0));
774
+ const rounding = new import_decimal.default(payment.rounding_amount || 0);
775
+ return amount.minus(rounding);
776
+ }
503
777
  calculatePaymentTotal(payments) {
504
778
  return (0, import_utils.mapPaymentItemsToOrderPayments)(payments, {
505
779
  includeVoided: false
506
780
  }).reduce((sum, payment) => {
507
- const amount = new import_decimal.default(payment.amount || 0);
508
- const rounding = new import_decimal.default(payment.rounding_amount || 0);
509
- return sum.plus(amount.minus(rounding));
781
+ return sum.plus(this.calculatePaymentEffectiveAmount(payment));
782
+ }, new import_decimal.default(0));
783
+ }
784
+ getDepositAmount(tempOrder, summary) {
785
+ return new import_decimal.default(summary.deposit_amount || tempOrder.deposit_amount || "0.00");
786
+ }
787
+ normalizeDepositAmount(amount) {
788
+ return import_decimal.default.max(new import_decimal.default(Number(amount) || 0), 0).toDecimalPlaces(2).toFixed(2);
789
+ }
790
+ applyDepositAmountToSummary(tempOrder, summary, amount) {
791
+ const depositAmount = this.normalizeDepositAmount(amount);
792
+ const hasDepositAmount = new import_decimal.default(depositAmount).gt(0);
793
+ const existedDeposit = summary.deposit && typeof summary.deposit === "object" ? summary.deposit : void 0;
794
+ const nextSummary = {
795
+ ...summary,
796
+ deposit_amount: depositAmount,
797
+ deposit: hasDepositAmount ? {
798
+ ...existedDeposit || {},
799
+ total: depositAmount,
800
+ deposit_policy_ids: (existedDeposit == null ? void 0 : existedDeposit.deposit_policy_ids) || [],
801
+ hasDeposit: true
802
+ } : void 0
803
+ };
804
+ tempOrder.deposit_amount = depositAmount;
805
+ tempOrder.is_deposit = hasDepositAmount ? 1 : 0;
806
+ return nextSummary;
807
+ }
808
+ isDepositOrder(tempOrder, depositAmount) {
809
+ return tempOrder.is_deposit === 1 || depositAmount.gt(0);
810
+ }
811
+ getOrderExpectedAmount(summary) {
812
+ return new import_decimal.default(summary.expect_amount || summary.total_amount || 0);
813
+ }
814
+ isDepositCovered(params) {
815
+ const depositAmount = this.getDepositAmount(params.tempOrder, params.summary);
816
+ if (!this.isDepositOrder(params.tempOrder, depositAmount))
817
+ return false;
818
+ if (depositAmount.lte(0))
819
+ return false;
820
+ return params.paidAmount.gte(depositAmount);
821
+ }
822
+ calculateDepositPaidAmount(payments) {
823
+ return (payments || []).reduce((sum, payment) => {
824
+ const paymentRecord = payment;
825
+ if ((paymentRecord == null ? void 0 : paymentRecord.status) !== "paid")
826
+ return sum;
827
+ const isDepositPayment = paymentRecord.type === "deposit" || paymentRecord.order_payment_type === "deposit";
828
+ if (!isDepositPayment)
829
+ return sum;
830
+ if (paymentRecord.origin_amount !== void 0 && paymentRecord.origin_amount !== null && paymentRecord.origin_amount !== "") {
831
+ return sum.plus(this.calculatePaymentGapAmount(paymentRecord));
832
+ }
833
+ const rounding = new import_decimal.default(paymentRecord.rounding_amount || 0);
834
+ return sum.plus(new import_decimal.default(paymentRecord.amount || 0).minus(rounding));
510
835
  }, new import_decimal.default(0));
511
836
  }
837
+ resolveNextOrderPaymentType(tempOrder) {
838
+ const depositAmount = new import_decimal.default(tempOrder.deposit_amount || "0.00");
839
+ if (!this.isDepositOrder(tempOrder, depositAmount))
840
+ return "normal";
841
+ if (depositAmount.lte(0))
842
+ return "normal";
843
+ const depositPaidAmount = this.calculateDepositPaidAmount(tempOrder.payments || []);
844
+ return depositPaidAmount.lt(depositAmount) ? "deposit" : "normal";
845
+ }
846
+ normalizePaymentSource(payment, options) {
847
+ const paymentRecord = payment;
848
+ const metadata = paymentRecord.metadata && typeof paymentRecord.metadata === "object" ? { ...paymentRecord.metadata } : {};
849
+ if (!metadata.unique_payment_number) {
850
+ metadata.unique_payment_number = (0, import_utils.createUuidV4)();
851
+ }
852
+ const normalized = {
853
+ ...paymentRecord,
854
+ metadata,
855
+ origin_amount: paymentRecord.origin_amount ?? paymentRecord.amount ?? "0.00"
856
+ };
857
+ if (paymentRecord.status !== void 0) {
858
+ normalized.status = paymentRecord.status;
859
+ } else if ((options == null ? void 0 : options.defaultPaid) !== false) {
860
+ normalized.status = "paid";
861
+ }
862
+ return normalized;
863
+ }
864
+ updateTempOrderPaymentStatus(tempOrder, options) {
865
+ const summary = (options == null ? void 0 : options.summary) || this.store.summary || (0, import_utils.createEmptySummary)();
866
+ const paymentTotal = this.calculatePaymentTotal(tempOrder.payments || []);
867
+ const refundAmount = this.getSummaryRefundAmount(summary);
868
+ const netPaymentTotal = import_decimal.default.max(paymentTotal.minus(refundAmount), 0);
869
+ const targetAmount = this.calculatePaymentTargetAmount(
870
+ tempOrder,
871
+ summary,
872
+ netPaymentTotal
873
+ );
874
+ if (this.shouldKeepPaymentStatusAfterAmountRecalc(tempOrder.payment_status, {
875
+ netPaymentTotal,
876
+ paymentTotal,
877
+ refundAmount,
878
+ targetAmount,
879
+ previousSummary: options == null ? void 0 : options.previousSummary,
880
+ tempOrder
881
+ })) {
882
+ return;
883
+ }
884
+ if (targetAmount.lte(0)) {
885
+ tempOrder.payment_status = "paid";
886
+ return;
887
+ }
888
+ if (netPaymentTotal.lte(0)) {
889
+ tempOrder.payment_status = "payment_processing";
890
+ return;
891
+ }
892
+ tempOrder.payment_status = netPaymentTotal.gte(targetAmount) ? "paid" : "partially_paid";
893
+ }
894
+ shouldKeepPaymentStatusAfterAmountRecalc(paymentStatus, params) {
895
+ const normalizedStatus = String(paymentStatus || "").trim().toLowerCase();
896
+ if (normalizedStatus !== "refunded" && normalizedStatus !== "partially_refunded") {
897
+ return false;
898
+ }
899
+ if (params.refundAmount.lte(0))
900
+ return false;
901
+ if (params.previousSummary) {
902
+ const previousTargetAmount = this.calculatePaymentTargetAmount(
903
+ params.tempOrder,
904
+ params.previousSummary,
905
+ params.netPaymentTotal
906
+ );
907
+ if (!previousTargetAmount.eq(params.targetAmount))
908
+ return false;
909
+ }
910
+ if (normalizedStatus === "refunded") {
911
+ return params.refundAmount.gte(params.paymentTotal);
912
+ }
913
+ return params.netPaymentTotal.gte(params.targetAmount);
914
+ }
915
+ resolveWalletPassUseValue(payment, amount) {
916
+ const usageUnit = payment.wallet_pass_usage_unit && typeof payment.wallet_pass_usage_unit === "object" ? payment.wallet_pass_usage_unit : null;
917
+ if (!usageUnit)
918
+ return payment.wallet_pass_use_value;
919
+ const price = new import_decimal.default(usageUnit.price || 0);
920
+ const points = new import_decimal.default(usageUnit.points || 0);
921
+ if (price.lte(0) || points.lte(0))
922
+ return payment.wallet_pass_use_value;
923
+ return amount.div(price).times(points).toDecimalPlaces(2).toFixed(2);
924
+ }
925
+ adjustVoucherFundRecord(params) {
926
+ var _a;
927
+ const fundRecord = params.voucher.fund_record && typeof params.voucher.fund_record === "object" && !Array.isArray(params.voucher.fund_record) ? { ...params.voucher.fund_record } : null;
928
+ if (!fundRecord || fundRecord.using_before_value === void 0 || fundRecord.using_before_value === null) {
929
+ return fundRecord || void 0;
930
+ }
931
+ const code = String(params.voucher.code || "").toUpperCase();
932
+ const isPointCard = code === "POINTCARD" || String(((_a = params.voucher.fund_record) == null ? void 0 : _a.tag) || "").toLowerCase() === "point_card";
933
+ const usingValue = isPointCard ? new import_decimal.default(params.walletPassUseValue || 0) : params.amount;
934
+ fundRecord.using_after_value = new import_decimal.default(fundRecord.using_before_value || 0).minus(usingValue).toDecimalPlaces(2).toFixed(2);
935
+ return fundRecord;
936
+ }
937
+ capVoucherPaymentsByRemainingAmount(params) {
938
+ const targetAmount = this.getPaymentTargetAmount();
939
+ const nonVoucherTotal = this.calculatePaymentTotal(params.nonVoucherPayments);
940
+ if (targetAmount.lte(0))
941
+ return [];
942
+ let remainingAmount = import_decimal.default.max(
943
+ targetAmount.minus(nonVoucherTotal),
944
+ 0
945
+ );
946
+ const cappedVouchers = [];
947
+ for (const voucher of params.vouchers) {
948
+ if (remainingAmount.lte(0))
949
+ break;
950
+ const voucherAmount = import_decimal.default.max(new import_decimal.default(voucher.amount || 0), 0);
951
+ if (voucherAmount.lte(0))
952
+ continue;
953
+ const cappedAmount = import_decimal.default.min(voucherAmount, remainingAmount);
954
+ const amountText = cappedAmount.toDecimalPlaces(2).toFixed(2);
955
+ const walletPassUseValue = this.resolveWalletPassUseValue(
956
+ voucher,
957
+ cappedAmount
958
+ );
959
+ cappedVouchers.push({
960
+ ...voucher,
961
+ amount: amountText,
962
+ origin_amount: amountText,
963
+ wallet_pass_use_value: walletPassUseValue,
964
+ fund_record: this.adjustVoucherFundRecord({
965
+ voucher,
966
+ amount: cappedAmount,
967
+ walletPassUseValue
968
+ })
969
+ });
970
+ remainingAmount = remainingAmount.minus(cappedAmount);
971
+ }
972
+ return cappedVouchers;
973
+ }
512
974
  calculatePaidPaymentSummary(payments) {
513
975
  return (payments || []).reduce(
514
976
  (summary, payment) => {
@@ -518,13 +980,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
518
980
  return {
519
981
  customerPaidAmount: summary.customerPaidAmount.plus(paymentRecord.amount || 0),
520
982
  orderPaidAmount: summary.orderPaidAmount.plus(paymentRecord.origin_amount || 0),
521
- payServiceChargeAmount: summary.payServiceChargeAmount.plus(this.calculatePaymentServiceFee(paymentRecord))
983
+ gapPaidAmount: summary.gapPaidAmount.plus(this.calculatePaymentGapAmount(paymentRecord)),
984
+ payServiceChargeAmount: summary.payServiceChargeAmount.plus(this.calculatePaymentServiceFee(paymentRecord)),
985
+ roundingAmount: summary.roundingAmount.plus(this.calculatePaymentRoundingAmount(paymentRecord))
522
986
  };
523
987
  },
524
988
  {
525
989
  customerPaidAmount: new import_decimal.default(0),
526
990
  orderPaidAmount: new import_decimal.default(0),
527
- payServiceChargeAmount: new import_decimal.default(0)
991
+ gapPaidAmount: new import_decimal.default(0),
992
+ payServiceChargeAmount: new import_decimal.default(0),
993
+ roundingAmount: new import_decimal.default(0)
528
994
  }
529
995
  );
530
996
  }
@@ -537,15 +1003,390 @@ var OrderModule = class extends import_BaseModule.BaseModule {
537
1003
  const fixedAmount = new import_decimal.default(serviceCharge.amount || 0);
538
1004
  return new import_decimal.default(payment.amount || 0).times(percentage).plus(fixedAmount);
539
1005
  }
1006
+ calculatePaymentGapAmount(payment) {
1007
+ if (payment.origin_amount === void 0 || payment.origin_amount === null || payment.origin_amount === "") {
1008
+ return new import_decimal.default(0);
1009
+ }
1010
+ const rounding = new import_decimal.default(payment.rounding_amount || 0);
1011
+ return new import_decimal.default(payment.origin_amount || 0).minus(rounding);
1012
+ }
1013
+ calculatePaymentRoundingAmount(payment) {
1014
+ if (payment.rounding_amount === void 0 || payment.rounding_amount === null || payment.rounding_amount === "") {
1015
+ return new import_decimal.default(0);
1016
+ }
1017
+ return new import_decimal.default(payment.rounding_amount || 0);
1018
+ }
1019
+ formatSummaryMetadataMoney(value) {
1020
+ if (value === void 0 || value === null || value === "")
1021
+ return void 0;
1022
+ if (value instanceof import_decimal.default)
1023
+ return value.toFixed(2);
1024
+ return new import_decimal.default(String(value || 0)).toFixed(2);
1025
+ }
1026
+ syncSummaryProductMetadata(products) {
1027
+ const moneyKeys = [
1028
+ "main_product_attached_bundle_surcharge_fee",
1029
+ "main_product_attached_bundle_tax_fee",
1030
+ "surcharge_rounding_remainder",
1031
+ "tax_fee_rounding_remainder"
1032
+ ];
1033
+ const metadataMoneyKeys = [
1034
+ "main_product_attached_bundle_selling_price",
1035
+ "main_product_attached_bundle_payment_price"
1036
+ ];
1037
+ for (const product of products || []) {
1038
+ const productRecord = product;
1039
+ const metadata = productRecord.metadata && typeof productRecord.metadata === "object" ? { ...productRecord.metadata } : {};
1040
+ let hasMetadataPatch = false;
1041
+ for (const key of moneyKeys) {
1042
+ const value = this.formatSummaryMetadataMoney(productRecord[key]);
1043
+ if (value === void 0)
1044
+ continue;
1045
+ metadata[key] = value;
1046
+ hasMetadataPatch = true;
1047
+ }
1048
+ for (const key of metadataMoneyKeys) {
1049
+ const value = this.formatSummaryMetadataMoney(metadata[key]);
1050
+ if (value === void 0)
1051
+ continue;
1052
+ metadata[key] = value;
1053
+ hasMetadataPatch = true;
1054
+ }
1055
+ if (metadata.average_discount_amount_rate !== void 0) {
1056
+ hasMetadataPatch = true;
1057
+ }
1058
+ if (Array.isArray(productRecord.relation_surcharge_ids)) {
1059
+ metadata.relation_surcharge_ids = productRecord.relation_surcharge_ids;
1060
+ hasMetadataPatch = true;
1061
+ }
1062
+ const productPaymentPrice = this.formatSummaryMetadataMoney(
1063
+ productRecord.payment_price
1064
+ );
1065
+ if (productPaymentPrice !== void 0) {
1066
+ productRecord.payment_price = productPaymentPrice;
1067
+ }
1068
+ if (hasMetadataPatch)
1069
+ productRecord.metadata = metadata;
1070
+ if (!Array.isArray(productRecord.product_bundle))
1071
+ continue;
1072
+ for (const bundle of productRecord.product_bundle) {
1073
+ const bundleRecord = bundle;
1074
+ const bundleMetadata = bundleRecord.metadata && typeof bundleRecord.metadata === "object" ? { ...bundleRecord.metadata } : {};
1075
+ let hasBundleMetadataPatch = false;
1076
+ const bundleSurchargeFee = this.formatSummaryMetadataMoney(
1077
+ bundleRecord.surcharge_fee
1078
+ );
1079
+ if (bundleSurchargeFee !== void 0) {
1080
+ bundleMetadata.surcharge_fee = bundleSurchargeFee;
1081
+ hasBundleMetadataPatch = true;
1082
+ }
1083
+ const bundlePaymentPrice = this.formatSummaryMetadataMoney(
1084
+ bundleRecord.bundle_payment_price
1085
+ );
1086
+ if (bundlePaymentPrice !== void 0) {
1087
+ bundleRecord.bundle_payment_price = bundlePaymentPrice;
1088
+ }
1089
+ if (Array.isArray(bundleRecord.relation_surcharge_ids)) {
1090
+ bundleMetadata.relation_surcharge_ids = bundleRecord.relation_surcharge_ids;
1091
+ hasBundleMetadataPatch = true;
1092
+ }
1093
+ if (hasBundleMetadataPatch)
1094
+ bundleRecord.metadata = bundleMetadata;
1095
+ }
1096
+ }
1097
+ }
1098
+ calculateSummaryAmountGap(params) {
1099
+ const { tempOrder, summary, orderPaidAmount } = params;
1100
+ const refundAmount = this.getSummaryRefundAmount(summary);
1101
+ const netOrderPaidAmount = import_decimal.default.max(orderPaidAmount.minus(refundAmount), 0);
1102
+ const targetAmount = this.calculatePaymentTargetAmount(
1103
+ tempOrder,
1104
+ summary,
1105
+ netOrderPaidAmount
1106
+ );
1107
+ return targetAmount.minus(netOrderPaidAmount).toFixed(2);
1108
+ }
1109
+ getSummaryRefundAmount(summary) {
1110
+ return import_decimal.default.max(new import_decimal.default((summary == null ? void 0 : summary.total_refund_amount) || 0), 0);
1111
+ }
1112
+ calculatePaymentTargetAmount(tempOrder, summary, paidAmount = new import_decimal.default(0)) {
1113
+ const depositAmount = this.getDepositAmount(tempOrder, summary);
1114
+ if (!this.isDepositOrder(tempOrder, depositAmount)) {
1115
+ return this.getOrderExpectedAmount(summary);
1116
+ }
1117
+ if (this.isDepositCovered({ tempOrder, summary, paidAmount })) {
1118
+ return this.getOrderExpectedAmount(summary);
1119
+ }
1120
+ return depositAmount;
1121
+ }
1122
+ normalizeFingerprintMoney(value) {
1123
+ if (value === void 0 || value === null || value === "")
1124
+ return "";
1125
+ try {
1126
+ const parsed = new import_decimal.default(String(value || 0));
1127
+ return parsed.toFixed(4);
1128
+ } catch {
1129
+ return String(value);
1130
+ }
1131
+ }
1132
+ normalizeFingerprintValue(value) {
1133
+ if (Array.isArray(value)) {
1134
+ return value.map((item) => this.normalizeFingerprintValue(item));
1135
+ }
1136
+ if (!value || typeof value !== "object")
1137
+ return value ?? "";
1138
+ return Object.keys(value).sort().reduce((result, key) => {
1139
+ result[key] = this.normalizeFingerprintValue(value[key]);
1140
+ return result;
1141
+ }, {});
1142
+ }
1143
+ buildProductFingerprintItem(product) {
1144
+ const sku = (product == null ? void 0 : product.product_sku) || {};
1145
+ const metadata = (product == null ? void 0 : product.metadata) || {};
1146
+ const discountTypes = ((product == null ? void 0 : product.discount_list) || []).map((discount) => (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag));
1147
+ const extensionType = (product == null ? void 0 : product.extension_type) || (discountTypes.includes("good_pass") ? "good_pass" : "normal");
1148
+ return {
1149
+ product_id: (product == null ? void 0 : product.product_id) ?? null,
1150
+ product_variant_id: (product == null ? void 0 : product.product_variant_id) ?? null,
1151
+ extension_type: extensionType,
1152
+ num: (0, import_utils3.getSafeProductNum)((product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity)),
1153
+ selling_price: this.normalizeFingerprintMoney(product == null ? void 0 : product.selling_price),
1154
+ original_price: this.normalizeFingerprintMoney(product == null ? void 0 : product.original_price),
1155
+ payment_price: this.normalizeFingerprintMoney((product == null ? void 0 : product.payment_price) ?? (product == null ? void 0 : product.selling_price)),
1156
+ metadata: {
1157
+ source_product_price: this.normalizeFingerprintMoney(metadata.source_product_price),
1158
+ main_product_selling_price: this.normalizeFingerprintMoney(metadata.main_product_selling_price),
1159
+ main_product_original_price: this.normalizeFingerprintMoney(metadata.main_product_original_price),
1160
+ product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference)
1161
+ },
1162
+ product_sku: this.normalizeFingerprintValue({
1163
+ code: sku.code ?? "",
1164
+ barcode: sku.barcode ?? "",
1165
+ variant_id: sku.variant_id ?? (product == null ? void 0 : product.product_variant_id) ?? 0,
1166
+ variant: sku.variant || [],
1167
+ option: (0, import_utils.getProductSkuOptions)(product || {}).map((option) => ({
1168
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
1169
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
1170
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
1171
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
1172
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
1173
+ }))
1174
+ }),
1175
+ product_bundle: this.normalizeFingerprintValue(((product == null ? void 0 : product.product_bundle) || []).map((bundle) => ({
1176
+ bundle_product_id: (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id) ?? null,
1177
+ bundle_variant_id: (bundle == null ? void 0 : bundle.bundle_variant_id) ?? (bundle == null ? void 0 : bundle.product_variant_id) ?? 0,
1178
+ num: (0, import_utils3.getSafeProductNum)((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity)),
1179
+ price: this.normalizeFingerprintMoney(bundle == null ? void 0 : bundle.price),
1180
+ bundle_selling_price: this.normalizeFingerprintMoney(bundle == null ? void 0 : bundle.bundle_selling_price),
1181
+ price_type: (bundle == null ? void 0 : bundle.price_type) ?? "",
1182
+ price_type_ext: (bundle == null ? void 0 : bundle.price_type_ext) ?? ""
1183
+ }))),
1184
+ discount_list: this.normalizeFingerprintValue(((product == null ? void 0 : product.discount_list) || []).map((discount) => {
1185
+ var _a;
1186
+ return {
1187
+ type: (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag) ?? "",
1188
+ discount_id: (discount == null ? void 0 : discount.discount_id) ?? (discount == null ? void 0 : discount.order_discount_id) ?? ((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id) ?? null,
1189
+ amount: this.normalizeFingerprintMoney(discount == null ? void 0 : discount.amount)
1190
+ };
1191
+ }))
1192
+ };
1193
+ }
1194
+ buildOrderProductsFingerprint(products) {
1195
+ const items = (products || []).map((product) => this.buildProductFingerprintItem(product));
1196
+ items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1197
+ return JSON.stringify(items);
1198
+ }
1199
+ buildProductStructuralFingerprintItem(product) {
1200
+ const sku = (product == null ? void 0 : product.product_sku) || {};
1201
+ const metadata = (product == null ? void 0 : product.metadata) || {};
1202
+ const discountTypes = ((product == null ? void 0 : product.discount_list) || []).map((discount) => (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag));
1203
+ const extensionType = (product == null ? void 0 : product.extension_type) || (discountTypes.includes("good_pass") ? "good_pass" : "normal");
1204
+ return {
1205
+ product_id: (product == null ? void 0 : product.product_id) ?? null,
1206
+ product_variant_id: (product == null ? void 0 : product.product_variant_id) ?? null,
1207
+ extension_type: extensionType,
1208
+ num: (0, import_utils3.getSafeProductNum)((product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity)),
1209
+ metadata: {
1210
+ unique_identification_number: metadata.unique_identification_number ?? (product == null ? void 0 : product.unique_identification_number) ?? "",
1211
+ price_override: metadata.price_override ?? "",
1212
+ is_manual_discount: metadata.is_manual_discount ?? "",
1213
+ product_discount_reason: metadata.product_discount_reason ?? ""
1214
+ },
1215
+ product_sku: this.normalizeFingerprintValue({
1216
+ code: sku.code ?? "",
1217
+ barcode: sku.barcode ?? "",
1218
+ variant_id: sku.variant_id ?? (product == null ? void 0 : product.product_variant_id) ?? 0,
1219
+ variant: sku.variant || [],
1220
+ option: (0, import_utils.getProductSkuOptions)(product || {}).map((option) => ({
1221
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
1222
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
1223
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
1224
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
1225
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
1226
+ }))
1227
+ }),
1228
+ product_bundle: this.normalizeFingerprintValue(((product == null ? void 0 : product.product_bundle) || []).map((bundle) => ({
1229
+ bundle_id: (bundle == null ? void 0 : bundle.bundle_id) ?? (bundle == null ? void 0 : bundle.id) ?? null,
1230
+ bundle_group_id: (bundle == null ? void 0 : bundle.bundle_group_id) ?? (bundle == null ? void 0 : bundle.group_id) ?? null,
1231
+ bundle_product_id: (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id) ?? null,
1232
+ bundle_variant_id: (bundle == null ? void 0 : bundle.bundle_variant_id) ?? (bundle == null ? void 0 : bundle.product_variant_id) ?? 0,
1233
+ num: (0, import_utils3.getSafeProductNum)((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity)),
1234
+ price_type: (bundle == null ? void 0 : bundle.price_type) ?? "",
1235
+ price_type_ext: (bundle == null ? void 0 : bundle.price_type_ext) ?? "",
1236
+ option: this.normalizeFingerprintValue(((bundle == null ? void 0 : bundle.option) || []).map((option) => ({
1237
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
1238
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
1239
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
1240
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
1241
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
1242
+ })))
1243
+ }))),
1244
+ discount_list: this.normalizeFingerprintValue(((product == null ? void 0 : product.discount_list) || []).map((discount) => {
1245
+ var _a;
1246
+ return {
1247
+ type: (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag) ?? "",
1248
+ discount_id: (discount == null ? void 0 : discount.discount_id) ?? (discount == null ? void 0 : discount.order_discount_id) ?? ((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id) ?? null,
1249
+ amount: this.normalizeFingerprintMoney(discount == null ? void 0 : discount.amount)
1250
+ };
1251
+ }))
1252
+ };
1253
+ }
1254
+ buildOrderProductsStructuralFingerprint(products) {
1255
+ const items = (products || []).map((product) => this.buildProductStructuralFingerprintItem(product));
1256
+ items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1257
+ return JSON.stringify(items);
1258
+ }
1259
+ getManualDepositOverride(tempOrder) {
1260
+ var _a;
1261
+ const override = (_a = tempOrder._extend) == null ? void 0 : _a.manualDepositOverride;
1262
+ if (!override || typeof override !== "object")
1263
+ return null;
1264
+ if (typeof override.amount !== "string")
1265
+ return null;
1266
+ if (typeof override.productStructuralFingerprint !== "string")
1267
+ return null;
1268
+ return override;
1269
+ }
1270
+ setManualDepositOverride(tempOrder, amount) {
1271
+ tempOrder._extend = {
1272
+ ...tempOrder._extend || {},
1273
+ manualDepositOverride: {
1274
+ amount,
1275
+ productStructuralFingerprint: this.buildOrderProductsStructuralFingerprint(tempOrder.products)
1276
+ }
1277
+ };
1278
+ }
1279
+ clearManualDepositOverride(tempOrder) {
1280
+ var _a;
1281
+ if (!((_a = tempOrder._extend) == null ? void 0 : _a.manualDepositOverride))
1282
+ return;
1283
+ tempOrder._extend = { ...tempOrder._extend };
1284
+ delete tempOrder._extend.manualDepositOverride;
1285
+ }
1286
+ getOriginalSalesSnapshot(tempOrder) {
1287
+ var _a;
1288
+ const snapshot = (_a = tempOrder._extend) == null ? void 0 : _a.originalSalesSnapshot;
1289
+ if (!snapshot || typeof snapshot !== "object")
1290
+ return null;
1291
+ if (typeof snapshot.productFingerprint !== "string")
1292
+ return null;
1293
+ return snapshot;
1294
+ }
1295
+ isSnapshotPayableAmountUnchanged(tempOrder, snapshot, snapshotSummary) {
1296
+ const currentPaidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1297
+ const currentAmountGap = this.calculateSummaryAmountGap({
1298
+ tempOrder,
1299
+ summary: snapshotSummary,
1300
+ orderPaidAmount: currentPaidPaymentSummary.gapPaidAmount
1301
+ });
1302
+ const snapshotPaidPaymentSummary = this.calculatePaidPaymentSummary(
1303
+ Array.isArray(snapshot.payments) ? snapshot.payments : []
1304
+ );
1305
+ const snapshotAmountGap = this.calculateSummaryAmountGap({
1306
+ tempOrder,
1307
+ summary: snapshotSummary,
1308
+ orderPaidAmount: snapshotPaidPaymentSummary.gapPaidAmount
1309
+ });
1310
+ return currentAmountGap === snapshotAmountGap;
1311
+ }
1312
+ restoreOriginalSnapshotIfProductsUnchanged(tempOrder) {
1313
+ const snapshot = this.getOriginalSalesSnapshot(tempOrder);
1314
+ if (!snapshot)
1315
+ return null;
1316
+ const currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
1317
+ if (currentFingerprint !== snapshot.productFingerprint) {
1318
+ const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
1319
+ const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(
1320
+ Array.isArray(snapshot.products) ? snapshot.products : []
1321
+ );
1322
+ if (currentStructuralFingerprint !== snapshotStructuralFingerprint)
1323
+ return null;
1324
+ }
1325
+ const summary = {
1326
+ ...(0, import_utils.createEmptySummary)(),
1327
+ ...(0, import_lodash_es.cloneDeep)(snapshot.summary || {})
1328
+ };
1329
+ if (!this.isSnapshotPayableAmountUnchanged(tempOrder, snapshot, summary))
1330
+ return null;
1331
+ if (Array.isArray(snapshot.products)) {
1332
+ tempOrder.products = (0, import_lodash_es.cloneDeep)(snapshot.products);
1333
+ }
1334
+ if (Array.isArray(snapshot.surcharges)) {
1335
+ tempOrder.surcharges = (0, import_lodash_es.cloneDeep)(snapshot.surcharges);
1336
+ }
1337
+ tempOrder.surcharge_fee = summary.surcharge_fee || tempOrder.surcharge_fee;
1338
+ tempOrder.deposit_amount = summary.deposit_amount || "0.00";
1339
+ tempOrder.is_deposit = summary.deposit_amount !== "0.00" ? 1 : 0;
1340
+ this.store.summary = summary;
1341
+ return summary;
1342
+ }
1343
+ clearPersistedAmountFieldsForFullRecalc(products) {
1344
+ const moneyKeys = [
1345
+ "surcharge_fee",
1346
+ "main_product_attached_bundle_surcharge_fee",
1347
+ "surcharge_rounding_remainder",
1348
+ "main_product_attached_bundle_tax_fee",
1349
+ "tax_fee",
1350
+ "original_tax_fee",
1351
+ "tax_fee_rounding_remainder",
1352
+ "original_tax_fee_rounding_remainder"
1353
+ ];
1354
+ const metadataMoneyKeys = [
1355
+ "main_product_attached_bundle_surcharge_fee",
1356
+ "surcharge_rounding_remainder",
1357
+ "main_product_attached_bundle_tax_fee",
1358
+ "tax_fee_rounding_remainder"
1359
+ ];
1360
+ for (const product of products || []) {
1361
+ const record = product;
1362
+ for (const key of moneyKeys)
1363
+ delete record[key];
1364
+ if (record.metadata && typeof record.metadata === "object") {
1365
+ record.metadata = { ...record.metadata };
1366
+ for (const key of metadataMoneyKeys)
1367
+ delete record.metadata[key];
1368
+ }
1369
+ for (const bundle of record.product_bundle || []) {
1370
+ for (const key of moneyKeys)
1371
+ delete bundle[key];
1372
+ if (bundle.metadata && typeof bundle.metadata === "object") {
1373
+ bundle.metadata = { ...bundle.metadata };
1374
+ for (const key of metadataMoneyKeys)
1375
+ delete bundle.metadata[key];
1376
+ }
1377
+ }
1378
+ }
1379
+ }
540
1380
  getPaymentTargetAmount() {
541
1381
  const tempOrder = this.ensureTempOrder();
542
1382
  const summary = this.store.summary || (0, import_utils.createEmptySummary)();
543
- if (tempOrder.is_deposit === 1) {
544
- return new import_decimal.default(
545
- tempOrder.deposit_amount || summary.deposit_amount || 0
546
- );
547
- }
548
- return new import_decimal.default(summary.total_amount || summary.expect_amount || 0);
1383
+ const paidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1384
+ const refundAmount = this.getSummaryRefundAmount(summary);
1385
+ const netPaidAmount = import_decimal.default.max(
1386
+ paidPaymentSummary.gapPaidAmount.minus(refundAmount),
1387
+ 0
1388
+ );
1389
+ return this.calculatePaymentTargetAmount(tempOrder, summary, netPaidAmount);
549
1390
  }
550
1391
  ensureTempOrder() {
551
1392
  if (this.store.tempOrder) {
@@ -559,17 +1400,43 @@ var OrderModule = class extends import_BaseModule.BaseModule {
559
1400
  return newOrder;
560
1401
  }
561
1402
  restoreOrder() {
1403
+ var _a, _b;
562
1404
  const freshTempOrder = this.createDefaultTempOrderInstance();
563
1405
  this.ensureExternalSaleNumber(freshTempOrder);
564
1406
  this.store.tempOrder = freshTempOrder;
565
1407
  this.store.summary = (0, import_utils.createEmptySummary)();
566
1408
  this.store.lastOrderInfo = void 0;
1409
+ this.store.syncState = void 0;
1410
+ void ((_a = this.store.discount) == null ? void 0 : _a.setOriginalDiscountList([]));
1411
+ void ((_b = this.store.discount) == null ? void 0 : _b.setDiscountList([]));
567
1412
  this.persistTempOrder();
568
1413
  return freshTempOrder;
569
1414
  }
570
1415
  getTempOrder() {
571
1416
  return this.store.tempOrder;
572
1417
  }
1418
+ async replaceTempOrder(tempOrder, options) {
1419
+ if (!(0, import_utils.isTempOrder)(tempOrder)) {
1420
+ throw new Error("无效的 tempOrder 数据");
1421
+ }
1422
+ const nextTempOrder = this.normalizeTempOrderForRuntime(
1423
+ (0, import_lodash_es.cloneDeep)(tempOrder),
1424
+ { ensureIdentity: false }
1425
+ );
1426
+ this.store.tempOrder = nextTempOrder;
1427
+ if ((options == null ? void 0 : options.recalculateSummary) !== false) {
1428
+ await this.recalculateSummary({ createIfMissing: false });
1429
+ } else {
1430
+ this.store.summary = (0, import_utils.createEmptySummary)();
1431
+ }
1432
+ if ((options == null ? void 0 : options.persist) !== false) {
1433
+ this.persistTempOrder();
1434
+ }
1435
+ if (options == null ? void 0 : options.saveDraft) {
1436
+ await this.saveDraft();
1437
+ }
1438
+ return nextTempOrder;
1439
+ }
573
1440
  getOrderIdentity() {
574
1441
  var _a;
575
1442
  const tempOrder = this.store.tempOrder;
@@ -605,9 +1472,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
605
1472
  return null;
606
1473
  const summary = this.store.summary || (0, import_utils.createEmptySummary)();
607
1474
  const depositAmount = tempOrder.deposit_amount || summary.deposit_amount || "0.00";
608
- const targetAmount = tempOrder.is_deposit === 1 ? new import_decimal.default(depositAmount || 0) : new import_decimal.default(summary.total_amount || summary.expect_amount || 0);
609
- const paymentTotal = this.calculatePaymentTotal(tempOrder.payments || []);
610
- const amountGap = import_decimal.default.max(0, targetAmount.minus(paymentTotal)).toFixed(2);
1475
+ const paidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1476
+ const amountGap = this.calculateSummaryAmountGap({
1477
+ tempOrder,
1478
+ summary,
1479
+ orderPaidAmount: paidPaymentSummary.gapPaidAmount
1480
+ });
611
1481
  return {
612
1482
  isDeposit: tempOrder.is_deposit === 1 || depositAmount !== "0.00",
613
1483
  depositAmount,
@@ -650,7 +1520,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
650
1520
  this.ensureExternalSaleNumber(tempOrder);
651
1521
  await this.recalculateSummary({ createIfMissing: true });
652
1522
  this.persistTempOrder();
653
- await this.saveDraft();
1523
+ if (this.draftPersistEnabled) {
1524
+ await this.saveDraft();
1525
+ }
654
1526
  return tempOrder;
655
1527
  }
656
1528
  getOrderProducts() {
@@ -664,6 +1536,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
664
1536
  product.metadata = metadata;
665
1537
  return String(uid);
666
1538
  }
1539
+ sanitizeOrderProductForTempOrder(product) {
1540
+ if (product.metadata && typeof product.metadata === "object") {
1541
+ delete product.metadata.origin;
1542
+ }
1543
+ return product;
1544
+ }
1545
+ sanitizeTempOrderProducts(tempOrder) {
1546
+ tempOrder.products = (tempOrder.products || []).map(
1547
+ (product) => this.sanitizeOrderProductForTempOrder(product)
1548
+ );
1549
+ }
667
1550
  ensureExtend(tempOrder) {
668
1551
  if (!tempOrder._extend || typeof tempOrder._extend !== "object") {
669
1552
  tempOrder._extend = { productsByUid: {} };
@@ -697,6 +1580,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
697
1580
  );
698
1581
  productMetadata.unique_identification_number = productUid;
699
1582
  bookingMetadata.unique_identification_number = bookingUid;
1583
+ this.syncBookingMetadataHolder(params.booking, bookingMetadata);
700
1584
  return {
701
1585
  productUid,
702
1586
  bookingUid,
@@ -718,44 +1602,266 @@ var OrderModule = class extends import_BaseModule.BaseModule {
718
1602
  }
719
1603
  };
720
1604
  }
1605
+ /**
1606
+ * booking.holder 是提交真源;metadata.holder 作为详情/回显冗余字段同步保存。
1607
+ *
1608
+ * @example
1609
+ * this.syncBookingMetadataHolder(booking, metadata);
1610
+ */
1611
+ syncBookingMetadataHolder(booking, metadata) {
1612
+ if ((booking == null ? void 0 : booking.holder) !== void 0) {
1613
+ metadata.holder = booking.holder;
1614
+ }
1615
+ }
1616
+ /**
1617
+ * 从单条 booking 的 holder / metadata 中收集 holder form_record。
1618
+ *
1619
+ * @example
1620
+ * const ids = this.collectBookingHolderRecords(booking);
1621
+ */
1622
+ collectBookingHolderRecords(booking) {
1623
+ var _a;
1624
+ const holder = (booking == null ? void 0 : booking.holder) && typeof booking.holder === "object" ? booking.holder : null;
1625
+ const source = (holder == null ? void 0 : holder.form_record) ?? ((_a = booking == null ? void 0 : booking.metadata) == null ? void 0 : _a.holder_id);
1626
+ const records = Array.isArray(source) ? source : [source];
1627
+ return records.filter((record) => record !== void 0 && record !== null && record !== "");
1628
+ }
1629
+ /**
1630
+ * 按 form_record 顺序读取 booking holder 的主字段名称。
1631
+ *
1632
+ * @example
1633
+ * const names = this.collectBookingHolderNames(booking);
1634
+ */
1635
+ collectBookingHolderNames(booking) {
1636
+ const holder = (booking == null ? void 0 : booking.holder) && typeof booking.holder === "object" ? booking.holder : null;
1637
+ const rawName = holder == null ? void 0 : holder.name;
1638
+ if (Array.isArray(rawName)) {
1639
+ return rawName.map((name) => String(name || "").trim());
1640
+ }
1641
+ if (typeof rawName === "string") {
1642
+ return rawName.split(",").map((name) => name.trim());
1643
+ }
1644
+ return [];
1645
+ }
1646
+ /**
1647
+ * 按老 ticketBooking `formatHolder` 语义汇总订单顶层 holder。
1648
+ *
1649
+ * @example
1650
+ * const holder = this.buildTempOrderHolderFromBookings(tempOrder);
1651
+ */
1652
+ buildTempOrderHolderFromBookings(tempOrder) {
1653
+ var _a, _b;
1654
+ const holderRecords = [];
1655
+ const holderNames = [];
1656
+ let baseHolder = null;
1657
+ const seen = /* @__PURE__ */ new Set();
1658
+ for (const booking of tempOrder.bookings || []) {
1659
+ const holder = (booking == null ? void 0 : booking.holder) && typeof booking.holder === "object" ? booking.holder : null;
1660
+ if (!baseHolder && holder) {
1661
+ baseHolder = holder;
1662
+ }
1663
+ const records = this.collectBookingHolderRecords(booking);
1664
+ const names = this.collectBookingHolderNames(booking);
1665
+ for (const [index, record] of records.entries()) {
1666
+ const key = String(record);
1667
+ if (seen.has(key))
1668
+ continue;
1669
+ seen.add(key);
1670
+ holderRecords.push(record);
1671
+ if (names[index]) {
1672
+ holderNames.push(names[index]);
1673
+ }
1674
+ }
1675
+ }
1676
+ if (!holderRecords.length) {
1677
+ return null;
1678
+ }
1679
+ const nextHolder = {
1680
+ customer_id: (baseHolder == null ? void 0 : baseHolder.customer_id) ?? tempOrder.customer_id,
1681
+ form_id: (baseHolder == null ? void 0 : baseHolder.form_id) ?? ((_a = tempOrder.holder) == null ? void 0 : _a.form_id) ?? 0,
1682
+ form_record: holderRecords
1683
+ };
1684
+ if (holderNames.length) {
1685
+ nextHolder.name = holderNames.join(",");
1686
+ }
1687
+ if ((baseHolder == null ? void 0 : baseHolder.is_source_shop) || ((_b = this.otherParams) == null ? void 0 : _b.isFranchisee)) {
1688
+ nextHolder.is_source_shop = 1;
1689
+ }
1690
+ return nextHolder;
1691
+ }
1692
+ /**
1693
+ * 将 booking 级 holder 汇总到 tempOrder 顶层 holder。
1694
+ *
1695
+ * @example
1696
+ * this.syncTempOrderHolderFromBookings(tempOrder);
1697
+ */
1698
+ syncTempOrderHolderFromBookings(tempOrder) {
1699
+ const bookings = tempOrder.bookings || [];
1700
+ const hasHolderSource = bookings.some((booking) => {
1701
+ var _a;
1702
+ return (booking == null ? void 0 : booking.holder) !== void 0 || ((_a = booking == null ? void 0 : booking.metadata) == null ? void 0 : _a.holder_id) !== void 0;
1703
+ });
1704
+ const nextHolder = this.buildTempOrderHolderFromBookings(tempOrder);
1705
+ if (nextHolder || hasHolderSource || bookings.length === 0) {
1706
+ tempOrder.holder = nextHolder;
1707
+ }
1708
+ }
1709
+ getBookingUniqueIdentificationNumber(booking) {
1710
+ var _a;
1711
+ const uid = (_a = booking == null ? void 0 : booking.metadata) == null ? void 0 : _a.unique_identification_number;
1712
+ if (uid === void 0 || uid === null || uid === "")
1713
+ return null;
1714
+ return String(uid);
1715
+ }
1716
+ findBookingIndexByUniqueIdentificationNumber(tempOrder, uniqueIdentificationNumber) {
1717
+ return (tempOrder.bookings || []).findIndex((booking) => {
1718
+ return this.getBookingUniqueIdentificationNumber(booking) === uniqueIdentificationNumber;
1719
+ });
1720
+ }
1721
+ removeLinkedBookingsForProduct(tempOrder, product) {
1722
+ var _a, _b;
1723
+ const productUid = ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.unique_identification_number) || (product == null ? void 0 : product.unique_identification_number);
1724
+ const bookingUid = (product == null ? void 0 : product.booking_uid) || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.booking_uid);
1725
+ if (!productUid && !bookingUid)
1726
+ return;
1727
+ tempOrder.bookings = (tempOrder.bookings || []).filter((booking) => {
1728
+ const currentBookingUid = this.getBookingUniqueIdentificationNumber(booking);
1729
+ if (bookingUid && currentBookingUid === String(bookingUid))
1730
+ return false;
1731
+ if (productUid && String((booking == null ? void 0 : booking.product_uid) || "") === String(productUid))
1732
+ return false;
1733
+ return true;
1734
+ });
1735
+ }
721
1736
  // ─── TempOrder: 金额汇总 ───
722
1737
  getSalesSummary() {
723
1738
  if (!this.salesSummaryModuleName)
724
1739
  return null;
725
1740
  return this.core.getModule(this.salesSummaryModuleName);
726
1741
  }
1742
+ applyOrderProductsDepositSummary(tempOrder, summary) {
1743
+ var _a;
1744
+ const depositSummary = (0, import_utils.calculateOrderProductsDeposit)(tempOrder.products || [], {
1745
+ productsByUid: (_a = tempOrder._extend) == null ? void 0 : _a.productsByUid
1746
+ });
1747
+ const manualDepositOverride = this.getManualDepositOverride(tempOrder);
1748
+ const currentStructuralFingerprint = manualDepositOverride ? this.buildOrderProductsStructuralFingerprint(tempOrder.products) : "";
1749
+ const shouldUseManualDepositOverride = Boolean(
1750
+ manualDepositOverride && manualDepositOverride.productStructuralFingerprint === currentStructuralFingerprint
1751
+ );
1752
+ if (manualDepositOverride && !shouldUseManualDepositOverride) {
1753
+ this.clearManualDepositOverride(tempOrder);
1754
+ }
1755
+ const depositAmount = shouldUseManualDepositOverride ? manualDepositOverride.amount : depositSummary.totalText;
1756
+ const hasDepositAmount = new import_decimal.default(depositAmount).gt(0);
1757
+ const nextSummary = {
1758
+ ...summary,
1759
+ deposit_amount: depositAmount,
1760
+ deposit: hasDepositAmount ? {
1761
+ total: depositAmount,
1762
+ deposit_policy_ids: depositSummary.deposit_policy_ids,
1763
+ deposit_policy_data: depositSummary.protocols,
1764
+ hasDeposit: true
1765
+ } : void 0
1766
+ };
1767
+ tempOrder.deposit_amount = depositAmount;
1768
+ tempOrder.is_deposit = hasDepositAmount ? 1 : 0;
1769
+ return nextSummary;
1770
+ }
727
1771
  async recalculateSummary(options) {
728
1772
  const tempOrder = (options == null ? void 0 : options.createIfMissing) ? this.ensureTempOrder() : this.store.tempOrder;
729
1773
  if (!tempOrder)
730
1774
  return null;
1775
+ this.sanitizeTempOrderProducts(tempOrder);
1776
+ const snapshotSummary = this.restoreOriginalSnapshotIfProductsUnchanged(tempOrder);
1777
+ if (snapshotSummary)
1778
+ return snapshotSummary;
1779
+ const shouldFullRecalculateFromSnapshot = Boolean(this.getOriginalSalesSnapshot(tempOrder));
1780
+ const summaryProducts = shouldFullRecalculateFromSnapshot ? (0, import_lodash_es.cloneDeep)(tempOrder.products || []) : tempOrder.products;
1781
+ if (shouldFullRecalculateFromSnapshot) {
1782
+ this.clearPersistedAmountFieldsForFullRecalc(summaryProducts || []);
1783
+ }
731
1784
  const salesSummary = this.getSalesSummary();
732
1785
  const existedSummary = this.store.summary || (0, import_utils.createEmptySummary)();
1786
+ const totalRefundAmount = existedSummary.total_refund_amount || "0.00";
733
1787
  const paidPaymentSummary = this.calculatePaidPaymentSummary(
734
1788
  tempOrder.payments || []
735
1789
  );
736
1790
  if (!salesSummary) {
737
- const emptySummary = {
1791
+ const emptyBaseSummary = {
738
1792
  ...(0, import_utils.createEmptySummary)(),
739
- total_refund_amount: existedSummary.total_refund_amount || "0.00",
1793
+ ...existedSummary,
1794
+ total_refund_amount: totalRefundAmount
1795
+ };
1796
+ const emptySummaryBase = {
1797
+ ...emptyBaseSummary,
740
1798
  customer_paid_amount: paidPaymentSummary.customerPaidAmount.toFixed(2),
741
1799
  order_paid_amount: paidPaymentSummary.orderPaidAmount.toFixed(2),
742
- pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2)
1800
+ pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2),
1801
+ rounding_amount: paidPaymentSummary.roundingAmount.toFixed(2)
1802
+ };
1803
+ const emptySummaryWithDeposit = this.applyOrderProductsDepositSummary(
1804
+ tempOrder,
1805
+ emptySummaryBase
1806
+ );
1807
+ const emptySummary = {
1808
+ ...emptySummaryWithDeposit,
1809
+ amount_gap: this.calculateSummaryAmountGap({
1810
+ tempOrder,
1811
+ summary: emptySummaryWithDeposit,
1812
+ orderPaidAmount: paidPaymentSummary.gapPaidAmount
1813
+ })
743
1814
  };
744
- this.store.summary = emptySummary;
745
1815
  tempOrder.surcharge_fee = emptySummary.surcharge_fee;
1816
+ this.store.summary = emptySummary;
1817
+ this.updateTempOrderPaymentStatus(tempOrder, {
1818
+ previousSummary: existedSummary,
1819
+ summary: emptySummary
1820
+ });
746
1821
  return this.store.summary;
747
1822
  }
748
1823
  const salesSummaryResult = await salesSummary.getSummary({
749
- products: tempOrder.products,
1824
+ products: summaryProducts,
750
1825
  isPriceIncludeTax: tempOrder.is_price_include_tax,
751
1826
  shopDiscount: tempOrder.shop_discount
752
1827
  });
753
- const summary = {
1828
+ if (shouldFullRecalculateFromSnapshot) {
1829
+ tempOrder.products = summaryProducts;
1830
+ }
1831
+ this.syncSummaryProductMetadata(tempOrder.products || []);
1832
+ const roundingAmount = paidPaymentSummary.roundingAmount;
1833
+ const payServiceChargeAmount = paidPaymentSummary.payServiceChargeAmount;
1834
+ const hasSalesSummaryAmount = salesSummaryResult.expect_amount !== void 0 || salesSummaryResult.total_amount !== void 0;
1835
+ const expectAmount = hasSalesSummaryAmount ? new import_decimal.default(salesSummaryResult.expect_amount ?? salesSummaryResult.total_amount ?? 0) : null;
1836
+ const amountPaymentPatch = hasSalesSummaryAmount || !roundingAmount.eq(0) || !payServiceChargeAmount.eq(0) ? {
1837
+ rounding_amount: roundingAmount.toFixed(2),
1838
+ ...expectAmount ? {
1839
+ total_amount: import_decimal.default.max(
1840
+ 0,
1841
+ expectAmount.plus(roundingAmount).plus(payServiceChargeAmount)
1842
+ ).toFixed(2)
1843
+ } : {}
1844
+ } : {};
1845
+ const normalizedExpectAmountPatch = expectAmount && salesSummaryResult.expect_amount === void 0 ? { expect_amount: expectAmount.toFixed(2) } : {};
1846
+ const summaryForGap = this.applyOrderProductsDepositSummary(tempOrder, {
754
1847
  ...salesSummaryResult,
755
- total_refund_amount: existedSummary.total_refund_amount || "0.00",
1848
+ total_refund_amount: totalRefundAmount,
1849
+ ...amountPaymentPatch,
1850
+ ...normalizedExpectAmountPatch
1851
+ });
1852
+ const summary = {
1853
+ ...summaryForGap,
1854
+ total_refund_amount: totalRefundAmount,
756
1855
  customer_paid_amount: paidPaymentSummary.customerPaidAmount.toFixed(2),
757
1856
  order_paid_amount: paidPaymentSummary.orderPaidAmount.toFixed(2),
758
- pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2)
1857
+ ...amountPaymentPatch,
1858
+ ...normalizedExpectAmountPatch,
1859
+ amount_gap: this.calculateSummaryAmountGap({
1860
+ tempOrder,
1861
+ summary: summaryForGap,
1862
+ orderPaidAmount: paidPaymentSummary.gapPaidAmount
1863
+ }),
1864
+ pay_service_charge_amount: payServiceChargeAmount.toFixed(2)
759
1865
  };
760
1866
  this.store.summary = summary;
761
1867
  if (summary.is_price_include_tax !== void 0) {
@@ -766,8 +1872,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
766
1872
  }
767
1873
  tempOrder.surcharge_fee = summary.surcharge_fee;
768
1874
  tempOrder.surcharges = summary.surcharges || [];
769
- tempOrder.deposit_amount = summary.deposit_amount || "0.00";
770
- tempOrder.is_deposit = summary.deposit_amount !== "0.00" ? 1 : 0;
1875
+ this.updateTempOrderPaymentStatus(tempOrder, {
1876
+ previousSummary: existedSummary,
1877
+ summary
1878
+ });
771
1879
  return this.store.summary;
772
1880
  }
773
1881
  async getOrderSummary() {
@@ -777,13 +1885,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
777
1885
  this.persistTempOrder();
778
1886
  return summary;
779
1887
  }
780
- // ─── TempOrder: 备注 ───
781
- updateTempOrderNote(note) {
1888
+ updateTempOrderNote(note, sync = false) {
782
1889
  const tempOrder = this.ensureTempOrder();
783
1890
  tempOrder.note = String(note || "");
784
1891
  this.persistTempOrder();
1892
+ if (sync) {
1893
+ const orderId = tempOrder.order_id;
1894
+ if (!orderId)
1895
+ return tempOrder.note;
1896
+ return this.syncTempOrderNoteToRemote(orderId, tempOrder.note);
1897
+ }
785
1898
  return tempOrder.note;
786
1899
  }
1900
+ async syncTempOrderNoteToRemote(orderId, note) {
1901
+ await this.request.put(`/order/order/${orderId}/note`, { note });
1902
+ return note;
1903
+ }
787
1904
  getTempOrderNote() {
788
1905
  var _a;
789
1906
  return ((_a = this.store.tempOrder) == null ? void 0 : _a.note) || "";
@@ -795,6 +1912,36 @@ var OrderModule = class extends import_BaseModule.BaseModule {
795
1912
  this.persistTempOrder();
796
1913
  return tempOrder.shop_discount;
797
1914
  }
1915
+ updateTempOrderDepositAmount(amount) {
1916
+ const tempOrder = this.ensureTempOrder();
1917
+ const depositAmount = this.normalizeDepositAmount(amount);
1918
+ const previousSummary = this.store.summary || (0, import_utils.createEmptySummary)();
1919
+ const summaryWithDeposit = this.applyDepositAmountToSummary(
1920
+ tempOrder,
1921
+ {
1922
+ ...(0, import_utils.createEmptySummary)(),
1923
+ ...previousSummary
1924
+ },
1925
+ depositAmount
1926
+ );
1927
+ this.setManualDepositOverride(tempOrder, depositAmount);
1928
+ const paidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1929
+ const summary = {
1930
+ ...summaryWithDeposit,
1931
+ amount_gap: this.calculateSummaryAmountGap({
1932
+ tempOrder,
1933
+ summary: summaryWithDeposit,
1934
+ orderPaidAmount: paidPaymentSummary.gapPaidAmount
1935
+ })
1936
+ };
1937
+ this.store.summary = summary;
1938
+ this.updateTempOrderPaymentStatus(tempOrder, {
1939
+ previousSummary,
1940
+ summary
1941
+ });
1942
+ this.persistTempOrder();
1943
+ return summary;
1944
+ }
798
1945
  updateTempOrderBuzzer(buzzer) {
799
1946
  const tempOrder = this.ensureTempOrder();
800
1947
  tempOrder.buzzer = String(buzzer || "");
@@ -807,14 +1954,77 @@ var OrderModule = class extends import_BaseModule.BaseModule {
807
1954
  this.persistTempOrder();
808
1955
  return tempOrder.contacts_info;
809
1956
  }
1957
+ buildTempOrderCustomer(params) {
1958
+ if (!params.customerId)
1959
+ return null;
1960
+ const source = params.source ? (0, import_lodash_es.cloneDeep)(params.source) : {};
1961
+ const name = source.name ?? source.display_name ?? source.customerName ?? source.customer_name ?? params.customerName;
1962
+ const customerName = source.customer_name ?? source.customerName ?? source.display_name ?? source.name ?? params.customerName;
1963
+ return {
1964
+ ...source,
1965
+ id: source.id ?? params.customerId,
1966
+ customer_id: source.customer_id ?? params.customerId,
1967
+ name: String(name || ""),
1968
+ customer_name: String(customerName || ""),
1969
+ country_calling_code: String(
1970
+ source.country_calling_code ?? source.countryCallingCode ?? params.countryCallingCode
1971
+ ),
1972
+ phone: String(source.phone ?? params.phone),
1973
+ email: String(source.email ?? params.email)
1974
+ };
1975
+ }
1976
+ isCustomerBoundDiscount(discount) {
1977
+ const type = (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag);
1978
+ return type === "good_pass" || type === "discount_card" || type === "product_discount_card";
1979
+ }
1980
+ clearCustomerBoundDiscounts(tempOrder) {
1981
+ var _a, _b, _c, _d;
1982
+ const filterDiscountList = (discountList) => {
1983
+ if (!Array.isArray(discountList))
1984
+ return [];
1985
+ return discountList.filter((discount) => !this.isCustomerBoundDiscount(discount));
1986
+ };
1987
+ tempOrder.products = (tempOrder.products || []).map((product) => {
1988
+ const nextProduct = {
1989
+ ...product,
1990
+ discount_list: filterDiscountList(product.discount_list)
1991
+ };
1992
+ if (Array.isArray(nextProduct.product_bundle)) {
1993
+ nextProduct.product_bundle = nextProduct.product_bundle.map((bundle) => ({
1994
+ ...bundle,
1995
+ discount_list: filterDiscountList(bundle.discount_list)
1996
+ }));
1997
+ }
1998
+ return nextProduct;
1999
+ });
2000
+ delete tempOrder.discount_list;
2001
+ const discountModule = this.store.discount;
2002
+ if (!discountModule)
2003
+ return;
2004
+ const currentDiscounts = ((_a = discountModule.getDiscountList) == null ? void 0 : _a.call(discountModule)) || [];
2005
+ const currentOriginalDiscounts = ((_b = discountModule.getOriginalDiscountList) == null ? void 0 : _b.call(discountModule)) || [];
2006
+ const nextDiscounts = currentDiscounts.filter((discount) => {
2007
+ if (discount == null ? void 0 : discount.isEditMode)
2008
+ return true;
2009
+ return !this.isCustomerBoundDiscount(discount);
2010
+ });
2011
+ const nextOriginalDiscounts = currentOriginalDiscounts.filter((discount) => {
2012
+ if (discount == null ? void 0 : discount.isEditMode)
2013
+ return true;
2014
+ return !this.isCustomerBoundDiscount(discount);
2015
+ });
2016
+ void ((_c = discountModule.setDiscountList) == null ? void 0 : _c.call(discountModule, nextDiscounts));
2017
+ void ((_d = discountModule.setOriginalDiscountList) == null ? void 0 : _d.call(discountModule, nextOriginalDiscounts));
2018
+ }
810
2019
  /**
811
2020
  * 更新当前 tempOrder 的客户协议字段。
812
2021
  *
813
- * PaymentModal 只需要修改订单里的客户字段;如果外部还有客户模块需要同步,
2022
+ * PaymentModal 只需要修改订单里的客户事实;如果外部还有客户模块需要同步,
814
2023
  * 应由调用方通过回调处理,不能把外部 UI 状态写进 tempOrder。
815
2024
  */
816
2025
  updateTempOrderCustomer(customer) {
817
2026
  const tempOrder = this.ensureTempOrder();
2027
+ const previousCustomerId = tempOrder.customer_id ?? null;
818
2028
  const customerId = customer.customer_id ?? customer.customerId ?? customer.id ?? null;
819
2029
  const customerName = customer.customer_name ?? customer.customerName ?? customer.display_name ?? customer.name ?? "";
820
2030
  tempOrder.customer_id = customerId === null || customerId === void 0 || customerId === "" ? null : Number(customerId);
@@ -824,6 +2034,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
824
2034
  );
825
2035
  tempOrder.phone = String(customer.phone || "");
826
2036
  tempOrder.email = String(customer.email || "");
2037
+ tempOrder.customer = this.buildTempOrderCustomer({
2038
+ source: customer,
2039
+ customerId: tempOrder.customer_id,
2040
+ customerName: tempOrder.customer_name,
2041
+ countryCallingCode: tempOrder.country_calling_code,
2042
+ phone: tempOrder.phone,
2043
+ email: tempOrder.email
2044
+ });
2045
+ const nextCustomerId = tempOrder.customer_id ?? null;
827
2046
  this.persistTempOrder();
828
2047
  return {
829
2048
  customerId: tempOrder.customer_id,
@@ -838,11 +2057,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
838
2057
  return;
839
2058
  }
840
2059
  const tempOrder = this.ensureTempOrder();
2060
+ const previousCustomerId = tempOrder.customer_id ?? null;
841
2061
  tempOrder.customer_id = patch.customer_id || patch.id || null;
842
2062
  tempOrder.customer_name = String(patch.customer_name || "");
843
2063
  tempOrder.country_calling_code = String(patch.country_calling_code || "");
844
2064
  tempOrder.phone = String(patch.phone || "");
845
2065
  tempOrder.email = String(patch.email || "");
2066
+ tempOrder.customer = this.buildTempOrderCustomer({
2067
+ source: snapshot || null,
2068
+ customerId: tempOrder.customer_id,
2069
+ customerName: tempOrder.customer_name,
2070
+ countryCallingCode: tempOrder.country_calling_code,
2071
+ phone: tempOrder.phone,
2072
+ email: tempOrder.email
2073
+ });
846
2074
  if (snapshot !== void 0) {
847
2075
  const extend = this.ensureExtend(tempOrder);
848
2076
  if (snapshot === null)
@@ -850,12 +2078,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
850
2078
  else
851
2079
  extend.customerSnapshot = (0, import_lodash_es.cloneDeep)(snapshot);
852
2080
  }
2081
+ const nextCustomerId = tempOrder.customer_id ?? null;
2082
+ if (String(previousCustomerId ?? "") !== String(nextCustomerId ?? "")) {
2083
+ (0, import_utils.clearTempOrderHolderAssignments)(tempOrder);
2084
+ this.clearCustomerBoundDiscounts(tempOrder);
2085
+ }
853
2086
  this.persistTempOrder();
854
- this.emitOrderCustomerChange();
2087
+ this.saveDraftInBackground();
2088
+ if (String(previousCustomerId ?? "") !== String(nextCustomerId ?? "")) {
2089
+ this.emitOrderCustomerChange();
2090
+ }
855
2091
  }
856
2092
  getOrderCustomer() {
857
2093
  const tempOrder = this.store.tempOrder;
858
- if (!tempOrder || tempOrder.customer_id === null || tempOrder.customer_id === void 0) {
2094
+ if (!tempOrder || !tempOrder.customer_id) {
859
2095
  return null;
860
2096
  }
861
2097
  return {
@@ -873,14 +2109,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
873
2109
  }
874
2110
  clearOrderCustomer() {
875
2111
  const tempOrder = this.ensureTempOrder();
2112
+ (0, import_utils.clearTempOrderHolderAssignments)(tempOrder);
876
2113
  tempOrder.customer_id = null;
877
2114
  tempOrder.customer_name = "";
878
2115
  tempOrder.country_calling_code = "";
879
2116
  tempOrder.phone = "";
880
2117
  tempOrder.email = "";
2118
+ tempOrder.customer = null;
881
2119
  if (tempOrder._extend)
882
2120
  delete tempOrder._extend.customerSnapshot;
2121
+ this.clearCustomerBoundDiscounts(tempOrder);
883
2122
  this.persistTempOrder();
2123
+ this.saveDraftInBackground();
884
2124
  this.core.effects.emit(import_types.OrderHooks.OnOrderCustomerChange, null);
885
2125
  }
886
2126
  emitOrderCustomerChange() {
@@ -920,10 +2160,28 @@ var OrderModule = class extends import_BaseModule.BaseModule {
920
2160
  }
921
2161
  /** 追加单个支付项,并立即持久化当前 tempOrder。 */
922
2162
  addOrderPayment(payment) {
2163
+ this.logInfo("addOrderPayment", {
2164
+ payment
2165
+ });
923
2166
  const tempOrder = this.ensureTempOrder();
924
- const mapped = (0, import_utils.mapPaymentItemsToOrderPayments)([payment]);
2167
+ const orderPaymentType = this.resolveNextOrderPaymentType(tempOrder);
2168
+ const mapped = (0, import_utils.mapPaymentItemsToOrderPayments)([
2169
+ this.normalizePaymentSource(
2170
+ {
2171
+ ...payment,
2172
+ type: orderPaymentType,
2173
+ order_payment_type: orderPaymentType
2174
+ },
2175
+ { defaultPaid: true }
2176
+ )
2177
+ ]);
925
2178
  tempOrder.payments = [...tempOrder.payments || [], ...mapped];
926
2179
  this.persistTempOrder();
2180
+ void this.recalculateSummary({ createIfMissing: true }).catch((error) => {
2181
+ this.logError("recalculate summary after addOrderPayment failed", {
2182
+ error: error instanceof Error ? error.message : String(error)
2183
+ });
2184
+ });
927
2185
  return tempOrder.payments;
928
2186
  }
929
2187
  /**
@@ -989,14 +2247,48 @@ var OrderModule = class extends import_BaseModule.BaseModule {
989
2247
  */
990
2248
  updateVoucherOrderPayments(payments) {
991
2249
  const tempOrder = this.ensureTempOrder();
992
- const mappedVouchers = (0, import_utils.mapPaymentItemsToOrderPayments)(payments).filter(
993
- (payment) => payment.voucher_id !== void 0 && Number(payment.voucher_id) !== 0
994
- );
2250
+ const isVoucherPayment = (payment) => {
2251
+ return payment.voucher_id !== void 0 && Number(payment.voucher_id) !== 0;
2252
+ };
2253
+ const hasSyncedOrderPayment = (payment) => {
2254
+ return payment.order_payment_id !== void 0 && payment.order_payment_id !== null;
2255
+ };
2256
+ const mappedVouchers = (0, import_utils.mapPaymentItemsToOrderPayments)(
2257
+ payments.map(
2258
+ (payment) => this.normalizePaymentSource(payment, { defaultPaid: true })
2259
+ )
2260
+ ).filter((payment) => {
2261
+ return isVoucherPayment(payment);
2262
+ });
995
2263
  const nonVoucherPayments = (tempOrder.payments || []).filter((payment) => {
996
- return payment.voucher_id === void 0 || Number(payment.voucher_id) === 0;
2264
+ return !isVoucherPayment(payment);
2265
+ });
2266
+ const syncedVoucherPayments = (tempOrder.payments || []).filter((payment) => {
2267
+ return isVoucherPayment(payment) && hasSyncedOrderPayment(payment);
2268
+ });
2269
+ const syncedVoucherPaymentIds = new Set(
2270
+ syncedVoucherPayments.map((payment) => String(payment.order_payment_id))
2271
+ );
2272
+ const replaceableVouchers = mappedVouchers.filter((payment) => {
2273
+ if (!hasSyncedOrderPayment(payment))
2274
+ return true;
2275
+ return !syncedVoucherPaymentIds.has(String(payment.order_payment_id));
997
2276
  });
998
- tempOrder.payments = [...nonVoucherPayments, ...mappedVouchers];
2277
+ const cappedVouchers = this.capVoucherPaymentsByRemainingAmount({
2278
+ vouchers: replaceableVouchers,
2279
+ nonVoucherPayments: [
2280
+ ...nonVoucherPayments,
2281
+ ...syncedVoucherPayments
2282
+ ]
2283
+ });
2284
+ tempOrder.payments = [...nonVoucherPayments, ...syncedVoucherPayments, ...cappedVouchers];
2285
+ this.updateTempOrderPaymentStatus(tempOrder);
999
2286
  this.persistTempOrder();
2287
+ void this.recalculateSummary({ createIfMissing: true }).catch((error) => {
2288
+ this.logError("recalculate summary after updateVoucherOrderPayments failed", {
2289
+ error: error instanceof Error ? error.message : String(error)
2290
+ });
2291
+ });
1000
2292
  return tempOrder.payments;
1001
2293
  }
1002
2294
  async shouldMergeProductToOrder(params) {
@@ -1015,37 +2307,98 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1015
2307
  }
1016
2308
  return true;
1017
2309
  }
1018
- // ─── TempOrder: 商品 CRUD ───
1019
- async addProductToOrder(product, booking) {
1020
- var _a;
1021
- const tempOrder = this.ensureTempOrder();
2310
+ hasOrderProductLineNote(product) {
2311
+ return typeof (product == null ? void 0 : product.note) === "string" && product.note.trim().length > 0;
2312
+ }
2313
+ /**
2314
+ * 判断商品行是否显式绑定了 booking。
2315
+ *
2316
+ * @example
2317
+ * this.hasLinkedBookingUid({ metadata: { booking_uid: 'booking-1' } });
2318
+ */
2319
+ hasLinkedBookingUid(product) {
2320
+ var _a;
2321
+ const bookingUid = (product == null ? void 0 : product.booking_uid) ?? ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.booking_uid);
2322
+ return bookingUid !== void 0 && bookingUid !== null && String(bookingUid) !== "";
2323
+ }
2324
+ // ─── TempOrder: 商品 CRUD ───
2325
+ /**
2326
+ * 预约商品加车后的统一收尾:促销、折扣、summary 重算与持久化(批量拆行时只调用一次)。
2327
+ *
2328
+ * @example
2329
+ * await this.finalizeProductOrderMutation(tempOrder);
2330
+ */
2331
+ async finalizeProductOrderMutation(tempOrder, options) {
2332
+ this.syncTempOrderHolderFromBookings(tempOrder);
2333
+ if (!(options == null ? void 0 : options.skipEditDiscountConfigRefresh)) {
2334
+ await this.ensureEditDiscountConfigForProductChange(tempOrder);
2335
+ }
2336
+ if (!(options == null ? void 0 : options.skipDiscountRecalculation)) {
2337
+ await this.applyPromotion();
2338
+ }
2339
+ if (!(options == null ? void 0 : options.skipDiscountRecalculation)) {
2340
+ this.applyDiscount();
2341
+ }
2342
+ this.sanitizeTempOrderProducts(tempOrder);
2343
+ await this.recalculateSummary({ createIfMissing: true });
2344
+ this.persistTempOrder();
2345
+ }
2346
+ /**
2347
+ * 向 tempOrder 追加一条商品行(及可选 booking),不触发 summary 重算。
2348
+ * 带 booking 且 num>1 时由 `addProductToOrder` 拆成多次本方法调用(每次 num=1)。
2349
+ *
2350
+ * @example
2351
+ * await this.appendProductLineToTempOrder(tempOrder, { product_id: 1, num: 1 }, booking);
2352
+ */
2353
+ async appendProductLineToTempOrder(tempOrder, product, booking) {
2354
+ var _a, _b;
1022
2355
  const linked = booking ? this.createLinkedProductAndBooking({ product, booking }) : null;
1023
2356
  const productToAdd = (linked == null ? void 0 : linked.product) || product;
1024
2357
  const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
1025
- productToAdd.product_option_item,
2358
+ (0, import_utils.getProductSkuOptions)(productToAdd),
1026
2359
  productToAdd.product_bundle
1027
2360
  );
1028
- const normalizedIncoming = (0, import_utils3.normalizeOrderProduct)(productToAdd);
2361
+ const normalizedIncoming = (0, import_utils.mergeOrderProductDisplayFields)(
2362
+ productToAdd,
2363
+ (0, import_utils3.normalizeOrderProduct)(productToAdd)
2364
+ );
2365
+ const incomingBookingUid = productToAdd.booking_uid ?? ((_a = productToAdd.metadata) == null ? void 0 : _a.booking_uid);
2366
+ if (incomingBookingUid !== void 0 && incomingBookingUid !== null && String(incomingBookingUid) !== "") {
2367
+ normalizedIncoming.booking_uid = String(incomingBookingUid);
2368
+ normalizedIncoming.metadata = {
2369
+ ...normalizedIncoming.metadata || {},
2370
+ booking_uid: String(incomingBookingUid)
2371
+ };
2372
+ }
2373
+ normalizedIncoming.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
2374
+ normalizedIncoming.discount_list
2375
+ );
1029
2376
  const hasIncomingGoodPass = this.hasGoodPassDiscount(
1030
2377
  normalizedIncoming
1031
2378
  );
1032
- const shouldForceNewLine = !!booking;
2379
+ const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
2380
+ const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
2381
+ const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid;
1033
2382
  const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex((item) => {
1034
2383
  if (this.hasGoodPassDiscount(item))
1035
2384
  return false;
2385
+ if (this.hasOrderProductLineNote(item))
2386
+ return false;
2387
+ if (item.order_detail_id !== void 0 && item.order_detail_id !== null)
2388
+ return false;
1036
2389
  if (item.product_id !== productToAdd.product_id)
1037
2390
  return false;
1038
2391
  if (item.product_variant_id !== productToAdd.product_variant_id)
1039
2392
  return false;
1040
2393
  const existedFingerprint2 = (0, import_utils3.buildProductLineFingerprint)(
1041
- item.product_option_item,
2394
+ (0, import_utils.getProductSkuOptions)(item),
1042
2395
  item.product_bundle
1043
2396
  );
1044
2397
  return existedFingerprint2 === incomingFingerprint;
1045
2398
  });
1046
2399
  const matchedProduct = matchedIndex === -1 ? null : tempOrder.products[matchedIndex];
1047
2400
  const existedFingerprint = matchedProduct ? (0, import_utils3.buildProductLineFingerprint)(
1048
- matchedProduct.product_option_item,
2401
+ (0, import_utils.getProductSkuOptions)(matchedProduct),
1049
2402
  matchedProduct.product_bundle
1050
2403
  ) : "";
1051
2404
  const shouldMerge = matchedProduct ? await this.shouldMergeProductToOrder({
@@ -1071,28 +2424,58 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1071
2424
  booking_uid: linked.bookingUid
1072
2425
  };
1073
2426
  }
1074
- tempOrder.products.push(normalizedIncoming);
2427
+ tempOrder.products = [...tempOrder.products, normalizedIncoming];
1075
2428
  } else {
1076
2429
  const targetProduct = matchedProduct;
1077
- const targetUid = (_a = targetProduct.metadata) == null ? void 0 : _a.unique_identification_number;
1078
- const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
1079
- ...productToAdd,
1080
- metadata: {
1081
- ...productToAdd.metadata || {},
1082
- unique_identification_number: targetUid
1083
- }
1084
- });
2430
+ const targetUid = (_b = targetProduct.metadata) == null ? void 0 : _b.unique_identification_number;
2431
+ const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
2432
+ targetProduct,
2433
+ (0, import_utils3.normalizeOrderProduct)({
2434
+ ...productToAdd,
2435
+ metadata: {
2436
+ ...productToAdd.metadata || {},
2437
+ unique_identification_number: targetUid
2438
+ }
2439
+ })
2440
+ );
2441
+ normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
2442
+ normalizedProduct.discount_list
2443
+ );
2444
+ const nextNum = (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
2445
+ const targetIsManualProductDiscount = isManualProductDiscountProduct(targetProduct);
2446
+ const nextDiscountList = targetIsManualProductDiscount ? (0, import_utils.normalizeOrderProductDiscountList)(
2447
+ (0, import_manualProductDiscount.syncManualProductDiscountProductNum)(
2448
+ targetProduct.discount_list,
2449
+ nextNum
2450
+ )
2451
+ ) : normalizedProduct.discount_list;
1085
2452
  tempOrder.products[matchedIndex] = {
1086
2453
  ...targetProduct,
1087
2454
  ...normalizedProduct,
2455
+ discount_list: nextDiscountList,
1088
2456
  metadata: {
1089
2457
  ...targetProduct.metadata || {},
1090
2458
  ...normalizedProduct.metadata || {},
1091
2459
  unique_identification_number: targetUid
1092
2460
  },
2461
+ product_sku: {
2462
+ ...targetProduct.product_sku || { option: [] },
2463
+ ...normalizedProduct.product_sku || { option: [] },
2464
+ option: (0, import_utils.getProductSkuOptions)(normalizedProduct)
2465
+ },
2466
+ ...targetIsManualProductDiscount ? {
2467
+ selling_price: targetProduct.selling_price,
2468
+ original_price: targetProduct.original_price,
2469
+ payment_price: targetProduct.payment_price,
2470
+ metadata: {
2471
+ ...normalizedProduct.metadata || {},
2472
+ ...targetProduct.metadata || {},
2473
+ unique_identification_number: targetUid
2474
+ }
2475
+ } : {},
1093
2476
  note: targetProduct.note,
1094
2477
  order_detail_id: targetProduct.order_detail_id,
1095
- num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num)
2478
+ num: nextNum
1096
2479
  };
1097
2480
  this.captureProductRuntime(
1098
2481
  tempOrder,
@@ -1104,9 +2487,79 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1104
2487
  if (linked) {
1105
2488
  tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
1106
2489
  }
1107
- this.applyDiscount();
1108
- await this.recalculateSummary({ createIfMissing: true });
1109
- this.persistTempOrder();
2490
+ }
2491
+ /**
2492
+ * 添加商品行。带 booking 时强制独立行;num>1 时拆成多条 num=1 的 product+booking(对齐 BookingByStep / ticketBooking addService)。
2493
+ *
2494
+ * @example
2495
+ * await order.addProductToOrder({ product_id: 1, num: 3 }, { start_time: '10:00' });
2496
+ * // → tempOrder.products 新增 3 行,每行 num=1,bookings 3 条
2497
+ */
2498
+ async addProductToOrder(product, booking) {
2499
+ const tempOrder = this.ensureTempOrder();
2500
+ if (booking) {
2501
+ const productRecord = product;
2502
+ const splitCount = (0, import_utils3.getSafeProductNum)(
2503
+ productRecord.num ?? productRecord.product_quantity ?? 1
2504
+ );
2505
+ if (splitCount > 1) {
2506
+ for (let i = 0; i < splitCount; i += 1) {
2507
+ const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
2508
+ singleLine.num = 1;
2509
+ delete singleLine.product_quantity;
2510
+ await this.appendProductLineToTempOrder(
2511
+ tempOrder,
2512
+ singleLine,
2513
+ (0, import_lodash_es.cloneDeep)(booking)
2514
+ );
2515
+ }
2516
+ await this.finalizeProductOrderMutation(tempOrder);
2517
+ return tempOrder.products;
2518
+ }
2519
+ }
2520
+ await this.appendProductLineToTempOrder(tempOrder, product, booking);
2521
+ await this.finalizeProductOrderMutation(tempOrder);
2522
+ return tempOrder.products;
2523
+ }
2524
+ /**
2525
+ * 批量添加商品行,所有行追加完成后只触发一次促销、折扣、summary 重算与持久化。
2526
+ *
2527
+ * @example
2528
+ * await order.addProductsToOrder([
2529
+ * { product: { product_id: 1, product_variant_id: 0, num: 1 } },
2530
+ * { product: { product_id: 2, product_variant_id: 0, num: 1 } },
2531
+ * ]);
2532
+ */
2533
+ async addProductsToOrder(items, options) {
2534
+ const tempOrder = this.ensureTempOrder();
2535
+ if (!Array.isArray(items) || items.length === 0)
2536
+ return tempOrder.products;
2537
+ for (const item of items || []) {
2538
+ const { product, booking } = item;
2539
+ if (!product)
2540
+ continue;
2541
+ if (booking) {
2542
+ const productRecord = product;
2543
+ const splitCount = (0, import_utils3.getSafeProductNum)(
2544
+ productRecord.num ?? productRecord.product_quantity ?? 1
2545
+ );
2546
+ if (splitCount > 1) {
2547
+ for (let i = 0; i < splitCount; i += 1) {
2548
+ const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
2549
+ singleLine.num = 1;
2550
+ delete singleLine.product_quantity;
2551
+ await this.appendProductLineToTempOrder(
2552
+ tempOrder,
2553
+ singleLine,
2554
+ (0, import_lodash_es.cloneDeep)(booking)
2555
+ );
2556
+ }
2557
+ continue;
2558
+ }
2559
+ }
2560
+ await this.appendProductLineToTempOrder(tempOrder, product, booking);
2561
+ }
2562
+ await this.finalizeProductOrderMutation(tempOrder, options);
1110
2563
  return tempOrder.products;
1111
2564
  }
1112
2565
  hasGoodPassDiscount(product) {
@@ -1127,15 +2580,55 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1127
2580
  (item) => (item == null ? void 0 : item.type) === "good_pass" || (item == null ? void 0 : item.tag) === "good_pass"
1128
2581
  );
1129
2582
  }
1130
- async updateProductInOrder(params) {
1131
- var _a, _b, _c, _d, _e;
2583
+ getBundleRuntimeIdentity(bundle) {
2584
+ if (!bundle || typeof bundle !== "object")
2585
+ return "";
2586
+ return [
2587
+ bundle.bundle_id ?? bundle.id ?? "",
2588
+ bundle.bundle_group_id ?? bundle.group_id ?? "",
2589
+ bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? "",
2590
+ bundle.bundle_variant_id ?? bundle.product_variant_id ?? 0
2591
+ ].join("|");
2592
+ }
2593
+ preservePersistedBundlePriceFields(previousBundles, nextBundles) {
2594
+ if (!Array.isArray(nextBundles))
2595
+ return nextBundles;
2596
+ if (!Array.isArray(previousBundles) || previousBundles.length === 0)
2597
+ return nextBundles;
2598
+ const previousByIdentity = /* @__PURE__ */ new Map();
2599
+ previousBundles.forEach((bundle) => {
2600
+ const identity = this.getBundleRuntimeIdentity(bundle);
2601
+ if (identity)
2602
+ previousByIdentity.set(identity, bundle);
2603
+ });
2604
+ return nextBundles.map((bundle, index) => {
2605
+ if (!bundle || typeof bundle !== "object")
2606
+ return bundle;
2607
+ const previous = previousByIdentity.get(this.getBundleRuntimeIdentity(bundle)) || previousBundles[index];
2608
+ if (!previous || typeof previous !== "object")
2609
+ return bundle;
2610
+ return {
2611
+ ...bundle,
2612
+ price: previous.price,
2613
+ custom_price: previous.custom_price,
2614
+ bundle_payment_price: previous.bundle_payment_price,
2615
+ bundle_selling_price: previous.bundle_selling_price,
2616
+ original_price: previous.original_price,
2617
+ product_price: previous.product_price
2618
+ };
2619
+ });
2620
+ }
2621
+ async updateOrderProduct(params) {
2622
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
1132
2623
  const {
1133
2624
  product_id,
1134
2625
  product_variant_id,
1135
2626
  updates,
1136
2627
  unique_identification_number,
1137
- product_option_item,
1138
- product_bundle
2628
+ identity_key,
2629
+ product_sku,
2630
+ product_bundle,
2631
+ booking
1139
2632
  } = params;
1140
2633
  const tempOrder = this.ensureTempOrder();
1141
2634
  const identityLookup = {
@@ -1144,12 +2637,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1144
2637
  };
1145
2638
  if (unique_identification_number !== void 0) {
1146
2639
  identityLookup.unique_identification_number = unique_identification_number;
2640
+ if (identity_key === void 0) {
2641
+ identityLookup.identity_key = unique_identification_number;
2642
+ }
1147
2643
  }
1148
- if (product_option_item !== void 0)
1149
- identityLookup.product_option_item = product_option_item;
2644
+ if (identity_key !== void 0) {
2645
+ identityLookup.identity_key = identity_key;
2646
+ }
2647
+ if (product_sku !== void 0)
2648
+ identityLookup.product_sku = product_sku;
1150
2649
  if (product_bundle !== void 0)
1151
2650
  identityLookup.product_bundle = product_bundle;
1152
- const productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, identityLookup);
2651
+ let productIndex = -1;
2652
+ if (unique_identification_number !== void 0) {
2653
+ const targetUid = String(unique_identification_number);
2654
+ productIndex = tempOrder.products.findIndex((item) => {
2655
+ var _a2;
2656
+ return String(
2657
+ ((_a2 = item.metadata) == null ? void 0 : _a2.unique_identification_number) || item.unique_identification_number || ""
2658
+ ) === targetUid;
2659
+ });
2660
+ }
2661
+ if (productIndex === -1) {
2662
+ productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, identityLookup);
2663
+ }
1153
2664
  if (productIndex === -1) {
1154
2665
  throw new Error("[Order] 目标商品不存在,无法更新");
1155
2666
  }
@@ -1163,12 +2674,49 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1163
2674
  ...targetProduct.metadata || {},
1164
2675
  ...(updates == null ? void 0 : updates.metadata) || {},
1165
2676
  unique_identification_number: ((_a = targetProduct.metadata) == null ? void 0 : _a.unique_identification_number) || unique_identification_number
2677
+ },
2678
+ product_sku: {
2679
+ ...targetProduct.product_sku || { option: [] },
2680
+ ...(updates == null ? void 0 : updates.product_sku) && typeof updates.product_sku === "object" ? updates.product_sku : {},
2681
+ option: Array.isArray((_b = updates == null ? void 0 : updates.product_sku) == null ? void 0 : _b.option) ? updates.product_sku.option : (0, import_utils.getProductSkuOptions)(targetProduct)
1166
2682
  }
1167
2683
  };
1168
2684
  nextProduct.num = (0, import_utils3.getSafeProductNum)(nextProduct.num);
1169
2685
  const callerUpdatesTopPrice = Object.prototype.hasOwnProperty.call(updates || {}, "selling_price") || Object.prototype.hasOwnProperty.call(updates || {}, "original_price");
1170
- const callerUpdatesMainMeta = ((_b = updates == null ? void 0 : updates.metadata) == null ? void 0 : _b.main_product_selling_price) !== void 0 || ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.main_product_original_price) !== void 0 || ((_d = updates == null ? void 0 : updates.metadata) == null ? void 0 : _d.source_product_price) !== void 0;
1171
- if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
2686
+ const callerUpdatesMainMeta = ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.main_product_selling_price) !== void 0 || ((_d = updates == null ? void 0 : updates.metadata) == null ? void 0 : _d.main_product_original_price) !== void 0 || ((_e = updates == null ? void 0 : updates.metadata) == null ? void 0 : _e.source_product_price) !== void 0;
2687
+ const isPersistedOrderLine = targetProduct.order_detail_id !== void 0 && targetProduct.order_detail_id !== null;
2688
+ const callerChangesDiscountList = Array.isArray(updates == null ? void 0 : updates.discount_list) && updates.discount_list.length > 0 && !isSameDiscountList(updates.discount_list, targetProduct.discount_list);
2689
+ const callerUpdatesManualPrice = ((_f = updates == null ? void 0 : updates.metadata) == null ? void 0 : _f.price_override) !== void 0 || ((_g = updates == null ? void 0 : updates.metadata) == null ? void 0 : _g.is_manual_discount) !== void 0 || ((_h = updates == null ? void 0 : updates.metadata) == null ? void 0 : _h.product_discount_reason) !== void 0 || callerChangesDiscountList;
2690
+ const callerAllowsBookingReprice = (() => {
2691
+ if (params.allow_booking_reprice !== true || !booking || !callerUpdatesTopPrice || !callerUpdatesMainMeta) {
2692
+ return false;
2693
+ }
2694
+ const hasChangedPrice = (nextValue, currentValue) => {
2695
+ if (nextValue === void 0 || nextValue === null || nextValue === "") {
2696
+ return false;
2697
+ }
2698
+ return !new import_decimal.default(Number(nextValue) || 0).equals(
2699
+ new import_decimal.default(Number(currentValue) || 0)
2700
+ );
2701
+ };
2702
+ return hasChangedPrice(updates.selling_price, targetProduct.selling_price) || hasChangedPrice(updates.original_price, targetProduct.original_price);
2703
+ })();
2704
+ if (isPersistedOrderLine && !callerUpdatesManualPrice && !callerAllowsBookingReprice) {
2705
+ nextProduct.selling_price = targetProduct.selling_price;
2706
+ nextProduct.original_price = targetProduct.original_price;
2707
+ nextProduct.payment_price = targetProduct.payment_price;
2708
+ nextProduct.metadata = {
2709
+ ...nextProduct.metadata || {},
2710
+ source_product_price: (_i = targetProduct.metadata) == null ? void 0 : _i.source_product_price,
2711
+ main_product_selling_price: (_j = targetProduct.metadata) == null ? void 0 : _j.main_product_selling_price,
2712
+ main_product_original_price: (_k = targetProduct.metadata) == null ? void 0 : _k.main_product_original_price,
2713
+ price_schema_version: ((_l = targetProduct.metadata) == null ? void 0 : _l.price_schema_version) ?? 2
2714
+ };
2715
+ nextProduct.product_bundle = this.preservePersistedBundlePriceFields(
2716
+ targetProduct.product_bundle,
2717
+ nextProduct.product_bundle
2718
+ );
2719
+ } else if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
1172
2720
  const existedMeta = nextProduct.metadata || {};
1173
2721
  nextProduct.metadata = { ...existedMeta };
1174
2722
  delete nextProduct.metadata.source_product_price;
@@ -1176,39 +2724,313 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1176
2724
  delete nextProduct.metadata.main_product_original_price;
1177
2725
  delete nextProduct.metadata.price_schema_version;
1178
2726
  }
1179
- tempOrder.products[productIndex] = (0, import_utils3.normalizeOrderProduct)(nextProduct);
2727
+ let normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
2728
+ nextProduct,
2729
+ (0, import_utils3.normalizeOrderProduct)(nextProduct)
2730
+ );
2731
+ normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
2732
+ normalizedProduct.discount_list
2733
+ );
2734
+ const preservedBookingUid = nextProduct.booking_uid || ((_m = nextProduct.metadata) == null ? void 0 : _m.booking_uid) || targetProduct.booking_uid || ((_n = targetProduct.metadata) == null ? void 0 : _n.booking_uid);
2735
+ if (!booking && preservedBookingUid) {
2736
+ normalizedProduct.booking_uid = preservedBookingUid;
2737
+ normalizedProduct.metadata = {
2738
+ ...normalizedProduct.metadata || {},
2739
+ booking_uid: preservedBookingUid
2740
+ };
2741
+ }
2742
+ if (booking) {
2743
+ const productUid = String(
2744
+ ((_o = normalizedProduct.metadata) == null ? void 0 : _o.unique_identification_number) || ((_p = targetProduct.metadata) == null ? void 0 : _p.unique_identification_number) || unique_identification_number || (0, import_utils.createUuidV4)()
2745
+ );
2746
+ normalizedProduct.metadata = {
2747
+ ...normalizedProduct.metadata || {},
2748
+ unique_identification_number: productUid
2749
+ };
2750
+ const linked = this.createLinkedProductAndBooking({
2751
+ product: {
2752
+ ...normalizedProduct,
2753
+ unique_identification_number: productUid
2754
+ },
2755
+ booking
2756
+ });
2757
+ this.removeLinkedBookingsForProduct(tempOrder, targetProduct);
2758
+ normalizedProduct = {
2759
+ ...normalizedProduct,
2760
+ booking_uid: linked.bookingUid,
2761
+ metadata: {
2762
+ ...normalizedProduct.metadata || {},
2763
+ booking_uid: linked.bookingUid,
2764
+ unique_identification_number: productUid
2765
+ }
2766
+ };
2767
+ tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
2768
+ }
2769
+ tempOrder.products[productIndex] = normalizedProduct;
2770
+ this.syncTempOrderHolderFromBookings(tempOrder);
1180
2771
  this.captureProductRuntime(
1181
2772
  tempOrder,
1182
2773
  updates,
1183
2774
  tempOrder.products[productIndex],
1184
- (_e = tempOrder.products[productIndex].metadata) == null ? void 0 : _e.unique_identification_number
2775
+ (_q = tempOrder.products[productIndex].metadata) == null ? void 0 : _q.unique_identification_number
1185
2776
  );
2777
+ await this.applyPromotion();
1186
2778
  this.applyDiscount();
2779
+ this.sanitizeTempOrderProducts(tempOrder);
1187
2780
  await this.recalculateSummary({ createIfMissing: true });
1188
2781
  this.persistTempOrder();
1189
2782
  return tempOrder.products;
1190
2783
  }
1191
- async removeProductFromOrder(identity) {
2784
+ async updateOrderProductQuantity(params) {
2785
+ var _a;
2786
+ const {
2787
+ product_id,
2788
+ product_variant_id,
2789
+ num,
2790
+ unique_identification_number,
2791
+ identity_key,
2792
+ product_sku,
2793
+ product_bundle
2794
+ } = params;
2795
+ const tempOrder = this.ensureTempOrder();
2796
+ const identityLookup = {
2797
+ product_id,
2798
+ product_variant_id
2799
+ };
2800
+ if (unique_identification_number !== void 0) {
2801
+ identityLookup.unique_identification_number = unique_identification_number;
2802
+ if (identity_key === void 0) {
2803
+ identityLookup.identity_key = unique_identification_number;
2804
+ }
2805
+ }
2806
+ if (identity_key !== void 0)
2807
+ identityLookup.identity_key = identity_key;
2808
+ if (product_sku !== void 0)
2809
+ identityLookup.product_sku = product_sku;
2810
+ if (product_bundle !== void 0)
2811
+ identityLookup.product_bundle = product_bundle;
2812
+ let productIndex = -1;
2813
+ if (unique_identification_number !== void 0) {
2814
+ const targetUid = String(unique_identification_number);
2815
+ productIndex = tempOrder.products.findIndex((item) => {
2816
+ var _a2;
2817
+ return String(
2818
+ ((_a2 = item.metadata) == null ? void 0 : _a2.unique_identification_number) || item.unique_identification_number || ""
2819
+ ) === targetUid;
2820
+ });
2821
+ }
2822
+ if (productIndex === -1) {
2823
+ productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, identityLookup);
2824
+ }
2825
+ if (productIndex === -1) {
2826
+ throw new Error("[Order] 目标商品不存在,无法更新数量");
2827
+ }
2828
+ const targetProduct = tempOrder.products[productIndex];
2829
+ const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
2830
+ ...targetProduct,
2831
+ num: (0, import_utils3.getSafeProductNum)(num),
2832
+ metadata: {
2833
+ ...targetProduct.metadata || {},
2834
+ unique_identification_number: ((_a = targetProduct.metadata) == null ? void 0 : _a.unique_identification_number) || unique_identification_number
2835
+ }
2836
+ });
2837
+ normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
2838
+ normalizedProduct.discount_list
2839
+ );
2840
+ tempOrder.products[productIndex] = normalizedProduct;
2841
+ await this.applyPromotion();
2842
+ this.applyDiscount();
2843
+ this.sanitizeTempOrderProducts(tempOrder);
2844
+ await this.recalculateSummary({ createIfMissing: true });
2845
+ this.persistTempOrder();
2846
+ return tempOrder.products;
2847
+ }
2848
+ updateOrderBooking(params) {
2849
+ const { unique_identification_number, updates } = params;
1192
2850
  const tempOrder = this.ensureTempOrder();
1193
- tempOrder.products = tempOrder.products.filter(
1194
- (item) => !(0, import_utils3.isIdentityMatch)(item, identity)
2851
+ const bookingUid = String(unique_identification_number || "");
2852
+ const bookingIndex = this.findBookingIndexByUniqueIdentificationNumber(
2853
+ tempOrder,
2854
+ bookingUid
1195
2855
  );
2856
+ if (!bookingUid || bookingIndex === -1) {
2857
+ throw new Error("[Order] 目标 booking 不存在,无法更新");
2858
+ }
2859
+ const targetBooking = tempOrder.bookings[bookingIndex] || {};
2860
+ const nextBooking = {
2861
+ ...targetBooking,
2862
+ ...updates,
2863
+ metadata: {
2864
+ ...targetBooking.metadata || {},
2865
+ ...updates.metadata || {},
2866
+ unique_identification_number: bookingUid
2867
+ }
2868
+ };
2869
+ this.syncBookingMetadataHolder(nextBooking, nextBooking.metadata);
2870
+ nextBooking.is_all = (0, import_utils.normalizeBookingIsAll)(nextBooking);
2871
+ nextBooking.sub_type = (0, import_utils.normalizeBookingSubType)(nextBooking);
2872
+ tempOrder.bookings[bookingIndex] = nextBooking;
2873
+ this.syncTempOrderHolderFromBookings(tempOrder);
2874
+ this.persistTempOrder();
2875
+ return tempOrder.bookings;
2876
+ }
2877
+ /**
2878
+ * 商品行写路径收尾:促销 → 折扣 → 清洗 → summary → 持久化。
2879
+ * 批量删除等多行变更场景只应调用一次,避免 N 次 applyPromotion。
2880
+ *
2881
+ * @example
2882
+ * await this.finalizeAfterProductsMutation(tempOrder);
2883
+ */
2884
+ async finalizeAfterProductsMutation(tempOrder) {
2885
+ this.syncTempOrderHolderFromBookings(tempOrder);
2886
+ await this.applyPromotion();
1196
2887
  this.applyDiscount();
2888
+ this.sanitizeTempOrderProducts(tempOrder);
1197
2889
  await this.recalculateSummary({ createIfMissing: true });
1198
2890
  this.persistTempOrder();
2891
+ }
2892
+ /**
2893
+ * 批量按 identity 删除购物车行,末尾仅一次促销重算。
2894
+ *
2895
+ * @example
2896
+ * await order.removeProductsFromOrder([identityA, identityB]);
2897
+ */
2898
+ async removeProductsFromOrder(identities) {
2899
+ var _a, _b, _c, _d;
2900
+ const tempOrder = this.ensureTempOrder();
2901
+ if (!identities.length) {
2902
+ return tempOrder.products;
2903
+ }
2904
+ const productsBeforeRemove = tempOrder.products || [];
2905
+ const bookingsBeforeRemove = tempOrder.bookings || [];
2906
+ const matchedProducts = productsBeforeRemove.filter((item) => {
2907
+ return identities.some((identity) => (0, import_utils3.isIdentityMatch)(item, identity));
2908
+ });
2909
+ const removedProducts = [];
2910
+ tempOrder.products = tempOrder.products.filter((item) => {
2911
+ const shouldRemove = identities.some((identity) => (0, import_utils3.isIdentityMatch)(item, identity));
2912
+ if (shouldRemove)
2913
+ removedProducts.push(item);
2914
+ return !shouldRemove;
2915
+ });
2916
+ for (const product of removedProducts) {
2917
+ this.removeLinkedBookingsForProduct(tempOrder, product);
2918
+ }
2919
+ const linkedBookingUidsToRemove = /* @__PURE__ */ new Set();
2920
+ for (const product of matchedProducts) {
2921
+ const productUid = ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.unique_identification_number) || (product == null ? void 0 : product.unique_identification_number);
2922
+ const productBookingUid = (product == null ? void 0 : product.booking_uid) || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.booking_uid);
2923
+ const isAddTimeProduct = ((_c = product == null ? void 0 : product.metadata) == null ? void 0 : _c.product_add_schedule_time) !== void 0 && ((_d = product == null ? void 0 : product.metadata) == null ? void 0 : _d.product_add_schedule_time) !== null;
2924
+ if (isAddTimeProduct)
2925
+ continue;
2926
+ if (productBookingUid !== void 0 && productBookingUid !== null && productBookingUid !== "") {
2927
+ linkedBookingUidsToRemove.add(String(productBookingUid));
2928
+ }
2929
+ if (productUid !== void 0 && productUid !== null && productUid !== "") {
2930
+ bookingsBeforeRemove.forEach((booking) => {
2931
+ const bookingUid = this.getBookingUniqueIdentificationNumber(booking);
2932
+ if (bookingUid && String((booking == null ? void 0 : booking.product_uid) || "") === String(productUid)) {
2933
+ linkedBookingUidsToRemove.add(bookingUid);
2934
+ }
2935
+ });
2936
+ }
2937
+ }
2938
+ if (linkedBookingUidsToRemove.size > 0) {
2939
+ tempOrder.products = (tempOrder.products || []).filter((line) => {
2940
+ var _a2, _b2, _c2;
2941
+ const lineBookingUid = ((_a2 = line == null ? void 0 : line.metadata) == null ? void 0 : _a2.booking_uid) || (line == null ? void 0 : line.booking_uid);
2942
+ const isAddTimeProduct = ((_b2 = line == null ? void 0 : line.metadata) == null ? void 0 : _b2.product_add_schedule_time) !== void 0 && ((_c2 = line == null ? void 0 : line.metadata) == null ? void 0 : _c2.product_add_schedule_time) !== null;
2943
+ return !(isAddTimeProduct && lineBookingUid !== void 0 && lineBookingUid !== null && linkedBookingUidsToRemove.has(String(lineBookingUid)));
2944
+ });
2945
+ }
2946
+ await this.finalizeAfterProductsMutation(tempOrder);
1199
2947
  return tempOrder.products;
1200
2948
  }
2949
+ async removeProductFromOrder(identity) {
2950
+ return this.removeProductsFromOrder([identity]);
2951
+ }
2952
+ /**
2953
+ * 仅清空购物车行(products / bookings),不重置整单。
2954
+ * 用于「仅清空商品」;客户、备注、支付等协议字段保持不变。
2955
+ */
2956
+ async clearOrderCartLines() {
2957
+ const tempOrder = this.ensureTempOrder();
2958
+ tempOrder.products = [];
2959
+ tempOrder.bookings = [];
2960
+ this.syncTempOrderHolderFromBookings(tempOrder);
2961
+ if (tempOrder._extend && typeof tempOrder._extend === "object") {
2962
+ tempOrder._extend = {
2963
+ ...tempOrder._extend,
2964
+ productsByUid: {}
2965
+ };
2966
+ }
2967
+ await this.applyPromotion();
2968
+ this.applyDiscount();
2969
+ this.sanitizeTempOrderProducts(tempOrder);
2970
+ await this.recalculateSummary({ createIfMissing: true });
2971
+ this.persistTempOrder();
2972
+ return tempOrder;
2973
+ }
1201
2974
  // ─── TempOrder: 提交 ───
2975
+ buildCurrentSubmitPayloadForLocalPrint(params) {
2976
+ var _a, _b, _c;
2977
+ const tempOrder = this.ensureTempOrder();
2978
+ this.persistTempOrder();
2979
+ const payload = (0, import_utils.buildSubmitPayload)({
2980
+ tempOrder,
2981
+ cacheId: (params == null ? void 0 : params.cacheId) ?? this.cacheId,
2982
+ platform: (params == null ? void 0 : params.platform) || ((_a = this.otherParams) == null ? void 0 : _a.platform),
2983
+ businessCode: (params == null ? void 0 : params.businessCode) ?? ((_b = this.otherParams) == null ? void 0 : _b.businessCode) ?? ((_c = this.otherParams) == null ? void 0 : _c.business_code),
2984
+ channel: params == null ? void 0 : params.channel,
2985
+ type: params == null ? void 0 : params.type,
2986
+ summary: this.store.summary || (0, import_utils.createEmptySummary)(),
2987
+ enhance: (nextPayload) => ({
2988
+ ...nextPayload,
2989
+ order_number: tempOrder.order_number ?? nextPayload.order_number ?? null,
2990
+ shop_order_number: tempOrder.shop_order_number ?? nextPayload.shop_order_number ?? null,
2991
+ shop_full_order_number: tempOrder.shop_full_order_number ?? nextPayload.shop_full_order_number ?? null,
2992
+ small_ticket_data_flag: 1
2993
+ })
2994
+ });
2995
+ payload.created_at = void 0;
2996
+ return payload;
2997
+ }
2998
+ async applyLocalPrintOrderNumbers(order) {
2999
+ const tempOrder = this.ensureTempOrder();
3000
+ if (!order || typeof order !== "object")
3001
+ return tempOrder;
3002
+ const shopOrderNumber = order.shop_order_number;
3003
+ const shopFullOrderNumber = order.shop_full_order_number;
3004
+ if (shopOrderNumber !== void 0 && shopOrderNumber !== null && shopOrderNumber !== "") {
3005
+ tempOrder.shop_order_number = String(shopOrderNumber);
3006
+ }
3007
+ if (shopFullOrderNumber !== void 0 && shopFullOrderNumber !== null && shopFullOrderNumber !== "") {
3008
+ tempOrder.shop_full_order_number = String(shopFullOrderNumber);
3009
+ }
3010
+ this.persistTempOrder();
3011
+ await this.saveDraft();
3012
+ return tempOrder;
3013
+ }
1202
3014
  /**
1203
3015
  * 提交当前 Sales tempOrder。
1204
3016
  *
1205
3017
  * smallTicketDataFlag 用于 B 端 checkout 小票数据返回。PaymentModal 在支付提交时
1206
- * 应传 1,确保 /order/sales/checkout 返回打印所需数据。
3018
+ * 应传 1,确保 /shop/order/sales/checkout 返回打印所需数据。
1207
3019
  */
1208
3020
  async submitTempOrder(params) {
1209
- var _a, _b, _c;
3021
+ return this.runSubmitTempOrder(params);
3022
+ }
3023
+ async submitTempOrderAsync(params) {
3024
+ return this.runSubmitTempOrder({
3025
+ ...params,
3026
+ syncMode: true
3027
+ });
3028
+ }
3029
+ async runSubmitTempOrder(params) {
3030
+ var _a, _b, _c, _d, _e;
1210
3031
  const tempOrder = this.ensureTempOrder();
1211
3032
  this.persistTempOrder();
3033
+ const latestSummary = await this.recalculateSummary({ createIfMissing: true }) || this.store.summary || (0, import_utils.createEmptySummary)();
1212
3034
  const effectiveCacheId = (params == null ? void 0 : params.cacheId) ?? this.cacheId;
1213
3035
  const hasPaymentOverride = (params == null ? void 0 : params.payments) !== void 0;
1214
3036
  const hasPaymentStatusOverride = (params == null ? void 0 : params.paymentStatus) !== void 0;
@@ -1224,26 +3046,37 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1224
3046
  ...hasPaymentStatusOverride ? { payment_status: params == null ? void 0 : params.paymentStatus } : {},
1225
3047
  ...hasSmallTicketDataFlagOverride ? { small_ticket_data_flag: params == null ? void 0 : params.smallTicketDataFlag } : {}
1226
3048
  };
1227
- return (params == null ? void 0 : params.enhancePayload) ? params.enhancePayload(nextPayload, ctx) : nextPayload;
3049
+ const enhancedPayload = (params == null ? void 0 : params.enhancePayload) ? params.enhancePayload(nextPayload, ctx) : nextPayload;
3050
+ return enhancedPayload;
1228
3051
  } : void 0;
1229
3052
  const payload = (0, import_utils.buildSubmitPayload)({
1230
3053
  tempOrder,
1231
3054
  cacheId: effectiveCacheId,
1232
3055
  platform: (params == null ? void 0 : params.platform) || ((_a = this.otherParams) == null ? void 0 : _a.platform),
1233
- businessCode: params == null ? void 0 : params.businessCode,
3056
+ businessCode: (params == null ? void 0 : params.businessCode) ?? ((_b = this.otherParams) == null ? void 0 : _b.businessCode) ?? ((_c = this.otherParams) == null ? void 0 : _c.business_code),
1234
3057
  channel: params == null ? void 0 : params.channel,
1235
3058
  type: params == null ? void 0 : params.type,
3059
+ summary: latestSummary,
3060
+ request_unique_idempotency_token: params == null ? void 0 : params.request_unique_idempotency_token,
1236
3061
  enhance: enhancePayload
1237
3062
  });
3063
+ if (params == null ? void 0 : params.syncMode) {
3064
+ payload.sync_mode = true;
3065
+ }
3066
+ if (!payload.created_at) {
3067
+ payload.created_at = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
3068
+ }
1238
3069
  await this.saveDraft();
1239
3070
  let result;
1240
3071
  try {
1241
3072
  this.logInfo("submitTempOrder calling sales checkout", {
1242
3073
  orderId: payload.order_id,
1243
3074
  externalSaleNumber: payload.external_sale_number,
3075
+ requestUniqueIdempotencyToken: payload.request_unique_idempotency_token,
1244
3076
  paymentStatus: payload.payment_status,
1245
- paymentsCount: ((_b = payload.payments) == null ? void 0 : _b.length) || 0,
1246
- smallTicketDataFlag: payload.small_ticket_data_flag
3077
+ paymentsCount: ((_d = payload.payments) == null ? void 0 : _d.length) || 0,
3078
+ smallTicketDataFlag: payload.small_ticket_data_flag,
3079
+ syncMode: payload.sync_mode
1247
3080
  });
1248
3081
  result = await this.submitSalesOrder({
1249
3082
  query: payload
@@ -1261,7 +3094,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1261
3094
  orderId: payload.order_id,
1262
3095
  externalSaleNumber: payload.external_sale_number,
1263
3096
  paymentStatus: payload.payment_status,
1264
- paymentsCount: ((_c = payload.payments) == null ? void 0 : _c.length) || 0
3097
+ paymentsCount: ((_e = payload.payments) == null ? void 0 : _e.length) || 0
1265
3098
  });
1266
3099
  throw error;
1267
3100
  }
@@ -1271,6 +3104,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1271
3104
  return result;
1272
3105
  }
1273
3106
  const submittedOrderId = this.extractOrderIdFromSubmitResult(result);
3107
+ this.logInfo("runSubmitTempOrder: 提交成功", {
3108
+ submittedOrderId,
3109
+ result,
3110
+ tempOrder
3111
+ });
1274
3112
  if (submittedOrderId !== null && submittedOrderId !== void 0) {
1275
3113
  tempOrder.order_id = submittedOrderId;
1276
3114
  const resultRecord = result;
@@ -1278,23 +3116,43 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1278
3116
  submittedOrderId,
1279
3117
  (resultRecord == null ? void 0 : resultRecord.data) || resultRecord || {}
1280
3118
  );
3119
+ } else if (this.isLocalPendingSubmitResult(result)) {
3120
+ this.store.syncState = "local";
3121
+ } else {
3122
+ this.store.syncState = "submitted";
1281
3123
  }
1282
3124
  return result;
1283
3125
  }
1284
3126
  async markLocalOrderSynced(orderId, remoteOrder) {
1285
3127
  const tempOrder = this.ensureTempOrder();
1286
3128
  tempOrder.order_id = orderId;
3129
+ this.applyRemoteOrderNumbersToTempOrder(tempOrder, remoteOrder);
1287
3130
  this.store.lastOrderInfo = remoteOrder;
1288
3131
  this.store.syncState = "submitted";
1289
3132
  this.persistTempOrder();
1290
3133
  await this.saveDraft();
1291
3134
  }
3135
+ applyRemoteOrderNumbersToTempOrder(tempOrder, remoteOrder) {
3136
+ const applyOrderNumber = (key) => {
3137
+ const value = remoteOrder == null ? void 0 : remoteOrder[key];
3138
+ if (value !== void 0 && value !== null && value !== "") {
3139
+ tempOrder[key] = String(value);
3140
+ }
3141
+ };
3142
+ applyOrderNumber("order_number");
3143
+ applyOrderNumber("shop_order_number");
3144
+ applyOrderNumber("shop_full_order_number");
3145
+ }
1292
3146
  isSubmitResponseRejected(response) {
1293
3147
  const isErrorCode = (response == null ? void 0 : response.code) !== void 0 && response.code !== 200 && response.code !== "200";
1294
3148
  const isErrorStatus = (response == null ? void 0 : response.status) === false || typeof (response == null ? void 0 : response.status) === "number" && response.status >= 400;
1295
3149
  const isErrorSuccess = (response == null ? void 0 : response.success) === false;
1296
3150
  return isErrorCode || isErrorStatus || isErrorSuccess;
1297
3151
  }
3152
+ isLocalPendingSubmitResult(response) {
3153
+ const data = (response == null ? void 0 : response.data) && typeof response.data === "object" ? response.data : response;
3154
+ return Number(data == null ? void 0 : data.need_sync) === 1;
3155
+ }
1298
3156
  isSubmitErrorResponse(response) {
1299
3157
  if (!response || typeof response !== "object")
1300
3158
  return false;
@@ -1322,26 +3180,51 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1322
3180
  }
1323
3181
  });
1324
3182
  }
3183
+ generateIdempotencyToken() {
3184
+ const tempOrder = this.ensureTempOrder();
3185
+ const token = this.buildPaymentSyncIdempotencyToken(
3186
+ tempOrder,
3187
+ tempOrder.payments
3188
+ );
3189
+ return `${token}_${Date.now()}`;
3190
+ }
1325
3191
  async syncPaymentsToOrder(params) {
1326
3192
  const tempOrder = this.ensureTempOrder();
1327
3193
  const mappedPayments = (0, import_utils.mapPaymentItemsToOrderPayments)(
1328
3194
  params.payments || []
1329
3195
  );
3196
+ const paymentTotal = this.calculatePaymentTotal(mappedPayments);
3197
+ const targetAmount = this.getPaymentTargetAmount();
3198
+ const isFullyPaid = targetAmount.lte(0) ? true : paymentTotal.gte(targetAmount);
3199
+ const paymentStatus = isFullyPaid ? params.paymentStatus || "paid" : "partially_paid";
1330
3200
  tempOrder.payments = mappedPayments;
1331
- if (params.paymentStatus)
1332
- tempOrder.payment_status = params.paymentStatus;
3201
+ tempOrder.payment_status = paymentStatus;
1333
3202
  this.persistTempOrder();
1334
3203
  await this.saveDraft();
1335
- const paymentTotal = this.calculatePaymentTotal(mappedPayments);
1336
- const targetAmount = this.getPaymentTargetAmount();
1337
- const isFullyPaid = targetAmount.lte(0) ? false : paymentTotal.gte(targetAmount);
1338
- if (!isFullyPaid || !params.submitWhenPaid) {
3204
+ if (!params.submitWhenPaid) {
1339
3205
  return { isFullyPaid };
1340
3206
  }
3207
+ if (this.store.syncState === "submitting") {
3208
+ return { isFullyPaid };
3209
+ }
3210
+ this.store.syncState = "submitting";
3211
+ const paymentSyncIdempotencyToken = this.buildPaymentSyncIdempotencyToken(
3212
+ tempOrder,
3213
+ mappedPayments
3214
+ );
1341
3215
  const submitResult = await this.submitTempOrder({
1342
3216
  payments: mappedPayments,
1343
- paymentStatus: params.paymentStatus || "paid",
1344
- smallTicketDataFlag: params.smallTicketDataFlag
3217
+ paymentStatus,
3218
+ smallTicketDataFlag: params.smallTicketDataFlag,
3219
+ businessCode: params.businessCode,
3220
+ channel: params.channel,
3221
+ enhancePayload: (payload) => {
3222
+ const nextPayload = {
3223
+ ...payload,
3224
+ request_unique_idempotency_token: paymentSyncIdempotencyToken
3225
+ };
3226
+ return nextPayload;
3227
+ }
1345
3228
  });
1346
3229
  return { isFullyPaid, submitResult };
1347
3230
  }
@@ -1477,7 +3360,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1477
3360
  * Checkout 专用:创建订单到后端
1478
3361
  *
1479
3362
  * 专门为 Checkout 模块设计的订单创建方法,
1480
- * 直接调用 /order/checkout 接口创建订单
3363
+ * 通过 OS Server 调用 checkout 接口创建订单
1481
3364
  * 接收已经处理好的订单数据,无需再处理购物车
1482
3365
  *
1483
3366
  * @param params Checkout 订单参数(已处理的订单数据)
@@ -1546,7 +3429,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1546
3429
  orderData.schedule_date = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
1547
3430
  }
1548
3431
  console.log("[Order] 调用后端接口创建订单:", {
1549
- url: "/order/checkout",
3432
+ url: "/shop/order/checkout",
1550
3433
  orderType: orderData.type,
1551
3434
  platform: orderData.platform,
1552
3435
  isDeposit: orderData.is_deposit,
@@ -1557,7 +3440,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1557
3440
  paymentsMethods: ((_m = orderData.payments) == null ? void 0 : _m.map((p) => p.code)) || []
1558
3441
  });
1559
3442
  this.logInfo("Calling backend checkout API", {
1560
- url: "/order/checkout",
3443
+ url: "/shop/order/checkout",
1561
3444
  orderType: orderData.type,
1562
3445
  platform: orderData.platform,
1563
3446
  isDeposit: orderData.is_deposit,
@@ -1579,7 +3462,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1579
3462
  hasOrderId: !!orderData.order_id,
1580
3463
  smallTicketDataFlag: orderData.small_ticket_data_flag
1581
3464
  });
1582
- const response = await this.request.post("/order/checkout", orderData);
3465
+ const response = await this.request.post("/order/checkout", orderData, {
3466
+ osServer: true,
3467
+ customToast: () => {
3468
+ }
3469
+ });
1583
3470
  this.logInfo("Order API called successfully", {
1584
3471
  response
1585
3472
  });
@@ -1599,7 +3486,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1599
3486
  async submitSalesOrder(params) {
1600
3487
  const { url, query } = params;
1601
3488
  const fetchUrl = url || "/order/sales/checkout";
1602
- return this.request.post(fetchUrl, query, { customToast: () => {
3489
+ return this.request.post(fetchUrl, query, { osServer: true, customToast: () => {
1603
3490
  } });
1604
3491
  }
1605
3492
  /**
@@ -1623,13 +3510,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1623
3510
  emails: params.emails
1624
3511
  });
1625
3512
  }
1626
- // TODO 获取详情的接口
1627
- async getOrderInfoByRemote(order_id) {
1628
- const res = await this.request.get(`/order/sales/${order_id}`, {
1629
- with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"]
1630
- }, {
1631
- osServer: true
1632
- });
3513
+ async getSalesOrderByLookup(params) {
3514
+ const lookup = params.lookup === void 0 || params.lookup === null ? "" : String(params.lookup).trim();
3515
+ if (!lookup) {
3516
+ throw new Error("加载销售详情需要 lookup");
3517
+ }
3518
+ if (lookup.startsWith("LOCAL_")) {
3519
+ params.forceRemote = false;
3520
+ }
3521
+ const res = await this.request.get(`/order/sales/${encodeURIComponent(lookup)}`, {
3522
+ with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"],
3523
+ ...params.forceRemote ? { forceRemote: true } : {}
3524
+ }, { osServer: true });
1633
3525
  if (res.code === 200) {
1634
3526
  this.store.lastOrderInfo = res.data;
1635
3527
  }
@@ -1642,58 +3534,64 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1642
3534
  * 例如数组字段、商品行唯一值、价格 metadata、summary 派生状态和 _extend。
1643
3535
  */
1644
3536
  async hydrateTempOrderFromRecord(record, options) {
3537
+ var _a, _b, _c;
1645
3538
  const raw = record && typeof record === "object" && record.data && record.order_id == null ? record.data : record || {};
1646
- const defaults = this.createDefaultTempOrderInstance();
1647
- const nextTempOrder = {
1648
- ...defaults
3539
+ const nextTempOrder = this.normalizeTempOrderForRuntime(raw);
3540
+ const rawSummary = raw.summary && typeof raw.summary === "object" ? raw.summary : {};
3541
+ const summarySurcharges = Array.isArray(rawSummary.surcharges) ? rawSummary.surcharges.map((s) => ({ ...s || {} })) : (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []);
3542
+ this.store.tempOrder = nextTempOrder;
3543
+ this.store.summary = {
3544
+ ...(0, import_utils.createEmptySummary)(),
3545
+ ...rawSummary,
3546
+ surcharges: summarySurcharges
1649
3547
  };
1650
- const TEMP_ORDER_KEYS = [
1651
- "order_id",
1652
- "external_sale_number",
1653
- "order_number",
1654
- "shop_order_number",
1655
- "shop_full_order_number",
1656
- "type",
1657
- "business_code",
1658
- "platform",
1659
- "sales_channel",
1660
- "order_sales_channel",
1661
- "vouchers",
1662
- "status",
1663
- "payment_status",
1664
- "shipping_status",
1665
- "customer_id",
1666
- "customer_name",
1667
- "country_calling_code",
1668
- "phone",
1669
- "email",
1670
- "customer",
1671
- "is_price_include_tax",
1672
- "tax_title",
1673
- "tax_country_code",
1674
- "currency_code",
1675
- "currency_symbol",
1676
- "currency_format",
1677
- "is_deposit",
1678
- "deposit_amount",
1679
- "shop_discount",
1680
- "surcharge_fee",
1681
- "note",
1682
- "buzzer",
1683
- "delivery_type",
1684
- "table_number",
1685
- "schedule_date",
1686
- "created_at",
1687
- "request_unique_idempotency_token"
1688
- ];
1689
- TEMP_ORDER_KEYS.forEach((key) => {
1690
- if (raw[key] !== void 0) {
1691
- nextTempOrder[key] = raw[key];
3548
+ nextTempOrder._extend = {
3549
+ ...nextTempOrder._extend || {},
3550
+ originalSalesSnapshot: {
3551
+ summary: (0, import_lodash_es.cloneDeep)(this.store.summary),
3552
+ products: (0, import_lodash_es.cloneDeep)(nextTempOrder.products || []),
3553
+ payments: (0, import_lodash_es.cloneDeep)(nextTempOrder.payments || []),
3554
+ surcharges: (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []),
3555
+ productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
1692
3556
  }
1693
- });
3557
+ };
3558
+ this.store.lastOrderInfo = raw.lastOrderInfo || raw;
3559
+ const hydratedEditDiscounts = this.collectHydratedEditDiscounts(nextTempOrder.products);
3560
+ const currentDiscounts = typeof ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList) === "function" ? this.store.discount.getDiscountList() || [] : [];
3561
+ const shouldSkipEmptyDiscountSync = hydratedEditDiscounts.length === 0 && currentDiscounts.length === 0;
3562
+ if (!shouldSkipEmptyDiscountSync) {
3563
+ await ((_b = this.store.discount) == null ? void 0 : _b.setOriginalDiscountList(hydratedEditDiscounts));
3564
+ await ((_c = this.store.discount) == null ? void 0 : _c.setDiscountList(hydratedEditDiscounts));
3565
+ }
3566
+ if (options == null ? void 0 : options.recalcOnHydrate) {
3567
+ await this.recalculateSummary({ createIfMissing: false });
3568
+ }
3569
+ this.persistTempOrder();
3570
+ return nextTempOrder;
3571
+ }
3572
+ normalizeTempOrderForRuntime(raw, options) {
3573
+ var _a, _b;
3574
+ const nextTempOrder = {
3575
+ ...this.createDefaultTempOrderInstance(),
3576
+ ...raw || {}
3577
+ };
3578
+ delete nextTempOrder.summary;
3579
+ delete nextTempOrder.lastOrderInfo;
3580
+ delete nextTempOrder.discount_list;
3581
+ delete nextTempOrder.shop_id;
3582
+ delete nextTempOrder.create_date;
3583
+ delete nextTempOrder.total_amount;
3584
+ delete nextTempOrder.expect_amount;
3585
+ delete nextTempOrder.paid_amount;
3586
+ delete nextTempOrder.shop_note;
3587
+ delete nextTempOrder.start_time;
3588
+ delete nextTempOrder.tax_fee;
3589
+ delete nextTempOrder.total_refund_amount;
3590
+ delete nextTempOrder.holder_id;
1694
3591
  nextTempOrder.metadata = raw.metadata && typeof raw.metadata === "object" ? { ...raw.metadata } : {};
1695
3592
  nextTempOrder.holder = raw.holder && typeof raw.holder === "object" ? { ...raw.holder } : null;
1696
- nextTempOrder.products = Array.isArray(raw.products) ? raw.products.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
3593
+ const rawProducts = Array.isArray(raw.products) ? raw.products : [];
3594
+ nextTempOrder.products = rawProducts.length > 0 ? rawProducts.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
1697
3595
  nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) => ({
1698
3596
  ...b || {},
1699
3597
  is_all: (0, import_utils.normalizeBookingIsAll)(b || {}),
@@ -1701,7 +3599,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1701
3599
  })) : [];
1702
3600
  nextTempOrder.payments = Array.isArray(raw.payments) ? raw.payments.map((p) => ({ ...p || {} })) : [];
1703
3601
  nextTempOrder.surcharges = Array.isArray(raw.surcharges) ? raw.surcharges.map((s) => ({ ...s || {} })) : [];
1704
- nextTempOrder.discount_list = Array.isArray(raw.discount_list) ? raw.discount_list.map((d) => ({ ...d || {} })) : [];
1705
3602
  nextTempOrder.relation_forms = Array.isArray(raw.relation_forms) ? raw.relation_forms.map((f) => ({ ...f || {} })) : [];
1706
3603
  nextTempOrder.contacts = Array.isArray(raw.contacts) ? raw.contacts.map((c) => ({ ...c || {} })) : [];
1707
3604
  nextTempOrder.contacts_info = raw.contacts_info && typeof raw.contacts_info === "object" && !Array.isArray(raw.contacts_info) ? { ...raw.contacts_info } : null;
@@ -1709,35 +3606,120 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1709
3606
  ...raw._extend,
1710
3607
  productsByUid: raw._extend.productsByUid || {}
1711
3608
  } : { productsByUid: {} };
1712
- this.ensureExternalSaleNumber(nextTempOrder);
1713
- this.store.tempOrder = nextTempOrder;
1714
- this.store.summary = raw.summary && typeof raw.summary === "object" ? { ...(0, import_utils.createEmptySummary)(), ...raw.summary } : (0, import_utils.createEmptySummary)();
1715
- this.store.lastOrderInfo = raw.lastOrderInfo || raw;
1716
- if (options == null ? void 0 : options.recalcOnHydrate) {
1717
- await this.recalculateSummary({ createIfMissing: false });
3609
+ const tempOrderExtend = nextTempOrder._extend;
3610
+ const productsByUid = tempOrderExtend.productsByUid || {};
3611
+ for (const [index, product] of nextTempOrder.products.entries()) {
3612
+ const uid = (_a = product.metadata) == null ? void 0 : _a.unique_identification_number;
3613
+ if (!uid)
3614
+ continue;
3615
+ const existed = productsByUid[uid] && typeof productsByUid[uid] === "object" ? productsByUid[uid] : {};
3616
+ const rawProduct = rawProducts[index] && typeof rawProducts[index] === "object" ? rawProducts[index] : product;
3617
+ const origin = existed.origin ?? rawProduct._origin ?? ((_b = rawProduct.metadata) == null ? void 0 : _b.origin) ?? rawProduct;
3618
+ const originSnapshot = (0, import_lodash_es.cloneDeep)(origin);
3619
+ const productOptionString = this.buildHydratedProductOptionString(rawProduct) || this.buildHydratedProductOptionString(product);
3620
+ if (productOptionString && originSnapshot && typeof originSnapshot === "object") {
3621
+ if (originSnapshot.product_option_string === void 0) {
3622
+ originSnapshot.product_option_string = productOptionString;
3623
+ }
3624
+ if (originSnapshot.product_options_stirng === void 0) {
3625
+ originSnapshot.product_options_stirng = productOptionString;
3626
+ }
3627
+ }
3628
+ productsByUid[uid] = {
3629
+ ...existed,
3630
+ origin: originSnapshot
3631
+ };
1718
3632
  }
1719
- this.persistTempOrder();
3633
+ tempOrderExtend.productsByUid = productsByUid;
3634
+ if ((options == null ? void 0 : options.ensureIdentity) !== false) {
3635
+ this.ensureExternalSaleNumber(nextTempOrder);
3636
+ }
3637
+ nextTempOrder.vouchers = raw.vouchers || [];
1720
3638
  return nextTempOrder;
1721
3639
  }
3640
+ pickHydratedDisplayText(value) {
3641
+ if (value === void 0 || value === null)
3642
+ return "";
3643
+ if (typeof value === "string")
3644
+ return value;
3645
+ if (typeof value !== "object")
3646
+ return String(value);
3647
+ return value.auto || value.original || value.en || value["zh-CN"] || value["zh-HK"] || "";
3648
+ }
3649
+ formatHydratedNamePair(group, item) {
3650
+ const groupText = this.pickHydratedDisplayText(group);
3651
+ const itemText = this.pickHydratedDisplayText(item);
3652
+ if (groupText && itemText)
3653
+ return `${groupText}:${itemText}`;
3654
+ return groupText || itemText;
3655
+ }
3656
+ buildHydratedProductOptionString(product) {
3657
+ const segments = [];
3658
+ const sku = (product == null ? void 0 : product.product_sku) || {};
3659
+ if (Array.isArray(sku.variant)) {
3660
+ for (const variant of sku.variant) {
3661
+ const segment = this.formatHydratedNamePair(variant == null ? void 0 : variant.group, variant == null ? void 0 : variant.item);
3662
+ if (segment)
3663
+ segments.push(segment);
3664
+ }
3665
+ }
3666
+ return segments.join(", ");
3667
+ }
3668
+ normalizeHydratedProductOptionItem(optionItem) {
3669
+ const rawNum = (optionItem == null ? void 0 : optionItem.num) ?? (optionItem == null ? void 0 : optionItem.quantity) ?? 1;
3670
+ const parsedNum = Number(rawNum);
3671
+ const rawPrice = (optionItem == null ? void 0 : optionItem.add_price) ?? (optionItem == null ? void 0 : optionItem.price) ?? 0;
3672
+ const parsedPrice = Number(rawPrice);
3673
+ const normalized = {
3674
+ ...optionItem,
3675
+ option_group_item_id: optionItem == null ? void 0 : optionItem.option_group_item_id,
3676
+ option_group_id: optionItem == null ? void 0 : optionItem.option_group_id,
3677
+ num: Number.isFinite(parsedNum) && parsedNum > 0 ? parsedNum : 1,
3678
+ add_price: Number.isFinite(parsedPrice) ? parsedPrice : 0
3679
+ };
3680
+ delete normalized.price;
3681
+ if ((optionItem == null ? void 0 : optionItem.name) !== void 0)
3682
+ normalized.name = optionItem.name;
3683
+ if ((optionItem == null ? void 0 : optionItem.group_name) !== void 0)
3684
+ normalized.group_name = optionItem.group_name;
3685
+ if ((optionItem == null ? void 0 : optionItem.id) !== void 0)
3686
+ normalized.id = optionItem.id;
3687
+ return normalized;
3688
+ }
1722
3689
  normalizeHydratedOrderProduct(product) {
1723
3690
  const row = { ...product || {} };
1724
3691
  if (row.num === void 0 && row.product_quantity !== void 0) {
1725
3692
  row.num = row.product_quantity;
1726
3693
  }
1727
- if (!Array.isArray(row.product_option_item))
1728
- row.product_option_item = [];
3694
+ const productSku = (0, import_utils.ensureProductSku)(row);
3695
+ row.product_sku = {
3696
+ ...productSku,
3697
+ option: (0, import_utils.normalizeProductSkuOptions)(
3698
+ productSku.option.map(
3699
+ (optionItem) => this.normalizeHydratedProductOptionItem(optionItem || {})
3700
+ )
3701
+ )
3702
+ };
3703
+ delete row[`product_${"option"}_item`];
1729
3704
  if (!Array.isArray(row.product_bundle))
1730
3705
  row.product_bundle = [];
1731
3706
  if (!row.metadata || typeof row.metadata !== "object")
1732
3707
  row.metadata = {};
3708
+ if (row.booking_uid && !row.metadata.booking_uid) {
3709
+ row.metadata.booking_uid = row.booking_uid;
3710
+ }
1733
3711
  const existingIdentity = row.metadata.unique_identification_number || row.unique_identification_number;
1734
3712
  if (!existingIdentity) {
1735
3713
  row.metadata.unique_identification_number = (0, import_utils.createUuidV4)();
1736
3714
  }
1737
3715
  const normalized = (0, import_utils3.normalizeOrderProduct)(row);
3716
+ normalized.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
3717
+ normalized.discount_list
3718
+ );
1738
3719
  const result = {
1739
3720
  ...row,
1740
3721
  ...normalized,
3722
+ product_sku: normalized.product_sku,
1741
3723
  metadata: {
1742
3724
  ...row.metadata,
1743
3725
  ...normalized.metadata
@@ -1745,7 +3727,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1745
3727
  };
1746
3728
  if (result.metadata)
1747
3729
  delete result.metadata.price_schema_version;
1748
- return result;
3730
+ return this.sanitizeOrderProductForTempOrder(result);
1749
3731
  }
1750
3732
  getLastOrderInfo() {
1751
3733
  var _a;
@@ -1754,8 +3736,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1754
3736
  async getOrderInfo(order_id) {
1755
3737
  const res = await this.request.get(`/order/sales/${order_id}`, {
1756
3738
  with: ["products", "bookings"]
1757
- }, {
1758
- osServer: true
1759
3739
  });
1760
3740
  return res;
1761
3741
  }