@pisell/pisellos 2.3.39 → 2.3.41

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 (226) hide show
  1. package/dist/core/index.d.ts +2 -0
  2. package/dist/core/index.js +7 -0
  3. package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  4. package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
  5. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  6. package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
  7. package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
  8. package/dist/model/strategy/adapter/promotion/examples.js +99 -0
  9. package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
  10. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  11. package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
  12. package/dist/model/strategy/adapter/promotion/type.js +45 -0
  13. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -3
  14. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +6 -3
  15. package/dist/modules/Discount/index.d.ts +0 -1
  16. package/dist/modules/Discount/index.js +11 -40
  17. package/dist/modules/Discount/types.d.ts +0 -1
  18. package/dist/modules/OpenData/index.d.ts +2 -0
  19. package/dist/modules/OpenData/index.js +10 -2
  20. package/dist/modules/Order/index.d.ts +29 -12
  21. package/dist/modules/Order/index.js +750 -509
  22. package/dist/modules/Order/payment-utils.d.ts +26 -0
  23. package/dist/modules/Order/payment-utils.js +225 -0
  24. package/dist/modules/Order/types.d.ts +33 -10
  25. package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
  26. package/dist/modules/Order/utils.d.ts +0 -10
  27. package/dist/modules/Order/utils.js +13 -41
  28. package/dist/modules/Payment/index.d.ts +2 -0
  29. package/dist/modules/Payment/index.js +79 -50
  30. package/dist/modules/Payment/types.d.ts +99 -28
  31. package/dist/modules/Payment/types.js +20 -3
  32. package/dist/modules/Payment/walletpass.d.ts +25 -1
  33. package/dist/modules/Payment/walletpass.js +707 -157
  34. package/dist/modules/Product/types.d.ts +0 -1
  35. package/dist/modules/ProductList/index.js +14 -33
  36. package/dist/modules/Quotation/index.d.ts +1 -1
  37. package/dist/modules/Quotation/index.js +2 -2
  38. package/dist/modules/Rules/index.d.ts +1 -0
  39. package/dist/modules/Rules/index.js +89 -96
  40. package/dist/modules/SalesSummary/index.js +13 -12
  41. package/dist/modules/ScanOrderLogger/index.d.ts +0 -2
  42. package/dist/modules/ScanOrderLogger/index.js +2 -15
  43. package/dist/modules/ScanOrderLogger/providers/feishu.js +27 -45
  44. package/dist/modules/ScanOrderLogger/types.d.ts +0 -1
  45. package/dist/modules/Schedule/index.d.ts +1 -3
  46. package/dist/modules/Schedule/index.js +16 -21
  47. package/dist/modules/Summary/utils.js +13 -38
  48. package/dist/modules/index.d.ts +0 -2
  49. package/dist/modules/index.js +1 -3
  50. package/dist/plugins/window.d.ts +0 -1
  51. package/dist/server/index.d.ts +16 -14
  52. package/dist/server/index.js +1925 -1143
  53. package/dist/server/modules/order/index.d.ts +54 -4
  54. package/dist/server/modules/order/index.js +1600 -700
  55. package/dist/server/modules/order/types.d.ts +11 -3
  56. package/dist/server/modules/order/types.js +1 -1
  57. package/dist/solution/BaseSales/index.d.ts +109 -20
  58. package/dist/solution/BaseSales/index.js +1800 -480
  59. package/dist/solution/BaseSales/types.d.ts +52 -0
  60. package/dist/solution/BaseSales/types.js +2 -1
  61. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  62. package/dist/solution/BaseSales/utils/cartPromotion.js +90 -31
  63. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  64. package/dist/solution/BookingByStep/index.d.ts +2 -17
  65. package/dist/solution/BookingByStep/index.js +215 -294
  66. package/dist/solution/BookingByStep/types.d.ts +1 -2
  67. package/dist/solution/BookingByStep/types.js +1 -3
  68. package/dist/solution/BookingByStep/utils/capacity.js +1 -17
  69. package/dist/solution/BookingByStep/utils/timeslots.d.ts +1 -3
  70. package/dist/solution/BookingByStep/utils/timeslots.js +12 -19
  71. package/dist/solution/BookingTicket/index.d.ts +7 -3
  72. package/dist/solution/BookingTicket/index.js +132 -49
  73. package/dist/solution/BookingTicket/utils/addProductDecision.js +6 -0
  74. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  75. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +172 -82
  76. package/dist/solution/BookingTicket/utils/weighingProductSku.d.ts +5 -0
  77. package/dist/solution/BookingTicket/utils/weighingProductSku.js +45 -0
  78. package/dist/solution/Sales/index.d.ts +1 -0
  79. package/dist/solution/Sales/index.js +10 -2
  80. package/dist/solution/ScanOrder/index.d.ts +14 -26
  81. package/dist/solution/ScanOrder/index.js +756 -1148
  82. package/dist/solution/ScanOrder/types.d.ts +1 -21
  83. package/dist/solution/ScanOrder/utils.d.ts +0 -8
  84. package/dist/solution/ScanOrder/utils.js +25 -66
  85. package/dist/solution/ShopDiscount/index.d.ts +0 -1
  86. package/dist/solution/ShopDiscount/index.js +87 -125
  87. package/dist/solution/VenueBooking/index.d.ts +11 -39
  88. package/dist/solution/VenueBooking/index.js +860 -1176
  89. package/dist/solution/VenueBooking/types.d.ts +0 -3
  90. package/dist/solution/VenueBooking/utils/resource.js +0 -1
  91. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  92. package/dist/solution/VenueBooking/utils/slotMerge.js +5 -10
  93. package/dist/solution/index.d.ts +0 -1
  94. package/dist/solution/index.js +1 -2
  95. package/dist/types/index.d.ts +1 -1
  96. package/dist/utils/payment-number.d.ts +9 -0
  97. package/dist/utils/payment-number.js +69 -0
  98. package/lib/core/index.d.ts +2 -0
  99. package/lib/core/index.js +4 -0
  100. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  101. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  102. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  103. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  104. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  105. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  106. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  107. package/lib/model/strategy/adapter/promotion/index.js +51 -0
  108. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  109. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  110. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  111. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  112. package/lib/modules/Discount/index.d.ts +0 -1
  113. package/lib/modules/Discount/index.js +0 -9
  114. package/lib/modules/Discount/types.d.ts +0 -1
  115. package/lib/modules/OpenData/index.d.ts +2 -0
  116. package/lib/modules/OpenData/index.js +6 -1
  117. package/lib/modules/Order/index.d.ts +29 -12
  118. package/lib/modules/Order/index.js +196 -86
  119. package/lib/modules/Order/payment-utils.d.ts +26 -0
  120. package/lib/modules/Order/payment-utils.js +224 -0
  121. package/lib/modules/Order/types.d.ts +33 -10
  122. package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
  123. package/lib/modules/Order/utils.d.ts +0 -10
  124. package/lib/modules/Order/utils.js +16 -40
  125. package/lib/modules/Payment/index.d.ts +2 -0
  126. package/lib/modules/Payment/index.js +34 -13
  127. package/lib/modules/Payment/types.d.ts +99 -28
  128. package/lib/modules/Payment/types.js +4 -3
  129. package/lib/modules/Payment/walletpass.d.ts +25 -1
  130. package/lib/modules/Payment/walletpass.js +470 -21
  131. package/lib/modules/Product/types.d.ts +0 -1
  132. package/lib/modules/ProductList/index.js +31 -40
  133. package/lib/modules/Quotation/index.d.ts +1 -1
  134. package/lib/modules/Quotation/index.js +2 -2
  135. package/lib/modules/Rules/index.d.ts +1 -0
  136. package/lib/modules/Rules/index.js +47 -40
  137. package/lib/modules/SalesSummary/index.js +7 -6
  138. package/lib/modules/ScanOrderLogger/index.d.ts +0 -2
  139. package/lib/modules/ScanOrderLogger/index.js +1 -13
  140. package/lib/modules/ScanOrderLogger/providers/feishu.js +6 -15
  141. package/lib/modules/ScanOrderLogger/types.d.ts +0 -1
  142. package/lib/modules/Schedule/index.d.ts +1 -3
  143. package/lib/modules/Schedule/index.js +8 -10
  144. package/lib/modules/Summary/utils.js +1 -21
  145. package/lib/modules/index.d.ts +0 -2
  146. package/lib/modules/index.js +1 -5
  147. package/lib/plugins/window.d.ts +0 -1
  148. package/lib/server/index.d.ts +16 -14
  149. package/lib/server/index.js +675 -83
  150. package/lib/server/modules/order/index.d.ts +54 -4
  151. package/lib/server/modules/order/index.js +679 -66
  152. package/lib/server/modules/order/types.d.ts +11 -3
  153. package/lib/solution/BaseSales/index.d.ts +109 -20
  154. package/lib/solution/BaseSales/index.js +883 -70
  155. package/lib/solution/BaseSales/types.d.ts +52 -0
  156. package/lib/solution/BaseSales/types.js +2 -1
  157. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  158. package/lib/solution/BaseSales/utils/cartPromotion.js +63 -12
  159. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  160. package/lib/solution/BookingByStep/index.d.ts +2 -17
  161. package/lib/solution/BookingByStep/index.js +18 -60
  162. package/lib/solution/BookingByStep/types.d.ts +1 -2
  163. package/lib/solution/BookingByStep/types.js +0 -5
  164. package/lib/solution/BookingByStep/utils/capacity.js +1 -20
  165. package/lib/solution/BookingByStep/utils/timeslots.d.ts +1 -3
  166. package/lib/solution/BookingByStep/utils/timeslots.js +11 -19
  167. package/lib/solution/BookingTicket/index.d.ts +7 -3
  168. package/lib/solution/BookingTicket/index.js +62 -9
  169. package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -0
  170. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  171. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +36 -4
  172. package/lib/solution/BookingTicket/utils/weighingProductSku.d.ts +5 -0
  173. package/lib/solution/BookingTicket/utils/weighingProductSku.js +63 -0
  174. package/lib/solution/Sales/index.d.ts +1 -0
  175. package/lib/solution/Sales/index.js +5 -3
  176. package/lib/solution/ScanOrder/index.d.ts +14 -26
  177. package/lib/solution/ScanOrder/index.js +190 -449
  178. package/lib/solution/ScanOrder/types.d.ts +1 -21
  179. package/lib/solution/ScanOrder/utils.d.ts +0 -8
  180. package/lib/solution/ScanOrder/utils.js +0 -31
  181. package/lib/solution/ShopDiscount/index.d.ts +0 -1
  182. package/lib/solution/ShopDiscount/index.js +0 -14
  183. package/lib/solution/VenueBooking/index.d.ts +11 -39
  184. package/lib/solution/VenueBooking/index.js +123 -328
  185. package/lib/solution/VenueBooking/types.d.ts +0 -3
  186. package/lib/solution/VenueBooking/utils/resource.js +0 -1
  187. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  188. package/lib/solution/VenueBooking/utils/slotMerge.js +4 -6
  189. package/lib/solution/index.d.ts +0 -1
  190. package/lib/solution/index.js +1 -3
  191. package/lib/types/index.d.ts +1 -1
  192. package/lib/utils/payment-number.d.ts +9 -0
  193. package/lib/utils/payment-number.js +64 -0
  194. package/package.json +1 -1
  195. package/dist/modules/Holder/index.d.ts +0 -48
  196. package/dist/modules/Holder/index.js +0 -640
  197. package/dist/modules/Holder/types.d.ts +0 -123
  198. package/dist/modules/Holder/types.js +0 -1
  199. package/dist/modules/Holder/utils.d.ts +0 -13
  200. package/dist/modules/Holder/utils.js +0 -34
  201. package/dist/modules/ResourcePlanner/index.d.ts +0 -24
  202. package/dist/modules/ResourcePlanner/index.js +0 -181
  203. package/dist/modules/ResourcePlanner/planner.d.ts +0 -14
  204. package/dist/modules/ResourcePlanner/planner.js +0 -1069
  205. package/dist/modules/ResourcePlanner/types.d.ts +0 -227
  206. package/dist/modules/ResourcePlanner/types.js +0 -1
  207. package/dist/solution/UnifiedBookingSales/index.d.ts +0 -183
  208. package/dist/solution/UnifiedBookingSales/index.js +0 -1871
  209. package/dist/solution/UnifiedBookingSales/types.d.ts +0 -143
  210. package/dist/solution/UnifiedBookingSales/types.js +0 -11
  211. package/lib/modules/Holder/index.d.ts +0 -48
  212. package/lib/modules/Holder/index.js +0 -402
  213. package/lib/modules/Holder/types.d.ts +0 -123
  214. package/lib/modules/Holder/types.js +0 -17
  215. package/lib/modules/Holder/utils.d.ts +0 -13
  216. package/lib/modules/Holder/utils.js +0 -71
  217. package/lib/modules/ResourcePlanner/index.d.ts +0 -24
  218. package/lib/modules/ResourcePlanner/index.js +0 -148
  219. package/lib/modules/ResourcePlanner/planner.d.ts +0 -14
  220. package/lib/modules/ResourcePlanner/planner.js +0 -933
  221. package/lib/modules/ResourcePlanner/types.d.ts +0 -227
  222. package/lib/modules/ResourcePlanner/types.js +0 -17
  223. package/lib/solution/UnifiedBookingSales/index.d.ts +0 -183
  224. package/lib/solution/UnifiedBookingSales/index.js +0 -1076
  225. package/lib/solution/UnifiedBookingSales/types.d.ts +0 -143
  226. package/lib/solution/UnifiedBookingSales/types.js +0 -33
@@ -37,6 +37,7 @@ var import_dayjs = __toESM(require("dayjs"));
37
37
  var import_BaseModule = require("../../../modules/BaseModule");
38
38
  var import_orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
39
39
  var import_types = require("./types");
40
+ var import_payment_utils = require("../../../modules/Order/payment-utils");
40
41
  var INDEXDB_STORE_NAME = "orders";
41
42
  var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
42
43
  var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
@@ -46,10 +47,13 @@ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
46
47
  var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
47
48
  "upsertOrdersFromRemote",
48
49
  "upsertPendingSyncOrders",
50
+ "upsertLocalDraftOrders",
49
51
  "overwriteExistingOrder",
50
- "markOrderSyncedByExternalSaleNumber"
52
+ "markOrderSyncedByExternalSaleNumber",
53
+ "updateLocalPayment"
51
54
  ]);
52
55
  var ORDER_MERGE_SELF_CHECK = false;
56
+ var PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER = "__pisell_os_pending_payment_without_unique_number__";
53
57
  var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
54
58
  var ORDER_COLLECTION_KIND_BY_FIELD = {
55
59
  products: "product",
@@ -100,7 +104,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
100
104
  this.updateCreateStore();
101
105
  }
102
106
  if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
103
- this.store.list = options.initialState.list.map((order) => this.normalizeOrderForMemoryList(order));
107
+ this.store.list = this.normalizeOrdersForMemoryList(
108
+ options.initialState.list,
109
+ "initialState"
110
+ );
104
111
  this.syncOrdersMap();
105
112
  this.emitOrdersChanged([], "initialState");
106
113
  } else {
@@ -166,7 +173,35 @@ var OrderModule = class extends import_BaseModule.BaseModule {
166
173
  * 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
167
174
  */
168
175
  normalizeOrderCollectionsForIngress(order, source) {
169
- const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(order);
176
+ const sourceOrder = (0, import_lodash_es.cloneDeep)(order);
177
+ const sourceOrderRecord = sourceOrder;
178
+ if (Array.isArray(sourceOrderRecord.payments)) {
179
+ sourceOrderRecord.payments = sourceOrderRecord.payments.map((payment) => {
180
+ if (!(0, import_payment_utils.isPendingOrderPayment)(payment) || (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => key.startsWith("unique_payment_number:"))) {
181
+ return payment;
182
+ }
183
+ return {
184
+ ...payment,
185
+ [PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]: true
186
+ };
187
+ });
188
+ }
189
+ const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(sourceOrder);
190
+ const normalizedOrderRecord = result.order;
191
+ if (Array.isArray(normalizedOrderRecord.payments)) {
192
+ normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(
193
+ (payment) => {
194
+ if (!(payment == null ? void 0 : payment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]))
195
+ return payment;
196
+ const nextPayment = { ...payment };
197
+ const metadata = { ...nextPayment.metadata || {} };
198
+ delete metadata.unique_payment_number;
199
+ delete nextPayment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER];
200
+ nextPayment.metadata = metadata;
201
+ return nextPayment;
202
+ }
203
+ );
204
+ }
170
205
  const kinds = ["product", "booking", "payment"];
171
206
  const hasChanges = kinds.some((kind) => {
172
207
  const stats = result.stats[kind];
@@ -202,9 +237,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
202
237
  /**
203
238
  * incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
204
239
  */
205
- mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = []) {
240
+ mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = [], options = {}) {
206
241
  const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
207
242
  const existingItems = Array.isArray(existing) ? existing : [];
243
+ if (field === "payments" && options.preserveIdentifiedPendingPayments) {
244
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
245
+ existingItems,
246
+ incoming,
247
+ { preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
248
+ );
249
+ }
208
250
  return incoming.map((incomingItem) => {
209
251
  const existingItem = existingItems.find(
210
252
  (item) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem)
@@ -460,17 +502,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
460
502
  return DEFAULT_ORDER_SYNC_THROTTLE_MS;
461
503
  }
462
504
  async preload() {
463
- const getData = async () => {
464
- const orders = await this.loadOrdersByServer();
465
- if (orders.length === 0) {
466
- return;
467
- }
468
- this.store.list = (0, import_lodash_es.cloneDeep)(orders);
469
- this.syncOrdersMap();
470
- this.emitOrdersChanged([], "preload");
471
- this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
472
- };
473
- getData();
505
+ const orders = await this.loadOrdersByServer();
506
+ this.store.list = (0, import_lodash_es.cloneDeep)(orders);
507
+ this.syncOrdersMap();
508
+ await this.emitOrdersChanged([], "preload");
509
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
474
510
  }
475
511
  getOrders() {
476
512
  return this.store.list;
@@ -482,6 +518,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
482
518
  getOrderByOrderId(orderId) {
483
519
  return this.store.map.get(this.getIdKey(orderId));
484
520
  }
521
+ buildLocalPaymentOrderLogContext(order) {
522
+ if (!order)
523
+ return {};
524
+ return {
525
+ order_id: order.order_id ?? null,
526
+ external_sale_number: order.external_sale_number ?? null,
527
+ order_number: order.order_number ?? null,
528
+ shop_order_number: order.shop_order_number ?? null,
529
+ shop_full_order_number: order.shop_full_order_number ?? null,
530
+ order_status: order.status ?? null,
531
+ payment_status: order.payment_status ?? null,
532
+ is_draft_order: Number(order.is_draft_order || 0),
533
+ need_sync: Number(order.need_sync || 0),
534
+ platform: order.platform ?? null,
535
+ business_code: order.business_code ?? null,
536
+ order_sales_channel: order.order_sales_channel ?? null,
537
+ sales_channel: order.sales_channel ?? null,
538
+ order_type: order.type ?? null,
539
+ payments_count: Array.isArray(order.payments) ? order.payments.length : 0
540
+ };
541
+ }
485
542
  getLocalOrderFromMemoryByLookup(lookup) {
486
543
  const key = this.getIdKey(lookup);
487
544
  const memoryOrderById = this.store.map.get(key);
@@ -490,28 +547,200 @@ var OrderModule = class extends import_BaseModule.BaseModule {
490
547
  const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
491
548
  return memoryOrder || null;
492
549
  }
493
- async getLocalOrderByLookup(lookup) {
550
+ async getLocalOrderByLookup(lookup, options = {}) {
494
551
  const key = this.getIdKey(lookup);
552
+ const logContext = {
553
+ operation_id: options.operationId,
554
+ lookup: key,
555
+ memory_order_count: this.store.list.length
556
+ };
557
+ if (options.operationId) {
558
+ this.logInfo("getLocalOrderByLookup-localPayment-开始", logContext);
559
+ }
495
560
  const memoryOrderById = this.store.map.get(key);
496
- if (memoryOrderById)
561
+ if (memoryOrderById) {
562
+ if (options.operationId) {
563
+ this.logInfo("getLocalOrderByLookup-localPayment-命中内存映射", {
564
+ ...logContext,
565
+ ...this.buildLocalPaymentOrderLogContext(memoryOrderById)
566
+ });
567
+ }
497
568
  return memoryOrderById;
569
+ }
498
570
  const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
499
- if (memoryOrder)
571
+ if (memoryOrder) {
572
+ if (options.operationId) {
573
+ this.logInfo("getLocalOrderByLookup-localPayment-命中内存列表", {
574
+ ...logContext,
575
+ ...this.buildLocalPaymentOrderLogContext(memoryOrder)
576
+ });
577
+ }
500
578
  return memoryOrder;
579
+ }
580
+ if (options.operationId) {
581
+ this.logInfo("getLocalOrderByLookup-localPayment-开始读取SQLite", logContext);
582
+ }
501
583
  const orders = await this.loadOrdersFromSQLite();
502
584
  const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
503
- if (!localOrder)
585
+ if (!localOrder) {
586
+ if (options.operationId) {
587
+ this.logWarning("getLocalOrderByLookup-localPayment-SQLite未命中", {
588
+ ...logContext,
589
+ sqlite_order_count: orders.length
590
+ });
591
+ }
592
+ return null;
593
+ }
594
+ this.store.list = this.normalizeOrdersForMemoryList(
595
+ orders,
596
+ "getLocalOrderByLookup.sqliteMemory"
597
+ );
598
+ this.syncOrdersMap();
599
+ const normalizedOrder = this.normalizeOrderForMemoryList(localOrder);
600
+ if (options.operationId) {
601
+ this.logInfo("getLocalOrderByLookup-localPayment-SQLite命中", {
602
+ ...logContext,
603
+ sqlite_order_count: orders.length,
604
+ ...this.buildLocalPaymentOrderLogContext(normalizedOrder)
605
+ });
606
+ }
607
+ return normalizedOrder;
608
+ }
609
+ async getLocalPayment(params) {
610
+ const logContext = {
611
+ operation_id: params.operationId,
612
+ sale_id: params.saleId,
613
+ payment_number: params.paymentNumber
614
+ };
615
+ this.logInfo("getLocalPayment-开始", logContext);
616
+ try {
617
+ const order = await this.getLocalOrderByLookup(params.saleId, {
618
+ operationId: params.operationId
619
+ });
620
+ if (!order) {
621
+ this.logWarning("getLocalPayment-订单未命中", logContext);
622
+ return null;
623
+ }
624
+ const payments = order.payments || [];
625
+ const match = (0, import_payment_utils.resolveOrderPaymentIdentity)(
626
+ payments,
627
+ params.paymentNumber,
628
+ "compat"
629
+ );
630
+ if (!match) {
631
+ this.logWarning("getLocalPayment-支付项未命中", {
632
+ ...logContext,
633
+ ...this.buildLocalPaymentOrderLogContext(order),
634
+ payments
635
+ });
636
+ return null;
637
+ }
638
+ this.logInfo("getLocalPayment-支付项命中", {
639
+ ...logContext,
640
+ ...this.buildLocalPaymentOrderLogContext(order),
641
+ matched_by: match.matchedBy,
642
+ payment_index: match.index,
643
+ payment: match.payment
644
+ });
645
+ return {
646
+ order,
647
+ payment: match.payment,
648
+ paymentIndex: match.index,
649
+ matchedBy: match.matchedBy
650
+ };
651
+ } catch (error) {
652
+ this.logError("getLocalPayment-查询失败", {
653
+ ...logContext,
654
+ error: error instanceof Error ? error.message : String(error)
655
+ });
656
+ throw error;
657
+ }
658
+ }
659
+ async updateLocalPayment(params) {
660
+ const logContext = {
661
+ operation_id: params.operationId,
662
+ sale_id: params.saleId,
663
+ payment_number: params.paymentNumber,
664
+ incoming_payment_update: params.updates
665
+ };
666
+ this.logInfo("updateLocalPayment-开始", logContext);
667
+ const found = await this.getLocalPayment(params);
668
+ if (!found) {
669
+ this.logWarning("updateLocalPayment-支付项未命中", logContext);
504
670
  return null;
505
- this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
671
+ }
672
+ const previousPayment = (0, import_lodash_es.cloneDeep)(found.payment);
673
+ const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(found.payment, {
674
+ ...params.updates,
675
+ updated_at: params.updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
676
+ });
677
+ const nextOrder = {
678
+ ...found.order,
679
+ payments: (found.order.payments || []).map((payment, index) => index === found.paymentIndex ? nextPayment : payment),
680
+ updated_at: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
681
+ };
682
+ const paymentContext = {
683
+ ...logContext,
684
+ matched_by: found.matchedBy,
685
+ payment_index: found.paymentIndex,
686
+ ...this.buildLocalPaymentOrderLogContext(nextOrder),
687
+ previous_payment: previousPayment,
688
+ payment: nextPayment
689
+ };
690
+ this.logInfo("updateLocalPayment-支付项合并完成", paymentContext);
691
+ const targetIndex = this.findOrderIndexByIdentity(this.store.list, found.order);
692
+ const shouldKeepInMemory = this.shouldKeepOrderInMemory(nextOrder);
693
+ if (targetIndex < 0 && shouldKeepInMemory) {
694
+ this.logError("updateLocalPayment-订单Store索引未命中", paymentContext);
695
+ return null;
696
+ }
697
+ const previousList = this.store.list;
698
+ this.store.list = shouldKeepInMemory ? this.store.list.map((order, index) => index === targetIndex ? nextOrder : order) : this.store.list.filter((_, index) => index !== targetIndex);
506
699
  this.syncOrdersMap();
507
- return this.normalizeOrderForMemoryList(localOrder);
700
+ const storageOrder = this.withoutSyntheticDraftOrderId(nextOrder);
701
+ try {
702
+ this.logInfo("updateLocalPayment-SQLite写入开始", {
703
+ ...paymentContext,
704
+ storage_order_id: storageOrder.order_id ?? null
705
+ });
706
+ await this.updateOrderInSQLite(storageOrder, "updateLocalPayment", { throwOnError: true });
707
+ this.logInfo("updateLocalPayment-SQLite写入完成", {
708
+ ...paymentContext,
709
+ storage_order_id: storageOrder.order_id ?? null
710
+ });
711
+ } catch (error) {
712
+ this.store.list = previousList;
713
+ this.syncOrdersMap();
714
+ this.logError("updateLocalPayment-SQLite写入失败并回滚内存", {
715
+ ...paymentContext,
716
+ storage_order_id: storageOrder.order_id ?? null,
717
+ error: error instanceof Error ? error.message : String(error)
718
+ });
719
+ throw error;
720
+ }
721
+ if (shouldKeepInMemory || targetIndex >= 0) {
722
+ await this.emitOrdersChanged(
723
+ shouldKeepInMemory ? [nextOrder] : [],
724
+ shouldKeepInMemory ? "updateLocalPayment" : "updateLocalPayment.sqliteOnlyDraft"
725
+ );
726
+ }
727
+ this.logInfo("updateLocalPayment-变更事件完成", paymentContext);
728
+ return { order: nextOrder, payment: nextPayment, previousPayment };
508
729
  }
509
730
  async loadOrdersByServer() {
510
731
  var _a;
511
732
  let orderList = [];
733
+ const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
734
+ (order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
735
+ );
512
736
  this.logInfo("loadOrdersByServer-开始", {
513
737
  hasOrderDataSource: !!this.orderDataSource,
514
- query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null
738
+ query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
739
+ protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
740
+ protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce(
741
+ (count, order) => count + this.getIdentifiedPendingPayments(order).length,
742
+ 0
743
+ )
515
744
  });
516
745
  if (this.orderDataSource) {
517
746
  try {
@@ -531,10 +760,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
531
760
  return this.store.list;
532
761
  }
533
762
  }
534
- const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
535
- const memoryOrders = mergedOrders.map((order) => this.normalizeOrderForMemoryList(order));
763
+ const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
764
+ orderList,
765
+ "loadOrdersByServer",
766
+ protectedOrdersBeforeRemoteFetch
767
+ );
768
+ const memoryOrders = this.normalizeOrdersForMemoryList(
769
+ mergedOrders,
770
+ "loadOrdersByServer.memory"
771
+ );
536
772
  this.logInfo("loadOrdersByServer-结束", {
537
- count: memoryOrders.length
773
+ count: memoryOrders.length,
774
+ persistedCount: mergedOrders.length,
775
+ sqliteOnlyDraftCount: mergedOrders.length - memoryOrders.length
538
776
  });
539
777
  await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
540
778
  return memoryOrders;
@@ -554,18 +792,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
554
792
  try {
555
793
  this.updateCreateStore();
556
794
  const orders = await this.loadOrdersByServer();
557
- if (orders.length > 0) {
558
- this.store.list = (0, import_lodash_es.cloneDeep)(orders);
559
- this.syncOrdersMap();
560
- this.emitOrdersChanged([], "silentRefresh");
561
- await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
562
- this.logInfo("silentRefresh 完成", {
563
- orderCount: orders.length,
564
- duration: `${Date.now() - startTime}ms`
565
- });
566
- } else {
567
- this.logInfo("silentRefresh: 服务器未返回数据");
568
- }
795
+ this.store.list = (0, import_lodash_es.cloneDeep)(orders);
796
+ this.syncOrdersMap();
797
+ await this.emitOrdersChanged([], "silentRefresh");
798
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
799
+ this.logInfo("silentRefresh 完成", {
800
+ orderCount: orders.length,
801
+ duration: `${Date.now() - startTime}ms`
802
+ });
569
803
  return this.store.list;
570
804
  } catch (error) {
571
805
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -579,6 +813,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
579
813
  normalizeOrderForMemoryList(order, source = "normalizeOrderForMemoryList") {
580
814
  const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, source);
581
815
  const externalSaleNumber = normalizedOrder == null ? void 0 : normalizedOrder.external_sale_number;
816
+ if (this.isDraftOrder(normalizedOrder) && !this.hasRealOrderId(normalizedOrder)) {
817
+ return normalizedOrder;
818
+ }
582
819
  if ((normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== void 0 && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== null && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== "") {
583
820
  return normalizedOrder;
584
821
  }
@@ -590,6 +827,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
590
827
  order_id: externalSaleNumber
591
828
  };
592
829
  }
830
+ normalizeOrdersForMemoryList(orders, source) {
831
+ return orders.map((order) => this.normalizeOrderForMemoryList(order, source)).filter((order) => this.shouldKeepOrderInMemory(order));
832
+ }
833
+ hasRealOrderId(order) {
834
+ if (!order || this.isBlankIdentityValue(order.order_id))
835
+ return false;
836
+ const externalSaleNumber = order.external_sale_number;
837
+ return !(this.isDraftOrder(order) && !this.isBlankIdentityValue(externalSaleNumber) && String(order.order_id) === String(externalSaleNumber));
838
+ }
839
+ shouldKeepOrderInMemory(order) {
840
+ return !this.isDraftOrder(order) || this.hasRealOrderId(order);
841
+ }
842
+ withoutSyntheticDraftOrderId(order) {
843
+ const externalSaleNumber = order.external_sale_number;
844
+ if (Number(order.is_draft_order || 0) !== 1 || order.order_id === void 0 || externalSaleNumber === void 0 || String(order.order_id) !== String(externalSaleNumber)) {
845
+ return order;
846
+ }
847
+ const next = { ...order };
848
+ delete next.order_id;
849
+ return next;
850
+ }
593
851
  /**
594
852
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
595
853
  * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
@@ -638,13 +896,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
638
896
  * 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
639
897
  * 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
640
898
  */
641
- async upsertOrdersFromRemote(freshOrders) {
899
+ async upsertOrdersFromRemote(freshOrders, source = "upsertOrdersFromRemote") {
642
900
  if (!(freshOrders == null ? void 0 : freshOrders.length)) {
643
901
  this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
644
902
  return;
645
903
  }
646
- this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
647
- await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
904
+ this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length, source });
905
+ await this.mergeOrdersToStore(freshOrders, source);
648
906
  }
649
907
  async markOrderSyncedByExternalSaleNumber(params) {
650
908
  const externalSaleNumber = params.externalSaleNumber;
@@ -670,7 +928,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
670
928
  ...existing,
671
929
  ...params.patch || {},
672
930
  external_sale_number: existing.external_sale_number ?? externalSaleNumber,
673
- need_sync: 0
931
+ need_sync: 0,
932
+ is_draft_order: 0
674
933
  });
675
934
  const storageKey = this.getOrderStorageKey(nextOrder) || key;
676
935
  this.store.list = this.store.list.map((order, index) => {
@@ -695,7 +954,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
695
954
  * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
696
955
  * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
697
956
  */
698
- async upsertPendingSyncOrders(pendingOrders) {
957
+ async upsertPendingSyncOrders(pendingOrders, options = {}) {
699
958
  if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
700
959
  this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
701
960
  return;
@@ -707,14 +966,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
707
966
  order,
708
967
  "upsertPendingSyncOrders.incoming"
709
968
  );
710
- const storageKey = this.getOrderStorageKey(normalizedOrder);
969
+ const pendingOrder = {
970
+ ...normalizedOrder,
971
+ need_sync: 1,
972
+ is_draft_order: 0
973
+ };
974
+ const storageKey = this.getOrderStorageKey(pendingOrder);
711
975
  if (!storageKey)
712
976
  continue;
713
- pendingMap.set(storageKey, normalizedOrder);
977
+ pendingMap.set(storageKey, pendingOrder);
714
978
  memoryPendingMap.set(
715
979
  storageKey,
716
980
  this.normalizeOrderForMemoryList(
717
- normalizedOrder,
981
+ pendingOrder,
718
982
  "upsertPendingSyncOrders.memory"
719
983
  )
720
984
  );
@@ -745,7 +1009,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
745
1009
  if (matchIndex >= 0) {
746
1010
  const existingOrder = updatedList[matchIndex];
747
1011
  const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
748
- updatedList[matchIndex] = mergedOrder;
1012
+ const nextOrder = {
1013
+ ...mergedOrder,
1014
+ need_sync: 1,
1015
+ is_draft_order: 0
1016
+ };
1017
+ updatedList[matchIndex] = nextOrder;
749
1018
  const pendingSnapshot = pendingMap.get(storageKey);
750
1019
  if (pendingSnapshot) {
751
1020
  pendingMap.set(
@@ -753,7 +1022,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
753
1022
  this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
754
1023
  );
755
1024
  }
756
- this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
1025
+ this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
757
1026
  mergeActions[storageKey] = "update";
758
1027
  continue;
759
1028
  }
@@ -763,15 +1032,131 @@ var OrderModule = class extends import_BaseModule.BaseModule {
763
1032
  mergeActions[storageKey] = "insert";
764
1033
  }
765
1034
  const patchedOrders = [...pendingMap.values()];
1035
+ const previousList = this.store.list;
766
1036
  this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
767
1037
  this.syncOrdersMap();
768
- await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
1038
+ try {
1039
+ await this.patchOrdersInSQLite(
1040
+ patchedOrders,
1041
+ "upsertPendingSyncOrders",
1042
+ mergeActions,
1043
+ options
1044
+ );
1045
+ } catch (error) {
1046
+ this.store.list = previousList;
1047
+ this.syncOrdersMap();
1048
+ throw error;
1049
+ }
769
1050
  this.logInfo("upsertPendingSyncOrders-结束", {
770
1051
  count: patchedOrders.length,
771
1052
  storeOrderCountAfter: this.store.list.length
772
1053
  });
773
1054
  await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
774
1055
  }
1056
+ /**
1057
+ * 将 POS 草稿订单按 SQLite storage key 落库。
1058
+ * 只有具备真实 order_id 的草稿进入 store;其余草稿仅供本地恢复查询。
1059
+ */
1060
+ async upsertLocalDraftOrders(draftOrders) {
1061
+ if (!(draftOrders == null ? void 0 : draftOrders.length)) {
1062
+ this.logInfo("upsertLocalDraftOrders-订单列表为空", {});
1063
+ return;
1064
+ }
1065
+ const draftMap = /* @__PURE__ */ new Map();
1066
+ const memoryDraftMap = /* @__PURE__ */ new Map();
1067
+ for (const order of draftOrders) {
1068
+ const draftOrder = {
1069
+ ...order,
1070
+ need_sync: 0,
1071
+ is_draft_order: 1
1072
+ };
1073
+ const storageKey = this.getOrderStorageKey(draftOrder);
1074
+ if (!storageKey)
1075
+ continue;
1076
+ draftMap.set(storageKey, draftOrder);
1077
+ const memoryDraftOrder = this.normalizeOrderForMemoryList(draftOrder);
1078
+ if (this.shouldKeepOrderInMemory(memoryDraftOrder)) {
1079
+ memoryDraftMap.set(storageKey, memoryDraftOrder);
1080
+ }
1081
+ }
1082
+ if (draftMap.size === 0) {
1083
+ this.logError("upsertLocalDraftOrders-订单缺少可落库标识", {
1084
+ count: draftOrders.length
1085
+ });
1086
+ return;
1087
+ }
1088
+ this.logInfo("upsertLocalDraftOrders-开始", {
1089
+ count: draftMap.size,
1090
+ memoryDraftCount: memoryDraftMap.size,
1091
+ sqliteOnlyDraftCount: draftMap.size - memoryDraftMap.size
1092
+ });
1093
+ const mergeActions = {};
1094
+ const updatedList = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
1095
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
1096
+ for (let index = 0; index < updatedList.length; index += 1) {
1097
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
1098
+ if (!identityKeyToIndex.has(key))
1099
+ identityKeyToIndex.set(key, index);
1100
+ }
1101
+ }
1102
+ for (const [storageKey, draftOrder] of memoryDraftMap.entries()) {
1103
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(
1104
+ identityKeyToIndex,
1105
+ this.getOrderIdentityMatchKeys(draftOrder)
1106
+ );
1107
+ if (matchIndex >= 0) {
1108
+ const existingOrder = updatedList[matchIndex];
1109
+ const reconciledDraftOrder = this.preserveExistingBusinessCodeForDraft(
1110
+ existingOrder,
1111
+ draftOrder
1112
+ );
1113
+ const mergedOrder = this.mergeOrderRecords(existingOrder, reconciledDraftOrder);
1114
+ const nextOrder = {
1115
+ ...mergedOrder,
1116
+ need_sync: 0,
1117
+ is_draft_order: 1
1118
+ };
1119
+ updatedList[matchIndex] = nextOrder;
1120
+ draftMap.set(storageKey, reconciledDraftOrder);
1121
+ this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
1122
+ mergeActions[storageKey] = "update";
1123
+ continue;
1124
+ }
1125
+ const insertIndex = updatedList.length;
1126
+ updatedList.push(draftOrder);
1127
+ this.registerOrderIdentityKeys(identityKeyToIndex, draftOrder, insertIndex);
1128
+ mergeActions[storageKey] = "insert";
1129
+ }
1130
+ const patchedOrders = [...draftMap.values()];
1131
+ const previousList = this.store.list;
1132
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertLocalDraftOrders.store");
1133
+ this.syncOrdersMap();
1134
+ try {
1135
+ await this.patchOrdersInSQLite(
1136
+ patchedOrders,
1137
+ "upsertLocalDraftOrders",
1138
+ mergeActions,
1139
+ { throwOnError: true }
1140
+ );
1141
+ } catch (error) {
1142
+ this.store.list = previousList;
1143
+ this.syncOrdersMap();
1144
+ throw error;
1145
+ }
1146
+ this.logInfo("upsertLocalDraftOrders-结束", {
1147
+ count: patchedOrders.length,
1148
+ storeOrderCountAfter: this.store.list.length
1149
+ });
1150
+ const removedLegacyMemoryDraft = previousList.some(
1151
+ (order) => !this.shouldKeepOrderInMemory(order)
1152
+ );
1153
+ if (memoryDraftMap.size > 0 || removedLegacyMemoryDraft) {
1154
+ await this.emitOrdersChanged(
1155
+ patchedOrders.filter((order) => this.shouldKeepOrderInMemory(order)),
1156
+ "upsertLocalDraftOrders"
1157
+ );
1158
+ }
1159
+ }
775
1160
  /**
776
1161
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
777
1162
  */
@@ -804,6 +1189,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
804
1189
  super.destroy();
805
1190
  }
806
1191
  syncOrdersMap() {
1192
+ this.store.list = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
807
1193
  this.store.map.clear();
808
1194
  for (const order of this.store.list) {
809
1195
  const primaryIdentity = this.getOrderMapKey(order);
@@ -827,6 +1213,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
827
1213
  isBlankIdentityValue(value) {
828
1214
  return value === void 0 || value === null || value === "";
829
1215
  }
1216
+ /**
1217
+ * `/sales/draft` 的旧调用方可能把未设置的 business_code 传成空串。
1218
+ * 对同一真实订单,空值不能覆盖已有的分类,否则 booking 查询会把该订单从 Party 列表过滤掉。
1219
+ */
1220
+ preserveExistingBusinessCodeForDraft(existingOrder, draftOrder) {
1221
+ const existingBusinessCode = existingOrder.business_code;
1222
+ const draftBusinessCode = draftOrder.business_code;
1223
+ const hasExistingBusinessCode = typeof existingBusinessCode === "string" && existingBusinessCode.trim() !== "";
1224
+ const hasDraftBusinessCode = typeof draftBusinessCode === "string" && draftBusinessCode.trim() !== "";
1225
+ if (!hasExistingBusinessCode || hasDraftBusinessCode)
1226
+ return draftOrder;
1227
+ return {
1228
+ ...draftOrder,
1229
+ business_code: existingBusinessCode
1230
+ };
1231
+ }
830
1232
  getOrderIdentityEntries(order) {
831
1233
  if (!order)
832
1234
  return [];
@@ -1126,9 +1528,43 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1126
1528
  });
1127
1529
  continue;
1128
1530
  }
1129
- const mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1130
- updatedList[matchIndex] = mergedOrder;
1131
- this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
1531
+ if (this.isDraftOrder(existingOrder) && this.shouldProtectDraftOrderFromIncoming(source)) {
1532
+ this.logInfo("mergeOrdersToStore-跳过 draft 订单远端覆盖", {
1533
+ source,
1534
+ order_id: existingOrder.order_id ?? fresh.order_id ?? null,
1535
+ external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
1536
+ local_is_draft_order: existingOrder.is_draft_order ?? null,
1537
+ remote_is_draft_order: fresh.is_draft_order ?? null,
1538
+ reason: "protect_draft_order_from_remote_echo"
1539
+ });
1540
+ continue;
1541
+ }
1542
+ let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1543
+ let adjustedMatchIndex = matchIndex;
1544
+ const duplicateIndexes = /* @__PURE__ */ new Set();
1545
+ for (const key of freshIdentityKeys) {
1546
+ const duplicateIndex = identityKeyToIndex.get(key);
1547
+ if (duplicateIndex === void 0 || duplicateIndex === matchIndex)
1548
+ continue;
1549
+ duplicateIndexes.add(duplicateIndex);
1550
+ }
1551
+ if (duplicateIndexes.size > 0) {
1552
+ for (const duplicateIndex of [...duplicateIndexes].sort((left, right) => right - left)) {
1553
+ mergedOrder = this.mergeOrderRecords(mergedOrder, updatedList[duplicateIndex]);
1554
+ updatedList.splice(duplicateIndex, 1);
1555
+ if (duplicateIndex < adjustedMatchIndex)
1556
+ adjustedMatchIndex -= 1;
1557
+ }
1558
+ identityKeyToIndex.clear();
1559
+ for (let index = 0; index < updatedList.length; index += 1) {
1560
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
1561
+ if (!identityKeyToIndex.has(key))
1562
+ identityKeyToIndex.set(key, index);
1563
+ }
1564
+ }
1565
+ }
1566
+ updatedList[adjustedMatchIndex] = mergedOrder;
1567
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
1132
1568
  patchedOrders.push(mergedOrder);
1133
1569
  if (mergeKey)
1134
1570
  mergeActions[mergeKey] = "update";
@@ -1320,6 +1756,72 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1320
1756
  return right;
1321
1757
  return left;
1322
1758
  }
1759
+ getProductIdentityKeys(product) {
1760
+ var _a;
1761
+ const record = product;
1762
+ if (!record)
1763
+ return [];
1764
+ const keys = [];
1765
+ const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
1766
+ if (!this.isBlankIdentityValue(metadataUid))
1767
+ keys.push(`uid:${String(metadataUid)}`);
1768
+ const topLevelUid = record.unique_identification_number;
1769
+ if (!this.isBlankIdentityValue(topLevelUid))
1770
+ keys.push(`uid:${String(topLevelUid)}`);
1771
+ const orderDetailId = record.order_detail_id;
1772
+ if (!this.isBlankIdentityValue(orderDetailId))
1773
+ keys.push(`detail:${String(orderDetailId)}`);
1774
+ const bookingUid = record.booking_uid;
1775
+ if (!this.isBlankIdentityValue(bookingUid))
1776
+ keys.push(`booking:${String(bookingUid)}`);
1777
+ return keys;
1778
+ }
1779
+ mergeOrderProductLists(preferred, secondary) {
1780
+ const preferredList = Array.isArray(preferred) ? preferred : [];
1781
+ const secondaryList = Array.isArray(secondary) ? secondary : [];
1782
+ if (secondaryList.length === 0)
1783
+ return preferredList;
1784
+ if (preferredList.length === 0)
1785
+ return secondaryList;
1786
+ const seenKeys = /* @__PURE__ */ new Set();
1787
+ for (const item of preferredList) {
1788
+ const keys = this.getProductIdentityKeys(item);
1789
+ for (const key of keys)
1790
+ seenKeys.add(key);
1791
+ }
1792
+ const result = [...preferredList];
1793
+ for (const item of secondaryList) {
1794
+ const keys = this.getProductIdentityKeys(item);
1795
+ if (keys.length === 0 || keys.some((key) => seenKeys.has(key)))
1796
+ continue;
1797
+ for (const key of keys)
1798
+ seenKeys.add(key);
1799
+ result.push((0, import_lodash_es.cloneDeep)(item));
1800
+ }
1801
+ return result;
1802
+ }
1803
+ mergeOrderPaymentLists(existing, incoming) {
1804
+ const existingList = Array.isArray(existing) ? existing : [];
1805
+ const incomingList = Array.isArray(incoming) ? incoming : [];
1806
+ if (incomingList.length === 0)
1807
+ return (0, import_lodash_es.cloneDeep)(existingList);
1808
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
1809
+ }
1810
+ getIdentifiedPendingPayments(order) {
1811
+ const payments = Array.isArray(order == null ? void 0 : order.payments) ? order.payments : [];
1812
+ return payments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment));
1813
+ }
1814
+ shouldProtectLocalOrderFromRemoteSnapshot(order) {
1815
+ return this.isPendingSyncOrder(order) || this.isDraftOrder(order) || this.getIdentifiedPendingPayments(order).length > 0;
1816
+ }
1817
+ getUnmatchedIdentifiedPendingPayments(existing, incoming) {
1818
+ const existingPayments = Array.isArray(existing) ? existing : [];
1819
+ const incomingPayments = Array.isArray(incoming) ? incoming : [];
1820
+ const incomingIdentityKeys = new Set(
1821
+ incomingPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1822
+ );
1823
+ return existingPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => incomingIdentityKeys.has(key)));
1824
+ }
1323
1825
  mergeOrderRecords(existing, incoming) {
1324
1826
  const preferred = this.pickPreferredOrder(existing, incoming);
1325
1827
  const secondary = preferred === existing ? incoming : existing;
@@ -1349,7 +1851,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1349
1851
  "contacts_info",
1350
1852
  "phone",
1351
1853
  "email",
1352
- "relation_forms"
1854
+ "relation_forms",
1855
+ "is_draft_order"
1353
1856
  ];
1354
1857
  const mergedRecord = merged;
1355
1858
  const preferredRecord = preferred;
@@ -1377,11 +1880,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1377
1880
  }
1378
1881
  for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
1379
1882
  if (Array.isArray(incomingRecord[field])) {
1883
+ if (field === "payments") {
1884
+ const preservedPending = this.getUnmatchedIdentifiedPendingPayments(
1885
+ existingRecord[field],
1886
+ incomingRecord[field]
1887
+ );
1888
+ if (preservedPending.length > 0) {
1889
+ this.logInfo("mergeOrderRecords-保留本地 pending 支付项", {
1890
+ order_id: existing.order_id ?? incoming.order_id ?? null,
1891
+ external_sale_number: existingRecord.external_sale_number ?? incomingRecord.external_sale_number ?? null,
1892
+ preserved_pending_count: preservedPending.length,
1893
+ preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1894
+ });
1895
+ }
1896
+ }
1380
1897
  mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
1381
1898
  field,
1382
1899
  existingRecord[field],
1383
1900
  incomingRecord[field],
1384
- childUidRemaps
1901
+ childUidRemaps,
1902
+ { preserveIdentifiedPendingPayments: field === "payments" }
1385
1903
  );
1386
1904
  continue;
1387
1905
  }
@@ -1416,7 +1934,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1416
1934
  external_sale_number: order.external_sale_number ?? null,
1417
1935
  shop_order_number: order.shop_order_number ?? null,
1418
1936
  shop_full_order_number: order.shop_full_order_number ?? null,
1419
- need_sync: order.need_sync ?? null
1937
+ need_sync: order.need_sync ?? null,
1938
+ is_draft_order: order.is_draft_order ?? null
1420
1939
  }))
1421
1940
  }));
1422
1941
  }
@@ -1533,18 +2052,48 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1533
2052
  isPendingSyncOrder(order) {
1534
2053
  return Number(order == null ? void 0 : order.need_sync) === 1;
1535
2054
  }
2055
+ isDraftOrder(order) {
2056
+ return Number(order == null ? void 0 : order.is_draft_order) === 1;
2057
+ }
2058
+ shouldProtectDraftOrderFromIncoming(source) {
2059
+ return source !== "checkoutSync";
2060
+ }
1536
2061
  normalizeRemoteSyncedOrder(order) {
1537
2062
  const normalizedOrder = this.normalizeOrderCollectionsForIngress(
1538
2063
  order,
1539
2064
  "normalizeRemoteSyncedOrder"
1540
2065
  );
1541
2066
  if (this.isPendingSyncOrder(normalizedOrder))
1542
- return normalizedOrder;
2067
+ return {
2068
+ ...normalizedOrder,
2069
+ is_draft_order: 0
2070
+ };
1543
2071
  return {
1544
2072
  ...normalizedOrder,
1545
- need_sync: 0
2073
+ need_sync: 0,
2074
+ is_draft_order: 0
1546
2075
  };
1547
2076
  }
2077
+ mergeRemoteIdentityIntoDraftOrder(draftOrder, remoteOrder) {
2078
+ const merged = {
2079
+ ...this.withoutSyntheticDraftOrderId(draftOrder)
2080
+ };
2081
+ const remote = remoteOrder;
2082
+ for (const field of [
2083
+ "order_id",
2084
+ "order_number",
2085
+ "shop_order_number",
2086
+ "shop_full_order_number"
2087
+ ]) {
2088
+ if (this.isBlankIdentityValue(merged[field]) && !this.isBlankIdentityValue(remote[field])) {
2089
+ merged[field] = remote[field];
2090
+ }
2091
+ }
2092
+ return this.normalizeOrderCollectionsForIngress(
2093
+ merged,
2094
+ "mergeRemoteIdentityIntoDraftOrder"
2095
+ );
2096
+ }
1548
2097
  mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
1549
2098
  const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
1550
2099
  for (const rawOrder of existingOrders) {
@@ -1552,11 +2101,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1552
2101
  rawOrder,
1553
2102
  "mergeRemoteSnapshotWithPendingOrders.existingSQLite"
1554
2103
  );
1555
- if (!this.isPendingSyncOrder(order))
2104
+ if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order))
1556
2105
  continue;
1557
2106
  const matchIndex = this.findOrderIndexByIdentity(merged, order);
1558
2107
  if (matchIndex >= 0) {
1559
- merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
2108
+ if (this.isDraftOrder(order)) {
2109
+ merged[matchIndex] = this.mergeRemoteIdentityIntoDraftOrder(
2110
+ order,
2111
+ merged[matchIndex]
2112
+ );
2113
+ } else {
2114
+ merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
2115
+ }
1560
2116
  continue;
1561
2117
  }
1562
2118
  if (!this.getOrderStorageKey(order))
@@ -1584,8 +2140,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1584
2140
  * @example
1585
2141
  * await this.patchOrdersInSQLite(freshOrders)
1586
2142
  */
1587
- async patchOrdersInSQLite(orders, source, mergeActions = {}) {
1588
- if (!this.dbManager || orders.length === 0) {
2143
+ async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}) {
2144
+ if (orders.length === 0) {
2145
+ return;
2146
+ }
2147
+ if (!this.dbManager) {
2148
+ if (options.throwOnError)
2149
+ throw new Error("订单 SQLite 数据库未初始化");
1589
2150
  return;
1590
2151
  }
1591
2152
  const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
@@ -1623,6 +2184,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1623
2184
  for (const order of compactedToWrite) {
1624
2185
  await this.dbManager.update(INDEXDB_STORE_NAME, order);
1625
2186
  }
2187
+ } else if (options.throwOnError) {
2188
+ throw new Error("订单 SQLite 数据库不支持写入");
1626
2189
  }
1627
2190
  this.recordRecentSqliteWrite(source, compactedToWrite);
1628
2191
  this.logInfo("patchOrdersInSQLite-完成", {
@@ -1637,6 +2200,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1637
2200
  error: error instanceof Error ? error.message : String(error),
1638
2201
  orderCount: ordersSnapshot.length
1639
2202
  });
2203
+ if (options.throwOnError)
2204
+ throw error;
1640
2205
  }
1641
2206
  }
1642
2207
  /**
@@ -1645,8 +2210,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1645
2210
  * @example
1646
2211
  * await this.updateOrderInSQLite(freshOrder)
1647
2212
  */
1648
- async updateOrderInSQLite(order, source) {
1649
- if (!this.dbManager || !this.getOrderStorageKey(order)) {
2213
+ async updateOrderInSQLite(order, source, options = {}) {
2214
+ if (!this.getOrderStorageKey(order)) {
2215
+ if (options.throwOnError)
2216
+ throw new Error("订单缺少可用的 SQLite 存储主键");
2217
+ return;
2218
+ }
2219
+ if (!this.dbManager) {
2220
+ if (options.throwOnError)
2221
+ throw new Error("订单 SQLite 数据库未初始化");
1650
2222
  return;
1651
2223
  }
1652
2224
  const orderSnapshot = this.normalizeOrderCollectionsForIngress(
@@ -1670,6 +2242,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1670
2242
  } else if (typeof this.dbManager.bulkAdd === "function") {
1671
2243
  writeMethod = "bulkAdd";
1672
2244
  await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
2245
+ } else if (options.throwOnError) {
2246
+ throw new Error("订单 SQLite 数据库不支持写入");
1673
2247
  }
1674
2248
  this.recordRecentSqliteWrite(source, [orderSnapshot]);
1675
2249
  this.logInfo("updateOrderInSQLite-完成", {
@@ -1683,15 +2257,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1683
2257
  error: error instanceof Error ? error.message : String(error),
1684
2258
  orderId: orderSnapshot.order_id ?? null
1685
2259
  });
2260
+ if (options.throwOnError)
2261
+ throw error;
1686
2262
  }
1687
2263
  }
1688
2264
  /**
1689
- * 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
2265
+ * 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
2266
+ * 用于 SSE 全量拉取与营业日窗口裁剪。
1690
2267
  *
1691
2268
  * @example
1692
2269
  * await this.replaceOrdersSnapshotInSQLite(orderList)
1693
2270
  */
1694
- async replaceOrdersSnapshotInSQLite(orderList, source) {
2271
+ async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
1695
2272
  if (!this.dbManager) {
1696
2273
  return this.compactOrderListByIdentity(
1697
2274
  orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
@@ -1708,16 +2285,52 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1708
2285
  try {
1709
2286
  await this.runInOrderSQLiteSaveQueue(async () => {
1710
2287
  const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
2288
+ const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map((order) => this.normalizeOrderCollectionsForIngress(
2289
+ order,
2290
+ `${source}.protectedBeforeRemoteFetch`
2291
+ )).filter((order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
2292
+ for (const rawCurrentOrder of existingOrders || []) {
2293
+ const currentOrder = this.normalizeOrderCollectionsForIngress(
2294
+ rawCurrentOrder,
2295
+ `${source}.currentSQLite`
2296
+ );
2297
+ const protectedIndex = this.findOrderIndexByIdentity(
2298
+ protectedLocalOrders,
2299
+ currentOrder
2300
+ );
2301
+ const currentNeedsProtection = this.shouldProtectLocalOrderFromRemoteSnapshot(currentOrder);
2302
+ if (protectedIndex >= 0) {
2303
+ if (currentNeedsProtection) {
2304
+ protectedLocalOrders[protectedIndex] = currentOrder;
2305
+ } else {
2306
+ protectedLocalOrders.splice(protectedIndex, 1);
2307
+ }
2308
+ continue;
2309
+ }
2310
+ if (currentNeedsProtection)
2311
+ protectedLocalOrders.push(currentOrder);
2312
+ }
1711
2313
  const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
1712
2314
  remoteSnapshot,
1713
- existingOrders || []
2315
+ protectedLocalOrders
1714
2316
  );
1715
2317
  mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
1716
2318
  this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
1717
2319
  source,
1718
2320
  count: mergedSnapshot.length,
1719
2321
  remoteCount: remoteSnapshot.length,
1720
- preservedPendingCount: mergedSnapshot.length - remoteSnapshot.length
2322
+ protectedBeforeRemoteFetchCount: protectedOrdersBeforeRemoteFetch.length,
2323
+ protectedLocalOrderCount: protectedLocalOrders.length,
2324
+ preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length,
2325
+ protectedPendingPaymentCount: protectedLocalOrders.reduce(
2326
+ (count, order) => count + this.getIdentifiedPendingPayments(order).length,
2327
+ 0
2328
+ ),
2329
+ protectedPendingPaymentIdentities: protectedLocalOrders.flatMap((order) => this.getIdentifiedPendingPayments(order).map((payment) => ({
2330
+ order_id: order.order_id ?? null,
2331
+ external_sale_number: order.external_sale_number ?? null,
2332
+ payment_identities: (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment)
2333
+ })))
1721
2334
  });
1722
2335
  await this.dbManager.clear(INDEXDB_STORE_NAME);
1723
2336
  this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {