@pisell/pisellos 2.2.274 → 2.2.275

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 (117) 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 +1 -1
  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/OpenData/index.d.ts +2 -0
  14. package/dist/modules/OpenData/index.js +8 -0
  15. package/dist/modules/Order/index.d.ts +28 -8
  16. package/dist/modules/Order/index.js +821 -503
  17. package/dist/modules/Order/payment-utils.d.ts +26 -0
  18. package/dist/modules/Order/payment-utils.js +225 -0
  19. package/dist/modules/Order/types.d.ts +35 -1
  20. package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
  21. package/dist/modules/Order/utils.js +10 -6
  22. package/dist/modules/Payment/index.d.ts +2 -0
  23. package/dist/modules/Payment/index.js +78 -49
  24. package/dist/modules/Payment/types.d.ts +104 -25
  25. package/dist/modules/Payment/types.js +17 -0
  26. package/dist/modules/Payment/walletpass.d.ts +38 -1
  27. package/dist/modules/Payment/walletpass.js +917 -114
  28. package/dist/modules/Rules/index.d.ts +3 -0
  29. package/dist/modules/Rules/index.js +100 -70
  30. package/dist/server/index.d.ts +20 -0
  31. package/dist/server/index.js +1955 -1049
  32. package/dist/server/modules/index.d.ts +1 -1
  33. package/dist/server/modules/order/index.d.ts +70 -4
  34. package/dist/server/modules/order/index.js +1816 -728
  35. package/dist/server/modules/order/types.d.ts +25 -3
  36. package/dist/server/modules/order/types.js +7 -1
  37. package/dist/solution/BaseSales/index.d.ts +104 -5
  38. package/dist/solution/BaseSales/index.js +1767 -436
  39. package/dist/solution/BaseSales/types.d.ts +55 -1
  40. package/dist/solution/BaseSales/types.js +2 -1
  41. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  42. package/dist/solution/BaseSales/utils/cartPromotion.js +94 -32
  43. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  44. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -3
  45. package/dist/solution/BookingByStep/index.d.ts +1 -1
  46. package/dist/solution/BookingTicket/index.d.ts +20 -4
  47. package/dist/solution/BookingTicket/index.js +138 -52
  48. package/dist/solution/BookingTicket/types.d.ts +1 -0
  49. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  50. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +173 -83
  51. package/dist/solution/Sales/index.d.ts +2 -0
  52. package/dist/solution/Sales/index.js +26 -4
  53. package/dist/solution/ScanOrder/index.js +31 -20
  54. package/dist/solution/VenueBooking/index.d.ts +1 -0
  55. package/dist/solution/VenueBooking/index.js +30 -19
  56. package/dist/types/index.d.ts +1 -0
  57. package/dist/utils/payment-number.d.ts +9 -0
  58. package/dist/utils/payment-number.js +69 -0
  59. package/lib/core/index.d.ts +2 -0
  60. package/lib/core/index.js +4 -0
  61. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  62. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  63. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  64. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  65. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  66. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  67. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  68. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  69. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  70. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  71. package/lib/modules/OpenData/index.d.ts +2 -0
  72. package/lib/modules/OpenData/index.js +5 -0
  73. package/lib/modules/Order/index.d.ts +28 -8
  74. package/lib/modules/Order/index.js +240 -74
  75. package/lib/modules/Order/payment-utils.d.ts +26 -0
  76. package/lib/modules/Order/payment-utils.js +224 -0
  77. package/lib/modules/Order/types.d.ts +35 -1
  78. package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
  79. package/lib/modules/Order/utils.js +11 -4
  80. package/lib/modules/Payment/index.d.ts +2 -0
  81. package/lib/modules/Payment/index.js +33 -12
  82. package/lib/modules/Payment/types.d.ts +104 -25
  83. package/lib/modules/Payment/types.js +1 -0
  84. package/lib/modules/Payment/walletpass.d.ts +38 -1
  85. package/lib/modules/Payment/walletpass.js +730 -21
  86. package/lib/modules/Rules/index.d.ts +3 -0
  87. package/lib/modules/Rules/index.js +38 -9
  88. package/lib/server/index.d.ts +20 -0
  89. package/lib/server/index.js +684 -24
  90. package/lib/server/modules/index.d.ts +1 -1
  91. package/lib/server/modules/order/index.d.ts +70 -4
  92. package/lib/server/modules/order/index.js +818 -69
  93. package/lib/server/modules/order/types.d.ts +25 -3
  94. package/lib/server/modules/order/types.js +1 -0
  95. package/lib/solution/BaseSales/index.d.ts +104 -5
  96. package/lib/solution/BaseSales/index.js +858 -27
  97. package/lib/solution/BaseSales/types.d.ts +55 -1
  98. package/lib/solution/BaseSales/types.js +2 -1
  99. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  100. package/lib/solution/BaseSales/utils/cartPromotion.js +66 -12
  101. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +20 -4
  105. package/lib/solution/BookingTicket/index.js +63 -9
  106. package/lib/solution/BookingTicket/types.d.ts +1 -0
  107. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  108. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +37 -5
  109. package/lib/solution/Sales/index.d.ts +2 -0
  110. package/lib/solution/Sales/index.js +20 -6
  111. package/lib/solution/ScanOrder/index.js +8 -0
  112. package/lib/solution/VenueBooking/index.d.ts +1 -0
  113. package/lib/solution/VenueBooking/index.js +8 -0
  114. package/lib/types/index.d.ts +1 -0
  115. package/lib/utils/payment-number.d.ts +9 -0
  116. package/lib/utils/payment-number.js +64 -0
  117. 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,
@@ -313,11 +341,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
313
341
  this.store.availableWalletIds = [];
314
342
  }
315
343
  this.request = this.core.getPlugin("request");
316
- const appPlugin = this.core.getPlugin("app");
317
- if (!appPlugin) {
344
+ this.appPlugin = this.core.getPlugin("app");
345
+ if (!this.appPlugin) {
318
346
  throw new Error("Order 模块需要 app 插件支持");
319
347
  }
320
- const app = appPlugin.getApp();
348
+ const app = this.appPlugin.getApp();
321
349
  this.logger = app.logger;
322
350
  this.window = this.core.getPlugin("window");
323
351
  const otherParams = options.otherParams || {};
@@ -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
  };
@@ -1053,17 +1099,40 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1053
1099
  const depositPaidAmount = this.calculateDepositPaidAmount(tempOrder.payments || []);
1054
1100
  return depositPaidAmount.lt(depositAmount) ? "deposit" : "normal";
1055
1101
  }
1102
+ getPaymentNumberAppData(key) {
1103
+ var _a, _b, _c, _d, _e;
1104
+ const appPlugin = this.appPlugin;
1105
+ if (!appPlugin)
1106
+ return void 0;
1107
+ const getData = (_a = appPlugin.getData) == null ? void 0 : _a.call(appPlugin);
1108
+ if (typeof getData === "function")
1109
+ return getData(key);
1110
+ const app = appPlugin.getApp();
1111
+ 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");
1112
+ return coreData == null ? void 0 : coreData[key];
1113
+ }
1114
+ getPaymentNumberDevicePrefixSync() {
1115
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefixFromDeviceId)(
1116
+ (key) => this.getPaymentNumberAppData(key)
1117
+ );
1118
+ }
1119
+ getPaymentNumberDevicePrefixAsync() {
1120
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefix)(
1121
+ (key) => this.getPaymentNumberAppData(key)
1122
+ );
1123
+ }
1056
1124
  normalizePaymentSource(payment, options) {
1057
1125
  const paymentRecord = payment;
1058
1126
  const metadata = paymentRecord.metadata && typeof paymentRecord.metadata === "object" ? { ...paymentRecord.metadata } : {};
1059
- if (!metadata.unique_payment_number) {
1060
- metadata.unique_payment_number = (0, import_utils.createUuidV4)();
1061
- }
1062
- const normalized = {
1063
- ...paymentRecord,
1064
- metadata,
1065
- origin_amount: paymentRecord.origin_amount ?? paymentRecord.amount ?? "0.00"
1066
- };
1127
+ const normalized = (0, import_payment_utils.ensureOrderPaymentNumber)(
1128
+ {
1129
+ ...paymentRecord,
1130
+ metadata,
1131
+ origin_amount: paymentRecord.origin_amount ?? paymentRecord.amount ?? "0.00"
1132
+ },
1133
+ (options == null ? void 0 : options.devicePrefix) || this.getPaymentNumberDevicePrefixSync(),
1134
+ import_utils.createUuidV4
1135
+ );
1067
1136
  if (paymentRecord.status !== void 0) {
1068
1137
  normalized.status = paymentRecord.status;
1069
1138
  } else if ((options == null ? void 0 : options.defaultPaid) !== false) {
@@ -2484,17 +2553,36 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2484
2553
  * 用一组支付来源覆盖当前订单支付项。
2485
2554
  *
2486
2555
  * 入参允许来自 PaymentModule 的 PaymentItem,内部统一映射为 Sales 协议:
2487
- * uuid -> metadata.unique_payment_number,id -> custom_payment_id,
2556
+ * 新支付来源的 uuid 会作为 payment_number 的唯一号段,id -> custom_payment_id,
2488
2557
  * isSynced 等运行态字段不会进入 tempOrder.payments。
2489
2558
  */
2490
2559
  setOrderPayments(payments) {
2491
2560
  const tempOrder = this.ensureTempOrder();
2492
- tempOrder.payments = (0, import_utils.mapPaymentItemsToOrderPayments)(payments);
2561
+ tempOrder.payments = (0, import_utils.mapPaymentItemsToOrderPayments)(
2562
+ (payments || []).map((payment) => this.normalizePaymentSource(payment, { defaultPaid: false }))
2563
+ );
2493
2564
  this.persistTempOrder();
2494
2565
  return tempOrder.payments;
2495
2566
  }
2496
- /** 追加单个支付项,并立即持久化当前 tempOrder。 */
2567
+ /** 同步兼容入口:按调用当下的 device_id 或 LOCAL 生成支付编号。 */
2497
2568
  addOrderPayment(payment) {
2569
+ const hasPaymentNumber = String(
2570
+ payment.payment_number || ""
2571
+ ).trim() !== "";
2572
+ return this.addOrderPaymentWithDevicePrefix(
2573
+ payment,
2574
+ hasPaymentNumber ? "LOCAL" : this.getPaymentNumberDevicePrefixSync()
2575
+ );
2576
+ }
2577
+ /** 异步入口:创建支付项时读取最新 IoT 设备短号。 */
2578
+ async addOrderPaymentAsync(payment) {
2579
+ const hasPaymentNumber = String(
2580
+ payment.payment_number || ""
2581
+ ).trim() !== "";
2582
+ const devicePrefix = hasPaymentNumber ? "LOCAL" : await this.getPaymentNumberDevicePrefixAsync();
2583
+ return this.addOrderPaymentWithDevicePrefix(payment, devicePrefix);
2584
+ }
2585
+ addOrderPaymentWithDevicePrefix(payment, devicePrefix) {
2498
2586
  this.logInfo("addOrderPayment", {
2499
2587
  payment
2500
2588
  });
@@ -2507,7 +2595,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2507
2595
  type: orderPaymentType,
2508
2596
  order_payment_type: orderPaymentType
2509
2597
  },
2510
- { defaultPaid: true }
2598
+ { defaultPaid: true, devicePrefix }
2511
2599
  )
2512
2600
  ]);
2513
2601
  tempOrder.payments = [...tempOrder.payments || [], ...mapped];
@@ -2520,57 +2608,55 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2520
2608
  return tempOrder.payments;
2521
2609
  }
2522
2610
  /**
2523
- * 按支付唯一号、后端支付 ID、自定义支付方式 ID 或旧 uuid 更新支付项。
2524
- *
2525
- * 该方法服务 PaymentModal 的 void / 编辑场景;更新 metadata 时会做浅合并,
2526
- * 避免覆盖 unique_payment_number、现金实付/找零等已有元数据。
2611
+ * 默认按支付唯一号精确更新;仅显式指定 legacy 时兼容历史支付标识。
2612
+ * metadata 与 transactions 会分别合并,避免覆盖支付会话号和已有交易记录。
2527
2613
  */
2528
- updateOrderPayment(paymentIdentity, updates) {
2614
+ async updateOrderPayment(paymentIdentity, updates, options = {}) {
2529
2615
  const tempOrder = this.ensureTempOrder();
2530
2616
  const identity = String(paymentIdentity);
2531
- tempOrder.payments = (tempOrder.payments || []).map((payment) => {
2532
- var _a;
2533
- const uniquePaymentNumber = (_a = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a.unique_payment_number;
2534
- const orderPaymentId = payment == null ? void 0 : payment.order_payment_id;
2535
- const customPaymentId = payment == null ? void 0 : payment.custom_payment_id;
2536
- const uuid = payment == null ? void 0 : payment.uuid;
2537
- const matched = [
2538
- uniquePaymentNumber,
2539
- orderPaymentId,
2540
- customPaymentId,
2541
- uuid
2542
- ].some((value) => value !== void 0 && String(value) === identity);
2543
- if (!matched)
2617
+ const matchMode = options.matchBy === "compat" || options.matchBy === "legacy" ? "compat" : "payment_number";
2618
+ const matchedPayment = (0, import_payment_utils.resolveOrderPaymentIdentity)(
2619
+ tempOrder.payments || [],
2620
+ identity,
2621
+ matchMode
2622
+ );
2623
+ if (!matchedPayment) {
2624
+ throw new Error(`未找到支付项: ${identity}`);
2625
+ }
2626
+ let updatedPayment = null;
2627
+ tempOrder.payments = (tempOrder.payments || []).map((payment, index) => {
2628
+ if (index !== matchedPayment.index)
2544
2629
  return payment;
2545
- return {
2546
- ...payment,
2630
+ const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(payment, {
2547
2631
  ...updates,
2548
- metadata: {
2549
- ...payment.metadata || {},
2550
- ...updates.metadata || {}
2551
- }
2552
- };
2632
+ updated_at: updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
2633
+ });
2634
+ updatedPayment = nextPayment;
2635
+ return nextPayment;
2553
2636
  });
2554
2637
  this.persistTempOrder();
2555
- return tempOrder.payments;
2638
+ const summary = await this.recalculateSummary({ createIfMissing: true });
2639
+ this.persistTempOrder();
2640
+ const payments = tempOrder.payments;
2641
+ return {
2642
+ updated: true,
2643
+ payment: payments[matchedPayment.index] || updatedPayment,
2644
+ payments,
2645
+ summary
2646
+ };
2556
2647
  }
2557
2648
  /** 从当前订单支付项中移除指定支付项。 */
2558
2649
  deleteOrderPayment(paymentIdentity) {
2559
2650
  const tempOrder = this.ensureTempOrder();
2560
2651
  const identity = String(paymentIdentity);
2561
- tempOrder.payments = (tempOrder.payments || []).filter((payment) => {
2562
- var _a;
2563
- const uniquePaymentNumber = (_a = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a.unique_payment_number;
2564
- const orderPaymentId = payment == null ? void 0 : payment.order_payment_id;
2565
- const customPaymentId = payment == null ? void 0 : payment.custom_payment_id;
2566
- const uuid = payment == null ? void 0 : payment.uuid;
2567
- return ![
2568
- uniquePaymentNumber,
2569
- orderPaymentId,
2570
- customPaymentId,
2571
- uuid
2572
- ].some((value) => value !== void 0 && String(value) === identity);
2573
- });
2652
+ const matchedPayment = (0, import_payment_utils.resolveOrderPaymentIdentity)(
2653
+ tempOrder.payments || [],
2654
+ identity,
2655
+ "compat"
2656
+ );
2657
+ if (!matchedPayment)
2658
+ return tempOrder.payments;
2659
+ tempOrder.payments = (tempOrder.payments || []).filter((_, index) => index !== matchedPayment.index);
2574
2660
  this.persistTempOrder();
2575
2661
  return tempOrder.payments;
2576
2662
  }
@@ -2679,7 +2765,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2679
2765
  payments.map(
2680
2766
  (payment) => this.normalizePaymentSource(
2681
2767
  normalizeVoucherPaymentStatus(withVoucherPaymentType(payment)),
2682
- { defaultPaid: false }
2768
+ {
2769
+ defaultPaid: false,
2770
+ devicePrefix: options == null ? void 0 : options.devicePrefix
2771
+ }
2683
2772
  )
2684
2773
  )
2685
2774
  ).filter((payment) => {
@@ -2701,14 +2790,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2701
2790
  const committedVoucherPaymentIds = new Set(
2702
2791
  committedVoucherPayments.filter((payment) => hasSyncedOrderPaymentRecord(payment)).map((payment) => String(payment.order_payment_id))
2703
2792
  );
2704
- const committedVoucherIds = new Set(
2705
- committedVoucherPayments.map((payment) => String(payment.voucher_id))
2793
+ const committedVoucherLifecycleKeys = new Set(
2794
+ committedVoucherPayments.map((payment) => getVoucherPaymentLifecycleKey(payment)).filter((key) => key !== null)
2706
2795
  );
2707
2796
  const replaceableVouchers = mappedVouchers.filter((payment) => {
2708
2797
  if (hasSyncedOrderPaymentRecord(payment) && committedVoucherPaymentIds.has(String(payment.order_payment_id))) {
2709
2798
  return false;
2710
2799
  }
2711
- if (payment.voucher_id !== void 0 && committedVoucherIds.has(String(payment.voucher_id))) {
2800
+ const lifecycleKey = getVoucherPaymentLifecycleKey(payment);
2801
+ if (lifecycleKey && committedVoucherLifecycleKeys.has(lifecycleKey)) {
2712
2802
  return false;
2713
2803
  }
2714
2804
  return true;
@@ -2730,6 +2820,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2730
2820
  });
2731
2821
  return tempOrder.payments;
2732
2822
  }
2823
+ async updateVoucherOrderPaymentsAsync(payments, options) {
2824
+ const needsPaymentNumber = (payments || []).some((payment) => String(payment.payment_number || "").trim() === "");
2825
+ const devicePrefix = needsPaymentNumber ? await this.getPaymentNumberDevicePrefixAsync() : "LOCAL";
2826
+ return this.updateVoucherOrderPayments(payments, {
2827
+ ...options,
2828
+ devicePrefix
2829
+ });
2830
+ }
2733
2831
  async shouldMergeProductToOrder(params) {
2734
2832
  var _a;
2735
2833
  const onBeforeMergeProductToOrder = (_a = this.orderHooks) == null ? void 0 : _a.onBeforeMergeProductToOrder;
@@ -2790,7 +2888,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2790
2888
  * await this.appendProductLineToTempOrder(tempOrder, { product_id: 1, num: 1 }, booking);
2791
2889
  */
2792
2890
  async appendProductLineToTempOrder(tempOrder, product, booking, options) {
2793
- var _a, _b, _c, _d;
2891
+ var _a, _b, _c, _d, _e, _f, _g;
2794
2892
  const linked = booking ? this.createLinkedProductAndBooking({ product, booking }) : null;
2795
2893
  const productToAdd = (linked == null ? void 0 : linked.product) || product;
2796
2894
  const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
@@ -2822,7 +2920,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2822
2920
  );
2823
2921
  const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
2824
2922
  const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
2825
- const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid || isWeighingProduct;
2923
+ const isIncomingCustomItem = ((_e = (_d = productToAdd.metadata) == null ? void 0 : _d.origin) == null ? void 0 : _e.isCustomItem) === true || ((_f = productToAdd._origin) == null ? void 0 : _f.isCustomItem) === true;
2924
+ const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
2826
2925
  const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex((item) => {
2827
2926
  var _a2;
2828
2927
  if (this.hasGoodPassDiscount(item))
@@ -2883,7 +2982,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2883
2982
  }
2884
2983
  } else {
2885
2984
  const targetProduct = matchedProduct;
2886
- const targetUid = (_d = targetProduct.metadata) == null ? void 0 : _d.unique_identification_number;
2985
+ const targetUid = (_g = targetProduct.metadata) == null ? void 0 : _g.unique_identification_number;
2887
2986
  const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
2888
2987
  targetProduct,
2889
2988
  (0, import_utils3.normalizeOrderProduct)({
@@ -3627,6 +3726,38 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3627
3726
  await this.saveDraft();
3628
3727
  return tempOrder;
3629
3728
  }
3729
+ async saveTempOrderAsDraft(params) {
3730
+ var _a, _b, _c, _d, _e;
3731
+ const tempOrder = this.ensureTempOrder();
3732
+ this.ensureExternalSaleNumber(tempOrder);
3733
+ this.persistTempOrder();
3734
+ const latestSummary = await this.recalculateSummary({ createIfMissing: true }) || this.store.summary || (0, import_utils.createEmptySummary)();
3735
+ const payload = (0, import_utils.buildSubmitPayload)({
3736
+ tempOrder,
3737
+ cacheId: (params == null ? void 0 : params.cacheId) ?? this.cacheId,
3738
+ platform: (params == null ? void 0 : params.platform) || ((_a = this.otherParams) == null ? void 0 : _a.platform),
3739
+ 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,
3740
+ channel: params == null ? void 0 : params.channel,
3741
+ type: (params == null ? void 0 : params.type) ?? ((_d = this.otherParams) == null ? void 0 : _d.type),
3742
+ summary: latestSummary,
3743
+ enhance: params == null ? void 0 : params.enhancePayload
3744
+ });
3745
+ if (!payload.created_at) {
3746
+ payload.created_at = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
3747
+ }
3748
+ payload.need_sync = 0;
3749
+ payload.is_draft_order = 1;
3750
+ this.logInfo("saveTempOrderAsDraft calling sales draft", {
3751
+ orderId: payload.order_id,
3752
+ externalSaleNumber: payload.external_sale_number,
3753
+ productsCount: ((_e = payload.products) == null ? void 0 : _e.length) || 0
3754
+ });
3755
+ return this.request.post("/order/sales/draft", payload, {
3756
+ osServer: true,
3757
+ customToast: () => {
3758
+ }
3759
+ });
3760
+ }
3630
3761
  /**
3631
3762
  * 提交当前 Sales tempOrder。
3632
3763
  *
@@ -3827,8 +3958,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3827
3958
  }
3828
3959
  async syncPaymentsToOrder(params) {
3829
3960
  const tempOrder = this.ensureTempOrder();
3961
+ const needsPaymentNumber = (params.payments || []).some((payment) => String(payment.payment_number || "").trim() === "");
3962
+ const devicePrefix = needsPaymentNumber ? await this.getPaymentNumberDevicePrefixAsync() : "LOCAL";
3830
3963
  const mappedPayments = (0, import_utils.mapPaymentItemsToOrderPayments)(
3831
- params.payments || []
3964
+ (params.payments || []).map((payment) => this.normalizePaymentSource(payment, {
3965
+ defaultPaid: false,
3966
+ devicePrefix
3967
+ }))
3832
3968
  );
3833
3969
  const shouldConfirmPendingVoucherPayments = params.confirmPendingVoucherPayments ?? params.submitWhenPaid === true;
3834
3970
  const effectivePayments = shouldConfirmPendingVoucherPayments ? this.confirmPendingVoucherPaymentsInList(mappedPayments) : params.confirmPendingVoucherPayments === false ? this.discardPendingVoucherPaymentsFromList(mappedPayments) : mappedPayments;
@@ -4158,7 +4294,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4158
4294
  params.forceRemote = false;
4159
4295
  }
4160
4296
  const res = await this.request.get(`/order/sales/${encodeURIComponent(lookup)}`, {
4161
- with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"],
4297
+ with: ["products", "bookings", "payments", "customer", "summary", "contacts_info", "refunds"],
4162
4298
  ...params.forceRemote ? { forceRemote: true } : {}
4163
4299
  }, { osServer: true });
4164
4300
  if (res.code === 200) {
@@ -4204,6 +4340,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4204
4340
  }
4205
4341
  }
4206
4342
  const nextTempOrder = this.normalizeTempOrderForRuntime(raw, { makeEditMark: true });
4343
+ const sourceLastOrderInfo = raw.lastOrderInfo || raw;
4344
+ const isDraftOrder = Number(nextTempOrder.is_draft_order || 0) === 1;
4345
+ const syntheticIdentityOptions = {
4346
+ isDraftOrder,
4347
+ externalSaleNumber: nextTempOrder.external_sale_number
4348
+ };
4207
4349
  const rawSummary = raw.summary && typeof raw.summary === "object" ? raw.summary : {};
4208
4350
  const summarySurcharges = Array.isArray(rawSummary.surcharges) ? rawSummary.surcharges.map((s) => ({ ...s || {} })) : (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []);
4209
4351
  this.store.tempOrder = nextTempOrder;
@@ -4224,7 +4366,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4224
4366
  productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
4225
4367
  }
4226
4368
  };
4227
- this.store.lastOrderInfo = sourceRaw.lastOrderInfo || sourceRaw;
4369
+ this.store.lastOrderInfo = this.withoutSyntheticDraftOrderIdForRuntime(
4370
+ sourceLastOrderInfo,
4371
+ syntheticIdentityOptions
4372
+ );
4373
+ const hadSyntheticDraftOrderId = this.isSyntheticDraftOrderIdForRuntime(raw, syntheticIdentityOptions) || this.isSyntheticDraftOrderIdForRuntime(sourceLastOrderInfo, syntheticIdentityOptions);
4374
+ if (hadSyntheticDraftOrderId && this.store.syncState !== "submitting") {
4375
+ this.store.syncState = "local";
4376
+ }
4228
4377
  const hydratedEditDiscounts = this.collectHydratedEditDiscounts(nextTempOrder.products);
4229
4378
  const currentDiscounts = typeof ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList) === "function" ? this.store.discount.getDiscountList() || [] : [];
4230
4379
  const currentScanDiscounts = currentDiscounts.filter((discount) => discount == null ? void 0 : discount.isScan);
@@ -4337,12 +4486,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4337
4486
  }
4338
4487
  normalizeTempOrderForRuntime(raw, options) {
4339
4488
  var _a, _b;
4489
+ const runtimeRaw = this.withoutSyntheticDraftOrderIdForRuntime(raw);
4340
4490
  const nextTempOrder = {
4341
4491
  ...this.createDefaultTempOrderInstance(),
4342
- ...raw || {}
4492
+ ...runtimeRaw || {}
4343
4493
  };
4344
- 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) {
4345
- nextTempOrder.order_id = raw.id;
4494
+ 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) {
4495
+ nextTempOrder.order_id = runtimeRaw.id;
4346
4496
  }
4347
4497
  delete nextTempOrder.summary;
4348
4498
  delete nextTempOrder.lastOrderInfo;
@@ -4410,6 +4560,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4410
4560
  nextTempOrder.vouchers = raw.vouchers || [];
4411
4561
  return nextTempOrder;
4412
4562
  }
4563
+ isSyntheticDraftOrderIdForRuntime(record, options) {
4564
+ const isDraftOrder = (options == null ? void 0 : options.isDraftOrder) ?? Number((record == null ? void 0 : record.is_draft_order) || 0) === 1;
4565
+ const externalSaleNumber = (record == null ? void 0 : record.external_sale_number) ?? (options == null ? void 0 : options.externalSaleNumber);
4566
+ const orderId = record == null ? void 0 : record.order_id;
4567
+ return Boolean(
4568
+ isDraftOrder && orderId !== void 0 && orderId !== null && orderId !== "" && externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "" && String(orderId) === String(externalSaleNumber)
4569
+ );
4570
+ }
4571
+ withoutSyntheticDraftOrderIdForRuntime(record, options) {
4572
+ if (!this.isSyntheticDraftOrderIdForRuntime(record, options))
4573
+ return record;
4574
+ return {
4575
+ ...record,
4576
+ order_id: null
4577
+ };
4578
+ }
4413
4579
  hydrateLinkedBookingIdentity(tempOrder) {
4414
4580
  const bookingUidByProductUid = /* @__PURE__ */ new Map();
4415
4581
  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[];