@pisell/pisellos 2.2.244 → 2.2.246

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
  2. package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
  3. package/dist/modules/BookingContext/index.d.ts +48 -0
  4. package/dist/modules/BookingContext/index.js +566 -0
  5. package/dist/modules/BookingContext/types.d.ts +102 -0
  6. package/dist/modules/BookingContext/types.js +51 -0
  7. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +284 -0
  9. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  10. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +148 -0
  11. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  12. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +218 -0
  13. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  14. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  15. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  16. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  17. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  18. package/dist/modules/BookingContext/utils/index.js +11 -0
  19. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  20. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  21. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  22. package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
  23. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  24. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  25. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  26. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  27. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  28. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  29. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  30. package/dist/modules/BookingContext/utils/resources.js +486 -0
  31. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  32. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  33. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  34. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  35. package/dist/modules/Cart/utils/cartProduct.js +24 -3
  36. package/dist/modules/Cart/utils/changePrice.js +11 -11
  37. package/dist/modules/Customer/index.d.ts +20 -0
  38. package/dist/modules/Customer/index.js +172 -83
  39. package/dist/modules/Customer/types.d.ts +2 -0
  40. package/dist/modules/Discount/index.d.ts +1 -1
  41. package/dist/modules/Discount/index.js +13 -6
  42. package/dist/modules/Discount/types.d.ts +1 -0
  43. package/dist/modules/OpenData/index.d.ts +8 -0
  44. package/dist/modules/OpenData/index.js +37 -17
  45. package/dist/modules/Order/index.d.ts +277 -18
  46. package/dist/modules/Order/index.js +3581 -779
  47. package/dist/modules/Order/types.d.ts +286 -31
  48. package/dist/modules/Order/types.js +38 -0
  49. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  50. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  51. package/dist/modules/Order/utils.d.ts +147 -5
  52. package/dist/modules/Order/utils.js +750 -104
  53. package/dist/modules/Payment/index.d.ts +10 -13
  54. package/dist/modules/Payment/index.js +467 -837
  55. package/dist/modules/Payment/types.d.ts +2 -0
  56. package/dist/modules/Payment/utils.js +2 -1
  57. package/dist/modules/Payment/walletpass.js +41 -25
  58. package/dist/modules/ProductList/index.d.ts +16 -12
  59. package/dist/modules/ProductList/index.js +133 -59
  60. package/dist/modules/ProductList/types.d.ts +14 -0
  61. package/dist/modules/Quotation/index.d.ts +0 -1
  62. package/dist/modules/Quotation/index.js +25 -22
  63. package/dist/modules/Rules/index.d.ts +4 -0
  64. package/dist/modules/Rules/index.js +97 -70
  65. package/dist/modules/Rules/types.d.ts +1 -0
  66. package/dist/modules/SalesSummary/index.d.ts +8 -25
  67. package/dist/modules/SalesSummary/index.js +86 -35
  68. package/dist/modules/SalesSummary/types.d.ts +4 -1
  69. package/dist/modules/SalesSummary/utils.d.ts +2 -25
  70. package/dist/modules/SalesSummary/utils.js +794 -162
  71. package/dist/modules/Schedule/index.d.ts +7 -0
  72. package/dist/modules/Schedule/index.js +24 -2
  73. package/dist/modules/Summary/index.js +4 -3
  74. package/dist/modules/SurchargeList/index.d.ts +16 -0
  75. package/dist/modules/SurchargeList/index.js +162 -0
  76. package/dist/modules/SurchargeList/types.d.ts +11 -0
  77. package/dist/modules/SurchargeList/types.js +1 -0
  78. package/dist/modules/index.d.ts +2 -0
  79. package/dist/modules/index.js +3 -1
  80. package/dist/plugins/request.d.ts +1 -0
  81. package/dist/server/index.d.ts +204 -1
  82. package/dist/server/index.js +3654 -922
  83. package/dist/server/modules/index.d.ts +2 -0
  84. package/dist/server/modules/index.js +2 -0
  85. package/dist/server/modules/order/index.d.ts +120 -3
  86. package/dist/server/modules/order/index.js +1762 -448
  87. package/dist/server/modules/order/types.d.ts +32 -3
  88. package/dist/server/modules/order/types.js +8 -0
  89. package/dist/server/modules/order/utils/filterBookings.js +26 -3
  90. package/dist/server/modules/order/utils/filterOrders.js +23 -8
  91. package/dist/server/modules/payment/index.d.ts +28 -0
  92. package/dist/server/modules/payment/index.js +305 -0
  93. package/dist/server/modules/payment/types.d.ts +9 -0
  94. package/dist/server/modules/payment/types.js +1 -0
  95. package/dist/server/modules/products/index.d.ts +34 -7
  96. package/dist/server/modules/products/index.js +631 -317
  97. package/dist/server/modules/resource/index.d.ts +2 -0
  98. package/dist/server/modules/resource/index.js +29 -3
  99. package/dist/server/modules/schedule/index.d.ts +4 -4
  100. package/dist/server/modules/schedule/index.js +111 -88
  101. package/dist/server/test.json +713 -0
  102. package/dist/server/utils/small-ticket.d.ts +71 -0
  103. package/dist/server/utils/small-ticket.js +840 -0
  104. package/dist/solution/BaseSales/index.d.ts +133 -10
  105. package/dist/solution/BaseSales/index.js +1950 -447
  106. package/dist/solution/BaseSales/types.d.ts +82 -6
  107. package/dist/solution/BaseSales/types.js +5 -4
  108. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  109. package/dist/solution/BaseSales/utils/cartPromotion.js +1438 -0
  110. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  111. package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
  112. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  113. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +105 -24
  114. package/dist/solution/BaseSales/utils.d.ts +1 -1
  115. package/dist/solution/BaseSales/utils.js +62 -21
  116. package/dist/solution/BookingByStep/index.d.ts +1 -1
  117. package/dist/solution/BookingTicket/index.d.ts +271 -11
  118. package/dist/solution/BookingTicket/index.js +1777 -242
  119. package/dist/solution/BookingTicket/types.d.ts +118 -1
  120. package/dist/solution/BookingTicket/types.js +41 -2
  121. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  122. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  123. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  124. package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
  125. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  126. package/dist/solution/BookingTicket/utils/bookingStatus.js +70 -0
  127. package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
  128. package/dist/solution/BookingTicket/utils/cartView.js +94 -7
  129. package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  130. package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
  131. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  132. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
  133. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  134. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
  135. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  136. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
  137. package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  138. package/dist/solution/BookingTicket/utils/scan/index.js +20 -8
  139. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  140. package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
  141. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  142. package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
  143. package/dist/solution/Checkout/index.d.ts +1 -0
  144. package/dist/solution/Checkout/index.js +10 -9
  145. package/dist/solution/RegisterAndLogin/config.js +2 -10
  146. package/dist/solution/ScanOrder/index.d.ts +9 -3
  147. package/dist/solution/ScanOrder/index.js +241 -134
  148. package/dist/solution/ScanOrder/types.d.ts +9 -5
  149. package/dist/solution/ScanOrder/types.js +2 -3
  150. package/dist/solution/ScanOrder/utils.d.ts +1 -1
  151. package/dist/solution/ScanOrder/utils.js +84 -22
  152. package/dist/solution/VenueBooking/index.d.ts +5 -2
  153. package/dist/solution/VenueBooking/index.js +110 -59
  154. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  155. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  156. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
  157. package/dist/types/index.d.ts +10 -0
  158. package/lib/model/strategy/adapter/promotion/evaluator.js +2 -1
  159. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  160. package/lib/model/strategy/adapter/walletPass/utils.js +3 -2
  161. package/lib/modules/BookingContext/index.d.ts +48 -0
  162. package/lib/modules/BookingContext/index.js +368 -0
  163. package/lib/modules/BookingContext/types.d.ts +102 -0
  164. package/lib/modules/BookingContext/types.js +34 -0
  165. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  166. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
  167. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  168. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +154 -0
  169. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  170. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +201 -0
  171. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  172. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  173. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  174. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  175. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  176. package/lib/modules/BookingContext/utils/index.js +43 -0
  177. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  178. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  179. package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  180. package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
  181. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  182. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  183. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  184. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  185. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  186. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  187. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  188. package/lib/modules/BookingContext/utils/resources.js +377 -0
  189. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  190. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  191. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  192. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  193. package/lib/modules/Cart/utils/cartProduct.js +20 -3
  194. package/lib/modules/Cart/utils/changePrice.js +12 -20
  195. package/lib/modules/Customer/index.d.ts +20 -0
  196. package/lib/modules/Customer/index.js +64 -11
  197. package/lib/modules/Customer/types.d.ts +2 -0
  198. package/lib/modules/Discount/index.d.ts +1 -1
  199. package/lib/modules/Discount/index.js +9 -1
  200. package/lib/modules/Discount/types.d.ts +1 -0
  201. package/lib/modules/OpenData/index.d.ts +8 -0
  202. package/lib/modules/OpenData/index.js +19 -5
  203. package/lib/modules/Order/index.d.ts +277 -18
  204. package/lib/modules/Order/index.js +2317 -337
  205. package/lib/modules/Order/types.d.ts +286 -31
  206. package/lib/modules/Order/types.js +1 -0
  207. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  208. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  209. package/lib/modules/Order/utils.d.ts +147 -5
  210. package/lib/modules/Order/utils.js +615 -46
  211. package/lib/modules/Payment/index.d.ts +10 -13
  212. package/lib/modules/Payment/index.js +18 -150
  213. package/lib/modules/Payment/types.d.ts +2 -0
  214. package/lib/modules/Payment/utils.js +2 -1
  215. package/lib/modules/Payment/walletpass.js +16 -3
  216. package/lib/modules/ProductList/index.d.ts +16 -12
  217. package/lib/modules/ProductList/index.js +41 -4
  218. package/lib/modules/ProductList/types.d.ts +14 -0
  219. package/lib/modules/Quotation/index.d.ts +0 -1
  220. package/lib/modules/Quotation/index.js +19 -16
  221. package/lib/modules/Rules/index.d.ts +4 -0
  222. package/lib/modules/Rules/index.js +137 -120
  223. package/lib/modules/Rules/types.d.ts +1 -0
  224. package/lib/modules/SalesSummary/index.d.ts +8 -25
  225. package/lib/modules/SalesSummary/index.js +30 -4
  226. package/lib/modules/SalesSummary/types.d.ts +4 -1
  227. package/lib/modules/SalesSummary/utils.d.ts +2 -25
  228. package/lib/modules/SalesSummary/utils.js +645 -91
  229. package/lib/modules/Schedule/index.d.ts +7 -0
  230. package/lib/modules/Schedule/index.js +17 -1
  231. package/lib/modules/Summary/index.js +5 -4
  232. package/lib/modules/SurchargeList/index.d.ts +16 -0
  233. package/lib/modules/SurchargeList/index.js +89 -0
  234. package/lib/modules/SurchargeList/types.d.ts +11 -0
  235. package/lib/modules/SurchargeList/types.js +17 -0
  236. package/lib/modules/index.d.ts +2 -0
  237. package/lib/modules/index.js +5 -1
  238. package/lib/plugins/request.d.ts +1 -0
  239. package/lib/server/index.d.ts +204 -1
  240. package/lib/server/index.js +1891 -59
  241. package/lib/server/modules/index.d.ts +2 -0
  242. package/lib/server/modules/index.js +3 -0
  243. package/lib/server/modules/order/index.d.ts +120 -3
  244. package/lib/server/modules/order/index.js +887 -94
  245. package/lib/server/modules/order/types.d.ts +32 -3
  246. package/lib/server/modules/order/utils/filterBookings.js +24 -5
  247. package/lib/server/modules/order/utils/filterOrders.js +15 -6
  248. package/lib/server/modules/payment/index.d.ts +28 -0
  249. package/lib/server/modules/payment/index.js +192 -0
  250. package/lib/server/modules/payment/types.d.ts +9 -0
  251. package/lib/server/modules/payment/types.js +17 -0
  252. package/lib/server/modules/products/index.d.ts +34 -7
  253. package/lib/server/modules/products/index.js +189 -54
  254. package/lib/server/modules/resource/index.d.ts +2 -0
  255. package/lib/server/modules/resource/index.js +27 -3
  256. package/lib/server/modules/schedule/index.d.ts +4 -4
  257. package/lib/server/modules/schedule/index.js +47 -40
  258. package/lib/server/test.json +713 -0
  259. package/lib/server/utils/small-ticket.d.ts +71 -0
  260. package/lib/server/utils/small-ticket.js +800 -0
  261. package/lib/solution/BaseSales/index.d.ts +133 -10
  262. package/lib/solution/BaseSales/index.js +1111 -63
  263. package/lib/solution/BaseSales/types.d.ts +82 -6
  264. package/lib/solution/BaseSales/types.js +3 -1
  265. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  266. package/lib/solution/BaseSales/utils/cartPromotion.js +992 -0
  267. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  268. package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
  269. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  270. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +106 -18
  271. package/lib/solution/BaseSales/utils.d.ts +1 -1
  272. package/lib/solution/BaseSales/utils.js +54 -10
  273. package/lib/solution/BookingByStep/index.d.ts +1 -1
  274. package/lib/solution/BookingTicket/index.d.ts +271 -11
  275. package/lib/solution/BookingTicket/index.js +922 -29
  276. package/lib/solution/BookingTicket/types.d.ts +118 -1
  277. package/lib/solution/BookingTicket/types.js +11 -0
  278. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  279. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  280. package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  281. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
  282. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
  283. package/lib/solution/BookingTicket/utils/bookingStatus.js +44 -2
  284. package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
  285. package/lib/solution/BookingTicket/utils/cartView.js +61 -6
  286. package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  287. package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
  288. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  289. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
  290. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  291. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
  292. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  293. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
  294. package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  295. package/lib/solution/BookingTicket/utils/scan/index.js +17 -3
  296. package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  297. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
  298. package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  299. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
  300. package/lib/solution/Checkout/index.d.ts +1 -0
  301. package/lib/solution/Checkout/index.js +1 -2
  302. package/lib/solution/RegisterAndLogin/config.js +2 -10
  303. package/lib/solution/ScanOrder/index.d.ts +9 -3
  304. package/lib/solution/ScanOrder/index.js +153 -70
  305. package/lib/solution/ScanOrder/types.d.ts +9 -5
  306. package/lib/solution/ScanOrder/utils.d.ts +1 -1
  307. package/lib/solution/ScanOrder/utils.js +83 -17
  308. package/lib/solution/VenueBooking/index.d.ts +5 -2
  309. package/lib/solution/VenueBooking/index.js +54 -17
  310. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  311. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  312. package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
  313. package/lib/types/index.d.ts +10 -0
  314. package/package.json +1 -1
  315. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  316. package/lib/solution/Checkout/appointmentDemo.json +0 -1
@@ -41,6 +41,7 @@ var import_schedule = require("./modules/schedule");
41
41
  var import_resource = require("./modules/resource");
42
42
  var import_floor_plan = require("./modules/floor-plan");
43
43
  var import_types = require("./modules/floor-plan/types");
44
+ var import_payment = require("./modules/payment");
44
45
  var import_schedule2 = require("./utils/schedule");
45
46
  var import_types2 = require("./modules/products/types");
46
47
  var import_product = require("./utils/product");
@@ -48,9 +49,22 @@ var import_order = require("./modules/order");
48
49
  var import_types3 = require("./modules/order/types");
49
50
  var import_filterOrders = require("./modules/order/utils/filterOrders");
50
51
  var import_filterBookings = require("./modules/order/utils/filterBookings");
52
+ var import_small_ticket = require("./utils/small-ticket");
51
53
  __reExport(server_exports, require("./modules"), module.exports);
54
+ var PRODUCT_TITLE_SNAPSHOT_KEYS = [
55
+ "en",
56
+ "ja",
57
+ "pt",
58
+ "auto",
59
+ "zh-CN",
60
+ "zh-HK",
61
+ "kitchen",
62
+ "original"
63
+ ];
52
64
  var Server = class {
53
65
  constructor(core) {
66
+ this.quotationAvailableCache = /* @__PURE__ */ new Map();
67
+ this.quotationAvailableInFlight = /* @__PURE__ */ new Map();
54
68
  /** GET 前缀路由(最长前缀优先匹配) */
55
69
  this.prefixRouterGet = [];
56
70
  // 路由注册表
@@ -69,6 +83,8 @@ var Server = class {
69
83
  this.bookingRemoteCache = /* @__PURE__ */ new Map();
70
84
  this.BOOKING_REMOTE_CACHE_TTL_MS = 5 * 60 * 1e3;
71
85
  this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
86
+ this.salesSearchSubscribers = /* @__PURE__ */ new Map();
87
+ this.deviceTaskActionsRegistered = false;
72
88
  this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
73
89
  // 模块注册表 - 定义所有可用的模块配置
74
90
  this.moduleRegistry = {
@@ -120,6 +136,15 @@ var Server = class {
120
136
  list: []
121
137
  }
122
138
  },
139
+ payment: {
140
+ name: "payment",
141
+ moduleClass: import_payment.PaymentServerModule,
142
+ moduleName: "server_payment",
143
+ version: "1.0.0",
144
+ defaultStore: {
145
+ payMethods: []
146
+ }
147
+ },
123
148
  resource: {
124
149
  name: "resource",
125
150
  moduleClass: import_resource.ResourceModule,
@@ -143,31 +168,67 @@ var Server = class {
143
168
  }
144
169
  }
145
170
  };
171
+ this.handlePaymentMethods = async ({ data, config }) => {
172
+ const payment = await this.getPaymentRouteModule();
173
+ const payMethods = await payment.getPayMethodListAsync({
174
+ shouldFilter: (data == null ? void 0 : data.filterPaymentMethods) === true || (config == null ? void 0 : config.filterPaymentMethods) === true
175
+ });
176
+ return {
177
+ code: 200,
178
+ status: true,
179
+ data: payMethods
180
+ };
181
+ };
182
+ this.handleQuotationAvailable = async ({ data }) => {
183
+ const queryPayload = data && typeof data === "object" ? { ...data } : {};
184
+ const cacheKey = this.stableSerialize(queryPayload);
185
+ if (this.quotationAvailableCache.has(cacheKey)) {
186
+ this.logInfo("handleQuotationAvailable: 命中运行时缓存", { cacheKey });
187
+ return this.quotationAvailableCache.get(cacheKey);
188
+ }
189
+ const inFlight = this.quotationAvailableInFlight.get(cacheKey);
190
+ if (inFlight) {
191
+ this.logInfo("handleQuotationAvailable: 复用进行中的请求", { cacheKey });
192
+ return inFlight;
193
+ }
194
+ const requestPromise = this.fetchQuotationAvailableFromAPI(queryPayload).then((response) => {
195
+ if (this.isSuccessfulRemoteResponse(response)) {
196
+ this.quotationAvailableCache.set(cacheKey, response);
197
+ }
198
+ return response;
199
+ }).finally(() => {
200
+ this.quotationAvailableInFlight.delete(cacheKey);
201
+ });
202
+ this.quotationAvailableInFlight.set(cacheKey, requestPromise);
203
+ return requestPromise;
204
+ };
146
205
  /**
147
206
  * 处理商品查询请求
148
207
  * 存储订阅者信息,便于数据变更时推送最新结果
149
208
  */
150
209
  this.handleProductQuery = async ({ url, method, data, config }) => {
151
210
  console.log("[Server] handleProductQuery:", url, method, data, config);
152
- const { menu_list_ids, schedule_datetime, schedule_date, customer_id } = data;
211
+ const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type } = data;
153
212
  const { callback, subscriberId } = config || {};
154
213
  this.logInfo("handleProductQuery: 开始处理商品查询请求", {
155
214
  menu_list_ids,
215
+ ids,
156
216
  schedule_datetime,
157
217
  schedule_date,
158
- customer_id
218
+ customer_id,
219
+ extension_type
159
220
  });
160
221
  if (subscriberId && typeof callback === "function") {
161
222
  this.productQuerySubscribers.set(subscriberId, {
162
223
  callback,
163
- context: { menu_list_ids, schedule_date, schedule_datetime, customer_id }
224
+ context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type }
164
225
  });
165
226
  this.logInfo("handleProductQuery: 已注册订阅者", {
166
227
  subscriberId,
167
228
  totalSubscribers: this.productQuerySubscribers.size
168
229
  });
169
230
  }
170
- return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime, customer_id });
231
+ return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type });
171
232
  };
172
233
  /**
173
234
  * 按商品 id 查询单条(GET /shop/product/query/:productId)
@@ -269,6 +330,41 @@ var Server = class {
269
330
  }
270
331
  return { code: 200, message: "ok", status: true };
271
332
  };
333
+ /**
334
+ * 处理 sales 单模块搜索:请求透传后端,仅在 OS 层维护已返回订单号集合。
335
+ *
336
+ * @example
337
+ * await this.handleSalesSearchModule({ url: '/shop/es/search/sales', method: 'post', data: { keyword: 'A' } })
338
+ */
339
+ this.handleSalesSearchModule = async ({ data, config }) => {
340
+ return this.handleSalesSearchRequest("single", "/shop/es/search/sales", data, config);
341
+ };
342
+ /**
343
+ * 处理 sales 聚合搜索:请求透传后端,仅订阅 sales 分组的已返回订单号。
344
+ *
345
+ * @example
346
+ * await this.handleSalesSearchAggregate({ url: '/shop/es/search', method: 'post', data: { modules: [] } })
347
+ */
348
+ this.handleSalesSearchAggregate = async ({ data, config }) => {
349
+ return this.handleSalesSearchRequest("aggregate", "/shop/es/search", data, config);
350
+ };
351
+ /**
352
+ * 取消 sales 搜索订阅。
353
+ *
354
+ * @example
355
+ * await this.handleUnsubscribeSalesSearch({ data: { subscriberId: 'global-search-order' } } as any)
356
+ */
357
+ this.handleUnsubscribeSalesSearch = async ({ data }) => {
358
+ const { subscriberId } = data || {};
359
+ if (subscriberId) {
360
+ this.salesSearchSubscribers.delete(subscriberId);
361
+ this.logInfo("handleUnsubscribeSalesSearch: 已移除订阅者", {
362
+ subscriberId,
363
+ remaining: this.salesSearchSubscribers.size
364
+ });
365
+ }
366
+ return { code: 200, message: "ok", status: true };
367
+ };
272
368
  /**
273
369
  * 日历(compact_fields)场景下要直接在 SSE 层排除的订单类型:
274
370
  * 这些类型不会出现在日历上,拉取它们只会浪费带宽并增加前端过滤成本。
@@ -372,7 +468,13 @@ var Server = class {
372
468
  * @example 批量:GET /update/localOrder?order_ids=96971,96972,96973
373
469
  */
374
470
  this.handleUpdateLocalOrder = async ({ url, data }) => {
375
- var _a;
471
+ var _a, _b;
472
+ if (typeof (data == null ? void 0 : data.order_id) === "string" && ((_a = data == null ? void 0 : data.order_id) == null ? void 0 : _a.startsWith("LOCAL_"))) {
473
+ return {
474
+ code: 200,
475
+ status: true
476
+ };
477
+ }
376
478
  const batchIds = this.parseOrderIdsParam(url, data);
377
479
  if (batchIds.length > 0) {
378
480
  return this.handleUpdateLocalOrdersBatch(batchIds);
@@ -388,7 +490,7 @@ var Server = class {
388
490
  this.logError("handleUpdateLocalOrder: Order 模块未注册");
389
491
  return { code: 500, status: false, message: "Order 模块未注册", data: null };
390
492
  }
391
- if (!((_a = this.app) == null ? void 0 : _a.request)) {
493
+ if (!((_b = this.app) == null ? void 0 : _b.request)) {
392
494
  this.logError("handleUpdateLocalOrder: app.request 不可用");
393
495
  return { code: 500, status: false, message: "app.request 不可用", data: null };
394
496
  }
@@ -451,34 +553,149 @@ var Server = class {
451
553
  };
452
554
  }
453
555
  };
556
+ this.handleOrderSalesCheckout = async ({ data }) => {
557
+ return this.handleOrderCheckoutSubmit({
558
+ backendPath: "/shop/order/sales/checkout",
559
+ data,
560
+ title: "handleOrderSalesCheckout"
561
+ });
562
+ };
563
+ this.handleOrderCheckout = async ({ data }) => {
564
+ return this.handleOrderCheckoutSubmit({
565
+ backendPath: "/order/checkout",
566
+ data,
567
+ title: "handleOrderCheckout"
568
+ });
569
+ };
570
+ this.handleLocalPrintOrder = async ({ data }) => {
571
+ var _a;
572
+ try {
573
+ const inputOrder = (data == null ? void 0 : data.order) && typeof data.order === "object" ? data.order : data;
574
+ if (!inputOrder || typeof inputOrder !== "object") {
575
+ return {
576
+ code: 400,
577
+ status: false,
578
+ message: "订单数据不能为空",
579
+ data: { printed: false, order: null }
580
+ };
581
+ }
582
+ const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(data);
583
+ this.logInfo("handleLocalPrintOrder: 是否需要查找本地订单", {
584
+ shouldLookup,
585
+ inputOrder,
586
+ data
587
+ });
588
+ const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(data) : void 0;
589
+ let sourceOrder = inputOrder;
590
+ if (shouldLookup) {
591
+ if (lookup === void 0) {
592
+ return {
593
+ code: 400,
594
+ status: false,
595
+ message: "订单 lookup 缺失",
596
+ data: { printed: false, order: null }
597
+ };
598
+ }
599
+ if (!((_a = this.order) == null ? void 0 : _a.getLocalOrderByLookup)) {
600
+ return {
601
+ code: 500,
602
+ status: false,
603
+ message: "Order 模块未注册",
604
+ data: { printed: false, order: null }
605
+ };
606
+ }
607
+ const localOrder = await this.order.getLocalOrderByLookup(lookup);
608
+ if (!localOrder) {
609
+ return {
610
+ code: 404,
611
+ status: false,
612
+ message: "订单不存在",
613
+ data: { printed: false, order: null }
614
+ };
615
+ }
616
+ sourceOrder = {
617
+ ...localOrder,
618
+ ...inputOrder,
619
+ order_id: localOrder.order_id ?? inputOrder.order_id ?? inputOrder.orderId,
620
+ external_sale_number: localOrder.external_sale_number ?? inputOrder.external_sale_number ?? inputOrder.externalSaleNumber
621
+ };
622
+ }
623
+ const checkoutData = await this.ensureCheckoutOrderNumbers(
624
+ {
625
+ ...sourceOrder,
626
+ small_ticket_data_flag: 1
627
+ },
628
+ "handleLocalPrintOrder"
629
+ );
630
+ const printableOrder = {
631
+ ...checkoutData,
632
+ need_sync: checkoutData.need_sync ?? 1
633
+ };
634
+ this.logInfo("handleLocalPrintOrder: 本地打印小票,构建触发任务前", {
635
+ checkoutData,
636
+ printableOrder
637
+ });
638
+ const printResult = await this.dispatchLocalReceiptPrint({
639
+ checkoutData,
640
+ order: printableOrder,
641
+ response: null,
642
+ requireFullyPaid: false
643
+ });
644
+ return {
645
+ code: 200,
646
+ status: true,
647
+ message: "",
648
+ data: {
649
+ printed: printResult.printed,
650
+ order: printResult.order
651
+ }
652
+ };
653
+ } catch (error) {
654
+ const message = error instanceof Error ? error.message : String(error);
655
+ this.logError("handleLocalPrintOrder: 本地打印小票失败", { error: message });
656
+ return {
657
+ code: 500,
658
+ status: false,
659
+ message,
660
+ data: { printed: false, order: null }
661
+ };
662
+ }
663
+ };
454
664
  this.handleOrderSalesDetail = async ({ url, data, path }) => {
455
665
  var _a;
456
666
  const requestPath = this.parseRequestPath(url, path);
457
- const orderId = this.extractOrderSalesDetailId(requestPath);
458
- this.logInfo("handleOrderSalesDetail: 开始处理", { url, path: requestPath, orderId });
459
- if (!orderId) {
460
- this.logWarning("handleOrderSalesDetail: order_id 缺失", { url, path: requestPath });
461
- return { code: 400, status: false, message: "order_id 缺失", data: null };
667
+ const lookup = this.extractOrderSalesDetailLookup(requestPath);
668
+ this.logInfo("handleOrderSalesDetail: 开始处理", { url, path: requestPath, lookup });
669
+ if (!lookup) {
670
+ this.logWarning("handleOrderSalesDetail: lookup 缺失", { url, path: requestPath });
671
+ return { code: 400, status: false, message: "订单 lookup 缺失", data: null };
462
672
  }
463
673
  if (!this.order) {
464
674
  this.logError("handleOrderSalesDetail: Order 模块未注册");
465
675
  return { code: 500, status: false, message: "Order 模块未注册", data: null };
466
676
  }
467
- const localOrder = await this.order.getLocalOrderByOrderId(orderId);
468
- if (localOrder) {
469
- this.logInfo("handleOrderSalesDetail: 命中本地订单", { orderId });
470
- return {
471
- code: 200,
472
- status: true,
473
- message: "",
474
- data: localOrder
475
- };
677
+ if (!this.shouldForceRemoteSalesDetail(data)) {
678
+ const localOrder = await this.order.getLocalOrderByLookup(lookup);
679
+ if (localOrder) {
680
+ this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
681
+ return {
682
+ code: 200,
683
+ status: true,
684
+ message: "",
685
+ data: localOrder
686
+ };
687
+ }
476
688
  }
477
689
  if (!((_a = this.app) == null ? void 0 : _a.request)) {
478
690
  this.logError("handleOrderSalesDetail: app.request 不可用");
479
- return { code: 500, status: false, message: "app.request 不可用", data: null };
691
+ return {
692
+ code: 500,
693
+ status: false,
694
+ message: "app.request 不可用",
695
+ data: null
696
+ };
480
697
  }
481
- const backendPath = this.buildOrderSalesDetailBackendPath(orderId, data);
698
+ const backendPath = this.buildOrderSalesDetailBackendPath(lookup, data);
482
699
  try {
483
700
  const response = await this.app.request.get(backendPath, {
484
701
  lookup_mode: "multi"
@@ -489,8 +706,8 @@ var Server = class {
489
706
  });
490
707
  const fresh = (response == null ? void 0 : response.data) ?? response;
491
708
  if (!fresh || typeof fresh !== "object" || fresh.order_id == null) {
492
- this.logError("handleOrderSalesDetail: 后端返回订单为空", {
493
- orderId,
709
+ this.logInfo("handleOrderSalesDetail: 后端返回订单为空", {
710
+ lookup,
494
711
  backendPath
495
712
  });
496
713
  return {
@@ -501,9 +718,9 @@ var Server = class {
501
718
  };
502
719
  }
503
720
  await this.order.upsertOrdersFromRemote([fresh]);
504
- const savedOrder = await this.order.getLocalOrderByOrderId(orderId);
721
+ const savedOrder = await this.order.getLocalOrderByLookup(lookup);
505
722
  if (!savedOrder) {
506
- this.logError("handleOrderSalesDetail: 订单写入后回读失败", { orderId });
723
+ this.logError("handleOrderSalesDetail: 订单写入后回读失败", { lookup });
507
724
  return {
508
725
  code: 500,
509
726
  status: false,
@@ -511,7 +728,7 @@ var Server = class {
511
728
  data: null
512
729
  };
513
730
  }
514
- this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { orderId });
731
+ this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
515
732
  return {
516
733
  code: 200,
517
734
  status: true,
@@ -521,7 +738,7 @@ var Server = class {
521
738
  } catch (error) {
522
739
  const errorMessage = error instanceof Error ? error.message : String(error);
523
740
  this.logError("handleOrderSalesDetail: 请求失败", {
524
- orderId,
741
+ lookup,
525
742
  backendPath,
526
743
  error: errorMessage
527
744
  });
@@ -890,6 +1107,7 @@ var Server = class {
890
1107
  moduleConfigs
891
1108
  });
892
1109
  this.registerServerRoutes();
1110
+ this.registerDeviceTaskActions();
893
1111
  const registeredModules = await this.registerModules(moduleConfigs);
894
1112
  if (autoPreload) {
895
1113
  await this.preloadModulesData(registeredModules, options);
@@ -905,10 +1123,11 @@ var Server = class {
905
1123
  this.core.effects.on(import_types.FloorPlanHooks.onFloorPlansChanged, () => {
906
1124
  void this.recomputeAndNotifyFloorPlanQuery();
907
1125
  });
908
- this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, () => {
1126
+ this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, (payload) => {
909
1127
  this.recomputeAndNotifyOrderQuery();
910
1128
  this.recomputeAndNotifyBookingQuery();
911
1129
  this.syncBookingRemoteCacheFromOrderChanges();
1130
+ this.notifySalesSearchSubscribers(payload);
912
1131
  });
913
1132
  const duration = Date.now() - startTime;
914
1133
  this.logInfo("Server 初始化完成", {
@@ -917,20 +1136,236 @@ var Server = class {
917
1136
  });
918
1137
  return registeredModules;
919
1138
  }
1139
+ registerDeviceTaskActions() {
1140
+ if (this.deviceTaskActionsRegistered)
1141
+ return;
1142
+ const deviceTask = this.getDeviceTaskPlugin();
1143
+ if (!(deviceTask == null ? void 0 : deviceTask.registerAction)) {
1144
+ this.logWarning("registerDeviceTaskActions: deviceTask 插件不可用");
1145
+ return;
1146
+ }
1147
+ const registeredActions = new Set(
1148
+ typeof deviceTask.getActions === "function" ? (deviceTask.getActions() || []).map((action) => action == null ? void 0 : action.action).filter(Boolean) : []
1149
+ );
1150
+ const register = (definition) => {
1151
+ var _a;
1152
+ if (registeredActions.has(definition.action))
1153
+ return;
1154
+ (_a = deviceTask.registerAction) == null ? void 0 : _a.call(deviceTask, definition);
1155
+ registeredActions.add(definition.action);
1156
+ };
1157
+ register({
1158
+ action: "sync_sales",
1159
+ name: "同步订单",
1160
+ validate: (payload) => (payload == null ? void 0 : payload.backendPath) && (payload == null ? void 0 : payload.data) ? null : "缺少 backendPath 或 data",
1161
+ handler: (ctx) => this.handleSyncSalesTask(ctx)
1162
+ });
1163
+ this.deviceTaskActionsRegistered = true;
1164
+ this.logInfo("DeviceTask actions 已注册", {
1165
+ actions: ["sync_sales"]
1166
+ });
1167
+ }
1168
+ async handleSyncSalesTask(ctx) {
1169
+ var _a, _b, _c;
1170
+ const payload = ((_a = ctx.task) == null ? void 0 : _a.payload) || {};
1171
+ const backendPath = payload.backendPath;
1172
+ const data = payload.data;
1173
+ const title = payload.title || "sync_sales";
1174
+ if (!backendPath || !data) {
1175
+ return this.taskFail("INVALID_PAYLOAD", "缺少 backendPath 或 data");
1176
+ }
1177
+ if (!((_b = this.app) == null ? void 0 : _b.request)) {
1178
+ this.logError(`${title}: sync_sales app.request 不可用`);
1179
+ return this.taskTimeout("app.request 不可用");
1180
+ }
1181
+ try {
1182
+ const syncResult = await this.runCheckoutSync({
1183
+ backendPath,
1184
+ data,
1185
+ title,
1186
+ externalSaleNumber: payload.external_sale_number,
1187
+ deviceId: (_c = ctx.task) == null ? void 0 : _c.device_id,
1188
+ persistCheckoutDataWithResponse: false
1189
+ });
1190
+ if (syncResult.rejected) {
1191
+ this.logError(`${title}: sync_sales 后端明确失败`, {
1192
+ backendPath,
1193
+ response: syncResult.errorResponse
1194
+ });
1195
+ return this.taskFail(
1196
+ "BACKEND_REJECTED",
1197
+ syncResult.message || "后端明确拒绝 checkout",
1198
+ syncResult.errorResponse
1199
+ );
1200
+ }
1201
+ return this.taskOk({
1202
+ order: syncResult.syncedOrder ?? null,
1203
+ response: syncResult.normalizedResponse
1204
+ });
1205
+ } catch (error) {
1206
+ const backendError = this.extractBackendErrorResponse(error);
1207
+ if (backendError) {
1208
+ const message = (backendError == null ? void 0 : backendError.message) || "后端明确拒绝 checkout";
1209
+ this.logError(`${title}: sync_sales 后端明确失败`, {
1210
+ backendPath,
1211
+ backendError
1212
+ });
1213
+ return this.taskFail("BACKEND_REJECTED", message, backendError);
1214
+ }
1215
+ const errorMessage = this.getUnknownErrorMessage(error);
1216
+ this.logError(`${title}: sync_sales 请求未明确成功`, {
1217
+ backendPath,
1218
+ error: errorMessage,
1219
+ error_detail: this.normalizeUnknownError(error)
1220
+ });
1221
+ return this.taskTimeout(errorMessage);
1222
+ }
1223
+ }
1224
+ async runCheckoutSync(params) {
1225
+ var _a, _b;
1226
+ const { backendPath, title } = params;
1227
+ const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
1228
+ const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
1229
+ const remoteCheckoutData = this.omitCheckoutSyncMode(checkoutData);
1230
+ if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
1231
+ throw new Error("app.request 不可用");
1232
+ }
1233
+ const response = await this.app.request.post(backendPath, remoteCheckoutData, {
1234
+ isShopApi: true,
1235
+ customToast: () => {
1236
+ }
1237
+ });
1238
+ if (this.isCheckoutResponseRejected(response)) {
1239
+ return {
1240
+ rejected: true,
1241
+ message: (response == null ? void 0 : response.message) || "后端明确拒绝 checkout",
1242
+ errorResponse: response,
1243
+ response,
1244
+ normalizedResponse: this.normalizeCheckoutResponse(response),
1245
+ checkoutData: remoteCheckoutData
1246
+ };
1247
+ }
1248
+ const fresh = this.extractOrderDataFromCheckoutResponse(response);
1249
+ const externalSaleNumber = this.getCheckoutExternalSaleNumber(
1250
+ remoteCheckoutData,
1251
+ {
1252
+ external_sale_number: params.externalSaleNumber,
1253
+ data: remoteCheckoutData
1254
+ }
1255
+ );
1256
+ const syncedOrder = await this.persistSyncedCheckoutOrder({
1257
+ backendPath,
1258
+ checkoutData: remoteCheckoutData,
1259
+ externalSaleNumber,
1260
+ fresh,
1261
+ title,
1262
+ persistCheckoutDataWithResponse: params.persistCheckoutDataWithResponse === true
1263
+ });
1264
+ const printableSyncedOrder = syncedOrder ? this.buildSyncedOrderForPrint({
1265
+ syncedOrder,
1266
+ checkoutResponseOrder: fresh
1267
+ }) : void 0;
1268
+ if (printableSyncedOrder && this.shouldPrintSyncedOrder({
1269
+ checkoutData: remoteCheckoutData,
1270
+ syncedOrder: printableSyncedOrder
1271
+ })) {
1272
+ await this.dispatchPrintOtherReceiptTask({
1273
+ checkoutData: remoteCheckoutData,
1274
+ syncedOrder: printableSyncedOrder,
1275
+ response,
1276
+ deviceId: params.deviceId
1277
+ });
1278
+ }
1279
+ return {
1280
+ rejected: false,
1281
+ response,
1282
+ normalizedResponse: this.normalizeCheckoutResponse(response),
1283
+ checkoutData: remoteCheckoutData,
1284
+ syncedOrder,
1285
+ fresh
1286
+ };
1287
+ }
1288
+ omitCheckoutSyncMode(data) {
1289
+ if (!data || typeof data !== "object")
1290
+ return data;
1291
+ const next = { ...data };
1292
+ delete next.sync_mode;
1293
+ delete next.syncMode;
1294
+ return next;
1295
+ }
1296
+ async persistSyncedCheckoutOrder(params) {
1297
+ const {
1298
+ backendPath,
1299
+ checkoutData,
1300
+ externalSaleNumber,
1301
+ fresh,
1302
+ title,
1303
+ persistCheckoutDataWithResponse
1304
+ } = params;
1305
+ const shouldMergeRemoteOrder = fresh ? this.isMergeableCheckoutOrder(fresh, externalSaleNumber) : false;
1306
+ let syncedOrder;
1307
+ if (this.order && fresh && (shouldMergeRemoteOrder || persistCheckoutDataWithResponse)) {
1308
+ syncedOrder = persistCheckoutDataWithResponse ? {
1309
+ ...checkoutData,
1310
+ ...fresh,
1311
+ external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1312
+ need_sync: 0
1313
+ } : {
1314
+ ...fresh,
1315
+ external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1316
+ need_sync: 0
1317
+ };
1318
+ await this.order.upsertOrdersFromRemote([syncedOrder]);
1319
+ this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
1320
+ order_id: fresh.order_id,
1321
+ external_sale_number: syncedOrder.external_sale_number,
1322
+ order_number: fresh.order_number,
1323
+ mergedRemoteOrder: shouldMergeRemoteOrder,
1324
+ persistedCheckoutDataWithResponse: persistCheckoutDataWithResponse
1325
+ });
1326
+ } else if (this.order && externalSaleNumber && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
1327
+ const patch = this.buildCheckoutSyncSuccessPatch(fresh);
1328
+ const result = await this.order.markOrderSyncedByExternalSaleNumber({
1329
+ externalSaleNumber,
1330
+ patch
1331
+ });
1332
+ syncedOrder = (result == null ? void 0 : result.order) || {
1333
+ ...checkoutData,
1334
+ ...patch,
1335
+ external_sale_number: externalSaleNumber,
1336
+ need_sync: 0
1337
+ };
1338
+ this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
1339
+ order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
1340
+ external_sale_number: externalSaleNumber,
1341
+ hasRemoteOrder: !!fresh,
1342
+ mergedRemoteOrder: false
1343
+ });
1344
+ } else {
1345
+ this.logWarning(`${title}: sync_sales Order 模块未注册`, {
1346
+ backendPath,
1347
+ external_sale_number: externalSaleNumber,
1348
+ order_id: fresh == null ? void 0 : fresh.order_id
1349
+ });
1350
+ }
1351
+ return syncedOrder;
1352
+ }
920
1353
  /**
921
1354
  * 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
922
1355
  */
923
1356
  async setupProductsQuotationPriceBridge() {
924
1357
  var _a;
925
1358
  if (!this.products) {
926
- this.logWarning("setupProductsQuotationPriceBridge: Products 模块未注册");
1359
+ this.logInfo("setupProductsQuotationPriceBridge: Products 模块未注册");
927
1360
  return;
928
1361
  }
929
1362
  if (!this.schedule) {
930
- this.logWarning("setupProductsQuotationPriceBridge: Schedule 模块未注册");
1363
+ this.logInfo("setupProductsQuotationPriceBridge: Schedule 模块未注册");
931
1364
  return;
932
1365
  }
933
1366
  try {
1367
+ await this.schedule.loadAllSchedule();
1368
+ this.products.clearPriceCache();
934
1369
  await this.products.setupQuotationPriceBridge({
935
1370
  scheduleModule: this.schedule,
936
1371
  channel: (_a = this.core.context) == null ? void 0 : _a.channel
@@ -1218,6 +1653,26 @@ var Server = class {
1218
1653
  path: "/shop/order/v2/list/unsubscribe",
1219
1654
  handler: this.handleUnsubscribeOrderQuery.bind(this)
1220
1655
  },
1656
+ {
1657
+ method: "post",
1658
+ path: "/shop/es/search/sales",
1659
+ handler: this.handleSalesSearchModule.bind(this)
1660
+ },
1661
+ {
1662
+ method: "post",
1663
+ path: "/shop/es/search/sales/unsubscribe",
1664
+ handler: this.handleUnsubscribeSalesSearch.bind(this)
1665
+ },
1666
+ {
1667
+ method: "post",
1668
+ path: "/shop/es/search",
1669
+ handler: this.handleSalesSearchAggregate.bind(this)
1670
+ },
1671
+ {
1672
+ method: "post",
1673
+ path: "/shop/es/search/unsubscribe",
1674
+ handler: this.handleUnsubscribeSalesSearch.bind(this)
1675
+ },
1221
1676
  {
1222
1677
  method: "get",
1223
1678
  path: "/shop/schedule/booking",
@@ -1237,6 +1692,36 @@ var Server = class {
1237
1692
  method: "get",
1238
1693
  path: "/update/localOrder",
1239
1694
  handler: this.handleUpdateLocalOrder.bind(this)
1695
+ },
1696
+ {
1697
+ method: "get",
1698
+ path: "/shop/pay/custom-payment/all",
1699
+ handler: this.handlePaymentMethods.bind(this)
1700
+ },
1701
+ {
1702
+ method: "get",
1703
+ path: "/shop/quotation/available",
1704
+ handler: this.handleQuotationAvailable.bind(this)
1705
+ },
1706
+ {
1707
+ method: "get",
1708
+ path: "/quotation/available",
1709
+ handler: this.handleQuotationAvailable.bind(this)
1710
+ },
1711
+ {
1712
+ method: "post",
1713
+ path: "/shop/order/sales/checkout",
1714
+ handler: this.handleOrderSalesCheckout.bind(this)
1715
+ },
1716
+ {
1717
+ method: "post",
1718
+ path: "/order/checkout",
1719
+ handler: this.handleOrderCheckout.bind(this)
1720
+ },
1721
+ {
1722
+ method: "post",
1723
+ path: "/shop/local/print-order",
1724
+ handler: this.handleLocalPrintOrder.bind(this)
1240
1725
  }
1241
1726
  ]);
1242
1727
  this.registerPrefixRoutes([
@@ -1252,6 +1737,50 @@ var Server = class {
1252
1737
  }
1253
1738
  ]);
1254
1739
  }
1740
+ async getPaymentRouteModule() {
1741
+ if (this.payment)
1742
+ return this.payment;
1743
+ if (this.paymentRouteModule)
1744
+ return this.paymentRouteModule;
1745
+ if (this.paymentRouteModuleInFlight)
1746
+ return this.paymentRouteModuleInFlight;
1747
+ this.paymentRouteModuleInFlight = (async () => {
1748
+ const module2 = new import_payment.PaymentServerModule("server_payment_route", "1.0.0");
1749
+ await module2.initialize(this.core, {
1750
+ store: { payMethods: [] }
1751
+ });
1752
+ this.paymentRouteModule = module2;
1753
+ return module2;
1754
+ })().finally(() => {
1755
+ this.paymentRouteModuleInFlight = void 0;
1756
+ });
1757
+ return this.paymentRouteModuleInFlight;
1758
+ }
1759
+ async fetchQuotationAvailableFromAPI(data) {
1760
+ var _a;
1761
+ const requester = ((_a = this.app) == null ? void 0 : _a.request) || this.core.getPlugin("request");
1762
+ if (!(requester == null ? void 0 : requester.get)) {
1763
+ this.logError("fetchQuotationAvailableFromAPI: request 不可用");
1764
+ return {
1765
+ code: 500,
1766
+ message: "request 不可用",
1767
+ data: { list: [] },
1768
+ status: false
1769
+ };
1770
+ }
1771
+ return requester.get("/shop/quotation/available", data);
1772
+ }
1773
+ isSuccessfulRemoteResponse(response) {
1774
+ if (!response)
1775
+ return false;
1776
+ if (response.status === false)
1777
+ return false;
1778
+ if (typeof response.status === "number" && response.status >= 400)
1779
+ return false;
1780
+ if (response.code !== void 0 && response.code !== 200 && response.code !== "200")
1781
+ return false;
1782
+ return true;
1783
+ }
1255
1784
  /**
1256
1785
  * 根据 subscriberId 移除商品查询订阅者
1257
1786
  */
@@ -1265,40 +1794,196 @@ var Server = class {
1265
1794
  }
1266
1795
  }
1267
1796
  /**
1268
- * 从查询值中提取 YYYY-MM-DD 日期串。
1797
+ * 执行 sales 搜索并登记可见订单号。
1798
+ * 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
1269
1799
  *
1270
1800
  * @example
1271
- * this.extractQueryDate('2026-04-15 09:58:00') // => '2026-04-15'
1801
+ * const result = await this.handleSalesSearchRequest('single', '/shop/es/search/sales', { keyword: '1001' }, {})
1272
1802
  */
1273
- extractQueryDate(raw) {
1274
- if (raw == null)
1275
- return null;
1276
- const date = (0, import_dayjs.default)(raw);
1277
- if (date.isValid()) {
1278
- return date.format("YYYY-MM-DD");
1803
+ async handleSalesSearchRequest(kind, backendPath, data, config) {
1804
+ const queryPayload = data && typeof data === "object" ? { ...data } : {};
1805
+ const result = await this.fetchSalesSearchFromAPI(backendPath, queryPayload);
1806
+ const { callback, subscriberId, resetVisibleOrderIds } = config || {};
1807
+ if (subscriberId && typeof callback === "function") {
1808
+ const contextSignature = this.buildSalesSearchSignature(kind, queryPayload);
1809
+ const existing = this.salesSearchSubscribers.get(subscriberId);
1810
+ const shouldReset = resetVisibleOrderIds === true || !existing || existing.kind !== kind || existing.contextSignature !== contextSignature;
1811
+ const visibleOrderIds = shouldReset ? /* @__PURE__ */ new Set() : new Set(existing.visibleOrderIds);
1812
+ for (const orderId of this.extractSalesSearchOrderIds(kind, result)) {
1813
+ visibleOrderIds.add(orderId);
1814
+ }
1815
+ this.salesSearchSubscribers.set(subscriberId, {
1816
+ callback,
1817
+ kind,
1818
+ contextSignature,
1819
+ visibleOrderIds,
1820
+ lastResponseData: this.extractSalesSearchResponseData(result)
1821
+ });
1822
+ this.logInfo("handleSalesSearchRequest: 已注册/更新订阅者", {
1823
+ subscriberId,
1824
+ kind,
1825
+ shouldReset,
1826
+ visibleCount: visibleOrderIds.size
1827
+ });
1279
1828
  }
1280
- const text = String(raw).trim();
1281
- if (!text)
1282
- return null;
1283
- return text.split("T")[0].split(" ")[0] || null;
1829
+ return result;
1284
1830
  }
1285
1831
  /**
1286
- * 判断时间范围是否「开始和结束都不是今天」。
1832
+ * 透传调用后端 sales 搜索接口。
1287
1833
  *
1288
1834
  * @example
1289
- * this.isRangeBothNotToday('2026-04-13', '2026-04-14') // => true
1835
+ * const res = await this.fetchSalesSearchFromAPI('/shop/es/search/sales', { keyword: '1001' })
1290
1836
  */
1291
- isRangeBothNotToday(startRaw, endRaw) {
1292
- const startDate = this.extractQueryDate(startRaw);
1293
- const endDate = this.extractQueryDate(endRaw);
1294
- if (!startDate || !endDate)
1295
- return false;
1296
- const today = (0, import_dayjs.default)().format("YYYY-MM-DD");
1297
- return startDate !== today && endDate !== today;
1837
+ async fetchSalesSearchFromAPI(backendPath, data) {
1838
+ var _a;
1839
+ if (!((_a = this.app) == null ? void 0 : _a.request)) {
1840
+ this.logError("fetchSalesSearchFromAPI: app.request 不可用", { backendPath });
1841
+ return {
1842
+ code: 500,
1843
+ message: "app.request 不可用",
1844
+ data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
1845
+ status: false
1846
+ };
1847
+ }
1848
+ try {
1849
+ const response = await this.app.request.post(backendPath, data, {
1850
+ isShopApi: true
1851
+ });
1852
+ const payload = (response == null ? void 0 : response.data) ?? response;
1853
+ return {
1854
+ code: (response == null ? void 0 : response.code) ?? 200,
1855
+ status: (response == null ? void 0 : response.status) ?? true,
1856
+ message: (response == null ? void 0 : response.message) ?? "",
1857
+ data: payload
1858
+ };
1859
+ } catch (error) {
1860
+ const errorMessage = error instanceof Error ? error.message : String(error);
1861
+ this.logError("fetchSalesSearchFromAPI: 请求失败", {
1862
+ backendPath,
1863
+ error: errorMessage
1864
+ });
1865
+ return {
1866
+ code: 500,
1867
+ message: errorMessage,
1868
+ data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
1869
+ status: false
1870
+ };
1871
+ }
1298
1872
  }
1299
1873
  /**
1300
- * 订单查询是否走本地:
1301
- * - 当 start_time 与 end_time 都不是今天时,走远端;
1874
+ * 构建搜索订阅签名;页码变化不重置,可继续累计 visibleOrderIds。
1875
+ *
1876
+ * @example
1877
+ * const signature = this.buildSalesSearchSignature('single', { keyword: 'A', page: 2 })
1878
+ */
1879
+ buildSalesSearchSignature(kind, payload) {
1880
+ return this.stableSerialize({
1881
+ kind,
1882
+ payload: this.stripSalesSearchPageParams(payload)
1883
+ });
1884
+ }
1885
+ /**
1886
+ * 移除页码参数,保留 page size、keyword、filters、sort 等查询语义参数。
1887
+ *
1888
+ * @example
1889
+ * this.stripSalesSearchPageParams({ page: 2, per_page: 20, keyword: 'A' })
1890
+ */
1891
+ stripSalesSearchPageParams(value) {
1892
+ if (Array.isArray(value)) {
1893
+ return value.map((item) => this.stripSalesSearchPageParams(item));
1894
+ }
1895
+ if (!value || typeof value !== "object")
1896
+ return value;
1897
+ const next = {};
1898
+ for (const [key, item] of Object.entries(value)) {
1899
+ if (key === "page" || key === "skip")
1900
+ continue;
1901
+ next[key] = this.stripSalesSearchPageParams(item);
1902
+ }
1903
+ return next;
1904
+ }
1905
+ /**
1906
+ * 提取响应 data,兼容 OS 包装结构与后端直接响应结构。
1907
+ *
1908
+ * @example
1909
+ * const data = this.extractSalesSearchResponseData(result)
1910
+ */
1911
+ extractSalesSearchResponseData(result) {
1912
+ return (result == null ? void 0 : result.data) ?? result;
1913
+ }
1914
+ /**
1915
+ * 从搜索响应中提取 sales 命中的订单号。
1916
+ *
1917
+ * @example
1918
+ * const ids = this.extractSalesSearchOrderIds('single', result)
1919
+ */
1920
+ extractSalesSearchOrderIds(kind, result) {
1921
+ var _a;
1922
+ const data = this.extractSalesSearchResponseData(result);
1923
+ const list = kind === "aggregate" ? (_a = this.findSalesSearchAggregateGroup(data)) == null ? void 0 : _a.list : data == null ? void 0 : data.list;
1924
+ if (!Array.isArray(list))
1925
+ return [];
1926
+ return list.map((item) => this.getSalesSearchOrderId(item)).filter((id) => !!id);
1927
+ }
1928
+ /**
1929
+ * 查找聚合搜索响应中的 sales 分组。
1930
+ *
1931
+ * @example
1932
+ * const group = this.findSalesSearchAggregateGroup({ results: [{ module: 'sales' }] })
1933
+ */
1934
+ findSalesSearchAggregateGroup(data) {
1935
+ const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
1936
+ return results.find((item) => (item == null ? void 0 : item.module) === "sales") || null;
1937
+ }
1938
+ /**
1939
+ * 从订单或搜索命中项中取订单号。
1940
+ *
1941
+ * @example
1942
+ * const id = this.getSalesSearchOrderId({ order_id: 1001 })
1943
+ */
1944
+ getSalesSearchOrderId(order) {
1945
+ if (!order || typeof order !== "object")
1946
+ return null;
1947
+ const raw = order.order_id ?? order.id;
1948
+ if (raw === void 0 || raw === null || raw === "")
1949
+ return null;
1950
+ return String(raw);
1951
+ }
1952
+ /**
1953
+ * 从查询值中提取 YYYY-MM-DD 日期串。
1954
+ *
1955
+ * @example
1956
+ * this.extractQueryDate('2026-04-15 09:58:00') // => '2026-04-15'
1957
+ */
1958
+ extractQueryDate(raw) {
1959
+ if (raw == null)
1960
+ return null;
1961
+ const date = (0, import_dayjs.default)(raw);
1962
+ if (date.isValid()) {
1963
+ return date.format("YYYY-MM-DD");
1964
+ }
1965
+ const text = String(raw).trim();
1966
+ if (!text)
1967
+ return null;
1968
+ return text.split("T")[0].split(" ")[0] || null;
1969
+ }
1970
+ /**
1971
+ * 判断时间范围是否「开始和结束都不是今天」。
1972
+ *
1973
+ * @example
1974
+ * this.isRangeBothNotToday('2026-04-13', '2026-04-14') // => true
1975
+ */
1976
+ isRangeBothNotToday(startRaw, endRaw) {
1977
+ const startDate = this.extractQueryDate(startRaw);
1978
+ const endDate = this.extractQueryDate(endRaw);
1979
+ if (!startDate || !endDate)
1980
+ return false;
1981
+ const today = (0, import_dayjs.default)().format("YYYY-MM-DD");
1982
+ return startDate !== today && endDate !== today;
1983
+ }
1984
+ /**
1985
+ * 订单查询是否走本地:
1986
+ * - 当 start_time 与 end_time 都不是今天时,走远端;
1302
1987
  * - 其余情况走本地。
1303
1988
  */
1304
1989
  shouldUseLocalOrderQuery(data) {
@@ -1704,6 +2389,734 @@ var Server = class {
1704
2389
  };
1705
2390
  }
1706
2391
  }
2392
+ getDeviceTaskPlugin() {
2393
+ var _a, _b;
2394
+ return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
2395
+ }
2396
+ getIdGeneratorPlugin() {
2397
+ var _a, _b;
2398
+ return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "idGenerator")) || null;
2399
+ }
2400
+ getAppData(key) {
2401
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
2402
+ const getData = (_b = (_a = this.core.getPlugin("app")) == null ? void 0 : _a.getData) == null ? void 0 : _b.call(_a);
2403
+ if (typeof getData === "function")
2404
+ return getData(key);
2405
+ const directValue = (_d = (_c = this.app) == null ? void 0 : _c.getData) == null ? void 0 : _d.call(_c, key);
2406
+ if (directValue !== void 0)
2407
+ return directValue;
2408
+ const coreData = ((_i = (_g = (_f = (_e = this.app) == null ? void 0 : _e.models) == null ? void 0 : _f.getStore) == null ? void 0 : (_h = _g.call(_f)).getDataByModel) == null ? void 0 : _i.call(_h, "core", "core")) || ((_o = (_m = (_l = (_k = (_j = this.app) == null ? void 0 : _j.data) == null ? void 0 : _k.store) == null ? void 0 : _l.getStore) == null ? void 0 : (_n = _m.call(_l)).getDataByModel) == null ? void 0 : _o.call(_n, "core", "core")) || ((_v = (_u = (_s = (_r = (_q = (_p = this.app) == null ? void 0 : _p.data) == null ? void 0 : _q.store) == null ? void 0 : _r.getStore) == null ? void 0 : (_t = _s.call(_r)).getDataByModel) == null ? void 0 : _u.call(_t, "core")) == null ? void 0 : _v.core);
2409
+ return coreData == null ? void 0 : coreData[key];
2410
+ }
2411
+ getSmallTicketShopInfo() {
2412
+ const shopInfo = this.getAppData("shop_info") || {};
2413
+ return {
2414
+ ...shopInfo,
2415
+ currency_symbol: shopInfo.currency_symbol || this.getAppData("shop_symbol") || this.getAppData("currency_symbol"),
2416
+ currency_code: shopInfo.currency_code || this.getAppData("shop_currency_code") || this.getAppData("currency_code"),
2417
+ tax_title: shopInfo.tax_title || this.getAppData("tax_title"),
2418
+ tax_country_code: shopInfo.tax_country_code || this.getAppData("tax_country_code"),
2419
+ is_price_include_tax: shopInfo.is_price_include_tax ?? this.getAppData("is_price_include_tax")
2420
+ };
2421
+ }
2422
+ taskOk(result) {
2423
+ return { status: "success", result };
2424
+ }
2425
+ taskFail(code, message, result) {
2426
+ return {
2427
+ status: "failed",
2428
+ error: { code, message },
2429
+ ...result !== void 0 ? { result } : {}
2430
+ };
2431
+ }
2432
+ taskTimeout(message) {
2433
+ return {
2434
+ status: "timeout",
2435
+ error: { code: "TIMEOUT", message }
2436
+ };
2437
+ }
2438
+ async getShortNumberOrDeviceId() {
2439
+ const getAsyncIotDeviceInfo = this.getAppData("async_iot_device_info");
2440
+ if (getAsyncIotDeviceInfo) {
2441
+ const res = await (getAsyncIotDeviceInfo == null ? void 0 : getAsyncIotDeviceInfo());
2442
+ if (res == null ? void 0 : res.short_number) {
2443
+ return res == null ? void 0 : res.short_number;
2444
+ }
2445
+ }
2446
+ return String(this.getAppData("device_id") || 0).slice(-2);
2447
+ }
2448
+ buildCheckoutTaskIdempotencyKey(data) {
2449
+ const identity = (data == null ? void 0 : data.request_unique_idempotency_token) || (data == null ? void 0 : data.external_sale_number) || (data == null ? void 0 : data.order_id) || (data == null ? void 0 : data.shop_order_number) || (data == null ? void 0 : data.shop_full_order_number);
2450
+ if (identity === void 0 || identity === null || identity === "")
2451
+ return void 0;
2452
+ return `sync_sales:${identity}`;
2453
+ }
2454
+ isBlankCheckoutValue(value) {
2455
+ return value === void 0 || value === null || value === "";
2456
+ }
2457
+ isLocalCheckoutOrderId(orderId) {
2458
+ return typeof orderId === "string" && orderId.startsWith("LOCAL_");
2459
+ }
2460
+ async normalizeCheckoutSubmitData(data, title) {
2461
+ if (!data || typeof data !== "object")
2462
+ return data;
2463
+ const next = { ...data };
2464
+ const externalSaleNumber = next.external_sale_number;
2465
+ const shouldClearLocalOrderId = this.isLocalCheckoutOrderId(next.order_id);
2466
+ if (shouldClearLocalOrderId)
2467
+ next.order_id = null;
2468
+ const hasCheckoutOrderNumbers = !this.isBlankCheckoutValue(next.shop_order_number) && !this.isBlankCheckoutValue(next.shop_full_order_number);
2469
+ if (hasCheckoutOrderNumbers) {
2470
+ this.logInfo(`${title}: checkout 已携带订单号,跳过查重`, {
2471
+ original_order_id: data.order_id,
2472
+ order_id: next.order_id,
2473
+ external_sale_number: externalSaleNumber,
2474
+ shop_order_number: next.shop_order_number,
2475
+ shop_full_order_number: next.shop_full_order_number
2476
+ });
2477
+ return next;
2478
+ }
2479
+ if (this.isBlankCheckoutValue(externalSaleNumber)) {
2480
+ if (shouldClearLocalOrderId) {
2481
+ this.logInfo(`${title}: checkout 本地订单号已清理`, {
2482
+ original_order_id: data.order_id,
2483
+ order_id: next.order_id
2484
+ });
2485
+ }
2486
+ return next;
2487
+ }
2488
+ if (!this.order || typeof this.order.getLocalOrderFromMemoryByLookup !== "function") {
2489
+ if (shouldClearLocalOrderId) {
2490
+ this.logInfo(`${title}: checkout 本地订单号已清理`, {
2491
+ original_order_id: data.order_id,
2492
+ external_sale_number: externalSaleNumber
2493
+ });
2494
+ }
2495
+ return next;
2496
+ }
2497
+ try {
2498
+ const localOrder = this.order.getLocalOrderFromMemoryByLookup(externalSaleNumber);
2499
+ if (!localOrder) {
2500
+ if (shouldClearLocalOrderId) {
2501
+ this.logInfo(`${title}: checkout 本地订单号已清理`, {
2502
+ original_order_id: data.order_id,
2503
+ external_sale_number: externalSaleNumber,
2504
+ localOrderFound: false
2505
+ });
2506
+ }
2507
+ return next;
2508
+ }
2509
+ if (this.isBlankCheckoutValue(next.shop_order_number)) {
2510
+ next.shop_order_number = localOrder.shop_order_number;
2511
+ }
2512
+ if (this.isBlankCheckoutValue(next.shop_full_order_number)) {
2513
+ next.shop_full_order_number = localOrder.shop_full_order_number;
2514
+ }
2515
+ this.logInfo(`${title}: checkout 已复用本地订单号`, {
2516
+ original_order_id: data.order_id,
2517
+ order_id: next.order_id,
2518
+ external_sale_number: externalSaleNumber,
2519
+ local_order_id: localOrder.order_id,
2520
+ shop_order_number: next.shop_order_number,
2521
+ shop_full_order_number: next.shop_full_order_number
2522
+ });
2523
+ delete next.vouchers;
2524
+ return next;
2525
+ } catch (error) {
2526
+ this.logWarning(`${title}: checkout 查找本地订单失败`, {
2527
+ external_sale_number: externalSaleNumber,
2528
+ error: this.getUnknownErrorMessage(error),
2529
+ error_detail: this.normalizeUnknownError(error)
2530
+ });
2531
+ return next;
2532
+ }
2533
+ }
2534
+ async ensureCheckoutOrderNumbers(data, title) {
2535
+ if (!data || typeof data !== "object")
2536
+ return data;
2537
+ const next = { ...data };
2538
+ const needsShopOrderNumber = next.shop_order_number === void 0 || next.shop_order_number === null || next.shop_order_number === "";
2539
+ const needsShopFullOrderNumber = next.shop_full_order_number === void 0 || next.shop_full_order_number === null || next.shop_full_order_number === "";
2540
+ if (!needsShopOrderNumber && !needsShopFullOrderNumber)
2541
+ return next;
2542
+ const idGenerator = this.getIdGeneratorPlugin();
2543
+ if (!idGenerator) {
2544
+ this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
2545
+ needsShopOrderNumber,
2546
+ needsShopFullOrderNumber
2547
+ });
2548
+ return next;
2549
+ }
2550
+ try {
2551
+ if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
2552
+ next.shop_order_number = await idGenerator.generateShopOrderNumber({
2553
+ biz: next.business_code || "ticket"
2554
+ });
2555
+ }
2556
+ if (needsShopFullOrderNumber && idGenerator.generateReceiptId) {
2557
+ next.shop_full_order_number = await idGenerator.generateReceiptId({
2558
+ biz: next.business_code || "ticket"
2559
+ });
2560
+ }
2561
+ this.logInfo(`${title}: checkout 订单号已准备`, {
2562
+ shop_order_number: next.shop_order_number,
2563
+ shop_full_order_number: next.shop_full_order_number
2564
+ });
2565
+ } catch (error) {
2566
+ this.logError(`${title}: 生成 checkout 订单号失败`, {
2567
+ error: error instanceof Error ? error.message : String(error)
2568
+ });
2569
+ }
2570
+ return next;
2571
+ }
2572
+ async dispatchCheckoutSyncTask(params) {
2573
+ var _a, _b, _c, _d;
2574
+ this.registerDeviceTaskActions();
2575
+ const deviceTask = this.getDeviceTaskPlugin();
2576
+ const debugDeviceId = await this.getShortNumberOrDeviceId();
2577
+ const debugIdempotencyKey = this.buildCheckoutTaskIdempotencyKey(params.data);
2578
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2579
+ this.logError(`${params.title}: deviceTask.dispatch 不可用`);
2580
+ return;
2581
+ }
2582
+ try {
2583
+ const result = await deviceTask.dispatch({
2584
+ action: "sync_sales",
2585
+ device_id: debugDeviceId,
2586
+ payload: {
2587
+ backendPath: params.backendPath,
2588
+ data: params.data,
2589
+ external_sale_number: (_a = params.data) == null ? void 0 : _a.external_sale_number,
2590
+ title: params.title
2591
+ },
2592
+ retry_limit: 5,
2593
+ idempotency_key: debugIdempotencyKey,
2594
+ name: "同步订单",
2595
+ source: "server",
2596
+ source_type: "order",
2597
+ source_id: ((_b = params.data) == null ? void 0 : _b.order_id) || ((_c = params.data) == null ? void 0 : _c.external_sale_number) || ((_d = params.data) == null ? void 0 : _d.shop_order_number)
2598
+ });
2599
+ this.logInfo(`${params.title}: sync_sales 任务已派发`, {
2600
+ uuid: result == null ? void 0 : result.uuid,
2601
+ status: result == null ? void 0 : result.status,
2602
+ reused: result == null ? void 0 : result.reused
2603
+ });
2604
+ } catch (error) {
2605
+ this.logError(`${params.title}: 派发 sync_sales 任务失败`, {
2606
+ error: error instanceof Error ? error.message : String(error)
2607
+ });
2608
+ }
2609
+ }
2610
+ async dispatchPrintOtherReceiptTask(params) {
2611
+ var _a, _b, _c, _d, _e;
2612
+ const deviceTask = this.getDeviceTaskPlugin();
2613
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2614
+ this.logWarning("dispatchPrintOtherReceiptTask: deviceTask.dispatch 不可用");
2615
+ return;
2616
+ }
2617
+ try {
2618
+ let printIdentity = this.getPrintOrderIdentity(params.syncedOrder);
2619
+ const deviceId = await this.getShortNumberOrDeviceId();
2620
+ await deviceTask.dispatch({
2621
+ action: "print_all",
2622
+ device_id: params.deviceId ?? deviceId,
2623
+ payload: {
2624
+ type: params.receiptOnly ? "0" : "99",
2625
+ data: params.receiptOnly ? {
2626
+ order_id: printIdentity,
2627
+ small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data
2628
+ } : {
2629
+ order_id: printIdentity,
2630
+ machine_code_print_info: (_d = (_c = params.syncedOrder) == null ? void 0 : _c.payment_info) == null ? void 0 : _d.machine_code_print_info,
2631
+ machine_code_print_info_v2: (_e = params.syncedOrder) == null ? void 0 : _e.machine_code_print_info_v2,
2632
+ skip_receipt: true
2633
+ }
2634
+ },
2635
+ idempotency_key: this.buildPrintOtherReceiptIdempotencyKey(params.syncedOrder, {
2636
+ receiptOnly: params.receiptOnly
2637
+ }),
2638
+ name: "打印转发",
2639
+ source: "server",
2640
+ source_type: "order",
2641
+ source_id: printIdentity
2642
+ });
2643
+ } catch (error) {
2644
+ this.logError("dispatchPrintOtherReceiptTask: 派发失败", {
2645
+ error: error instanceof Error ? error.message : String(error)
2646
+ });
2647
+ }
2648
+ }
2649
+ buildPrintOtherReceiptIdempotencyKey(order, options) {
2650
+ const identity = (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number) || (order == null ? void 0 : order.order_id);
2651
+ if (identity === void 0 || identity === null || identity === "")
2652
+ return void 0;
2653
+ return `${(options == null ? void 0 : options.receiptOnly) ? "print_receipt" : "print_voucher"}:${identity}:${Date.now()}`;
2654
+ }
2655
+ getPrintOrderIdentity(order) {
2656
+ return (order == null ? void 0 : order.order_id) || (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number);
2657
+ }
2658
+ async dispatchLocalReceiptPrint(params) {
2659
+ var _a;
2660
+ if (params.requireFullyPaid && !this.isSalesOrderFullyPaid(params.order)) {
2661
+ return { printed: false, order: params.order };
2662
+ }
2663
+ const printableOrder = await this.withLocalSmallTicketData(params.order, {
2664
+ requireFullyPaid: params.requireFullyPaid
2665
+ });
2666
+ if (!(0, import_small_ticket.hasSmallTicketData)((_a = printableOrder.payment_info) == null ? void 0 : _a.small_ticket_data)) {
2667
+ return { printed: false, order: printableOrder };
2668
+ }
2669
+ this.logInfo("dispatchLocalReceiptPrint: 构建触发任务前", {
2670
+ checkoutData: params.checkoutData,
2671
+ printableOrder,
2672
+ response: params.response
2673
+ });
2674
+ await this.dispatchPrintOtherReceiptTask({
2675
+ checkoutData: params.checkoutData,
2676
+ syncedOrder: printableOrder,
2677
+ response: params.response,
2678
+ receiptOnly: true
2679
+ });
2680
+ return { printed: true, order: printableOrder };
2681
+ }
2682
+ shouldLookupLocalPrintOrder(input) {
2683
+ const flag = (input == null ? void 0 : input.lookup_order_from_db) ?? (input == null ? void 0 : input.lookupOrderFromDb);
2684
+ return flag === true || flag === 1 || flag === "1";
2685
+ }
2686
+ getLocalPrintOrderLookup(input) {
2687
+ const orderId = (input == null ? void 0 : input.order_id) ?? (input == null ? void 0 : input.orderId);
2688
+ if (orderId !== void 0 && orderId !== null && orderId !== "")
2689
+ return orderId;
2690
+ const externalSaleNumber = (input == null ? void 0 : input.external_sale_number) ?? (input == null ? void 0 : input.externalSaleNumber);
2691
+ if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
2692
+ return externalSaleNumber;
2693
+ }
2694
+ return void 0;
2695
+ }
2696
+ async handleOrderCheckoutSubmit(params) {
2697
+ const { backendPath, data, title } = params;
2698
+ this.logInfo(`${title}: 开始处理`, {
2699
+ backendPath,
2700
+ order_id: data == null ? void 0 : data.order_id,
2701
+ external_sale_number: data == null ? void 0 : data.external_sale_number,
2702
+ order_number: data == null ? void 0 : data.order_number
2703
+ });
2704
+ if ((data == null ? void 0 : data.sync_mode) || (data == null ? void 0 : data.syncMode)) {
2705
+ return this.handleSyncCheckoutSubmit({
2706
+ backendPath,
2707
+ data,
2708
+ title
2709
+ });
2710
+ }
2711
+ const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
2712
+ const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
2713
+ const pendingResult = await this.handlePendingSyncCheckoutOrder({
2714
+ backendPath,
2715
+ data: checkoutData,
2716
+ title,
2717
+ reason: "checkout 已转入设备任务同步"
2718
+ });
2719
+ if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
2720
+ const pendingOrder = pendingResult.data;
2721
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,只有 type 为 virtual 才走打印
2722
+ // 后期需要迁移到 picoding ,根据工作流配置
2723
+ checkoutData.type === "virtual") {
2724
+ await this.dispatchLocalReceiptPrint({
2725
+ checkoutData,
2726
+ order: pendingOrder,
2727
+ response: pendingResult,
2728
+ requireFullyPaid: true
2729
+ });
2730
+ }
2731
+ await this.dispatchCheckoutSyncTask({
2732
+ backendPath,
2733
+ data: checkoutData,
2734
+ title
2735
+ });
2736
+ }
2737
+ if (!pendingResult.data.order_id) {
2738
+ return {
2739
+ ...pendingResult,
2740
+ data: {
2741
+ ...pendingResult.data,
2742
+ order_id: pendingResult.data.external_sale_number
2743
+ }
2744
+ };
2745
+ }
2746
+ return pendingResult;
2747
+ }
2748
+ async handleSyncCheckoutSubmit(params) {
2749
+ var _a, _b;
2750
+ const { backendPath, data, title } = params;
2751
+ if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
2752
+ this.logError(`${title}: sync checkout app.request 不可用`);
2753
+ return {
2754
+ code: 500,
2755
+ status: false,
2756
+ message: "app.request 不可用",
2757
+ data: null
2758
+ };
2759
+ }
2760
+ try {
2761
+ const syncResult = await this.runCheckoutSync({
2762
+ backendPath,
2763
+ data,
2764
+ title,
2765
+ persistCheckoutDataWithResponse: true
2766
+ });
2767
+ if (syncResult.rejected) {
2768
+ const normalized = this.normalizeCheckoutResponse(syncResult.errorResponse);
2769
+ return {
2770
+ ...normalized,
2771
+ status: false,
2772
+ message: syncResult.message || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
2773
+ data: (normalized == null ? void 0 : normalized.data) ?? null
2774
+ };
2775
+ }
2776
+ return this.withSyncedOrderIdInCheckoutResponse(
2777
+ syncResult.normalizedResponse,
2778
+ syncResult.syncedOrder
2779
+ );
2780
+ } catch (error) {
2781
+ const backendError = this.extractBackendErrorResponse(error);
2782
+ if (backendError) {
2783
+ const normalized = this.normalizeCheckoutResponse(backendError);
2784
+ return {
2785
+ ...normalized,
2786
+ status: false,
2787
+ message: (backendError == null ? void 0 : backendError.message) || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
2788
+ data: (normalized == null ? void 0 : normalized.data) ?? null
2789
+ };
2790
+ }
2791
+ const message = this.getUnknownErrorMessage(error);
2792
+ this.logError(`${title}: sync checkout 请求未明确成功`, {
2793
+ backendPath,
2794
+ error: message,
2795
+ error_detail: this.normalizeUnknownError(error)
2796
+ });
2797
+ return {
2798
+ code: 500,
2799
+ status: false,
2800
+ message,
2801
+ data: null
2802
+ };
2803
+ }
2804
+ }
2805
+ async handlePendingSyncCheckoutOrder(params) {
2806
+ var _a, _b, _c, _d;
2807
+ const { backendPath, data, title, reason } = params;
2808
+ const pendingOrder = await this.buildPendingSyncCheckoutOrder(data);
2809
+ if (!pendingOrder) {
2810
+ this.logError(`${title}: checkout 失败且订单缺少本地存储标识`, {
2811
+ backendPath,
2812
+ reason
2813
+ });
2814
+ return {
2815
+ code: 500,
2816
+ status: false,
2817
+ message: "订单缺少本地存储标识,无法写入待同步队列",
2818
+ data: null
2819
+ };
2820
+ }
2821
+ if (!this.order || typeof this.order.upsertPendingSyncOrders !== "function") {
2822
+ this.logError(`${title}: Order 模块不支持本地待同步写入`, {
2823
+ backendPath,
2824
+ reason
2825
+ });
2826
+ return {
2827
+ code: 500,
2828
+ status: false,
2829
+ message: "Order 模块不支持本地待同步写入",
2830
+ data: null
2831
+ };
2832
+ }
2833
+ try {
2834
+ await this.order.upsertPendingSyncOrders([pendingOrder]);
2835
+ this.logInfo(`${title}: 订单已写入本地待同步`, {
2836
+ backendPath,
2837
+ reason,
2838
+ order_id: pendingOrder.order_id,
2839
+ external_sale_number: pendingOrder.external_sale_number,
2840
+ order_number: pendingOrder.order_number
2841
+ });
2842
+ const changeGivenAmount = (_a = pendingOrder == null ? void 0 : pendingOrder.payments) == null ? void 0 : _a.reduce((sum, payment) => {
2843
+ var _a2;
2844
+ return sum + this.toAmountNumber((_a2 = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a2.change_given_amount);
2845
+ }, 0);
2846
+ return {
2847
+ code: 200,
2848
+ status: true,
2849
+ message: "",
2850
+ data: {
2851
+ ...pendingOrder,
2852
+ amount_gap: (_b = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _b.amount_gap,
2853
+ expect_amount: (_c = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _c.expect_amount,
2854
+ total_amount: (_d = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _d.total_amount,
2855
+ payment_status: pendingOrder == null ? void 0 : pendingOrder.payment_status,
2856
+ payment_info: {
2857
+ ...(pendingOrder == null ? void 0 : pendingOrder.payment_info) || {},
2858
+ current_change_given_amount: changeGivenAmount
2859
+ }
2860
+ }
2861
+ };
2862
+ } catch (error) {
2863
+ const errorMessage = error instanceof Error ? error.message : String(error);
2864
+ this.logError(`${title}: 写入本地待同步订单失败`, {
2865
+ backendPath,
2866
+ reason,
2867
+ error: errorMessage
2868
+ });
2869
+ return { code: 500, status: false, message: errorMessage, data: null };
2870
+ }
2871
+ }
2872
+ async buildPendingSyncCheckoutOrder(data) {
2873
+ if (!data || typeof data !== "object")
2874
+ return null;
2875
+ const hasStorageKey = data.external_sale_number !== void 0 && data.external_sale_number !== null && data.external_sale_number !== "" ? true : data.order_id !== void 0 && data.order_id !== null && data.order_id !== "";
2876
+ if (!hasStorageKey)
2877
+ return null;
2878
+ const pendingOrder = {
2879
+ ...data,
2880
+ need_sync: 1
2881
+ };
2882
+ const productMap = await this.buildSmallTicketProductMap(pendingOrder);
2883
+ const orderWithProductTitles = this.withPendingSyncProductTitles(
2884
+ pendingOrder,
2885
+ productMap
2886
+ );
2887
+ return this.withLocalSmallTicketData(
2888
+ orderWithProductTitles,
2889
+ { requireFullyPaid: true, productMap }
2890
+ );
2891
+ }
2892
+ shouldBuildSmallTicketData(order) {
2893
+ var _a;
2894
+ if (!order || typeof order !== "object")
2895
+ return false;
2896
+ if ((0, import_small_ticket.hasSmallTicketData)((_a = order.payment_info) == null ? void 0 : _a.small_ticket_data))
2897
+ return false;
2898
+ return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
2899
+ }
2900
+ shouldPrintSyncedOrder(params) {
2901
+ if (this.hasPaymentStatus(params.syncedOrder)) {
2902
+ return this.isSalesOrderFullyPaid(params.syncedOrder);
2903
+ }
2904
+ return this.isSalesOrderFullyPaid(params.checkoutData);
2905
+ }
2906
+ hasPaymentStatus(order) {
2907
+ return (order == null ? void 0 : order.payment_status) !== void 0 && (order == null ? void 0 : order.payment_status) !== null && (order == null ? void 0 : order.payment_status) !== "";
2908
+ }
2909
+ isSalesOrderFullyPaid(order) {
2910
+ var _a, _b, _c;
2911
+ if (!order || typeof order !== "object")
2912
+ return false;
2913
+ const paymentStatus = String(order.payment_status || "").toLowerCase();
2914
+ if (paymentStatus === "paid" || paymentStatus === "finished")
2915
+ return true;
2916
+ if (paymentStatus === "partially_paid" || paymentStatus === "payment_processing" || paymentStatus === "pending" || paymentStatus === "unpaid") {
2917
+ return false;
2918
+ }
2919
+ const amountGap = ((_a = order.summary) == null ? void 0 : _a.amount_gap) ?? order.amount_gap;
2920
+ if (amountGap !== void 0 && amountGap !== null && amountGap !== "") {
2921
+ return this.toAmountNumber(amountGap) <= 0;
2922
+ }
2923
+ const paidAmount = this.sumPaidOrderPayments(order.payments);
2924
+ const targetAmount = this.toAmountNumber(
2925
+ ((_b = order.summary) == null ? void 0 : _b.expect_amount) ?? ((_c = order.summary) == null ? void 0 : _c.total_amount) ?? order.expect_amount ?? order.total_amount
2926
+ );
2927
+ if (targetAmount <= 0)
2928
+ return paidAmount > 0;
2929
+ return paidAmount >= targetAmount;
2930
+ }
2931
+ sumPaidOrderPayments(payments) {
2932
+ if (!Array.isArray(payments))
2933
+ return 0;
2934
+ return payments.reduce((sum, payment) => {
2935
+ const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
2936
+ if (status === "voided" || status === "failed" || status === "cancelled")
2937
+ return sum;
2938
+ return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
2939
+ }, 0);
2940
+ }
2941
+ toAmountNumber(value) {
2942
+ if (typeof value === "number")
2943
+ return Number.isFinite(value) ? value : 0;
2944
+ if (typeof value !== "string")
2945
+ return 0;
2946
+ const parsed = Number(value.replace(/[^\d.-]/g, ""));
2947
+ return Number.isFinite(parsed) ? parsed : 0;
2948
+ }
2949
+ async buildSmallTicketProductMap(order) {
2950
+ var _a;
2951
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
2952
+ const productIdSet = /* @__PURE__ */ new Set();
2953
+ products.forEach((product) => {
2954
+ const productId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
2955
+ if (productId !== void 0 && productId !== null && productId !== "") {
2956
+ productIdSet.add(productId);
2957
+ }
2958
+ if (Array.isArray(product == null ? void 0 : product.product_bundle)) {
2959
+ product.product_bundle.forEach((bundle) => {
2960
+ const bundleProductId = (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id);
2961
+ if (bundleProductId !== void 0 && bundleProductId !== null && bundleProductId !== "") {
2962
+ productIdSet.add(bundleProductId);
2963
+ }
2964
+ });
2965
+ }
2966
+ });
2967
+ const productIds = Array.from(productIdSet);
2968
+ if (!productIds.length || typeof ((_a = this.products) == null ? void 0 : _a.getProductById) !== "function")
2969
+ return {};
2970
+ const entries = await Promise.all(
2971
+ productIds.map(async (id) => {
2972
+ var _a2, _b;
2973
+ try {
2974
+ const product = await ((_b = (_a2 = this.products) == null ? void 0 : _a2.getProductById) == null ? void 0 : _b.call(_a2, Number(id)));
2975
+ return product ? [String(id), product] : null;
2976
+ } catch (error) {
2977
+ this.logWarning("buildSmallTicketProductMap: 查询本地商品失败", {
2978
+ product_id: id,
2979
+ error: error instanceof Error ? error.message : String(error)
2980
+ });
2981
+ return null;
2982
+ }
2983
+ })
2984
+ );
2985
+ return entries.reduce((map, entry) => {
2986
+ if (!entry)
2987
+ return map;
2988
+ const [id, product] = entry;
2989
+ map[id] = product;
2990
+ return map;
2991
+ }, {});
2992
+ }
2993
+ withPendingSyncProductTitles(order, productMap) {
2994
+ const products = Array.isArray(order.products) ? order.products : null;
2995
+ if (!(products == null ? void 0 : products.length))
2996
+ return order;
2997
+ return {
2998
+ ...order,
2999
+ products: products.map((product) => ({
3000
+ ...product,
3001
+ product_title: this.buildProductTitleSnapshot(product, productMap)
3002
+ }))
3003
+ };
3004
+ }
3005
+ buildProductTitleSnapshot(product, productMap) {
3006
+ var _a, _b;
3007
+ const productId = product.product_id ?? product.id;
3008
+ const fallbackProduct = productId !== void 0 && productId !== null ? productMap[productId] || productMap[String(productId)] : null;
3009
+ const ownTitle = product.product_title || product.title || product.name || ((_a = product.product) == null ? void 0 : _a.title);
3010
+ const fallbackTitle = (fallbackProduct == null ? void 0 : fallbackProduct.product_title) || (fallbackProduct == null ? void 0 : fallbackProduct.title) || (fallbackProduct == null ? void 0 : fallbackProduct.name) || (fallbackProduct == null ? void 0 : fallbackProduct.format_title) || ((_b = fallbackProduct == null ? void 0 : fallbackProduct.product) == null ? void 0 : _b.title);
3011
+ const currentLocale = this.getProductTitleSnapshotCurrentLocale();
3012
+ const autoTitle = this.resolveFirstProductTitleValue(ownTitle) || this.resolveFirstProductTitleValue(fallbackTitle);
3013
+ return PRODUCT_TITLE_SNAPSHOT_KEYS.reduce((snapshot, key) => {
3014
+ snapshot[key] = this.resolveProductTitleValue(ownTitle, key, currentLocale) || this.resolveProductTitleValue(fallbackTitle, key, currentLocale) || (key === "auto" || key === "original" ? autoTitle : null);
3015
+ return snapshot;
3016
+ }, {});
3017
+ }
3018
+ getProductTitleSnapshotCurrentLocale() {
3019
+ var _a, _b;
3020
+ const shopInfo = this.getSmallTicketShopInfo();
3021
+ const rawLocale = shopInfo.primary_locale || this.getAppData("locale") || this.getAppData("language") || ((_a = this.core.context) == null ? void 0 : _a.locale) || ((_b = this.core.context) == null ? void 0 : _b.language);
3022
+ return this.normalizeProductTitleSnapshotLocale(rawLocale);
3023
+ }
3024
+ normalizeProductTitleSnapshotLocale(value) {
3025
+ if (typeof value !== "string" || !value)
3026
+ return null;
3027
+ const normalized = value.replace("_", "-");
3028
+ const matchedKey = PRODUCT_TITLE_SNAPSHOT_KEYS.find((key) => key === normalized);
3029
+ return matchedKey ?? null;
3030
+ }
3031
+ resolveProductTitleValue(value, key, currentLocale) {
3032
+ if (value === void 0 || value === null || value === "")
3033
+ return null;
3034
+ if (typeof value !== "object") {
3035
+ const title = String(value);
3036
+ if (key === "auto" || key === "original")
3037
+ return title;
3038
+ if (key === currentLocale && this.canAssignStringProductTitleToLocale(title, currentLocale))
3039
+ return title;
3040
+ return null;
3041
+ }
3042
+ const normalizedKey = key.replace("-", "_");
3043
+ const dashedKey = key.replace("_", "-");
3044
+ const rawValue = value[key] ?? value[normalizedKey] ?? value[dashedKey] ?? (key === "auto" ? value.default : void 0);
3045
+ if (rawValue === void 0 || rawValue === null || rawValue === "")
3046
+ return null;
3047
+ if (typeof rawValue === "object")
3048
+ return this.resolveFirstProductTitleValue(rawValue);
3049
+ return String(rawValue);
3050
+ }
3051
+ canAssignStringProductTitleToLocale(title, locale) {
3052
+ if (!locale)
3053
+ return false;
3054
+ if (locale === "zh-CN" || locale === "zh-HK" || locale === "kitchen") {
3055
+ return this.hasCjkText(title);
3056
+ }
3057
+ if (locale === "ja")
3058
+ return /[\u3040-\u30ff]/.test(title) || this.hasCjkText(title);
3059
+ if (locale === "en" || locale === "pt")
3060
+ return !this.hasCjkText(title);
3061
+ return false;
3062
+ }
3063
+ hasCjkText(value) {
3064
+ return /[\u3400-\u9fff]/.test(value);
3065
+ }
3066
+ resolveFirstProductTitleValue(value) {
3067
+ if (value === void 0 || value === null || value === "")
3068
+ return null;
3069
+ if (typeof value !== "object")
3070
+ return String(value);
3071
+ const preferredKeys = [
3072
+ "auto",
3073
+ "en",
3074
+ "original",
3075
+ "zh-CN",
3076
+ "zh_CN",
3077
+ "zh-HK",
3078
+ "zh_HK",
3079
+ "kitchen",
3080
+ "ja",
3081
+ "pt",
3082
+ "default"
3083
+ ];
3084
+ for (const key of preferredKeys) {
3085
+ const rawValue = value[key];
3086
+ if (rawValue !== void 0 && rawValue !== null && rawValue !== "")
3087
+ return String(rawValue);
3088
+ }
3089
+ const firstValue = Object.values(value).find(
3090
+ (item) => item !== void 0 && item !== null && item !== ""
3091
+ );
3092
+ return firstValue === void 0 ? null : String(firstValue);
3093
+ }
3094
+ async withLocalSmallTicketData(order, options) {
3095
+ if (!this.shouldBuildSmallTicketData(order))
3096
+ return order;
3097
+ if ((options == null ? void 0 : options.requireFullyPaid) && !this.isSalesOrderFullyPaid(order))
3098
+ return order;
3099
+ try {
3100
+ const productMap = (options == null ? void 0 : options.productMap) ?? await this.buildSmallTicketProductMap(order);
3101
+ const smallTicketData = (0, import_small_ticket.buildSmallTicketData)({
3102
+ order,
3103
+ shopInfo: this.getSmallTicketShopInfo(),
3104
+ productMap
3105
+ });
3106
+ return {
3107
+ ...order,
3108
+ payment_info: {
3109
+ ...order.payment_info || {},
3110
+ small_ticket_data: smallTicketData
3111
+ }
3112
+ };
3113
+ } catch (error) {
3114
+ this.logError("withLocalSmallTicketData: 生成本地小票数据失败", {
3115
+ error: error instanceof Error ? error.message : String(error)
3116
+ });
3117
+ return order;
3118
+ }
3119
+ }
1707
3120
  /**
1708
3121
  * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
1709
3122
  * 自动 trim、去空、按字符串去重,输出归一化后的字符串数组。
@@ -1856,12 +3269,15 @@ var Server = class {
1856
3269
  return null;
1857
3270
  }
1858
3271
  }
1859
- extractOrderSalesDetailId(url) {
3272
+ extractOrderSalesDetailLookup(url) {
1860
3273
  const path = this.parseRequestPath(url);
1861
3274
  const match = path.match(/^\/shop\/order\/sales\/([^/?#]+)$/);
1862
3275
  return (match == null ? void 0 : match[1]) ? decodeURIComponent(match[1]) : null;
1863
3276
  }
1864
- buildOrderSalesDetailBackendPath(orderId, data) {
3277
+ shouldForceRemoteSalesDetail(data) {
3278
+ return (data == null ? void 0 : data.forceRemote) === true || (data == null ? void 0 : data.force_remote) === true;
3279
+ }
3280
+ buildOrderSalesDetailBackendPath(lookup, data) {
1865
3281
  const rawWith = data && typeof data === "object" ? data.with : void 0;
1866
3282
  const withFields = Array.isArray(rawWith) && rawWith.length > 0 ? rawWith : ["products", "scheduleEvents"];
1867
3283
  const searchParams = new URLSearchParams();
@@ -1872,7 +3288,198 @@ var Server = class {
1872
3288
  });
1873
3289
  searchParams.append("lookup_mode", "multi");
1874
3290
  const query = searchParams.toString();
1875
- return `/shop/order/sales/${encodeURIComponent(orderId)}${query ? `?${query}` : ""}`;
3291
+ return `/shop/order/sales/${encodeURIComponent(lookup)}${query ? `?${query}` : ""}`;
3292
+ }
3293
+ extractOrderDataFromCheckoutResponse(response) {
3294
+ var _a, _b;
3295
+ const candidates = [
3296
+ (_a = response == null ? void 0 : response.data) == null ? void 0 : _a.order,
3297
+ (_b = response == null ? void 0 : response.data) == null ? void 0 : _b.sales,
3298
+ response == null ? void 0 : response.data,
3299
+ response == null ? void 0 : response.order,
3300
+ response == null ? void 0 : response.sales,
3301
+ response
3302
+ ];
3303
+ for (const candidate of candidates) {
3304
+ if (!candidate || typeof candidate !== "object")
3305
+ continue;
3306
+ if (candidate.order_id !== void 0 && candidate.order_id !== null) {
3307
+ return candidate;
3308
+ }
3309
+ }
3310
+ return null;
3311
+ }
3312
+ getCheckoutExternalSaleNumber(data, payload) {
3313
+ var _a;
3314
+ const candidates = [
3315
+ payload == null ? void 0 : payload.external_sale_number,
3316
+ data == null ? void 0 : data.external_sale_number,
3317
+ (_a = payload == null ? void 0 : payload.data) == null ? void 0 : _a.external_sale_number
3318
+ ];
3319
+ const value = candidates.find((candidate) => candidate !== void 0 && candidate !== null && candidate !== "");
3320
+ return value === void 0 ? void 0 : String(value);
3321
+ }
3322
+ buildCheckoutSyncSuccessPatch(fresh) {
3323
+ if (!fresh)
3324
+ return {};
3325
+ const patch = {};
3326
+ if (fresh.order_id !== void 0 && fresh.order_id !== null)
3327
+ patch.order_id = fresh.order_id;
3328
+ if (fresh.order_number !== void 0 && fresh.order_number !== null) {
3329
+ patch.order_number = fresh.order_number;
3330
+ }
3331
+ return patch;
3332
+ }
3333
+ buildSyncedOrderForPrint(params) {
3334
+ const { syncedOrder, checkoutResponseOrder } = params;
3335
+ if (!checkoutResponseOrder || typeof checkoutResponseOrder !== "object")
3336
+ return syncedOrder;
3337
+ const printableOrder = { ...syncedOrder };
3338
+ const responseOrder = checkoutResponseOrder;
3339
+ if (responseOrder.order_id !== void 0 && responseOrder.order_id !== null) {
3340
+ printableOrder.order_id = responseOrder.order_id;
3341
+ }
3342
+ if (responseOrder.payment_status !== void 0 && responseOrder.payment_status !== null) {
3343
+ printableOrder.payment_status = responseOrder.payment_status;
3344
+ }
3345
+ if (responseOrder.expect_amount !== void 0 && responseOrder.expect_amount !== null) {
3346
+ printableOrder.expect_amount = responseOrder.expect_amount;
3347
+ }
3348
+ if (responseOrder.machine_code_print_info_v2 !== void 0) {
3349
+ printableOrder.machine_code_print_info_v2 = responseOrder.machine_code_print_info_v2;
3350
+ }
3351
+ if (responseOrder.payment_info && typeof responseOrder.payment_info === "object") {
3352
+ printableOrder.payment_info = {
3353
+ ...syncedOrder.payment_info || {},
3354
+ ...responseOrder.payment_info
3355
+ };
3356
+ }
3357
+ return printableOrder;
3358
+ }
3359
+ isMergeableCheckoutOrder(order, externalSaleNumber) {
3360
+ if (!order || typeof order !== "object")
3361
+ return false;
3362
+ const orderExternalSaleNumber = order.external_sale_number;
3363
+ if (externalSaleNumber && orderExternalSaleNumber !== void 0 && orderExternalSaleNumber !== null && String(orderExternalSaleNumber) !== externalSaleNumber) {
3364
+ return false;
3365
+ }
3366
+ if (externalSaleNumber && (orderExternalSaleNumber === void 0 || orderExternalSaleNumber === null || orderExternalSaleNumber === "")) {
3367
+ return false;
3368
+ }
3369
+ return Array.isArray(order.products) || Array.isArray(order.bookings) || Array.isArray(order.payments) || !!order.summary || order.order_number !== void 0 || order.payment_status !== void 0 || order.status !== void 0;
3370
+ }
3371
+ normalizeCheckoutResponse(response) {
3372
+ if (response && typeof response === "object" && (response.code !== void 0 || response.status !== void 0)) {
3373
+ return response;
3374
+ }
3375
+ return {
3376
+ code: 200,
3377
+ status: true,
3378
+ message: "",
3379
+ data: response
3380
+ };
3381
+ }
3382
+ withSyncedOrderIdInCheckoutResponse(response, syncedOrder) {
3383
+ const normalized = this.normalizeCheckoutResponse(response);
3384
+ const orderId = syncedOrder == null ? void 0 : syncedOrder.order_id;
3385
+ if (orderId === void 0 || orderId === null)
3386
+ return normalized;
3387
+ if (!(normalized == null ? void 0 : normalized.data) || typeof normalized.data !== "object")
3388
+ return normalized;
3389
+ return {
3390
+ ...normalized,
3391
+ data: {
3392
+ ...normalized.data,
3393
+ order_id: normalized.data.order_id ?? orderId
3394
+ }
3395
+ };
3396
+ }
3397
+ isCheckoutResponseRejected(response) {
3398
+ const normalized = this.normalizeCheckoutResponse(response);
3399
+ const isErrorCode = (normalized == null ? void 0 : normalized.code) !== void 0 && normalized.code !== 200 && normalized.code !== "200";
3400
+ const isErrorStatus = (normalized == null ? void 0 : normalized.status) === false || typeof (normalized == null ? void 0 : normalized.status) === "number" && normalized.status >= 400;
3401
+ const isErrorSuccess = (normalized == null ? void 0 : normalized.success) === false;
3402
+ return isErrorCode || isErrorStatus || isErrorSuccess;
3403
+ }
3404
+ getUnknownErrorMessage(error) {
3405
+ var _a, _b, _c, _d, _e, _f;
3406
+ if (error instanceof Error && error.message)
3407
+ return error.message;
3408
+ if (typeof error === "string")
3409
+ return error;
3410
+ const candidates = [
3411
+ error == null ? void 0 : error.message,
3412
+ (_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
3413
+ (_c = error == null ? void 0 : error.data) == null ? void 0 : _c.message,
3414
+ (_e = (_d = error == null ? void 0 : error.response) == null ? void 0 : _d.body) == null ? void 0 : _e.message,
3415
+ (_f = error == null ? void 0 : error.body) == null ? void 0 : _f.message
3416
+ ];
3417
+ const message = candidates.find((candidate) => typeof candidate === "string" && candidate !== "");
3418
+ if (message)
3419
+ return message;
3420
+ const normalized = this.normalizeUnknownError(error);
3421
+ if (typeof normalized === "string")
3422
+ return normalized;
3423
+ try {
3424
+ return JSON.stringify(normalized);
3425
+ } catch {
3426
+ return String(error);
3427
+ }
3428
+ }
3429
+ normalizeUnknownError(error) {
3430
+ var _a, _b;
3431
+ if (error instanceof Error) {
3432
+ const normalized = {
3433
+ name: error.name,
3434
+ message: error.message,
3435
+ stack: error.stack
3436
+ };
3437
+ const record = error;
3438
+ if (((_a = record.response) == null ? void 0 : _a.data) !== void 0)
3439
+ normalized.responseData = record.response.data;
3440
+ if (record.data !== void 0)
3441
+ normalized.data = record.data;
3442
+ if (((_b = record.response) == null ? void 0 : _b.body) !== void 0)
3443
+ normalized.responseBody = record.response.body;
3444
+ if (record.body !== void 0)
3445
+ normalized.body = record.body;
3446
+ return this.safeJsonClone(normalized);
3447
+ }
3448
+ if (!error || typeof error !== "object")
3449
+ return String(error);
3450
+ return this.safeJsonClone(error);
3451
+ }
3452
+ safeJsonClone(value) {
3453
+ const seen = /* @__PURE__ */ new WeakSet();
3454
+ try {
3455
+ return JSON.parse(JSON.stringify(value, (_key, current) => {
3456
+ if (!current || typeof current !== "object")
3457
+ return current;
3458
+ if (seen.has(current))
3459
+ return "[Circular]";
3460
+ seen.add(current);
3461
+ return current;
3462
+ }));
3463
+ } catch {
3464
+ return String(value);
3465
+ }
3466
+ }
3467
+ extractBackendErrorResponse(error) {
3468
+ var _a, _b;
3469
+ const candidates = [
3470
+ (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data,
3471
+ error == null ? void 0 : error.data,
3472
+ (_b = error == null ? void 0 : error.response) == null ? void 0 : _b.body,
3473
+ error == null ? void 0 : error.body
3474
+ ];
3475
+ return candidates.find(
3476
+ (candidate) => this.isExplicitBackendErrorResponse(candidate)
3477
+ ) || null;
3478
+ }
3479
+ isExplicitBackendErrorResponse(candidate) {
3480
+ if (!candidate || typeof candidate !== "object")
3481
+ return false;
3482
+ return candidate.code !== void 0 || candidate.status !== void 0 || typeof candidate.message === "string";
1876
3483
  }
1877
3484
  /**
1878
3485
  * 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
@@ -2040,6 +3647,38 @@ var Server = class {
2040
3647
  status: true
2041
3648
  };
2042
3649
  }
3650
+ /**
3651
+ * 规范商品扩展类型过滤参数。
3652
+ *
3653
+ * @example
3654
+ * const types = this.normalizeProductExtensionTypes(['product_add_time']);
3655
+ */
3656
+ normalizeProductExtensionTypes(extension_type) {
3657
+ if (!Array.isArray(extension_type))
3658
+ return [];
3659
+ return extension_type.map((item) => String(item || "").trim()).filter(Boolean);
3660
+ }
3661
+ /**
3662
+ * 请求包含 product_add_time 时,按传入 extension_type 数组配置过滤商品。
3663
+ *
3664
+ * @example
3665
+ * const list = this.filterProductsByExtensionTypes(products, ['product_add_time']);
3666
+ */
3667
+ filterProductsByExtensionTypes(products, extension_type) {
3668
+ const extensionTypes = this.normalizeProductExtensionTypes(extension_type);
3669
+ if (!extensionTypes.includes("product_add_time"))
3670
+ return products;
3671
+ return products.filter((product) => extensionTypes.includes(String((product == null ? void 0 : product.extension_type) || "")));
3672
+ }
3673
+ /**
3674
+ * 判断本次查询是否需要跳过餐牌过滤,直接按扩展类型拉商品。
3675
+ *
3676
+ * @example
3677
+ * const skipMenu = this.shouldQueryProductsByExtensionTypes(['product_add_time']);
3678
+ */
3679
+ shouldQueryProductsByExtensionTypes(extension_type) {
3680
+ return this.normalizeProductExtensionTypes(extension_type).includes("product_add_time");
3681
+ }
2043
3682
  /**
2044
3683
  * 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
2045
3684
  * 供 handleProductQuery 首次返回及 pubsub 变更推送复用
@@ -2049,12 +3688,15 @@ var Server = class {
2049
3688
  */
2050
3689
  async computeProductQueryResult(context, options) {
2051
3690
  const tTotal = performance.now();
2052
- const { menu_list_ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
3691
+ const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id } = context;
3692
+ const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
2053
3693
  this.logInfo("computeProductQueryResult 开始", {
2054
3694
  menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
3695
+ ids: queryIds,
2055
3696
  schedule_datetime,
2056
3697
  schedule_date,
2057
3698
  customer_id,
3699
+ extension_type,
2058
3700
  product_id,
2059
3701
  changedIds: options == null ? void 0 : options.changedIds
2060
3702
  });
@@ -2062,6 +3704,39 @@ var Server = class {
2062
3704
  this.logError("computeProductQueryResult: Products 模块未注册");
2063
3705
  return { message: "Products 模块未注册", data: { list: [], count: 0 } };
2064
3706
  }
3707
+ if (queryIds.length > 0) {
3708
+ const uniqueIds = Array.from(new Set(queryIds));
3709
+ const tPrice2 = performance.now();
3710
+ const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
3711
+ scheduleModule: this.getSchedule(),
3712
+ schedule_datetime,
3713
+ customer_id
3714
+ }, {
3715
+ changedIds: options == null ? void 0 : options.changedIds,
3716
+ productIds: uniqueIds
3717
+ });
3718
+ (0, import_product.perfMark)("computeQuery.getProductsWithPrice(ids)", performance.now() - tPrice2, {
3719
+ count: productsWithPrice.length,
3720
+ ids: uniqueIds
3721
+ });
3722
+ const filteredProducts2 = productsWithPrice.filter((p) => uniqueIds.includes(Number(p == null ? void 0 : p.id))).filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3723
+ const extensionFilteredProducts = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
3724
+ (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
3725
+ mode: "ids",
3726
+ ids: uniqueIds,
3727
+ count: extensionFilteredProducts.length
3728
+ });
3729
+ this.logInfo("computeProductQueryResult 完成(ids)", {
3730
+ ids: uniqueIds,
3731
+ count: extensionFilteredProducts.length
3732
+ });
3733
+ return {
3734
+ code: 200,
3735
+ data: { list: extensionFilteredProducts, count: extensionFilteredProducts.length },
3736
+ message: "",
3737
+ status: true
3738
+ };
3739
+ }
2065
3740
  if (product_id != null && Number.isFinite(Number(product_id))) {
2066
3741
  const pid = Number(product_id);
2067
3742
  const tPrice2 = performance.now();
@@ -2074,7 +3749,10 @@ var Server = class {
2074
3749
  count: allProductsWithPrice.length,
2075
3750
  productId: pid
2076
3751
  });
2077
- const published = allProductsWithPrice.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3752
+ const published = this.filterProductsByExtensionTypes(
3753
+ allProductsWithPrice.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published"),
3754
+ extension_type
3755
+ );
2078
3756
  const item = published.find((p) => Number(p.id) === pid) ?? null;
2079
3757
  (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
2080
3758
  mode: "single",
@@ -2092,6 +3770,57 @@ var Server = class {
2092
3770
  status: true
2093
3771
  };
2094
3772
  }
3773
+ if (this.shouldQueryProductsByExtensionTypes(extension_type)) {
3774
+ const tPrice2 = performance.now();
3775
+ let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, {
3776
+ scheduleModule: this.getSchedule(),
3777
+ schedule_datetime,
3778
+ customer_id
3779
+ }, {
3780
+ changedIds: options == null ? void 0 : options.changedIds
3781
+ });
3782
+ (0, import_product.perfMark)("computeQuery.getProductsWithPrice(extensionType)", performance.now() - tPrice2, {
3783
+ count: filteredProducts2.length,
3784
+ extension_type
3785
+ });
3786
+ const tStatus2 = performance.now();
3787
+ const beforeStatusCount2 = filteredProducts2.length;
3788
+ filteredProducts2 = filteredProducts2.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3789
+ (0, import_product.perfMark)("computeQuery.filterByStatus(extensionType)", performance.now() - tStatus2, {
3790
+ before: beforeStatusCount2,
3791
+ after: filteredProducts2.length
3792
+ });
3793
+ const tExtensionType2 = performance.now();
3794
+ const beforeExtensionTypeCount2 = filteredProducts2.length;
3795
+ filteredProducts2 = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
3796
+ (0, import_product.perfMark)("computeQuery.filterByExtensionType(extensionType)", performance.now() - tExtensionType2, {
3797
+ before: beforeExtensionTypeCount2,
3798
+ after: filteredProducts2.length,
3799
+ extension_type
3800
+ });
3801
+ const tSort2 = performance.now();
3802
+ filteredProducts2 = filteredProducts2.sort((a, b) => {
3803
+ const sortDiff = Number(b.sort) - Number(a.sort);
3804
+ if (sortDiff !== 0)
3805
+ return sortDiff;
3806
+ return (a.title || "").localeCompare(b.title || "");
3807
+ });
3808
+ (0, import_product.perfMark)("computeQuery.sort(extensionType)", performance.now() - tSort2, { count: filteredProducts2.length });
3809
+ (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
3810
+ mode: "extensionType",
3811
+ filteredCount: filteredProducts2.length
3812
+ });
3813
+ this.logInfo("computeProductQueryResult 完成(extension_type)", {
3814
+ filteredCount: filteredProducts2.length,
3815
+ extension_type
3816
+ });
3817
+ return {
3818
+ code: 200,
3819
+ data: { list: filteredProducts2, count: filteredProducts2.length },
3820
+ message: "",
3821
+ status: true
3822
+ };
3823
+ }
2095
3824
  if (!this.menu) {
2096
3825
  this.logError("computeProductQueryResult: Menu 模块未注册");
2097
3826
  return { message: "Menu 模块未注册", data: { list: [], count: 0 } };
@@ -2141,6 +3870,14 @@ var Server = class {
2141
3870
  before: beforeStatusCount,
2142
3871
  after: filteredProducts.length
2143
3872
  });
3873
+ const tExtensionType = performance.now();
3874
+ const beforeExtensionTypeCount = filteredProducts.length;
3875
+ filteredProducts = this.filterProductsByExtensionTypes(filteredProducts, extension_type);
3876
+ (0, import_product.perfMark)("computeQuery.filterByExtensionType", performance.now() - tExtensionType, {
3877
+ before: beforeExtensionTypeCount,
3878
+ after: filteredProducts.length,
3879
+ extension_type
3880
+ });
2144
3881
  const tSort = performance.now();
2145
3882
  filteredProducts = filteredProducts.sort((a, b) => {
2146
3883
  const sortDiff = Number(b.sort) - Number(a.sort);
@@ -2234,6 +3971,101 @@ var Server = class {
2234
3971
  totalNotifyDurationMs: notifyEndAt - notifyStartAt
2235
3972
  });
2236
3973
  }
3974
+ /**
3975
+ * 订单变更后通知 sales 搜索订阅者。
3976
+ * 仅回传当前查询已返回订单号集合中的变更订单。
3977
+ *
3978
+ * @example
3979
+ * this.notifySalesSearchSubscribers({ list: [], changedOrders: [order], source: 'pubsub.bodyUpsert' })
3980
+ */
3981
+ notifySalesSearchSubscribers(payload) {
3982
+ if (this.salesSearchSubscribers.size === 0)
3983
+ return;
3984
+ const changedOrders = this.extractChangedOrdersFromPayload(payload);
3985
+ if (changedOrders.length === 0) {
3986
+ return;
3987
+ }
3988
+ for (const [subscriberId, subscriber] of this.salesSearchSubscribers.entries()) {
3989
+ try {
3990
+ const changedVisibleOrders = changedOrders.filter((order) => {
3991
+ const orderId = this.getSalesSearchOrderId(order);
3992
+ return !!orderId && subscriber.visibleOrderIds.has(orderId);
3993
+ });
3994
+ if (changedVisibleOrders.length === 0) {
3995
+ continue;
3996
+ }
3997
+ subscriber.callback(
3998
+ this.buildSalesSearchDeltaResponse(subscriber, changedVisibleOrders)
3999
+ );
4000
+ this.logInfo("notifySalesSearchSubscribers: 已推送 delta", {
4001
+ subscriberId,
4002
+ kind: subscriber.kind,
4003
+ count: changedVisibleOrders.length
4004
+ });
4005
+ } catch (error) {
4006
+ const errorMessage = error instanceof Error ? error.message : String(error);
4007
+ this.logError("notifySalesSearchSubscribers: 推送失败", {
4008
+ subscriberId,
4009
+ error: errorMessage
4010
+ });
4011
+ }
4012
+ }
4013
+ }
4014
+ /**
4015
+ * 从订单变更事件中提取明确 delta。
4016
+ *
4017
+ * @example
4018
+ * const list = this.extractChangedOrdersFromPayload(payload)
4019
+ */
4020
+ extractChangedOrdersFromPayload(payload) {
4021
+ if (!payload || Array.isArray(payload))
4022
+ return [];
4023
+ return Array.isArray(payload.changedOrders) ? payload.changedOrders : [];
4024
+ }
4025
+ /**
4026
+ * 构建与当前搜索接口一致的 delta 响应。
4027
+ *
4028
+ * @example
4029
+ * const response = this.buildSalesSearchDeltaResponse(subscriber, [order])
4030
+ */
4031
+ buildSalesSearchDeltaResponse(subscriber, changedOrders) {
4032
+ if (subscriber.kind === "aggregate") {
4033
+ return this.buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders);
4034
+ }
4035
+ const data = subscriber.lastResponseData || {};
4036
+ return {
4037
+ code: 200,
4038
+ status: true,
4039
+ message: "",
4040
+ data: {
4041
+ ...data,
4042
+ list: changedOrders
4043
+ }
4044
+ };
4045
+ }
4046
+ /**
4047
+ * 构建聚合搜索接口的 sales 分组 delta 响应。
4048
+ *
4049
+ * @example
4050
+ * const response = this.buildAggregateSalesSearchDeltaResponse(subscriber, [order])
4051
+ */
4052
+ buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders) {
4053
+ const data = subscriber.lastResponseData || {};
4054
+ const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
4055
+ const hasSalesGroup = results.some((item) => (item == null ? void 0 : item.module) === "sales");
4056
+ const nextResults = hasSalesGroup ? results.map(
4057
+ (item) => (item == null ? void 0 : item.module) === "sales" ? { ...item, list: changedOrders } : item
4058
+ ) : [{ module: "sales", list: changedOrders, count: changedOrders.length }];
4059
+ return {
4060
+ code: 200,
4061
+ status: true,
4062
+ message: "",
4063
+ data: {
4064
+ ...data,
4065
+ results: nextResults
4066
+ }
4067
+ };
4068
+ }
2237
4069
  /**
2238
4070
  * 预约数据变更后,遍历订阅者重新计算并通过 callback 推送
2239
4071
  */