@pisell/pisellos 0.0.568 → 0.10.1

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 (588) hide show
  1. package/dist/core/index.js +10 -6
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.js +0 -3
  4. package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +7 -5
  6. package/dist/model/strategy/adapter/walletPass/example.js +26 -3
  7. package/dist/model/strategy/adapter/walletPass/index.js +5 -5
  8. package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -3
  9. package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -26
  10. package/dist/model/strategy/adapter/walletPass/utils.js +24 -96
  11. package/dist/model/strategy/strategy-example.js +19 -5
  12. package/dist/modules/BaseModule.d.ts +2 -2
  13. package/dist/modules/BaseModule.js +12 -14
  14. package/dist/modules/BookingContext/index.d.ts +48 -0
  15. package/dist/modules/BookingContext/index.js +566 -0
  16. package/dist/modules/BookingContext/types.d.ts +102 -0
  17. package/dist/modules/BookingContext/types.js +51 -0
  18. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  19. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +302 -0
  20. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  21. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +149 -0
  22. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  23. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +249 -0
  24. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  25. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  26. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  27. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  28. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  29. package/dist/modules/BookingContext/utils/index.js +11 -0
  30. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  31. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  32. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  33. package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
  34. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  35. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  36. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  37. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  38. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  39. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  40. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  41. package/dist/modules/BookingContext/utils/resources.js +486 -0
  42. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  43. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  44. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  45. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  46. package/dist/modules/Cart/index.js +3 -0
  47. package/dist/modules/Cart/utils/cartProduct.js +27 -5
  48. package/dist/modules/Cart/utils/cartResource.js +0 -2
  49. package/dist/modules/Cart/utils/changePrice.js +11 -11
  50. package/dist/modules/Customer/index.d.ts +20 -0
  51. package/dist/modules/Customer/index.js +172 -83
  52. package/dist/modules/Customer/types.d.ts +2 -0
  53. package/dist/modules/Date/index.js +5 -1
  54. package/dist/modules/Discount/index.d.ts +2 -2
  55. package/dist/modules/Discount/index.js +43 -30
  56. package/dist/modules/Discount/types.d.ts +1 -1
  57. package/dist/modules/OpenData/index.d.ts +8 -0
  58. package/dist/modules/OpenData/index.js +38 -16
  59. package/dist/modules/Order/index.d.ts +449 -24
  60. package/dist/modules/Order/index.js +5460 -574
  61. package/dist/modules/Order/types.d.ts +693 -88
  62. package/dist/modules/Order/types.js +68 -1
  63. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  64. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  65. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  66. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  67. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  68. package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
  69. package/dist/modules/Order/utils.d.ts +167 -18
  70. package/dist/modules/Order/utils.js +960 -165
  71. package/dist/modules/Payment/index.d.ts +10 -9
  72. package/dist/modules/Payment/index.js +573 -746
  73. package/dist/modules/Payment/types.d.ts +44 -24
  74. package/dist/modules/Payment/utils.d.ts +1 -1
  75. package/dist/modules/Payment/utils.js +4 -3
  76. package/dist/modules/Payment/walletpass.d.ts +0 -2
  77. package/dist/modules/Payment/walletpass.js +49 -33
  78. package/dist/modules/Product/types.d.ts +29 -7
  79. package/dist/modules/ProductList/index.d.ts +17 -13
  80. package/dist/modules/ProductList/index.js +182 -81
  81. package/dist/modules/ProductList/types.d.ts +16 -0
  82. package/dist/modules/Quotation/index.d.ts +22 -2
  83. package/dist/modules/Quotation/index.js +108 -42
  84. package/dist/modules/Quotation/types.d.ts +19 -0
  85. package/dist/modules/ResourcePlanner/index.d.ts +24 -0
  86. package/dist/modules/ResourcePlanner/index.js +181 -0
  87. package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
  88. package/dist/modules/ResourcePlanner/planner.js +1069 -0
  89. package/dist/modules/ResourcePlanner/types.d.ts +227 -0
  90. package/dist/modules/ResourcePlanner/types.js +1 -0
  91. package/dist/modules/Rules/index.d.ts +8 -10
  92. package/dist/modules/Rules/index.js +324 -513
  93. package/dist/modules/Rules/types.d.ts +14 -3
  94. package/dist/modules/SalesSummary/index.d.ts +23 -26
  95. package/dist/modules/SalesSummary/index.js +152 -46
  96. package/dist/modules/SalesSummary/types.d.ts +9 -1
  97. package/dist/modules/SalesSummary/utils.d.ts +3 -22
  98. package/dist/modules/SalesSummary/utils.js +804 -165
  99. package/dist/modules/Schedule/getDateIsInSchedule.js +14 -12
  100. package/dist/modules/Schedule/index.d.ts +18 -5
  101. package/dist/modules/Schedule/index.js +79 -24
  102. package/dist/modules/Schedule/types.d.ts +2 -0
  103. package/dist/modules/Schedule/utils.js +1 -0
  104. package/dist/modules/Step/index.js +1 -0
  105. package/dist/modules/Summary/index.js +4 -3
  106. package/dist/modules/Summary/utils.js +22 -43
  107. package/dist/modules/SurchargeList/index.d.ts +18 -0
  108. package/dist/modules/SurchargeList/index.js +185 -0
  109. package/dist/modules/SurchargeList/types.d.ts +15 -0
  110. package/dist/modules/SurchargeList/types.js +1 -0
  111. package/dist/modules/index.d.ts +3 -0
  112. package/dist/modules/index.js +4 -1
  113. package/dist/plugins/app.d.ts +2 -0
  114. package/dist/plugins/request.d.ts +1 -0
  115. package/dist/plugins/request.js +4 -1
  116. package/dist/plugins/window.js +6 -2
  117. package/dist/server/index.d.ts +462 -8
  118. package/dist/server/index.js +6168 -680
  119. package/dist/server/modules/floor-plan/index.d.ts +39 -0
  120. package/dist/server/modules/floor-plan/index.js +595 -0
  121. package/dist/server/modules/floor-plan/types.d.ts +43 -0
  122. package/dist/server/modules/floor-plan/types.js +13 -0
  123. package/dist/server/modules/index.d.ts +7 -2
  124. package/dist/server/modules/index.js +6 -0
  125. package/dist/server/modules/menu/index.js +41 -32
  126. package/dist/server/modules/order/index.d.ts +207 -14
  127. package/dist/server/modules/order/index.js +2328 -379
  128. package/dist/server/modules/order/types.d.ts +76 -5
  129. package/dist/server/modules/order/types.js +14 -1
  130. package/dist/server/modules/order/utils/filterBookings.d.ts +7 -1
  131. package/dist/server/modules/order/utils/filterBookings.js +118 -11
  132. package/dist/server/modules/order/utils/filterOrders.js +242 -14
  133. package/dist/server/modules/payment/index.d.ts +28 -0
  134. package/dist/server/modules/payment/index.js +305 -0
  135. package/dist/server/modules/payment/types.d.ts +9 -0
  136. package/dist/server/modules/payment/types.js +1 -0
  137. package/dist/server/modules/products/index.d.ts +105 -14
  138. package/dist/server/modules/products/index.js +1416 -521
  139. package/dist/server/modules/products/types.d.ts +34 -1
  140. package/dist/server/modules/products/types.js +4 -0
  141. package/dist/server/modules/quotation/index.d.ts +39 -0
  142. package/dist/server/modules/quotation/index.js +298 -77
  143. package/dist/server/modules/resource/index.d.ts +2 -3
  144. package/dist/server/modules/resource/index.js +109 -86
  145. package/dist/server/modules/schedule/index.d.ts +6 -4
  146. package/dist/server/modules/schedule/index.js +145 -106
  147. package/dist/server/test.json +713 -0
  148. package/dist/server/types.d.ts +2 -0
  149. package/dist/server/utils/product.js +3 -2
  150. package/dist/server/utils/small-ticket.d.ts +71 -0
  151. package/dist/server/utils/small-ticket.js +963 -0
  152. package/dist/solution/BaseSales/index.d.ts +378 -0
  153. package/dist/solution/BaseSales/index.js +4009 -0
  154. package/dist/solution/BaseSales/types.d.ts +394 -0
  155. package/dist/solution/BaseSales/types.js +40 -0
  156. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  157. package/dist/solution/BaseSales/utils/cartPromotion.js +1450 -0
  158. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
  159. package/dist/solution/BaseSales/utils/parseSalesResponse.js +157 -0
  160. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
  161. package/dist/solution/BaseSales/utils/quotationPrice.js +250 -0
  162. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
  163. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +218 -0
  164. package/dist/solution/BaseSales/utils.d.ts +40 -0
  165. package/dist/solution/BaseSales/utils.js +263 -0
  166. package/dist/solution/BookingByStep/index.d.ts +1 -1
  167. package/dist/solution/BookingByStep/index.js +60 -11
  168. package/dist/solution/BookingByStep/utils/capacity.js +11 -1
  169. package/dist/solution/BookingByStep/utils/resources.js +3 -1
  170. package/dist/solution/BookingByStep/utils/timeslots.js +43 -2
  171. package/dist/solution/BookingTicket/index.d.ts +393 -24
  172. package/dist/solution/BookingTicket/index.js +2508 -443
  173. package/dist/solution/BookingTicket/types.d.ts +191 -6
  174. package/dist/solution/BookingTicket/types.js +83 -10
  175. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  176. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  177. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  178. package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
  179. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
  180. package/dist/solution/BookingTicket/utils/bookingStatus.js +136 -0
  181. package/dist/solution/BookingTicket/utils/cartView.d.ts +29 -0
  182. package/dist/solution/BookingTicket/utils/cartView.js +209 -0
  183. package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  184. package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
  185. package/dist/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  186. package/dist/solution/BookingTicket/utils/orderCustomer.js +31 -0
  187. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  188. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
  189. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  190. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
  191. package/dist/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
  192. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +42 -1
  193. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  194. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
  195. package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  196. package/dist/solution/BookingTicket/utils/scan/handleScan.js +42 -28
  197. package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  198. package/dist/solution/BookingTicket/utils/scan/index.js +30 -14
  199. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  200. package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
  201. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  202. package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
  203. package/dist/solution/BuyTickets/index.js +12 -9
  204. package/dist/solution/Checkout/index.d.ts +1 -0
  205. package/dist/solution/Checkout/index.js +275 -209
  206. package/dist/solution/Checkout/utils/index.js +20 -8
  207. package/dist/solution/RegisterAndLogin/config.js +2 -10
  208. package/dist/solution/RegisterAndLogin/index.js +76 -30
  209. package/dist/solution/Sales/index.d.ts +50 -5
  210. package/dist/solution/Sales/index.js +484 -92
  211. package/dist/solution/Sales/types.d.ts +26 -2
  212. package/dist/solution/ScanOrder/index.d.ts +27 -21
  213. package/dist/solution/ScanOrder/index.js +519 -444
  214. package/dist/solution/ScanOrder/types.d.ts +33 -11
  215. package/dist/solution/ScanOrder/types.js +4 -5
  216. package/dist/solution/ScanOrder/utils.d.ts +4 -1
  217. package/dist/solution/ScanOrder/utils.js +109 -34
  218. package/dist/solution/ShopDiscount/index.js +18 -19
  219. package/dist/solution/ShopDiscount/types.d.ts +4 -5
  220. package/dist/solution/ShopDiscount/utils.d.ts +0 -9
  221. package/dist/solution/ShopDiscount/utils.js +0 -9
  222. package/dist/solution/UnifiedBookingSales/index.d.ts +183 -0
  223. package/dist/solution/UnifiedBookingSales/index.js +1871 -0
  224. package/dist/solution/UnifiedBookingSales/types.d.ts +143 -0
  225. package/dist/solution/UnifiedBookingSales/types.js +11 -0
  226. package/dist/solution/VenueBooking/index.d.ts +32 -51
  227. package/dist/solution/VenueBooking/index.js +741 -808
  228. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  229. package/dist/solution/VenueBooking/types.d.ts +1 -3
  230. package/dist/solution/VenueBooking/types.js +0 -1
  231. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  232. package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
  233. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
  234. package/dist/solution/VenueBooking/utils/slotMerge.js +9 -3
  235. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
  236. package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
  237. package/dist/solution/index.d.ts +2 -0
  238. package/dist/solution/index.js +3 -1
  239. package/dist/types/index.d.ts +12 -2
  240. package/dist/utils/task.js +18 -15
  241. package/dist/utils/watch.js +1 -0
  242. package/lib/apis/picoding.js +0 -2
  243. package/lib/core/index.js +132 -130
  244. package/lib/effects/index.js +57 -46
  245. package/lib/index.d.ts +0 -1
  246. package/lib/index.js +50 -92
  247. package/lib/model/index.js +21 -14
  248. package/lib/model/strategy/adapter/dataVariant/adapter.js +50 -38
  249. package/lib/model/strategy/adapter/dataVariant/evaluator.js +236 -162
  250. package/lib/model/strategy/adapter/dataVariant/examples.js +237 -229
  251. package/lib/model/strategy/adapter/dataVariant/index.js +34 -39
  252. package/lib/model/strategy/adapter/dataVariant/type.js +28 -57
  253. package/lib/model/strategy/adapter/index.js +64 -100
  254. package/lib/model/strategy/adapter/itemRule/adapter.js +144 -156
  255. package/lib/model/strategy/adapter/itemRule/evaluator.js +48 -36
  256. package/lib/model/strategy/adapter/itemRule/examples.js +225 -295
  257. package/lib/model/strategy/adapter/itemRule/index.js +57 -83
  258. package/lib/model/strategy/adapter/itemRule/type.js +36 -97
  259. package/lib/model/strategy/adapter/promotion/adapter.js +63 -84
  260. package/lib/model/strategy/adapter/promotion/evaluator.js +233 -382
  261. package/lib/model/strategy/adapter/promotion/examples.js +159 -139
  262. package/lib/model/strategy/adapter/promotion/index.js +0 -1
  263. package/lib/model/strategy/adapter/promotion/type.js +35 -199
  264. package/lib/model/strategy/adapter/type.js +16 -4
  265. package/lib/model/strategy/adapter/walletPass/evaluator.js +152 -180
  266. package/lib/model/strategy/adapter/walletPass/example.js +190 -217
  267. package/lib/model/strategy/adapter/walletPass/index.js +51 -75
  268. package/lib/model/strategy/adapter/walletPass/locales.js +58 -36
  269. package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -3
  270. package/lib/model/strategy/adapter/walletPass/type.js +16 -4
  271. package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -26
  272. package/lib/model/strategy/adapter/walletPass/utils.js +383 -676
  273. package/lib/model/strategy/engine.js +168 -270
  274. package/lib/model/strategy/index.js +34 -49
  275. package/lib/model/strategy/strategy-example.js +239 -243
  276. package/lib/model/strategy/type.js +40 -100
  277. package/lib/modules/Account/index.js +53 -39
  278. package/lib/modules/Account/types.js +33 -20
  279. package/lib/modules/AccountList/index.js +154 -116
  280. package/lib/modules/AccountList/types.js +31 -30
  281. package/lib/modules/AccountList/utils.js +30 -18
  282. package/lib/modules/BaseModule.d.ts +2 -2
  283. package/lib/modules/BaseModule.js +50 -29
  284. package/lib/modules/BookingContext/index.d.ts +48 -0
  285. package/lib/modules/BookingContext/index.js +368 -0
  286. package/lib/modules/BookingContext/types.d.ts +102 -0
  287. package/lib/modules/BookingContext/types.js +34 -0
  288. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  289. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +298 -0
  290. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  291. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +155 -0
  292. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  293. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +222 -0
  294. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  295. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  296. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  297. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  298. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  299. package/lib/modules/BookingContext/utils/index.js +43 -0
  300. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  301. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  302. package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  303. package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
  304. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  305. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  306. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  307. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  308. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  309. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  310. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  311. package/lib/modules/BookingContext/utils/resources.js +377 -0
  312. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  313. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  314. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  315. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  316. package/lib/modules/Cart/index.js +124 -170
  317. package/lib/modules/Cart/types.js +51 -46
  318. package/lib/modules/Cart/utils/cartAccount.js +39 -40
  319. package/lib/modules/Cart/utils/cartDate.js +61 -56
  320. package/lib/modules/Cart/utils/cartDiscount.js +33 -28
  321. package/lib/modules/Cart/utils/cartNote.js +32 -27
  322. package/lib/modules/Cart/utils/cartProduct.js +261 -309
  323. package/lib/modules/Cart/utils/cartRelationForms.js +35 -29
  324. package/lib/modules/Cart/utils/cartResource.js +78 -72
  325. package/lib/modules/Cart/utils/changePrice.js +59 -31
  326. package/lib/modules/Cart/utils/index.js +48 -106
  327. package/lib/modules/Customer/constants.js +34 -13
  328. package/lib/modules/Customer/index.d.ts +20 -0
  329. package/lib/modules/Customer/index.js +207 -217
  330. package/lib/modules/Customer/types.d.ts +2 -0
  331. package/lib/modules/Customer/types.js +35 -38
  332. package/lib/modules/Date/index.js +115 -116
  333. package/lib/modules/Date/types.js +28 -16
  334. package/lib/modules/Date/utils.js +123 -174
  335. package/lib/modules/Discount/index.d.ts +2 -2
  336. package/lib/modules/Discount/index.js +133 -119
  337. package/lib/modules/Discount/types.d.ts +1 -1
  338. package/lib/modules/Discount/types.js +31 -9
  339. package/lib/modules/Guests/index.js +56 -30
  340. package/lib/modules/Guests/types.js +33 -23
  341. package/lib/modules/Holder/index.js +189 -209
  342. package/lib/modules/Holder/types.js +16 -4
  343. package/lib/modules/Holder/utils.js +49 -20
  344. package/lib/modules/OpenData/index.d.ts +8 -0
  345. package/lib/modules/OpenData/index.js +88 -63
  346. package/lib/modules/OpenData/types.js +16 -4
  347. package/lib/modules/OpenData/utils.js +78 -44
  348. package/lib/modules/Order/index.d.ts +449 -24
  349. package/lib/modules/Order/index.js +4184 -514
  350. package/lib/modules/Order/types.d.ts +693 -88
  351. package/lib/modules/Order/types.js +35 -24
  352. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  353. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  354. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  355. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  356. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  357. package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
  358. package/lib/modules/Order/utils.d.ts +167 -18
  359. package/lib/modules/Order/utils.js +1085 -414
  360. package/lib/modules/Payment/cash.js +33 -20
  361. package/lib/modules/Payment/cashRecommendationAlgorithm.js +76 -145
  362. package/lib/modules/Payment/eftpos.js +30 -16
  363. package/lib/modules/Payment/index.d.ts +10 -9
  364. package/lib/modules/Payment/index.js +402 -636
  365. package/lib/modules/Payment/mx51.js +0 -1
  366. package/lib/modules/Payment/types.d.ts +44 -24
  367. package/lib/modules/Payment/types.js +107 -216
  368. package/lib/modules/Payment/utils.d.ts +1 -1
  369. package/lib/modules/Payment/utils.js +50 -52
  370. package/lib/modules/Payment/walletpass.d.ts +0 -2
  371. package/lib/modules/Payment/walletpass.js +216 -221
  372. package/lib/modules/Product/index.js +46 -51
  373. package/lib/modules/Product/types.d.ts +29 -7
  374. package/lib/modules/Product/types.js +16 -4
  375. package/lib/modules/Product/utils.js +33 -32
  376. package/lib/modules/ProductList/index.d.ts +17 -13
  377. package/lib/modules/ProductList/index.js +161 -120
  378. package/lib/modules/ProductList/types.d.ts +16 -0
  379. package/lib/modules/ProductList/types.js +31 -9
  380. package/lib/modules/Quotation/index.d.ts +22 -2
  381. package/lib/modules/Quotation/index.js +154 -64
  382. package/lib/modules/Quotation/types.d.ts +19 -0
  383. package/lib/modules/Quotation/types.js +16 -4
  384. package/lib/modules/Resource/index.js +59 -27
  385. package/lib/modules/Resource/types.js +32 -22
  386. package/lib/modules/Resource/utils.js +38 -30
  387. package/lib/modules/ResourcePlanner/index.d.ts +24 -0
  388. package/lib/modules/ResourcePlanner/index.js +148 -0
  389. package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
  390. package/lib/modules/ResourcePlanner/planner.js +933 -0
  391. package/lib/modules/ResourcePlanner/types.d.ts +227 -0
  392. package/lib/modules/ResourcePlanner/types.js +17 -0
  393. package/lib/modules/Rules/index.d.ts +8 -10
  394. package/lib/modules/Rules/index.js +960 -1440
  395. package/lib/modules/Rules/types.d.ts +14 -3
  396. package/lib/modules/Rules/types.js +40 -17
  397. package/lib/modules/SalesSummary/index.d.ts +23 -26
  398. package/lib/modules/SalesSummary/index.js +134 -61
  399. package/lib/modules/SalesSummary/types.d.ts +9 -1
  400. package/lib/modules/SalesSummary/types.js +16 -4
  401. package/lib/modules/SalesSummary/utils.d.ts +3 -22
  402. package/lib/modules/SalesSummary/utils.js +814 -233
  403. package/lib/modules/ScanOrderLogger/index.js +79 -59
  404. package/lib/modules/ScanOrderLogger/providers/feishu.js +78 -54
  405. package/lib/modules/ScanOrderLogger/providers/grafana.js +36 -13
  406. package/lib/modules/ScanOrderLogger/types.js +16 -4
  407. package/lib/modules/Schedule/getDateIsInSchedule.js +169 -338
  408. package/lib/modules/Schedule/index.d.ts +18 -5
  409. package/lib/modules/Schedule/index.js +153 -104
  410. package/lib/modules/Schedule/type.js +16 -4
  411. package/lib/modules/Schedule/types.d.ts +2 -0
  412. package/lib/modules/Schedule/types.js +16 -4
  413. package/lib/modules/Schedule/utils.js +291 -433
  414. package/lib/modules/Step/index.js +52 -40
  415. package/lib/modules/Step/tyeps.js +16 -4
  416. package/lib/modules/Summary/index.js +71 -66
  417. package/lib/modules/Summary/types.js +16 -4
  418. package/lib/modules/Summary/utils.js +418 -791
  419. package/lib/modules/SurchargeList/index.d.ts +18 -0
  420. package/lib/modules/SurchargeList/index.js +109 -0
  421. package/lib/modules/SurchargeList/types.d.ts +15 -0
  422. package/lib/modules/SurchargeList/types.js +17 -0
  423. package/lib/modules/index.d.ts +3 -0
  424. package/lib/modules/index.js +63 -212
  425. package/lib/plugins/app.d.ts +2 -0
  426. package/lib/plugins/app.js +16 -4
  427. package/lib/plugins/index.js +25 -36
  428. package/lib/plugins/request.d.ts +1 -0
  429. package/lib/plugins/request.js +126 -137
  430. package/lib/plugins/shopStore.js +16 -4
  431. package/lib/plugins/user.js +16 -4
  432. package/lib/plugins/window.js +179 -171
  433. package/lib/server/index.d.ts +462 -8
  434. package/lib/server/index.js +4520 -1162
  435. package/lib/server/modules/floor-plan/index.d.ts +39 -0
  436. package/lib/server/modules/floor-plan/index.js +327 -0
  437. package/lib/server/modules/floor-plan/types.d.ts +43 -0
  438. package/lib/server/modules/floor-plan/types.js +34 -0
  439. package/lib/server/modules/index.d.ts +7 -2
  440. package/lib/server/modules/index.js +67 -84
  441. package/lib/server/modules/menu/index.js +122 -146
  442. package/lib/server/modules/menu/types.js +31 -18
  443. package/lib/server/modules/order/index.d.ts +207 -14
  444. package/lib/server/modules/order/index.js +1543 -285
  445. package/lib/server/modules/order/types.d.ts +76 -5
  446. package/lib/server/modules/order/types.js +32 -107
  447. package/lib/server/modules/order/utils/filterBookings.d.ts +7 -1
  448. package/lib/server/modules/order/utils/filterBookings.js +259 -176
  449. package/lib/server/modules/order/utils/filterOrders.js +293 -94
  450. package/lib/server/modules/payment/index.d.ts +28 -0
  451. package/lib/server/modules/payment/index.js +192 -0
  452. package/lib/server/modules/payment/types.d.ts +9 -0
  453. package/lib/server/modules/payment/types.js +17 -0
  454. package/lib/server/modules/products/index.d.ts +105 -14
  455. package/lib/server/modules/products/index.js +850 -475
  456. package/lib/server/modules/products/types.d.ts +34 -1
  457. package/lib/server/modules/products/types.js +34 -41
  458. package/lib/server/modules/quotation/index.d.ts +39 -0
  459. package/lib/server/modules/quotation/index.js +254 -75
  460. package/lib/server/modules/quotation/types.js +31 -21
  461. package/lib/server/modules/resource/index.d.ts +2 -3
  462. package/lib/server/modules/resource/index.js +240 -243
  463. package/lib/server/modules/resource/types.js +33 -42
  464. package/lib/server/modules/schedule/index.d.ts +6 -4
  465. package/lib/server/modules/schedule/index.js +146 -147
  466. package/lib/server/modules/schedule/types.js +21 -14
  467. package/lib/server/modules/schedule/utils.js +163 -334
  468. package/lib/server/test.json +713 -0
  469. package/lib/server/types.d.ts +2 -0
  470. package/lib/server/types.js +16 -4
  471. package/lib/server/utils/index.js +23 -25
  472. package/lib/server/utils/product.js +140 -197
  473. package/lib/server/utils/schedule.js +41 -34
  474. package/lib/server/utils/small-ticket.d.ts +71 -0
  475. package/lib/server/utils/small-ticket.js +904 -0
  476. package/lib/server/utils/time.js +49 -40
  477. package/lib/solution/BaseSales/index.d.ts +378 -0
  478. package/lib/solution/BaseSales/index.js +2533 -0
  479. package/lib/solution/BaseSales/types.d.ts +394 -0
  480. package/lib/solution/BaseSales/types.js +43 -0
  481. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  482. package/lib/solution/BaseSales/utils/cartPromotion.js +1004 -0
  483. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
  484. package/lib/solution/BaseSales/utils/parseSalesResponse.js +160 -0
  485. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
  486. package/lib/solution/BaseSales/utils/quotationPrice.js +289 -0
  487. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
  488. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +256 -0
  489. package/lib/solution/BaseSales/utils.d.ts +40 -0
  490. package/lib/solution/BaseSales/utils.js +244 -0
  491. package/lib/solution/BookingByStep/index.d.ts +1 -1
  492. package/lib/solution/BookingByStep/index.js +1340 -1530
  493. package/lib/solution/BookingByStep/types.js +99 -40
  494. package/lib/solution/BookingByStep/utils/capacity.js +160 -192
  495. package/lib/solution/BookingByStep/utils/products.js +52 -42
  496. package/lib/solution/BookingByStep/utils/resources.js +330 -527
  497. package/lib/solution/BookingByStep/utils/stock.js +44 -65
  498. package/lib/solution/BookingByStep/utils/timeslots.js +131 -129
  499. package/lib/solution/BookingTicket/index.d.ts +393 -24
  500. package/lib/solution/BookingTicket/index.js +1374 -184
  501. package/lib/solution/BookingTicket/types.d.ts +191 -6
  502. package/lib/solution/BookingTicket/types.js +79 -40
  503. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  504. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  505. package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  506. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
  507. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
  508. package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -0
  509. package/lib/solution/BookingTicket/utils/cartView.d.ts +29 -0
  510. package/lib/solution/BookingTicket/utils/cartView.js +184 -0
  511. package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  512. package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
  513. package/lib/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  514. package/lib/solution/BookingTicket/utils/orderCustomer.js +58 -0
  515. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  516. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
  517. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  518. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
  519. package/lib/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
  520. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +97 -64
  521. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  522. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
  523. package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  524. package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -82
  525. package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  526. package/lib/solution/BookingTicket/utils/scan/index.js +109 -91
  527. package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
  528. package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  529. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
  530. package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  531. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
  532. package/lib/solution/BuyTickets/index.js +70 -67
  533. package/lib/solution/BuyTickets/types.js +38 -22
  534. package/lib/solution/Checkout/index.d.ts +1 -0
  535. package/lib/solution/Checkout/index.js +1169 -1463
  536. package/lib/solution/Checkout/types.js +61 -91
  537. package/lib/solution/Checkout/utils/index.js +156 -228
  538. package/lib/solution/PlaceOrder/index.js +0 -55
  539. package/lib/solution/RegisterAndLogin/config.js +462 -503
  540. package/lib/solution/RegisterAndLogin/index.js +630 -633
  541. package/lib/solution/RegisterAndLogin/types.js +76 -189
  542. package/lib/solution/RegisterAndLogin/utils.js +125 -183
  543. package/lib/solution/Sales/index.d.ts +50 -5
  544. package/lib/solution/Sales/index.js +498 -238
  545. package/lib/solution/Sales/types.d.ts +26 -2
  546. package/lib/solution/Sales/types.js +33 -27
  547. package/lib/solution/ScanOrder/index.d.ts +27 -21
  548. package/lib/solution/ScanOrder/index.js +936 -864
  549. package/lib/solution/ScanOrder/types.d.ts +33 -11
  550. package/lib/solution/ScanOrder/types.js +34 -34
  551. package/lib/solution/ScanOrder/utils.d.ts +4 -1
  552. package/lib/solution/ScanOrder/utils.js +422 -385
  553. package/lib/solution/ShopDiscount/index.js +233 -235
  554. package/lib/solution/ShopDiscount/types.d.ts +4 -5
  555. package/lib/solution/ShopDiscount/types.js +37 -15
  556. package/lib/solution/ShopDiscount/utils.d.ts +0 -9
  557. package/lib/solution/ShopDiscount/utils.js +172 -309
  558. package/lib/solution/UnifiedBookingSales/index.d.ts +183 -0
  559. package/lib/solution/UnifiedBookingSales/index.js +1076 -0
  560. package/lib/solution/UnifiedBookingSales/types.d.ts +143 -0
  561. package/lib/solution/UnifiedBookingSales/types.js +33 -0
  562. package/lib/solution/VenueBooking/index.d.ts +32 -51
  563. package/lib/solution/VenueBooking/index.js +1008 -984
  564. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  565. package/lib/solution/VenueBooking/types.d.ts +1 -3
  566. package/lib/solution/VenueBooking/types.js +39 -20
  567. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  568. package/lib/solution/VenueBooking/utils/dateSummary.js +62 -25
  569. package/lib/solution/VenueBooking/utils/resource.js +54 -31
  570. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
  571. package/lib/solution/VenueBooking/utils/slotMerge.js +109 -90
  572. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
  573. package/lib/solution/VenueBooking/utils/timeSlot.js +133 -138
  574. package/lib/solution/VenueBooking/utils.js +67 -130
  575. package/lib/solution/index.d.ts +2 -0
  576. package/lib/solution/index.js +41 -102
  577. package/lib/store/createStore.js +29 -32
  578. package/lib/types/index.d.ts +12 -2
  579. package/lib/types/index.js +16 -4
  580. package/lib/utils/task.js +36 -36
  581. package/lib/utils/watch.js +47 -81
  582. package/package.json +2 -4
  583. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  584. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
  585. package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
  586. package/lib/solution/Checkout/appointmentDemo.json +0 -1
  587. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
  588. package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
@@ -1,117 +1,137 @@
1
- "use strict";
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
28
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
29
+ // src/server/modules/order/index.ts
30
+ var order_exports = {};
31
+ __export(order_exports, {
32
+ OrderModule: () => OrderModule
5
33
  });
6
- exports.OrderModule = void 0;
7
- var _lodashEs = require("lodash-es");
8
- var _dayjs = _interopRequireDefault(require("dayjs"));
9
- var _BaseModule = require("../../../modules/BaseModule");
10
- var _types = require("./types");
11
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
- /**
13
- * SQLite 存储名称
14
- */
15
- const INDEXDB_STORE_NAME = 'orders';
16
- const ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = 'server_order_last_full_fetch_at';
17
-
18
- /**
19
- * Order 模块 - 基础框架
20
- */
21
- class OrderModule extends _BaseModule.BaseModule {
22
- defaultName = 'order';
23
- defaultVersion = '1.0.0';
24
- store;
25
- dbManager;
26
- orderDataSource;
27
- pendingSyncMessages = [];
28
- syncTimer;
29
- ORDER_SYNC_DEBOUNCE_MS = 5_000;
30
- // Map<resource_id, OrderId[]> 资源到订单的倒排索引
31
- resourceIdIndex = new Map();
32
- logger; // LoggerManager 实例
33
- storage;
34
+ module.exports = __toCommonJS(order_exports);
35
+ var import_lodash_es = require("lodash-es");
36
+ var import_dayjs = __toESM(require("dayjs"));
37
+ var import_BaseModule = require("../../../modules/BaseModule");
38
+ var import_orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
39
+ var import_types = require("./types");
40
+ var INDEXDB_STORE_NAME = "orders";
41
+ var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
42
+ var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
43
+ var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
44
+ var ORDER_SQLITE_DEDUPE_MS = 15e3;
45
+ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
46
+ var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
47
+ "upsertOrdersFromRemote",
48
+ "upsertPendingSyncOrders",
49
+ "overwriteExistingOrder",
50
+ "markOrderSyncedByExternalSaleNumber"
51
+ ]);
52
+ var ORDER_MERGE_SELF_CHECK = false;
53
+ var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
54
+ var ORDER_COLLECTION_KIND_BY_FIELD = {
55
+ products: "product",
56
+ bookings: "booking",
57
+ payments: "payment"
58
+ };
59
+ var OrderModule = class extends import_BaseModule.BaseModule {
34
60
  constructor(name, version) {
35
61
  super(name, version);
62
+ this.defaultName = "order";
63
+ this.defaultVersion = "1.0.0";
64
+ this.pendingSyncMessages = [];
65
+ this.isProcessingSyncBatch = false;
66
+ this.isIdlePhase = true;
67
+ this.orderSQLiteSaveQueue = Promise.resolve();
68
+ /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
69
+ this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
70
+ /** 最近一次 SSE 全量拉取完成时间 */
71
+ this.lastServerFullFetchAtMs = 0;
72
+ }
73
+ /**
74
+ * 广播订单变更事件,兼容全量列表订阅并额外携带本次变更订单。
75
+ *
76
+ * @example
77
+ * await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
78
+ */
79
+ async emitOrdersChanged(changedOrders = [], source) {
80
+ console.log("触发emitOrdersChanged");
81
+ const payload = {
82
+ list: this.store.list,
83
+ changedOrders: changedOrders.map((order) => this.normalizeOrderForMemoryList(order)),
84
+ source
85
+ };
86
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
36
87
  }
37
88
  async initialize(core, options) {
89
+ var _a;
38
90
  this.core = core;
39
- this.store = options?.store;
40
- if (!this.store.map) this.store.map = new Map();
41
- const appPlugin = core.getPlugin('app');
42
- const app = appPlugin?.getApp();
91
+ this.store = options == null ? void 0 : options.store;
92
+ if (!this.store.map)
93
+ this.store.map = /* @__PURE__ */ new Map();
94
+ const appPlugin = core.getPlugin("app");
95
+ const app = appPlugin == null ? void 0 : appPlugin.getApp();
43
96
  if (app) {
44
97
  this.dbManager = app.sqlite;
45
98
  this.logger = app.logger;
46
99
  this.storage = app.storage;
47
- const coreData = app.data.store.getStore().getDataByModel('core');
48
- if (!this.store.createdAtQuery?.sales_time_between && coreData?.core) {
49
- const today = (0, _dayjs.default)();
50
- if (coreData?.core.operating_day_boundary) {
51
- const operatingDayBoundary = coreData.core.operating_day_boundary;
52
- if (operatingDayBoundary.type === 'start_time') {
53
- const boundaryTime = String(operatingDayBoundary.time || '').trim();
54
- const boundaryStart = (0, _dayjs.default)(`${today.format('YYYY-MM-DD')} ${boundaryTime}`);
55
- const boundaryEnd = boundaryStart.add(1, 'day');
56
- if (boundaryStart.isValid()) {
57
- this.store.createdAtQuery = {
58
- sales_time_between: [boundaryStart.format('YYYY-MM-DD HH:mm:ss'), boundaryEnd.format('YYYY-MM-DD HH:mm:ss')]
59
- };
60
- } else {
61
- // 边界时间异常时回退到自然日,避免 createdAtQuery 为空导致后续查询异常
62
- this.store.createdAtQuery = {
63
- sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
64
- };
65
- }
66
- } else {
67
- this.store.createdAtQuery = {
68
- sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
69
- };
70
- }
71
- } else {
72
- // TODO: 这里后续可能需要使用店铺营业时间查询
73
- this.store.createdAtQuery = {
74
- sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
75
- };
76
- }
77
- }
100
+ this.updateCreateStore();
78
101
  }
79
- if (Array.isArray(options?.initialState?.list)) {
80
- this.store.list = options.initialState.list;
102
+ if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
103
+ this.store.list = options.initialState.list.map((order) => this.normalizeOrderForMemoryList(order));
81
104
  this.syncOrdersMap();
82
- this.core.effects.emit(_types.OrderHooks.onOrdersChanged, this.store.list);
105
+ this.emitOrdersChanged([], "initialState");
83
106
  } else {
84
107
  this.store.list = [];
85
- this.store.map = new Map();
108
+ this.store.map = /* @__PURE__ */ new Map();
86
109
  }
87
110
  this.initOrderDataSource();
88
111
  this.setupOrderSync();
89
- this.logInfo('OrderServer模块初始化完成', {
112
+ this.logInfo("OrderServer模块初始化完成", {
90
113
  hasDbManager: !!this.dbManager,
91
114
  hasLogger: !!this.logger,
92
115
  initialOrderCount: this.store.list.length
93
116
  });
94
117
  }
95
-
96
118
  /**
97
- * 记录信息日志
98
- * @param title 日志标题
99
- * @param metadata 日志元数据
100
- */
119
+ * 记录信息日志
120
+ * @param title 日志标题
121
+ * @param metadata 日志元数据
122
+ */
101
123
  logInfo(title, metadata) {
102
124
  try {
103
125
  if (this.logger) {
104
126
  this.logger.addLog({
105
- type: 'info',
127
+ type: "info",
106
128
  title: `[OrderServerModule] ${title}`,
107
129
  metadata: metadata || {}
108
130
  });
109
131
  }
110
132
  } catch {
111
- // 日志记录失败不影响主流程
112
133
  }
113
134
  }
114
-
115
135
  /**
116
136
  * 记录错误日志
117
137
  * @param title 日志标题
@@ -121,38 +141,336 @@ class OrderModule extends _BaseModule.BaseModule {
121
141
  try {
122
142
  if (this.logger) {
123
143
  this.logger.addLog({
124
- type: 'error',
144
+ type: "error",
145
+ title: `[OrderServerModule] ${title}`,
146
+ metadata: metadata || {}
147
+ });
148
+ }
149
+ } catch {
150
+ }
151
+ }
152
+ logWarning(title, metadata) {
153
+ try {
154
+ if (this.logger) {
155
+ this.logger.addLog({
156
+ type: "warning",
125
157
  title: `[OrderServerModule] ${title}`,
126
158
  metadata: metadata || {}
127
159
  });
128
160
  }
129
161
  } catch {
130
- // 日志记录失败不影响主流程
131
162
  }
132
163
  }
164
+ /**
165
+ * 在订单进入内存或 SQLite 前统一压缩子项强身份重复并补齐协议 UID。
166
+ * 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
167
+ */
168
+ normalizeOrderCollectionsForIngress(order, source) {
169
+ const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(order);
170
+ const kinds = ["product", "booking", "payment"];
171
+ const hasChanges = kinds.some((kind) => {
172
+ const stats = result.stats[kind];
173
+ return stats.backfilledUidCount > 0 || stats.collapsedDuplicateCount > 0 || stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
174
+ });
175
+ if (hasChanges) {
176
+ const summarize = (stats) => ({
177
+ backfilled_uid_count: stats.backfilledUidCount,
178
+ collapsed_duplicate_count: stats.collapsedDuplicateCount,
179
+ uid_conflict_count: stats.uidConflictCount,
180
+ anonymous_row_count: stats.anonymousRowCount
181
+ });
182
+ const context = {
183
+ source,
184
+ order_id: (order == null ? void 0 : order.order_id) ?? null,
185
+ external_sale_number: (order == null ? void 0 : order.external_sale_number) ?? null,
186
+ products: summarize(result.stats.product),
187
+ bookings: summarize(result.stats.booking),
188
+ payments: summarize(result.stats.payment)
189
+ };
190
+ const hasUnsafeIdentity = kinds.some((kind) => {
191
+ const stats = result.stats[kind];
192
+ return stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
193
+ });
194
+ if (hasUnsafeIdentity) {
195
+ this.logWarning("订单子项身份存在冲突或匿名行", context);
196
+ } else {
197
+ this.logInfo("订单子项身份已规范化", context);
198
+ }
199
+ }
200
+ return result.order;
201
+ }
202
+ /**
203
+ * incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
204
+ */
205
+ mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = []) {
206
+ const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
207
+ const existingItems = Array.isArray(existing) ? existing : [];
208
+ return incoming.map((incomingItem) => {
209
+ const existingItem = existingItems.find(
210
+ (item) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem)
211
+ );
212
+ if (!existingItem)
213
+ return (0, import_lodash_es.cloneDeep)(incomingItem);
214
+ const mergedItem = (0, import_orderCollectionIdentity.mergeOrderCollectionItems)(kind, existingItem, incomingItem);
215
+ const mergedUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)(kind, mergedItem);
216
+ if (mergedUid) {
217
+ for (const from of /* @__PURE__ */ new Set([
218
+ (0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, existingItem),
219
+ (0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, incomingItem)
220
+ ])) {
221
+ if (!from || from === mergedUid)
222
+ continue;
223
+ uidRemaps.push({
224
+ kind,
225
+ from,
226
+ to: mergedUid,
227
+ persistentId: (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, incomingItem) || (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, existingItem)
228
+ });
229
+ }
230
+ }
231
+ return mergedItem;
232
+ });
233
+ }
234
+ reconcileOverwriteOrderCollections(existing, incoming) {
235
+ const reconciled = (0, import_lodash_es.cloneDeep)(incoming);
236
+ const existingRecord = existing;
237
+ const incomingRecord = incoming;
238
+ const uidRemaps = [];
239
+ for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
240
+ if (!Array.isArray(incomingRecord[field]))
241
+ continue;
242
+ reconciled[field] = this.mergeAuthoritativeOrderCollection(
243
+ field,
244
+ existingRecord[field],
245
+ incomingRecord[field],
246
+ uidRemaps
247
+ );
248
+ }
249
+ return this.normalizeOrderCollectionsForIngress(
250
+ (0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(reconciled, uidRemaps),
251
+ "overwriteExistingOrder.reconciled"
252
+ );
253
+ }
254
+ /**
255
+ * 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
256
+ *
257
+ * @example
258
+ * this.recordRecentSqliteWrite('upsertOrdersFromRemote', orders)
259
+ */
260
+ recordRecentSqliteWrite(source, orders) {
261
+ const now = Date.now();
262
+ for (const order of orders) {
263
+ const storageKey = this.getOrderStorageKey(order);
264
+ if (!storageKey)
265
+ continue;
266
+ this.recentSqliteWriteByStorageKey.set(storageKey, { source, ts: now });
267
+ }
268
+ }
269
+ /**
270
+ * 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
271
+ *
272
+ * @example
273
+ * const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
274
+ */
275
+ filterRedundantPatchOrders(source, orders, mergeActions) {
276
+ const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
277
+ if (!eligibleSkipSources.has(source)) {
278
+ return { toWrite: orders, skipped: [] };
279
+ }
280
+ const now = Date.now();
281
+ const toWrite = [];
282
+ const skipped = [];
283
+ for (const order of orders) {
284
+ const storageKey = this.getOrderStorageKey(order);
285
+ if (!storageKey) {
286
+ toWrite.push(order);
287
+ continue;
288
+ }
289
+ const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
290
+ const mergeAction = orderKey ? mergeActions[orderKey] : void 0;
291
+ if (mergeAction === "insert") {
292
+ toWrite.push(order);
293
+ continue;
294
+ }
295
+ const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
296
+ if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
297
+ skipped.push({
298
+ orderId: order.order_id ?? null,
299
+ storageKey,
300
+ reason: "skip_pubsub_echo_after_business_write",
301
+ lastSource: recent.source,
302
+ elapsedMs: now - recent.ts
303
+ });
304
+ continue;
305
+ }
306
+ toWrite.push(order);
307
+ }
308
+ return { toWrite, skipped };
309
+ }
310
+ /**
311
+ * 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
312
+ *
313
+ * @example
314
+ * const ids = this.filterRedundantHttpRefreshIds([99331, 99332])
315
+ */
316
+ filterRedundantHttpRefreshIds(ids) {
317
+ const now = Date.now();
318
+ const toFetch = [];
319
+ const skipped = [];
320
+ for (const id of ids) {
321
+ const existing = this.getOrderByOrderId(id);
322
+ if (!existing) {
323
+ toFetch.push(id);
324
+ continue;
325
+ }
326
+ const storageKey = this.getOrderStorageKey(existing);
327
+ const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : void 0;
328
+ if (recent && recent.source === "upsertOrdersFromRemote" && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
329
+ skipped.push({
330
+ orderId: id,
331
+ lastSource: recent.source,
332
+ elapsedMs: now - recent.ts
333
+ });
334
+ continue;
335
+ }
336
+ toFetch.push(id);
337
+ }
338
+ return { toFetch, skipped };
339
+ }
340
+ /**
341
+ * 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
342
+ *
343
+ * @example
344
+ * this.resolveSyncMessageRoute(msg)
345
+ * // => { route: 'httpRefresh.batchIds', ... }
346
+ */
347
+ resolveSyncMessageRoute(msg) {
348
+ var _a;
349
+ const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
350
+ const singleIdRaw = msg.id ?? msg.order_id;
351
+ const hasSingleId = !hasBatchIds && singleIdRaw !== void 0 && singleIdRaw !== null;
352
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
353
+ if (hasBatchIds) {
354
+ return {
355
+ route: "httpRefresh.batchIds",
356
+ hasBatchIds: true,
357
+ hasSingleId: false,
358
+ hasNormalizedBody: !!normalizedBody,
359
+ singleId: null,
360
+ batchIds: msg.ids || [],
361
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
362
+ };
363
+ }
364
+ if (hasSingleId && normalizedBody) {
365
+ return {
366
+ route: "bodyUpsert",
367
+ hasBatchIds: false,
368
+ hasSingleId: true,
369
+ hasNormalizedBody: true,
370
+ singleId: singleIdRaw,
371
+ batchIds: [],
372
+ bodyOrderId: normalizedBody.order_id ?? null
373
+ };
374
+ }
375
+ if (hasSingleId) {
376
+ return {
377
+ route: "httpRefresh.singleId",
378
+ hasBatchIds: false,
379
+ hasSingleId: true,
380
+ hasNormalizedBody: !!normalizedBody,
381
+ singleId: singleIdRaw,
382
+ batchIds: [],
383
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
384
+ };
385
+ }
386
+ if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length) {
387
+ return {
388
+ route: "httpRefresh.relationIds",
389
+ hasBatchIds: false,
390
+ hasSingleId: false,
391
+ hasNormalizedBody: !!normalizedBody,
392
+ singleId: null,
393
+ batchIds: msg.relation_order_ids,
394
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
395
+ };
396
+ }
397
+ return {
398
+ route: "noop",
399
+ hasBatchIds: false,
400
+ hasSingleId: false,
401
+ hasNormalizedBody: !!normalizedBody,
402
+ singleId: null,
403
+ batchIds: [],
404
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
405
+ };
406
+ }
407
+ updateCreateStore() {
408
+ const appPlugin = this.core.getPlugin("app");
409
+ const app = appPlugin == null ? void 0 : appPlugin.getApp();
410
+ if (app) {
411
+ const coreData = app.data.store.getStore().getDataByModel("core");
412
+ if (coreData == null ? void 0 : coreData.core) {
413
+ const today = (0, import_dayjs.default)();
414
+ if (coreData == null ? void 0 : coreData.core.operating_day_boundary) {
415
+ const operatingDayBoundary = coreData.core.operating_day_boundary;
416
+ if (operatingDayBoundary.type === "start_time") {
417
+ const boundaryTime = String(operatingDayBoundary.time || "").trim();
418
+ const boundaryStart = (0, import_dayjs.default)(`${today.format("YYYY-MM-DD")} ${boundaryTime}`);
419
+ if (boundaryStart.isValid()) {
420
+ const isAfterBoundary = today.isAfter(boundaryStart);
421
+ const queryStart = isAfterBoundary ? today.startOf("day") : today.subtract(1, "day").startOf("day");
422
+ const queryEnd = isAfterBoundary ? today.add(1, "day").endOf("day") : today.endOf("day");
423
+ this.store.createdAtQuery = {
424
+ sales_time_between: [
425
+ queryStart.format("YYYY-MM-DD HH:mm:ss"),
426
+ queryEnd.format("YYYY-MM-DD HH:mm:ss")
427
+ ]
428
+ };
429
+ } else {
430
+ this.store.createdAtQuery = {
431
+ sales_time_between: [
432
+ today.startOf("day").format("YYYY-MM-DD HH:mm:ss"),
433
+ today.endOf("day").format("YYYY-MM-DD HH:mm:ss")
434
+ ]
435
+ };
436
+ }
437
+ } else {
438
+ this.store.createdAtQuery = {
439
+ sales_time_between: [
440
+ today.startOf("day").format("YYYY-MM-DD HH:mm:ss"),
441
+ today.endOf("day").format("YYYY-MM-DD HH:mm:ss")
442
+ ]
443
+ };
444
+ }
445
+ } else {
446
+ this.store.createdAtQuery = {
447
+ sales_time_between: [today.startOf("day").format("YYYY-MM-DD HH:mm:ss"), today.endOf("day").format("YYYY-MM-DD HH:mm:ss")]
448
+ };
449
+ }
450
+ }
451
+ }
452
+ }
453
+ getOrderSyncThrottleMs() {
454
+ const raw = localStorage.getItem(ORDER_SYNC_THROTTLE_MS_STORAGE_KEY);
455
+ if (raw !== null) {
456
+ const parsed = Number(raw);
457
+ if (Number.isFinite(parsed) && parsed >= 0)
458
+ return parsed;
459
+ }
460
+ return DEFAULT_ORDER_SYNC_THROTTLE_MS;
461
+ }
133
462
  async preload() {
134
- // const cachedOrders = await this.loadOrdersFromSQLite()
135
- // const hasPulledInCurrentWindow = this.hasPulledOrdersToday()
136
- // // 仅当缓存属于当前统计窗口时才直接复用,避免跨天/跨营业日窗口继续使用旧数据
137
- // if (cachedOrders.length > 0 && hasPulledInCurrentWindow) {
138
- // this.store.list = cloneDeep(cachedOrders)
139
- // this.syncOrdersMap()
140
- // this.core.effects.emit(OrderHooks.onOrdersChanged, this.store.list)
141
- // return
142
- // }
143
-
144
- // if (hasPulledInCurrentWindow) {
145
- // this.logInfo('当天已完成全量订单拉取,跳过本次全量拉取', {
146
- // lastFullFetchAt: this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY),
147
- // })
148
- // return
149
- // }
150
-
151
- const orders = await this.loadOrdersByServer();
152
- if (orders.length === 0) return;
153
- this.store.list = (0, _lodashEs.cloneDeep)(orders);
154
- this.syncOrdersMap();
155
- this.core.effects.emit(_types.OrderHooks.onOrdersChanged, this.store.list);
463
+ const getData = async () => {
464
+ const orders = await this.loadOrdersByServer();
465
+ if (orders.length === 0) {
466
+ return;
467
+ }
468
+ this.store.list = (0, import_lodash_es.cloneDeep)(orders);
469
+ this.syncOrdersMap();
470
+ this.emitOrdersChanged([], "preload");
471
+ this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
472
+ };
473
+ getData();
156
474
  }
157
475
  getOrders() {
158
476
  return this.store.list;
@@ -160,179 +478,591 @@ class OrderModule extends _BaseModule.BaseModule {
160
478
  getOrderById(id) {
161
479
  return this.store.map.get(this.getIdKey(id));
162
480
  }
163
-
164
- /** 按 order_id 查询(推荐) */
481
+ /** 按 order_id 查询内存订单。 */
165
482
  getOrderByOrderId(orderId) {
166
483
  return this.store.map.get(this.getIdKey(orderId));
167
484
  }
485
+ getLocalOrderFromMemoryByLookup(lookup) {
486
+ const key = this.getIdKey(lookup);
487
+ const memoryOrderById = this.store.map.get(key);
488
+ if (memoryOrderById)
489
+ return memoryOrderById;
490
+ const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
491
+ return memoryOrder || null;
492
+ }
493
+ async getLocalOrderByLookup(lookup) {
494
+ const key = this.getIdKey(lookup);
495
+ const memoryOrderById = this.store.map.get(key);
496
+ if (memoryOrderById)
497
+ return memoryOrderById;
498
+ const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
499
+ if (memoryOrder)
500
+ return memoryOrder;
501
+ const orders = await this.loadOrdersFromSQLite();
502
+ const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
503
+ if (!localOrder)
504
+ return null;
505
+ this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
506
+ this.syncOrdersMap();
507
+ return this.normalizeOrderForMemoryList(localOrder);
508
+ }
168
509
  async loadOrdersByServer() {
510
+ var _a;
169
511
  let orderList = [];
512
+ this.logInfo("loadOrdersByServer-开始", {
513
+ hasOrderDataSource: !!this.orderDataSource,
514
+ query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null
515
+ });
170
516
  if (this.orderDataSource) {
171
517
  try {
172
518
  const data = await this.orderDataSource.run({
173
- http: {
519
+ sse: {
174
520
  query: this.store.createdAtQuery
175
521
  }
176
522
  });
177
523
  orderList = data || [];
524
+ this.logInfo("loadOrdersByServer-SSE拉取成功", {
525
+ count: orderList.length
526
+ });
178
527
  this.markOrderPulledAtNow();
528
+ this.lastServerFullFetchAtMs = Date.now();
179
529
  } catch {
180
- orderList = [];
530
+ this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
531
+ return this.store.list;
181
532
  }
182
533
  }
183
- await this.saveOrdersToSQLite(orderList);
184
- await this.core.effects.emit(_types.OrderHooks.onOrdersLoaded, orderList);
185
- return orderList;
534
+ const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
535
+ const memoryOrders = mergedOrders.map((order) => this.normalizeOrderForMemoryList(order));
536
+ this.logInfo("loadOrdersByServer-结束", {
537
+ count: memoryOrders.length
538
+ });
539
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
540
+ return memoryOrders;
186
541
  }
187
- getOrdersByResourceId(resourceId) {
188
- const ids = this.resourceIdIndex.get(String(resourceId)) || [];
189
- return ids.map(id => this.store.map.get(id)).filter(order => !!order);
542
+ /**
543
+ * 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
544
+ * 拿到完整数据后一次性替换 store,触发订单变更与同步完成事件
545
+ * @returns 刷新后的订单列表
546
+ */
547
+ async silentRefresh() {
548
+ const startTime = Date.now();
549
+ const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
550
+ if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
551
+ return this.store.list;
552
+ }
553
+ this.logInfo("silentRefresh 开始");
554
+ try {
555
+ this.updateCreateStore();
556
+ const orders = await this.loadOrdersByServer();
557
+ if (orders.length > 0) {
558
+ this.store.list = (0, import_lodash_es.cloneDeep)(orders);
559
+ this.syncOrdersMap();
560
+ this.emitOrdersChanged([], "silentRefresh");
561
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
562
+ this.logInfo("silentRefresh 完成", {
563
+ orderCount: orders.length,
564
+ duration: `${Date.now() - startTime}ms`
565
+ });
566
+ } else {
567
+ this.logInfo("silentRefresh: 服务器未返回数据");
568
+ }
569
+ return this.store.list;
570
+ } catch (error) {
571
+ const errorMessage = error instanceof Error ? error.message : String(error);
572
+ this.logError("silentRefresh 失败", {
573
+ duration: `${Date.now() - startTime}ms`,
574
+ error: errorMessage
575
+ });
576
+ return this.store.list;
577
+ }
578
+ }
579
+ normalizeOrderForMemoryList(order, source = "normalizeOrderForMemoryList") {
580
+ const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, source);
581
+ const externalSaleNumber = normalizedOrder == null ? void 0 : normalizedOrder.external_sale_number;
582
+ if ((normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== void 0 && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== null && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== "") {
583
+ return normalizedOrder;
584
+ }
585
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
586
+ return normalizedOrder;
587
+ }
588
+ return {
589
+ ...normalizedOrder,
590
+ order_id: externalSaleNumber
591
+ };
592
+ }
593
+ /**
594
+ * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
595
+ * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
596
+ */
597
+ async overwriteExistingOrder(fresh) {
598
+ const orderId = fresh == null ? void 0 : fresh.order_id;
599
+ if (orderId === void 0 || orderId === null) {
600
+ this.logError("overwriteExistingOrder-入参缺少 order_id");
601
+ return { overwritten: false };
602
+ }
603
+ const key = this.getIdKey(orderId);
604
+ if (!this.store.map.has(key)) {
605
+ this.logInfo("overwriteExistingOrder-本地不存在该订单,跳过", { orderId });
606
+ return { overwritten: false };
607
+ }
608
+ this.logInfo("overwriteExistingOrder-开始覆盖", {
609
+ orderId,
610
+ storeOrderCountBefore: this.store.list.length
611
+ });
612
+ const normalizedFresh = this.normalizeOrderForMemoryList(
613
+ fresh,
614
+ "overwriteExistingOrder.incoming"
615
+ );
616
+ const existingOrder = this.store.map.get(key);
617
+ const reconciledFresh = this.reconcileOverwriteOrderCollections(
618
+ existingOrder,
619
+ normalizedFresh
620
+ );
621
+ this.store.list = this.store.list.map((order) => {
622
+ const id = order == null ? void 0 : order.order_id;
623
+ if (id === void 0 || id === null) {
624
+ return this.normalizeOrderForMemoryList(order, "overwriteExistingOrder.existingMemory");
625
+ }
626
+ return this.getIdKey(id) === key ? reconciledFresh : this.normalizeOrderForMemoryList(order, "overwriteExistingOrder.existingMemory");
627
+ });
628
+ this.syncOrdersMap();
629
+ await this.updateOrderInSQLite(reconciledFresh, "overwriteExistingOrder");
630
+ this.logInfo("overwriteExistingOrder-结束", {
631
+ orderId,
632
+ storeOrderCountAfter: this.store.list.length
633
+ });
634
+ await this.emitOrdersChanged([reconciledFresh], "overwriteExistingOrder");
635
+ return { overwritten: true };
636
+ }
637
+ /**
638
+ * 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
639
+ * 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
640
+ */
641
+ async upsertOrdersFromRemote(freshOrders) {
642
+ if (!(freshOrders == null ? void 0 : freshOrders.length)) {
643
+ this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
644
+ return;
645
+ }
646
+ this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
647
+ await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
648
+ }
649
+ async markOrderSyncedByExternalSaleNumber(params) {
650
+ const externalSaleNumber = params.externalSaleNumber;
651
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
652
+ this.logError("markOrderSyncedByExternalSaleNumber-缺少 external_sale_number");
653
+ return { updated: false };
654
+ }
655
+ const key = this.getIdKey(externalSaleNumber);
656
+ const targetIndex = this.store.list.findIndex((order) => {
657
+ const value = order == null ? void 0 : order.external_sale_number;
658
+ if (value === void 0 || value === null || value === "")
659
+ return false;
660
+ return this.getIdKey(value) === key;
661
+ });
662
+ if (targetIndex < 0) {
663
+ this.logInfo("markOrderSyncedByExternalSaleNumber-本地订单不存在,跳过", {
664
+ external_sale_number: externalSaleNumber
665
+ });
666
+ return { updated: false };
667
+ }
668
+ const existing = this.store.list[targetIndex];
669
+ const nextOrder = this.normalizeRemoteSyncedOrder({
670
+ ...existing,
671
+ ...params.patch || {},
672
+ external_sale_number: existing.external_sale_number ?? externalSaleNumber,
673
+ need_sync: 0
674
+ });
675
+ const storageKey = this.getOrderStorageKey(nextOrder) || key;
676
+ this.store.list = this.store.list.map((order, index) => {
677
+ if (index !== targetIndex)
678
+ return order;
679
+ return nextOrder;
680
+ });
681
+ this.syncOrdersMap();
682
+ await this.patchOrdersInSQLite(
683
+ [nextOrder],
684
+ "markOrderSyncedByExternalSaleNumber",
685
+ { [storageKey]: "update" }
686
+ );
687
+ this.logInfo("markOrderSyncedByExternalSaleNumber-完成", {
688
+ external_sale_number: externalSaleNumber,
689
+ order_id: nextOrder.order_id ?? null
690
+ });
691
+ await this.emitOrdersChanged([nextOrder], "markOrderSyncedByExternalSaleNumber");
692
+ return { updated: true, order: nextOrder };
693
+ }
694
+ /**
695
+ * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
696
+ * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
697
+ */
698
+ async upsertPendingSyncOrders(pendingOrders) {
699
+ if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
700
+ this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
701
+ return;
702
+ }
703
+ const pendingMap = /* @__PURE__ */ new Map();
704
+ const memoryPendingMap = /* @__PURE__ */ new Map();
705
+ for (const order of pendingOrders) {
706
+ const normalizedOrder = this.normalizeOrderCollectionsForIngress(
707
+ order,
708
+ "upsertPendingSyncOrders.incoming"
709
+ );
710
+ const storageKey = this.getOrderStorageKey(normalizedOrder);
711
+ if (!storageKey)
712
+ continue;
713
+ pendingMap.set(storageKey, normalizedOrder);
714
+ memoryPendingMap.set(
715
+ storageKey,
716
+ this.normalizeOrderForMemoryList(
717
+ normalizedOrder,
718
+ "upsertPendingSyncOrders.memory"
719
+ )
720
+ );
721
+ }
722
+ if (pendingMap.size === 0) {
723
+ this.logError("upsertPendingSyncOrders-订单缺少可落库标识", {
724
+ count: pendingOrders.length
725
+ });
726
+ return;
727
+ }
728
+ this.logInfo("upsertPendingSyncOrders-开始", { count: pendingMap.size });
729
+ const mergeActions = {};
730
+ const updatedList = this.store.list.map(
731
+ (order) => this.normalizeOrderForMemoryList(order, "upsertPendingSyncOrders.existingMemory")
732
+ );
733
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
734
+ for (let index = 0; index < updatedList.length; index += 1) {
735
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
736
+ if (!identityKeyToIndex.has(key))
737
+ identityKeyToIndex.set(key, index);
738
+ }
739
+ }
740
+ for (const [storageKey, pendingOrder] of memoryPendingMap.entries()) {
741
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(
742
+ identityKeyToIndex,
743
+ this.getOrderIdentityMatchKeys(pendingOrder)
744
+ );
745
+ if (matchIndex >= 0) {
746
+ const existingOrder = updatedList[matchIndex];
747
+ const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
748
+ updatedList[matchIndex] = mergedOrder;
749
+ const pendingSnapshot = pendingMap.get(storageKey);
750
+ if (pendingSnapshot) {
751
+ pendingMap.set(
752
+ storageKey,
753
+ this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
754
+ );
755
+ }
756
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
757
+ mergeActions[storageKey] = "update";
758
+ continue;
759
+ }
760
+ const insertIndex = updatedList.length;
761
+ updatedList.push(pendingOrder);
762
+ this.registerOrderIdentityKeys(identityKeyToIndex, pendingOrder, insertIndex);
763
+ mergeActions[storageKey] = "insert";
764
+ }
765
+ const patchedOrders = [...pendingMap.values()];
766
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
767
+ this.syncOrdersMap();
768
+ await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
769
+ this.logInfo("upsertPendingSyncOrders-结束", {
770
+ count: patchedOrders.length,
771
+ storeOrderCountAfter: this.store.list.length
772
+ });
773
+ await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
774
+ }
775
+ /**
776
+ * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
777
+ */
778
+ async fetchOrdersBySSE(query = {}) {
779
+ if (!this.orderDataSource)
780
+ return [];
781
+ try {
782
+ const data = await this.orderDataSource.run({ sse: { query } });
783
+ return data || [];
784
+ } catch (error) {
785
+ this.logError("fetchOrdersBySSE-失败", {
786
+ error: error instanceof Error ? error.message : String(error)
787
+ });
788
+ return [];
789
+ }
190
790
  }
191
791
  getRoutes() {
192
792
  return [];
193
793
  }
194
794
  destroy() {
795
+ var _a;
195
796
  if (this.syncTimer) {
196
797
  clearTimeout(this.syncTimer);
197
- this.syncTimer = undefined;
798
+ this.syncTimer = void 0;
198
799
  }
800
+ this.isProcessingSyncBatch = false;
199
801
  this.pendingSyncMessages = [];
200
- if (this.orderDataSource?.destroy) this.orderDataSource.destroy();
802
+ if ((_a = this.orderDataSource) == null ? void 0 : _a.destroy)
803
+ this.orderDataSource.destroy();
201
804
  super.destroy();
202
805
  }
203
806
  syncOrdersMap() {
204
807
  this.store.map.clear();
205
- this.resourceIdIndex.clear();
206
808
  for (const order of this.store.list) {
207
- const id = order.order_id;
208
- if (id === undefined || id === null) continue;
209
- this.store.map.set(this.getIdKey(id), order);
210
- const resourceIds = this.extractResourceIds(order);
211
- for (const resourceId of resourceIds) {
212
- const key = String(resourceId);
213
- const existing = this.resourceIdIndex.get(key) || [];
214
- if (existing.some(eid => this.getIdKey(eid) === this.getIdKey(id))) continue;
215
- existing.push(id);
216
- this.resourceIdIndex.set(key, existing);
217
- }
218
- }
219
- }
220
- extractResourceIds(order) {
221
- const ids = new Set();
222
- const visitResources = resources => {
223
- if (!Array.isArray(resources)) return;
224
- resources.forEach(resource => {
225
- const rid = resource?.relation_id;
226
- if (rid !== undefined && rid !== null && rid !== '') ids.add(String(rid));
227
- if (Array.isArray(resource?.children)) visitResources(resource.children);
228
- });
229
- };
230
- if (Array.isArray(order?.bookings)) {
231
- order.bookings.forEach(booking => visitResources(booking?.resources || []));
809
+ const primaryIdentity = this.getOrderMapKey(order);
810
+ if (!primaryIdentity)
811
+ continue;
812
+ this.store.map.set(primaryIdentity, order);
813
+ }
814
+ }
815
+ getOrderMapKey(order) {
816
+ if (!order)
817
+ return "";
818
+ if (!this.isBlankIdentityValue(order.order_id)) {
819
+ return this.getIdKey(order.order_id);
820
+ }
821
+ const externalSaleNumber = order.external_sale_number;
822
+ if (!this.isBlankIdentityValue(externalSaleNumber)) {
823
+ return this.getIdKey(externalSaleNumber);
824
+ }
825
+ return "";
826
+ }
827
+ isBlankIdentityValue(value) {
828
+ return value === void 0 || value === null || value === "";
829
+ }
830
+ getOrderIdentityEntries(order) {
831
+ if (!order)
832
+ return [];
833
+ const record = order;
834
+ const candidates = [
835
+ { field: "order_id", value: order.order_id },
836
+ { field: "external_sale_number", value: record.external_sale_number },
837
+ { field: "order_number", value: record.order_number },
838
+ { field: "shop_order_number", value: record.shop_order_number }
839
+ ];
840
+ const entries = [];
841
+ for (const candidate of candidates) {
842
+ if (this.isBlankIdentityValue(candidate.value))
843
+ continue;
844
+ const key = this.getIdKey(candidate.value);
845
+ if (entries.some((entry) => entry.field === candidate.field && entry.key === key))
846
+ continue;
847
+ entries.push({ field: candidate.field, key });
848
+ }
849
+ return entries;
850
+ }
851
+ getOrderIdentityKeys(order) {
852
+ const keys = [];
853
+ for (const entry of this.getOrderIdentityEntries(order)) {
854
+ if (!keys.includes(entry.key))
855
+ keys.push(entry.key);
232
856
  }
233
- return [...ids];
857
+ return keys;
234
858
  }
235
859
  getOrderDateKey(order) {
236
- const candidates = [order?.schedule_date, order?.create_date, order?.created_at, order?.bookings?.[0]?.start_date, order?.bookings?.[0]?.select_date];
860
+ var _a, _b, _c, _d;
861
+ const candidates = [
862
+ order == null ? void 0 : order.schedule_date,
863
+ order == null ? void 0 : order.create_date,
864
+ order == null ? void 0 : order.created_at,
865
+ (_b = (_a = order == null ? void 0 : order.bookings) == null ? void 0 : _a[0]) == null ? void 0 : _b.start_date,
866
+ (_d = (_c = order == null ? void 0 : order.bookings) == null ? void 0 : _c[0]) == null ? void 0 : _d.select_date
867
+ ];
237
868
  for (const v of candidates) {
238
- if (!v) continue;
869
+ if (!v)
870
+ continue;
239
871
  const text = String(v);
240
- if (!text) continue;
241
- return text.split('T')[0].split(' ')[0];
872
+ if (!text)
873
+ continue;
874
+ return text.split("T")[0].split(" ")[0];
242
875
  }
243
- return undefined;
876
+ return void 0;
244
877
  }
245
-
246
878
  /**
247
879
  * 初始化 OrderDataSource 实例
248
880
  */
249
881
  initOrderDataSource() {
250
- const OrderDataSourceClass = this.core.serverOptions?.All_DATA_SOURCES?.OrderDataSource;
251
- if (!OrderDataSourceClass) return;
882
+ var _a, _b;
883
+ const OrderDataSourceClass = (_b = (_a = this.core.serverOptions) == null ? void 0 : _a.All_DATA_SOURCES) == null ? void 0 : _b.OrderDataSource;
884
+ if (!OrderDataSourceClass)
885
+ return;
252
886
  this.orderDataSource = new OrderDataSourceClass();
253
887
  }
254
-
255
888
  /**
256
- * 初始化 pubsub 订阅,监听订单变更
889
+ * 初始化 pubsub 订阅,监听订单变更(纯订阅,不拉数据;全量 SSE 由 loadOrdersByServer 负责)
257
890
  */
258
891
  setupOrderSync() {
259
- if (!this.orderDataSource) return;
260
- const shouldSkipHttpPull = this.hasPulledOrdersToday();
261
- const syncPayload = {
892
+ if (!this.orderDataSource)
893
+ return;
894
+ this.orderDataSource.run({
262
895
  pubsub: {
263
- callback: res => {
896
+ callback: (res) => {
897
+ console.log("orderDataSource", res);
898
+ const pubsubReceivedAt = Date.now();
264
899
  const message = this.normalizeOrderSyncMessage(res);
265
- if (!message) return;
900
+ if (!message)
901
+ return;
902
+ message._pubsubReceivedAt = pubsubReceivedAt;
266
903
  this.pendingSyncMessages.push(message);
267
- if (this.syncTimer) clearTimeout(this.syncTimer);
268
- this.syncTimer = setTimeout(() => {
269
- this.processOrderSyncMessages();
270
- }, this.ORDER_SYNC_DEBOUNCE_MS);
904
+ const throttleMs = this.getOrderSyncThrottleMs();
905
+ const routeInfo = this.resolveSyncMessageRoute(message);
906
+ this.logInfo("orderSync-收到消息并入队", {
907
+ id: message.id ?? null,
908
+ order_id: message.order_id ?? null,
909
+ type: message.type ?? null,
910
+ pendingCount: this.pendingSyncMessages.length,
911
+ throttleMs,
912
+ pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString(),
913
+ fullMessage: JSON.stringify(message)
914
+ });
915
+ this.scheduleOrderSyncThrottle();
271
916
  }
272
917
  }
273
- };
274
- syncPayload.http = {
275
- query: this.store.createdAtQuery,
276
- skipHttp: shouldSkipHttpPull
277
- };
278
- this.orderDataSource.run(syncPayload).then(() => {
279
- if (!shouldSkipHttpPull) this.markOrderPulledAtNow();
280
918
  }).catch(() => {
281
- // 忽略同步初始化异常,避免影响主流程
282
919
  });
283
920
  }
284
-
285
921
  /**
286
- * 处理防抖后的同步消息批次
922
+ * 调度订单同步节流窗口(leading-edge throttle):
923
+ * - 空闲状态下收到的第一条消息立即触发批处理,无需等待;
924
+ * - 首条处理后进入冷却窗口,窗口期间的后续消息聚合,窗口结束后批量处理;
925
+ * - 若当前批处理执行中,则由批处理结束后决定是否开启下一轮窗口。
926
+ */
927
+ scheduleOrderSyncThrottle() {
928
+ if (this.isProcessingSyncBatch)
929
+ return;
930
+ if (this.isIdlePhase) {
931
+ this.isIdlePhase = false;
932
+ this.logInfo("orderSync-首条消息立即触发处理");
933
+ void this.flushOrderSyncMessagesByThrottle();
934
+ return;
935
+ }
936
+ if (this.syncTimer)
937
+ return;
938
+ const throttleMs = this.getOrderSyncThrottleMs();
939
+ this.syncTimer = setTimeout(() => {
940
+ this.syncTimer = void 0;
941
+ void this.flushOrderSyncMessagesByThrottle();
942
+ }, throttleMs);
943
+ }
944
+ /**
945
+ * 执行一次节流批处理并在需要时续约下一轮窗口。
946
+ * 批处理完成且无后续消息时恢复空闲状态,下一条消息将立即触发。
947
+ */
948
+ async flushOrderSyncMessagesByThrottle() {
949
+ if (this.isProcessingSyncBatch)
950
+ return;
951
+ if (this.pendingSyncMessages.length === 0) {
952
+ this.isIdlePhase = true;
953
+ return;
954
+ }
955
+ this.isProcessingSyncBatch = true;
956
+ try {
957
+ await this.processOrderSyncMessages();
958
+ } finally {
959
+ this.isProcessingSyncBatch = false;
960
+ if (this.pendingSyncMessages.length > 0) {
961
+ this.scheduleOrderSyncThrottle();
962
+ } else {
963
+ this.isIdlePhase = true;
964
+ }
965
+ }
966
+ }
967
+ /**
968
+ * 处理节流窗口内聚合后的同步消息批次
287
969
  *
288
970
  * 后端统一发送 change 消息,不再区分新增/编辑/删除。
289
971
  * - 单条(id/order_id):若携带 body/data 则直接 upsert 到本地
290
972
  * - 批量(ids):通过 HTTP 按 ids 增量拉取,再 merge 到本地
973
+ *
974
+ * @example
975
+ * // pending 队列中存在 8 条消息时,仅处理一次批次并统一 merge
976
+ * await this.processOrderSyncMessages()
291
977
  */
292
978
  async processOrderSyncMessages() {
293
979
  const messages = [...this.pendingSyncMessages];
294
980
  this.pendingSyncMessages = [];
295
- if (messages.length === 0) return;
296
- const upsertOrders = new Map();
981
+ if (messages.length === 0)
982
+ return;
983
+ const batchProcessStartAt = Date.now();
984
+ const earliestReceivedAt = Math.min(
985
+ ...messages.map((m) => m._pubsubReceivedAt ?? batchProcessStartAt)
986
+ );
987
+ this.logInfo("processOrderSyncMessages-开始", {
988
+ messageCount: messages.length,
989
+ earliestReceivedAt: new Date(earliestReceivedAt).toISOString(),
990
+ batchProcessStartAt: new Date(batchProcessStartAt).toISOString(),
991
+ waitDurationMs: batchProcessStartAt - earliestReceivedAt
992
+ });
993
+ const upsertOrders = /* @__PURE__ */ new Map();
297
994
  const refreshIds = [];
298
- for (const msg of messages) {
299
- const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
300
- const singleId = msg.id ?? msg.order_id;
301
- const hasSingleId = !hasBatchIds && singleId !== undefined && singleId !== null;
302
- const rawBody = msg.body || msg.data;
303
- const normalizedBody = this.normalizeOrderSyncPayload(rawBody);
304
- if (hasSingleId && normalizedBody) {
995
+ messages.forEach((msg, msgIndex) => {
996
+ const routeInfo = this.resolveSyncMessageRoute(msg);
997
+ const hasBatchIds = routeInfo.hasBatchIds;
998
+ const singleId = routeInfo.singleId;
999
+ const hasSingleId = routeInfo.hasSingleId;
1000
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
1001
+ if (routeInfo.route === "bodyUpsert" && normalizedBody) {
305
1002
  upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
306
- continue;
1003
+ return;
307
1004
  }
308
- if (hasBatchIds) refreshIds.push(...msg.ids);else if (hasSingleId) refreshIds.push(singleId);else if (msg.relation_order_ids?.length) refreshIds.push(...msg.relation_order_ids);
309
- }
1005
+ if (hasBatchIds)
1006
+ refreshIds.push(...routeInfo.batchIds);
1007
+ else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
1008
+ refreshIds.push(singleId);
1009
+ else if (routeInfo.route === "httpRefresh.relationIds")
1010
+ refreshIds.push(...routeInfo.batchIds);
1011
+ });
310
1012
  const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
311
1013
  const upsertList = [...upsertOrders.values()];
312
- if (upsertList.length > 0) await this.mergeOrdersToStore(upsertList);
1014
+ this.logInfo("processOrderSyncMessages-去重完成", {
1015
+ upsertCount: upsertList.length,
1016
+ refreshIdCount: uniqueRefreshIds.length
1017
+ });
1018
+ if (upsertList.length > 0) {
1019
+ await this.mergeOrdersToStore(upsertList, "pubsub.bodyUpsert");
1020
+ }
313
1021
  if (uniqueRefreshIds.length > 0) {
314
- const freshOrders = await this.fetchOrdersByHttp(uniqueRefreshIds);
315
- if (freshOrders.length > 0) await this.mergeOrdersToStore(freshOrders);
1022
+ const { toFetch, skipped } = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
1023
+ if (skipped.length > 0) {
1024
+ }
1025
+ if (toFetch.length > 0) {
1026
+ const freshOrders = await this.fetchOrdersByHttp(toFetch);
1027
+ if (freshOrders.length > 0) {
1028
+ await this.mergeOrdersToStore(freshOrders, "pubsub.httpRefresh");
1029
+ } else {
1030
+ }
1031
+ }
316
1032
  }
317
- if (upsertList.length === 0 && uniqueRefreshIds.length === 0) return;
318
- await this.core.effects.emit(_types.OrderHooks.onOrdersSyncCompleted, null);
1033
+ if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
1034
+ return;
1035
+ }
1036
+ const batchProcessEndAt = Date.now();
1037
+ this.logInfo("processOrderSyncMessages-结束", {
1038
+ upsertCount: upsertList.length,
1039
+ refreshIdCount: uniqueRefreshIds.length,
1040
+ batchProcessDurationMs: batchProcessEndAt - batchProcessStartAt,
1041
+ totalFromPubsubToProcessedMs: batchProcessEndAt - earliestReceivedAt
1042
+ });
1043
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
319
1044
  }
320
-
321
1045
  /**
322
- * 通过 HTTP 按 ids 增量拉取订单
1046
+ * 通过 HTTP 按 ids 批量拉取订单详情(走 orderDataSource)。
1047
+ *
1048
+ * - 优先使用 `orderDataSource.fetchOrdersByIds`(如适配器实现了该方法)
1049
+ * - 否则回退到 `orderDataSource.run({ http: { query: { ids } } })`
1050
+ * - 失败统一返回空数组(由调用方按"返回缺失的 id" 判断单笔失败)
1051
+ *
1052
+ * @example
1053
+ * const fresh = await orderModule.fetchOrdersByHttp(['96971', '96972'])
323
1054
  */
324
1055
  async fetchOrdersByHttp(ids) {
325
- if (!this.orderDataSource || ids.length === 0) return [];
1056
+ if (!this.orderDataSource || ids.length === 0)
1057
+ return [];
326
1058
  try {
327
- if (typeof this.orderDataSource.fetchOrdersByIds === 'function') {
328
- const orderList = await this.orderDataSource.fetchOrdersByIds(ids);
329
- return orderList || [];
1059
+ if (typeof this.orderDataSource.fetchOrdersByIds === "function") {
1060
+ const orderList2 = await this.orderDataSource.fetchOrdersByIds(ids);
1061
+ return orderList2 || [];
330
1062
  }
331
1063
  const orderList = await this.orderDataSource.run({
332
1064
  http: {
333
- query: {
334
- ids
335
- }
1065
+ query: { ids }
336
1066
  }
337
1067
  });
338
1068
  return orderList || [];
@@ -340,62 +1070,177 @@ class OrderModule extends _BaseModule.BaseModule {
340
1070
  return [];
341
1071
  }
342
1072
  }
343
-
344
1073
  /**
345
1074
  * 将增量订单合并到 store
346
1075
  */
347
- async mergeOrdersToStore(freshOrders) {
348
- const freshMap = new Map();
349
- for (const order of freshOrders) {
350
- const id = order?.order_id;
351
- if (id === undefined || id === null) continue;
352
- freshMap.set(this.getIdKey(id), order);
353
- }
354
- const updatedList = this.store.list.map(order => {
355
- const id = order.order_id;
356
- if (id === undefined || id === null) return order;
357
- const key = this.getIdKey(id);
358
- if (!freshMap.has(key)) return order;
359
- const fresh = freshMap.get(key);
360
- freshMap.delete(key);
361
- return fresh;
1076
+ async mergeOrdersToStore(freshOrders, source) {
1077
+ const storeOrderCountBefore = this.store.list.length;
1078
+ this.logInfo("mergeOrdersToStore-开始", {
1079
+ freshOrderCount: freshOrders.length,
1080
+ storeOrderCountBefore,
1081
+ source
362
1082
  });
363
- for (const order of freshMap.values()) {
364
- updatedList.push(order);
1083
+ this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
1084
+ const normalizedFreshOrders = [];
1085
+ for (const order of freshOrders) {
1086
+ const id = order == null ? void 0 : order.order_id;
1087
+ if (id === void 0 || id === null)
1088
+ continue;
1089
+ normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
1090
+ }
1091
+ const uniqueFreshOrders = this.compactOrderListByIdentity(
1092
+ normalizedFreshOrders,
1093
+ `${source}.incoming`
1094
+ ).list;
1095
+ const uniqueFreshCount = uniqueFreshOrders.length;
1096
+ const patchedOrders = [];
1097
+ const mergeActions = {};
1098
+ const updatedList = this.store.list.map(
1099
+ (order) => this.normalizeOrderForMemoryList(order, `${source}.existingMemory`)
1100
+ );
1101
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
1102
+ for (let index = 0; index < updatedList.length; index += 1) {
1103
+ const identityKeys = this.getOrderIdentityMatchKeys(updatedList[index]);
1104
+ for (const key of identityKeys) {
1105
+ if (!identityKeyToIndex.has(key))
1106
+ identityKeyToIndex.set(key, index);
1107
+ }
1108
+ }
1109
+ for (const fresh of uniqueFreshOrders) {
1110
+ const freshIdentityKeys = this.getOrderIdentityMatchKeys(fresh);
1111
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys);
1112
+ const storageKey = this.getOrderStorageKey(fresh);
1113
+ const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
1114
+ if (matchIndex >= 0) {
1115
+ const existingOrder = updatedList[matchIndex];
1116
+ if (this.isPendingSyncOrder(existingOrder) && this.isRemoteEchoMergeSource(source)) {
1117
+ this.logInfo("mergeOrdersToStore-跳过 pending 订单远端覆盖", {
1118
+ source,
1119
+ order_id: existingOrder.order_id ?? fresh.order_id ?? null,
1120
+ external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
1121
+ local_payment_status: existingOrder.payment_status ?? null,
1122
+ remote_payment_status: fresh.payment_status ?? null,
1123
+ local_need_sync: existingOrder.need_sync ?? null,
1124
+ remote_need_sync: fresh.need_sync ?? null,
1125
+ reason: "protect_pending_sync_order_from_remote_echo"
1126
+ });
1127
+ continue;
1128
+ }
1129
+ const mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1130
+ updatedList[matchIndex] = mergedOrder;
1131
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
1132
+ patchedOrders.push(mergedOrder);
1133
+ if (mergeKey)
1134
+ mergeActions[mergeKey] = "update";
1135
+ continue;
1136
+ }
1137
+ const insertIndex = updatedList.length;
1138
+ updatedList.push(fresh);
1139
+ this.registerOrderIdentityKeys(identityKeyToIndex, fresh, insertIndex);
1140
+ patchedOrders.push(fresh);
1141
+ if (mergeKey)
1142
+ mergeActions[mergeKey] = "insert";
365
1143
  }
366
- this.store.list = updatedList;
1144
+ const insertCount = Object.values(mergeActions).filter((v) => v === "insert").length;
1145
+ const updateCount = Object.values(mergeActions).filter((v) => v === "update").length;
1146
+ this.logInfo("mergeOrdersToStore-合并完成", {
1147
+ insertCount,
1148
+ updateCount,
1149
+ storeOrderCountAfter: this.store.list.length
1150
+ });
1151
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, `${source}.store`);
367
1152
  this.syncOrdersMap();
368
- await this.saveOrdersToSQLite(this.store.list);
369
- this.core.effects.emit(_types.OrderHooks.onOrdersChanged, this.store.list);
1153
+ await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
1154
+ this.logInfo("mergeOrdersToStore-结束", {
1155
+ uniqueFreshCount,
1156
+ storeOrderCountAfter: this.store.list.length,
1157
+ insertCount,
1158
+ updateCount
1159
+ });
1160
+ await this.emitOrdersChanged(patchedOrders, source);
1161
+ }
1162
+ /**
1163
+ * 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
1164
+ * 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
1165
+ *
1166
+ * @example
1167
+ * const idx = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys)
1168
+ */
1169
+ lookupOrderIndexByIdentityKeys(identityKeyToIndex, identityKeys) {
1170
+ let matchIndex = -1;
1171
+ for (const key of identityKeys) {
1172
+ const index = identityKeyToIndex.get(key);
1173
+ if (index === void 0)
1174
+ continue;
1175
+ if (matchIndex < 0 || index < matchIndex)
1176
+ matchIndex = index;
1177
+ }
1178
+ return matchIndex;
1179
+ }
1180
+ isRemoteEchoMergeSource(source) {
1181
+ return source === "pubsub.bodyUpsert" || source === "pubsub.httpRefresh";
1182
+ }
1183
+ /**
1184
+ * 将订单的全部身份键登记到索引并指向其在列表中的下标。
1185
+ * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
1186
+ *
1187
+ * @example
1188
+ * this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex)
1189
+ */
1190
+ registerOrderIdentityKeys(identityKeyToIndex, order, index) {
1191
+ const identityKeys = this.getOrderIdentityMatchKeys(order);
1192
+ for (const key of identityKeys) {
1193
+ identityKeyToIndex.set(key, index);
1194
+ }
1195
+ }
1196
+ /**
1197
+ * 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
1198
+ * 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
1199
+ */
1200
+ runOrderStoreSelfCheck(orders, source) {
1201
+ if (!ORDER_MERGE_SELF_CHECK)
1202
+ return orders;
1203
+ const { list, removedCount } = this.compactOrderListByIdentity(orders, source);
1204
+ if (removedCount > 0) {
1205
+ this.logWarning("合并自检发现残留重复订单,已压缩", { source, removedCount });
1206
+ }
1207
+ return list;
370
1208
  }
371
1209
  normalizeOrderSyncMessage(res) {
372
- const data = res?.data || res;
373
- if (!data) return null;
374
- const payload = data?.data && typeof data.data === 'object' ? data.data : undefined;
1210
+ const data = (res == null ? void 0 : res.data) || res;
1211
+ if (!data)
1212
+ return null;
1213
+ const payload = (data == null ? void 0 : data.data) && typeof data.data === "object" ? data.data : void 0;
375
1214
  const normalized = {
376
1215
  ...data,
377
- _channelKey: data.module || 'sales_sync'
1216
+ _channelKey: data.module || "sales_sync"
378
1217
  };
379
- if (!normalized.type && typeof data.event === 'string') normalized.type = data.event;
380
- if (!normalized.id && data.id !== undefined) normalized.id = data.id;
381
- if (!normalized.id && data.order_id !== undefined) normalized.id = data.order_id;
382
- if (!normalized.order_id && data.order_id !== undefined) normalized.order_id = data.order_id;
383
- if (!normalized.order_id && payload?.order_id !== undefined) normalized.order_id = payload.order_id;
384
- if (!normalized.body && payload?.order_id !== undefined) normalized.body = payload;
385
- if (!normalized.data && payload?.order_id !== undefined) normalized.data = payload;
1218
+ if (!normalized.type && typeof data.event === "string")
1219
+ normalized.type = data.event;
1220
+ if (!normalized.id && data.id !== void 0)
1221
+ normalized.id = data.id;
1222
+ if (!normalized.id && data.order_id !== void 0)
1223
+ normalized.id = data.order_id;
1224
+ if (!normalized.order_id && data.order_id !== void 0)
1225
+ normalized.order_id = data.order_id;
1226
+ if (!normalized.order_id && (payload == null ? void 0 : payload.order_id) !== void 0)
1227
+ normalized.order_id = payload.order_id;
1228
+ if (!normalized.body && (payload == null ? void 0 : payload.order_id) !== void 0)
1229
+ normalized.body = payload;
1230
+ if (!normalized.data && (payload == null ? void 0 : payload.order_id) !== void 0)
1231
+ normalized.data = payload;
386
1232
  return normalized;
387
1233
  }
388
1234
  normalizeOrderSyncPayload(payload) {
389
- if (!payload) return null;
1235
+ if (!payload)
1236
+ return null;
390
1237
  const orderId = payload.order_id;
391
- if (orderId === undefined || orderId === null) return null;
392
- return {
393
- ...payload,
394
- order_id: orderId
395
- };
1238
+ if (orderId === void 0 || orderId === null)
1239
+ return null;
1240
+ return { ...payload, order_id: orderId };
396
1241
  }
397
1242
  uniqueOrderIds(ids) {
398
- const idMap = new Map();
1243
+ const idMap = /* @__PURE__ */ new Map();
399
1244
  for (const id of ids) {
400
1245
  idMap.set(this.getIdKey(id), id);
401
1246
  }
@@ -404,104 +1249,517 @@ class OrderModule extends _BaseModule.BaseModule {
404
1249
  getIdKey(id) {
405
1250
  return String(id);
406
1251
  }
407
-
1252
+ isOrderLookupMatch(order, lookupKey) {
1253
+ if (!order || !lookupKey)
1254
+ return false;
1255
+ const candidates = [
1256
+ order.order_id,
1257
+ order.external_sale_number,
1258
+ order.order_number,
1259
+ order.shop_order_number,
1260
+ order.shop_full_order_number
1261
+ ];
1262
+ return candidates.some((value) => {
1263
+ if (value === void 0 || value === null || value === "")
1264
+ return false;
1265
+ return this.getIdKey(value) === lookupKey;
1266
+ });
1267
+ }
1268
+ /**
1269
+ * 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
1270
+ *
1271
+ * @example
1272
+ * const key = this.getOrderStorageKey({ order_id: 1001, external_sale_number: 'S-1001' })
1273
+ * // => 'S-1001'
1274
+ */
1275
+ getOrderStorageKey(order) {
1276
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
1277
+ if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
1278
+ return String(externalSaleNumber);
1279
+ }
1280
+ const orderId = order == null ? void 0 : order.order_id;
1281
+ if (orderId !== void 0 && orderId !== null && orderId !== "") {
1282
+ return String(orderId);
1283
+ }
1284
+ return "";
1285
+ }
1286
+ getOrderIdentityMatchKeys(order) {
1287
+ return this.getOrderIdentityEntries(order).map((entry) => `${entry.field}:${entry.key}`);
1288
+ }
1289
+ doOrdersShareIdentity(left, right) {
1290
+ const leftKeys = new Set(this.getOrderIdentityMatchKeys(left));
1291
+ if (leftKeys.size === 0)
1292
+ return false;
1293
+ return this.getOrderIdentityMatchKeys(right).some((key) => leftKeys.has(key));
1294
+ }
1295
+ findOrderIndexByIdentity(orders, target) {
1296
+ if (this.getOrderIdentityMatchKeys(target).length === 0)
1297
+ return -1;
1298
+ return orders.findIndex((order) => this.doOrdersShareIdentity(order, target));
1299
+ }
1300
+ getOrderCompletenessScore(order) {
1301
+ const record = order;
1302
+ let score = this.isPendingSyncOrder(order) ? 0 : 100;
1303
+ if (!this.isBlankIdentityValue(order.order_id) && order.order_id !== record.external_sale_number)
1304
+ score += 30;
1305
+ score += this.getOrderIdentityMatchKeys(order).length * 5;
1306
+ if (Array.isArray(order.products))
1307
+ score += Math.min(order.products.length, 10);
1308
+ if (Array.isArray(order.bookings))
1309
+ score += Math.min(order.bookings.length, 10);
1310
+ if (Array.isArray(order.payments))
1311
+ score += Math.min(order.payments.length, 10);
1312
+ if (record.updated_at)
1313
+ score += 1;
1314
+ return score;
1315
+ }
1316
+ pickPreferredOrder(left, right) {
1317
+ const leftScore = this.getOrderCompletenessScore(left);
1318
+ const rightScore = this.getOrderCompletenessScore(right);
1319
+ if (rightScore >= leftScore)
1320
+ return right;
1321
+ return left;
1322
+ }
1323
+ mergeOrderRecords(existing, incoming) {
1324
+ const preferred = this.pickPreferredOrder(existing, incoming);
1325
+ const secondary = preferred === existing ? incoming : existing;
1326
+ const merged = {
1327
+ ...secondary,
1328
+ ...preferred
1329
+ };
1330
+ const fieldsToPreserve = [
1331
+ "order_id",
1332
+ "external_sale_number",
1333
+ "order_number",
1334
+ "shop_order_number",
1335
+ "shop_full_order_number"
1336
+ ];
1337
+ const incomingPatchFields = [
1338
+ "payment_status",
1339
+ "status",
1340
+ "shipping_status",
1341
+ "updated_at",
1342
+ "shop_discount",
1343
+ "summary",
1344
+ "note",
1345
+ "customer_id",
1346
+ "customer_name",
1347
+ "customer",
1348
+ "holder",
1349
+ "contacts_info",
1350
+ "phone",
1351
+ "email",
1352
+ "relation_forms"
1353
+ ];
1354
+ const mergedRecord = merged;
1355
+ const preferredRecord = preferred;
1356
+ const secondaryRecord = secondary;
1357
+ const existingRecord = existing;
1358
+ const incomingRecord = incoming;
1359
+ const childUidRemaps = [];
1360
+ for (const field of fieldsToPreserve) {
1361
+ if (!this.isBlankIdentityValue(preferredRecord[field])) {
1362
+ mergedRecord[field] = preferredRecord[field];
1363
+ continue;
1364
+ }
1365
+ if (!this.isBlankIdentityValue(secondaryRecord[field])) {
1366
+ mergedRecord[field] = secondaryRecord[field];
1367
+ }
1368
+ }
1369
+ for (const field of incomingPatchFields) {
1370
+ if (!Object.prototype.hasOwnProperty.call(incomingRecord, field))
1371
+ continue;
1372
+ if (incomingRecord[field] === void 0 || incomingRecord[field] === null)
1373
+ continue;
1374
+ if (typeof incomingRecord[field] === "string" && incomingRecord[field] === "")
1375
+ continue;
1376
+ mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
1377
+ }
1378
+ for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
1379
+ if (Array.isArray(incomingRecord[field])) {
1380
+ mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
1381
+ field,
1382
+ existingRecord[field],
1383
+ incomingRecord[field],
1384
+ childUidRemaps
1385
+ );
1386
+ continue;
1387
+ }
1388
+ if (Object.prototype.hasOwnProperty.call(existingRecord, field)) {
1389
+ mergedRecord[field] = (0, import_lodash_es.cloneDeep)(existingRecord[field]);
1390
+ } else {
1391
+ delete mergedRecord[field];
1392
+ }
1393
+ }
1394
+ if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
1395
+ merged.need_sync = 0;
1396
+ }
1397
+ return this.normalizeOrderCollectionsForIngress(
1398
+ (0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(merged, childUidRemaps),
1399
+ "mergeOrderRecords"
1400
+ );
1401
+ }
1402
+ summarizeDuplicateOrders(orders) {
1403
+ const groups = /* @__PURE__ */ new Map();
1404
+ for (const order of orders) {
1405
+ for (const key of this.getOrderIdentityMatchKeys(order)) {
1406
+ const group = groups.get(key) || [];
1407
+ group.push(order);
1408
+ groups.set(key, group);
1409
+ }
1410
+ }
1411
+ return [...groups.entries()].filter(([, group]) => group.length > 1).slice(0, 20).map(([key, group]) => ({
1412
+ key,
1413
+ count: group.length,
1414
+ orders: group.map((order) => ({
1415
+ order_id: order.order_id ?? null,
1416
+ external_sale_number: order.external_sale_number ?? null,
1417
+ shop_order_number: order.shop_order_number ?? null,
1418
+ shop_full_order_number: order.shop_full_order_number ?? null,
1419
+ need_sync: order.need_sync ?? null
1420
+ }))
1421
+ }));
1422
+ }
1423
+ logDuplicateOrders(source, orders) {
1424
+ const duplicateGroups = this.summarizeDuplicateOrders(orders);
1425
+ if (duplicateGroups.length === 0)
1426
+ return;
1427
+ this.logWarning("检测到重复订单身份键", {
1428
+ source,
1429
+ duplicateGroupCount: duplicateGroups.length,
1430
+ duplicateGroups
1431
+ });
1432
+ }
1433
+ compactOrderListByIdentity(orders, source) {
1434
+ const list = [];
1435
+ let removedCount = 0;
1436
+ for (const order of orders) {
1437
+ const normalizedOrder = this.normalizeOrderCollectionsForIngress(
1438
+ order,
1439
+ `${source}.order`
1440
+ );
1441
+ const matchIndex = this.findOrderIndexByIdentity(list, normalizedOrder);
1442
+ if (matchIndex < 0) {
1443
+ list.push(normalizedOrder);
1444
+ continue;
1445
+ }
1446
+ list[matchIndex] = this.mergeOrderRecords(list[matchIndex], normalizedOrder);
1447
+ removedCount += 1;
1448
+ }
1449
+ if (removedCount > 0) {
1450
+ this.logWarning("订单列表重复项已压缩", {
1451
+ source,
1452
+ beforeCount: orders.length,
1453
+ afterCount: list.length,
1454
+ removedCount
1455
+ });
1456
+ } else {
1457
+ this.logDuplicateOrders(source, orders);
1458
+ }
1459
+ return { list, removedCount };
1460
+ }
408
1461
  /**
409
1462
  * 当前订单拉取窗口:
410
1463
  * - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
411
1464
  * - 无法解析时退化为自然日窗口
412
1465
  */
413
1466
  getCurrentPullWindow() {
414
- const now = (0, _dayjs.default)();
415
- const range = this.store?.createdAtQuery?.sales_time_between;
1467
+ var _a, _b;
1468
+ const now = (0, import_dayjs.default)();
1469
+ const range = (_b = (_a = this.store) == null ? void 0 : _a.createdAtQuery) == null ? void 0 : _b.sales_time_between;
416
1470
  if (Array.isArray(range) && range.length >= 2) {
417
- const startAt = (0, _dayjs.default)(range[0]);
418
- const endExclusiveAt = (0, _dayjs.default)(range[1]);
419
- if (startAt.isValid() && endExclusiveAt.isValid() && endExclusiveAt.isAfter(startAt)) {
420
- return {
421
- startAt,
422
- endExclusiveAt
423
- };
1471
+ const startAt2 = (0, import_dayjs.default)(range[0]);
1472
+ const endExclusiveAt = (0, import_dayjs.default)(range[1]);
1473
+ if (startAt2.isValid() && endExclusiveAt.isValid() && endExclusiveAt.isAfter(startAt2)) {
1474
+ return { startAt: startAt2, endExclusiveAt };
424
1475
  }
425
1476
  }
426
- const startAt = now.startOf('day');
427
- return {
428
- startAt,
429
- endExclusiveAt: startAt.add(1, 'day')
430
- };
1477
+ const startAt = now.startOf("day");
1478
+ return { startAt, endExclusiveAt: startAt.add(1, "day") };
431
1479
  }
432
1480
  hasPulledOrdersToday() {
433
1481
  const lastFullFetchAt = this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY);
434
- if (!lastFullFetchAt) return false;
435
- const parsed = (0, _dayjs.default)(lastFullFetchAt);
436
- if (!parsed.isValid()) return false;
437
-
438
- // 按当前拉取窗口判断,而不是自然日判断。
439
- // 这样在营业日跨日边界(start_time)场景下也能正确判定是否需要重新拉取。
440
- const {
441
- startAt,
442
- endExclusiveAt
443
- } = this.getCurrentPullWindow();
1482
+ if (!lastFullFetchAt)
1483
+ return false;
1484
+ const parsed = (0, import_dayjs.default)(lastFullFetchAt);
1485
+ if (!parsed.isValid())
1486
+ return false;
1487
+ const { startAt, endExclusiveAt } = this.getCurrentPullWindow();
444
1488
  return (parsed.isAfter(startAt) || parsed.isSame(startAt)) && parsed.isBefore(endExclusiveAt);
445
1489
  }
446
1490
  markOrderPulledAtNow() {
447
- this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss'));
1491
+ this.setStorageItem(
1492
+ ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY,
1493
+ (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
1494
+ );
448
1495
  }
449
1496
  getStorageItem(key) {
1497
+ var _a;
450
1498
  try {
451
- if (this.storage?.getStorage) return this.storage.getStorage(key);
452
- if (typeof globalThis !== 'undefined' && globalThis?.localStorage) {
1499
+ if ((_a = this.storage) == null ? void 0 : _a.getStorage)
1500
+ return this.storage.getStorage(key);
1501
+ if (typeof globalThis !== "undefined" && (globalThis == null ? void 0 : globalThis.localStorage)) {
453
1502
  return globalThis.localStorage.getItem(key);
454
1503
  }
455
1504
  } catch {
456
- // 忽略存储异常,避免影响主流程
457
1505
  }
458
1506
  return null;
459
1507
  }
460
1508
  setStorageItem(key, value) {
1509
+ var _a;
461
1510
  try {
462
- if (this.storage?.setStorage) {
1511
+ if ((_a = this.storage) == null ? void 0 : _a.setStorage) {
463
1512
  this.storage.setStorage(key, value);
464
1513
  return;
465
1514
  }
466
- if (typeof globalThis !== 'undefined' && globalThis?.localStorage) {
1515
+ if (typeof globalThis !== "undefined" && (globalThis == null ? void 0 : globalThis.localStorage)) {
467
1516
  globalThis.localStorage.setItem(key, value);
468
1517
  }
469
1518
  } catch {
470
- // 忽略存储异常,避免影响主流程
471
1519
  }
472
1520
  }
473
1521
  async loadOrdersFromSQLite() {
474
- if (!this.dbManager) return [];
1522
+ if (!this.dbManager)
1523
+ return [];
475
1524
  try {
476
1525
  const orders = await this.dbManager.getAll(INDEXDB_STORE_NAME);
477
- return orders || [];
1526
+ return (orders || []).map(
1527
+ (order) => this.normalizeOrderCollectionsForIngress(order, "loadOrdersFromSQLite")
1528
+ );
478
1529
  } catch {
479
1530
  return [];
480
1531
  }
481
1532
  }
482
- async saveOrdersToSQLite(orderList) {
483
- if (!this.dbManager) return;
1533
+ isPendingSyncOrder(order) {
1534
+ return Number(order == null ? void 0 : order.need_sync) === 1;
1535
+ }
1536
+ normalizeRemoteSyncedOrder(order) {
1537
+ const normalizedOrder = this.normalizeOrderCollectionsForIngress(
1538
+ order,
1539
+ "normalizeRemoteSyncedOrder"
1540
+ );
1541
+ if (this.isPendingSyncOrder(normalizedOrder))
1542
+ return normalizedOrder;
1543
+ return {
1544
+ ...normalizedOrder,
1545
+ need_sync: 0
1546
+ };
1547
+ }
1548
+ mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
1549
+ const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
1550
+ for (const rawOrder of existingOrders) {
1551
+ const order = this.normalizeOrderCollectionsForIngress(
1552
+ rawOrder,
1553
+ "mergeRemoteSnapshotWithPendingOrders.existingSQLite"
1554
+ );
1555
+ if (!this.isPendingSyncOrder(order))
1556
+ continue;
1557
+ const matchIndex = this.findOrderIndexByIdentity(merged, order);
1558
+ if (matchIndex >= 0) {
1559
+ merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
1560
+ continue;
1561
+ }
1562
+ if (!this.getOrderStorageKey(order))
1563
+ continue;
1564
+ merged.push(order);
1565
+ }
1566
+ return this.compactOrderListByIdentity(merged, "mergeRemoteSnapshotWithPendingOrders").list;
1567
+ }
1568
+ /**
1569
+ * 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
1570
+ *
1571
+ * @example
1572
+ * await this.runInOrderSQLiteSaveQueue(async () => {
1573
+ * await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, orders)
1574
+ * })
1575
+ */
1576
+ async runInOrderSQLiteSaveQueue(task) {
1577
+ const queuedTask = this.orderSQLiteSaveQueue.then(task, task);
1578
+ this.orderSQLiteSaveQueue = queuedTask.then(() => void 0, () => void 0);
1579
+ return queuedTask;
1580
+ }
1581
+ /**
1582
+ * 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
1583
+ *
1584
+ * @example
1585
+ * await this.patchOrdersInSQLite(freshOrders)
1586
+ */
1587
+ async patchOrdersInSQLite(orders, source, mergeActions = {}) {
1588
+ if (!this.dbManager || orders.length === 0) {
1589
+ return;
1590
+ }
1591
+ const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
1592
+ if (ordersSnapshot.length === 0) {
1593
+ return;
1594
+ }
1595
+ const { toWrite, skipped } = this.filterRedundantPatchOrders(
1596
+ source,
1597
+ ordersSnapshot,
1598
+ mergeActions
1599
+ );
1600
+ if (toWrite.length === 0) {
1601
+ return;
1602
+ }
1603
+ const compactedToWrite = this.compactOrderListByIdentity(toWrite, `${source}.sqlitePatch`).list;
1604
+ if (compactedToWrite.length === 0) {
1605
+ return;
1606
+ }
484
1607
  try {
485
- await this.dbManager.clear(INDEXDB_STORE_NAME);
486
- if (orderList.length === 0) return;
487
- await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orderList);
1608
+ await this.runInOrderSQLiteSaveQueue(async () => {
1609
+ let writeMethod = "none";
1610
+ this.logInfo("patchOrdersInSQLite-开始", {
1611
+ source,
1612
+ count: compactedToWrite.length,
1613
+ dedupedCount: skipped.length
1614
+ });
1615
+ if (typeof this.dbManager.bulkUpdate === "function") {
1616
+ writeMethod = "bulkUpdate";
1617
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, compactedToWrite);
1618
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1619
+ writeMethod = "bulkAdd";
1620
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, compactedToWrite);
1621
+ } else if (typeof this.dbManager.update === "function") {
1622
+ writeMethod = "update";
1623
+ for (const order of compactedToWrite) {
1624
+ await this.dbManager.update(INDEXDB_STORE_NAME, order);
1625
+ }
1626
+ }
1627
+ this.recordRecentSqliteWrite(source, compactedToWrite);
1628
+ this.logInfo("patchOrdersInSQLite-完成", {
1629
+ source,
1630
+ count: compactedToWrite.length,
1631
+ writeMethod,
1632
+ dedupedCount: skipped.length
1633
+ });
1634
+ });
488
1635
  } catch (error) {
489
- // SQLite 异常,避免影响主流程
490
- this.logError('保存订单到 SQLite 失败', {
1636
+ this.logError("增量保存订单到 SQLite 失败", {
491
1637
  error: error instanceof Error ? error.message : String(error),
492
- orderList: orderList.length
1638
+ orderCount: ordersSnapshot.length
493
1639
  });
494
1640
  }
495
1641
  }
1642
+ /**
1643
+ * 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
1644
+ *
1645
+ * @example
1646
+ * await this.updateOrderInSQLite(freshOrder)
1647
+ */
1648
+ async updateOrderInSQLite(order, source) {
1649
+ if (!this.dbManager || !this.getOrderStorageKey(order)) {
1650
+ return;
1651
+ }
1652
+ const orderSnapshot = this.normalizeOrderCollectionsForIngress(
1653
+ (0, import_lodash_es.cloneDeep)(order),
1654
+ `${source}.sqliteIngress`
1655
+ );
1656
+ try {
1657
+ await this.runInOrderSQLiteSaveQueue(async () => {
1658
+ let writeMethod = "none";
1659
+ this.logInfo("updateOrderInSQLite-开始", {
1660
+ source,
1661
+ orderId: orderSnapshot.order_id ?? null,
1662
+ storageKey: this.getOrderStorageKey(orderSnapshot)
1663
+ });
1664
+ if (typeof this.dbManager.update === "function") {
1665
+ writeMethod = "update";
1666
+ await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
1667
+ } else if (typeof this.dbManager.bulkUpdate === "function") {
1668
+ writeMethod = "bulkUpdate";
1669
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
1670
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1671
+ writeMethod = "bulkAdd";
1672
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
1673
+ }
1674
+ this.recordRecentSqliteWrite(source, [orderSnapshot]);
1675
+ this.logInfo("updateOrderInSQLite-完成", {
1676
+ source,
1677
+ orderId: orderSnapshot.order_id ?? null,
1678
+ writeMethod
1679
+ });
1680
+ });
1681
+ } catch (error) {
1682
+ this.logError("单条保存订单到 SQLite 失败", {
1683
+ error: error instanceof Error ? error.message : String(error),
1684
+ orderId: orderSnapshot.order_id ?? null
1685
+ });
1686
+ }
1687
+ }
1688
+ /**
1689
+ * 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
1690
+ *
1691
+ * @example
1692
+ * await this.replaceOrdersSnapshotInSQLite(orderList)
1693
+ */
1694
+ async replaceOrdersSnapshotInSQLite(orderList, source) {
1695
+ if (!this.dbManager) {
1696
+ return this.compactOrderListByIdentity(
1697
+ orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
1698
+ `${source}.snapshotNoDb`
1699
+ ).list;
1700
+ }
1701
+ const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList).map(
1702
+ (order) => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`)
1703
+ );
1704
+ let mergedSnapshot = this.compactOrderListByIdentity(
1705
+ remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
1706
+ `${source}.remoteSnapshot`
1707
+ ).list;
1708
+ try {
1709
+ await this.runInOrderSQLiteSaveQueue(async () => {
1710
+ const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
1711
+ const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
1712
+ remoteSnapshot,
1713
+ existingOrders || []
1714
+ );
1715
+ mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
1716
+ this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
1717
+ source,
1718
+ count: mergedSnapshot.length,
1719
+ remoteCount: remoteSnapshot.length,
1720
+ preservedPendingCount: mergedSnapshot.length - remoteSnapshot.length
1721
+ });
1722
+ await this.dbManager.clear(INDEXDB_STORE_NAME);
1723
+ this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
1724
+ count: mergedSnapshot.length
1725
+ });
1726
+ if (mergedSnapshot.length === 0) {
1727
+ return;
1728
+ }
1729
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, mergedSnapshot);
1730
+ this.recordRecentSqliteWrite(source, mergedSnapshot);
1731
+ this.logInfo("replaceOrdersSnapshotInSQLite-bulkAdd完成", {
1732
+ source,
1733
+ count: mergedSnapshot.length
1734
+ });
1735
+ });
1736
+ } catch (error) {
1737
+ this.logError("全量保存订单到 SQLite 失败", {
1738
+ error: error instanceof Error ? error.message : String(error),
1739
+ orderList: remoteSnapshot.length
1740
+ });
1741
+ }
1742
+ return mergedSnapshot;
1743
+ }
1744
+ /**
1745
+ * 清空订单模块的内存数据和本地 SQLite 订单表。
1746
+ *
1747
+ * @example
1748
+ * await orderModule.clear()
1749
+ */
496
1750
  async clear() {
497
1751
  this.store.list = [];
498
- this.store.map = new Map();
499
- this.resourceIdIndex.clear();
1752
+ this.store.map = /* @__PURE__ */ new Map();
500
1753
  if (this.dbManager) {
501
- await this.dbManager.clear(INDEXDB_STORE_NAME);
1754
+ await this.runInOrderSQLiteSaveQueue(async () => {
1755
+ await this.dbManager.clear(INDEXDB_STORE_NAME);
1756
+ });
502
1757
  }
503
- this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, '');
504
- this.core.effects.emit(_types.OrderHooks.onOrdersChanged, this.store.list);
1758
+ this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
1759
+ this.emitOrdersChanged([], "clear");
505
1760
  }
506
- }
507
- exports.OrderModule = OrderModule;
1761
+ };
1762
+ // Annotate the CommonJS export names for ESM import in node:
1763
+ 0 && (module.exports = {
1764
+ OrderModule
1765
+ });