@pisell/pisellos 2.2.148 → 2.2.150

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 (247) hide show
  1. package/dist/apis/picoding.d.ts +0 -0
  2. package/dist/apis/picoding.js +1 -0
  3. package/dist/model/strategy/adapter/index.d.ts +2 -0
  4. package/dist/model/strategy/adapter/index.js +3 -1
  5. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +67 -0
  6. package/dist/model/strategy/adapter/itemRule/adapter.js +483 -0
  7. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +43 -0
  8. package/dist/model/strategy/adapter/itemRule/evaluator.js +169 -0
  9. package/dist/model/strategy/adapter/itemRule/examples.d.ts +79 -0
  10. package/dist/model/strategy/adapter/itemRule/examples.js +382 -0
  11. package/dist/model/strategy/adapter/itemRule/index.d.ts +5 -0
  12. package/dist/model/strategy/adapter/itemRule/index.js +5 -0
  13. package/dist/model/strategy/adapter/itemRule/type.d.ts +225 -0
  14. package/dist/model/strategy/adapter/itemRule/type.js +101 -0
  15. package/dist/modules/Cart/types.d.ts +2 -0
  16. package/dist/modules/Cart/utils/cartProduct.js +22 -1
  17. package/dist/modules/Cart/utils/changePrice.js +6 -0
  18. package/dist/modules/Date/index.d.ts +1 -1
  19. package/dist/modules/Date/index.js +16 -8
  20. package/dist/modules/Date/types.d.ts +3 -1
  21. package/dist/modules/OpenData/index.d.ts +24 -0
  22. package/dist/modules/OpenData/index.js +173 -0
  23. package/dist/modules/OpenData/types.d.ts +73 -0
  24. package/dist/modules/OpenData/types.js +1 -0
  25. package/dist/modules/OpenData/utils.d.ts +2 -0
  26. package/dist/modules/OpenData/utils.js +75 -0
  27. package/dist/modules/Order/index.d.ts +171 -1
  28. package/dist/modules/Order/index.js +2052 -112
  29. package/dist/modules/Order/types.d.ts +441 -20
  30. package/dist/modules/Order/types.js +23 -0
  31. package/dist/modules/Order/utils.d.ts +120 -0
  32. package/dist/modules/Order/utils.js +653 -2
  33. package/dist/modules/Product/utils.js +2 -2
  34. package/dist/modules/ProductList/index.js +2 -1
  35. package/dist/modules/Quotation/index.d.ts +8 -1
  36. package/dist/modules/Quotation/index.js +40 -10
  37. package/dist/modules/Quotation/types.d.ts +5 -0
  38. package/dist/modules/Rules/index.d.ts +3 -1
  39. package/dist/modules/Rules/index.js +136 -50
  40. package/dist/modules/Rules/types.d.ts +6 -0
  41. package/dist/modules/Rules/types.js +8 -0
  42. package/dist/modules/SalesSummary/index.d.ts +70 -0
  43. package/dist/modules/SalesSummary/index.js +175 -0
  44. package/dist/modules/SalesSummary/types.d.ts +64 -0
  45. package/dist/modules/SalesSummary/types.js +1 -0
  46. package/dist/modules/SalesSummary/utils.d.ts +34 -0
  47. package/dist/modules/SalesSummary/utils.js +488 -0
  48. package/dist/modules/ScanOrderLogger/index.d.ts +21 -0
  49. package/dist/modules/ScanOrderLogger/index.js +161 -0
  50. package/dist/modules/ScanOrderLogger/providers/feishu.d.ts +2 -0
  51. package/dist/modules/ScanOrderLogger/providers/feishu.js +203 -0
  52. package/dist/modules/ScanOrderLogger/providers/grafana.d.ts +2 -0
  53. package/dist/modules/ScanOrderLogger/providers/grafana.js +50 -0
  54. package/dist/modules/ScanOrderLogger/types.d.ts +52 -0
  55. package/dist/modules/ScanOrderLogger/types.js +1 -0
  56. package/dist/modules/Schedule/getDateIsInSchedule.js +7 -7
  57. package/dist/modules/Schedule/index.d.ts +4 -13
  58. package/dist/modules/Schedule/index.js +6 -23
  59. package/dist/modules/Schedule/utils.d.ts +1 -1
  60. package/dist/modules/Summary/index.d.ts +3 -0
  61. package/dist/modules/Summary/index.js +134 -15
  62. package/dist/modules/Summary/types.d.ts +7 -0
  63. package/dist/modules/Summary/utils.d.ts +104 -1
  64. package/dist/modules/Summary/utils.js +1116 -13
  65. package/dist/modules/index.d.ts +4 -0
  66. package/dist/modules/index.js +5 -1
  67. package/dist/server/index.d.ts +41 -4
  68. package/dist/server/index.js +900 -405
  69. package/dist/server/modules/order/index.d.ts +10 -2
  70. package/dist/server/modules/order/index.js +246 -193
  71. package/dist/server/modules/products/index.d.ts +26 -0
  72. package/dist/server/modules/products/index.js +618 -338
  73. package/dist/server/modules/products/types.d.ts +5 -1
  74. package/dist/solution/BaseSales/index.d.ts +175 -0
  75. package/dist/solution/BaseSales/index.js +1293 -0
  76. package/dist/solution/BaseSales/types.d.ts +305 -0
  77. package/dist/solution/BaseSales/types.js +38 -0
  78. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +143 -0
  79. package/dist/solution/BaseSales/utils/parseSalesResponse.js +159 -0
  80. package/dist/solution/BaseSales/utils.d.ts +40 -0
  81. package/dist/solution/BaseSales/utils.js +222 -0
  82. package/dist/solution/BookingByStep/index.d.ts +14 -0
  83. package/dist/solution/BookingByStep/index.js +699 -212
  84. package/dist/solution/BookingByStep/types.d.ts +3 -1
  85. package/dist/solution/BookingByStep/types.js +5 -1
  86. package/dist/solution/BookingByStep/utils/capacity.js +1 -1
  87. package/dist/solution/BookingByStep/utils/resources.js +6 -1
  88. package/dist/solution/BookingTicket/index.d.ts +113 -15
  89. package/dist/solution/BookingTicket/index.js +534 -196
  90. package/dist/solution/BookingTicket/types.d.ts +69 -6
  91. package/dist/solution/BookingTicket/types.js +40 -9
  92. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +37 -0
  93. package/dist/solution/BookingTicket/utils/bookingStatus.js +66 -0
  94. package/dist/solution/BookingTicket/utils/cartView.d.ts +26 -0
  95. package/dist/solution/BookingTicket/utils/cartView.js +84 -0
  96. package/dist/solution/Sales/index.d.ts +1 -0
  97. package/dist/solution/Sales/index.js +1 -0
  98. package/dist/solution/ScanOrder/index.d.ts +146 -0
  99. package/dist/solution/ScanOrder/index.js +3029 -0
  100. package/dist/solution/ScanOrder/types.d.ts +305 -0
  101. package/dist/solution/ScanOrder/types.js +35 -0
  102. package/dist/solution/ScanOrder/utils.d.ts +167 -0
  103. package/dist/solution/ScanOrder/utils.js +768 -0
  104. package/dist/solution/ShopDiscount/index.d.ts +2 -0
  105. package/dist/solution/ShopDiscount/index.js +9 -5
  106. package/dist/solution/ShopDiscount/types.d.ts +4 -0
  107. package/dist/solution/VenueBooking/index.d.ts +197 -0
  108. package/dist/solution/VenueBooking/index.js +3411 -0
  109. package/dist/solution/VenueBooking/sales-section-4-annotated.json +343 -0
  110. package/dist/solution/VenueBooking/types.d.ts +153 -0
  111. package/dist/solution/VenueBooking/types.js +21 -0
  112. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +11 -0
  113. package/dist/solution/VenueBooking/utils/dateSummary.js +104 -0
  114. package/dist/solution/VenueBooking/utils/resource.d.ts +14 -0
  115. package/dist/solution/VenueBooking/utils/resource.js +130 -0
  116. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +34 -0
  117. package/dist/solution/VenueBooking/utils/slotMerge.js +224 -0
  118. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +32 -0
  119. package/dist/solution/VenueBooking/utils/timeSlot.js +453 -0
  120. package/dist/solution/VenueBooking/utils.d.ts +1 -0
  121. package/dist/solution/VenueBooking/utils.js +1 -0
  122. package/dist/solution/index.d.ts +3 -0
  123. package/dist/solution/index.js +4 -1
  124. package/lib/apis/picoding.d.ts +0 -0
  125. package/lib/apis/picoding.js +0 -0
  126. package/lib/model/strategy/adapter/index.d.ts +2 -0
  127. package/lib/model/strategy/adapter/index.js +6 -0
  128. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +67 -0
  129. package/lib/model/strategy/adapter/itemRule/adapter.js +377 -0
  130. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +43 -0
  131. package/lib/model/strategy/adapter/itemRule/evaluator.js +124 -0
  132. package/lib/model/strategy/adapter/itemRule/examples.d.ts +79 -0
  133. package/lib/model/strategy/adapter/itemRule/examples.js +316 -0
  134. package/lib/model/strategy/adapter/itemRule/index.d.ts +5 -0
  135. package/lib/model/strategy/adapter/itemRule/index.js +60 -0
  136. package/lib/model/strategy/adapter/itemRule/type.d.ts +225 -0
  137. package/lib/model/strategy/adapter/itemRule/type.js +46 -0
  138. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  139. package/lib/modules/Cart/types.d.ts +2 -0
  140. package/lib/modules/Cart/utils/cartProduct.js +17 -1
  141. package/lib/modules/Cart/utils/changePrice.js +5 -0
  142. package/lib/modules/Date/index.d.ts +1 -1
  143. package/lib/modules/Date/index.js +7 -1
  144. package/lib/modules/Date/types.d.ts +3 -1
  145. package/lib/modules/OpenData/index.d.ts +24 -0
  146. package/lib/modules/OpenData/index.js +119 -0
  147. package/lib/modules/OpenData/types.d.ts +73 -0
  148. package/lib/modules/OpenData/types.js +17 -0
  149. package/lib/modules/OpenData/utils.d.ts +2 -0
  150. package/lib/modules/OpenData/utils.js +111 -0
  151. package/lib/modules/Order/index.d.ts +171 -1
  152. package/lib/modules/Order/index.js +1396 -5
  153. package/lib/modules/Order/types.d.ts +441 -20
  154. package/lib/modules/Order/types.js +1 -0
  155. package/lib/modules/Order/utils.d.ts +120 -0
  156. package/lib/modules/Order/utils.js +562 -2
  157. package/lib/modules/Product/utils.js +2 -2
  158. package/lib/modules/ProductList/index.js +2 -1
  159. package/lib/modules/Quotation/index.d.ts +8 -1
  160. package/lib/modules/Quotation/index.js +33 -4
  161. package/lib/modules/Quotation/types.d.ts +5 -0
  162. package/lib/modules/Rules/index.d.ts +3 -1
  163. package/lib/modules/Rules/index.js +46 -6
  164. package/lib/modules/Rules/types.d.ts +6 -0
  165. package/lib/modules/Rules/types.js +11 -2
  166. package/lib/modules/SalesSummary/index.d.ts +70 -0
  167. package/lib/modules/SalesSummary/index.js +106 -0
  168. package/lib/modules/SalesSummary/types.d.ts +64 -0
  169. package/lib/modules/SalesSummary/types.js +17 -0
  170. package/lib/modules/SalesSummary/utils.d.ts +34 -0
  171. package/lib/modules/SalesSummary/utils.js +430 -0
  172. package/lib/modules/ScanOrderLogger/index.d.ts +21 -0
  173. package/lib/modules/ScanOrderLogger/index.js +135 -0
  174. package/lib/modules/ScanOrderLogger/providers/feishu.d.ts +2 -0
  175. package/lib/modules/ScanOrderLogger/providers/feishu.js +148 -0
  176. package/lib/modules/ScanOrderLogger/providers/grafana.d.ts +2 -0
  177. package/lib/modules/ScanOrderLogger/providers/grafana.js +52 -0
  178. package/lib/modules/ScanOrderLogger/types.d.ts +52 -0
  179. package/lib/modules/ScanOrderLogger/types.js +17 -0
  180. package/lib/modules/Schedule/getDateIsInSchedule.js +5 -5
  181. package/lib/modules/Schedule/index.d.ts +4 -13
  182. package/lib/modules/Schedule/index.js +4 -15
  183. package/lib/modules/Schedule/utils.d.ts +1 -1
  184. package/lib/modules/Summary/index.d.ts +3 -0
  185. package/lib/modules/Summary/index.js +61 -2
  186. package/lib/modules/Summary/types.d.ts +7 -0
  187. package/lib/modules/Summary/utils.d.ts +104 -1
  188. package/lib/modules/Summary/utils.js +659 -8
  189. package/lib/modules/index.d.ts +4 -0
  190. package/lib/modules/index.js +9 -1
  191. package/lib/server/index.d.ts +41 -4
  192. package/lib/server/index.js +272 -10
  193. package/lib/server/modules/order/index.d.ts +10 -2
  194. package/lib/server/modules/order/index.js +26 -1
  195. package/lib/server/modules/products/index.d.ts +26 -0
  196. package/lib/server/modules/products/index.js +174 -22
  197. package/lib/server/modules/products/types.d.ts +5 -1
  198. package/lib/solution/BaseSales/index.d.ts +175 -0
  199. package/lib/solution/BaseSales/index.js +655 -0
  200. package/lib/solution/BaseSales/types.d.ts +305 -0
  201. package/lib/solution/BaseSales/types.js +40 -0
  202. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +143 -0
  203. package/lib/solution/BaseSales/utils/parseSalesResponse.js +160 -0
  204. package/lib/solution/BaseSales/utils.d.ts +40 -0
  205. package/lib/solution/BaseSales/utils.js +200 -0
  206. package/lib/solution/BookingByStep/index.d.ts +14 -0
  207. package/lib/solution/BookingByStep/index.js +469 -91
  208. package/lib/solution/BookingByStep/types.d.ts +3 -1
  209. package/lib/solution/BookingByStep/types.js +10 -0
  210. package/lib/solution/BookingByStep/utils/capacity.js +1 -1
  211. package/lib/solution/BookingByStep/utils/resources.js +5 -2
  212. package/lib/solution/BookingTicket/index.d.ts +113 -15
  213. package/lib/solution/BookingTicket/index.js +253 -61
  214. package/lib/solution/BookingTicket/types.d.ts +69 -6
  215. package/lib/solution/BookingTicket/types.js +16 -14
  216. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +37 -0
  217. package/lib/solution/BookingTicket/utils/bookingStatus.js +65 -0
  218. package/lib/solution/BookingTicket/utils/cartView.d.ts +26 -0
  219. package/lib/solution/BookingTicket/utils/cartView.js +103 -0
  220. package/lib/solution/Sales/index.d.ts +1 -0
  221. package/lib/solution/ScanOrder/index.d.ts +146 -0
  222. package/lib/solution/ScanOrder/index.js +1820 -0
  223. package/lib/solution/ScanOrder/types.d.ts +305 -0
  224. package/lib/solution/ScanOrder/types.js +36 -0
  225. package/lib/solution/ScanOrder/utils.d.ts +167 -0
  226. package/lib/solution/ScanOrder/utils.js +639 -0
  227. package/lib/solution/ShopDiscount/index.d.ts +2 -0
  228. package/lib/solution/ShopDiscount/index.js +9 -4
  229. package/lib/solution/ShopDiscount/types.d.ts +4 -0
  230. package/lib/solution/VenueBooking/index.d.ts +197 -0
  231. package/lib/solution/VenueBooking/index.js +1892 -0
  232. package/lib/solution/VenueBooking/sales-section-4-annotated.json +343 -0
  233. package/lib/solution/VenueBooking/types.d.ts +153 -0
  234. package/lib/solution/VenueBooking/types.js +44 -0
  235. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +11 -0
  236. package/lib/solution/VenueBooking/utils/dateSummary.js +110 -0
  237. package/lib/solution/VenueBooking/utils/resource.d.ts +14 -0
  238. package/lib/solution/VenueBooking/utils/resource.js +91 -0
  239. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +34 -0
  240. package/lib/solution/VenueBooking/utils/slotMerge.js +225 -0
  241. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +32 -0
  242. package/lib/solution/VenueBooking/utils/timeSlot.js +339 -0
  243. package/lib/solution/VenueBooking/utils.d.ts +1 -0
  244. package/lib/solution/VenueBooking/utils.js +69 -0
  245. package/lib/solution/index.d.ts +3 -0
  246. package/lib/solution/index.js +7 -1
  247. package/package.json +1 -1
@@ -11,4 +11,8 @@ export * from './Payment';
11
11
  export * from './Resource';
12
12
  export * from './Step';
13
13
  export * from './Summary';
14
+ export * from './SalesSummary';
14
15
  export * from './Schedule';
16
+ export * from './Quotation';
17
+ export * from './ScanOrderLogger';
18
+ export * from './OpenData';
@@ -29,7 +29,11 @@ __reExport(modules_exports, require("./Payment"), module.exports);
29
29
  __reExport(modules_exports, require("./Resource"), module.exports);
30
30
  __reExport(modules_exports, require("./Step"), module.exports);
31
31
  __reExport(modules_exports, require("./Summary"), module.exports);
32
+ __reExport(modules_exports, require("./SalesSummary"), module.exports);
32
33
  __reExport(modules_exports, require("./Schedule"), module.exports);
34
+ __reExport(modules_exports, require("./Quotation"), module.exports);
35
+ __reExport(modules_exports, require("./ScanOrderLogger"), module.exports);
36
+ __reExport(modules_exports, require("./OpenData"), module.exports);
33
37
  // Annotate the CommonJS export names for ESM import in node:
34
38
  0 && (module.exports = {
35
39
  ...require("./Product"),
@@ -45,5 +49,9 @@ __reExport(modules_exports, require("./Schedule"), module.exports);
45
49
  ...require("./Resource"),
46
50
  ...require("./Step"),
47
51
  ...require("./Summary"),
48
- ...require("./Schedule")
52
+ ...require("./SalesSummary"),
53
+ ...require("./Schedule"),
54
+ ...require("./Quotation"),
55
+ ...require("./ScanOrderLogger"),
56
+ ...require("./OpenData")
49
57
  });
@@ -85,6 +85,10 @@ declare class Server {
85
85
  config: ModuleRegistryConfig;
86
86
  shouldPreload: boolean;
87
87
  }[]>;
88
+ /**
89
+ * 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
90
+ */
91
+ private setupProductsQuotationPriceBridge;
88
92
  /**
89
93
  * 获取 Products 模块实例
90
94
  */
@@ -260,16 +264,49 @@ declare class Server {
260
264
  */
261
265
  private handleResourceList;
262
266
  /**
263
- * 代理刷新 / 合并单个订单到本地:
264
- * - 入参:order_id(dataurl query)
265
- * - 流程:调后端 /order/sales/{id}?with[]=... → 若本地已有则覆盖;若无则 merge 写入 → 落 SQLite → emit onOrdersChanged
266
- * - 监听级联:onOrdersChanged 触发订单/预约/bookingRemoteCache 三路订阅者推送
267
+ * 代理刷新 / 合并订单到本地(单笔 / 批量二合一):
268
+ * - 入参(GET query data 任一):
269
+ * - `order_id`:单笔模式,原有行为
270
+ * - `order_ids`:批量模式,逗号分隔的 id 列表(如 `?order_ids=1,2,3`),数组也兼容
271
+ * - 同时存在时优先批量
272
+ * - 单笔流程:后端 /order/sales/{id}?with[]=all → 本地有则覆盖、无则 merge → 落 SQLite → emit onOrdersChanged
273
+ * - 批量流程:并发拉取每笔详情 → 一次性 `upsertOrdersFromRemote` 合并写入 → 仅 emit 一次 onOrdersChanged,
274
+ * 单笔失败不影响其他成功项;返回 { overwritten, inserted, failed }
275
+ * - 监听级联:onOrdersChanged 触发订单 / 预约 / bookingRemoteCache 三路订阅者推送
276
+ *
277
+ * @example 单笔:GET /update/localOrder?order_id=96971
278
+ * @example 批量:GET /update/localOrder?order_ids=96971,96972,96973
267
279
  */
268
280
  private handleUpdateLocalOrder;
281
+ private handleOrderSalesDetail;
282
+ /**
283
+ * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
284
+ * 自动 trim、去空、按字符串去重,输出归一化后的字符串数组。
285
+ *
286
+ * @example
287
+ * // url: /update/localOrder?order_ids=1,2,2,, → ['1','2']
288
+ * this.parseOrderIdsParam(url, undefined)
289
+ *
290
+ * @example
291
+ * // data: { order_ids: [1, '2', null] } → ['1','2']
292
+ * this.parseOrderIdsParam('', { order_ids: [1, '2', null] })
293
+ */
294
+ private parseOrderIdsParam;
295
+ /**
296
+ * 批量代理刷新 / 合并订单到本地:并发拉详情 → 单次合并 → 单次 emit。
297
+ * - 单笔失败不影响其他成功项
298
+ * - 没有任何成功项时不触发 emit / 落库
299
+ *
300
+ * @example
301
+ * await this.handleUpdateLocalOrdersBatch(['96971', '96972'])
302
+ */
303
+ private handleUpdateLocalOrdersBatch;
269
304
  /**
270
305
  * 从 url 中解析指定 query 参数,兼容相对路径与绝对路径
271
306
  */
272
307
  private extractQueryParam;
308
+ private extractOrderSalesDetailId;
309
+ private buildOrderSalesDetailBackendPath;
273
310
  /**
274
311
  * 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
275
312
  */
@@ -149,24 +149,25 @@ var Server = class {
149
149
  */
150
150
  this.handleProductQuery = async ({ url, method, data, config }) => {
151
151
  console.log("[Server] handleProductQuery:", url, method, data, config);
152
- const { menu_list_ids, schedule_datetime, schedule_date } = data;
152
+ const { menu_list_ids, schedule_datetime, schedule_date, customer_id } = data;
153
153
  const { callback, subscriberId } = config || {};
154
154
  this.logInfo("handleProductQuery: 开始处理商品查询请求", {
155
155
  menu_list_ids,
156
156
  schedule_datetime,
157
- schedule_date
157
+ schedule_date,
158
+ customer_id
158
159
  });
159
160
  if (subscriberId && typeof callback === "function") {
160
161
  this.productQuerySubscribers.set(subscriberId, {
161
162
  callback,
162
- context: { menu_list_ids, schedule_date, schedule_datetime }
163
+ context: { menu_list_ids, schedule_date, schedule_datetime, customer_id }
163
164
  });
164
165
  this.logInfo("handleProductQuery: 已注册订阅者", {
165
166
  subscriberId,
166
167
  totalSubscribers: this.productQuerySubscribers.size
167
168
  });
168
169
  }
169
- return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime });
170
+ return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime, customer_id });
170
171
  };
171
172
  /**
172
173
  * 按商品 id 查询单条(GET /shop/product/query/:productId)
@@ -357,13 +358,25 @@ var Server = class {
357
358
  };
358
359
  };
359
360
  /**
360
- * 代理刷新 / 合并单个订单到本地:
361
- * - 入参:order_id(dataurl query)
362
- * - 流程:调后端 /order/sales/{id}?with[]=... → 若本地已有则覆盖;若无则 merge 写入 → 落 SQLite → emit onOrdersChanged
363
- * - 监听级联:onOrdersChanged 触发订单/预约/bookingRemoteCache 三路订阅者推送
361
+ * 代理刷新 / 合并订单到本地(单笔 / 批量二合一):
362
+ * - 入参(GET query data 任一):
363
+ * - `order_id`:单笔模式,原有行为
364
+ * - `order_ids`:批量模式,逗号分隔的 id 列表(如 `?order_ids=1,2,3`),数组也兼容
365
+ * - 同时存在时优先批量
366
+ * - 单笔流程:后端 /order/sales/{id}?with[]=all → 本地有则覆盖、无则 merge → 落 SQLite → emit onOrdersChanged
367
+ * - 批量流程:并发拉取每笔详情 → 一次性 `upsertOrdersFromRemote` 合并写入 → 仅 emit 一次 onOrdersChanged,
368
+ * 单笔失败不影响其他成功项;返回 { overwritten, inserted, failed }
369
+ * - 监听级联:onOrdersChanged 触发订单 / 预约 / bookingRemoteCache 三路订阅者推送
370
+ *
371
+ * @example 单笔:GET /update/localOrder?order_id=96971
372
+ * @example 批量:GET /update/localOrder?order_ids=96971,96972,96973
364
373
  */
365
374
  this.handleUpdateLocalOrder = async ({ url, data }) => {
366
375
  var _a;
376
+ const batchIds = this.parseOrderIdsParam(url, data);
377
+ if (batchIds.length > 0) {
378
+ return this.handleUpdateLocalOrdersBatch(batchIds);
379
+ }
367
380
  const rawOrderId = (data && typeof data === "object" ? data.order_id : void 0) ?? this.extractQueryParam(url, "order_id");
368
381
  const orderId = rawOrderId === void 0 || rawOrderId === null || rawOrderId === "" ? null : String(rawOrderId).trim();
369
382
  this.logInfo("handleUpdateLocalOrder: 开始处理", { url, orderId });
@@ -438,6 +451,84 @@ var Server = class {
438
451
  };
439
452
  }
440
453
  };
454
+ this.handleOrderSalesDetail = async ({ url, data, path }) => {
455
+ var _a;
456
+ 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 };
462
+ }
463
+ if (!this.order) {
464
+ this.logError("handleOrderSalesDetail: Order 模块未注册");
465
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
466
+ }
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
+ };
476
+ }
477
+ if (!((_a = this.app) == null ? void 0 : _a.request)) {
478
+ this.logError("handleOrderSalesDetail: app.request 不可用");
479
+ return { code: 500, status: false, message: "app.request 不可用", data: null };
480
+ }
481
+ const backendPath = this.buildOrderSalesDetailBackendPath(orderId, data);
482
+ try {
483
+ const response = await this.app.request.get(backendPath, void 0, {
484
+ isShopApi: true
485
+ });
486
+ const fresh = (response == null ? void 0 : response.data) ?? response;
487
+ if (!fresh || typeof fresh !== "object" || fresh.order_id == null) {
488
+ this.logError("handleOrderSalesDetail: 后端返回订单为空", {
489
+ orderId,
490
+ backendPath
491
+ });
492
+ return {
493
+ code: 500,
494
+ status: false,
495
+ message: "后端返回订单为空",
496
+ data: null
497
+ };
498
+ }
499
+ await this.order.upsertOrdersFromRemote([fresh]);
500
+ const savedOrder = await this.order.getLocalOrderByOrderId(orderId);
501
+ if (!savedOrder) {
502
+ this.logError("handleOrderSalesDetail: 订单写入后回读失败", { orderId });
503
+ return {
504
+ code: 500,
505
+ status: false,
506
+ message: "订单写入后回读失败",
507
+ data: null
508
+ };
509
+ }
510
+ this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { orderId });
511
+ return {
512
+ code: 200,
513
+ status: true,
514
+ message: "",
515
+ data: savedOrder
516
+ };
517
+ } catch (error) {
518
+ const errorMessage = error instanceof Error ? error.message : String(error);
519
+ this.logError("handleOrderSalesDetail: 请求失败", {
520
+ orderId,
521
+ backendPath,
522
+ error: errorMessage
523
+ });
524
+ return {
525
+ code: 500,
526
+ status: false,
527
+ message: errorMessage,
528
+ data: null
529
+ };
530
+ }
531
+ };
441
532
  /**
442
533
  * GET /shop/schedule/floor-plan* 前缀路由:读本地 store;支持 subscriberId + callback 订阅更新
443
534
  */
@@ -801,6 +892,7 @@ var Server = class {
801
892
  } else {
802
893
  this.logInfo("跳过自动预加载", { autoPreload });
803
894
  }
895
+ await this.setupProductsQuotationPriceBridge();
804
896
  this.core.effects.on(import_types2.ProductsHooks.onProductsSyncCompleted, (payload) => {
805
897
  this.recomputeAndNotifyProductQuery({
806
898
  changedIds: payload == null ? void 0 : payload.changedIds
@@ -821,6 +913,30 @@ var Server = class {
821
913
  });
822
914
  return registeredModules;
823
915
  }
916
+ /**
917
+ * 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
918
+ */
919
+ async setupProductsQuotationPriceBridge() {
920
+ var _a;
921
+ if (!this.products) {
922
+ this.logWarning("setupProductsQuotationPriceBridge: Products 模块未注册");
923
+ return;
924
+ }
925
+ if (!this.schedule) {
926
+ this.logWarning("setupProductsQuotationPriceBridge: Schedule 模块未注册");
927
+ return;
928
+ }
929
+ try {
930
+ await this.products.setupQuotationPriceBridge({
931
+ scheduleModule: this.schedule,
932
+ channel: (_a = this.core.context) == null ? void 0 : _a.channel
933
+ });
934
+ this.logInfo("Products 报价单价格桥接初始化完成");
935
+ } catch (error) {
936
+ const errorMessage = error instanceof Error ? error.message : String(error);
937
+ this.logError("Products 报价单价格桥接初始化失败", { error: errorMessage });
938
+ }
939
+ }
824
940
  /**
825
941
  * 获取 Products 模块实例
826
942
  */
@@ -1094,6 +1210,11 @@ var Server = class {
1094
1210
  }
1095
1211
  ]);
1096
1212
  this.registerPrefixRoutes([
1213
+ {
1214
+ method: "get",
1215
+ prefix: "/shop/order/sales",
1216
+ handler: this.handleOrderSalesDetail.bind(this)
1217
+ },
1097
1218
  {
1098
1219
  method: "get",
1099
1220
  prefix: "/shop/schedule/floor-plan",
@@ -1553,6 +1674,127 @@ var Server = class {
1553
1674
  };
1554
1675
  }
1555
1676
  }
1677
+ /**
1678
+ * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
1679
+ * 自动 trim、去空、按字符串去重,输出归一化后的字符串数组。
1680
+ *
1681
+ * @example
1682
+ * // url: /update/localOrder?order_ids=1,2,2,, → ['1','2']
1683
+ * this.parseOrderIdsParam(url, undefined)
1684
+ *
1685
+ * @example
1686
+ * // data: { order_ids: [1, '2', null] } → ['1','2']
1687
+ * this.parseOrderIdsParam('', { order_ids: [1, '2', null] })
1688
+ */
1689
+ parseOrderIdsParam(url, data) {
1690
+ const collected = [];
1691
+ const pushRaw = (raw) => {
1692
+ if (raw === void 0 || raw === null)
1693
+ return;
1694
+ if (Array.isArray(raw)) {
1695
+ raw.forEach(pushRaw);
1696
+ return;
1697
+ }
1698
+ const str = String(raw).trim();
1699
+ if (!str)
1700
+ return;
1701
+ str.split(",").forEach((piece) => {
1702
+ const v = piece.trim();
1703
+ if (v)
1704
+ collected.push(v);
1705
+ });
1706
+ };
1707
+ if (data && typeof data === "object") {
1708
+ pushRaw(data.order_ids);
1709
+ }
1710
+ pushRaw(this.extractQueryParam(url, "order_ids"));
1711
+ const seen = /* @__PURE__ */ new Set();
1712
+ const result = [];
1713
+ for (const id of collected) {
1714
+ if (seen.has(id))
1715
+ continue;
1716
+ seen.add(id);
1717
+ result.push(id);
1718
+ }
1719
+ return result;
1720
+ }
1721
+ /**
1722
+ * 批量代理刷新 / 合并订单到本地:并发拉详情 → 单次合并 → 单次 emit。
1723
+ * - 单笔失败不影响其他成功项
1724
+ * - 没有任何成功项时不触发 emit / 落库
1725
+ *
1726
+ * @example
1727
+ * await this.handleUpdateLocalOrdersBatch(['96971', '96972'])
1728
+ */
1729
+ async handleUpdateLocalOrdersBatch(orderIds) {
1730
+ var _a;
1731
+ this.logInfo("handleUpdateLocalOrdersBatch: 开始处理", {
1732
+ count: orderIds.length,
1733
+ orderIds
1734
+ });
1735
+ if (!this.order) {
1736
+ this.logError("handleUpdateLocalOrdersBatch: Order 模块未注册");
1737
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
1738
+ }
1739
+ if (!((_a = this.app) == null ? void 0 : _a.request)) {
1740
+ this.logError("handleUpdateLocalOrdersBatch: app.request 不可用");
1741
+ return { code: 500, status: false, message: "app.request 不可用", data: null };
1742
+ }
1743
+ const existedBefore = /* @__PURE__ */ new Map();
1744
+ for (const id of orderIds) {
1745
+ existedBefore.set(id, !!this.order.getOrderByOrderId(id));
1746
+ }
1747
+ let fetched = [];
1748
+ try {
1749
+ fetched = await this.order.fetchOrdersByHttp(orderIds);
1750
+ } catch (error) {
1751
+ const message = error instanceof Error ? error.message : String(error);
1752
+ this.logError("handleUpdateLocalOrdersBatch: 批量拉取失败", { message });
1753
+ return { code: 500, status: false, message, data: null };
1754
+ }
1755
+ const fetchedMap = /* @__PURE__ */ new Map();
1756
+ for (const order of fetched) {
1757
+ const oid = order == null ? void 0 : order.order_id;
1758
+ if (oid === void 0 || oid === null)
1759
+ continue;
1760
+ fetchedMap.set(String(oid), order);
1761
+ }
1762
+ const freshOrders = [];
1763
+ const succeedIds = [];
1764
+ const failed = [];
1765
+ for (const id of orderIds) {
1766
+ const fresh = fetchedMap.get(id);
1767
+ if (fresh) {
1768
+ freshOrders.push(fresh);
1769
+ succeedIds.push(id);
1770
+ } else {
1771
+ failed.push({ order_id: id, message: "后端未返回该订单详情" });
1772
+ }
1773
+ }
1774
+ if (freshOrders.length > 0) {
1775
+ try {
1776
+ await this.order.upsertOrdersFromRemote(freshOrders);
1777
+ } catch (error) {
1778
+ const message = error instanceof Error ? error.message : String(error);
1779
+ this.logError("handleUpdateLocalOrdersBatch: 合并写入失败", { message });
1780
+ return { code: 500, status: false, message, data: null };
1781
+ }
1782
+ }
1783
+ const overwritten = succeedIds.filter((id) => existedBefore.get(id));
1784
+ const inserted = succeedIds.filter((id) => !existedBefore.get(id));
1785
+ this.logInfo("handleUpdateLocalOrdersBatch: 完成", {
1786
+ total: orderIds.length,
1787
+ overwrittenCount: overwritten.length,
1788
+ insertedCount: inserted.length,
1789
+ failedCount: failed.length
1790
+ });
1791
+ return {
1792
+ code: 200,
1793
+ status: true,
1794
+ message: "",
1795
+ data: { overwritten, inserted, failed }
1796
+ };
1797
+ }
1556
1798
  /**
1557
1799
  * 从 url 中解析指定 query 参数,兼容相对路径与绝对路径
1558
1800
  */
@@ -1584,6 +1826,23 @@ var Server = class {
1584
1826
  return null;
1585
1827
  }
1586
1828
  }
1829
+ extractOrderSalesDetailId(url) {
1830
+ const path = this.parseRequestPath(url);
1831
+ const match = path.match(/^\/shop\/order\/sales\/([^/?#]+)$/);
1832
+ return (match == null ? void 0 : match[1]) ? decodeURIComponent(match[1]) : null;
1833
+ }
1834
+ buildOrderSalesDetailBackendPath(orderId, data) {
1835
+ const rawWith = data && typeof data === "object" ? data.with : void 0;
1836
+ const withFields = Array.isArray(rawWith) && rawWith.length > 0 ? rawWith : ["products", "scheduleEvents"];
1837
+ const searchParams = new URLSearchParams();
1838
+ withFields.forEach((field) => {
1839
+ if (field === void 0 || field === null || field === "")
1840
+ return;
1841
+ searchParams.append("with[]", String(field));
1842
+ });
1843
+ const query = searchParams.toString();
1844
+ return `/shop/order/sales/${encodeURIComponent(orderId)}${query ? `?${query}` : ""}`;
1845
+ }
1587
1846
  /**
1588
1847
  * 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
1589
1848
  */
@@ -1759,11 +2018,12 @@ var Server = class {
1759
2018
  */
1760
2019
  async computeProductQueryResult(context, options) {
1761
2020
  const tTotal = performance.now();
1762
- const { menu_list_ids, schedule_date, schedule_datetime, product_id } = context;
2021
+ const { menu_list_ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
1763
2022
  this.logInfo("computeProductQueryResult 开始", {
1764
2023
  menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
1765
2024
  schedule_datetime,
1766
2025
  schedule_date,
2026
+ customer_id,
1767
2027
  product_id,
1768
2028
  changedIds: options == null ? void 0 : options.changedIds
1769
2029
  });
@@ -1824,7 +2084,9 @@ var Server = class {
1824
2084
  }
1825
2085
  const tPrice = performance.now();
1826
2086
  const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
1827
- scheduleModule: this.getSchedule()
2087
+ scheduleModule: this.getSchedule(),
2088
+ schedule_datetime,
2089
+ customer_id
1828
2090
  }, {
1829
2091
  changedIds: options == null ? void 0 : options.changedIds
1830
2092
  });
@@ -38,6 +38,7 @@ export declare class OrderModule extends BaseModule implements Module {
38
38
  getOrderById(id: OrderId): OrderData | undefined;
39
39
  /** 按 order_id 查询(推荐) */
40
40
  getOrderByOrderId(orderId: OrderId): OrderData | undefined;
41
+ getLocalOrderByOrderId(orderId: OrderId): Promise<OrderData | null>;
41
42
  loadOrdersByServer(): Promise<OrderData[]>;
42
43
  getOrdersByResourceId(resourceId: string | number): OrderData[];
43
44
  /**
@@ -94,9 +95,16 @@ export declare class OrderModule extends BaseModule implements Module {
94
95
  */
95
96
  private processOrderSyncMessages;
96
97
  /**
97
- * 通过 HTTP 按 ids 增量拉取订单
98
+ * 通过 HTTP 按 ids 批量拉取订单详情(走 orderDataSource)。
99
+ *
100
+ * - 优先使用 `orderDataSource.fetchOrdersByIds`(如适配器实现了该方法)
101
+ * - 否则回退到 `orderDataSource.run({ http: { query: { ids } } })`
102
+ * - 失败统一返回空数组(由调用方按"返回缺失的 id" 判断单笔失败)
103
+ *
104
+ * @example
105
+ * const fresh = await orderModule.fetchOrdersByHttp(['96971', '96972'])
98
106
  */
99
- private fetchOrdersByHttp;
107
+ fetchOrdersByHttp(ids: OrderId[]): Promise<OrderData[]>;
100
108
  /**
101
109
  * 将增量订单合并到 store
102
110
  */
@@ -185,6 +185,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
185
185
  getOrderByOrderId(orderId) {
186
186
  return this.store.map.get(this.getIdKey(orderId));
187
187
  }
188
+ async getLocalOrderByOrderId(orderId) {
189
+ const key = this.getIdKey(orderId);
190
+ const memoryOrder = this.store.map.get(key);
191
+ if (memoryOrder)
192
+ return memoryOrder;
193
+ const orders = await this.loadOrdersFromSQLite();
194
+ const localOrder = orders.find((order) => {
195
+ const id = order == null ? void 0 : order.order_id;
196
+ if (id === void 0 || id === null)
197
+ return false;
198
+ return this.getIdKey(id) === key;
199
+ });
200
+ if (!localOrder)
201
+ return null;
202
+ this.store.list = orders;
203
+ this.syncOrdersMap();
204
+ return localOrder;
205
+ }
188
206
  async loadOrdersByServer() {
189
207
  var _a;
190
208
  let orderList = [];
@@ -511,7 +529,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
511
529
  await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
512
530
  }
513
531
  /**
514
- * 通过 HTTP 按 ids 增量拉取订单
532
+ * 通过 HTTP 按 ids 批量拉取订单详情(走 orderDataSource)。
533
+ *
534
+ * - 优先使用 `orderDataSource.fetchOrdersByIds`(如适配器实现了该方法)
535
+ * - 否则回退到 `orderDataSource.run({ http: { query: { ids } } })`
536
+ * - 失败统一返回空数组(由调用方按"返回缺失的 id" 判断单笔失败)
537
+ *
538
+ * @example
539
+ * const fresh = await orderModule.fetchOrdersByHttp(['96971', '96972'])
515
540
  */
516
541
  async fetchOrdersByHttp(ids) {
517
542
  if (!this.orderDataSource || ids.length === 0)
@@ -19,6 +19,11 @@ export declare class ProductsModule extends BaseModule implements Module {
19
19
  private readonly CACHE_MAX_DAYS;
20
20
  private formatters;
21
21
  private isPriceFormatterRegistered;
22
+ private quotationPriceBridge?;
23
+ private quotationBridgeChannel?;
24
+ private quotationBridgeCustomerId?;
25
+ private quotationBridgeRefreshPromise?;
26
+ private quotationBridgeRefreshKey?;
22
27
  private productDataSource;
23
28
  private pendingSyncMessages;
24
29
  private syncTimer?;
@@ -47,6 +52,26 @@ export declare class ProductsModule extends BaseModule implements Module {
47
52
  * @private
48
53
  */
49
54
  private loadProductsPrice;
55
+ /**
56
+ * 设置报价单价格桥接器。
57
+ * Server 层负责传入完整 schedule 模块,Products 只负责把报价单计算结果转成价格响应形状。
58
+ */
59
+ setupQuotationPriceBridge(params: {
60
+ scheduleModule?: any;
61
+ channel?: string;
62
+ customer_id?: number | string;
63
+ }): Promise<void>;
64
+ /**
65
+ * 刷新桥接器内的报价单列表。
66
+ */
67
+ refreshQuotationPriceBridge(params?: {
68
+ customer_id?: number | string;
69
+ }): Promise<void>;
70
+ private ensureQuotationBridgeReady;
71
+ private getQuotationBridgeScopeKey;
72
+ private buildPriceDataFromQuotation;
73
+ private buildVariantPriceData;
74
+ private buildBundleGroupPriceData;
50
75
  /**
51
76
  * 获取应用了价格的商品列表(带缓存)
52
77
  * 使用日期作为缓存 key,同一天的商品价格会被缓存
@@ -70,6 +95,7 @@ export declare class ProductsModule extends BaseModule implements Module {
70
95
  * @private
71
96
  */
72
97
  private prepareProductsWithPrice;
98
+ private getProductsPriceCacheKey;
73
99
  /**
74
100
  * 应用所有已注册的格式化器
75
101
  * @param products 商品列表