@pisell/pisellos 2.2.244 → 2.2.245

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 (317) hide show
  1. package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
  2. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  3. package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
  4. package/dist/modules/BookingContext/index.d.ts +48 -0
  5. package/dist/modules/BookingContext/index.js +566 -0
  6. package/dist/modules/BookingContext/types.d.ts +102 -0
  7. package/dist/modules/BookingContext/types.js +51 -0
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  9. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +284 -0
  10. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  11. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +145 -0
  12. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  13. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +218 -0
  14. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  15. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  16. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  17. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  18. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  19. package/dist/modules/BookingContext/utils/index.js +11 -0
  20. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  21. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  22. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  23. package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
  24. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  25. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  26. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  27. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  28. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  29. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  30. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  31. package/dist/modules/BookingContext/utils/resources.js +486 -0
  32. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  33. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  34. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  35. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  36. package/dist/modules/Cart/utils/cartProduct.js +24 -3
  37. package/dist/modules/Cart/utils/changePrice.js +11 -11
  38. package/dist/modules/Customer/index.d.ts +20 -0
  39. package/dist/modules/Customer/index.js +172 -83
  40. package/dist/modules/Customer/types.d.ts +2 -0
  41. package/dist/modules/Discount/index.d.ts +1 -1
  42. package/dist/modules/Discount/index.js +13 -6
  43. package/dist/modules/Discount/types.d.ts +1 -0
  44. package/dist/modules/OpenData/index.d.ts +8 -0
  45. package/dist/modules/OpenData/index.js +37 -17
  46. package/dist/modules/Order/index.d.ts +275 -19
  47. package/dist/modules/Order/index.js +3493 -809
  48. package/dist/modules/Order/types.d.ts +286 -31
  49. package/dist/modules/Order/types.js +38 -0
  50. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  51. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  52. package/dist/modules/Order/utils.d.ts +147 -5
  53. package/dist/modules/Order/utils.js +750 -104
  54. package/dist/modules/Payment/index.d.ts +10 -13
  55. package/dist/modules/Payment/index.js +467 -837
  56. package/dist/modules/Payment/types.d.ts +2 -0
  57. package/dist/modules/Payment/utils.js +2 -1
  58. package/dist/modules/Payment/walletpass.js +41 -25
  59. package/dist/modules/ProductList/index.d.ts +16 -12
  60. package/dist/modules/ProductList/index.js +133 -59
  61. package/dist/modules/ProductList/types.d.ts +14 -0
  62. package/dist/modules/Quotation/index.d.ts +0 -1
  63. package/dist/modules/Quotation/index.js +25 -22
  64. package/dist/modules/Rules/index.d.ts +4 -0
  65. package/dist/modules/Rules/index.js +97 -70
  66. package/dist/modules/Rules/types.d.ts +1 -0
  67. package/dist/modules/SalesSummary/index.d.ts +8 -25
  68. package/dist/modules/SalesSummary/index.js +86 -35
  69. package/dist/modules/SalesSummary/types.d.ts +4 -1
  70. package/dist/modules/SalesSummary/utils.d.ts +2 -25
  71. package/dist/modules/SalesSummary/utils.js +794 -162
  72. package/dist/modules/Schedule/index.d.ts +7 -0
  73. package/dist/modules/Schedule/index.js +24 -2
  74. package/dist/modules/Summary/index.js +4 -3
  75. package/dist/modules/SurchargeList/index.d.ts +16 -0
  76. package/dist/modules/SurchargeList/index.js +162 -0
  77. package/dist/modules/SurchargeList/types.d.ts +11 -0
  78. package/dist/modules/SurchargeList/types.js +1 -0
  79. package/dist/modules/index.d.ts +2 -0
  80. package/dist/modules/index.js +3 -1
  81. package/dist/plugins/request.d.ts +1 -0
  82. package/dist/server/index.d.ts +204 -1
  83. package/dist/server/index.js +3654 -922
  84. package/dist/server/modules/index.d.ts +2 -0
  85. package/dist/server/modules/index.js +2 -0
  86. package/dist/server/modules/order/index.d.ts +120 -3
  87. package/dist/server/modules/order/index.js +1758 -448
  88. package/dist/server/modules/order/types.d.ts +32 -3
  89. package/dist/server/modules/order/types.js +8 -0
  90. package/dist/server/modules/order/utils/filterBookings.js +26 -3
  91. package/dist/server/modules/order/utils/filterOrders.js +23 -8
  92. package/dist/server/modules/payment/index.d.ts +28 -0
  93. package/dist/server/modules/payment/index.js +305 -0
  94. package/dist/server/modules/payment/types.d.ts +9 -0
  95. package/dist/server/modules/payment/types.js +1 -0
  96. package/dist/server/modules/products/index.d.ts +34 -7
  97. package/dist/server/modules/products/index.js +631 -317
  98. package/dist/server/modules/resource/index.d.ts +2 -0
  99. package/dist/server/modules/resource/index.js +29 -3
  100. package/dist/server/modules/schedule/index.d.ts +4 -4
  101. package/dist/server/modules/schedule/index.js +111 -88
  102. package/dist/server/test.json +713 -0
  103. package/dist/server/utils/small-ticket.d.ts +71 -0
  104. package/dist/server/utils/small-ticket.js +840 -0
  105. package/dist/solution/BaseSales/index.d.ts +133 -10
  106. package/dist/solution/BaseSales/index.js +1950 -447
  107. package/dist/solution/BaseSales/types.d.ts +82 -6
  108. package/dist/solution/BaseSales/types.js +5 -4
  109. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  110. package/dist/solution/BaseSales/utils/cartPromotion.js +1438 -0
  111. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  112. package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
  113. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  114. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +105 -24
  115. package/dist/solution/BaseSales/utils.d.ts +1 -1
  116. package/dist/solution/BaseSales/utils.js +62 -21
  117. package/dist/solution/BookingByStep/index.d.ts +1 -1
  118. package/dist/solution/BookingTicket/index.d.ts +271 -11
  119. package/dist/solution/BookingTicket/index.js +1777 -242
  120. package/dist/solution/BookingTicket/types.d.ts +118 -1
  121. package/dist/solution/BookingTicket/types.js +41 -2
  122. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  123. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  124. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  125. package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
  126. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  127. package/dist/solution/BookingTicket/utils/bookingStatus.js +70 -0
  128. package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
  129. package/dist/solution/BookingTicket/utils/cartView.js +94 -7
  130. package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  131. package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
  132. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  133. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
  134. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  135. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
  136. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  137. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
  138. package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  139. package/dist/solution/BookingTicket/utils/scan/index.js +20 -8
  140. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  141. package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
  142. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  143. package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
  144. package/dist/solution/Checkout/index.d.ts +1 -0
  145. package/dist/solution/Checkout/index.js +10 -9
  146. package/dist/solution/RegisterAndLogin/config.js +2 -10
  147. package/dist/solution/ScanOrder/index.d.ts +9 -3
  148. package/dist/solution/ScanOrder/index.js +241 -134
  149. package/dist/solution/ScanOrder/types.d.ts +9 -5
  150. package/dist/solution/ScanOrder/types.js +2 -3
  151. package/dist/solution/ScanOrder/utils.d.ts +1 -1
  152. package/dist/solution/ScanOrder/utils.js +84 -22
  153. package/dist/solution/VenueBooking/index.d.ts +5 -2
  154. package/dist/solution/VenueBooking/index.js +110 -59
  155. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  156. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  157. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
  158. package/dist/types/index.d.ts +10 -0
  159. package/lib/model/strategy/adapter/promotion/evaluator.js +2 -1
  160. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  161. package/lib/model/strategy/adapter/walletPass/utils.js +3 -2
  162. package/lib/modules/BookingContext/index.d.ts +48 -0
  163. package/lib/modules/BookingContext/index.js +368 -0
  164. package/lib/modules/BookingContext/types.d.ts +102 -0
  165. package/lib/modules/BookingContext/types.js +34 -0
  166. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  167. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
  168. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  169. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +151 -0
  170. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  171. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +201 -0
  172. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  173. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  174. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  175. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  176. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  177. package/lib/modules/BookingContext/utils/index.js +43 -0
  178. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  179. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  180. package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  181. package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
  182. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  183. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  184. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  185. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  186. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  187. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  188. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  189. package/lib/modules/BookingContext/utils/resources.js +377 -0
  190. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  191. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  192. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  193. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  194. package/lib/modules/Cart/utils/cartProduct.js +20 -3
  195. package/lib/modules/Cart/utils/changePrice.js +12 -20
  196. package/lib/modules/Customer/index.d.ts +20 -0
  197. package/lib/modules/Customer/index.js +64 -11
  198. package/lib/modules/Customer/types.d.ts +2 -0
  199. package/lib/modules/Discount/index.d.ts +1 -1
  200. package/lib/modules/Discount/index.js +9 -1
  201. package/lib/modules/Discount/types.d.ts +1 -0
  202. package/lib/modules/OpenData/index.d.ts +8 -0
  203. package/lib/modules/OpenData/index.js +19 -5
  204. package/lib/modules/Order/index.d.ts +275 -19
  205. package/lib/modules/Order/index.js +2245 -336
  206. package/lib/modules/Order/types.d.ts +286 -31
  207. package/lib/modules/Order/types.js +1 -0
  208. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  209. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  210. package/lib/modules/Order/utils.d.ts +147 -5
  211. package/lib/modules/Order/utils.js +615 -46
  212. package/lib/modules/Payment/index.d.ts +10 -13
  213. package/lib/modules/Payment/index.js +18 -150
  214. package/lib/modules/Payment/types.d.ts +2 -0
  215. package/lib/modules/Payment/utils.js +2 -1
  216. package/lib/modules/Payment/walletpass.js +16 -3
  217. package/lib/modules/ProductList/index.d.ts +16 -12
  218. package/lib/modules/ProductList/index.js +41 -4
  219. package/lib/modules/ProductList/types.d.ts +14 -0
  220. package/lib/modules/Quotation/index.d.ts +0 -1
  221. package/lib/modules/Quotation/index.js +19 -16
  222. package/lib/modules/Rules/index.d.ts +4 -0
  223. package/lib/modules/Rules/index.js +137 -120
  224. package/lib/modules/Rules/types.d.ts +1 -0
  225. package/lib/modules/SalesSummary/index.d.ts +8 -25
  226. package/lib/modules/SalesSummary/index.js +30 -4
  227. package/lib/modules/SalesSummary/types.d.ts +4 -1
  228. package/lib/modules/SalesSummary/utils.d.ts +2 -25
  229. package/lib/modules/SalesSummary/utils.js +645 -91
  230. package/lib/modules/Schedule/index.d.ts +7 -0
  231. package/lib/modules/Schedule/index.js +17 -1
  232. package/lib/modules/Summary/index.js +5 -4
  233. package/lib/modules/SurchargeList/index.d.ts +16 -0
  234. package/lib/modules/SurchargeList/index.js +89 -0
  235. package/lib/modules/SurchargeList/types.d.ts +11 -0
  236. package/lib/modules/SurchargeList/types.js +17 -0
  237. package/lib/modules/index.d.ts +2 -0
  238. package/lib/modules/index.js +5 -1
  239. package/lib/plugins/request.d.ts +1 -0
  240. package/lib/server/index.d.ts +204 -1
  241. package/lib/server/index.js +1891 -59
  242. package/lib/server/modules/index.d.ts +2 -0
  243. package/lib/server/modules/index.js +3 -0
  244. package/lib/server/modules/order/index.d.ts +120 -3
  245. package/lib/server/modules/order/index.js +883 -94
  246. package/lib/server/modules/order/types.d.ts +32 -3
  247. package/lib/server/modules/order/utils/filterBookings.js +24 -5
  248. package/lib/server/modules/order/utils/filterOrders.js +15 -6
  249. package/lib/server/modules/payment/index.d.ts +28 -0
  250. package/lib/server/modules/payment/index.js +192 -0
  251. package/lib/server/modules/payment/types.d.ts +9 -0
  252. package/lib/server/modules/payment/types.js +17 -0
  253. package/lib/server/modules/products/index.d.ts +34 -7
  254. package/lib/server/modules/products/index.js +189 -54
  255. package/lib/server/modules/resource/index.d.ts +2 -0
  256. package/lib/server/modules/resource/index.js +27 -3
  257. package/lib/server/modules/schedule/index.d.ts +4 -4
  258. package/lib/server/modules/schedule/index.js +47 -40
  259. package/lib/server/test.json +713 -0
  260. package/lib/server/utils/small-ticket.d.ts +71 -0
  261. package/lib/server/utils/small-ticket.js +800 -0
  262. package/lib/solution/BaseSales/index.d.ts +133 -10
  263. package/lib/solution/BaseSales/index.js +1111 -63
  264. package/lib/solution/BaseSales/types.d.ts +82 -6
  265. package/lib/solution/BaseSales/types.js +3 -1
  266. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  267. package/lib/solution/BaseSales/utils/cartPromotion.js +992 -0
  268. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  269. package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
  270. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  271. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +106 -18
  272. package/lib/solution/BaseSales/utils.d.ts +1 -1
  273. package/lib/solution/BaseSales/utils.js +54 -10
  274. package/lib/solution/BookingByStep/index.d.ts +1 -1
  275. package/lib/solution/BookingTicket/index.d.ts +271 -11
  276. package/lib/solution/BookingTicket/index.js +922 -29
  277. package/lib/solution/BookingTicket/types.d.ts +118 -1
  278. package/lib/solution/BookingTicket/types.js +11 -0
  279. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  280. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  281. package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  282. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
  283. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  284. package/lib/solution/BookingTicket/utils/bookingStatus.js +44 -2
  285. package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
  286. package/lib/solution/BookingTicket/utils/cartView.js +61 -6
  287. package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  288. package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
  289. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  290. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
  291. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  292. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
  293. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  294. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
  295. package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  296. package/lib/solution/BookingTicket/utils/scan/index.js +17 -3
  297. package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  298. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
  299. package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  300. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
  301. package/lib/solution/Checkout/index.d.ts +1 -0
  302. package/lib/solution/Checkout/index.js +1 -2
  303. package/lib/solution/RegisterAndLogin/config.js +2 -10
  304. package/lib/solution/ScanOrder/index.d.ts +9 -3
  305. package/lib/solution/ScanOrder/index.js +153 -70
  306. package/lib/solution/ScanOrder/types.d.ts +9 -5
  307. package/lib/solution/ScanOrder/utils.d.ts +1 -1
  308. package/lib/solution/ScanOrder/utils.js +83 -17
  309. package/lib/solution/VenueBooking/index.d.ts +5 -2
  310. package/lib/solution/VenueBooking/index.js +54 -17
  311. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  312. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  313. package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
  314. package/lib/types/index.d.ts +10 -0
  315. package/package.json +1 -1
  316. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  317. package/lib/solution/Checkout/appointmentDemo.json +0 -1
@@ -40,6 +40,14 @@ var INDEXDB_STORE_NAME = "orders";
40
40
  var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
41
41
  var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
42
42
  var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
43
+ var ORDER_SQLITE_DEDUPE_MS = 15e3;
44
+ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
45
+ var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
46
+ "upsertOrdersFromRemote",
47
+ "upsertPendingSyncOrders",
48
+ "overwriteExistingOrder",
49
+ "markOrderSyncedByExternalSaleNumber"
50
+ ]);
43
51
  var OrderModule = class extends import_BaseModule.BaseModule {
44
52
  constructor(name, version) {
45
53
  super(name, version);
@@ -50,6 +58,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
50
58
  this.isIdlePhase = true;
51
59
  // Map<resource_id, OrderId[]> 资源到订单的倒排索引
52
60
  this.resourceIdIndex = /* @__PURE__ */ new Map();
61
+ this.orderSQLiteSaveQueue = Promise.resolve();
62
+ /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
63
+ this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
64
+ /** 最近一次 SSE 全量拉取完成时间 */
65
+ this.lastServerFullFetchAtMs = 0;
66
+ }
67
+ /**
68
+ * 广播订单变更事件,兼容全量列表订阅并额外携带本次变更订单。
69
+ *
70
+ * @example
71
+ * await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
72
+ */
73
+ async emitOrdersChanged(changedOrders = [], source) {
74
+ console.log("触发emitOrdersChanged");
75
+ const payload = {
76
+ list: this.store.list,
77
+ changedOrders: changedOrders.map((order) => this.normalizeOrderForMemoryList(order)),
78
+ source
79
+ };
80
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
53
81
  }
54
82
  async initialize(core, options) {
55
83
  var _a;
@@ -66,9 +94,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
66
94
  this.updateCreateStore();
67
95
  }
68
96
  if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
69
- this.store.list = options.initialState.list;
97
+ this.store.list = options.initialState.list.map((order) => this.normalizeOrderForMemoryList(order));
70
98
  this.syncOrdersMap();
71
- this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
99
+ this.emitOrdersChanged([], "initialState");
72
100
  } else {
73
101
  this.store.list = [];
74
102
  this.store.map = /* @__PURE__ */ new Map();
@@ -115,6 +143,171 @@ var OrderModule = class extends import_BaseModule.BaseModule {
115
143
  } catch {
116
144
  }
117
145
  }
146
+ logWarning(title, metadata) {
147
+ try {
148
+ if (this.logger) {
149
+ this.logger.addLog({
150
+ type: "warning",
151
+ title: `[OrderServerModule] ${title}`,
152
+ metadata: metadata || {}
153
+ });
154
+ }
155
+ } catch {
156
+ }
157
+ }
158
+ /**
159
+ * 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
160
+ *
161
+ * @example
162
+ * this.recordRecentSqliteWrite('upsertOrdersFromRemote', orders)
163
+ */
164
+ recordRecentSqliteWrite(source, orders) {
165
+ const now = Date.now();
166
+ for (const order of orders) {
167
+ const storageKey = this.getOrderStorageKey(order);
168
+ if (!storageKey)
169
+ continue;
170
+ this.recentSqliteWriteByStorageKey.set(storageKey, { source, ts: now });
171
+ }
172
+ }
173
+ /**
174
+ * 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
175
+ *
176
+ * @example
177
+ * const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
178
+ */
179
+ filterRedundantPatchOrders(source, orders, mergeActions) {
180
+ const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
181
+ if (!eligibleSkipSources.has(source)) {
182
+ return { toWrite: orders, skipped: [] };
183
+ }
184
+ const now = Date.now();
185
+ const toWrite = [];
186
+ const skipped = [];
187
+ for (const order of orders) {
188
+ const storageKey = this.getOrderStorageKey(order);
189
+ if (!storageKey) {
190
+ toWrite.push(order);
191
+ continue;
192
+ }
193
+ const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
194
+ const mergeAction = orderKey ? mergeActions[orderKey] : void 0;
195
+ if (mergeAction === "insert") {
196
+ toWrite.push(order);
197
+ continue;
198
+ }
199
+ const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
200
+ if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
201
+ skipped.push({
202
+ orderId: order.order_id ?? null,
203
+ storageKey,
204
+ reason: "skip_pubsub_echo_after_business_write",
205
+ lastSource: recent.source,
206
+ elapsedMs: now - recent.ts
207
+ });
208
+ continue;
209
+ }
210
+ toWrite.push(order);
211
+ }
212
+ return { toWrite, skipped };
213
+ }
214
+ /**
215
+ * 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
216
+ *
217
+ * @example
218
+ * const ids = this.filterRedundantHttpRefreshIds([99331, 99332])
219
+ */
220
+ filterRedundantHttpRefreshIds(ids) {
221
+ const now = Date.now();
222
+ const toFetch = [];
223
+ const skipped = [];
224
+ for (const id of ids) {
225
+ const existing = this.getOrderByOrderId(id);
226
+ if (!existing) {
227
+ toFetch.push(id);
228
+ continue;
229
+ }
230
+ const storageKey = this.getOrderStorageKey(existing);
231
+ const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : void 0;
232
+ if (recent && recent.source === "upsertOrdersFromRemote" && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
233
+ skipped.push({
234
+ orderId: id,
235
+ lastSource: recent.source,
236
+ elapsedMs: now - recent.ts
237
+ });
238
+ continue;
239
+ }
240
+ toFetch.push(id);
241
+ }
242
+ return { toFetch, skipped };
243
+ }
244
+ /**
245
+ * 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
246
+ *
247
+ * @example
248
+ * this.resolveSyncMessageRoute(msg)
249
+ * // => { route: 'httpRefresh.batchIds', ... }
250
+ */
251
+ resolveSyncMessageRoute(msg) {
252
+ var _a;
253
+ const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
254
+ const singleIdRaw = msg.id ?? msg.order_id;
255
+ const hasSingleId = !hasBatchIds && singleIdRaw !== void 0 && singleIdRaw !== null;
256
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
257
+ if (hasBatchIds) {
258
+ return {
259
+ route: "httpRefresh.batchIds",
260
+ hasBatchIds: true,
261
+ hasSingleId: false,
262
+ hasNormalizedBody: !!normalizedBody,
263
+ singleId: null,
264
+ batchIds: msg.ids || [],
265
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
266
+ };
267
+ }
268
+ if (hasSingleId && normalizedBody) {
269
+ return {
270
+ route: "bodyUpsert",
271
+ hasBatchIds: false,
272
+ hasSingleId: true,
273
+ hasNormalizedBody: true,
274
+ singleId: singleIdRaw,
275
+ batchIds: [],
276
+ bodyOrderId: normalizedBody.order_id ?? null
277
+ };
278
+ }
279
+ if (hasSingleId) {
280
+ return {
281
+ route: "httpRefresh.singleId",
282
+ hasBatchIds: false,
283
+ hasSingleId: true,
284
+ hasNormalizedBody: !!normalizedBody,
285
+ singleId: singleIdRaw,
286
+ batchIds: [],
287
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
288
+ };
289
+ }
290
+ if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length) {
291
+ return {
292
+ route: "httpRefresh.relationIds",
293
+ hasBatchIds: false,
294
+ hasSingleId: false,
295
+ hasNormalizedBody: !!normalizedBody,
296
+ singleId: null,
297
+ batchIds: msg.relation_order_ids,
298
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
299
+ };
300
+ }
301
+ return {
302
+ route: "noop",
303
+ hasBatchIds: false,
304
+ hasSingleId: false,
305
+ hasNormalizedBody: !!normalizedBody,
306
+ singleId: null,
307
+ batchIds: [],
308
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
309
+ };
310
+ }
118
311
  updateCreateStore() {
119
312
  var _a;
120
313
  const appPlugin = this.core.getPlugin("app");
@@ -174,11 +367,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
174
367
  async preload() {
175
368
  const getData = async () => {
176
369
  const orders = await this.loadOrdersByServer();
177
- if (orders.length === 0)
370
+ if (orders.length === 0) {
178
371
  return;
372
+ }
179
373
  this.store.list = (0, import_lodash_es.cloneDeep)(orders);
180
374
  this.syncOrdersMap();
181
- this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
375
+ this.emitOrdersChanged([], "preload");
182
376
  this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
183
377
  };
184
378
  getData();
@@ -189,30 +383,33 @@ var OrderModule = class extends import_BaseModule.BaseModule {
189
383
  getOrderById(id) {
190
384
  return this.store.map.get(this.getIdKey(id));
191
385
  }
192
- /** 按 order_id 查询(推荐) */
386
+ /** 按 order_id 查询内存订单。 */
193
387
  getOrderByOrderId(orderId) {
194
388
  return this.store.map.get(this.getIdKey(orderId));
195
389
  }
196
- async getLocalOrderByOrderId(orderId) {
197
- const key = this.getIdKey(orderId);
198
- const memoryOrder = this.store.map.get(key);
390
+ getLocalOrderFromMemoryByLookup(lookup) {
391
+ const key = this.getIdKey(lookup);
392
+ const memoryOrderById = this.store.map.get(key);
393
+ if (memoryOrderById)
394
+ return memoryOrderById;
395
+ const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
396
+ return memoryOrder || null;
397
+ }
398
+ async getLocalOrderByLookup(lookup) {
399
+ const key = this.getIdKey(lookup);
400
+ const memoryOrderById = this.store.map.get(key);
401
+ if (memoryOrderById)
402
+ return memoryOrderById;
403
+ const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
199
404
  if (memoryOrder)
200
405
  return memoryOrder;
201
406
  const orders = await this.loadOrdersFromSQLite();
202
- const localOrder = orders.find((order) => {
203
- const shopOrderNumber = order == null ? void 0 : order.shop_order_number;
204
- if (shopOrderNumber && this.getIdKey(shopOrderNumber) === key)
205
- return true;
206
- const id = order == null ? void 0 : order.order_id;
207
- if (id === void 0 || id === null)
208
- return false;
209
- return this.getIdKey(id) === key;
210
- });
407
+ const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
211
408
  if (!localOrder)
212
409
  return null;
213
- this.store.list = orders;
410
+ this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
214
411
  this.syncOrdersMap();
215
- return localOrder;
412
+ return this.normalizeOrderForMemoryList(localOrder);
216
413
  }
217
414
  async loadOrdersByServer() {
218
415
  var _a;
@@ -233,17 +430,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
233
430
  count: orderList.length
234
431
  });
235
432
  this.markOrderPulledAtNow();
433
+ this.lastServerFullFetchAtMs = Date.now();
236
434
  } catch {
237
- orderList = [];
238
- this.logInfo("loadOrdersByServer-SSE拉取失败,回退为空数组");
435
+ this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
436
+ return this.store.list;
239
437
  }
240
438
  }
241
- await this.saveOrdersToSQLite(orderList);
439
+ const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
440
+ const memoryOrders = mergedOrders.map((order) => this.normalizeOrderForMemoryList(order));
242
441
  this.logInfo("loadOrdersByServer-结束", {
243
- count: orderList.length
442
+ count: memoryOrders.length
244
443
  });
245
- await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, orderList);
246
- return orderList;
444
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
445
+ return memoryOrders;
247
446
  }
248
447
  /**
249
448
  * 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
@@ -252,6 +451,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
252
451
  */
253
452
  async silentRefresh() {
254
453
  const startTime = Date.now();
454
+ const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
455
+ if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
456
+ return this.store.list;
457
+ }
255
458
  this.logInfo("silentRefresh 开始");
256
459
  try {
257
460
  this.updateCreateStore();
@@ -259,7 +462,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
259
462
  if (orders.length > 0) {
260
463
  this.store.list = (0, import_lodash_es.cloneDeep)(orders);
261
464
  this.syncOrdersMap();
262
- this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
465
+ this.emitOrdersChanged([], "silentRefresh");
263
466
  await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
264
467
  this.logInfo("silentRefresh 完成", {
265
468
  orderCount: orders.length,
@@ -282,6 +485,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
282
485
  const ids = this.resourceIdIndex.get(String(resourceId)) || [];
283
486
  return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
284
487
  }
488
+ normalizeOrderForMemoryList(order) {
489
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
490
+ if ((order == null ? void 0 : order.order_id) !== void 0 && (order == null ? void 0 : order.order_id) !== null && (order == null ? void 0 : order.order_id) !== "") {
491
+ return order;
492
+ }
493
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
494
+ return order;
495
+ }
496
+ return {
497
+ ...order,
498
+ order_id: externalSaleNumber
499
+ };
500
+ }
285
501
  /**
286
502
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
287
503
  * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
@@ -308,12 +524,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
308
524
  return this.getIdKey(id) === key ? fresh : order;
309
525
  });
310
526
  this.syncOrdersMap();
311
- await this.saveOrdersToSQLite(this.store.list);
527
+ await this.updateOrderInSQLite(fresh, "overwriteExistingOrder");
312
528
  this.logInfo("overwriteExistingOrder-结束", {
313
529
  orderId,
314
530
  storeOrderCountAfter: this.store.list.length
315
531
  });
316
- await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
532
+ await this.emitOrdersChanged([fresh], "overwriteExistingOrder");
317
533
  return { overwritten: true };
318
534
  }
319
535
  /**
@@ -326,7 +542,102 @@ var OrderModule = class extends import_BaseModule.BaseModule {
326
542
  return;
327
543
  }
328
544
  this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
329
- await this.mergeOrdersToStore(freshOrders);
545
+ await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
546
+ }
547
+ async markOrderSyncedByExternalSaleNumber(params) {
548
+ const externalSaleNumber = params.externalSaleNumber;
549
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
550
+ this.logError("markOrderSyncedByExternalSaleNumber-缺少 external_sale_number");
551
+ return { updated: false };
552
+ }
553
+ const key = this.getIdKey(externalSaleNumber);
554
+ const targetIndex = this.store.list.findIndex((order) => {
555
+ const value = order == null ? void 0 : order.external_sale_number;
556
+ if (value === void 0 || value === null || value === "")
557
+ return false;
558
+ return this.getIdKey(value) === key;
559
+ });
560
+ if (targetIndex < 0) {
561
+ this.logInfo("markOrderSyncedByExternalSaleNumber-本地订单不存在,跳过", {
562
+ external_sale_number: externalSaleNumber
563
+ });
564
+ return { updated: false };
565
+ }
566
+ const existing = this.store.list[targetIndex];
567
+ const nextOrder = this.normalizeRemoteSyncedOrder({
568
+ ...existing,
569
+ ...params.patch || {},
570
+ external_sale_number: existing.external_sale_number ?? externalSaleNumber,
571
+ need_sync: 0
572
+ });
573
+ const storageKey = this.getOrderStorageKey(nextOrder) || key;
574
+ this.store.list = this.store.list.map((order, index) => {
575
+ if (index !== targetIndex)
576
+ return order;
577
+ return nextOrder;
578
+ });
579
+ this.syncOrdersMap();
580
+ await this.patchOrdersInSQLite(
581
+ [nextOrder],
582
+ "markOrderSyncedByExternalSaleNumber",
583
+ { [storageKey]: "update" }
584
+ );
585
+ this.logInfo("markOrderSyncedByExternalSaleNumber-完成", {
586
+ external_sale_number: externalSaleNumber,
587
+ order_id: nextOrder.order_id ?? null
588
+ });
589
+ await this.emitOrdersChanged([nextOrder], "markOrderSyncedByExternalSaleNumber");
590
+ return { updated: true, order: nextOrder };
591
+ }
592
+ /**
593
+ * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
594
+ * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
595
+ */
596
+ async upsertPendingSyncOrders(pendingOrders) {
597
+ if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
598
+ this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
599
+ return;
600
+ }
601
+ const pendingMap = /* @__PURE__ */ new Map();
602
+ const memoryPendingMap = /* @__PURE__ */ new Map();
603
+ for (const order of pendingOrders) {
604
+ const storageKey = this.getOrderStorageKey(order);
605
+ if (!storageKey)
606
+ continue;
607
+ pendingMap.set(storageKey, order);
608
+ memoryPendingMap.set(storageKey, this.normalizeOrderForMemoryList(order));
609
+ }
610
+ if (pendingMap.size === 0) {
611
+ this.logError("upsertPendingSyncOrders-订单缺少可落库标识", {
612
+ count: pendingOrders.length
613
+ });
614
+ return;
615
+ }
616
+ this.logInfo("upsertPendingSyncOrders-开始", { count: pendingMap.size });
617
+ const patchedOrders = [...pendingMap.values()];
618
+ const mergeActions = {};
619
+ const updatedList = [...this.store.list];
620
+ for (const [storageKey, pendingOrder] of memoryPendingMap.entries()) {
621
+ const matchIndex = this.findOrderIndexByIdentity(updatedList, pendingOrder);
622
+ if (matchIndex < 0)
623
+ continue;
624
+ updatedList[matchIndex] = this.mergeOrderRecords(updatedList[matchIndex], pendingOrder);
625
+ pendingMap.delete(storageKey);
626
+ memoryPendingMap.delete(storageKey);
627
+ mergeActions[storageKey] = "update";
628
+ }
629
+ for (const [storageKey, order] of memoryPendingMap.entries()) {
630
+ mergeActions[storageKey] = "insert";
631
+ updatedList.push(order);
632
+ }
633
+ this.store.list = this.compactOrderListByIdentity(updatedList, "upsertPendingSyncOrders.store").list;
634
+ this.syncOrdersMap();
635
+ await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
636
+ this.logInfo("upsertPendingSyncOrders-结束", {
637
+ count: patchedOrders.length,
638
+ storeOrderCountAfter: this.store.list.length
639
+ });
640
+ await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
330
641
  }
331
642
  /**
332
643
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
@@ -363,21 +674,65 @@ var OrderModule = class extends import_BaseModule.BaseModule {
363
674
  this.store.map.clear();
364
675
  this.resourceIdIndex.clear();
365
676
  for (const order of this.store.list) {
366
- const id = order.order_id;
367
- if (id === void 0 || id === null)
677
+ const primaryIdentity = this.getOrderMapKey(order);
678
+ if (!primaryIdentity)
368
679
  continue;
369
- this.store.map.set(this.getIdKey(id), order);
680
+ this.store.map.set(primaryIdentity, order);
370
681
  const resourceIds = this.extractResourceIds(order);
371
682
  for (const resourceId of resourceIds) {
372
683
  const key = String(resourceId);
373
684
  const existing = this.resourceIdIndex.get(key) || [];
374
- if (existing.some((eid) => this.getIdKey(eid) === this.getIdKey(id)))
685
+ if (existing.some((eid) => this.getIdKey(eid) === primaryIdentity))
375
686
  continue;
376
- existing.push(id);
687
+ existing.push(primaryIdentity);
377
688
  this.resourceIdIndex.set(key, existing);
378
689
  }
379
690
  }
380
691
  }
692
+ getOrderMapKey(order) {
693
+ if (!order)
694
+ return "";
695
+ if (!this.isBlankIdentityValue(order.order_id)) {
696
+ return this.getIdKey(order.order_id);
697
+ }
698
+ const externalSaleNumber = order.external_sale_number;
699
+ if (!this.isBlankIdentityValue(externalSaleNumber)) {
700
+ return this.getIdKey(externalSaleNumber);
701
+ }
702
+ return "";
703
+ }
704
+ isBlankIdentityValue(value) {
705
+ return value === void 0 || value === null || value === "";
706
+ }
707
+ getOrderIdentityEntries(order) {
708
+ if (!order)
709
+ return [];
710
+ const record = order;
711
+ const candidates = [
712
+ { field: "order_id", value: order.order_id },
713
+ { field: "external_sale_number", value: record.external_sale_number },
714
+ { field: "order_number", value: record.order_number },
715
+ { field: "shop_order_number", value: record.shop_order_number }
716
+ ];
717
+ const entries = [];
718
+ for (const candidate of candidates) {
719
+ if (this.isBlankIdentityValue(candidate.value))
720
+ continue;
721
+ const key = this.getIdKey(candidate.value);
722
+ if (entries.some((entry) => entry.field === candidate.field && entry.key === key))
723
+ continue;
724
+ entries.push({ field: candidate.field, key });
725
+ }
726
+ return entries;
727
+ }
728
+ getOrderIdentityKeys(order) {
729
+ const keys = [];
730
+ for (const entry of this.getOrderIdentityEntries(order)) {
731
+ if (!keys.includes(entry.key))
732
+ keys.push(entry.key);
733
+ }
734
+ return keys;
735
+ }
381
736
  extractResourceIds(order) {
382
737
  const ids = /* @__PURE__ */ new Set();
383
738
  const visitResources = (resources) => {
@@ -434,7 +789,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
434
789
  this.orderDataSource.run({
435
790
  pubsub: {
436
791
  callback: (res) => {
437
- console.log("orderDataSource");
792
+ console.log("orderDataSource", res);
438
793
  const pubsubReceivedAt = Date.now();
439
794
  const message = this.normalizeOrderSyncMessage(res);
440
795
  if (!message)
@@ -442,13 +797,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
442
797
  message._pubsubReceivedAt = pubsubReceivedAt;
443
798
  this.pendingSyncMessages.push(message);
444
799
  const throttleMs = this.getOrderSyncThrottleMs();
800
+ const routeInfo = this.resolveSyncMessageRoute(message);
445
801
  this.logInfo("orderSync-收到消息并入队", {
446
802
  id: message.id ?? null,
447
803
  order_id: message.order_id ?? null,
448
804
  type: message.type ?? null,
449
805
  pendingCount: this.pendingSyncMessages.length,
450
806
  throttleMs,
451
- pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString()
807
+ pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString(),
808
+ fullMessage: JSON.stringify(message)
452
809
  });
453
810
  this.scheduleOrderSyncThrottle();
454
811
  }
@@ -514,7 +871,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
514
871
  * await this.processOrderSyncMessages()
515
872
  */
516
873
  async processOrderSyncMessages() {
517
- var _a;
518
874
  const messages = [...this.pendingSyncMessages];
519
875
  this.pendingSyncMessages = [];
520
876
  if (messages.length === 0)
@@ -531,38 +887,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
531
887
  });
532
888
  const upsertOrders = /* @__PURE__ */ new Map();
533
889
  const refreshIds = [];
534
- for (const msg of messages) {
535
- const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
536
- const singleId = msg.id ?? msg.order_id;
537
- const hasSingleId = !hasBatchIds && singleId !== void 0 && singleId !== null;
538
- const rawBody = msg.body || msg.data;
539
- const normalizedBody = this.normalizeOrderSyncPayload(rawBody);
540
- if (hasSingleId && normalizedBody) {
890
+ messages.forEach((msg, msgIndex) => {
891
+ const routeInfo = this.resolveSyncMessageRoute(msg);
892
+ const hasBatchIds = routeInfo.hasBatchIds;
893
+ const singleId = routeInfo.singleId;
894
+ const hasSingleId = routeInfo.hasSingleId;
895
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
896
+ if (routeInfo.route === "bodyUpsert" && normalizedBody) {
541
897
  upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
542
- continue;
898
+ return;
543
899
  }
544
900
  if (hasBatchIds)
545
- refreshIds.push(...msg.ids);
546
- else if (hasSingleId)
901
+ refreshIds.push(...routeInfo.batchIds);
902
+ else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
547
903
  refreshIds.push(singleId);
548
- else if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length)
549
- refreshIds.push(...msg.relation_order_ids);
550
- }
904
+ else if (routeInfo.route === "httpRefresh.relationIds")
905
+ refreshIds.push(...routeInfo.batchIds);
906
+ });
551
907
  const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
552
908
  const upsertList = [...upsertOrders.values()];
553
909
  this.logInfo("processOrderSyncMessages-去重完成", {
554
910
  upsertCount: upsertList.length,
555
911
  refreshIdCount: uniqueRefreshIds.length
556
912
  });
557
- if (upsertList.length > 0)
558
- await this.mergeOrdersToStore(upsertList);
913
+ if (upsertList.length > 0) {
914
+ await this.mergeOrdersToStore(upsertList, "pubsub.bodyUpsert");
915
+ }
559
916
  if (uniqueRefreshIds.length > 0) {
560
- const freshOrders = await this.fetchOrdersByHttp(uniqueRefreshIds);
561
- if (freshOrders.length > 0)
562
- await this.mergeOrdersToStore(freshOrders);
917
+ const { toFetch, skipped } = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
918
+ if (skipped.length > 0) {
919
+ }
920
+ if (toFetch.length > 0) {
921
+ const freshOrders = await this.fetchOrdersByHttp(toFetch);
922
+ if (freshOrders.length > 0) {
923
+ await this.mergeOrdersToStore(freshOrders, "pubsub.httpRefresh");
924
+ } else {
925
+ }
926
+ }
563
927
  }
564
- if (upsertList.length === 0 && uniqueRefreshIds.length === 0)
928
+ if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
565
929
  return;
930
+ }
566
931
  const batchProcessEndAt = Date.now();
567
932
  this.logInfo("processOrderSyncMessages-结束", {
568
933
  upsertCount: upsertList.length,
@@ -603,41 +968,62 @@ var OrderModule = class extends import_BaseModule.BaseModule {
603
968
  /**
604
969
  * 将增量订单合并到 store
605
970
  */
606
- async mergeOrdersToStore(freshOrders) {
971
+ async mergeOrdersToStore(freshOrders, source) {
607
972
  this.logInfo("mergeOrdersToStore-开始", {
608
973
  freshOrderCount: freshOrders.length,
609
- storeOrderCountBefore: this.store.list.length
974
+ storeOrderCountBefore: this.store.list.length,
975
+ source
610
976
  });
611
- const freshMap = /* @__PURE__ */ new Map();
977
+ this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
978
+ const normalizedFreshOrders = [];
612
979
  for (const order of freshOrders) {
613
980
  const id = order == null ? void 0 : order.order_id;
614
981
  if (id === void 0 || id === null)
615
982
  continue;
616
- freshMap.set(this.getIdKey(id), order);
983
+ normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
617
984
  }
618
- const uniqueFreshCount = freshMap.size;
619
- const updatedList = this.store.list.map((order) => {
620
- const id = order.order_id;
621
- if (id === void 0 || id === null)
622
- return order;
623
- const key = this.getIdKey(id);
624
- if (!freshMap.has(key))
625
- return order;
626
- const fresh = freshMap.get(key);
627
- freshMap.delete(key);
628
- return fresh;
629
- });
630
- for (const order of freshMap.values()) {
631
- updatedList.push(order);
985
+ const uniqueFreshOrders = this.compactOrderListByIdentity(
986
+ normalizedFreshOrders,
987
+ `${source}.incoming`
988
+ ).list;
989
+ const uniqueFreshCount = uniqueFreshOrders.length;
990
+ const patchedOrders = [];
991
+ const mergeActions = {};
992
+ const updatedList = [...this.store.list];
993
+ for (const fresh of uniqueFreshOrders) {
994
+ const matchIndex = this.findOrderIndexByIdentity(updatedList, fresh);
995
+ const storageKey = this.getOrderStorageKey(fresh);
996
+ const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
997
+ if (matchIndex >= 0) {
998
+ const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], fresh);
999
+ updatedList[matchIndex] = mergedOrder;
1000
+ patchedOrders.push(mergedOrder);
1001
+ if (mergeKey)
1002
+ mergeActions[mergeKey] = "update";
1003
+ continue;
1004
+ }
1005
+ updatedList.push(fresh);
1006
+ patchedOrders.push(fresh);
1007
+ if (mergeKey)
1008
+ mergeActions[mergeKey] = "insert";
632
1009
  }
633
- this.store.list = updatedList;
1010
+ const insertCount = Object.values(mergeActions).filter((v) => v === "insert").length;
1011
+ const updateCount = Object.values(mergeActions).filter((v) => v === "update").length;
1012
+ this.logInfo("mergeOrdersToStore-合并完成", {
1013
+ insertCount,
1014
+ updateCount,
1015
+ storeOrderCountAfter: this.store.list.length
1016
+ });
1017
+ this.store.list = this.compactOrderListByIdentity(updatedList, `${source}.store`).list;
634
1018
  this.syncOrdersMap();
635
- await this.saveOrdersToSQLite(this.store.list);
1019
+ await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
636
1020
  this.logInfo("mergeOrdersToStore-结束", {
637
1021
  uniqueFreshCount,
638
- storeOrderCountAfter: this.store.list.length
1022
+ storeOrderCountAfter: this.store.list.length,
1023
+ insertCount,
1024
+ updateCount
639
1025
  });
640
- this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
1026
+ await this.emitOrdersChanged(patchedOrders, source);
641
1027
  }
642
1028
  normalizeOrderSyncMessage(res) {
643
1029
  const data = (res == null ? void 0 : res.data) || res;
@@ -682,6 +1068,227 @@ var OrderModule = class extends import_BaseModule.BaseModule {
682
1068
  getIdKey(id) {
683
1069
  return String(id);
684
1070
  }
1071
+ isOrderLookupMatch(order, lookupKey) {
1072
+ if (!order || !lookupKey)
1073
+ return false;
1074
+ const candidates = [
1075
+ order.order_id,
1076
+ order.external_sale_number,
1077
+ order.order_number,
1078
+ order.shop_order_number,
1079
+ order.shop_full_order_number
1080
+ ];
1081
+ return candidates.some((value) => {
1082
+ if (value === void 0 || value === null || value === "")
1083
+ return false;
1084
+ return this.getIdKey(value) === lookupKey;
1085
+ });
1086
+ }
1087
+ /**
1088
+ * 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
1089
+ *
1090
+ * @example
1091
+ * const key = this.getOrderStorageKey({ order_id: 1001, external_sale_number: 'S-1001' })
1092
+ * // => 'S-1001'
1093
+ */
1094
+ getOrderStorageKey(order) {
1095
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
1096
+ if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
1097
+ return String(externalSaleNumber);
1098
+ }
1099
+ const orderId = order == null ? void 0 : order.order_id;
1100
+ if (orderId !== void 0 && orderId !== null && orderId !== "") {
1101
+ return String(orderId);
1102
+ }
1103
+ return "";
1104
+ }
1105
+ getOrderIdentityMatchKeys(order) {
1106
+ return this.getOrderIdentityEntries(order).map((entry) => `${entry.field}:${entry.key}`);
1107
+ }
1108
+ doOrdersShareIdentity(left, right) {
1109
+ const leftKeys = new Set(this.getOrderIdentityMatchKeys(left));
1110
+ if (leftKeys.size === 0)
1111
+ return false;
1112
+ return this.getOrderIdentityMatchKeys(right).some((key) => leftKeys.has(key));
1113
+ }
1114
+ findOrderIndexByIdentity(orders, target) {
1115
+ if (this.getOrderIdentityMatchKeys(target).length === 0)
1116
+ return -1;
1117
+ return orders.findIndex((order) => this.doOrdersShareIdentity(order, target));
1118
+ }
1119
+ getOrderCompletenessScore(order) {
1120
+ const record = order;
1121
+ let score = this.isPendingSyncOrder(order) ? 0 : 100;
1122
+ if (!this.isBlankIdentityValue(order.order_id) && order.order_id !== record.external_sale_number)
1123
+ score += 30;
1124
+ score += this.getOrderIdentityMatchKeys(order).length * 5;
1125
+ if (Array.isArray(order.products))
1126
+ score += Math.min(order.products.length, 10);
1127
+ if (Array.isArray(order.bookings))
1128
+ score += Math.min(order.bookings.length, 10);
1129
+ if (Array.isArray(order.payments))
1130
+ score += Math.min(order.payments.length, 10);
1131
+ if (record.updated_at)
1132
+ score += 1;
1133
+ return score;
1134
+ }
1135
+ pickPreferredOrder(left, right) {
1136
+ const leftScore = this.getOrderCompletenessScore(left);
1137
+ const rightScore = this.getOrderCompletenessScore(right);
1138
+ if (rightScore >= leftScore)
1139
+ return right;
1140
+ return left;
1141
+ }
1142
+ getProductMergeKey(product) {
1143
+ var _a;
1144
+ const record = product;
1145
+ if (!record)
1146
+ return "";
1147
+ const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
1148
+ if (!this.isBlankIdentityValue(metadataUid))
1149
+ return `uid:${String(metadataUid)}`;
1150
+ const topLevelUid = record.unique_identification_number;
1151
+ if (!this.isBlankIdentityValue(topLevelUid))
1152
+ return `uid:${String(topLevelUid)}`;
1153
+ const orderDetailId = record.order_detail_id;
1154
+ if (!this.isBlankIdentityValue(orderDetailId))
1155
+ return `detail:${String(orderDetailId)}`;
1156
+ const bookingUid = record.booking_uid;
1157
+ if (!this.isBlankIdentityValue(bookingUid))
1158
+ return `booking:${String(bookingUid)}`;
1159
+ return "";
1160
+ }
1161
+ mergeOrderProductLists(preferred, secondary) {
1162
+ const preferredList = Array.isArray(preferred) ? preferred : [];
1163
+ const secondaryList = Array.isArray(secondary) ? secondary : [];
1164
+ if (secondaryList.length === 0)
1165
+ return preferredList;
1166
+ if (preferredList.length === 0)
1167
+ return secondaryList;
1168
+ const seenKeys = /* @__PURE__ */ new Set();
1169
+ for (const item of preferredList) {
1170
+ const key = this.getProductMergeKey(item);
1171
+ if (key)
1172
+ seenKeys.add(key);
1173
+ }
1174
+ const result = [...preferredList];
1175
+ for (const item of secondaryList) {
1176
+ const key = this.getProductMergeKey(item);
1177
+ if (!key || seenKeys.has(key))
1178
+ continue;
1179
+ seenKeys.add(key);
1180
+ result.push((0, import_lodash_es.cloneDeep)(item));
1181
+ }
1182
+ return result;
1183
+ }
1184
+ mergeOrderRecords(existing, incoming) {
1185
+ const preferred = this.pickPreferredOrder(existing, incoming);
1186
+ const secondary = preferred === existing ? incoming : existing;
1187
+ const merged = {
1188
+ ...secondary,
1189
+ ...preferred
1190
+ };
1191
+ const fieldsToPreserve = [
1192
+ "order_id",
1193
+ "external_sale_number",
1194
+ "order_number",
1195
+ "shop_order_number",
1196
+ "shop_full_order_number"
1197
+ ];
1198
+ const incomingPatchFields = [
1199
+ "payment_status",
1200
+ "status",
1201
+ "shipping_status",
1202
+ "updated_at",
1203
+ "shop_discount",
1204
+ "summary",
1205
+ "payments",
1206
+ "products",
1207
+ "bookings"
1208
+ ];
1209
+ const mergedRecord = merged;
1210
+ const preferredRecord = preferred;
1211
+ const secondaryRecord = secondary;
1212
+ const incomingRecord = incoming;
1213
+ for (const field of fieldsToPreserve) {
1214
+ if (!this.isBlankIdentityValue(preferredRecord[field])) {
1215
+ mergedRecord[field] = preferredRecord[field];
1216
+ continue;
1217
+ }
1218
+ if (!this.isBlankIdentityValue(secondaryRecord[field])) {
1219
+ mergedRecord[field] = secondaryRecord[field];
1220
+ }
1221
+ }
1222
+ for (const field of incomingPatchFields) {
1223
+ if (!Object.prototype.hasOwnProperty.call(incomingRecord, field))
1224
+ continue;
1225
+ if (incomingRecord[field] === void 0 || incomingRecord[field] === null)
1226
+ continue;
1227
+ if (typeof incomingRecord[field] === "string" && incomingRecord[field] === "")
1228
+ continue;
1229
+ mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
1230
+ }
1231
+ mergedRecord.products = this.mergeOrderProductLists(preferredRecord.products, secondaryRecord.products);
1232
+ if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
1233
+ merged.need_sync = 0;
1234
+ }
1235
+ return merged;
1236
+ }
1237
+ summarizeDuplicateOrders(orders) {
1238
+ const groups = /* @__PURE__ */ new Map();
1239
+ for (const order of orders) {
1240
+ for (const key of this.getOrderIdentityMatchKeys(order)) {
1241
+ const group = groups.get(key) || [];
1242
+ group.push(order);
1243
+ groups.set(key, group);
1244
+ }
1245
+ }
1246
+ return [...groups.entries()].filter(([, group]) => group.length > 1).slice(0, 20).map(([key, group]) => ({
1247
+ key,
1248
+ count: group.length,
1249
+ orders: group.map((order) => ({
1250
+ order_id: order.order_id ?? null,
1251
+ external_sale_number: order.external_sale_number ?? null,
1252
+ shop_order_number: order.shop_order_number ?? null,
1253
+ shop_full_order_number: order.shop_full_order_number ?? null,
1254
+ need_sync: order.need_sync ?? null
1255
+ }))
1256
+ }));
1257
+ }
1258
+ logDuplicateOrders(source, orders) {
1259
+ const duplicateGroups = this.summarizeDuplicateOrders(orders);
1260
+ if (duplicateGroups.length === 0)
1261
+ return;
1262
+ this.logWarning("检测到重复订单身份键", {
1263
+ source,
1264
+ duplicateGroupCount: duplicateGroups.length,
1265
+ duplicateGroups
1266
+ });
1267
+ }
1268
+ compactOrderListByIdentity(orders, source) {
1269
+ const list = [];
1270
+ let removedCount = 0;
1271
+ for (const order of orders) {
1272
+ const matchIndex = this.findOrderIndexByIdentity(list, order);
1273
+ if (matchIndex < 0) {
1274
+ list.push(order);
1275
+ continue;
1276
+ }
1277
+ list[matchIndex] = this.mergeOrderRecords(list[matchIndex], order);
1278
+ removedCount += 1;
1279
+ }
1280
+ if (removedCount > 0) {
1281
+ this.logWarning("订单列表重复项已压缩", {
1282
+ source,
1283
+ beforeCount: orders.length,
1284
+ afterCount: list.length,
1285
+ removedCount
1286
+ });
1287
+ } else {
1288
+ this.logDuplicateOrders(source, orders);
1289
+ }
1290
+ return { list, removedCount };
1291
+ }
685
1292
  /**
686
1293
  * 当前订单拉取窗口:
687
1294
  * - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
@@ -752,39 +1359,221 @@ var OrderModule = class extends import_BaseModule.BaseModule {
752
1359
  return [];
753
1360
  }
754
1361
  }
755
- async saveOrdersToSQLite(orderList) {
756
- if (!this.dbManager)
1362
+ isPendingSyncOrder(order) {
1363
+ return Number(order == null ? void 0 : order.need_sync) === 1;
1364
+ }
1365
+ normalizeRemoteSyncedOrder(order) {
1366
+ if (this.isPendingSyncOrder(order))
1367
+ return order;
1368
+ return {
1369
+ ...order,
1370
+ need_sync: 0
1371
+ };
1372
+ }
1373
+ mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
1374
+ const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
1375
+ for (const order of existingOrders) {
1376
+ if (!this.isPendingSyncOrder(order))
1377
+ continue;
1378
+ const matchIndex = this.findOrderIndexByIdentity(merged, order);
1379
+ if (matchIndex >= 0) {
1380
+ merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
1381
+ continue;
1382
+ }
1383
+ if (!this.getOrderStorageKey(order))
1384
+ continue;
1385
+ merged.push(order);
1386
+ }
1387
+ return this.compactOrderListByIdentity(merged, "mergeRemoteSnapshotWithPendingOrders").list;
1388
+ }
1389
+ /**
1390
+ * 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
1391
+ *
1392
+ * @example
1393
+ * await this.runInOrderSQLiteSaveQueue(async () => {
1394
+ * await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, orders)
1395
+ * })
1396
+ */
1397
+ async runInOrderSQLiteSaveQueue(task) {
1398
+ const queuedTask = this.orderSQLiteSaveQueue.then(task, task);
1399
+ this.orderSQLiteSaveQueue = queuedTask.then(() => void 0, () => void 0);
1400
+ return queuedTask;
1401
+ }
1402
+ /**
1403
+ * 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
1404
+ *
1405
+ * @example
1406
+ * await this.patchOrdersInSQLite(freshOrders)
1407
+ */
1408
+ async patchOrdersInSQLite(orders, source, mergeActions = {}) {
1409
+ if (!this.dbManager || orders.length === 0) {
757
1410
  return;
1411
+ }
1412
+ const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).filter((order) => this.getOrderStorageKey(order));
1413
+ if (ordersSnapshot.length === 0) {
1414
+ return;
1415
+ }
1416
+ const { toWrite, skipped } = this.filterRedundantPatchOrders(
1417
+ source,
1418
+ ordersSnapshot,
1419
+ mergeActions
1420
+ );
1421
+ if (toWrite.length === 0) {
1422
+ return;
1423
+ }
1424
+ const compactedToWrite = this.compactOrderListByIdentity(toWrite, `${source}.sqlitePatch`).list;
1425
+ if (compactedToWrite.length === 0) {
1426
+ return;
1427
+ }
758
1428
  try {
759
- this.logInfo("saveOrdersToSQLite-开始", {
760
- count: orderList.length
1429
+ await this.runInOrderSQLiteSaveQueue(async () => {
1430
+ let writeMethod = "none";
1431
+ this.logInfo("patchOrdersInSQLite-开始", {
1432
+ source,
1433
+ count: compactedToWrite.length,
1434
+ dedupedCount: skipped.length
1435
+ });
1436
+ if (typeof this.dbManager.bulkUpdate === "function") {
1437
+ writeMethod = "bulkUpdate";
1438
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, compactedToWrite);
1439
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1440
+ writeMethod = "bulkAdd";
1441
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, compactedToWrite);
1442
+ } else if (typeof this.dbManager.update === "function") {
1443
+ writeMethod = "update";
1444
+ for (const order of compactedToWrite) {
1445
+ await this.dbManager.update(INDEXDB_STORE_NAME, order);
1446
+ }
1447
+ }
1448
+ this.recordRecentSqliteWrite(source, compactedToWrite);
1449
+ this.logInfo("patchOrdersInSQLite-完成", {
1450
+ source,
1451
+ count: compactedToWrite.length,
1452
+ writeMethod,
1453
+ dedupedCount: skipped.length
1454
+ });
761
1455
  });
762
- await this.dbManager.clear(INDEXDB_STORE_NAME);
763
- this.logInfo("saveOrdersToSQLite-clear完成", {
764
- count: orderList.length
1456
+ } catch (error) {
1457
+ this.logError("增量保存订单到 SQLite 失败", {
1458
+ error: error instanceof Error ? error.message : String(error),
1459
+ orderCount: ordersSnapshot.length
765
1460
  });
766
- if (orderList.length === 0)
767
- return;
768
- await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orderList);
769
- this.logInfo("saveOrdersToSQLite-bulkAdd完成", {
770
- count: orderList.length
1461
+ }
1462
+ }
1463
+ /**
1464
+ * 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
1465
+ *
1466
+ * @example
1467
+ * await this.updateOrderInSQLite(freshOrder)
1468
+ */
1469
+ async updateOrderInSQLite(order, source) {
1470
+ if (!this.dbManager || !this.getOrderStorageKey(order)) {
1471
+ return;
1472
+ }
1473
+ const orderSnapshot = (0, import_lodash_es.cloneDeep)(order);
1474
+ try {
1475
+ await this.runInOrderSQLiteSaveQueue(async () => {
1476
+ let writeMethod = "none";
1477
+ this.logInfo("updateOrderInSQLite-开始", {
1478
+ source,
1479
+ orderId: orderSnapshot.order_id ?? null,
1480
+ storageKey: this.getOrderStorageKey(orderSnapshot)
1481
+ });
1482
+ if (typeof this.dbManager.update === "function") {
1483
+ writeMethod = "update";
1484
+ await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
1485
+ } else if (typeof this.dbManager.bulkUpdate === "function") {
1486
+ writeMethod = "bulkUpdate";
1487
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
1488
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1489
+ writeMethod = "bulkAdd";
1490
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
1491
+ }
1492
+ this.recordRecentSqliteWrite(source, [orderSnapshot]);
1493
+ this.logInfo("updateOrderInSQLite-完成", {
1494
+ source,
1495
+ orderId: orderSnapshot.order_id ?? null,
1496
+ writeMethod
1497
+ });
1498
+ });
1499
+ } catch (error) {
1500
+ this.logError("单条保存订单到 SQLite 失败", {
1501
+ error: error instanceof Error ? error.message : String(error),
1502
+ orderId: orderSnapshot.order_id ?? null
1503
+ });
1504
+ }
1505
+ }
1506
+ /**
1507
+ * 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
1508
+ *
1509
+ * @example
1510
+ * await this.replaceOrdersSnapshotInSQLite(orderList)
1511
+ */
1512
+ async replaceOrdersSnapshotInSQLite(orderList, source) {
1513
+ if (!this.dbManager) {
1514
+ return this.compactOrderListByIdentity(
1515
+ orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
1516
+ `${source}.snapshotNoDb`
1517
+ ).list;
1518
+ }
1519
+ const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList);
1520
+ let mergedSnapshot = this.compactOrderListByIdentity(
1521
+ remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
1522
+ `${source}.remoteSnapshot`
1523
+ ).list;
1524
+ try {
1525
+ await this.runInOrderSQLiteSaveQueue(async () => {
1526
+ const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
1527
+ const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
1528
+ remoteSnapshot,
1529
+ existingOrders || []
1530
+ );
1531
+ mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
1532
+ this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
1533
+ source,
1534
+ count: mergedSnapshot.length,
1535
+ remoteCount: remoteSnapshot.length,
1536
+ preservedPendingCount: mergedSnapshot.length - remoteSnapshot.length
1537
+ });
1538
+ await this.dbManager.clear(INDEXDB_STORE_NAME);
1539
+ this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
1540
+ count: mergedSnapshot.length
1541
+ });
1542
+ if (mergedSnapshot.length === 0) {
1543
+ return;
1544
+ }
1545
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, mergedSnapshot);
1546
+ this.recordRecentSqliteWrite(source, mergedSnapshot);
1547
+ this.logInfo("replaceOrdersSnapshotInSQLite-bulkAdd完成", {
1548
+ source,
1549
+ count: mergedSnapshot.length
1550
+ });
771
1551
  });
772
1552
  } catch (error) {
773
- this.logError("保存订单到 SQLite 失败", {
1553
+ this.logError("全量保存订单到 SQLite 失败", {
774
1554
  error: error instanceof Error ? error.message : String(error),
775
- orderList: orderList.length
1555
+ orderList: remoteSnapshot.length
776
1556
  });
777
1557
  }
1558
+ return mergedSnapshot;
778
1559
  }
1560
+ /**
1561
+ * 清空订单模块的内存数据和本地 SQLite 订单表。
1562
+ *
1563
+ * @example
1564
+ * await orderModule.clear()
1565
+ */
779
1566
  async clear() {
780
1567
  this.store.list = [];
781
1568
  this.store.map = /* @__PURE__ */ new Map();
782
1569
  this.resourceIdIndex.clear();
783
1570
  if (this.dbManager) {
784
- await this.dbManager.clear(INDEXDB_STORE_NAME);
1571
+ await this.runInOrderSQLiteSaveQueue(async () => {
1572
+ await this.dbManager.clear(INDEXDB_STORE_NAME);
1573
+ });
785
1574
  }
786
1575
  this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
787
- this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
1576
+ this.emitOrdersChanged([], "clear");
788
1577
  }
789
1578
  };
790
1579
  // Annotate the CommonJS export names for ESM import in node: