@pisell/pisellos 2.2.314 → 2.2.315

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 (214) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +3 -1
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  8. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  9. package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
  10. package/dist/modules/BookingContext/utils/productExtend.js +62 -18
  11. package/dist/modules/BookingContext/utils/resources.js +1 -1
  12. package/dist/modules/BusinessAvailability/index.d.ts +30 -0
  13. package/dist/modules/BusinessAvailability/index.js +204 -0
  14. package/dist/modules/Cart/index.js +4 -3
  15. package/dist/modules/Cart/types.d.ts +2 -0
  16. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  17. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  18. package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
  19. package/dist/modules/FulfillmentTiming/index.js +407 -0
  20. package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
  21. package/dist/modules/FulfillmentTiming/types.js +1 -0
  22. package/dist/modules/OpenData/types.d.ts +14 -0
  23. package/dist/modules/Order/index.d.ts +14 -2
  24. package/dist/modules/Order/index.js +856 -486
  25. package/dist/modules/Order/localEftposState.d.ts +13 -0
  26. package/dist/modules/Order/localEftposState.js +39 -0
  27. package/dist/modules/Order/pickupTiming.d.ts +46 -0
  28. package/dist/modules/Order/pickupTiming.js +53 -0
  29. package/dist/modules/Order/types.d.ts +30 -2
  30. package/dist/modules/Order/utils.js +25 -7
  31. package/dist/modules/Payment/index.js +9 -10
  32. package/dist/modules/Product/types.d.ts +11 -0
  33. package/dist/modules/ProductList/index.js +1 -1
  34. package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
  35. package/dist/modules/ResourcePlanner/planner.js +332 -23
  36. package/dist/modules/ResourcePlanner/types.d.ts +29 -0
  37. package/dist/modules/Schedule/index.d.ts +8 -0
  38. package/dist/modules/Schedule/index.js +141 -39
  39. package/dist/modules/index.d.ts +1 -0
  40. package/dist/modules/index.js +1 -0
  41. package/dist/plugins/request.d.ts +7 -0
  42. package/dist/server/index.d.ts +1 -0
  43. package/dist/server/index.js +1536 -1309
  44. package/dist/server/modules/form/index.d.ts +19 -0
  45. package/dist/server/modules/form/index.js +205 -0
  46. package/dist/server/modules/form/types.d.ts +13 -0
  47. package/dist/server/modules/form/types.js +3 -0
  48. package/dist/server/modules/index.d.ts +3 -0
  49. package/dist/server/modules/index.js +4 -0
  50. package/dist/server/modules/order/index.d.ts +15 -0
  51. package/dist/server/modules/order/index.js +920 -688
  52. package/dist/server/modules/order/types.d.ts +1 -0
  53. package/dist/server/test.json +1 -1
  54. package/dist/server/utils/small-ticket.d.ts +1 -85
  55. package/dist/server/utils/small-ticket.js +2 -2542
  56. package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
  57. package/dist/shared/payment/loadPaymentMethods.js +66 -0
  58. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  59. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  60. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  61. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
  62. package/dist/shared/receipt/small-ticket.d.ts +96 -0
  63. package/dist/shared/receipt/small-ticket.js +2751 -0
  64. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  65. package/dist/shared/receipt/templateVisibility.js +64 -0
  66. package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  67. package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
  68. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  69. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  70. package/dist/solution/BaseSales/index.d.ts +39 -16
  71. package/dist/solution/BaseSales/index.js +1754 -1154
  72. package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
  73. package/dist/solution/BaseSales/pickupTiming.js +616 -0
  74. package/dist/solution/BaseSales/types.d.ts +11 -0
  75. package/dist/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  76. package/dist/solution/BookingByStep/index.d.ts +3 -1
  77. package/dist/solution/BookingByStep/index.js +8 -3
  78. package/dist/solution/BookingTicket/index.d.ts +8 -2
  79. package/dist/solution/BookingTicket/index.js +513 -436
  80. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  81. package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
  82. package/dist/solution/BookingTicket/utils/cartView.js +3 -1
  83. package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
  84. package/dist/solution/OrderInvoicePreview/index.js +340 -0
  85. package/dist/solution/RegisterAndLogin/config.js +54 -11
  86. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  87. package/dist/solution/RegisterAndLogin/index.js +1 -1
  88. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  89. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  90. package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  91. package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
  92. package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
  93. package/dist/solution/UnifiedBookingSales/index.js +1714 -905
  94. package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
  95. package/dist/solution/VenueBooking/index.d.ts +15 -2
  96. package/dist/solution/VenueBooking/index.js +1062 -785
  97. package/dist/solution/VenueBooking/types.d.ts +2 -1
  98. package/dist/solution/VenueBooking/types.js +1 -0
  99. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  100. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  101. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  102. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  103. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  104. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  105. package/dist/solution/index.d.ts +1 -0
  106. package/dist/solution/index.js +2 -1
  107. package/lib/index.d.ts +2 -0
  108. package/lib/index.js +21 -1
  109. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  110. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  111. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  112. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  113. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  114. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  115. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  116. package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
  117. package/lib/modules/BookingContext/utils/productExtend.js +45 -2
  118. package/lib/modules/BookingContext/utils/resources.js +1 -1
  119. package/lib/modules/BusinessAvailability/index.d.ts +30 -0
  120. package/lib/modules/BusinessAvailability/index.js +146 -0
  121. package/lib/modules/Cart/index.js +4 -2
  122. package/lib/modules/Cart/types.d.ts +2 -0
  123. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  124. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  125. package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
  126. package/lib/modules/FulfillmentTiming/index.js +359 -0
  127. package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
  128. package/lib/modules/FulfillmentTiming/types.js +5 -0
  129. package/lib/modules/OpenData/types.d.ts +14 -0
  130. package/lib/modules/Order/index.d.ts +14 -2
  131. package/lib/modules/Order/index.js +240 -38
  132. package/lib/modules/Order/localEftposState.d.ts +13 -0
  133. package/lib/modules/Order/localEftposState.js +44 -0
  134. package/lib/modules/Order/pickupTiming.d.ts +46 -0
  135. package/lib/modules/Order/pickupTiming.js +61 -0
  136. package/lib/modules/Order/types.d.ts +30 -2
  137. package/lib/modules/Order/utils.js +21 -5
  138. package/lib/modules/Payment/index.js +3 -4
  139. package/lib/modules/Product/types.d.ts +11 -0
  140. package/lib/modules/ProductList/index.js +1 -1
  141. package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
  142. package/lib/modules/ResourcePlanner/planner.js +252 -8
  143. package/lib/modules/ResourcePlanner/types.d.ts +29 -0
  144. package/lib/modules/Schedule/index.d.ts +8 -0
  145. package/lib/modules/Schedule/index.js +68 -12
  146. package/lib/modules/index.d.ts +1 -0
  147. package/lib/modules/index.js +11 -0
  148. package/lib/plugins/request.d.ts +7 -0
  149. package/lib/server/index.d.ts +1 -0
  150. package/lib/server/index.js +158 -37
  151. package/lib/server/modules/form/index.d.ts +19 -0
  152. package/lib/server/modules/form/index.js +73 -0
  153. package/lib/server/modules/form/types.d.ts +13 -0
  154. package/lib/server/modules/form/types.js +9 -0
  155. package/lib/server/modules/index.d.ts +3 -0
  156. package/lib/server/modules/index.js +15 -1
  157. package/lib/server/modules/order/index.d.ts +15 -0
  158. package/lib/server/modules/order/index.js +114 -3
  159. package/lib/server/modules/order/types.d.ts +1 -0
  160. package/lib/server/test.json +1 -1
  161. package/lib/server/utils/small-ticket.d.ts +1 -85
  162. package/lib/server/utils/small-ticket.js +9 -2305
  163. package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
  164. package/lib/shared/payment/loadPaymentMethods.js +40 -0
  165. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  166. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  167. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  168. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
  169. package/lib/shared/receipt/small-ticket.d.ts +96 -0
  170. package/lib/shared/receipt/small-ticket.js +2546 -0
  171. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  172. package/lib/shared/receipt/templateVisibility.js +63 -0
  173. package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  174. package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
  175. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  176. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  177. package/lib/solution/BaseSales/index.d.ts +39 -16
  178. package/lib/solution/BaseSales/index.js +333 -31
  179. package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
  180. package/lib/solution/BaseSales/pickupTiming.js +290 -0
  181. package/lib/solution/BaseSales/types.d.ts +11 -0
  182. package/lib/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  183. package/lib/solution/BookingByStep/index.d.ts +3 -1
  184. package/lib/solution/BookingByStep/index.js +7 -3
  185. package/lib/solution/BookingTicket/index.d.ts +8 -2
  186. package/lib/solution/BookingTicket/index.js +65 -6
  187. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  188. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
  189. package/lib/solution/BookingTicket/utils/cartView.js +3 -1
  190. package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
  191. package/lib/solution/OrderInvoicePreview/index.js +246 -0
  192. package/lib/solution/RegisterAndLogin/config.js +57 -11
  193. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  194. package/lib/solution/RegisterAndLogin/index.js +9 -1
  195. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  196. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  197. package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  198. package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
  199. package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
  200. package/lib/solution/UnifiedBookingSales/index.js +561 -74
  201. package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
  202. package/lib/solution/VenueBooking/index.d.ts +15 -2
  203. package/lib/solution/VenueBooking/index.js +243 -96
  204. package/lib/solution/VenueBooking/types.d.ts +2 -1
  205. package/lib/solution/VenueBooking/types.js +1 -0
  206. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  207. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  208. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  209. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  210. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  211. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  212. package/lib/solution/index.d.ts +1 -0
  213. package/lib/solution/index.js +11 -0
  214. package/package.json +1 -1
@@ -4,11 +4,20 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.OrderModule = void 0;
7
+ Object.defineProperty(exports, "isFulfillmentTimingBooking", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _pickupTiming.isFulfillmentTimingBooking;
11
+ }
12
+ });
13
+ var _loadSalesOrderSnapshot = require("../../shared/sales/loadSalesOrderSnapshot");
14
+ var _localEftposState = require("./localEftposState");
7
15
  var _BaseModule = require("../BaseModule");
8
16
  var _types = require("./types");
9
17
  var _utils = require("./utils");
10
18
  var _utils2 = require("../Product/utils");
11
19
  var _weighedProduct = require("./utils/weighedProduct");
20
+ var _pickupTiming = require("./pickupTiming");
12
21
  var _dayjs = _interopRequireDefault(require("dayjs"));
13
22
  var _availability = require("../Discount/availability");
14
23
  var _osPrivatePayload = require("../../utils/os-private-payload");
@@ -433,6 +442,29 @@ class OrderModule extends _BaseModule.BaseModule {
433
442
  this.otherParams = otherParams;
434
443
  }
435
444
 
445
+ /** Internal intent boundary shared with asynchronous scanner/detail flows. */
446
+ createCartIntentCommitGuard(action, tempOrder = this.store.tempOrder) {
447
+ const hook = this.orderHooks?.beforeCartIntentCommit;
448
+ if (!hook) return () => {};
449
+ const getScope = this.orderHooks?.getCartIntentScope;
450
+ const scope = getScope?.();
451
+ const otherParams = this.otherParams;
452
+ let committed = false;
453
+ return () => {
454
+ if (this.store.tempOrder !== tempOrder || this.otherParams !== otherParams || this.orderHooks?.beforeCartIntentCommit !== hook || this.orderHooks?.getCartIntentScope !== getScope || getScope?.() !== scope) {
455
+ throw new Error('[Order] Cart intent belongs to a previous order or business');
456
+ }
457
+ // Derived gifts, discounts and persistence belong to the accepted intent,
458
+ // but an asynchronous continuation must never target a different cart.
459
+ if (committed) return;
460
+ hook({
461
+ action,
462
+ tempOrder
463
+ });
464
+ committed = true;
465
+ };
466
+ }
467
+
436
468
  /** PC/H5 属于在线店铺;其它或缺失平台统一沿用 POS 行为。 */
437
469
  isOnlineStorePlatform() {
438
470
  const platform = String(this.otherParams?.platform || '').trim().toLowerCase();
@@ -661,6 +693,7 @@ class OrderModule extends _BaseModule.BaseModule {
661
693
  });
662
694
  }
663
695
  async scanCode(code, customerId) {
696
+ const beforeCommit = this.createCartIntentCommitGuard('scan_promotion');
664
697
  if (this.isActiveVirtualSettlementOrder(this.store.tempOrder)) {
665
698
  return {
666
699
  type: 'clientCalc',
@@ -708,6 +741,7 @@ class OrderModule extends _BaseModule.BaseModule {
708
741
  }));
709
742
  const currentSelected = this.getDiscountList().filter(n => n.isSelected);
710
743
  if (currentSelected.length && currentSelected.some(n => withScanList.some(m => m.id === n.id))) {
744
+ beforeCommit();
711
745
  await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
712
746
  return {
713
747
  type: 'clientCalc',
@@ -741,6 +775,7 @@ class OrderModule extends _BaseModule.BaseModule {
741
775
  const normalizedNewDiscountList = newDiscountList ? markScannedDiscounts(newDiscountList, withScanList) : undefined;
742
776
  let resolvedDiscountList = normalizedNewDiscountList || this.getDiscountList();
743
777
  if (isAvailable && normalizedNewDiscountList) {
778
+ beforeCommit();
744
779
  await this.store.discount?.setDiscountList(normalizedNewDiscountList);
745
780
  // 实际写回商品时沿用扫码试算的优先级,避免旧商品行的选卡覆盖本次扫码。
746
781
  this.applyDiscount({
@@ -749,6 +784,7 @@ class OrderModule extends _BaseModule.BaseModule {
749
784
  await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
750
785
  resolvedDiscountList = this.getDiscountList();
751
786
  } else if (shouldRetainForLater) {
787
+ beforeCommit();
752
788
  // 只合并本次识别的卡券;不把试算产生的其他选券状态写回订单。
753
789
  const retainedDiscounts = new Map(this.getDiscountList().map(discount => [String(discount.id), discount]));
754
790
  evaluatedScannedDiscounts.forEach(discount => {
@@ -878,7 +914,8 @@ class OrderModule extends _BaseModule.BaseModule {
878
914
  * - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进;
879
915
  * - 返回的 payload 只能在 applyDiscount(商品写路径还需 summary/persist)完成后发布。
880
916
  */
881
- async evaluatePromotion() {
917
+ async evaluatePromotion(options) {
918
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
882
919
  if (this.isApplyingPromotion || this.isEmittingPromotionApplied) {
883
920
  return null;
884
921
  }
@@ -939,6 +976,10 @@ class OrderModule extends _BaseModule.BaseModule {
939
976
  continue;
940
977
  }
941
978
  }
979
+ const giftMutationBaseline = options?.isCurrentOrder ? (0, _lodashEs.cloneDeep)({
980
+ products: tempOrder.products,
981
+ bookings: tempOrder.bookings
982
+ }) : null;
942
983
  try {
943
984
  const giftResult = await this.giftSelectResolver({
944
985
  strategyId: addAction.strategyId,
@@ -947,6 +988,11 @@ class OrderModule extends _BaseModule.BaseModule {
947
988
  giftOptions: addAction.giftOptions,
948
989
  sourceProductIds: addAction.sourceProductIds
949
990
  });
991
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
992
+ if (options?.isCurrentOrder && !(0, _lodashEs.isEqual)({
993
+ products: tempOrder.products,
994
+ bookings: tempOrder.bookings
995
+ }, giftMutationBaseline)) return null;
950
996
  const giftProducts = Array.isArray(giftResult) ? giftResult : giftResult?.products;
951
997
  const giftBookings = Array.isArray(giftResult) ? [] : giftResult?.bookings || [];
952
998
  if (Array.isArray(giftProducts) && giftProducts.length > 0) {
@@ -967,12 +1013,18 @@ class OrderModule extends _BaseModule.BaseModule {
967
1013
  }
968
1014
  }
969
1015
  } catch (error) {
1016
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
1017
+ if (options?.isCurrentOrder && !(0, _lodashEs.isEqual)({
1018
+ products: tempOrder.products,
1019
+ bookings: tempOrder.bookings
1020
+ }, giftMutationBaseline)) return null;
970
1021
  // 用户取消 / 选择失败 → 视为放弃本次新增
971
1022
  console.warn('[OrderModule] giftSelectResolver rejected, skip add gift', addAction.strategyId, error);
972
1023
  }
973
1024
  }
974
1025
  }
975
1026
  }
1027
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
976
1028
  tempOrder.products = result.products;
977
1029
  this.lastUnfulfilledPromotions = result.unfulfilledPromotions;
978
1030
  this.lastGiftActions = result.giftActions;
@@ -2275,6 +2327,7 @@ class OrderModule extends _BaseModule.BaseModule {
2275
2327
  const bookingByBookingUid = new Map();
2276
2328
  bookings.forEach(booking => {
2277
2329
  if (!booking || typeof booking !== 'object') return;
2330
+ if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) return;
2278
2331
  const productUid = booking.product_uid || booking.metadata?.product_uid;
2279
2332
  if (productUid !== undefined && productUid !== null && String(productUid) !== '') {
2280
2333
  bookingByProductUid.set(String(productUid), booking);
@@ -2325,6 +2378,7 @@ class OrderModule extends _BaseModule.BaseModule {
2325
2378
  let baseHolder = null;
2326
2379
  const seen = new Set();
2327
2380
  for (const booking of tempOrder.bookings || []) {
2381
+ if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) continue;
2328
2382
  const holder = booking?.holder && typeof booking.holder === 'object' ? booking.holder : null;
2329
2383
  if (!baseHolder && holder) {
2330
2384
  baseHolder = holder;
@@ -2365,7 +2419,7 @@ class OrderModule extends _BaseModule.BaseModule {
2365
2419
  * this.syncTempOrderHolderFromBookings(tempOrder);
2366
2420
  */
2367
2421
  syncTempOrderHolderFromBookings(tempOrder) {
2368
- const bookings = tempOrder.bookings || [];
2422
+ const bookings = (tempOrder.bookings || []).filter(booking => !(0, _pickupTiming.isFulfillmentTimingBooking)(booking));
2369
2423
  const hasHolderSource = bookings.some(booking => {
2370
2424
  return booking?.holder !== undefined || booking?.metadata?.holder_id !== undefined;
2371
2425
  });
@@ -2390,6 +2444,7 @@ class OrderModule extends _BaseModule.BaseModule {
2390
2444
  const bookingUid = product?.booking_uid || product?.metadata?.booking_uid;
2391
2445
  if (!productUid && !bookingUid) return;
2392
2446
  tempOrder.bookings = (tempOrder.bookings || []).filter(booking => {
2447
+ if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) return true;
2393
2448
  const currentBookingUid = this.getBookingUniqueIdentificationNumber(booking);
2394
2449
  if (bookingUid && currentBookingUid === String(bookingUid)) return false;
2395
2450
  if (productUid && String(booking?.product_uid || '') === String(productUid)) return false;
@@ -2431,6 +2486,7 @@ class OrderModule extends _BaseModule.BaseModule {
2431
2486
  return shouldUseManualDepositOverride ? nextSummary : this.applyLastOrderDepositSnapshot(tempOrder, nextSummary);
2432
2487
  }
2433
2488
  async recalculateSummary(options) {
2489
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
2434
2490
  const tempOrder = options?.createIfMissing ? this.ensureTempOrder() : this.store.tempOrder;
2435
2491
  if (!tempOrder) return null;
2436
2492
  this.sanitizeTempOrderProducts(tempOrder);
@@ -2440,7 +2496,7 @@ class OrderModule extends _BaseModule.BaseModule {
2440
2496
  const snapshotSummary = shouldReuseOriginalSnapshot ? this.restoreOriginalSnapshotIfProductsUnchanged(tempOrder, originalSnapshot) : null;
2441
2497
  if (snapshotSummary) return snapshotSummary;
2442
2498
  const shouldFullRecalculateFromSnapshot = Boolean(originalSnapshot);
2443
- const summaryProducts = shouldFullRecalculateFromSnapshot ? (0, _lodashEs.cloneDeep)(tempOrder.products || []) : tempOrder.products;
2499
+ const summaryProducts = shouldFullRecalculateFromSnapshot || options?.isCurrentOrder ? (0, _lodashEs.cloneDeep)(tempOrder.products || []) : tempOrder.products;
2444
2500
  if (shouldFullRecalculateFromSnapshot) {
2445
2501
  this.clearPersistedAmountFieldsForFullRecalc(summaryProducts || []);
2446
2502
  }
@@ -2478,6 +2534,10 @@ class OrderModule extends _BaseModule.BaseModule {
2478
2534
  });
2479
2535
  return this.store.summary;
2480
2536
  }
2537
+ const summaryMutationBaseline = options?.isCurrentOrder ? (0, _lodashEs.cloneDeep)({
2538
+ tempOrder,
2539
+ summary: this.store.summary
2540
+ }) : null;
2481
2541
  const salesSummaryResult = await salesSummary.getSummary({
2482
2542
  products: summaryProducts,
2483
2543
  isPriceIncludeTax: tempOrder.is_price_include_tax,
@@ -2487,7 +2547,12 @@ class OrderModule extends _BaseModule.BaseModule {
2487
2547
  channel: this.otherParams.channel
2488
2548
  } : {})
2489
2549
  });
2490
- if (shouldFullRecalculateFromSnapshot) {
2550
+ if (options?.isCurrentOrder && !options.isCurrentOrder()) return null;
2551
+ if (options?.isCurrentOrder && !(0, _lodashEs.isEqual)({
2552
+ tempOrder,
2553
+ summary: this.store.summary
2554
+ }, summaryMutationBaseline)) return null;
2555
+ if (shouldFullRecalculateFromSnapshot || options?.isCurrentOrder) {
2491
2556
  tempOrder.products = summaryProducts;
2492
2557
  }
2493
2558
  this.syncSummaryProductMetadata(tempOrder.products || []);
@@ -2803,10 +2868,33 @@ class OrderModule extends _BaseModule.BaseModule {
2803
2868
  });
2804
2869
  }
2805
2870
  updateTempOrderServiceType(serviceType) {
2871
+ if (serviceType !== 'pick_up') {
2872
+ const tempOrder = this.ensureTempOrder();
2873
+ tempOrder.bookings = (tempOrder.bookings || []).filter(booking => !(0, _pickupTiming.isFulfillmentTimingBooking)(booking));
2874
+ }
2806
2875
  return this.updateTempOrderShopServiceData({
2807
2876
  service_type: serviceType
2808
2877
  });
2809
2878
  }
2879
+ getPickupTimingBooking() {
2880
+ return (this.store.tempOrder?.bookings || []).find(_pickupTiming.isFulfillmentTimingBooking) || null;
2881
+ }
2882
+ setPickupTimingBooking(input) {
2883
+ const tempOrder = this.ensureTempOrder();
2884
+ const bookings = tempOrder.bookings || [];
2885
+ const firstIndex = bookings.findIndex(_pickupTiming.isFulfillmentTimingBooking);
2886
+ const nextBooking = (0, _pickupTiming.buildPickupTimingBooking)(input, bookings[firstIndex]);
2887
+ // Keep the first row's identity and position; repair duplicate marked rows only.
2888
+ tempOrder.bookings = firstIndex === -1 ? [...bookings, nextBooking] : bookings.flatMap((booking, index) => index === firstIndex ? [nextBooking] : (0, _pickupTiming.isFulfillmentTimingBooking)(booking) ? [] : [booking]);
2889
+ this.notifyTempOrderChanged();
2890
+ return nextBooking;
2891
+ }
2892
+ clearPickupTimingBooking() {
2893
+ const tempOrder = this.store.tempOrder;
2894
+ if (!tempOrder?.bookings?.some(_pickupTiming.isFulfillmentTimingBooking)) return;
2895
+ tempOrder.bookings = tempOrder.bookings.filter(booking => !(0, _pickupTiming.isFulfillmentTimingBooking)(booking));
2896
+ this.notifyTempOrderChanged();
2897
+ }
2810
2898
  updateTempOrderContactsInfo(contactsInfo) {
2811
2899
  const tempOrder = this.ensureTempOrder();
2812
2900
  tempOrder.contacts_info = contactsInfo && typeof contactsInfo === 'object' && !Array.isArray(contactsInfo) ? contactsInfo : null;
@@ -3086,6 +3174,18 @@ class OrderModule extends _BaseModule.BaseModule {
3086
3174
  const matchMode = options.matchBy === 'compat' || options.matchBy === 'legacy' ? 'compat' : 'payment_number';
3087
3175
  const matchedPayment = (0, _paymentUtils.resolveOrderPaymentIdentity)(tempOrder.payments || [], identity, matchMode);
3088
3176
  if (!matchedPayment) {
3177
+ try {
3178
+ void Promise.resolve(this.logger?.addLog?.({
3179
+ type: 'warning',
3180
+ title: '[PaymentTrace] payment-missing',
3181
+ metadata: {
3182
+ moduleName: this.name,
3183
+ saleId: tempOrder.external_sale_number,
3184
+ paymentNumber: identity,
3185
+ currentPaymentNumbers: (tempOrder.payments || []).map(p => p.payment_number)
3186
+ }
3187
+ })).catch(() => {});
3188
+ } catch {/* 日志失败不影响原异常。 */}
3089
3189
  throw new Error(`未找到支付项: ${identity}`);
3090
3190
  }
3091
3191
  let updatedPayment = null;
@@ -3393,20 +3493,30 @@ class OrderModule extends _BaseModule.BaseModule {
3393
3493
  * await this.finalizeProductOrderMutation(tempOrder);
3394
3494
  */
3395
3495
  async finalizeProductOrderMutation(tempOrder, options) {
3496
+ const isCurrentOrder = options?.isCurrentOrder;
3497
+ if (isCurrentOrder && !isCurrentOrder()) return;
3396
3498
  this.syncTempOrderHolderFromBookings(tempOrder);
3397
3499
  this.prepareVirtualSettlementTempOrder(tempOrder);
3398
3500
  const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
3399
3501
  if (!options?.skipEditDiscountConfigRefresh && !isVirtualSettlement) {
3400
3502
  await this.ensureEditDiscountConfigForProductChange(tempOrder);
3401
3503
  }
3402
- const promotionPayload = !options?.skipDiscountRecalculation && !isVirtualSettlement ? await this.evaluatePromotion() : null;
3504
+ if (isCurrentOrder && !isCurrentOrder()) return;
3505
+ const promotionPayload = !options?.skipDiscountRecalculation && !isVirtualSettlement ? await this.evaluatePromotion(isCurrentOrder ? {
3506
+ isCurrentOrder
3507
+ } : undefined) : null;
3508
+ if (isCurrentOrder && !isCurrentOrder()) return;
3403
3509
  if (!options?.skipDiscountRecalculation && !isVirtualSettlement) {
3404
3510
  this.applyDiscount();
3405
3511
  }
3406
3512
  this.sanitizeTempOrderProducts(tempOrder);
3407
- await this.recalculateSummary({
3408
- createIfMissing: true
3513
+ const summary = await this.recalculateSummary({
3514
+ createIfMissing: true,
3515
+ ...(isCurrentOrder ? {
3516
+ isCurrentOrder
3517
+ } : {})
3409
3518
  });
3519
+ if (isCurrentOrder && (!isCurrentOrder() || !summary)) return;
3410
3520
  this.persistTempOrder();
3411
3521
  this.emitPromotionApplied(promotionPayload);
3412
3522
  }
@@ -3429,7 +3539,6 @@ class OrderModule extends _BaseModule.BaseModule {
3429
3539
  booking
3430
3540
  }) : null;
3431
3541
  const productToAdd = linked?.product || product;
3432
- this.assertAndLockProductSettlement(tempOrder, productToAdd);
3433
3542
  const disableMerge = options?.disableMerge === true;
3434
3543
  const incomingFingerprint = disableMerge ? '' : (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(productToAdd), productToAdd.product_bundle);
3435
3544
  const normalizedIncoming = this.normalizeVirtualSettlementProductIfEnabled((0, _utils.mergeOrderProductDisplayFields)(productToAdd, (0, _utils3.normalizeOrderProduct)(productToAdd)));
@@ -3491,6 +3600,8 @@ class OrderModule extends _BaseModule.BaseModule {
3491
3600
  const matchedProduct = matchedIndex === -1 ? null : tempOrder.products[matchedIndex];
3492
3601
  const existedFingerprint = matchedProduct ? (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(matchedProduct), matchedProduct.product_bundle) : '';
3493
3602
  const commitProductLine = shouldMerge => {
3603
+ options?.beforeCommit?.();
3604
+ this.assertAndLockProductSettlement(tempOrder, productToAdd);
3494
3605
  let committedProduct;
3495
3606
  if (matchedIndex === -1 || !matchedProduct || !shouldMerge) {
3496
3607
  this.captureProductRuntime(tempOrder, productToAdd, normalizedIncoming);
@@ -3642,7 +3753,16 @@ class OrderModule extends _BaseModule.BaseModule {
3642
3753
  * // → tempOrder.products 新增 3 行,每行 num=1,bookings 3 条
3643
3754
  */
3644
3755
  async addProductToOrder(product, booking, options) {
3645
- const tempOrder = this.ensureTempOrder();
3756
+ const availabilityCommitGuard = options?.availabilityCommitGuard;
3757
+ availabilityCommitGuard?.();
3758
+ const liveTempOrder = this.ensureTempOrder();
3759
+ const beforeCommit = this.createCartIntentCommitGuard('add_product', liveTempOrder);
3760
+ // 自动预约在草稿上准备完整批次,避免拆票期间暴露半成品,或在失败时
3761
+ // 用整单快照回滚而抹掉其他入口的并发修改。人工路径保持原有写入行为。
3762
+ const tempOrder = availabilityCommitGuard ? (0, _lodashEs.cloneDeep)(liveTempOrder) : liveTempOrder;
3763
+ const guardedMutationFields = ['products', 'bookings', 'notes', '_extend', 'metadata', 'currency_code', 'currency_symbol', 'currency_format'];
3764
+ const readGuardedMutationFields = order => Object.fromEntries(guardedMutationFields.map(key => [key, order[key]]));
3765
+ const guardedMutationBaseline = availabilityCommitGuard ? (0, _lodashEs.cloneDeep)(readGuardedMutationFields(liveTempOrder)) : null;
3646
3766
  const salesNoteDrafts = (options?.salesNotes || []).map(draft => ({
3647
3767
  note_type: String(draft.note_type || '').trim(),
3648
3768
  text: {
@@ -3685,7 +3805,7 @@ class OrderModule extends _BaseModule.BaseModule {
3685
3805
  const uid = line.metadata?.unique_identification_number || line.unique_identification_number;
3686
3806
  return uid !== undefined && uid !== null && String(uid) === String(insertAfterProductUid);
3687
3807
  }) : -1;
3688
- let insertAtIndex = anchorIndex >= 0 ? anchorIndex + 1 : undefined;
3808
+ let insertAtIndex = options?.insertAtStart ? 0 : anchorIndex >= 0 ? anchorIndex + 1 : undefined;
3689
3809
  try {
3690
3810
  if (booking) {
3691
3811
  const productRecord = product;
@@ -3713,35 +3833,76 @@ class OrderModule extends _BaseModule.BaseModule {
3713
3833
  }
3714
3834
  const committedProduct = await this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking, {
3715
3835
  insertAtIndex,
3716
- disableMerge: options?.disableMerge
3836
+ disableMerge: options?.disableMerge,
3837
+ beforeCommit
3717
3838
  });
3839
+ availabilityCommitGuard?.();
3718
3840
  attachSalesNoteDrafts(committedProduct);
3719
3841
  if (insertAtIndex !== undefined) insertAtIndex += 1;
3720
3842
  }
3721
3843
  } else {
3722
3844
  const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, (0, _lodashEs.cloneDeep)(booking), {
3723
3845
  insertAtIndex,
3724
- disableMerge: options?.disableMerge
3846
+ disableMerge: options?.disableMerge,
3847
+ beforeCommit
3725
3848
  });
3849
+ availabilityCommitGuard?.();
3726
3850
  attachSalesNoteDrafts(committedProduct);
3727
3851
  }
3728
3852
  } else {
3729
3853
  const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, undefined, {
3730
3854
  insertAtIndex,
3731
- disableMerge: options?.disableMerge
3855
+ disableMerge: options?.disableMerge,
3856
+ beforeCommit
3732
3857
  });
3858
+ availabilityCommitGuard?.();
3733
3859
  attachSalesNoteDrafts(committedProduct);
3734
3860
  }
3861
+ if (availabilityCommitGuard) {
3862
+ availabilityCommitGuard();
3863
+ beforeCommit();
3864
+ // 调用方的结构 revision 可能不包括备注、价格或结算元数据。
3865
+ // 本次会覆盖的字段也要保持原值,不能让草稿覆盖并发编辑。
3866
+ if (!(0, _lodashEs.isEqual)(readGuardedMutationFields(liveTempOrder), guardedMutationBaseline)) {
3867
+ throw Object.assign(new Error('预约加购期间订单已变化,请重新选择'), {
3868
+ code: 'AVAILABILITY_SELECTION_STALE'
3869
+ });
3870
+ }
3871
+ // 从最后一次门禁到真正新增之间不再 await。只发布本次新增会改写的
3872
+ // 字段;其余订单字段继续使用 live 对象,外部持有的订单引用也不变。
3873
+ Object.assign(liveTempOrder, readGuardedMutationFields(tempOrder));
3874
+ }
3735
3875
  } catch (error) {
3736
3876
  rollbackProductAndNotesMutation();
3737
3877
  throw error;
3738
3878
  }
3739
- await this.finalizeProductOrderMutation(tempOrder);
3879
+ // 发布后预约已加购;后续促销/summary 沿用既有收尾,不用自身新增后的
3880
+ // revision 再执行提交 CAS,也不会把已加购预约因收尾耗时而撤回。
3881
+ if (availabilityCommitGuard) {
3882
+ const committedIdentity = [liveTempOrder.order_id, liveTempOrder.external_sale_number];
3883
+ const isCurrentOrder = () => this.store.tempOrder === liveTempOrder && liveTempOrder.order_id === committedIdentity[0] && liveTempOrder.external_sale_number === committedIdentity[1] && (options?.availabilityCommitTargetGuard?.() ?? true);
3884
+ try {
3885
+ // 新增已发布,即使后续报价/促销收尾失败,也不能向调用方报告未加购。
3886
+ // 先保存已提交行;异步结果只允许写回仍属于本次提交的订单。
3887
+ if (isCurrentOrder()) this.persistTempOrder();
3888
+ await this.finalizeProductOrderMutation(liveTempOrder, {
3889
+ isCurrentOrder
3890
+ });
3891
+ } catch (error) {
3892
+ this.logWarning('addProductToOrder committed; finalization failed', {
3893
+ product_id: product.product_id,
3894
+ committed: true,
3895
+ error: error instanceof Error ? error.message : String(error)
3896
+ });
3897
+ }
3898
+ } else {
3899
+ await this.finalizeProductOrderMutation(liveTempOrder);
3900
+ }
3740
3901
  this.logInfo('addProductToOrder success', {
3741
3902
  product_id: product.product_id,
3742
3903
  with_booking: !!booking
3743
3904
  });
3744
- return tempOrder.products;
3905
+ return liveTempOrder.products;
3745
3906
  }
3746
3907
 
3747
3908
  /**
@@ -3756,6 +3917,7 @@ class OrderModule extends _BaseModule.BaseModule {
3756
3917
  async addProductsToOrder(items, options) {
3757
3918
  const tempOrder = this.ensureTempOrder();
3758
3919
  if (!Array.isArray(items) || items.length === 0) return tempOrder.products;
3920
+ const beforeCommit = this.createCartIntentCommitGuard('add_product', tempOrder);
3759
3921
  for (const item of items || []) {
3760
3922
  const {
3761
3923
  product,
@@ -3768,13 +3930,17 @@ class OrderModule extends _BaseModule.BaseModule {
3768
3930
  if (splitCount > 1) {
3769
3931
  for (let i = 0; i < splitCount; i += 1) {
3770
3932
  const splitLine = this.createSplitBookingLine(productRecord, booking, i, splitCount);
3771
- const appendResult = this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking);
3933
+ const appendResult = this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking, {
3934
+ beforeCommit
3935
+ });
3772
3936
  if (appendResult) await appendResult;
3773
3937
  }
3774
3938
  continue;
3775
3939
  }
3776
3940
  }
3777
- const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking);
3941
+ const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking, {
3942
+ beforeCommit
3943
+ });
3778
3944
  if (appendResult) await appendResult;
3779
3945
  }
3780
3946
  await this.finalizeProductOrderMutation(tempOrder, options);
@@ -3859,6 +4025,16 @@ class OrderModule extends _BaseModule.BaseModule {
3859
4025
  };
3860
4026
  });
3861
4027
  }
4028
+ isRestrictedCartProductUpdate(tempOrder, params) {
4029
+ if (!this.orderHooks?.beforeCartIntentCommit) return false;
4030
+ if (params.booking || Object.keys(params.updates || {}).some(key => key !== 'num')) {
4031
+ return true;
4032
+ }
4033
+ if (params.updates?.num === undefined) return false;
4034
+ const uid = params.unique_identification_number;
4035
+ const product = uid !== undefined ? tempOrder.products.find(item => String(item.metadata?.unique_identification_number || item.unique_identification_number || '') === String(uid)) : tempOrder.products[(0, _utils3.getProductIdentityIndex)(tempOrder.products, params)];
4036
+ return !product || (0, _utils3.getSafeProductNum)(params.updates.num) > product.num;
4037
+ }
3862
4038
  applyOrderProductUpdateToTempOrder(tempOrder, params, reapplyWeighedDiscountProductUids) {
3863
4039
  const {
3864
4040
  product_id,
@@ -4110,6 +4286,9 @@ class OrderModule extends _BaseModule.BaseModule {
4110
4286
  }
4111
4287
  async updateOrderProduct(params) {
4112
4288
  const tempOrder = this.ensureTempOrder();
4289
+ if (this.isRestrictedCartProductUpdate(tempOrder, params)) {
4290
+ this.createCartIntentCommitGuard('update_product', tempOrder)();
4291
+ }
4113
4292
  const reapplyWeighedDiscountProductUids = [];
4114
4293
  const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params, reapplyWeighedDiscountProductUids);
4115
4294
  const promotionPayload = await this.evaluatePromotion();
@@ -4133,6 +4312,9 @@ class OrderModule extends _BaseModule.BaseModule {
4133
4312
  if (!paramsList.length) {
4134
4313
  return tempOrder.products;
4135
4314
  }
4315
+ if (paramsList.some(params => this.isRestrictedCartProductUpdate(tempOrder, params))) {
4316
+ this.createCartIntentCommitGuard('update_product', tempOrder)();
4317
+ }
4136
4318
  const reapplyWeighedDiscountProductUids = [];
4137
4319
  const reapplyBookingDiscountProductUids = paramsList.reduce((acc, params) => {
4138
4320
  const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params, reapplyWeighedDiscountProductUids);
@@ -4151,7 +4333,9 @@ class OrderModule extends _BaseModule.BaseModule {
4151
4333
  });
4152
4334
  return tempOrder.products;
4153
4335
  }
4154
- async updateOrderProductQuantity(params) {
4336
+ async updateOrderProductQuantity(params, options) {
4337
+ const isCurrentOrder = options?.isCurrentOrder;
4338
+ if (isCurrentOrder && !isCurrentOrder()) return this.store.tempOrder?.products || [];
4155
4339
  const {
4156
4340
  product_id,
4157
4341
  product_variant_id,
@@ -4217,19 +4401,30 @@ class OrderModule extends _BaseModule.BaseModule {
4217
4401
  throw new _virtualSettlement.VirtualCurrencyBalanceError(balance.toFixed(2), requiredAmount.toFixed(2));
4218
4402
  }
4219
4403
  }
4404
+ if (normalizedProduct.num > targetProduct.num) {
4405
+ this.createCartIntentCommitGuard('increase_quantity', tempOrder)();
4406
+ }
4407
+ if (isCurrentOrder && !isCurrentOrder()) return tempOrder.products;
4220
4408
  tempOrder.products[productIndex] = normalizedProduct;
4221
- this.prepareVirtualSettlementTempOrder(tempOrder);
4222
- const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
4223
- const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
4224
- if (!isVirtualSettlement) {
4225
- this.applyDiscount();
4409
+ if (isCurrentOrder) {
4410
+ await this.finalizeProductOrderMutation(tempOrder, {
4411
+ skipEditDiscountConfigRefresh: true,
4412
+ isCurrentOrder
4413
+ });
4414
+ } else {
4415
+ this.prepareVirtualSettlementTempOrder(tempOrder);
4416
+ const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
4417
+ const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
4418
+ if (!isVirtualSettlement) {
4419
+ this.applyDiscount();
4420
+ }
4421
+ this.sanitizeTempOrderProducts(tempOrder);
4422
+ await this.recalculateSummary({
4423
+ createIfMissing: true
4424
+ });
4425
+ this.persistTempOrder();
4426
+ this.emitPromotionApplied(promotionPayload);
4226
4427
  }
4227
- this.sanitizeTempOrderProducts(tempOrder);
4228
- await this.recalculateSummary({
4229
- createIfMissing: true
4230
- });
4231
- this.persistTempOrder();
4232
- this.emitPromotionApplied(promotionPayload);
4233
4428
  this.logInfo('updateOrderProductQuantity success', {
4234
4429
  params
4235
4430
  });
@@ -4294,6 +4489,8 @@ class OrderModule extends _BaseModule.BaseModule {
4294
4489
  * await order.removeProductsFromOrder([identityA, identityB]);
4295
4490
  */
4296
4491
  async removeProductsFromOrder(identities, options) {
4492
+ const isCurrentOrder = options?.isCurrentOrder;
4493
+ if (isCurrentOrder && !isCurrentOrder()) return this.store.tempOrder?.products || [];
4297
4494
  const tempOrder = this.ensureTempOrder();
4298
4495
  if (!identities.length) {
4299
4496
  return tempOrder.products;
@@ -4361,7 +4558,14 @@ class OrderModule extends _BaseModule.BaseModule {
4361
4558
  }
4362
4559
  }
4363
4560
  this.removeSalesNotesForMissingProductLines(tempOrder);
4364
- await this.finalizeAfterProductsMutation(tempOrder);
4561
+ if (isCurrentOrder) {
4562
+ await this.finalizeProductOrderMutation(tempOrder, {
4563
+ skipEditDiscountConfigRefresh: true,
4564
+ isCurrentOrder
4565
+ });
4566
+ } else {
4567
+ await this.finalizeAfterProductsMutation(tempOrder);
4568
+ }
4365
4569
  this.logInfo('removeProductsFromOrder success', {
4366
4570
  identities
4367
4571
  });
@@ -4525,6 +4729,7 @@ class OrderModule extends _BaseModule.BaseModule {
4525
4729
  }
4526
4730
  async runSubmitTempOrder(params) {
4527
4731
  const tempOrder = this.ensureTempOrder();
4732
+ if ((0, _localEftposState.requiresLocalPaymentRefresh)(tempOrder)) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
4528
4733
  this.prepareVirtualSettlementTempOrder(tempOrder);
4529
4734
  const isOnlineStorePlatform = this.isOnlineStorePlatform();
4530
4735
  const shouldConfirmPendingVoucherPayments = params?.confirmPendingVoucherPayments !== false;
@@ -4999,7 +5204,7 @@ class OrderModule extends _BaseModule.BaseModule {
4999
5204
  query
5000
5205
  } = params;
5001
5206
  const fetchUrl = url || '/order/sales/checkout';
5002
- const requestQuery = this.isSalesCheckoutHandledByOsServer(fetchUrl) ? query : (0, _osPrivatePayload.stripOsPrivatePayloadFields)(query);
5207
+ const requestQuery = this.isSalesCheckoutHandledByOsServer(fetchUrl) ? query : (0, _localEftposState.stripLocalEftposState)((0, _osPrivatePayload.stripOsPrivatePayloadFields)(query));
5003
5208
  return this.request.post(fetchUrl, requestQuery, {
5004
5209
  osServer: true,
5005
5210
  customToast: () => {}
@@ -5044,13 +5249,10 @@ class OrderModule extends _BaseModule.BaseModule {
5044
5249
  if (lookup.startsWith('LOCAL_')) {
5045
5250
  params.forceRemote = false;
5046
5251
  }
5047
- const res = await this.request.get(`/order/sales/${encodeURIComponent(lookup)}`, {
5048
- with: ['products', 'bookings', 'payments', 'customer', 'summary', 'contacts_info', 'order_meta_list', 'refunds', 'notes'],
5049
- ...(params.forceRemote ? {
5050
- forceRemote: true
5051
- } : {})
5052
- }, {
5053
- osServer: true
5252
+ const res = await (0, _loadSalesOrderSnapshot.loadSalesOrderSnapshot)(this.request, {
5253
+ lookup,
5254
+ transport: 'os-server',
5255
+ forceRemote: params.forceRemote
5054
5256
  });
5055
5257
  if (res.code === 200) {
5056
5258
  this.store.lastOrderInfo = res.data;
@@ -0,0 +1,13 @@
1
+ /** Local reconciliation state; never part of a cloud checkout payload. */
2
+ export declare const LOCAL_EFTPOS_REFRESH_REQUIRED = "_local_eftpos_refresh_required";
3
+ export declare const LOCAL_EFTPOS_FINALIZED = "_local_eftpos_finalized";
4
+ export declare const PAYMENT_REFRESH_MESSAGE = "\u8BA2\u5355\u9700\u8981\u5237\u65B0\uFF0C\u8BF7\u8054\u7F51\u5237\u65B0\u8BA2\u5355\u540E\u518D\u4ED8\u6B3E";
5
+ export interface LocalEftposFinalization {
6
+ saleId: string | number;
7
+ paymentNumber: string;
8
+ result: 'failed' | 'not_started';
9
+ failedTransactionNumbers: string[];
10
+ }
11
+ export declare function requiresLocalPaymentRefresh(order: any): boolean;
12
+ export declare function isLocalFinalizedPayment(payment: any): boolean;
13
+ export declare function stripLocalEftposState<T extends Record<string, any>>(order: T): T;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PAYMENT_REFRESH_MESSAGE = exports.LOCAL_EFTPOS_REFRESH_REQUIRED = exports.LOCAL_EFTPOS_FINALIZED = void 0;
7
+ exports.isLocalFinalizedPayment = isLocalFinalizedPayment;
8
+ exports.requiresLocalPaymentRefresh = requiresLocalPaymentRefresh;
9
+ exports.stripLocalEftposState = stripLocalEftposState;
10
+ /** Local reconciliation state; never part of a cloud checkout payload. */
11
+ const LOCAL_EFTPOS_REFRESH_REQUIRED = exports.LOCAL_EFTPOS_REFRESH_REQUIRED = '_local_eftpos_refresh_required';
12
+ const LOCAL_EFTPOS_FINALIZED = exports.LOCAL_EFTPOS_FINALIZED = '_local_eftpos_finalized';
13
+ const PAYMENT_REFRESH_MESSAGE = exports.PAYMENT_REFRESH_MESSAGE = '订单需要刷新,请联网刷新订单后再付款';
14
+ function requiresLocalPaymentRefresh(order) {
15
+ return order?.metadata?.[LOCAL_EFTPOS_REFRESH_REQUIRED] === true;
16
+ }
17
+ function isLocalFinalizedPayment(payment) {
18
+ return payment?.status === 'voided' && payment?.metadata?.[LOCAL_EFTPOS_FINALIZED] === true;
19
+ }
20
+ function stripLocalEftposState(order) {
21
+ const result = {
22
+ ...order
23
+ };
24
+ if (order.metadata) {
25
+ result.metadata = {
26
+ ...order.metadata
27
+ };
28
+ delete result.metadata[LOCAL_EFTPOS_REFRESH_REQUIRED];
29
+ }
30
+ if (Array.isArray(order.payments)) {
31
+ result.payments = order.payments.filter(payment => !isLocalFinalizedPayment(payment)).map(payment => {
32
+ if (!payment.metadata?.[LOCAL_EFTPOS_FINALIZED]) return payment;
33
+ const metadata = {
34
+ ...payment.metadata
35
+ };
36
+ delete metadata[LOCAL_EFTPOS_FINALIZED];
37
+ return {
38
+ ...payment,
39
+ metadata
40
+ };
41
+ });
42
+ }
43
+ return result;
44
+ }