@pisell/pisellos 0.10.2 → 0.10.3

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 (131) 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 +0 -9
  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/OpenData/index.d.ts +2 -0
  16. package/dist/modules/OpenData/index.js +8 -0
  17. package/dist/modules/Order/index.d.ts +28 -8
  18. package/dist/modules/Order/index.js +818 -503
  19. package/dist/modules/Order/payment-utils.d.ts +26 -0
  20. package/dist/modules/Order/payment-utils.js +225 -0
  21. package/dist/modules/Order/types.d.ts +35 -1
  22. package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
  23. package/dist/modules/Order/utils.js +10 -6
  24. package/dist/modules/Payment/index.d.ts +2 -0
  25. package/dist/modules/Payment/index.js +79 -50
  26. package/dist/modules/Payment/types.d.ts +107 -28
  27. package/dist/modules/Payment/types.js +20 -3
  28. package/dist/modules/Payment/walletpass.d.ts +38 -1
  29. package/dist/modules/Payment/walletpass.js +917 -114
  30. package/dist/modules/ProductList/index.js +1 -1
  31. package/dist/modules/Rules/index.d.ts +3 -0
  32. package/dist/modules/Rules/index.js +130 -99
  33. package/dist/server/index.d.ts +16 -0
  34. package/dist/server/index.js +2084 -1188
  35. package/dist/server/modules/index.d.ts +1 -1
  36. package/dist/server/modules/order/index.d.ts +70 -4
  37. package/dist/server/modules/order/index.js +1816 -728
  38. package/dist/server/modules/order/types.d.ts +25 -3
  39. package/dist/server/modules/order/types.js +7 -1
  40. package/dist/solution/BaseSales/index.d.ts +111 -13
  41. package/dist/solution/BaseSales/index.js +1799 -446
  42. package/dist/solution/BaseSales/types.d.ts +55 -1
  43. package/dist/solution/BaseSales/types.js +2 -1
  44. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  45. package/dist/solution/BaseSales/utils/cartPromotion.js +90 -31
  46. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  47. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -3
  48. package/dist/solution/BookingByStep/index.d.ts +1 -1
  49. package/dist/solution/BookingTicket/index.d.ts +7 -3
  50. package/dist/solution/BookingTicket/index.js +138 -52
  51. package/dist/solution/BookingTicket/types.d.ts +1 -0
  52. package/dist/solution/BookingTicket/utils/addProductDecision.js +6 -0
  53. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  54. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +173 -83
  55. package/dist/solution/BookingTicket/utils/weighingProductSku.d.ts +5 -0
  56. package/dist/solution/BookingTicket/utils/weighingProductSku.js +45 -0
  57. package/dist/solution/Sales/index.d.ts +1 -0
  58. package/dist/solution/Sales/index.js +10 -2
  59. package/dist/solution/ScanOrder/index.js +31 -20
  60. package/dist/solution/UnifiedBookingSales/index.js +23 -3
  61. package/dist/solution/VenueBooking/index.d.ts +1 -0
  62. package/dist/solution/VenueBooking/index.js +34 -24
  63. package/dist/types/index.d.ts +1 -0
  64. package/dist/utils/payment-number.d.ts +9 -0
  65. package/dist/utils/payment-number.js +69 -0
  66. package/lib/core/index.d.ts +2 -0
  67. package/lib/core/index.js +4 -0
  68. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  69. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  70. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  71. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  72. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  73. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  74. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  75. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  76. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  77. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  78. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  79. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  80. package/lib/modules/OpenData/index.d.ts +2 -0
  81. package/lib/modules/OpenData/index.js +5 -0
  82. package/lib/modules/Order/index.d.ts +28 -8
  83. package/lib/modules/Order/index.js +233 -68
  84. package/lib/modules/Order/payment-utils.d.ts +26 -0
  85. package/lib/modules/Order/payment-utils.js +224 -0
  86. package/lib/modules/Order/types.d.ts +35 -1
  87. package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
  88. package/lib/modules/Order/utils.js +11 -4
  89. package/lib/modules/Payment/index.d.ts +2 -0
  90. package/lib/modules/Payment/index.js +34 -13
  91. package/lib/modules/Payment/types.d.ts +107 -28
  92. package/lib/modules/Payment/types.js +4 -3
  93. package/lib/modules/Payment/walletpass.d.ts +38 -1
  94. package/lib/modules/Payment/walletpass.js +730 -21
  95. package/lib/modules/ProductList/index.js +9 -1
  96. package/lib/modules/Rules/index.d.ts +3 -0
  97. package/lib/modules/Rules/index.js +39 -10
  98. package/lib/server/index.d.ts +16 -0
  99. package/lib/server/index.js +677 -28
  100. package/lib/server/modules/index.d.ts +1 -1
  101. package/lib/server/modules/order/index.d.ts +70 -4
  102. package/lib/server/modules/order/index.js +818 -69
  103. package/lib/server/modules/order/types.d.ts +25 -3
  104. package/lib/server/modules/order/types.js +1 -0
  105. package/lib/solution/BaseSales/index.d.ts +111 -13
  106. package/lib/solution/BaseSales/index.js +882 -46
  107. package/lib/solution/BaseSales/types.d.ts +55 -1
  108. package/lib/solution/BaseSales/types.js +2 -1
  109. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  110. package/lib/solution/BaseSales/utils/cartPromotion.js +63 -12
  111. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  112. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
  113. package/lib/solution/BookingByStep/index.d.ts +1 -1
  114. package/lib/solution/BookingTicket/index.d.ts +7 -3
  115. package/lib/solution/BookingTicket/index.js +63 -9
  116. package/lib/solution/BookingTicket/types.d.ts +1 -0
  117. package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -0
  118. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  119. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +37 -5
  120. package/lib/solution/BookingTicket/utils/weighingProductSku.d.ts +5 -0
  121. package/lib/solution/BookingTicket/utils/weighingProductSku.js +63 -0
  122. package/lib/solution/Sales/index.d.ts +1 -0
  123. package/lib/solution/Sales/index.js +5 -3
  124. package/lib/solution/ScanOrder/index.js +8 -0
  125. package/lib/solution/UnifiedBookingSales/index.js +10 -2
  126. package/lib/solution/VenueBooking/index.d.ts +1 -0
  127. package/lib/solution/VenueBooking/index.js +13 -6
  128. package/lib/types/index.d.ts +1 -0
  129. package/lib/utils/payment-number.d.ts +9 -0
  130. package/lib/utils/payment-number.js +64 -0
  131. package/package.json +1 -1
@@ -37,6 +37,8 @@ var import_types = require("./types");
37
37
  var import_utils = require("./utils");
38
38
  var import_utils2 = require("../Product/utils");
39
39
  var import_dayjs = __toESM(require("dayjs"));
40
+ var import_payment_utils = require("./payment-utils");
41
+ var import_payment_number = require("../../utils/payment-number");
40
42
  var import_cartPromotion = require("../../solution/BaseSales/utils/cartPromotion");
41
43
  var import_utils3 = require("../../solution/ScanOrder/utils");
42
44
  var import_manualProductDiscount = require("./utils/manualProductDiscount");
@@ -68,6 +70,24 @@ function isManualProductDiscountProduct(product) {
68
70
  }
69
71
  var ORDER_PAYMENT_STATUS_PAID = "paid";
70
72
  var ORDER_PAYMENT_STATUS_PENDING = "payment_pending";
73
+ var CUSTOMER_PROMOTION_DISCOUNT_TAGS = /* @__PURE__ */ new Set([
74
+ "good_pass",
75
+ "product_discount_card",
76
+ "discount_card"
77
+ ]);
78
+ function isCustomerPromotionDiscount(discount) {
79
+ return CUSTOMER_PROMOTION_DISCOUNT_TAGS.has(
80
+ String((discount == null ? void 0 : discount.tag) || (discount == null ? void 0 : discount.type) || "").toLowerCase()
81
+ );
82
+ }
83
+ function markScannedDiscounts(discountList, scannedDiscountList) {
84
+ const scannedIds = new Set(
85
+ scannedDiscountList.map((discount) => discount == null ? void 0 : discount.id).filter((id) => id !== void 0 && id !== null).map(String)
86
+ );
87
+ return discountList.map(
88
+ (discount) => scannedIds.has(String(discount == null ? void 0 : discount.id)) ? { ...discount, isScan: true } : discount
89
+ );
90
+ }
71
91
  function isVoucherPaymentRecord(payment) {
72
92
  return (payment == null ? void 0 : payment.voucher_id) !== void 0 && Number(payment.voucher_id) !== 0;
73
93
  }
@@ -83,6 +103,11 @@ function isPaidPaymentRecord(payment) {
83
103
  function isCommittedVoucherPaymentRecord(payment) {
84
104
  return isVoucherPaymentRecord(payment) && (payment == null ? void 0 : payment.status) !== "voided" && (hasSyncedOrderPaymentRecord(payment) || isPaidPaymentRecord(payment));
85
105
  }
106
+ function getVoucherPaymentLifecycleKey(payment) {
107
+ if (!isVoucherPaymentRecord(payment))
108
+ return null;
109
+ return `${String(payment.voucher_id)}::${String(payment.status || "")}`;
110
+ }
86
111
  var OrderModule = class extends import_BaseModule.BaseModule {
87
112
  constructor(name, version) {
88
113
  super(name || "order", version);
@@ -115,6 +140,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
115
140
  const type = (item == null ? void 0 : item.type) ?? (item == null ? void 0 : item.tag);
116
141
  if (!type || type === "product")
117
142
  continue;
143
+ const isDiscountCard = type === "discount_card" || type === "product_discount_card";
118
144
  const resourceId = ((_a = item == null ? void 0 : item.discount) == null ? void 0 : _a.resource_id) ?? (item == null ? void 0 : item.resource_id) ?? (item == null ? void 0 : item.discount_id) ?? (item == null ? void 0 : item.order_discount_id);
119
145
  if (resourceId === void 0 || resourceId === null || resourceId === "")
120
146
  continue;
@@ -137,7 +163,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
137
163
  if (existed) {
138
164
  existed.amount = Number(existed.amount || 0) + amount;
139
165
  existed.used_par_value = String(Number(existed.used_par_value || 0) + amount);
140
- existed.balance = String(Number(existed.balance || 0) + amount);
166
+ if (!isDiscountCard) {
167
+ existed.balance = String(Number(existed.balance || 0) + amount);
168
+ }
141
169
  const productIds = Array.isArray((_f = existed.limited_relation_product_data) == null ? void 0 : _f.product_ids) ? existed.limited_relation_product_data.product_ids : [];
142
170
  if ((product == null ? void 0 : product.product_id) !== void 0 && (product == null ? void 0 : product.product_id) !== null && !productIds.includes(product.product_id)) {
143
171
  existed.limited_relation_product_data = {
@@ -174,7 +202,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
174
202
  filter: 0,
175
203
  exclude_product_ids: []
176
204
  },
177
- balance: String((item == null ? void 0 : item.amount) ?? "0"),
205
+ balance: isDiscountCard ? void 0 : String((item == null ? void 0 : item.amount) ?? "0"),
178
206
  format_title: title,
179
207
  product: {
180
208
  id: (product == null ? void 0 : product.product_id) ?? 0,
@@ -521,7 +549,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
521
549
  });
522
550
  }
523
551
  async scanCode(code, customerId) {
524
- var _a, _b, _c, _d;
552
+ var _a, _b, _c, _d, _e;
525
553
  const resultDiscountWithReason = await ((_a = this.store.discount) == null ? void 0 : _a.batchSearch(code, { customerId })) || { discountList: [], unavailableReasonKey: null };
526
554
  const { discountList: resultDiscountList, unavailableReasonKey } = resultDiscountWithReason;
527
555
  const rulesModule = this.store.rules;
@@ -529,6 +557,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
529
557
  return {
530
558
  type: "clientCalc",
531
559
  isAvailable: false,
560
+ isAccepted: false,
532
561
  discountList: this.getDiscountList(),
533
562
  scannedDiscountList: resultDiscountList,
534
563
  unavailableReason: import_types2.UnavailableReason.Unknown
@@ -538,6 +567,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
538
567
  return {
539
568
  type: "server",
540
569
  isAvailable: false,
570
+ isAccepted: false,
541
571
  discountList: this.getDiscountList(),
542
572
  scannedDiscountList: resultDiscountList,
543
573
  unavailableReasonKey
@@ -553,13 +583,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
553
583
  return {
554
584
  type: "clientCalc",
555
585
  isAvailable: true,
586
+ isAccepted: true,
556
587
  discountList: this.getDiscountList(),
557
588
  scannedDiscountList: resultDiscountList
558
589
  };
559
590
  }
560
591
  const tempOrder = this.store.tempOrder;
561
592
  const holders = ((_b = tempOrder == null ? void 0 : tempOrder.holder) == null ? void 0 : _b.form_record) || [];
562
- const { isAvailable, discountList: newDiscountList, unavailableReason } = rulesModule.isDiscountListAvailable({
593
+ const {
594
+ isAvailable,
595
+ discountList: newDiscountList,
596
+ evaluatedDiscountList,
597
+ unavailableReason
598
+ } = rulesModule.isDiscountListAvailable({
563
599
  productList: (tempOrder == null ? void 0 : tempOrder.products) || [],
564
600
  oldDiscountList: this.getDiscountList(),
565
601
  newDiscountList: withScanList,
@@ -567,15 +603,25 @@ var OrderModule = class extends import_BaseModule.BaseModule {
567
603
  holders,
568
604
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product)
569
605
  }) || { isAvailable: false, discountList: this.getDiscountList() };
570
- if (isAvailable && newDiscountList) {
571
- (_d = this.store.discount) == null ? void 0 : _d.setDiscountList(newDiscountList);
606
+ const shouldRetainForLater = !isAvailable && unavailableReason === import_types2.UnavailableReason.ProductNotApplicable && withScanList.some(isCustomerPromotionDiscount);
607
+ const normalizedNewDiscountList = newDiscountList ? markScannedDiscounts(newDiscountList, withScanList) : void 0;
608
+ const retainedDiscountList = evaluatedDiscountList ? markScannedDiscounts(evaluatedDiscountList, withScanList) : normalizedNewDiscountList;
609
+ let resolvedDiscountList = normalizedNewDiscountList || this.getDiscountList();
610
+ if (isAvailable && normalizedNewDiscountList) {
611
+ await ((_d = this.store.discount) == null ? void 0 : _d.setDiscountList(normalizedNewDiscountList));
572
612
  this.applyDiscount();
573
613
  await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
614
+ resolvedDiscountList = this.getDiscountList();
615
+ } else if (shouldRetainForLater && retainedDiscountList) {
616
+ await ((_e = this.store.discount) == null ? void 0 : _e.setDiscountList(retainedDiscountList));
617
+ await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
618
+ resolvedDiscountList = this.getDiscountList();
574
619
  }
575
620
  return {
576
621
  type: "clientCalc",
577
622
  isAvailable: isAvailable || false,
578
- discountList: newDiscountList || this.getDiscountList(),
623
+ isAccepted: Boolean(isAvailable || shouldRetainForLater),
624
+ discountList: resolvedDiscountList,
579
625
  scannedDiscountList: resultDiscountList,
580
626
  unavailableReason
581
627
  };
@@ -1063,17 +1109,40 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1063
1109
  const depositPaidAmount = this.calculateDepositPaidAmount(tempOrder.payments || []);
1064
1110
  return depositPaidAmount.lt(depositAmount) ? "deposit" : "normal";
1065
1111
  }
1112
+ getPaymentNumberAppData(key) {
1113
+ var _a, _b, _c, _d, _e;
1114
+ const appPlugin = this.appPlugin;
1115
+ if (!appPlugin)
1116
+ return void 0;
1117
+ const getData = (_a = appPlugin.getData) == null ? void 0 : _a.call(appPlugin);
1118
+ if (typeof getData === "function")
1119
+ return getData(key);
1120
+ const app = appPlugin.getApp();
1121
+ const coreData = (_e = (_c = (_b = app == null ? void 0 : app.models) == null ? void 0 : _b.getStore) == null ? void 0 : (_d = _c.call(_b)).getDataByModel) == null ? void 0 : _e.call(_d, "core", "core");
1122
+ return coreData == null ? void 0 : coreData[key];
1123
+ }
1124
+ getPaymentNumberDevicePrefixSync() {
1125
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefixFromDeviceId)(
1126
+ (key) => this.getPaymentNumberAppData(key)
1127
+ );
1128
+ }
1129
+ getPaymentNumberDevicePrefixAsync() {
1130
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefix)(
1131
+ (key) => this.getPaymentNumberAppData(key)
1132
+ );
1133
+ }
1066
1134
  normalizePaymentSource(payment, options) {
1067
1135
  const paymentRecord = payment;
1068
1136
  const metadata = paymentRecord.metadata && typeof paymentRecord.metadata === "object" ? { ...paymentRecord.metadata } : {};
1069
- if (!metadata.unique_payment_number) {
1070
- metadata.unique_payment_number = (0, import_utils.createUuidV4)();
1071
- }
1072
- const normalized = {
1073
- ...paymentRecord,
1074
- metadata,
1075
- origin_amount: paymentRecord.origin_amount ?? paymentRecord.amount ?? "0.00"
1076
- };
1137
+ const normalized = (0, import_payment_utils.ensureOrderPaymentNumber)(
1138
+ {
1139
+ ...paymentRecord,
1140
+ metadata,
1141
+ origin_amount: paymentRecord.origin_amount ?? paymentRecord.amount ?? "0.00"
1142
+ },
1143
+ (options == null ? void 0 : options.devicePrefix) || this.getPaymentNumberDevicePrefixSync(),
1144
+ import_utils.createUuidV4
1145
+ );
1077
1146
  if (paymentRecord.status !== void 0) {
1078
1147
  normalized.status = paymentRecord.status;
1079
1148
  } else if ((options == null ? void 0 : options.defaultPaid) !== false) {
@@ -2494,17 +2563,36 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2494
2563
  * 用一组支付来源覆盖当前订单支付项。
2495
2564
  *
2496
2565
  * 入参允许来自 PaymentModule 的 PaymentItem,内部统一映射为 Sales 协议:
2497
- * uuid -> metadata.unique_payment_number,id -> custom_payment_id,
2566
+ * 新支付来源的 uuid 会作为 payment_number 的唯一号段,id -> custom_payment_id,
2498
2567
  * isSynced 等运行态字段不会进入 tempOrder.payments。
2499
2568
  */
2500
2569
  setOrderPayments(payments) {
2501
2570
  const tempOrder = this.ensureTempOrder();
2502
- tempOrder.payments = (0, import_utils.mapPaymentItemsToOrderPayments)(payments);
2571
+ tempOrder.payments = (0, import_utils.mapPaymentItemsToOrderPayments)(
2572
+ (payments || []).map((payment) => this.normalizePaymentSource(payment, { defaultPaid: false }))
2573
+ );
2503
2574
  this.persistTempOrder();
2504
2575
  return tempOrder.payments;
2505
2576
  }
2506
- /** 追加单个支付项,并立即持久化当前 tempOrder。 */
2577
+ /** 同步兼容入口:按调用当下的 device_id 或 LOCAL 生成支付编号。 */
2507
2578
  addOrderPayment(payment) {
2579
+ const hasPaymentNumber = String(
2580
+ payment.payment_number || ""
2581
+ ).trim() !== "";
2582
+ return this.addOrderPaymentWithDevicePrefix(
2583
+ payment,
2584
+ hasPaymentNumber ? "LOCAL" : this.getPaymentNumberDevicePrefixSync()
2585
+ );
2586
+ }
2587
+ /** 异步入口:创建支付项时读取最新 IoT 设备短号。 */
2588
+ async addOrderPaymentAsync(payment) {
2589
+ const hasPaymentNumber = String(
2590
+ payment.payment_number || ""
2591
+ ).trim() !== "";
2592
+ const devicePrefix = hasPaymentNumber ? "LOCAL" : await this.getPaymentNumberDevicePrefixAsync();
2593
+ return this.addOrderPaymentWithDevicePrefix(payment, devicePrefix);
2594
+ }
2595
+ addOrderPaymentWithDevicePrefix(payment, devicePrefix) {
2508
2596
  this.logInfo("addOrderPayment", {
2509
2597
  payment
2510
2598
  });
@@ -2517,7 +2605,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2517
2605
  type: orderPaymentType,
2518
2606
  order_payment_type: orderPaymentType
2519
2607
  },
2520
- { defaultPaid: true }
2608
+ { defaultPaid: true, devicePrefix }
2521
2609
  )
2522
2610
  ]);
2523
2611
  tempOrder.payments = [...tempOrder.payments || [], ...mapped];
@@ -2530,57 +2618,55 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2530
2618
  return tempOrder.payments;
2531
2619
  }
2532
2620
  /**
2533
- * 按支付唯一号、后端支付 ID、自定义支付方式 ID 或旧 uuid 更新支付项。
2534
- *
2535
- * 该方法服务 PaymentModal 的 void / 编辑场景;更新 metadata 时会做浅合并,
2536
- * 避免覆盖 unique_payment_number、现金实付/找零等已有元数据。
2621
+ * 默认按支付唯一号精确更新;仅显式指定 legacy 时兼容历史支付标识。
2622
+ * metadata 与 transactions 会分别合并,避免覆盖支付会话号和已有交易记录。
2537
2623
  */
2538
- updateOrderPayment(paymentIdentity, updates) {
2624
+ async updateOrderPayment(paymentIdentity, updates, options = {}) {
2539
2625
  const tempOrder = this.ensureTempOrder();
2540
2626
  const identity = String(paymentIdentity);
2541
- tempOrder.payments = (tempOrder.payments || []).map((payment) => {
2542
- var _a;
2543
- const uniquePaymentNumber = (_a = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a.unique_payment_number;
2544
- const orderPaymentId = payment == null ? void 0 : payment.order_payment_id;
2545
- const customPaymentId = payment == null ? void 0 : payment.custom_payment_id;
2546
- const uuid = payment == null ? void 0 : payment.uuid;
2547
- const matched = [
2548
- uniquePaymentNumber,
2549
- orderPaymentId,
2550
- customPaymentId,
2551
- uuid
2552
- ].some((value) => value !== void 0 && String(value) === identity);
2553
- if (!matched)
2627
+ const matchMode = options.matchBy === "compat" || options.matchBy === "legacy" ? "compat" : "payment_number";
2628
+ const matchedPayment = (0, import_payment_utils.resolveOrderPaymentIdentity)(
2629
+ tempOrder.payments || [],
2630
+ identity,
2631
+ matchMode
2632
+ );
2633
+ if (!matchedPayment) {
2634
+ throw new Error(`未找到支付项: ${identity}`);
2635
+ }
2636
+ let updatedPayment = null;
2637
+ tempOrder.payments = (tempOrder.payments || []).map((payment, index) => {
2638
+ if (index !== matchedPayment.index)
2554
2639
  return payment;
2555
- return {
2556
- ...payment,
2640
+ const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(payment, {
2557
2641
  ...updates,
2558
- metadata: {
2559
- ...payment.metadata || {},
2560
- ...updates.metadata || {}
2561
- }
2562
- };
2642
+ updated_at: updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
2643
+ });
2644
+ updatedPayment = nextPayment;
2645
+ return nextPayment;
2563
2646
  });
2564
2647
  this.persistTempOrder();
2565
- return tempOrder.payments;
2648
+ const summary = await this.recalculateSummary({ createIfMissing: true });
2649
+ this.persistTempOrder();
2650
+ const payments = tempOrder.payments;
2651
+ return {
2652
+ updated: true,
2653
+ payment: payments[matchedPayment.index] || updatedPayment,
2654
+ payments,
2655
+ summary
2656
+ };
2566
2657
  }
2567
2658
  /** 从当前订单支付项中移除指定支付项。 */
2568
2659
  deleteOrderPayment(paymentIdentity) {
2569
2660
  const tempOrder = this.ensureTempOrder();
2570
2661
  const identity = String(paymentIdentity);
2571
- tempOrder.payments = (tempOrder.payments || []).filter((payment) => {
2572
- var _a;
2573
- const uniquePaymentNumber = (_a = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a.unique_payment_number;
2574
- const orderPaymentId = payment == null ? void 0 : payment.order_payment_id;
2575
- const customPaymentId = payment == null ? void 0 : payment.custom_payment_id;
2576
- const uuid = payment == null ? void 0 : payment.uuid;
2577
- return ![
2578
- uniquePaymentNumber,
2579
- orderPaymentId,
2580
- customPaymentId,
2581
- uuid
2582
- ].some((value) => value !== void 0 && String(value) === identity);
2583
- });
2662
+ const matchedPayment = (0, import_payment_utils.resolveOrderPaymentIdentity)(
2663
+ tempOrder.payments || [],
2664
+ identity,
2665
+ "compat"
2666
+ );
2667
+ if (!matchedPayment)
2668
+ return tempOrder.payments;
2669
+ tempOrder.payments = (tempOrder.payments || []).filter((_, index) => index !== matchedPayment.index);
2584
2670
  this.persistTempOrder();
2585
2671
  return tempOrder.payments;
2586
2672
  }
@@ -2689,7 +2775,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2689
2775
  payments.map(
2690
2776
  (payment) => this.normalizePaymentSource(
2691
2777
  normalizeVoucherPaymentStatus(withVoucherPaymentType(payment)),
2692
- { defaultPaid: false }
2778
+ {
2779
+ defaultPaid: false,
2780
+ devicePrefix: options == null ? void 0 : options.devicePrefix
2781
+ }
2693
2782
  )
2694
2783
  )
2695
2784
  ).filter((payment) => {
@@ -2711,14 +2800,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2711
2800
  const committedVoucherPaymentIds = new Set(
2712
2801
  committedVoucherPayments.filter((payment) => hasSyncedOrderPaymentRecord(payment)).map((payment) => String(payment.order_payment_id))
2713
2802
  );
2714
- const committedVoucherIds = new Set(
2715
- committedVoucherPayments.map((payment) => String(payment.voucher_id))
2803
+ const committedVoucherLifecycleKeys = new Set(
2804
+ committedVoucherPayments.map((payment) => getVoucherPaymentLifecycleKey(payment)).filter((key) => key !== null)
2716
2805
  );
2717
2806
  const replaceableVouchers = mappedVouchers.filter((payment) => {
2718
2807
  if (hasSyncedOrderPaymentRecord(payment) && committedVoucherPaymentIds.has(String(payment.order_payment_id))) {
2719
2808
  return false;
2720
2809
  }
2721
- if (payment.voucher_id !== void 0 && committedVoucherIds.has(String(payment.voucher_id))) {
2810
+ const lifecycleKey = getVoucherPaymentLifecycleKey(payment);
2811
+ if (lifecycleKey && committedVoucherLifecycleKeys.has(lifecycleKey)) {
2722
2812
  return false;
2723
2813
  }
2724
2814
  return true;
@@ -2740,6 +2830,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2740
2830
  });
2741
2831
  return tempOrder.payments;
2742
2832
  }
2833
+ async updateVoucherOrderPaymentsAsync(payments, options) {
2834
+ const needsPaymentNumber = (payments || []).some((payment) => String(payment.payment_number || "").trim() === "");
2835
+ const devicePrefix = needsPaymentNumber ? await this.getPaymentNumberDevicePrefixAsync() : "LOCAL";
2836
+ return this.updateVoucherOrderPayments(payments, {
2837
+ ...options,
2838
+ devicePrefix
2839
+ });
2840
+ }
2743
2841
  async shouldMergeProductToOrder(params) {
2744
2842
  var _a;
2745
2843
  const onBeforeMergeProductToOrder = (_a = this.orderHooks) == null ? void 0 : _a.onBeforeMergeProductToOrder;
@@ -3570,6 +3668,38 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3570
3668
  await this.saveDraft();
3571
3669
  return tempOrder;
3572
3670
  }
3671
+ async saveTempOrderAsDraft(params) {
3672
+ var _a, _b, _c, _d, _e;
3673
+ const tempOrder = this.ensureTempOrder();
3674
+ this.ensureExternalSaleNumber(tempOrder);
3675
+ this.persistTempOrder();
3676
+ const latestSummary = await this.recalculateSummary({ createIfMissing: true }) || this.store.summary || (0, import_utils.createEmptySummary)();
3677
+ const payload = (0, import_utils.buildSubmitPayload)({
3678
+ tempOrder,
3679
+ cacheId: (params == null ? void 0 : params.cacheId) ?? this.cacheId,
3680
+ platform: (params == null ? void 0 : params.platform) || ((_a = this.otherParams) == null ? void 0 : _a.platform),
3681
+ businessCode: (params == null ? void 0 : params.businessCode) || ((_b = this.otherParams) == null ? void 0 : _b.businessCode) || ((_c = this.otherParams) == null ? void 0 : _c.business_code) || tempOrder.business_code,
3682
+ channel: params == null ? void 0 : params.channel,
3683
+ type: (params == null ? void 0 : params.type) ?? ((_d = this.otherParams) == null ? void 0 : _d.type),
3684
+ summary: latestSummary,
3685
+ enhance: params == null ? void 0 : params.enhancePayload
3686
+ });
3687
+ if (!payload.created_at) {
3688
+ payload.created_at = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
3689
+ }
3690
+ payload.need_sync = 0;
3691
+ payload.is_draft_order = 1;
3692
+ this.logInfo("saveTempOrderAsDraft calling sales draft", {
3693
+ orderId: payload.order_id,
3694
+ externalSaleNumber: payload.external_sale_number,
3695
+ productsCount: ((_e = payload.products) == null ? void 0 : _e.length) || 0
3696
+ });
3697
+ return this.request.post("/order/sales/draft", payload, {
3698
+ osServer: true,
3699
+ customToast: () => {
3700
+ }
3701
+ });
3702
+ }
3573
3703
  /**
3574
3704
  * 提交当前 Sales tempOrder。
3575
3705
  *
@@ -3770,8 +3900,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3770
3900
  }
3771
3901
  async syncPaymentsToOrder(params) {
3772
3902
  const tempOrder = this.ensureTempOrder();
3903
+ const needsPaymentNumber = (params.payments || []).some((payment) => String(payment.payment_number || "").trim() === "");
3904
+ const devicePrefix = needsPaymentNumber ? await this.getPaymentNumberDevicePrefixAsync() : "LOCAL";
3773
3905
  const mappedPayments = (0, import_utils.mapPaymentItemsToOrderPayments)(
3774
- params.payments || []
3906
+ (params.payments || []).map((payment) => this.normalizePaymentSource(payment, {
3907
+ defaultPaid: false,
3908
+ devicePrefix
3909
+ }))
3775
3910
  );
3776
3911
  const shouldConfirmPendingVoucherPayments = params.confirmPendingVoucherPayments ?? params.submitWhenPaid === true;
3777
3912
  const effectivePayments = shouldConfirmPendingVoucherPayments ? this.confirmPendingVoucherPaymentsInList(mappedPayments) : params.confirmPendingVoucherPayments === false ? this.discardPendingVoucherPaymentsFromList(mappedPayments) : mappedPayments;
@@ -4107,7 +4242,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4107
4242
  params.forceRemote = false;
4108
4243
  }
4109
4244
  const res = await this.request.get(`/order/sales/${encodeURIComponent(lookup)}`, {
4110
- with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"],
4245
+ with: ["products", "bookings", "payments", "customer", "summary", "contacts_info", "refunds"],
4111
4246
  ...params.forceRemote ? { forceRemote: true } : {}
4112
4247
  }, { osServer: true });
4113
4248
  if (res.code === 200) {
@@ -4153,6 +4288,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4153
4288
  }
4154
4289
  }
4155
4290
  const nextTempOrder = this.normalizeTempOrderForRuntime(raw, { makeEditMark: true });
4291
+ const sourceLastOrderInfo = raw.lastOrderInfo || raw;
4292
+ const isDraftOrder = Number(nextTempOrder.is_draft_order || 0) === 1;
4293
+ const syntheticIdentityOptions = {
4294
+ isDraftOrder,
4295
+ externalSaleNumber: nextTempOrder.external_sale_number
4296
+ };
4156
4297
  const rawSummary = raw.summary && typeof raw.summary === "object" ? raw.summary : {};
4157
4298
  const summarySurcharges = Array.isArray(rawSummary.surcharges) ? rawSummary.surcharges.map((s) => ({ ...s || {} })) : (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []);
4158
4299
  this.store.tempOrder = nextTempOrder;
@@ -4173,7 +4314,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4173
4314
  productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
4174
4315
  }
4175
4316
  };
4176
- this.store.lastOrderInfo = sourceRaw.lastOrderInfo || sourceRaw;
4317
+ this.store.lastOrderInfo = this.withoutSyntheticDraftOrderIdForRuntime(
4318
+ sourceLastOrderInfo,
4319
+ syntheticIdentityOptions
4320
+ );
4321
+ const hadSyntheticDraftOrderId = this.isSyntheticDraftOrderIdForRuntime(raw, syntheticIdentityOptions) || this.isSyntheticDraftOrderIdForRuntime(sourceLastOrderInfo, syntheticIdentityOptions);
4322
+ if (hadSyntheticDraftOrderId && this.store.syncState !== "submitting") {
4323
+ this.store.syncState = "local";
4324
+ }
4177
4325
  const hydratedEditDiscounts = this.collectHydratedEditDiscounts(nextTempOrder.products);
4178
4326
  const currentDiscounts = typeof ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList) === "function" ? this.store.discount.getDiscountList() || [] : [];
4179
4327
  const currentScanDiscounts = currentDiscounts.filter((discount) => discount == null ? void 0 : discount.isScan);
@@ -4286,12 +4434,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4286
4434
  }
4287
4435
  normalizeTempOrderForRuntime(raw, options) {
4288
4436
  var _a, _b;
4437
+ const runtimeRaw = this.withoutSyntheticDraftOrderIdForRuntime(raw);
4289
4438
  const nextTempOrder = {
4290
4439
  ...this.createDefaultTempOrderInstance(),
4291
- ...raw || {}
4440
+ ...runtimeRaw || {}
4292
4441
  };
4293
- if ((nextTempOrder.order_id === void 0 || nextTempOrder.order_id === null) && (raw == null ? void 0 : raw.id) !== void 0 && (raw == null ? void 0 : raw.id) !== null) {
4294
- nextTempOrder.order_id = raw.id;
4442
+ if ((nextTempOrder.order_id === void 0 || nextTempOrder.order_id === null) && (runtimeRaw == null ? void 0 : runtimeRaw.id) !== void 0 && (runtimeRaw == null ? void 0 : runtimeRaw.id) !== null) {
4443
+ nextTempOrder.order_id = runtimeRaw.id;
4295
4444
  }
4296
4445
  delete nextTempOrder.summary;
4297
4446
  delete nextTempOrder.lastOrderInfo;
@@ -4359,6 +4508,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4359
4508
  nextTempOrder.vouchers = raw.vouchers || [];
4360
4509
  return nextTempOrder;
4361
4510
  }
4511
+ isSyntheticDraftOrderIdForRuntime(record, options) {
4512
+ const isDraftOrder = (options == null ? void 0 : options.isDraftOrder) ?? Number((record == null ? void 0 : record.is_draft_order) || 0) === 1;
4513
+ const externalSaleNumber = (record == null ? void 0 : record.external_sale_number) ?? (options == null ? void 0 : options.externalSaleNumber);
4514
+ const orderId = record == null ? void 0 : record.order_id;
4515
+ return Boolean(
4516
+ isDraftOrder && orderId !== void 0 && orderId !== null && orderId !== "" && externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "" && String(orderId) === String(externalSaleNumber)
4517
+ );
4518
+ }
4519
+ withoutSyntheticDraftOrderIdForRuntime(record, options) {
4520
+ if (!this.isSyntheticDraftOrderIdForRuntime(record, options))
4521
+ return record;
4522
+ return {
4523
+ ...record,
4524
+ order_id: null
4525
+ };
4526
+ }
4362
4527
  hydrateLinkedBookingIdentity(tempOrder) {
4363
4528
  const bookingUidByProductUid = /* @__PURE__ */ new Map();
4364
4529
  const productByUid = /* @__PURE__ */ new Map();
@@ -0,0 +1,26 @@
1
+ export type OrderPaymentTransactionStatus = 'success' | 'fail';
2
+ export interface OrderPaymentTransaction {
3
+ number: string;
4
+ status: OrderPaymentTransactionStatus;
5
+ }
6
+ export type OrderPaymentIdentityType = 'order_payment_id' | 'payment_number' | 'unique_payment_number';
7
+ export interface OrderPaymentIdentityMatch<T> {
8
+ index: number;
9
+ payment: T;
10
+ matchedBy: OrderPaymentIdentityType;
11
+ }
12
+ export declare function getOrderPaymentIdentityKeys(payment: unknown): string[];
13
+ export declare function isPendingOrderPayment(payment: unknown): boolean;
14
+ export declare function isIdentifiedPendingOrderPayment(payment: unknown): boolean;
15
+ export declare function hasOrderPaymentIdentityOverlap(left: unknown, right: unknown): boolean;
16
+ export declare function resolveOrderPaymentIdentity<T extends Record<string, any>>(payments: T[] | null | undefined, identity: string | number, mode?: 'payment_number' | 'compat'): OrderPaymentIdentityMatch<T> | null;
17
+ export declare function ensureOrderPaymentNumber<T extends Record<string, any>>(payment: T, devicePrefix: string, createPaymentNumber: () => string): T & {
18
+ payment_number: string;
19
+ };
20
+ export declare function mergeOrderPaymentTransactions(current: unknown, incoming: unknown): OrderPaymentTransaction[];
21
+ export declare function mergeOrderPaymentRecord<T extends Record<string, any>>(payment: T, updates: Record<string, any>): T;
22
+ export declare function mergeOrderPaymentSnapshot<T extends Record<string, any>>(current: T, incoming: T): T;
23
+ export declare function mergeOrderPaymentListsByIdentity<T extends Record<string, any>>(existing: T[] | null | undefined, incoming: T[] | null | undefined, options?: {
24
+ preserveUnmatchedExisting?: boolean;
25
+ preserveUnmatchedExistingWhen?: (payment: T) => boolean;
26
+ }): T[];