@pisell/pisellos 2.3.29 → 2.3.30

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 (98) hide show
  1. package/dist/model/strategy/adapter/index.d.ts +0 -4
  2. package/dist/model/strategy/adapter/index.js +1 -5
  3. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  4. package/dist/modules/Discount/index.d.ts +2 -5
  5. package/dist/modules/Discount/index.js +7 -30
  6. package/dist/modules/Discount/types.d.ts +0 -4
  7. package/dist/modules/Order/index.d.ts +28 -10
  8. package/dist/modules/Order/index.js +747 -498
  9. package/dist/modules/Order/payment-utils.d.ts +23 -0
  10. package/dist/modules/Order/payment-utils.js +203 -0
  11. package/dist/modules/Order/types.d.ts +33 -3
  12. package/dist/modules/Order/utils.js +4 -4
  13. package/dist/modules/Payment/index.d.ts +2 -0
  14. package/dist/modules/Payment/index.js +78 -49
  15. package/dist/modules/Payment/types.d.ts +26 -24
  16. package/dist/modules/Payment/types.js +2 -0
  17. package/dist/modules/Product/index.d.ts +1 -1
  18. package/dist/modules/Product/types.d.ts +0 -22
  19. package/dist/modules/ProductList/index.d.ts +1 -1
  20. package/dist/modules/ProductList/index.js +2 -4
  21. package/dist/modules/ProductList/types.d.ts +0 -2
  22. package/dist/server/index.d.ts +14 -50
  23. package/dist/server/index.js +1975 -1395
  24. package/dist/server/modules/order/index.d.ts +40 -3
  25. package/dist/server/modules/order/index.js +1200 -501
  26. package/dist/server/modules/order/types.d.ts +11 -3
  27. package/dist/server/modules/order/types.js +1 -1
  28. package/dist/server/modules/products/index.d.ts +7 -26
  29. package/dist/server/modules/products/index.js +76 -167
  30. package/dist/server/modules/products/types.d.ts +0 -14
  31. package/dist/solution/BaseSales/index.d.ts +33 -5
  32. package/dist/solution/BaseSales/index.js +622 -345
  33. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  34. package/dist/solution/BookingByStep/index.d.ts +1 -1
  35. package/dist/solution/BookingTicket/index.d.ts +1 -1
  36. package/dist/solution/BookingTicket/index.js +2 -1
  37. package/dist/solution/BookingTicket/types.d.ts +0 -2
  38. package/dist/solution/ShopDiscount/index.js +14 -15
  39. package/dist/utils/payment-number.d.ts +9 -0
  40. package/dist/utils/payment-number.js +69 -0
  41. package/lib/model/strategy/adapter/index.d.ts +0 -4
  42. package/lib/model/strategy/adapter/index.js +2 -13
  43. package/lib/modules/Discount/index.d.ts +2 -5
  44. package/lib/modules/Discount/index.js +3 -23
  45. package/lib/modules/Discount/types.d.ts +0 -4
  46. package/lib/modules/Order/index.d.ts +28 -10
  47. package/lib/modules/Order/index.js +181 -73
  48. package/lib/modules/Order/payment-utils.d.ts +23 -0
  49. package/lib/modules/Order/payment-utils.js +193 -0
  50. package/lib/modules/Order/types.d.ts +33 -3
  51. package/lib/modules/Order/utils.js +2 -3
  52. package/lib/modules/Payment/index.d.ts +2 -0
  53. package/lib/modules/Payment/index.js +33 -12
  54. package/lib/modules/Payment/types.d.ts +26 -24
  55. package/lib/modules/Product/index.d.ts +1 -1
  56. package/lib/modules/Product/types.d.ts +0 -22
  57. package/lib/modules/ProductList/index.d.ts +1 -1
  58. package/lib/modules/ProductList/index.js +2 -4
  59. package/lib/modules/ProductList/types.d.ts +0 -2
  60. package/lib/server/index.d.ts +14 -50
  61. package/lib/server/index.js +633 -214
  62. package/lib/server/modules/order/index.d.ts +40 -3
  63. package/lib/server/modules/order/index.js +434 -31
  64. package/lib/server/modules/order/types.d.ts +11 -3
  65. package/lib/server/modules/products/index.d.ts +7 -26
  66. package/lib/server/modules/products/index.js +35 -114
  67. package/lib/server/modules/products/types.d.ts +0 -14
  68. package/lib/solution/BaseSales/index.d.ts +33 -5
  69. package/lib/solution/BaseSales/index.js +170 -19
  70. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  71. package/lib/solution/BookingByStep/index.d.ts +1 -1
  72. package/lib/solution/BookingTicket/index.d.ts +1 -1
  73. package/lib/solution/BookingTicket/index.js +2 -1
  74. package/lib/solution/BookingTicket/types.d.ts +0 -2
  75. package/lib/solution/ShopDiscount/index.js +1 -2
  76. package/lib/utils/payment-number.d.ts +9 -0
  77. package/lib/utils/payment-number.js +64 -0
  78. package/package.json +1 -1
  79. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
  80. package/dist/model/strategy/adapter/dataVariant/adapter.js +0 -167
  81. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
  82. package/dist/model/strategy/adapter/dataVariant/evaluator.js +0 -780
  83. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  84. package/dist/model/strategy/adapter/dataVariant/examples.js +0 -277
  85. package/dist/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  86. package/dist/model/strategy/adapter/dataVariant/index.js +0 -4
  87. package/dist/model/strategy/adapter/dataVariant/type.d.ts +0 -148
  88. package/dist/model/strategy/adapter/dataVariant/type.js +0 -54
  89. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
  90. package/lib/model/strategy/adapter/dataVariant/adapter.js +0 -149
  91. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
  92. package/lib/model/strategy/adapter/dataVariant/evaluator.js +0 -583
  93. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  94. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -293
  95. package/lib/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  96. package/lib/model/strategy/adapter/dataVariant/index.js +0 -38
  97. package/lib/model/strategy/adapter/dataVariant/type.d.ts +0 -148
  98. package/lib/model/strategy/adapter/dataVariant/type.js +0 -31
@@ -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,8 +47,10 @@ 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;
53
56
  var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
@@ -482,6 +485,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
482
485
  getOrderByOrderId(orderId) {
483
486
  return this.store.map.get(this.getIdKey(orderId));
484
487
  }
488
+ buildLocalPaymentOrderLogContext(order) {
489
+ if (!order)
490
+ return {};
491
+ return {
492
+ order_id: order.order_id ?? null,
493
+ external_sale_number: order.external_sale_number ?? null,
494
+ order_number: order.order_number ?? null,
495
+ shop_order_number: order.shop_order_number ?? null,
496
+ shop_full_order_number: order.shop_full_order_number ?? null,
497
+ order_status: order.status ?? null,
498
+ payment_status: order.payment_status ?? null,
499
+ is_draft_order: Number(order.is_draft_order || 0),
500
+ need_sync: Number(order.need_sync || 0),
501
+ platform: order.platform ?? null,
502
+ business_code: order.business_code ?? null,
503
+ order_sales_channel: order.order_sales_channel ?? null,
504
+ sales_channel: order.sales_channel ?? null,
505
+ order_type: order.type ?? null,
506
+ payments_count: Array.isArray(order.payments) ? order.payments.length : 0
507
+ };
508
+ }
485
509
  getLocalOrderFromMemoryByLookup(lookup) {
486
510
  const key = this.getIdKey(lookup);
487
511
  const memoryOrderById = this.store.map.get(key);
@@ -490,21 +514,176 @@ var OrderModule = class extends import_BaseModule.BaseModule {
490
514
  const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
491
515
  return memoryOrder || null;
492
516
  }
493
- async getLocalOrderByLookup(lookup) {
517
+ async getLocalOrderByLookup(lookup, options = {}) {
494
518
  const key = this.getIdKey(lookup);
519
+ const logContext = {
520
+ operation_id: options.operationId,
521
+ lookup: key,
522
+ memory_order_count: this.store.list.length
523
+ };
524
+ if (options.operationId) {
525
+ this.logInfo("getLocalOrderByLookup-localPayment-开始", logContext);
526
+ }
495
527
  const memoryOrderById = this.store.map.get(key);
496
- if (memoryOrderById)
528
+ if (memoryOrderById) {
529
+ if (options.operationId) {
530
+ this.logInfo("getLocalOrderByLookup-localPayment-命中内存映射", {
531
+ ...logContext,
532
+ ...this.buildLocalPaymentOrderLogContext(memoryOrderById)
533
+ });
534
+ }
497
535
  return memoryOrderById;
536
+ }
498
537
  const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
499
- if (memoryOrder)
538
+ if (memoryOrder) {
539
+ if (options.operationId) {
540
+ this.logInfo("getLocalOrderByLookup-localPayment-命中内存列表", {
541
+ ...logContext,
542
+ ...this.buildLocalPaymentOrderLogContext(memoryOrder)
543
+ });
544
+ }
500
545
  return memoryOrder;
546
+ }
547
+ if (options.operationId) {
548
+ this.logInfo("getLocalOrderByLookup-localPayment-开始读取SQLite", logContext);
549
+ }
501
550
  const orders = await this.loadOrdersFromSQLite();
502
551
  const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
503
- if (!localOrder)
552
+ if (!localOrder) {
553
+ if (options.operationId) {
554
+ this.logWarning("getLocalOrderByLookup-localPayment-SQLite未命中", {
555
+ ...logContext,
556
+ sqlite_order_count: orders.length
557
+ });
558
+ }
504
559
  return null;
560
+ }
505
561
  this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
506
562
  this.syncOrdersMap();
507
- return this.normalizeOrderForMemoryList(localOrder);
563
+ const normalizedOrder = this.normalizeOrderForMemoryList(localOrder);
564
+ if (options.operationId) {
565
+ this.logInfo("getLocalOrderByLookup-localPayment-SQLite命中", {
566
+ ...logContext,
567
+ sqlite_order_count: orders.length,
568
+ ...this.buildLocalPaymentOrderLogContext(normalizedOrder)
569
+ });
570
+ }
571
+ return normalizedOrder;
572
+ }
573
+ async getLocalPayment(params) {
574
+ const logContext = {
575
+ operation_id: params.operationId,
576
+ sale_id: params.saleId,
577
+ payment_number: params.paymentNumber
578
+ };
579
+ this.logInfo("getLocalPayment-开始", logContext);
580
+ try {
581
+ const order = await this.getLocalOrderByLookup(params.saleId, {
582
+ operationId: params.operationId
583
+ });
584
+ if (!order) {
585
+ this.logWarning("getLocalPayment-订单未命中", logContext);
586
+ return null;
587
+ }
588
+ const payments = order.payments || [];
589
+ const match = (0, import_payment_utils.resolveOrderPaymentIdentity)(
590
+ payments,
591
+ params.paymentNumber,
592
+ "compat"
593
+ );
594
+ if (!match) {
595
+ this.logWarning("getLocalPayment-支付项未命中", {
596
+ ...logContext,
597
+ ...this.buildLocalPaymentOrderLogContext(order),
598
+ payments
599
+ });
600
+ return null;
601
+ }
602
+ this.logInfo("getLocalPayment-支付项命中", {
603
+ ...logContext,
604
+ ...this.buildLocalPaymentOrderLogContext(order),
605
+ matched_by: match.matchedBy,
606
+ payment_index: match.index,
607
+ payment: match.payment
608
+ });
609
+ return {
610
+ order,
611
+ payment: match.payment,
612
+ paymentIndex: match.index,
613
+ matchedBy: match.matchedBy
614
+ };
615
+ } catch (error) {
616
+ this.logError("getLocalPayment-查询失败", {
617
+ ...logContext,
618
+ error: error instanceof Error ? error.message : String(error)
619
+ });
620
+ throw error;
621
+ }
622
+ }
623
+ async updateLocalPayment(params) {
624
+ const logContext = {
625
+ operation_id: params.operationId,
626
+ sale_id: params.saleId,
627
+ payment_number: params.paymentNumber,
628
+ incoming_payment_update: params.updates
629
+ };
630
+ this.logInfo("updateLocalPayment-开始", logContext);
631
+ const found = await this.getLocalPayment(params);
632
+ if (!found) {
633
+ this.logWarning("updateLocalPayment-支付项未命中", logContext);
634
+ return null;
635
+ }
636
+ const previousPayment = (0, import_lodash_es.cloneDeep)(found.payment);
637
+ const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(found.payment, {
638
+ ...params.updates,
639
+ updated_at: params.updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
640
+ });
641
+ const nextOrder = {
642
+ ...found.order,
643
+ payments: (found.order.payments || []).map((payment, index) => index === found.paymentIndex ? nextPayment : payment),
644
+ updated_at: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
645
+ };
646
+ const paymentContext = {
647
+ ...logContext,
648
+ matched_by: found.matchedBy,
649
+ payment_index: found.paymentIndex,
650
+ ...this.buildLocalPaymentOrderLogContext(nextOrder),
651
+ previous_payment: previousPayment,
652
+ payment: nextPayment
653
+ };
654
+ this.logInfo("updateLocalPayment-支付项合并完成", paymentContext);
655
+ const targetIndex = this.findOrderIndexByIdentity(this.store.list, found.order);
656
+ if (targetIndex < 0) {
657
+ this.logError("updateLocalPayment-订单Store索引未命中", paymentContext);
658
+ return null;
659
+ }
660
+ const previousList = this.store.list;
661
+ this.store.list = this.store.list.map((order, index) => index === targetIndex ? nextOrder : order);
662
+ this.syncOrdersMap();
663
+ const storageOrder = this.withoutSyntheticDraftOrderId(nextOrder);
664
+ try {
665
+ this.logInfo("updateLocalPayment-SQLite写入开始", {
666
+ ...paymentContext,
667
+ storage_order_id: storageOrder.order_id ?? null
668
+ });
669
+ await this.updateOrderInSQLite(storageOrder, "updateLocalPayment", { throwOnError: true });
670
+ this.logInfo("updateLocalPayment-SQLite写入完成", {
671
+ ...paymentContext,
672
+ storage_order_id: storageOrder.order_id ?? null
673
+ });
674
+ } catch (error) {
675
+ this.store.list = previousList;
676
+ this.syncOrdersMap();
677
+ this.logError("updateLocalPayment-SQLite写入失败并回滚内存", {
678
+ ...paymentContext,
679
+ storage_order_id: storageOrder.order_id ?? null,
680
+ error: error instanceof Error ? error.message : String(error)
681
+ });
682
+ throw error;
683
+ }
684
+ await this.emitOrdersChanged([nextOrder], "updateLocalPayment");
685
+ this.logInfo("updateLocalPayment-变更事件完成", paymentContext);
686
+ return { order: nextOrder, payment: nextPayment, previousPayment };
508
687
  }
509
688
  async loadOrdersByServer() {
510
689
  var _a;
@@ -590,6 +769,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
590
769
  order_id: externalSaleNumber
591
770
  };
592
771
  }
772
+ withoutSyntheticDraftOrderId(order) {
773
+ const externalSaleNumber = order.external_sale_number;
774
+ if (Number(order.is_draft_order || 0) !== 1 || order.order_id === void 0 || externalSaleNumber === void 0 || String(order.order_id) !== String(externalSaleNumber)) {
775
+ return order;
776
+ }
777
+ const next = { ...order };
778
+ delete next.order_id;
779
+ return next;
780
+ }
593
781
  /**
594
782
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
595
783
  * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
@@ -638,13 +826,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
638
826
  * 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
639
827
  * 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
640
828
  */
641
- async upsertOrdersFromRemote(freshOrders) {
829
+ async upsertOrdersFromRemote(freshOrders, source = "upsertOrdersFromRemote") {
642
830
  if (!(freshOrders == null ? void 0 : freshOrders.length)) {
643
831
  this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
644
832
  return;
645
833
  }
646
- this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
647
- await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
834
+ this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length, source });
835
+ await this.mergeOrdersToStore(freshOrders, source);
648
836
  }
649
837
  async markOrderSyncedByExternalSaleNumber(params) {
650
838
  const externalSaleNumber = params.externalSaleNumber;
@@ -670,7 +858,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
670
858
  ...existing,
671
859
  ...params.patch || {},
672
860
  external_sale_number: existing.external_sale_number ?? externalSaleNumber,
673
- need_sync: 0
861
+ need_sync: 0,
862
+ is_draft_order: 0
674
863
  });
675
864
  const storageKey = this.getOrderStorageKey(nextOrder) || key;
676
865
  this.store.list = this.store.list.map((order, index) => {
@@ -695,7 +884,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
695
884
  * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
696
885
  * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
697
886
  */
698
- async upsertPendingSyncOrders(pendingOrders) {
887
+ async upsertPendingSyncOrders(pendingOrders, options = {}) {
699
888
  if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
700
889
  this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
701
890
  return;
@@ -707,14 +896,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
707
896
  order,
708
897
  "upsertPendingSyncOrders.incoming"
709
898
  );
710
- const storageKey = this.getOrderStorageKey(normalizedOrder);
899
+ const pendingOrder = {
900
+ ...normalizedOrder,
901
+ need_sync: 1,
902
+ is_draft_order: 0
903
+ };
904
+ const storageKey = this.getOrderStorageKey(pendingOrder);
711
905
  if (!storageKey)
712
906
  continue;
713
- pendingMap.set(storageKey, normalizedOrder);
907
+ pendingMap.set(storageKey, pendingOrder);
714
908
  memoryPendingMap.set(
715
909
  storageKey,
716
910
  this.normalizeOrderForMemoryList(
717
- normalizedOrder,
911
+ pendingOrder,
718
912
  "upsertPendingSyncOrders.memory"
719
913
  )
720
914
  );
@@ -745,7 +939,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
745
939
  if (matchIndex >= 0) {
746
940
  const existingOrder = updatedList[matchIndex];
747
941
  const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
748
- updatedList[matchIndex] = mergedOrder;
942
+ const nextOrder = {
943
+ ...mergedOrder,
944
+ need_sync: 1,
945
+ is_draft_order: 0
946
+ };
947
+ updatedList[matchIndex] = nextOrder;
749
948
  const pendingSnapshot = pendingMap.get(storageKey);
750
949
  if (pendingSnapshot) {
751
950
  pendingMap.set(
@@ -753,7 +952,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
753
952
  this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
754
953
  );
755
954
  }
756
- this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
955
+ this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
757
956
  mergeActions[storageKey] = "update";
758
957
  continue;
759
958
  }
@@ -763,15 +962,98 @@ var OrderModule = class extends import_BaseModule.BaseModule {
763
962
  mergeActions[storageKey] = "insert";
764
963
  }
765
964
  const patchedOrders = [...pendingMap.values()];
965
+ const previousList = this.store.list;
766
966
  this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
767
967
  this.syncOrdersMap();
768
- await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
968
+ try {
969
+ await this.patchOrdersInSQLite(
970
+ patchedOrders,
971
+ "upsertPendingSyncOrders",
972
+ mergeActions,
973
+ options
974
+ );
975
+ } catch (error) {
976
+ this.store.list = previousList;
977
+ this.syncOrdersMap();
978
+ throw error;
979
+ }
769
980
  this.logInfo("upsertPendingSyncOrders-结束", {
770
981
  count: patchedOrders.length,
771
982
  storeOrderCountAfter: this.store.list.length
772
983
  });
773
984
  await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
774
985
  }
986
+ /**
987
+ * 将 POS 草稿订单按 SQLite storage key 合并进 store 并落库。
988
+ * 草稿只表示本地可恢复快照,不进入同步队列。
989
+ */
990
+ async upsertLocalDraftOrders(draftOrders) {
991
+ if (!(draftOrders == null ? void 0 : draftOrders.length)) {
992
+ this.logInfo("upsertLocalDraftOrders-订单列表为空", {});
993
+ return;
994
+ }
995
+ const draftMap = /* @__PURE__ */ new Map();
996
+ const memoryDraftMap = /* @__PURE__ */ new Map();
997
+ for (const order of draftOrders) {
998
+ const draftOrder = {
999
+ ...order,
1000
+ need_sync: 0,
1001
+ is_draft_order: 1
1002
+ };
1003
+ const storageKey = this.getOrderStorageKey(draftOrder);
1004
+ if (!storageKey)
1005
+ continue;
1006
+ draftMap.set(storageKey, draftOrder);
1007
+ memoryDraftMap.set(storageKey, this.normalizeOrderForMemoryList(draftOrder));
1008
+ }
1009
+ if (draftMap.size === 0) {
1010
+ this.logError("upsertLocalDraftOrders-订单缺少可落库标识", {
1011
+ count: draftOrders.length
1012
+ });
1013
+ return;
1014
+ }
1015
+ this.logInfo("upsertLocalDraftOrders-开始", { count: draftMap.size });
1016
+ const patchedOrders = [...draftMap.values()];
1017
+ const mergeActions = {};
1018
+ const updatedList = [...this.store.list];
1019
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
1020
+ for (let index = 0; index < updatedList.length; index += 1) {
1021
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
1022
+ if (!identityKeyToIndex.has(key))
1023
+ identityKeyToIndex.set(key, index);
1024
+ }
1025
+ }
1026
+ for (const [storageKey, draftOrder] of memoryDraftMap.entries()) {
1027
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(
1028
+ identityKeyToIndex,
1029
+ this.getOrderIdentityMatchKeys(draftOrder)
1030
+ );
1031
+ if (matchIndex >= 0) {
1032
+ const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], draftOrder);
1033
+ const nextOrder = {
1034
+ ...mergedOrder,
1035
+ need_sync: 0,
1036
+ is_draft_order: 1
1037
+ };
1038
+ updatedList[matchIndex] = nextOrder;
1039
+ this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
1040
+ mergeActions[storageKey] = "update";
1041
+ continue;
1042
+ }
1043
+ const insertIndex = updatedList.length;
1044
+ updatedList.push(draftOrder);
1045
+ this.registerOrderIdentityKeys(identityKeyToIndex, draftOrder, insertIndex);
1046
+ mergeActions[storageKey] = "insert";
1047
+ }
1048
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertLocalDraftOrders.store");
1049
+ this.syncOrdersMap();
1050
+ await this.patchOrdersInSQLite(patchedOrders, "upsertLocalDraftOrders", mergeActions);
1051
+ this.logInfo("upsertLocalDraftOrders-结束", {
1052
+ count: patchedOrders.length,
1053
+ storeOrderCountAfter: this.store.list.length
1054
+ });
1055
+ await this.emitOrdersChanged(patchedOrders, "upsertLocalDraftOrders");
1056
+ }
775
1057
  /**
776
1058
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
777
1059
  */
@@ -1126,9 +1408,43 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1126
1408
  });
1127
1409
  continue;
1128
1410
  }
1129
- const mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1130
- updatedList[matchIndex] = mergedOrder;
1131
- this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
1411
+ if (this.isDraftOrder(existingOrder) && this.shouldProtectDraftOrderFromIncoming(source)) {
1412
+ this.logInfo("mergeOrdersToStore-跳过 draft 订单远端覆盖", {
1413
+ source,
1414
+ order_id: existingOrder.order_id ?? fresh.order_id ?? null,
1415
+ external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
1416
+ local_is_draft_order: existingOrder.is_draft_order ?? null,
1417
+ remote_is_draft_order: fresh.is_draft_order ?? null,
1418
+ reason: "protect_draft_order_from_remote_echo"
1419
+ });
1420
+ continue;
1421
+ }
1422
+ let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1423
+ let adjustedMatchIndex = matchIndex;
1424
+ const duplicateIndexes = /* @__PURE__ */ new Set();
1425
+ for (const key of freshIdentityKeys) {
1426
+ const duplicateIndex = identityKeyToIndex.get(key);
1427
+ if (duplicateIndex === void 0 || duplicateIndex === matchIndex)
1428
+ continue;
1429
+ duplicateIndexes.add(duplicateIndex);
1430
+ }
1431
+ if (duplicateIndexes.size > 0) {
1432
+ for (const duplicateIndex of [...duplicateIndexes].sort((left, right) => right - left)) {
1433
+ mergedOrder = this.mergeOrderRecords(mergedOrder, updatedList[duplicateIndex]);
1434
+ updatedList.splice(duplicateIndex, 1);
1435
+ if (duplicateIndex < adjustedMatchIndex)
1436
+ adjustedMatchIndex -= 1;
1437
+ }
1438
+ identityKeyToIndex.clear();
1439
+ for (let index = 0; index < updatedList.length; index += 1) {
1440
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
1441
+ if (!identityKeyToIndex.has(key))
1442
+ identityKeyToIndex.set(key, index);
1443
+ }
1444
+ }
1445
+ }
1446
+ updatedList[adjustedMatchIndex] = mergedOrder;
1447
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
1132
1448
  patchedOrders.push(mergedOrder);
1133
1449
  if (mergeKey)
1134
1450
  mergeActions[mergeKey] = "update";
@@ -1320,6 +1636,57 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1320
1636
  return right;
1321
1637
  return left;
1322
1638
  }
1639
+ getProductIdentityKeys(product) {
1640
+ var _a;
1641
+ const record = product;
1642
+ if (!record)
1643
+ return [];
1644
+ const keys = [];
1645
+ const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
1646
+ if (!this.isBlankIdentityValue(metadataUid))
1647
+ keys.push(`uid:${String(metadataUid)}`);
1648
+ const topLevelUid = record.unique_identification_number;
1649
+ if (!this.isBlankIdentityValue(topLevelUid))
1650
+ keys.push(`uid:${String(topLevelUid)}`);
1651
+ const orderDetailId = record.order_detail_id;
1652
+ if (!this.isBlankIdentityValue(orderDetailId))
1653
+ keys.push(`detail:${String(orderDetailId)}`);
1654
+ const bookingUid = record.booking_uid;
1655
+ if (!this.isBlankIdentityValue(bookingUid))
1656
+ keys.push(`booking:${String(bookingUid)}`);
1657
+ return keys;
1658
+ }
1659
+ mergeOrderProductLists(preferred, secondary) {
1660
+ const preferredList = Array.isArray(preferred) ? preferred : [];
1661
+ const secondaryList = Array.isArray(secondary) ? secondary : [];
1662
+ if (secondaryList.length === 0)
1663
+ return preferredList;
1664
+ if (preferredList.length === 0)
1665
+ return secondaryList;
1666
+ const seenKeys = /* @__PURE__ */ new Set();
1667
+ for (const item of preferredList) {
1668
+ const keys = this.getProductIdentityKeys(item);
1669
+ for (const key of keys)
1670
+ seenKeys.add(key);
1671
+ }
1672
+ const result = [...preferredList];
1673
+ for (const item of secondaryList) {
1674
+ const keys = this.getProductIdentityKeys(item);
1675
+ if (keys.length === 0 || keys.some((key) => seenKeys.has(key)))
1676
+ continue;
1677
+ for (const key of keys)
1678
+ seenKeys.add(key);
1679
+ result.push((0, import_lodash_es.cloneDeep)(item));
1680
+ }
1681
+ return result;
1682
+ }
1683
+ mergeOrderPaymentLists(existing, incoming) {
1684
+ const existingList = Array.isArray(existing) ? existing : [];
1685
+ const incomingList = Array.isArray(incoming) ? incoming : [];
1686
+ if (incomingList.length === 0)
1687
+ return (0, import_lodash_es.cloneDeep)(existingList);
1688
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
1689
+ }
1323
1690
  mergeOrderRecords(existing, incoming) {
1324
1691
  const preferred = this.pickPreferredOrder(existing, incoming);
1325
1692
  const secondary = preferred === existing ? incoming : existing;
@@ -1349,7 +1716,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1349
1716
  "contacts_info",
1350
1717
  "phone",
1351
1718
  "email",
1352
- "relation_forms"
1719
+ "relation_forms",
1720
+ "is_draft_order"
1353
1721
  ];
1354
1722
  const mergedRecord = merged;
1355
1723
  const preferredRecord = preferred;
@@ -1416,7 +1784,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1416
1784
  external_sale_number: order.external_sale_number ?? null,
1417
1785
  shop_order_number: order.shop_order_number ?? null,
1418
1786
  shop_full_order_number: order.shop_full_order_number ?? null,
1419
- need_sync: order.need_sync ?? null
1787
+ need_sync: order.need_sync ?? null,
1788
+ is_draft_order: order.is_draft_order ?? null
1420
1789
  }))
1421
1790
  }));
1422
1791
  }
@@ -1533,16 +1902,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1533
1902
  isPendingSyncOrder(order) {
1534
1903
  return Number(order == null ? void 0 : order.need_sync) === 1;
1535
1904
  }
1905
+ isDraftOrder(order) {
1906
+ return Number(order == null ? void 0 : order.is_draft_order) === 1;
1907
+ }
1908
+ shouldProtectDraftOrderFromIncoming(source) {
1909
+ return source !== "checkoutSync";
1910
+ }
1536
1911
  normalizeRemoteSyncedOrder(order) {
1537
1912
  const normalizedOrder = this.normalizeOrderCollectionsForIngress(
1538
1913
  order,
1539
1914
  "normalizeRemoteSyncedOrder"
1540
1915
  );
1541
1916
  if (this.isPendingSyncOrder(normalizedOrder))
1542
- return normalizedOrder;
1917
+ return {
1918
+ ...normalizedOrder,
1919
+ is_draft_order: 0
1920
+ };
1543
1921
  return {
1544
1922
  ...normalizedOrder,
1545
- need_sync: 0
1923
+ need_sync: 0,
1924
+ is_draft_order: 0
1546
1925
  };
1547
1926
  }
1548
1927
  mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
@@ -1552,11 +1931,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1552
1931
  rawOrder,
1553
1932
  "mergeRemoteSnapshotWithPendingOrders.existingSQLite"
1554
1933
  );
1555
- if (!this.isPendingSyncOrder(order))
1934
+ if (!this.isPendingSyncOrder(order) && !this.isDraftOrder(order))
1556
1935
  continue;
1557
1936
  const matchIndex = this.findOrderIndexByIdentity(merged, order);
1558
1937
  if (matchIndex >= 0) {
1559
- merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
1938
+ if (this.isDraftOrder(order)) {
1939
+ merged[matchIndex] = order;
1940
+ } else {
1941
+ merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
1942
+ }
1560
1943
  continue;
1561
1944
  }
1562
1945
  if (!this.getOrderStorageKey(order))
@@ -1584,8 +1967,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1584
1967
  * @example
1585
1968
  * await this.patchOrdersInSQLite(freshOrders)
1586
1969
  */
1587
- async patchOrdersInSQLite(orders, source, mergeActions = {}) {
1588
- if (!this.dbManager || orders.length === 0) {
1970
+ async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}) {
1971
+ if (orders.length === 0) {
1972
+ return;
1973
+ }
1974
+ if (!this.dbManager) {
1975
+ if (options.throwOnError)
1976
+ throw new Error("订单 SQLite 数据库未初始化");
1589
1977
  return;
1590
1978
  }
1591
1979
  const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
@@ -1623,6 +2011,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1623
2011
  for (const order of compactedToWrite) {
1624
2012
  await this.dbManager.update(INDEXDB_STORE_NAME, order);
1625
2013
  }
2014
+ } else if (options.throwOnError) {
2015
+ throw new Error("订单 SQLite 数据库不支持写入");
1626
2016
  }
1627
2017
  this.recordRecentSqliteWrite(source, compactedToWrite);
1628
2018
  this.logInfo("patchOrdersInSQLite-完成", {
@@ -1637,6 +2027,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1637
2027
  error: error instanceof Error ? error.message : String(error),
1638
2028
  orderCount: ordersSnapshot.length
1639
2029
  });
2030
+ if (options.throwOnError)
2031
+ throw error;
1640
2032
  }
1641
2033
  }
1642
2034
  /**
@@ -1645,8 +2037,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1645
2037
  * @example
1646
2038
  * await this.updateOrderInSQLite(freshOrder)
1647
2039
  */
1648
- async updateOrderInSQLite(order, source) {
1649
- if (!this.dbManager || !this.getOrderStorageKey(order)) {
2040
+ async updateOrderInSQLite(order, source, options = {}) {
2041
+ if (!this.getOrderStorageKey(order)) {
2042
+ if (options.throwOnError)
2043
+ throw new Error("订单缺少可用的 SQLite 存储主键");
2044
+ return;
2045
+ }
2046
+ if (!this.dbManager) {
2047
+ if (options.throwOnError)
2048
+ throw new Error("订单 SQLite 数据库未初始化");
1650
2049
  return;
1651
2050
  }
1652
2051
  const orderSnapshot = this.normalizeOrderCollectionsForIngress(
@@ -1670,6 +2069,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1670
2069
  } else if (typeof this.dbManager.bulkAdd === "function") {
1671
2070
  writeMethod = "bulkAdd";
1672
2071
  await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
2072
+ } else if (options.throwOnError) {
2073
+ throw new Error("订单 SQLite 数据库不支持写入");
1673
2074
  }
1674
2075
  this.recordRecentSqliteWrite(source, [orderSnapshot]);
1675
2076
  this.logInfo("updateOrderInSQLite-完成", {
@@ -1683,6 +2084,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1683
2084
  error: error instanceof Error ? error.message : String(error),
1684
2085
  orderId: orderSnapshot.order_id ?? null
1685
2086
  });
2087
+ if (options.throwOnError)
2088
+ throw error;
1686
2089
  }
1687
2090
  }
1688
2091
  /**
@@ -1717,7 +2120,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1717
2120
  source,
1718
2121
  count: mergedSnapshot.length,
1719
2122
  remoteCount: remoteSnapshot.length,
1720
- preservedPendingCount: mergedSnapshot.length - remoteSnapshot.length
2123
+ preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length
1721
2124
  });
1722
2125
  await this.dbManager.clear(INDEXDB_STORE_NAME);
1723
2126
  this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {