@pisell/pisellos 2.2.260 → 2.2.262

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 (107) hide show
  1. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +1 -0
  2. package/dist/model/strategy/adapter/dataVariant/adapter.js +15 -0
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +2 -0
  4. package/dist/model/strategy/adapter/dataVariant/evaluator.js +25 -0
  5. package/dist/model/strategy/adapter/dataVariant/examples.js +1 -6
  6. package/dist/model/strategy/adapter/dataVariant/type.d.ts +2 -0
  7. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +23 -13
  9. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  10. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  11. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
  12. package/dist/modules/Discount/index.d.ts +5 -2
  13. package/dist/modules/Discount/index.js +30 -7
  14. package/dist/modules/Discount/types.d.ts +4 -0
  15. package/dist/modules/Order/index.d.ts +45 -2
  16. package/dist/modules/Order/index.js +1552 -926
  17. package/dist/modules/Order/types.d.ts +36 -2
  18. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  19. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  20. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  21. package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
  22. package/dist/modules/Order/utils.d.ts +8 -3
  23. package/dist/modules/Order/utils.js +136 -56
  24. package/dist/modules/Rules/index.d.ts +4 -10
  25. package/dist/modules/Rules/index.js +63 -12
  26. package/dist/modules/Rules/types.d.ts +12 -2
  27. package/dist/modules/SalesSummary/index.d.ts +7 -3
  28. package/dist/modules/SalesSummary/index.js +67 -39
  29. package/dist/modules/SalesSummary/types.d.ts +1 -0
  30. package/dist/modules/SalesSummary/utils.js +2 -1
  31. package/dist/modules/SurchargeList/index.d.ts +6 -4
  32. package/dist/modules/SurchargeList/index.js +62 -39
  33. package/dist/modules/SurchargeList/types.d.ts +6 -2
  34. package/dist/server/index.d.ts +8 -0
  35. package/dist/server/index.js +1365 -911
  36. package/dist/server/modules/order/index.d.ts +32 -7
  37. package/dist/server/modules/order/index.js +551 -464
  38. package/dist/server/modules/order/types.d.ts +4 -0
  39. package/dist/server/modules/products/index.d.ts +5 -1
  40. package/dist/server/modules/products/index.js +384 -315
  41. package/dist/server/modules/products/types.d.ts +4 -0
  42. package/dist/solution/BaseSales/index.d.ts +42 -2
  43. package/dist/solution/BaseSales/index.js +1416 -775
  44. package/dist/solution/BaseSales/types.d.ts +7 -1
  45. package/dist/solution/BaseSales/types.js +3 -2
  46. package/dist/solution/BaseSales/utils/cartPromotion.js +19 -7
  47. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  48. package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
  49. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +20 -4
  50. package/dist/solution/BookingByStep/index.d.ts +1 -1
  51. package/dist/solution/BookingTicket/index.d.ts +8 -0
  52. package/dist/solution/BookingTicket/index.js +212 -31
  53. package/dist/solution/ShopDiscount/index.js +15 -14
  54. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +1 -0
  55. package/lib/model/strategy/adapter/dataVariant/adapter.js +10 -0
  56. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +2 -0
  57. package/lib/model/strategy/adapter/dataVariant/evaluator.js +20 -1
  58. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -2
  59. package/lib/model/strategy/adapter/dataVariant/type.d.ts +2 -0
  60. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  61. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -1
  62. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
  63. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  64. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
  65. package/lib/modules/Discount/index.d.ts +5 -2
  66. package/lib/modules/Discount/index.js +23 -3
  67. package/lib/modules/Discount/types.d.ts +4 -0
  68. package/lib/modules/Order/index.d.ts +45 -2
  69. package/lib/modules/Order/index.js +720 -116
  70. package/lib/modules/Order/types.d.ts +36 -2
  71. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  72. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  73. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  74. package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
  75. package/lib/modules/Order/utils.d.ts +8 -3
  76. package/lib/modules/Order/utils.js +104 -18
  77. package/lib/modules/Rules/index.d.ts +4 -10
  78. package/lib/modules/Rules/index.js +61 -9
  79. package/lib/modules/Rules/types.d.ts +12 -2
  80. package/lib/modules/SalesSummary/index.d.ts +7 -3
  81. package/lib/modules/SalesSummary/index.js +28 -11
  82. package/lib/modules/SalesSummary/types.d.ts +1 -0
  83. package/lib/modules/SalesSummary/utils.js +2 -0
  84. package/lib/modules/SurchargeList/index.d.ts +6 -4
  85. package/lib/modules/SurchargeList/index.js +41 -21
  86. package/lib/modules/SurchargeList/types.d.ts +6 -2
  87. package/lib/server/index.d.ts +8 -0
  88. package/lib/server/index.js +336 -11
  89. package/lib/server/modules/order/index.d.ts +32 -7
  90. package/lib/server/modules/order/index.js +298 -189
  91. package/lib/server/modules/order/types.d.ts +4 -0
  92. package/lib/server/modules/products/index.d.ts +5 -1
  93. package/lib/server/modules/products/index.js +21 -0
  94. package/lib/server/modules/products/types.d.ts +4 -0
  95. package/lib/solution/BaseSales/index.d.ts +42 -2
  96. package/lib/solution/BaseSales/index.js +535 -108
  97. package/lib/solution/BaseSales/types.d.ts +7 -1
  98. package/lib/solution/BaseSales/types.js +2 -1
  99. package/lib/solution/BaseSales/utils/cartPromotion.js +13 -1
  100. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  101. package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -6
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +8 -0
  105. package/lib/solution/BookingTicket/index.js +134 -8
  106. package/lib/solution/ShopDiscount/index.js +2 -1
  107. package/package.json +1 -1
@@ -25,15 +25,17 @@ __export(SurchargeList_exports, {
25
25
  module.exports = __toCommonJS(SurchargeList_exports);
26
26
  var import_BaseModule = require("../BaseModule");
27
27
  __reExport(SurchargeList_exports, require("./types"), module.exports);
28
+ var DEFAULT_SURCHARGE_CHANNEL = "online-store";
28
29
  var SurchargeListModule = class extends import_BaseModule.BaseModule {
29
30
  constructor(name, version) {
30
31
  super(name, version);
31
32
  this.defaultName = "surchargeList";
32
33
  this.defaultVersion = "1.0.0";
33
- this.loadingPromise = null;
34
+ this.loadingPromises = /* @__PURE__ */ new Map();
35
+ this.requestVersion = 0;
34
36
  }
35
37
  async initialize(core, options) {
36
- var _a, _b, _c;
38
+ var _a, _b, _c, _d, _e;
37
39
  this.core = core;
38
40
  this.store = options.store;
39
41
  this.request = this.core.getPlugin("request");
@@ -41,44 +43,62 @@ var SurchargeListModule = class extends import_BaseModule.BaseModule {
41
43
  (_a = options.initialState) == null ? void 0 : _a.surchargeList
42
44
  );
43
45
  this.store.surchargeList = hasInitialSurchargeList ? (_b = options.initialState) == null ? void 0 : _b.surchargeList : [];
44
- this.store.isLoaded = Boolean((_c = options.initialState) == null ? void 0 : _c.isLoaded) || hasInitialSurchargeList;
46
+ this.store.channel = ((_c = options.initialState) == null ? void 0 : _c.channel) || ((_d = options.otherParams) == null ? void 0 : _d.channel) || DEFAULT_SURCHARGE_CHANNEL;
47
+ this.store.isLoaded = Boolean((_e = options.initialState) == null ? void 0 : _e.isLoaded) || hasInitialSurchargeList;
45
48
  if (!this.request) {
46
49
  throw new Error("SurchargeListModule 需要 request 插件支持");
47
50
  }
48
51
  }
49
- async getSurchargeList() {
50
- if (this.store.isLoaded)
52
+ resolveChannel(query) {
53
+ return (query == null ? void 0 : query.channel) || DEFAULT_SURCHARGE_CHANNEL;
54
+ }
55
+ async getSurchargeList(query) {
56
+ const channel = this.resolveChannel(query);
57
+ if (this.store.isLoaded && this.store.channel === channel) {
51
58
  return this.store.surchargeList;
52
- if (this.loadingPromise)
53
- return this.loadingPromise;
54
- this.loadingPromise = this.loadSurchargeList();
55
- return this.loadingPromise;
59
+ }
60
+ const loadingPromise = this.loadingPromises.get(channel);
61
+ if (loadingPromise)
62
+ return loadingPromise;
63
+ const nextPromise = this.loadSurchargeList(channel);
64
+ this.loadingPromises.set(channel, nextPromise);
65
+ return nextPromise;
56
66
  }
57
- async refreshSurchargeList() {
58
- this.loadingPromise = this.loadSurchargeList();
59
- return this.loadingPromise;
67
+ async refreshSurchargeList(query) {
68
+ const channel = this.resolveChannel(query);
69
+ const nextPromise = this.loadSurchargeList(channel);
70
+ this.loadingPromises.set(channel, nextPromise);
71
+ return nextPromise;
60
72
  }
61
- async loadSurchargeList() {
73
+ async loadSurchargeList(channel) {
74
+ const currentRequestVersion = ++this.requestVersion;
62
75
  try {
63
76
  const surchargeList = await this.request.get(
64
77
  "/order/custom-surcharge/available/v2",
65
78
  {
66
- channel: "online-store",
79
+ channel,
67
80
  is_assemble_product_data: 1,
68
81
  is_assemble_schedule_data: 1,
69
82
  with: ["relationSchedule"]
70
83
  }
71
84
  );
72
- this.store.surchargeList = (surchargeList == null ? void 0 : surchargeList.data) || [];
73
- this.store.isLoaded = true;
74
- return this.store.surchargeList;
85
+ const nextSurchargeList = (surchargeList == null ? void 0 : surchargeList.data) || [];
86
+ if (currentRequestVersion === this.requestVersion) {
87
+ this.store.surchargeList = nextSurchargeList;
88
+ this.store.channel = channel;
89
+ this.store.isLoaded = true;
90
+ }
91
+ return nextSurchargeList;
75
92
  } catch (error) {
76
93
  console.warn("[SurchargeListModule] 加载附加费配置失败", error);
77
- this.store.surchargeList = [];
78
- this.store.isLoaded = true;
79
- return this.store.surchargeList;
94
+ if (currentRequestVersion === this.requestVersion) {
95
+ this.store.surchargeList = [];
96
+ this.store.channel = channel;
97
+ this.store.isLoaded = true;
98
+ }
99
+ return [];
80
100
  } finally {
81
- this.loadingPromise = null;
101
+ this.loadingPromises.delete(channel);
82
102
  }
83
103
  }
84
104
  };
@@ -4,8 +4,12 @@ export interface SurchargeListItem {
4
4
  export interface SurchargeListState {
5
5
  surchargeList: SurchargeListItem[];
6
6
  isLoaded: boolean;
7
+ channel?: string;
8
+ }
9
+ export interface SurchargeListQuery {
10
+ channel?: string;
7
11
  }
8
12
  export interface SurchargeListModuleAPI {
9
- getSurchargeList(): Promise<SurchargeListItem[]>;
10
- refreshSurchargeList(): Promise<SurchargeListItem[]>;
13
+ getSurchargeList(query?: SurchargeListQuery): Promise<SurchargeListItem[]>;
14
+ refreshSurchargeList(query?: SurchargeListQuery): Promise<SurchargeListItem[]>;
11
15
  }
@@ -475,6 +475,9 @@ declare class Server {
475
475
  private shouldLookupLocalPrintOrder;
476
476
  private getLocalPrintOrderLookup;
477
477
  private handleLocalPrintOrder;
478
+ private handleMachinecodeBatchMeta;
479
+ private resolveMachinecodeBatchMetadataLookup;
480
+ private syncMachinecodeRedeemStatusToLocalOrder;
478
481
  private handleOrderCheckoutSubmit;
479
482
  private handleSyncCheckoutSubmit;
480
483
  private handlePendingSyncCheckoutOrder;
@@ -486,6 +489,11 @@ declare class Server {
486
489
  private sumPaidOrderPayments;
487
490
  private toAmountNumber;
488
491
  private buildSmallTicketProductMap;
492
+ private collectSalesDetailProductIds;
493
+ private buildSalesDetailProductSnapshotMap;
494
+ private withProductCatalogSnapshots;
495
+ private withBundleCatalogSnapshots;
496
+ private withSalesDetailProductSnapshots;
489
497
  private withPendingSyncProductTitles;
490
498
  private buildProductTitleSnapshot;
491
499
  private getProductTitleSnapshotCurrentLocale;
@@ -654,7 +654,8 @@ var Server = class {
654
654
  checkoutData,
655
655
  order: printableOrder,
656
656
  response: null,
657
- requireFullyPaid: false
657
+ requireFullyPaid: false,
658
+ isManualPrint: true
658
659
  });
659
660
  return {
660
661
  code: 200,
@@ -676,6 +677,97 @@ var Server = class {
676
677
  };
677
678
  }
678
679
  };
680
+ this.handleMachinecodeBatchMeta = async ({ data }) => {
681
+ var _a, _b;
682
+ const title = "handleMachinecodeBatchMeta";
683
+ const backendPath = "/shop/machinecode/batch";
684
+ const ids = Array.isArray(data == null ? void 0 : data.ids) ? data.ids : [];
685
+ const status = data == null ? void 0 : data.status;
686
+ this.logInfo(`${title}: 开始处理`, {
687
+ backendPath,
688
+ batchSize: ids.length,
689
+ status,
690
+ order_lookup: this.resolveMachinecodeBatchMetadataLookup(data) ?? null
691
+ });
692
+ if (ids.length === 0) {
693
+ return {
694
+ code: 200,
695
+ status: true,
696
+ message: "",
697
+ data: []
698
+ };
699
+ }
700
+ if (status !== "used" && status !== "unused") {
701
+ return {
702
+ code: 400,
703
+ status: false,
704
+ message: "无效的核销状态",
705
+ data: null
706
+ };
707
+ }
708
+ try {
709
+ await this.syncMachinecodeRedeemStatusToLocalOrder(data, ids, status);
710
+ } catch (error) {
711
+ const message = this.getUnknownErrorMessage(error);
712
+ this.logError(`${title}: 本地订单核销状态更新失败`, {
713
+ error: message,
714
+ error_detail: this.normalizeUnknownError(error)
715
+ });
716
+ return {
717
+ code: 500,
718
+ status: false,
719
+ message,
720
+ data: null
721
+ };
722
+ }
723
+ if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
724
+ this.logError(`${title}: app.request 不可用`, { backendPath });
725
+ return {
726
+ code: 500,
727
+ status: false,
728
+ message: "app.request 不可用",
729
+ data: null
730
+ };
731
+ }
732
+ try {
733
+ const response = await this.app.request.post(backendPath, {
734
+ ids,
735
+ status
736
+ }, {
737
+ isShopApi: true,
738
+ customToast: () => {
739
+ }
740
+ });
741
+ return {
742
+ code: (response == null ? void 0 : response.code) ?? 200,
743
+ status: (response == null ? void 0 : response.status) ?? true,
744
+ message: (response == null ? void 0 : response.message) ?? "",
745
+ data: (response == null ? void 0 : response.data) ?? response
746
+ };
747
+ } catch (error) {
748
+ const backendError = this.extractBackendErrorResponse(error);
749
+ if (backendError) {
750
+ return {
751
+ code: backendError.code ?? 500,
752
+ status: backendError.status ?? false,
753
+ message: backendError.message ?? "后端拒绝 batch-metadata",
754
+ data: backendError.data ?? null
755
+ };
756
+ }
757
+ const message = this.getUnknownErrorMessage(error);
758
+ this.logError(`${title}: 请求失败`, {
759
+ backendPath,
760
+ error: message,
761
+ error_detail: this.normalizeUnknownError(error)
762
+ });
763
+ return {
764
+ code: 500,
765
+ status: false,
766
+ message,
767
+ data: null
768
+ };
769
+ }
770
+ };
679
771
  this.handleOrderSalesDetail = async ({ url, data, path }) => {
680
772
  var _a;
681
773
  const requestPath = this.parseRequestPath(url, path);
@@ -692,12 +784,13 @@ var Server = class {
692
784
  if (!this.shouldForceRemoteSalesDetail(data)) {
693
785
  const localOrder = await this.order.getLocalOrderByLookup(lookup);
694
786
  if (localOrder) {
787
+ const enrichedOrder = await this.withSalesDetailProductSnapshots(localOrder);
695
788
  this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
696
789
  return {
697
790
  code: 200,
698
791
  status: true,
699
792
  message: "",
700
- data: localOrder
793
+ data: enrichedOrder
701
794
  };
702
795
  }
703
796
  }
@@ -744,15 +837,16 @@ var Server = class {
744
837
  };
745
838
  }
746
839
  this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
840
+ const enrichedOrder = await this.withSalesDetailProductSnapshots(savedOrder);
747
841
  return {
748
842
  code: 200,
749
843
  status: true,
750
844
  message: "",
751
- data: savedOrder
845
+ data: enrichedOrder
752
846
  };
753
847
  } catch (error) {
754
848
  const errorMessage = error instanceof Error ? error.message : String(error);
755
- this.logError("handleOrderSalesDetail: 请求失败", {
849
+ this.logInfo("handleOrderSalesDetail: 请求失败", {
756
850
  lookup,
757
851
  backendPath,
758
852
  error: errorMessage
@@ -1758,6 +1852,16 @@ var Server = class {
1758
1852
  method: "post",
1759
1853
  path: "/shop/local/print-order",
1760
1854
  handler: this.handleLocalPrintOrder.bind(this)
1855
+ },
1856
+ {
1857
+ method: "post",
1858
+ path: "/shop/machinecode/batch",
1859
+ handler: this.handleMachinecodeBatchMeta.bind(this)
1860
+ },
1861
+ {
1862
+ method: "post",
1863
+ path: "/machinecode/batch",
1864
+ handler: this.handleMachinecodeBatchMeta.bind(this)
1761
1865
  }
1762
1866
  ]);
1763
1867
  this.registerPrefixRoutes([
@@ -2822,10 +2926,12 @@ var Server = class {
2822
2926
  action: "print_all",
2823
2927
  device_id: params.deviceId ?? deviceId,
2824
2928
  payload: {
2825
- type: params.receiptOnly ? "0" : "99",
2929
+ type: params.isManualPrint ? "0" : "99",
2826
2930
  data: params.receiptOnly ? {
2827
2931
  order_id: printIdentity,
2828
- small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data
2932
+ small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data,
2933
+ skip_wristband: true,
2934
+ skip_voucher: true
2829
2935
  } : {
2830
2936
  order_id: printIdentity,
2831
2937
  machine_code_print_info: (_d = (_c = params.syncedOrder) == null ? void 0 : _c.payment_info) == null ? void 0 : _d.machine_code_print_info,
@@ -2836,7 +2942,7 @@ var Server = class {
2836
2942
  idempotency_key: this.buildPrintOtherReceiptIdempotencyKey(params.syncedOrder, {
2837
2943
  receiptOnly: params.receiptOnly
2838
2944
  }),
2839
- name: "打印转发",
2945
+ name: "PRINT_V1",
2840
2946
  source: "server",
2841
2947
  source_type: "order",
2842
2948
  source_id: printIdentity
@@ -2876,7 +2982,8 @@ var Server = class {
2876
2982
  checkoutData: params.checkoutData,
2877
2983
  syncedOrder: printableOrder,
2878
2984
  response: params.response,
2879
- receiptOnly: true
2985
+ receiptOnly: true,
2986
+ isManualPrint: params.isManualPrint
2880
2987
  });
2881
2988
  return { printed: true, order: printableOrder };
2882
2989
  }
@@ -2894,6 +3001,110 @@ var Server = class {
2894
3001
  }
2895
3002
  return void 0;
2896
3003
  }
3004
+ resolveMachinecodeBatchMetadataLookup(data) {
3005
+ const candidates = [
3006
+ data == null ? void 0 : data.order_lookup,
3007
+ data == null ? void 0 : data.orderLookup,
3008
+ data == null ? void 0 : data.external_sale_number,
3009
+ data == null ? void 0 : data.externalSaleNumber,
3010
+ data == null ? void 0 : data.order_id,
3011
+ data == null ? void 0 : data.orderId,
3012
+ data == null ? void 0 : data.order_number,
3013
+ data == null ? void 0 : data.orderNumber,
3014
+ data == null ? void 0 : data.shop_order_number,
3015
+ data == null ? void 0 : data.shopOrderNumber,
3016
+ data == null ? void 0 : data.shop_full_order_number,
3017
+ data == null ? void 0 : data.shopFullOrderNumber
3018
+ ];
3019
+ return candidates.find((candidate) => candidate !== void 0 && candidate !== null && candidate !== "");
3020
+ }
3021
+ async syncMachinecodeRedeemStatusToLocalOrder(data, ids, status) {
3022
+ var _a;
3023
+ const title = "handleMachinecodeBatchMetadata";
3024
+ const lookup = this.resolveMachinecodeBatchMetadataLookup(data);
3025
+ if (lookup === void 0) {
3026
+ this.logWarning(`${title}: order lookup 缺失,跳过本地订单核销状态更新`, {
3027
+ batchSize: ids.length,
3028
+ status
3029
+ });
3030
+ return;
3031
+ }
3032
+ if (!((_a = this.order) == null ? void 0 : _a.getLocalOrderByLookup)) {
3033
+ this.logWarning(`${title}: Order 模块未注册,跳过本地订单核销状态更新`, {
3034
+ lookup,
3035
+ status
3036
+ });
3037
+ return;
3038
+ }
3039
+ const localOrder = await this.order.getLocalOrderByLookup(lookup);
3040
+ if (!localOrder) {
3041
+ this.logWarning(`${title}: 本地订单不存在,跳过核销状态更新`, {
3042
+ lookup,
3043
+ status
3044
+ });
3045
+ return;
3046
+ }
3047
+ const voucherIdSet = new Set(
3048
+ ids.filter((id) => id !== void 0 && id !== null && id !== "").map((id) => String(id))
3049
+ );
3050
+ if (voucherIdSet.size === 0) {
3051
+ this.logWarning(`${title}: voucher ids 缺失,跳过本地订单核销状态更新`, {
3052
+ lookup,
3053
+ status
3054
+ });
3055
+ return;
3056
+ }
3057
+ const vouchers = Array.isArray(localOrder.vouchers) ? localOrder.vouchers : [];
3058
+ let hasUpdatedVoucher = false;
3059
+ const nextVouchers = vouchers.map((voucher) => {
3060
+ const voucherId = voucher == null ? void 0 : voucher.voucher_id;
3061
+ if (voucherId === void 0 || voucherId === null)
3062
+ return voucher;
3063
+ if (!voucherIdSet.has(String(voucherId)))
3064
+ return voucher;
3065
+ hasUpdatedVoucher = true;
3066
+ return {
3067
+ ...voucher,
3068
+ status
3069
+ };
3070
+ });
3071
+ if (!hasUpdatedVoucher) {
3072
+ this.logWarning(`${title}: 本地订单未命中任何 voucher,跳过核销状态更新`, {
3073
+ lookup,
3074
+ voucher_ids: Array.from(voucherIdSet),
3075
+ status
3076
+ });
3077
+ return;
3078
+ }
3079
+ if (typeof this.order.overwriteExistingOrder === "function") {
3080
+ await this.order.overwriteExistingOrder({
3081
+ ...localOrder,
3082
+ vouchers: nextVouchers
3083
+ });
3084
+ this.logInfo(`${title}: 本地订单 vouchers 核销状态已更新`, {
3085
+ lookup,
3086
+ updatedCount: voucherIdSet.size,
3087
+ status
3088
+ });
3089
+ return;
3090
+ }
3091
+ if ((data == null ? void 0 : data.external_sale_number) && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
3092
+ await this.order.markOrderSyncedByExternalSaleNumber({
3093
+ externalSaleNumber: data.external_sale_number,
3094
+ patch: { vouchers: nextVouchers }
3095
+ });
3096
+ this.logInfo(`${title}: 本地订单 vouchers 核销状态已更新`, {
3097
+ lookup,
3098
+ updatedCount: voucherIdSet.size,
3099
+ status
3100
+ });
3101
+ return;
3102
+ }
3103
+ this.logWarning(`${title}: Order 模块不支持本地订单覆盖,跳过核销状态更新`, {
3104
+ lookup,
3105
+ status
3106
+ });
3107
+ }
2897
3108
  async handleOrderCheckoutSubmit(params) {
2898
3109
  const { backendPath, data, title } = params;
2899
3110
  this.logInfo(`${title}: 开始处理`, {
@@ -3091,11 +3302,8 @@ var Server = class {
3091
3302
  );
3092
3303
  }
3093
3304
  shouldBuildSmallTicketData(order) {
3094
- var _a;
3095
3305
  if (!order || typeof order !== "object")
3096
3306
  return false;
3097
- if ((0, import_small_ticket.hasSmallTicketData)((_a = order.payment_info) == null ? void 0 : _a.small_ticket_data))
3098
- return false;
3099
3307
  return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
3100
3308
  }
3101
3309
  shouldPrintSyncedOrder(params) {
@@ -3191,6 +3399,123 @@ var Server = class {
3191
3399
  return map;
3192
3400
  }, {});
3193
3401
  }
3402
+ collectSalesDetailProductIds(order) {
3403
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
3404
+ const productIds = /* @__PURE__ */ new Set();
3405
+ const addProductId = (rawProductId) => {
3406
+ if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
3407
+ return;
3408
+ const productId = Number(rawProductId);
3409
+ if (Number.isFinite(productId))
3410
+ productIds.add(productId);
3411
+ };
3412
+ products.forEach((product) => {
3413
+ addProductId((product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id));
3414
+ if (Array.isArray(product == null ? void 0 : product.product_bundle)) {
3415
+ product.product_bundle.forEach((bundle) => {
3416
+ addProductId((bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id));
3417
+ });
3418
+ }
3419
+ });
3420
+ return Array.from(productIds);
3421
+ }
3422
+ async buildSalesDetailProductSnapshotMap(order) {
3423
+ var _a;
3424
+ const productIds = this.collectSalesDetailProductIds(order);
3425
+ const getSnapshots = (_a = this.products) == null ? void 0 : _a.getProductSnapshotsByIds;
3426
+ if (!productIds.length || typeof getSnapshots !== "function")
3427
+ return {};
3428
+ try {
3429
+ return await getSnapshots.call(this.products, productIds);
3430
+ } catch (error) {
3431
+ this.logWarning("buildSalesDetailProductSnapshotMap: 查询本地商品快照失败", {
3432
+ product_ids: productIds,
3433
+ error: error instanceof Error ? error.message : String(error)
3434
+ });
3435
+ return {};
3436
+ }
3437
+ }
3438
+ withProductCatalogSnapshots(product, snapshotMap) {
3439
+ if (!product || typeof product !== "object")
3440
+ return product;
3441
+ const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
3442
+ if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
3443
+ return product;
3444
+ const productId = Number(rawProductId);
3445
+ if (!Number.isFinite(productId))
3446
+ return product;
3447
+ const snapshot = snapshotMap[String(productId)];
3448
+ if (!snapshot)
3449
+ return product;
3450
+ const shouldFillCover = (product.product_cover === void 0 || product.product_cover === null || product.product_cover === "") && snapshot.cover !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
3451
+ const metadata = product.metadata && typeof product.metadata === "object" ? product.metadata : {};
3452
+ const shouldFillHolderConfig = (metadata.holder_config === void 0 || metadata.holder_config === null) && snapshot.holder_config !== void 0 && snapshot.holder_config !== null;
3453
+ if (!shouldFillCover && !shouldFillHolderConfig)
3454
+ return product;
3455
+ return {
3456
+ ...product,
3457
+ ...shouldFillCover ? { product_cover: snapshot.cover } : {},
3458
+ ...shouldFillHolderConfig ? {
3459
+ metadata: {
3460
+ ...metadata,
3461
+ holder_config: snapshot.holder_config
3462
+ }
3463
+ } : {}
3464
+ };
3465
+ }
3466
+ withBundleCatalogSnapshots(product, snapshotMap) {
3467
+ if (!Array.isArray(product == null ? void 0 : product.product_bundle))
3468
+ return product;
3469
+ let hasChanged = false;
3470
+ const productBundle = product.product_bundle.map((bundle) => {
3471
+ if (!bundle || typeof bundle !== "object")
3472
+ return bundle;
3473
+ const rawProductId = (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id);
3474
+ if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
3475
+ return bundle;
3476
+ const productId = Number(rawProductId);
3477
+ if (!Number.isFinite(productId))
3478
+ return bundle;
3479
+ const snapshot = snapshotMap[String(productId)];
3480
+ const shouldFillCover = (bundle.cover === void 0 || bundle.cover === null || bundle.cover === "") && (snapshot == null ? void 0 : snapshot.cover) !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
3481
+ if (!shouldFillCover)
3482
+ return bundle;
3483
+ hasChanged = true;
3484
+ return {
3485
+ ...bundle,
3486
+ cover: snapshot.cover
3487
+ };
3488
+ });
3489
+ if (!hasChanged)
3490
+ return product;
3491
+ return {
3492
+ ...product,
3493
+ product_bundle: productBundle
3494
+ };
3495
+ }
3496
+ async withSalesDetailProductSnapshots(order) {
3497
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : null;
3498
+ if (!(products == null ? void 0 : products.length))
3499
+ return order;
3500
+ const snapshotMap = await this.buildSalesDetailProductSnapshotMap(order);
3501
+ if (!Object.keys(snapshotMap).length)
3502
+ return order;
3503
+ let hasChanged = false;
3504
+ const enrichedProducts = products.map((product) => {
3505
+ const productWithBundleSnapshots = this.withBundleCatalogSnapshots(product, snapshotMap);
3506
+ const nextProduct = this.withProductCatalogSnapshots(productWithBundleSnapshots, snapshotMap);
3507
+ if (nextProduct !== product)
3508
+ hasChanged = true;
3509
+ return nextProduct;
3510
+ });
3511
+ if (!hasChanged)
3512
+ return order;
3513
+ const enrichedOrder = {
3514
+ ...order,
3515
+ products: enrichedProducts
3516
+ };
3517
+ return enrichedOrder;
3518
+ }
3194
3519
  withPendingSyncProductTitles(order, productMap) {
3195
3520
  const products = Array.isArray(order.products) ? order.products : null;
3196
3521
  if (!(products == null ? void 0 : products.length))
@@ -15,7 +15,6 @@ export declare class OrderModule extends BaseModule implements Module {
15
15
  private syncTimer?;
16
16
  private isProcessingSyncBatch;
17
17
  private isIdlePhase;
18
- private resourceIdIndex;
19
18
  private logger;
20
19
  private storage;
21
20
  private orderSQLiteSaveQueue; /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
@@ -44,6 +43,16 @@ export declare class OrderModule extends BaseModule implements Module {
44
43
  */
45
44
  private logError;
46
45
  private logWarning;
46
+ /**
47
+ * 在订单进入内存或 SQLite 前统一压缩子项强身份重复并补齐协议 UID。
48
+ * 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
49
+ */
50
+ private normalizeOrderCollectionsForIngress;
51
+ /**
52
+ * incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
53
+ */
54
+ private mergeAuthoritativeOrderCollection;
55
+ private reconcileOverwriteOrderCollections;
47
56
  /**
48
57
  * 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
49
58
  *
@@ -89,7 +98,6 @@ export declare class OrderModule extends BaseModule implements Module {
89
98
  * @returns 刷新后的订单列表
90
99
  */
91
100
  silentRefresh(): Promise<OrderData[]>;
92
- getOrdersByResourceId(resourceId: string | number): OrderData[];
93
101
  private normalizeOrderForMemoryList;
94
102
  /**
95
103
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
@@ -126,7 +134,6 @@ export declare class OrderModule extends BaseModule implements Module {
126
134
  private isBlankIdentityValue;
127
135
  private getOrderIdentityEntries;
128
136
  private getOrderIdentityKeys;
129
- private extractResourceIds;
130
137
  private getOrderDateKey;
131
138
  /**
132
139
  * 初始化 OrderDataSource 实例
@@ -175,6 +182,28 @@ export declare class OrderModule extends BaseModule implements Module {
175
182
  * 将增量订单合并到 store
176
183
  */
177
184
  private mergeOrdersToStore;
185
+ /**
186
+ * 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
187
+ * 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
188
+ *
189
+ * @example
190
+ * const idx = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys)
191
+ */
192
+ private lookupOrderIndexByIdentityKeys;
193
+ private isRemoteEchoMergeSource;
194
+ /**
195
+ * 将订单的全部身份键登记到索引并指向其在列表中的下标。
196
+ * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
197
+ *
198
+ * @example
199
+ * this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex)
200
+ */
201
+ private registerOrderIdentityKeys;
202
+ /**
203
+ * 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
204
+ * 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
205
+ */
206
+ private runOrderStoreSelfCheck;
178
207
  private normalizeOrderSyncMessage;
179
208
  private normalizeOrderSyncPayload;
180
209
  private uniqueOrderIds;
@@ -193,10 +222,6 @@ export declare class OrderModule extends BaseModule implements Module {
193
222
  private findOrderIndexByIdentity;
194
223
  private getOrderCompletenessScore;
195
224
  private pickPreferredOrder;
196
- private getProductIdentityKeys;
197
- private mergeOrderProductLists;
198
- private getPaymentMergeKey;
199
- private mergeOrderPaymentLists;
200
225
  private mergeOrderRecords;
201
226
  private summarizeDuplicateOrders;
202
227
  private logDuplicateOrders;