@pisell/pisellos 2.2.302 → 2.2.303
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.
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/dist/model/strategy/adapter/itemRule/type.js +19 -1
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
- package/dist/modules/Discount/index.d.ts +2 -0
- package/dist/modules/Discount/index.js +41 -5
- package/dist/modules/Discount/types.d.ts +21 -0
- package/dist/modules/OpenData/index.d.ts +15 -2
- package/dist/modules/OpenData/index.js +307 -19
- package/dist/modules/OpenData/types.d.ts +55 -0
- package/dist/modules/OpenData/types.js +7 -1
- package/dist/modules/OpenData/utils.d.ts +21 -1
- package/dist/modules/OpenData/utils.js +138 -0
- package/dist/modules/Order/index.d.ts +50 -7
- package/dist/modules/Order/index.js +1690 -815
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +117 -10
- package/dist/modules/Order/types.js +6 -1
- package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/dist/modules/Order/utils/virtualSettlement.js +284 -0
- package/dist/modules/Order/utils.d.ts +5 -1
- package/dist/modules/Order/utils.js +138 -33
- package/dist/modules/Payment/walletpass.js +20 -21
- package/dist/modules/Product/types.d.ts +23 -0
- package/dist/modules/ProductList/index.d.ts +2 -1
- package/dist/modules/ProductList/index.js +100 -20
- package/dist/modules/ProductList/types.d.ts +10 -0
- package/dist/modules/Rules/index.d.ts +5 -0
- package/dist/modules/Rules/index.js +30 -14
- package/dist/modules/SalesSummary/index.d.ts +1 -0
- package/dist/modules/SalesSummary/index.js +4 -3
- package/dist/modules/SalesSummary/types.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.js +21 -1
- package/dist/plugins/request.d.ts +2 -1
- package/dist/plugins/request.js +4 -2
- package/dist/server/index.d.ts +21 -0
- package/dist/server/index.js +1774 -1285
- package/dist/server/modules/order/types.d.ts +50 -0
- package/dist/server/modules/order/types.js +2 -0
- package/dist/server/utils/small-ticket.d.ts +4 -1
- package/dist/server/utils/small-ticket.js +461 -96
- package/dist/solution/BaseSales/index.d.ts +24 -3
- package/dist/solution/BaseSales/index.js +1484 -873
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +22 -5
- package/dist/solution/BookingTicket/index.js +558 -443
- package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
- package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
- package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
- package/dist/solution/RegisterAndLogin/config.js +95 -40
- package/dist/solution/RegisterAndLogin/index.js +4 -1
- package/dist/solution/Sales/index.d.ts +16 -1
- package/dist/solution/Sales/index.js +338 -63
- package/dist/solution/Sales/types.d.ts +10 -0
- package/dist/solution/ScanOrder/index.d.ts +1 -0
- package/dist/solution/ScanOrder/index.js +31 -27
- package/dist/solution/ScanOrder/utils.d.ts +1 -0
- package/dist/solution/ScanOrder/utils.js +2 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/dist/solution/UnifiedBookingSales/index.js +874 -527
- package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
- package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/lib/model/strategy/adapter/itemRule/type.js +19 -1
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
- package/lib/modules/Discount/index.d.ts +2 -0
- package/lib/modules/Discount/index.js +34 -2
- package/lib/modules/Discount/types.d.ts +21 -0
- package/lib/modules/OpenData/index.d.ts +15 -2
- package/lib/modules/OpenData/index.js +230 -3
- package/lib/modules/OpenData/types.d.ts +55 -0
- package/lib/modules/OpenData/types.js +9 -1
- package/lib/modules/OpenData/utils.d.ts +21 -1
- package/lib/modules/OpenData/utils.js +126 -0
- package/lib/modules/Order/index.d.ts +50 -7
- package/lib/modules/Order/index.js +704 -64
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +117 -10
- package/lib/modules/Order/types.js +5 -1
- package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/lib/modules/Order/utils/virtualSettlement.js +262 -0
- package/lib/modules/Order/utils.d.ts +5 -1
- package/lib/modules/Order/utils.js +127 -21
- package/lib/modules/Payment/walletpass.js +14 -11
- package/lib/modules/Product/types.d.ts +23 -0
- package/lib/modules/ProductList/index.d.ts +2 -1
- package/lib/modules/ProductList/index.js +47 -2
- package/lib/modules/ProductList/types.d.ts +10 -0
- package/lib/modules/Rules/index.d.ts +5 -0
- package/lib/modules/Rules/index.js +22 -12
- package/lib/modules/SalesSummary/index.d.ts +1 -0
- package/lib/modules/SalesSummary/index.js +4 -2
- package/lib/modules/SalesSummary/types.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.js +17 -1
- package/lib/plugins/request.d.ts +2 -1
- package/lib/plugins/request.js +3 -2
- package/lib/server/index.d.ts +21 -0
- package/lib/server/index.js +492 -108
- package/lib/server/modules/order/types.d.ts +50 -0
- package/lib/server/modules/order/types.js +1 -0
- package/lib/server/utils/small-ticket.d.ts +4 -1
- package/lib/server/utils/small-ticket.js +427 -72
- package/lib/solution/BaseSales/index.d.ts +24 -3
- package/lib/solution/BaseSales/index.js +433 -30
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +22 -5
- package/lib/solution/BookingTicket/index.js +60 -15
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
- package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
- package/lib/solution/RegisterAndLogin/config.js +49 -8
- package/lib/solution/RegisterAndLogin/index.js +4 -1
- package/lib/solution/Sales/index.d.ts +16 -1
- package/lib/solution/Sales/index.js +168 -1
- package/lib/solution/Sales/types.d.ts +10 -0
- package/lib/solution/ScanOrder/index.d.ts +1 -0
- package/lib/solution/ScanOrder/index.js +5 -1
- package/lib/solution/ScanOrder/utils.d.ts +1 -0
- package/lib/solution/ScanOrder/utils.js +1 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/lib/solution/UnifiedBookingSales/index.js +169 -16
- package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ var _types = require("./types");
|
|
|
9
9
|
var _utils = require("./utils");
|
|
10
10
|
var _utils2 = require("../Product/utils");
|
|
11
11
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
12
|
+
var _salesNotes = require("./salesNotes");
|
|
12
13
|
var _paymentUtils = require("./payment-utils");
|
|
13
14
|
var _paymentNumber = require("../../utils/payment-number");
|
|
14
15
|
var _cartPromotion = require("../../solution/BaseSales/utils/cartPromotion");
|
|
@@ -17,6 +18,7 @@ var _manualProductDiscount = require("./utils/manualProductDiscount");
|
|
|
17
18
|
var _bundleDiscountHydration = require("./utils/bundleDiscountHydration");
|
|
18
19
|
var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
|
|
19
20
|
var _discountProductLineIdentity = require("./utils/discountProductLineIdentity");
|
|
21
|
+
var _virtualSettlement = require("./utils/virtualSettlement");
|
|
20
22
|
var _Discount = require("../Discount");
|
|
21
23
|
var _Rules = require("../Rules");
|
|
22
24
|
var _types2 = require("../Rules/types");
|
|
@@ -70,6 +72,13 @@ function getVoucherPaymentLifecycleKey(payment) {
|
|
|
70
72
|
if (!isVoucherPaymentRecord(payment)) return null;
|
|
71
73
|
return `${String(payment.voucher_id)}::${String(payment.status || '')}`;
|
|
72
74
|
}
|
|
75
|
+
function hasPersistedOrderId(orderId) {
|
|
76
|
+
if (orderId === undefined || orderId === null || orderId === '') return false;
|
|
77
|
+
if (typeof orderId === 'string' && orderId.startsWith('LOCAL_')) return false;
|
|
78
|
+
const normalizedOrderId = Number(orderId);
|
|
79
|
+
if (Number.isFinite(normalizedOrderId)) return normalizedOrderId > 0;
|
|
80
|
+
return String(orderId).trim() !== '';
|
|
81
|
+
}
|
|
73
82
|
class OrderModule extends _BaseModule.BaseModule {
|
|
74
83
|
defaultName = 'order';
|
|
75
84
|
defaultVersion = '1.0.0';
|
|
@@ -93,8 +102,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
93
102
|
promotionEvaluator = null;
|
|
94
103
|
/** 赠品选择 resolver;由 SDK host bridge 注入 */
|
|
95
104
|
giftSelectResolver = null;
|
|
96
|
-
/**
|
|
105
|
+
/** 促销评估递归保护 flag(写路径同步评估促销,禁止重入) */
|
|
97
106
|
isApplyingPromotion = false;
|
|
107
|
+
/** 保持旧事件语义:同步事件监听器内触发的订单写入不得递归评估促销。 */
|
|
108
|
+
isEmittingPromotionApplied = false;
|
|
98
109
|
/** 商品曾应用过客户券卡,客户变更剥离后需强制跑一次 calcDiscount 复位价格 */
|
|
99
110
|
hasActiveCustomerBoundDiscount = false;
|
|
100
111
|
/** 最近一次 applyPromotion 的未满足促销提示 */
|
|
@@ -260,12 +271,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
260
271
|
product.product_bundle = product.product_bundle.map(bundle => {
|
|
261
272
|
const hasBundleDiscount = Array.isArray(bundle?.discount_list) && bundle.discount_list.length > 0;
|
|
262
273
|
if (hasBundleDiscount) return bundle;
|
|
263
|
-
const restoredPrice = bundle?.
|
|
274
|
+
const restoredPrice = bundle?.price ?? bundle?.original_price ?? bundle?.product_price;
|
|
264
275
|
if (restoredPrice === undefined || restoredPrice === null || restoredPrice === '') return bundle;
|
|
265
276
|
return {
|
|
266
277
|
...bundle,
|
|
267
278
|
price: restoredPrice,
|
|
268
|
-
bundle_selling_price: restoredPrice
|
|
279
|
+
bundle_selling_price: bundle?.bundle_selling_price ?? restoredPrice
|
|
269
280
|
};
|
|
270
281
|
});
|
|
271
282
|
}
|
|
@@ -297,6 +308,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
297
308
|
this.store.tempOrder = null;
|
|
298
309
|
this.store.summary = (0, _utils.createEmptySummary)();
|
|
299
310
|
this.store.availableWalletIds = [];
|
|
311
|
+
this.store.virtualCurrencyList = [];
|
|
300
312
|
this.store.lastOrderInfo = undefined;
|
|
301
313
|
this.store.syncState = undefined;
|
|
302
314
|
this.store.discountList = [];
|
|
@@ -309,6 +321,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
309
321
|
if (!Array.isArray(this.store.availableWalletIds)) {
|
|
310
322
|
this.store.availableWalletIds = [];
|
|
311
323
|
}
|
|
324
|
+
if (!Array.isArray(this.store.virtualCurrencyList)) {
|
|
325
|
+
this.store.virtualCurrencyList = [];
|
|
326
|
+
}
|
|
312
327
|
this.request = this.core.getPlugin('request');
|
|
313
328
|
const appPlugin = this.core.getPlugin('app');
|
|
314
329
|
if (!appPlugin) {
|
|
@@ -363,6 +378,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
363
378
|
this.otherParams = otherParams;
|
|
364
379
|
}
|
|
365
380
|
|
|
381
|
+
/** PC/H5 属于在线店铺;其它或缺失平台统一沿用 POS 行为。 */
|
|
382
|
+
isOnlineStorePlatform() {
|
|
383
|
+
const platform = String(this.otherParams?.platform || '').trim().toLowerCase();
|
|
384
|
+
return platform === 'pc' || platform === 'h5';
|
|
385
|
+
}
|
|
386
|
+
|
|
366
387
|
/**
|
|
367
388
|
* 记录信息日志
|
|
368
389
|
*/
|
|
@@ -450,6 +471,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
450
471
|
with_wallet_pass_holder: 1,
|
|
451
472
|
with_available_wallet_flag: 1,
|
|
452
473
|
with_available_wallet_pass_flag: 1,
|
|
474
|
+
with_virtual_currency: 1,
|
|
453
475
|
request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
454
476
|
...(orderId ? {
|
|
455
477
|
order_id: orderId
|
|
@@ -457,6 +479,14 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
457
479
|
});
|
|
458
480
|
const discountList = prepareConfigResult?.discountList;
|
|
459
481
|
this.store.availableWalletIds = prepareConfigResult?.availableWalletIds || [];
|
|
482
|
+
this.store.virtualCurrencyList = prepareConfigResult?.virtualCurrencyList || [];
|
|
483
|
+
if (prepareConfigResult) {
|
|
484
|
+
this.writePointCardSnapshotFromPrepareConfig({
|
|
485
|
+
orderId,
|
|
486
|
+
customerId: params.customerId,
|
|
487
|
+
availableWalletPassList: prepareConfigResult.availableWalletPassList || []
|
|
488
|
+
});
|
|
489
|
+
}
|
|
460
490
|
if (discountList) {
|
|
461
491
|
const currentDiscountList = this.store.discount?.getDiscountList() || [];
|
|
462
492
|
const currentEditDiscounts = currentDiscountList.filter(discount => discount?.isEditMode);
|
|
@@ -484,6 +514,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
484
514
|
getAvailableWalletIds() {
|
|
485
515
|
return Array.isArray(this.store.availableWalletIds) ? [...this.store.availableWalletIds] : [];
|
|
486
516
|
}
|
|
517
|
+
getVirtualCurrencyList() {
|
|
518
|
+
return (0, _lodashEs.cloneDeep)(this.store.virtualCurrencyList || []);
|
|
519
|
+
}
|
|
487
520
|
async syncScannedDiscountsToOriginalDiscountList(discountList) {
|
|
488
521
|
const scanDiscounts = (discountList || []).filter(discount => discount?.isScan);
|
|
489
522
|
if (!scanDiscounts.length) return;
|
|
@@ -507,6 +540,16 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
507
540
|
});
|
|
508
541
|
}
|
|
509
542
|
async scanCode(code, customerId) {
|
|
543
|
+
if (this.isActiveVirtualSettlementOrder(this.store.tempOrder)) {
|
|
544
|
+
return {
|
|
545
|
+
type: 'clientCalc',
|
|
546
|
+
isAvailable: false,
|
|
547
|
+
isAccepted: false,
|
|
548
|
+
discountList: [],
|
|
549
|
+
scannedDiscountList: [],
|
|
550
|
+
unavailableReason: _types2.UnavailableReason.ProductNotApplicable
|
|
551
|
+
};
|
|
552
|
+
}
|
|
510
553
|
const resultDiscountWithReason = (await this.store.discount?.batchSearch(code, {
|
|
511
554
|
customerId
|
|
512
555
|
})) || {
|
|
@@ -602,6 +645,14 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
602
645
|
// 也需要让 Rules.calcDiscount 把 DiscountModule 的 isSelected / isAvailable /
|
|
603
646
|
// appliedProductDetails / savedAmount 复位。
|
|
604
647
|
if (!tempOrder) return;
|
|
648
|
+
if (this.isActiveVirtualSettlementOrder(tempOrder)) {
|
|
649
|
+
tempOrder.products = (0, _virtualSettlement.normalizeVirtualSettlementProducts)(tempOrder.products);
|
|
650
|
+
tempOrder.discount_list = [];
|
|
651
|
+
tempOrder.shop_discount = '0.00';
|
|
652
|
+
void this.store.discount?.setDiscountList([]);
|
|
653
|
+
void this.store.discount?.setOriginalDiscountList([]);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
605
656
|
this.syncLinkedBookingHoldersToProducts(tempOrder);
|
|
606
657
|
delete tempOrder.discount_list;
|
|
607
658
|
const discountList = this.store.discount?.getDiscountList() || [];
|
|
@@ -678,7 +729,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
678
729
|
}
|
|
679
730
|
|
|
680
731
|
/**
|
|
681
|
-
*
|
|
732
|
+
* 只执行购物车促销评估与赠品写回,不发布稳定态事件。
|
|
682
733
|
*
|
|
683
734
|
* 调用时机:写路径(add/update/remove/clear/setCustomer)末尾自动触发;外部一般无需手动调。
|
|
684
735
|
*
|
|
@@ -686,22 +737,27 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
686
737
|
* - 不调用任何公开 CRUD API(如 removeProductFromOrder),全部内部 mutate tempOrder.products,避免事件风暴;
|
|
687
738
|
* - 用 `isApplyingPromotion` 防递归;
|
|
688
739
|
* - 多选项赠品依赖 giftSelectResolver,未注入则跳过且 console.warn;
|
|
689
|
-
* - 不主动调用 applyDiscount / recalculateSummary
|
|
740
|
+
* - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进;
|
|
741
|
+
* - 返回的 payload 只能在 applyDiscount(商品写路径还需 summary/persist)完成后发布。
|
|
690
742
|
*/
|
|
691
|
-
async
|
|
692
|
-
if (this.isApplyingPromotion) {
|
|
693
|
-
return;
|
|
743
|
+
async evaluatePromotion() {
|
|
744
|
+
if (this.isApplyingPromotion || this.isEmittingPromotionApplied) {
|
|
745
|
+
return null;
|
|
694
746
|
}
|
|
695
747
|
if (!this.promotionEvaluator) {
|
|
696
|
-
return;
|
|
748
|
+
return null;
|
|
697
749
|
}
|
|
698
750
|
const tempOrder = this.store.tempOrder;
|
|
699
751
|
if (!tempOrder) {
|
|
700
|
-
return;
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
if (this.isActiveVirtualSettlementOrder(tempOrder)) {
|
|
755
|
+
tempOrder.products = (0, _virtualSettlement.normalizeVirtualSettlementProducts)(tempOrder.products);
|
|
756
|
+
return null;
|
|
701
757
|
}
|
|
702
758
|
const strategyConfigs = this.promotionEvaluator.getStrategyConfigs?.();
|
|
703
759
|
if (Array.isArray(strategyConfigs) && strategyConfigs.length === 0) {
|
|
704
|
-
return;
|
|
760
|
+
return null;
|
|
705
761
|
}
|
|
706
762
|
this.isApplyingPromotion = true;
|
|
707
763
|
try {
|
|
@@ -793,14 +849,46 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
793
849
|
})),
|
|
794
850
|
products: tempOrder.products
|
|
795
851
|
};
|
|
796
|
-
|
|
852
|
+
return payload;
|
|
797
853
|
} catch (error) {
|
|
798
854
|
console.error('[OrderModule] applyPromotion failed', error);
|
|
855
|
+
return null;
|
|
799
856
|
} finally {
|
|
800
857
|
this.isApplyingPromotion = false;
|
|
801
858
|
}
|
|
802
859
|
}
|
|
803
860
|
|
|
861
|
+
/** 发布促销稳定态;products 必须读取折扣计算后的当前数组。 */
|
|
862
|
+
emitPromotionApplied(payload) {
|
|
863
|
+
if (!payload) return;
|
|
864
|
+
const products = this.store.tempOrder?.products || payload.products;
|
|
865
|
+
this.isEmittingPromotionApplied = true;
|
|
866
|
+
try {
|
|
867
|
+
void this.effectsEmit('onPromotionApplied', {
|
|
868
|
+
...payload,
|
|
869
|
+
products
|
|
870
|
+
});
|
|
871
|
+
} finally {
|
|
872
|
+
// effectsEmit 同步调用监听器后返回 Promise;保持既有的非阻塞事件行为。
|
|
873
|
+
this.isEmittingPromotionApplied = false;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** 公开入口:促销、折扣、summary 与持久化完成后发布稳定态事件。 */
|
|
878
|
+
async applyPromotion() {
|
|
879
|
+
const payload = await this.evaluatePromotion();
|
|
880
|
+
if (!payload) return;
|
|
881
|
+
const tempOrder = this.store.tempOrder;
|
|
882
|
+
if (!tempOrder) return;
|
|
883
|
+
this.applyDiscount();
|
|
884
|
+
this.sanitizeTempOrderProducts(tempOrder);
|
|
885
|
+
await this.recalculateSummary({
|
|
886
|
+
createIfMissing: true
|
|
887
|
+
});
|
|
888
|
+
this.persistTempOrder();
|
|
889
|
+
this.emitPromotionApplied(payload);
|
|
890
|
+
}
|
|
891
|
+
|
|
804
892
|
/** 最近一次 applyPromotion 输出的未满足促销列表 */
|
|
805
893
|
getUnfulfilledPromotions() {
|
|
806
894
|
return this.lastUnfulfilledPromotions;
|
|
@@ -904,6 +992,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
904
992
|
this.store.tempOrder = {
|
|
905
993
|
...this.store.tempOrder,
|
|
906
994
|
products: [...this.store.tempOrder.products],
|
|
995
|
+
notes: [...(this.store.tempOrder.notes || [])],
|
|
907
996
|
bookings: this.store.tempOrder.bookings ? [...this.store.tempOrder.bookings] : []
|
|
908
997
|
};
|
|
909
998
|
this.persistTempOrder();
|
|
@@ -916,6 +1005,32 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
916
1005
|
now: (0, _utils.formatDateTime)(new Date())
|
|
917
1006
|
});
|
|
918
1007
|
}
|
|
1008
|
+
clearTempOrderPointCardSnapshot(tempOrder) {
|
|
1009
|
+
const orderMetaList = (0, _utils.normalizeOrderMetaList)(tempOrder.order_meta_list);
|
|
1010
|
+
if (!orderMetaList) return;
|
|
1011
|
+
const nextOrderMetaList = {
|
|
1012
|
+
...orderMetaList
|
|
1013
|
+
};
|
|
1014
|
+
delete nextOrderMetaList.point_cards_snapshot;
|
|
1015
|
+
if (Object.keys(nextOrderMetaList).length === 0) {
|
|
1016
|
+
delete tempOrder.order_meta_list;
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
tempOrder.order_meta_list = nextOrderMetaList;
|
|
1020
|
+
}
|
|
1021
|
+
writePointCardSnapshotFromPrepareConfig(params) {
|
|
1022
|
+
const tempOrder = this.store.tempOrder;
|
|
1023
|
+
if (!tempOrder) return;
|
|
1024
|
+
if (String(tempOrder.customer_id ?? '') !== String(params.customerId)) return;
|
|
1025
|
+
const effectiveOrderId = params.orderId ?? tempOrder.order_id;
|
|
1026
|
+
if (hasPersistedOrderId(effectiveOrderId)) return;
|
|
1027
|
+
tempOrder.order_meta_list = {
|
|
1028
|
+
...((0, _utils.normalizeOrderMetaList)(tempOrder.order_meta_list) || {}),
|
|
1029
|
+
point_cards_snapshot: (0, _utils.buildPointCardSnapshotFromWalletPassList)(params.availableWalletPassList)
|
|
1030
|
+
};
|
|
1031
|
+
this.persistTempOrder();
|
|
1032
|
+
this.saveDraftInBackground();
|
|
1033
|
+
}
|
|
919
1034
|
createExternalSaleNumber() {
|
|
920
1035
|
const timestamp = (0, _dayjs.default)().format('YYYYMMDDHHmmssSSS');
|
|
921
1036
|
const random6 = String(Math.floor(Math.random() * 1000000)).padStart(6, '0');
|
|
@@ -1828,7 +1943,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1828
1943
|
return product;
|
|
1829
1944
|
}
|
|
1830
1945
|
sanitizeTempOrderProducts(tempOrder) {
|
|
1831
|
-
tempOrder.products = (tempOrder.products || []).map(product => this.sanitizeOrderProductForTempOrder(product));
|
|
1946
|
+
tempOrder.products = (tempOrder.products || []).map(product => this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(product)));
|
|
1947
|
+
this.syncTempOrderSettlementState(tempOrder);
|
|
1832
1948
|
(0, _discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
|
|
1833
1949
|
}
|
|
1834
1950
|
ensureExtend(tempOrder) {
|
|
@@ -2149,6 +2265,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2149
2265
|
products: summaryProducts,
|
|
2150
2266
|
isPriceIncludeTax: tempOrder.is_price_include_tax,
|
|
2151
2267
|
shopDiscount: tempOrder.shop_discount,
|
|
2268
|
+
virtualSettlementMode: this.shouldUseVirtualSettlementSummary(tempOrder),
|
|
2152
2269
|
...(this.otherParams?.channel ? {
|
|
2153
2270
|
channel: this.otherParams.channel
|
|
2154
2271
|
} : {})
|
|
@@ -2236,6 +2353,179 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2236
2353
|
getTempOrderNote() {
|
|
2237
2354
|
return this.store.tempOrder?.note || '';
|
|
2238
2355
|
}
|
|
2356
|
+
ensureSalesNotesRuntimeState(tempOrder) {
|
|
2357
|
+
const hadNotesSnapshot = Array.isArray(tempOrder.notes);
|
|
2358
|
+
if (!Array.isArray(tempOrder.notes)) tempOrder.notes = [];
|
|
2359
|
+
if (!tempOrder._extend || typeof tempOrder._extend !== 'object') {
|
|
2360
|
+
tempOrder._extend = {
|
|
2361
|
+
productsByUid: {}
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
if (!tempOrder._extend.salesNotesState) {
|
|
2365
|
+
tempOrder._extend.salesNotesState = {
|
|
2366
|
+
loaded: hadNotesSnapshot,
|
|
2367
|
+
dirty: false
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
return tempOrder._extend.salesNotesState;
|
|
2371
|
+
}
|
|
2372
|
+
ensureSalesNotesLoadedForMutation(tempOrder) {
|
|
2373
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2374
|
+
if (state.loaded) return;
|
|
2375
|
+
if (tempOrder.order_id === null || tempOrder.order_id === undefined) {
|
|
2376
|
+
state.loaded = true;
|
|
2377
|
+
tempOrder.notes = [];
|
|
2378
|
+
return;
|
|
2379
|
+
}
|
|
2380
|
+
throw new Error('[Order Notes] 当前订单 Notes 尚未完整加载,禁止提交部分快照');
|
|
2381
|
+
}
|
|
2382
|
+
normalizeSalesNoteUuid(value, field) {
|
|
2383
|
+
const uuid = String(value ?? '').trim();
|
|
2384
|
+
if (!uuid) throw new Error(`[Order Notes] ${field} 不能为空`);
|
|
2385
|
+
if (uuid.length > 255) {
|
|
2386
|
+
throw new Error(`[Order Notes] ${field} 不能超过 255 个字符`);
|
|
2387
|
+
}
|
|
2388
|
+
return uuid;
|
|
2389
|
+
}
|
|
2390
|
+
getSalesNotePrimaryRelation(note) {
|
|
2391
|
+
return note.note_relations.find(relation => relation.is_primary === 1) || null;
|
|
2392
|
+
}
|
|
2393
|
+
removeSalesNotesForMissingProductLines(tempOrder) {
|
|
2394
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2395
|
+
if (!state.loaded || !Array.isArray(tempOrder.notes) || tempOrder.notes.length === 0) {
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
const remainingProductUids = new Set((tempOrder.products || []).map(product => product.metadata?.unique_identification_number || product.unique_identification_number).filter(uid => typeof uid === 'string' && uid.length > 0));
|
|
2399
|
+
const nextNotes = tempOrder.notes.filter(note => {
|
|
2400
|
+
const primary = this.getSalesNotePrimaryRelation(note);
|
|
2401
|
+
if (!primary || primary.target_type !== 'order_detail') return true;
|
|
2402
|
+
return remainingProductUids.has(primary.target_uuid);
|
|
2403
|
+
});
|
|
2404
|
+
if (nextNotes.length === tempOrder.notes.length) return;
|
|
2405
|
+
tempOrder.notes = nextNotes;
|
|
2406
|
+
state.dirty = true;
|
|
2407
|
+
}
|
|
2408
|
+
setSalesNoteOnTempOrder(tempOrder, input) {
|
|
2409
|
+
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
2410
|
+
const note_type = String(input.note_type || '').trim();
|
|
2411
|
+
const policy = (0, _salesNotes.getSalesNotePolicy)(note_type);
|
|
2412
|
+
if (!policy) {
|
|
2413
|
+
throw new Error(`[Order Notes] 当前未注册备注类型: ${note_type || '(empty)'}`);
|
|
2414
|
+
}
|
|
2415
|
+
if (input.target?.target_type !== 'order_detail') {
|
|
2416
|
+
throw new Error('[Order Notes] 本期只支持 order_detail 作为主体');
|
|
2417
|
+
}
|
|
2418
|
+
const target_uuid = this.normalizeSalesNoteUuid(input.target.target_uuid, 'target_uuid');
|
|
2419
|
+
const targetProductExists = (tempOrder.products || []).some(product => {
|
|
2420
|
+
const productLineUid = product.metadata?.unique_identification_number || product.unique_identification_number;
|
|
2421
|
+
return String(productLineUid ?? '') === target_uuid;
|
|
2422
|
+
});
|
|
2423
|
+
if (!targetProductExists) {
|
|
2424
|
+
throw new Error('[Order Notes] 目标商品行不存在');
|
|
2425
|
+
}
|
|
2426
|
+
const text = (0, _salesNotes.buildSalesNoteText)(input.text);
|
|
2427
|
+
const notes = tempOrder.notes || [];
|
|
2428
|
+
// 当前 allergy policy 固定同一商品行只保留一条;业务调用方不参与去重规则。
|
|
2429
|
+
const existingIndex = policy.uniquePerPrimaryTarget ? notes.findIndex(note => {
|
|
2430
|
+
const primary = this.getSalesNotePrimaryRelation(note);
|
|
2431
|
+
return note.note_type === note_type && primary?.target_type === 'order_detail' && primary.target_uuid === target_uuid;
|
|
2432
|
+
}) : -1;
|
|
2433
|
+
const existing = existingIndex >= 0 ? notes[existingIndex] : null;
|
|
2434
|
+
const existingPrimary = existing?.note_relations.find(relation => relation.is_primary === 1 && relation.target_type === 'order_detail');
|
|
2435
|
+
const existingOrderRelation = existing?.note_relations.find(relation => relation.is_primary === 0 && relation.target_type === 'order');
|
|
2436
|
+
const note = {
|
|
2437
|
+
uuid: existing?.uuid || (0, _utils.createUuidV4)(),
|
|
2438
|
+
note_type: policy.note_type,
|
|
2439
|
+
content: {
|
|
2440
|
+
text
|
|
2441
|
+
},
|
|
2442
|
+
importance: policy.importance,
|
|
2443
|
+
note_relations: [{
|
|
2444
|
+
uuid: existingPrimary?.uuid || (0, _utils.createUuidV4)(),
|
|
2445
|
+
relation_type: policy.primary_relation_type,
|
|
2446
|
+
target_type: 'order_detail',
|
|
2447
|
+
target_uuid,
|
|
2448
|
+
is_primary: 1
|
|
2449
|
+
}, {
|
|
2450
|
+
uuid: existingOrderRelation?.uuid || (0, _utils.createUuidV4)(),
|
|
2451
|
+
relation_type: policy.secondary_order_relation_type,
|
|
2452
|
+
target_type: 'order',
|
|
2453
|
+
target_uuid: String(tempOrder.shop_order_number ?? ''),
|
|
2454
|
+
is_primary: 0
|
|
2455
|
+
}]
|
|
2456
|
+
};
|
|
2457
|
+
const duplicateIndex = notes.findIndex((item, index) => item.uuid === note.uuid && index !== existingIndex);
|
|
2458
|
+
if (duplicateIndex >= 0) {
|
|
2459
|
+
throw new Error('[Order Notes] uuid 已被其他 Note 使用');
|
|
2460
|
+
}
|
|
2461
|
+
tempOrder.notes = existingIndex >= 0 ? notes.map((item, index) => index === existingIndex ? note : item) : [...notes, note];
|
|
2462
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2463
|
+
state.loaded = true;
|
|
2464
|
+
state.dirty = true;
|
|
2465
|
+
return note;
|
|
2466
|
+
}
|
|
2467
|
+
getSalesNotes() {
|
|
2468
|
+
const tempOrder = this.ensureTempOrder();
|
|
2469
|
+
this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2470
|
+
return (0, _lodashEs.cloneDeep)(tempOrder.notes || []);
|
|
2471
|
+
}
|
|
2472
|
+
createSalesNotesMutationSnapshot() {
|
|
2473
|
+
const tempOrder = this.ensureTempOrder();
|
|
2474
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2475
|
+
return {
|
|
2476
|
+
orderIdentity: {
|
|
2477
|
+
orderId: tempOrder.order_id ?? null,
|
|
2478
|
+
externalSaleNumber: String(tempOrder.external_sale_number || '')
|
|
2479
|
+
},
|
|
2480
|
+
notes: (0, _lodashEs.cloneDeep)(tempOrder.notes || []),
|
|
2481
|
+
state: (0, _lodashEs.cloneDeep)(state)
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
restoreSalesNotesMutationSnapshot(snapshot) {
|
|
2485
|
+
if (!snapshot || !Array.isArray(snapshot.notes) || !snapshot.orderIdentity || typeof snapshot.orderIdentity.externalSaleNumber !== 'string' || typeof snapshot.state?.loaded !== 'boolean' || typeof snapshot.state?.dirty !== 'boolean') {
|
|
2486
|
+
throw new Error('[Order Notes] 无效的 mutation snapshot');
|
|
2487
|
+
}
|
|
2488
|
+
const tempOrder = this.store.tempOrder;
|
|
2489
|
+
if (!tempOrder) throw new Error('[Order Notes] 当前订单不存在');
|
|
2490
|
+
const snapshotOrderId = snapshot.orderIdentity.orderId;
|
|
2491
|
+
const currentOrderId = tempOrder.order_id;
|
|
2492
|
+
const hasSnapshotOrderId = snapshotOrderId !== null && snapshotOrderId !== undefined && String(snapshotOrderId).trim().length > 0;
|
|
2493
|
+
const hasCurrentOrderId = currentOrderId !== null && currentOrderId !== undefined && String(currentOrderId).trim().length > 0;
|
|
2494
|
+
const isSameOrder = hasSnapshotOrderId && hasCurrentOrderId ? String(snapshotOrderId) === String(currentOrderId) : Boolean(snapshot.orderIdentity.externalSaleNumber) && snapshot.orderIdentity.externalSaleNumber === String(tempOrder.external_sale_number || '');
|
|
2495
|
+
if (!isSameOrder) {
|
|
2496
|
+
throw new Error('[Order Notes] 当前订单已切换,拒绝恢复旧订单快照');
|
|
2497
|
+
}
|
|
2498
|
+
this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2499
|
+
tempOrder.notes = (0, _lodashEs.cloneDeep)(snapshot.notes);
|
|
2500
|
+
tempOrder._extend.salesNotesState = (0, _lodashEs.cloneDeep)(snapshot.state);
|
|
2501
|
+
this.notifyTempOrderChanged();
|
|
2502
|
+
}
|
|
2503
|
+
async setSalesNote(input) {
|
|
2504
|
+
const tempOrder = this.ensureTempOrder();
|
|
2505
|
+
const note = this.setSalesNoteOnTempOrder(tempOrder, input);
|
|
2506
|
+
this.notifyTempOrderChanged();
|
|
2507
|
+
return (0, _lodashEs.cloneDeep)(note);
|
|
2508
|
+
}
|
|
2509
|
+
async removeSalesNote(uuid) {
|
|
2510
|
+
const tempOrder = this.ensureTempOrder();
|
|
2511
|
+
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
2512
|
+
const normalizedUuid = this.normalizeSalesNoteUuid(uuid, 'uuid');
|
|
2513
|
+
const notes = tempOrder.notes || [];
|
|
2514
|
+
const nextNotes = notes.filter(note => note.uuid !== normalizedUuid);
|
|
2515
|
+
if (nextNotes.length === notes.length) return;
|
|
2516
|
+
tempOrder.notes = nextNotes;
|
|
2517
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2518
|
+
state.dirty = true;
|
|
2519
|
+
this.notifyTempOrderChanged();
|
|
2520
|
+
}
|
|
2521
|
+
async clearSalesNotes() {
|
|
2522
|
+
const tempOrder = this.ensureTempOrder();
|
|
2523
|
+
tempOrder.notes = [];
|
|
2524
|
+
const state = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
2525
|
+
state.loaded = true;
|
|
2526
|
+
state.dirty = true;
|
|
2527
|
+
this.notifyTempOrderChanged();
|
|
2528
|
+
}
|
|
2239
2529
|
updateTempOrderShopDiscount(amount) {
|
|
2240
2530
|
const tempOrder = this.ensureTempOrder();
|
|
2241
2531
|
const discount = _decimal.default.max(new _decimal.default(Number(amount) || 0), 0).toDecimalPlaces(2).toFixed(2);
|
|
@@ -2275,6 +2565,31 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2275
2565
|
this.persistTempOrder();
|
|
2276
2566
|
return tempOrder.buzzer;
|
|
2277
2567
|
}
|
|
2568
|
+
updateTempOrderShopServiceData(patch) {
|
|
2569
|
+
const tempOrder = this.ensureTempOrder();
|
|
2570
|
+
const metadata = tempOrder.metadata && typeof tempOrder.metadata === 'object' && !Array.isArray(tempOrder.metadata) ? tempOrder.metadata : {};
|
|
2571
|
+
const currentShopServiceData = metadata.shop_service_data && typeof metadata.shop_service_data === 'object' && !Array.isArray(metadata.shop_service_data) ? metadata.shop_service_data : {};
|
|
2572
|
+
const shopServiceData = {
|
|
2573
|
+
...currentShopServiceData,
|
|
2574
|
+
...patch
|
|
2575
|
+
};
|
|
2576
|
+
tempOrder.metadata = {
|
|
2577
|
+
...metadata,
|
|
2578
|
+
shop_service_data: shopServiceData
|
|
2579
|
+
};
|
|
2580
|
+
this.persistTempOrder();
|
|
2581
|
+
return shopServiceData;
|
|
2582
|
+
}
|
|
2583
|
+
updateTempOrderPickupReferenceMode(mode) {
|
|
2584
|
+
return this.updateTempOrderShopServiceData({
|
|
2585
|
+
pickup_reference_mode: mode
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
updateTempOrderServiceType(serviceType) {
|
|
2589
|
+
return this.updateTempOrderShopServiceData({
|
|
2590
|
+
service_type: serviceType
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2278
2593
|
updateTempOrderContactsInfo(contactsInfo) {
|
|
2279
2594
|
const tempOrder = this.ensureTempOrder();
|
|
2280
2595
|
tempOrder.contacts_info = contactsInfo && typeof contactsInfo === 'object' && !Array.isArray(contactsInfo) ? contactsInfo : null;
|
|
@@ -2384,6 +2699,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2384
2699
|
email: tempOrder.email
|
|
2385
2700
|
});
|
|
2386
2701
|
const nextCustomerId = tempOrder.customer_id ?? null;
|
|
2702
|
+
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '') && !hasPersistedOrderId(tempOrder.order_id)) {
|
|
2703
|
+
this.store.availableWalletIds = [];
|
|
2704
|
+
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2705
|
+
}
|
|
2387
2706
|
this.persistTempOrder();
|
|
2388
2707
|
return {
|
|
2389
2708
|
customerId: tempOrder.customer_id,
|
|
@@ -2419,6 +2738,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2419
2738
|
const nextCustomerId = tempOrder.customer_id ?? null;
|
|
2420
2739
|
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')) {
|
|
2421
2740
|
this.store.availableWalletIds = [];
|
|
2741
|
+
this.store.virtualCurrencyList = [];
|
|
2742
|
+
if (!hasPersistedOrderId(tempOrder.order_id)) {
|
|
2743
|
+
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2744
|
+
}
|
|
2422
2745
|
(0, _utils.clearTempOrderHolderAssignments)(tempOrder);
|
|
2423
2746
|
this.clearCustomerBoundDiscounts(tempOrder);
|
|
2424
2747
|
this.applyDiscount();
|
|
@@ -2457,6 +2780,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2457
2780
|
tempOrder.customer = null;
|
|
2458
2781
|
if (tempOrder._extend) delete tempOrder._extend.customerSnapshot;
|
|
2459
2782
|
this.store.availableWalletIds = [];
|
|
2783
|
+
this.store.virtualCurrencyList = [];
|
|
2784
|
+
if (!hasPersistedOrderId(tempOrder.order_id)) {
|
|
2785
|
+
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2786
|
+
}
|
|
2460
2787
|
this.clearCustomerBoundDiscounts(tempOrder);
|
|
2461
2788
|
this.applyDiscount();
|
|
2462
2789
|
this.persistTempOrder();
|
|
@@ -2776,6 +3103,78 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2776
3103
|
const bookingUid = product?.booking_uid ?? product?.metadata?.booking_uid;
|
|
2777
3104
|
return bookingUid !== undefined && bookingUid !== null && String(bookingUid) !== '';
|
|
2778
3105
|
}
|
|
3106
|
+
isMultiCurrencySettlementEnabled() {
|
|
3107
|
+
return this.otherParams?.enableMultiCurrencySettlement === true;
|
|
3108
|
+
}
|
|
3109
|
+
isActiveVirtualSettlementOrder(tempOrder) {
|
|
3110
|
+
return this.isMultiCurrencySettlementEnabled() && (0, _virtualSettlement.isVirtualSettlementOrder)(tempOrder);
|
|
3111
|
+
}
|
|
3112
|
+
shouldUseVirtualSettlementSummary(tempOrder) {
|
|
3113
|
+
return this.isActiveVirtualSettlementOrder(tempOrder) || tempOrder?.metadata?.currency_settlement_config?.settlement_type === 'virtual_currency';
|
|
3114
|
+
}
|
|
3115
|
+
normalizeVirtualSettlementProductIfEnabled(product) {
|
|
3116
|
+
return this.isMultiCurrencySettlementEnabled() ? (0, _virtualSettlement.normalizeVirtualSettlementOrderProduct)(product) : product;
|
|
3117
|
+
}
|
|
3118
|
+
assertAndLockProductSettlement(tempOrder, product) {
|
|
3119
|
+
if (!this.isMultiCurrencySettlementEnabled()) return;
|
|
3120
|
+
const currentKey = (0, _virtualSettlement.getTempOrderSettlementKey)(tempOrder);
|
|
3121
|
+
const incomingKey = (0, _virtualSettlement.getSettlementKey)((0, _virtualSettlement.getSelectedSettlementSnapshot)(product)) || 'legal_currency';
|
|
3122
|
+
if (currentKey && currentKey !== incomingKey) {
|
|
3123
|
+
throw new _virtualSettlement.OrderSettlementConflictError(currentKey, incomingKey);
|
|
3124
|
+
}
|
|
3125
|
+
const snapshot = (0, _virtualSettlement.getSelectedSettlementSnapshot)(product);
|
|
3126
|
+
if (snapshot?.settlement_type === 'virtual_currency' && tempOrder.customer_id && Number(tempOrder.customer_id) !== 1) {
|
|
3127
|
+
const currencyProductId = Number(snapshot.currency_product_id);
|
|
3128
|
+
const asset = (this.store.virtualCurrencyList || []).find(item => Number(item?.product_id) === currencyProductId);
|
|
3129
|
+
if (!asset) {
|
|
3130
|
+
throw new _virtualSettlement.VirtualCurrencyAssetNotFoundError(currencyProductId);
|
|
3131
|
+
}
|
|
3132
|
+
const existedAmount = tempOrder.products.reduce((sum, item) => sum.plus(new _decimal.default(item.selling_price || 0).times(item.num || 1)), new _decimal.default(0));
|
|
3133
|
+
const requiredAmount = existedAmount.plus(new _decimal.default(snapshot.price || 0).times(product.num || 1));
|
|
3134
|
+
const balance = new _decimal.default(asset.balance || 0);
|
|
3135
|
+
if (balance.lt(requiredAmount)) {
|
|
3136
|
+
throw new _virtualSettlement.VirtualCurrencyBalanceError(balance.toFixed(2), requiredAmount.toFixed(2));
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
(0, _virtualSettlement.applyTempOrderSettlementState)(tempOrder, snapshot || {
|
|
3140
|
+
settlement_type: 'legal_currency',
|
|
3141
|
+
price: product.selling_price ?? product.original_price ?? product.payment_price ?? 0,
|
|
3142
|
+
unit_label: tempOrder.currency_code,
|
|
3143
|
+
symbol: tempOrder.currency_symbol,
|
|
3144
|
+
amount_format: tempOrder.currency_format
|
|
3145
|
+
});
|
|
3146
|
+
}
|
|
3147
|
+
syncTempOrderSettlementState(tempOrder) {
|
|
3148
|
+
if (!this.isMultiCurrencySettlementEnabled()) return;
|
|
3149
|
+
tempOrder.metadata = tempOrder.metadata || {};
|
|
3150
|
+
if (!tempOrder.products.length) {
|
|
3151
|
+
(0, _virtualSettlement.releaseTempOrderSettlementState)(tempOrder);
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
const snapshot = (0, _virtualSettlement.getTempOrderSettlementSnapshot)(tempOrder);
|
|
3155
|
+
if (snapshot) {
|
|
3156
|
+
(0, _virtualSettlement.applyTempOrderSettlementState)(tempOrder, snapshot);
|
|
3157
|
+
return;
|
|
3158
|
+
}
|
|
3159
|
+
tempOrder.metadata.cart_settlement_key = 'legal_currency';
|
|
3160
|
+
}
|
|
3161
|
+
prepareVirtualSettlementTempOrder(tempOrder) {
|
|
3162
|
+
if (!this.isMultiCurrencySettlementEnabled()) return;
|
|
3163
|
+
this.syncTempOrderSettlementState(tempOrder);
|
|
3164
|
+
if (!this.isActiveVirtualSettlementOrder(tempOrder)) return;
|
|
3165
|
+
tempOrder.products = (0, _virtualSettlement.normalizeVirtualSettlementProducts)(tempOrder.products);
|
|
3166
|
+
tempOrder.discount_list = [];
|
|
3167
|
+
tempOrder.shop_discount = '0.00';
|
|
3168
|
+
tempOrder.surcharge_fee = '0.00';
|
|
3169
|
+
tempOrder.surcharges = [];
|
|
3170
|
+
const virtualOrder = tempOrder;
|
|
3171
|
+
virtualOrder.discount_amount = '0.00';
|
|
3172
|
+
virtualOrder.product_tax_fee = '0.00';
|
|
3173
|
+
virtualOrder.tax_fee = '0.00';
|
|
3174
|
+
virtualOrder.shipping_fee = '0.00';
|
|
3175
|
+
virtualOrder.shipping_tax_fee = '0.00';
|
|
3176
|
+
virtualOrder.tip_fee = '0.00';
|
|
3177
|
+
}
|
|
2779
3178
|
|
|
2780
3179
|
// ─── TempOrder: 商品 CRUD ───
|
|
2781
3180
|
|
|
@@ -2787,13 +3186,13 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2787
3186
|
*/
|
|
2788
3187
|
async finalizeProductOrderMutation(tempOrder, options) {
|
|
2789
3188
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
2790
|
-
|
|
3189
|
+
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
3190
|
+
const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
|
|
3191
|
+
if (!options?.skipEditDiscountConfigRefresh && !isVirtualSettlement) {
|
|
2791
3192
|
await this.ensureEditDiscountConfigForProductChange(tempOrder);
|
|
2792
3193
|
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
}
|
|
2796
|
-
if (!options?.skipDiscountRecalculation) {
|
|
3194
|
+
const promotionPayload = !options?.skipDiscountRecalculation && !isVirtualSettlement ? await this.evaluatePromotion() : null;
|
|
3195
|
+
if (!options?.skipDiscountRecalculation && !isVirtualSettlement) {
|
|
2797
3196
|
this.applyDiscount();
|
|
2798
3197
|
}
|
|
2799
3198
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
@@ -2801,6 +3200,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2801
3200
|
createIfMissing: true
|
|
2802
3201
|
});
|
|
2803
3202
|
this.persistTempOrder();
|
|
3203
|
+
this.emitPromotionApplied(promotionPayload);
|
|
2804
3204
|
}
|
|
2805
3205
|
|
|
2806
3206
|
/**
|
|
@@ -2821,9 +3221,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2821
3221
|
booking
|
|
2822
3222
|
}) : null;
|
|
2823
3223
|
const productToAdd = linked?.product || product;
|
|
3224
|
+
this.assertAndLockProductSettlement(tempOrder, productToAdd);
|
|
2824
3225
|
const disableMerge = options?.disableMerge === true;
|
|
2825
3226
|
const incomingFingerprint = disableMerge ? '' : (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(productToAdd), productToAdd.product_bundle);
|
|
2826
|
-
const normalizedIncoming = (0, _utils.mergeOrderProductDisplayFields)(productToAdd, (0, _utils3.normalizeOrderProduct)(productToAdd));
|
|
3227
|
+
const normalizedIncoming = this.normalizeVirtualSettlementProductIfEnabled((0, _utils.mergeOrderProductDisplayFields)(productToAdd, (0, _utils3.normalizeOrderProduct)(productToAdd)));
|
|
2827
3228
|
if (disableMerge) {
|
|
2828
3229
|
normalizedIncoming.metadata = {
|
|
2829
3230
|
...(normalizedIncoming.metadata || {}),
|
|
@@ -2864,6 +3265,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2864
3265
|
const matchedProduct = matchedIndex === -1 ? null : tempOrder.products[matchedIndex];
|
|
2865
3266
|
const existedFingerprint = matchedProduct ? (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(matchedProduct), matchedProduct.product_bundle) : '';
|
|
2866
3267
|
const commitProductLine = shouldMerge => {
|
|
3268
|
+
let committedProduct;
|
|
2867
3269
|
if (matchedIndex === -1 || !matchedProduct || !shouldMerge) {
|
|
2868
3270
|
this.captureProductRuntime(tempOrder, productToAdd, normalizedIncoming);
|
|
2869
3271
|
if (linked) {
|
|
@@ -2879,16 +3281,17 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2879
3281
|
} else {
|
|
2880
3282
|
tempOrder.products = [...tempOrder.products, normalizedIncoming];
|
|
2881
3283
|
}
|
|
3284
|
+
committedProduct = normalizedIncoming;
|
|
2882
3285
|
} else {
|
|
2883
3286
|
const targetProduct = matchedProduct;
|
|
2884
3287
|
const targetUid = targetProduct.metadata?.unique_identification_number;
|
|
2885
|
-
const normalizedProduct = (0, _utils.mergeOrderProductDisplayFields)(targetProduct, (0, _utils3.normalizeOrderProduct)({
|
|
3288
|
+
const normalizedProduct = this.normalizeVirtualSettlementProductIfEnabled((0, _utils.mergeOrderProductDisplayFields)(targetProduct, (0, _utils3.normalizeOrderProduct)({
|
|
2886
3289
|
...productToAdd,
|
|
2887
3290
|
metadata: {
|
|
2888
3291
|
...(productToAdd.metadata || {}),
|
|
2889
3292
|
unique_identification_number: targetUid
|
|
2890
3293
|
}
|
|
2891
|
-
}));
|
|
3294
|
+
})));
|
|
2892
3295
|
normalizedProduct.discount_list = (0, _utils.normalizeOrderProductDiscountList)(normalizedProduct.discount_list);
|
|
2893
3296
|
const nextNum = (0, _utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
|
|
2894
3297
|
tempOrder.products[matchedIndex] = {
|
|
@@ -2914,6 +3317,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2914
3317
|
num: nextNum
|
|
2915
3318
|
};
|
|
2916
3319
|
this.captureProductRuntime(tempOrder, productToAdd, tempOrder.products[matchedIndex], targetUid);
|
|
3320
|
+
committedProduct = tempOrder.products[matchedIndex];
|
|
2917
3321
|
if (matchedIndex !== tempOrder.products.length - 1) {
|
|
2918
3322
|
const mergedProduct = tempOrder.products[matchedIndex];
|
|
2919
3323
|
tempOrder.products = [...tempOrder.products.slice(0, matchedIndex), ...tempOrder.products.slice(matchedIndex + 1), mergedProduct];
|
|
@@ -2922,10 +3326,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2922
3326
|
if (linked) {
|
|
2923
3327
|
tempOrder.bookings = [...(tempOrder.bookings || []), linked.booking];
|
|
2924
3328
|
}
|
|
3329
|
+
return committedProduct;
|
|
2925
3330
|
};
|
|
2926
3331
|
if (!matchedProduct) {
|
|
2927
|
-
commitProductLine(false);
|
|
2928
|
-
return;
|
|
3332
|
+
return commitProductLine(false);
|
|
2929
3333
|
}
|
|
2930
3334
|
const shouldMerge = this.shouldMergeProductToOrder({
|
|
2931
3335
|
incomingProduct: productToAdd,
|
|
@@ -2940,7 +3344,68 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2940
3344
|
if (shouldMerge && typeof shouldMerge === 'object' && typeof shouldMerge.then === 'function') {
|
|
2941
3345
|
return Promise.resolve(shouldMerge).then(commitProductLine);
|
|
2942
3346
|
}
|
|
2943
|
-
commitProductLine(shouldMerge);
|
|
3347
|
+
return commitProductLine(shouldMerge);
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
/**
|
|
3351
|
+
* booking 数量拆行时,若 Holder 数量与拆行数严格一致,则按下标分配。
|
|
3352
|
+
* 数量不一致时保持旧数据,避免猜测 Holder 与商品份数的对应关系。
|
|
3353
|
+
*/
|
|
3354
|
+
createSplitBookingLine(product, booking, index, splitCount) {
|
|
3355
|
+
const singleLine = (0, _lodashEs.cloneDeep)(product);
|
|
3356
|
+
singleLine.num = 1;
|
|
3357
|
+
delete singleLine.product_quantity;
|
|
3358
|
+
const singleBooking = (0, _lodashEs.cloneDeep)(booking);
|
|
3359
|
+
const bookingHolder = booking?.holder && typeof booking.holder === 'object' ? booking.holder : null;
|
|
3360
|
+
const metadataHolder = booking?.metadata?.holder && typeof booking.metadata.holder === 'object' ? booking.metadata.holder : null;
|
|
3361
|
+
const rawHolderIds = bookingHolder?.form_record ?? booking?.metadata?.holder_id ?? metadataHolder?.form_record ?? product?.metadata?.holder_id;
|
|
3362
|
+
const holderIds = (Array.isArray(rawHolderIds) ? rawHolderIds : [rawHolderIds]).map(holderId => holderId && typeof holderId === 'object' ? holderId.form_record_id : holderId).filter(holderId => holderId !== undefined && holderId !== null && holderId !== '');
|
|
3363
|
+
if (holderIds.length !== splitCount) {
|
|
3364
|
+
return {
|
|
3365
|
+
product: singleLine,
|
|
3366
|
+
booking: singleBooking
|
|
3367
|
+
};
|
|
3368
|
+
}
|
|
3369
|
+
const holderId = holderIds[index];
|
|
3370
|
+
const rawHolderName = bookingHolder?.name ?? metadataHolder?.name;
|
|
3371
|
+
const holderNames = Array.isArray(rawHolderName) ? rawHolderName.map(name => String(name || '').trim()) : typeof rawHolderName === 'string' ? rawHolderName.split(',').map(name => name.trim()) : [];
|
|
3372
|
+
const holderName = holderNames.length === splitCount ? holderNames[index] : undefined;
|
|
3373
|
+
const splitHolder = holder => ({
|
|
3374
|
+
...holder,
|
|
3375
|
+
form_record: [holderId],
|
|
3376
|
+
...(holderName ? {
|
|
3377
|
+
name: holderName
|
|
3378
|
+
} : Object.prototype.hasOwnProperty.call(holder, 'name') ? {
|
|
3379
|
+
name: undefined
|
|
3380
|
+
} : {})
|
|
3381
|
+
});
|
|
3382
|
+
singleLine.metadata = {
|
|
3383
|
+
...(singleLine.metadata || {}),
|
|
3384
|
+
holder_id: [holderId]
|
|
3385
|
+
};
|
|
3386
|
+
if (singleLine._extend && typeof singleLine._extend === 'object') {
|
|
3387
|
+
singleLine._extend = {
|
|
3388
|
+
...singleLine._extend,
|
|
3389
|
+
holder_id: [holderId]
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
if (singleBooking.holder && typeof singleBooking.holder === 'object') {
|
|
3393
|
+
singleBooking.holder = splitHolder(singleBooking.holder);
|
|
3394
|
+
}
|
|
3395
|
+
singleBooking.metadata = {
|
|
3396
|
+
...(singleBooking.metadata || {}),
|
|
3397
|
+
holder_id: [holderId],
|
|
3398
|
+
...(singleBooking.metadata?.holder && typeof singleBooking.metadata.holder === 'object' ? {
|
|
3399
|
+
holder: splitHolder(singleBooking.metadata.holder)
|
|
3400
|
+
} : {})
|
|
3401
|
+
};
|
|
3402
|
+
if (Object.prototype.hasOwnProperty.call(singleBooking, 'holder_id')) {
|
|
3403
|
+
singleBooking.holder_id = [holderId];
|
|
3404
|
+
}
|
|
3405
|
+
return {
|
|
3406
|
+
product: singleLine,
|
|
3407
|
+
booking: singleBooking
|
|
3408
|
+
};
|
|
2944
3409
|
}
|
|
2945
3410
|
|
|
2946
3411
|
/**
|
|
@@ -2952,36 +3417,99 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2952
3417
|
*/
|
|
2953
3418
|
async addProductToOrder(product, booking, options) {
|
|
2954
3419
|
const tempOrder = this.ensureTempOrder();
|
|
3420
|
+
const salesNoteDrafts = (options?.salesNotes || []).map(draft => ({
|
|
3421
|
+
note_type: String(draft.note_type || '').trim(),
|
|
3422
|
+
text: {
|
|
3423
|
+
kind: 'resolved',
|
|
3424
|
+
text: (0, _salesNotes.buildSalesNoteText)(draft.text)
|
|
3425
|
+
}
|
|
3426
|
+
}));
|
|
3427
|
+
const mutationSnapshot = salesNoteDrafts.length > 0 ? {
|
|
3428
|
+
products: (0, _lodashEs.cloneDeep)(tempOrder.products || []),
|
|
3429
|
+
bookings: (0, _lodashEs.cloneDeep)(tempOrder.bookings || []),
|
|
3430
|
+
notes: (0, _lodashEs.cloneDeep)(tempOrder.notes || []),
|
|
3431
|
+
extend: (0, _lodashEs.cloneDeep)(tempOrder._extend || {})
|
|
3432
|
+
} : null;
|
|
3433
|
+
const attachSalesNoteDrafts = orderProduct => {
|
|
3434
|
+
if (!salesNoteDrafts.length) return;
|
|
3435
|
+
const productLineUid = orderProduct.metadata?.unique_identification_number || orderProduct.unique_identification_number;
|
|
3436
|
+
if (!productLineUid) {
|
|
3437
|
+
throw new Error('[Order Notes] 商品行缺少 unique_identification_number');
|
|
3438
|
+
}
|
|
3439
|
+
salesNoteDrafts.forEach(draft => {
|
|
3440
|
+
this.setSalesNoteOnTempOrder(tempOrder, {
|
|
3441
|
+
note_type: draft.note_type,
|
|
3442
|
+
target: {
|
|
3443
|
+
target_type: 'order_detail',
|
|
3444
|
+
target_uuid: String(productLineUid)
|
|
3445
|
+
},
|
|
3446
|
+
text: draft.text
|
|
3447
|
+
});
|
|
3448
|
+
});
|
|
3449
|
+
};
|
|
3450
|
+
const rollbackProductAndNotesMutation = () => {
|
|
3451
|
+
if (!mutationSnapshot) return;
|
|
3452
|
+
tempOrder.products = mutationSnapshot.products;
|
|
3453
|
+
tempOrder.bookings = mutationSnapshot.bookings;
|
|
3454
|
+
tempOrder.notes = mutationSnapshot.notes;
|
|
3455
|
+
tempOrder._extend = mutationSnapshot.extend;
|
|
3456
|
+
};
|
|
2955
3457
|
const insertAfterProductUid = options?.insertAfterProductUid;
|
|
2956
3458
|
const anchorIndex = booking && insertAfterProductUid ? tempOrder.products.findIndex(line => {
|
|
2957
3459
|
const uid = line.metadata?.unique_identification_number || line.unique_identification_number;
|
|
2958
3460
|
return uid !== undefined && uid !== null && String(uid) === String(insertAfterProductUid);
|
|
2959
3461
|
}) : -1;
|
|
2960
3462
|
let insertAtIndex = anchorIndex >= 0 ? anchorIndex + 1 : undefined;
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
3463
|
+
try {
|
|
3464
|
+
if (booking) {
|
|
3465
|
+
const productRecord = product;
|
|
3466
|
+
const splitCount = (0, _utils3.getSafeProductNum)(productRecord.num ?? productRecord.product_quantity ?? 1);
|
|
3467
|
+
if (splitCount > 1) {
|
|
3468
|
+
for (let i = 0; i < splitCount; i += 1) {
|
|
3469
|
+
const splitLine = this.createSplitBookingLine(productRecord, booking, i, splitCount);
|
|
3470
|
+
if (i > 0) {
|
|
3471
|
+
delete splitLine.product.unique_identification_number;
|
|
3472
|
+
delete splitLine.product.identity_key;
|
|
3473
|
+
if (splitLine.product.metadata) {
|
|
3474
|
+
splitLine.product.metadata = {
|
|
3475
|
+
...splitLine.product.metadata
|
|
3476
|
+
};
|
|
3477
|
+
delete splitLine.product.metadata.unique_identification_number;
|
|
3478
|
+
delete splitLine.product.metadata.identity_key;
|
|
3479
|
+
}
|
|
3480
|
+
delete splitLine.booking.booking_uid;
|
|
3481
|
+
if (splitLine.booking.metadata) {
|
|
3482
|
+
splitLine.booking.metadata = {
|
|
3483
|
+
...splitLine.booking.metadata
|
|
3484
|
+
};
|
|
3485
|
+
delete splitLine.booking.metadata.unique_identification_number;
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking, {
|
|
3489
|
+
insertAtIndex,
|
|
3490
|
+
disableMerge: options?.disableMerge
|
|
3491
|
+
});
|
|
3492
|
+
attachSalesNoteDrafts(committedProduct);
|
|
3493
|
+
if (insertAtIndex !== undefined) insertAtIndex += 1;
|
|
3494
|
+
}
|
|
3495
|
+
} else {
|
|
3496
|
+
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, (0, _lodashEs.cloneDeep)(booking), {
|
|
2970
3497
|
insertAtIndex,
|
|
2971
3498
|
disableMerge: options?.disableMerge
|
|
2972
3499
|
});
|
|
2973
|
-
|
|
2974
|
-
if (insertAtIndex !== undefined) insertAtIndex += 1;
|
|
3500
|
+
attachSalesNoteDrafts(committedProduct);
|
|
2975
3501
|
}
|
|
2976
|
-
|
|
2977
|
-
|
|
3502
|
+
} else {
|
|
3503
|
+
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, undefined, {
|
|
3504
|
+
insertAtIndex,
|
|
3505
|
+
disableMerge: options?.disableMerge
|
|
3506
|
+
});
|
|
3507
|
+
attachSalesNoteDrafts(committedProduct);
|
|
2978
3508
|
}
|
|
3509
|
+
} catch (error) {
|
|
3510
|
+
rollbackProductAndNotesMutation();
|
|
3511
|
+
throw error;
|
|
2979
3512
|
}
|
|
2980
|
-
const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking, {
|
|
2981
|
-
insertAtIndex,
|
|
2982
|
-
disableMerge: options?.disableMerge
|
|
2983
|
-
});
|
|
2984
|
-
if (appendResult) await appendResult;
|
|
2985
3513
|
await this.finalizeProductOrderMutation(tempOrder);
|
|
2986
3514
|
this.logInfo('addProductToOrder success', {
|
|
2987
3515
|
product_id: product.product_id,
|
|
@@ -3013,10 +3541,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3013
3541
|
const splitCount = (0, _utils3.getSafeProductNum)(productRecord.num ?? productRecord.product_quantity ?? 1);
|
|
3014
3542
|
if (splitCount > 1) {
|
|
3015
3543
|
for (let i = 0; i < splitCount; i += 1) {
|
|
3016
|
-
const
|
|
3017
|
-
|
|
3018
|
-
delete singleLine.product_quantity;
|
|
3019
|
-
const appendResult = this.appendProductLineToTempOrder(tempOrder, singleLine, (0, _lodashEs.cloneDeep)(booking));
|
|
3544
|
+
const splitLine = this.createSplitBookingLine(productRecord, booking, i, splitCount);
|
|
3545
|
+
const appendResult = this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking);
|
|
3020
3546
|
if (appendResult) await appendResult;
|
|
3021
3547
|
}
|
|
3022
3548
|
continue;
|
|
@@ -3229,7 +3755,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3229
3755
|
}
|
|
3230
3756
|
// normalizeOrderProduct 幂等:v2 metadata 存在 → 保留 main_product_* 折扣重算 composite;
|
|
3231
3757
|
// 否则 → 把顶层 selling_price 视作 source,派生 main_product_* 并写 price_schema_version: 2。
|
|
3232
|
-
let normalizedProduct = (0, _utils.mergeOrderProductDisplayFields)(nextProduct, (0, _utils3.normalizeOrderProduct)(nextProduct));
|
|
3758
|
+
let normalizedProduct = this.normalizeVirtualSettlementProductIfEnabled((0, _utils.mergeOrderProductDisplayFields)(nextProduct, (0, _utils3.normalizeOrderProduct)(nextProduct)));
|
|
3233
3759
|
normalizedProduct.discount_list = (0, _utils.normalizeOrderProductDiscountList)(normalizedProduct.discount_list);
|
|
3234
3760
|
const preservedBookingUid = nextProduct.booking_uid || nextProduct.metadata?.booking_uid || targetProduct.booking_uid || targetProduct.metadata?.booking_uid;
|
|
3235
3761
|
if (!booking && preservedBookingUid) {
|
|
@@ -3272,7 +3798,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3272
3798
|
async updateOrderProduct(params) {
|
|
3273
3799
|
const tempOrder = this.ensureTempOrder();
|
|
3274
3800
|
const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
3275
|
-
await this.
|
|
3801
|
+
const promotionPayload = await this.evaluatePromotion();
|
|
3276
3802
|
this.applyDiscount({
|
|
3277
3803
|
reapplyBookingDiscountProductUids: params.allow_booking_discount_reapply && updatedProductUid ? [String(updatedProductUid)] : undefined
|
|
3278
3804
|
});
|
|
@@ -3281,6 +3807,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3281
3807
|
createIfMissing: true
|
|
3282
3808
|
});
|
|
3283
3809
|
this.persistTempOrder();
|
|
3810
|
+
this.emitPromotionApplied(promotionPayload);
|
|
3284
3811
|
this.logInfo('updateOrderProduct success', {
|
|
3285
3812
|
params
|
|
3286
3813
|
});
|
|
@@ -3346,23 +3873,45 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3346
3873
|
throw new Error('[Order] 目标商品不存在,无法更新数量');
|
|
3347
3874
|
}
|
|
3348
3875
|
const targetProduct = tempOrder.products[productIndex];
|
|
3349
|
-
const normalizedProduct = (0, _utils3.normalizeOrderProduct)({
|
|
3876
|
+
const normalizedProduct = this.normalizeVirtualSettlementProductIfEnabled((0, _utils3.normalizeOrderProduct)({
|
|
3350
3877
|
...targetProduct,
|
|
3351
3878
|
num: (0, _utils3.getSafeProductNum)(num),
|
|
3352
3879
|
metadata: {
|
|
3353
3880
|
...(targetProduct.metadata || {}),
|
|
3354
3881
|
unique_identification_number: targetProduct.metadata?.unique_identification_number || unique_identification_number
|
|
3355
3882
|
}
|
|
3356
|
-
});
|
|
3883
|
+
}));
|
|
3357
3884
|
normalizedProduct.discount_list = (0, _utils.normalizeOrderProductDiscountList)(normalizedProduct.discount_list);
|
|
3885
|
+
const settlementSnapshot = (0, _virtualSettlement.getSelectedSettlementSnapshot)(normalizedProduct);
|
|
3886
|
+
if (this.isMultiCurrencySettlementEnabled() && settlementSnapshot?.settlement_type === 'virtual_currency' && tempOrder.customer_id && Number(tempOrder.customer_id) !== 1) {
|
|
3887
|
+
const currencyProductId = Number(settlementSnapshot.currency_product_id);
|
|
3888
|
+
const asset = (this.store.virtualCurrencyList || []).find(item => Number(item?.product_id) === currencyProductId);
|
|
3889
|
+
if (!asset) {
|
|
3890
|
+
throw new _virtualSettlement.VirtualCurrencyAssetNotFoundError(currencyProductId);
|
|
3891
|
+
}
|
|
3892
|
+
const requiredAmount = tempOrder.products.reduce((sum, item, index) => {
|
|
3893
|
+
const current = index === productIndex ? normalizedProduct : item;
|
|
3894
|
+
const currentSnapshot = (0, _virtualSettlement.getSelectedSettlementSnapshot)(current);
|
|
3895
|
+
return sum.plus(new _decimal.default(currentSnapshot?.price || current.selling_price || 0).times(current.num || 1));
|
|
3896
|
+
}, new _decimal.default(0));
|
|
3897
|
+
const balance = new _decimal.default(asset.balance || 0);
|
|
3898
|
+
if (balance.lt(requiredAmount)) {
|
|
3899
|
+
throw new _virtualSettlement.VirtualCurrencyBalanceError(balance.toFixed(2), requiredAmount.toFixed(2));
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3358
3902
|
tempOrder.products[productIndex] = normalizedProduct;
|
|
3359
|
-
|
|
3360
|
-
this.
|
|
3903
|
+
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
3904
|
+
const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
|
|
3905
|
+
const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
|
|
3906
|
+
if (!isVirtualSettlement) {
|
|
3907
|
+
this.applyDiscount();
|
|
3908
|
+
}
|
|
3361
3909
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
3362
3910
|
await this.recalculateSummary({
|
|
3363
3911
|
createIfMissing: true
|
|
3364
3912
|
});
|
|
3365
3913
|
this.persistTempOrder();
|
|
3914
|
+
this.emitPromotionApplied(promotionPayload);
|
|
3366
3915
|
this.logInfo('updateOrderProductQuantity success', {
|
|
3367
3916
|
params
|
|
3368
3917
|
});
|
|
@@ -3407,7 +3956,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3407
3956
|
*/
|
|
3408
3957
|
async finalizeAfterProductsMutation(tempOrder, options) {
|
|
3409
3958
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
3410
|
-
await this.
|
|
3959
|
+
const promotionPayload = await this.evaluatePromotion();
|
|
3411
3960
|
this.applyDiscount({
|
|
3412
3961
|
reapplyBookingDiscountProductUids: options?.reapplyBookingDiscountProductUids
|
|
3413
3962
|
});
|
|
@@ -3416,6 +3965,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3416
3965
|
createIfMissing: true
|
|
3417
3966
|
});
|
|
3418
3967
|
this.persistTempOrder();
|
|
3968
|
+
this.emitPromotionApplied(promotionPayload);
|
|
3419
3969
|
}
|
|
3420
3970
|
|
|
3421
3971
|
/**
|
|
@@ -3426,10 +3976,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3426
3976
|
*/
|
|
3427
3977
|
async removeProductsFromOrder(identities, options) {
|
|
3428
3978
|
const tempOrder = this.ensureTempOrder();
|
|
3429
|
-
this.repairDuplicateProductLineIdentities(tempOrder);
|
|
3430
3979
|
if (!identities.length) {
|
|
3431
3980
|
return tempOrder.products;
|
|
3432
3981
|
}
|
|
3982
|
+
// 商品删除会同步删除以商品行为主关系的 Notes;快照不完整时禁止产生孤儿 Relation。
|
|
3983
|
+
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
3984
|
+
this.repairDuplicateProductLineIdentities(tempOrder);
|
|
3433
3985
|
const productsBeforeRemove = tempOrder.products || [];
|
|
3434
3986
|
const bookingsBeforeRemove = tempOrder.bookings || [];
|
|
3435
3987
|
const preserveDisplayPosition = options?.preserveDisplayPosition;
|
|
@@ -3489,6 +4041,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3489
4041
|
tempOrder.products = nextProductIndex >= 0 ? [...productsWithoutRemaining.slice(0, nextProductIndex), remainingProduct, ...productsWithoutRemaining.slice(nextProductIndex)] : [...productsWithoutRemaining, remainingProduct];
|
|
3490
4042
|
}
|
|
3491
4043
|
}
|
|
4044
|
+
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
3492
4045
|
await this.finalizeAfterProductsMutation(tempOrder);
|
|
3493
4046
|
this.logInfo('removeProductsFromOrder success', {
|
|
3494
4047
|
identities
|
|
@@ -3501,12 +4054,15 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3501
4054
|
|
|
3502
4055
|
/**
|
|
3503
4056
|
* 仅清空购物车行(products / bookings),不重置整单。
|
|
3504
|
-
*
|
|
4057
|
+
* 普通整单 note 保持不变;以商品行为主体的 Sales Notes 同步删除。
|
|
3505
4058
|
*/
|
|
3506
4059
|
async clearOrderCartLines() {
|
|
3507
4060
|
const tempOrder = this.ensureTempOrder();
|
|
4061
|
+
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
3508
4062
|
tempOrder.products = [];
|
|
3509
4063
|
tempOrder.bookings = [];
|
|
4064
|
+
(0, _virtualSettlement.releaseTempOrderSettlementState)(tempOrder);
|
|
4065
|
+
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
3510
4066
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
3511
4067
|
if (tempOrder._extend && typeof tempOrder._extend === 'object') {
|
|
3512
4068
|
tempOrder._extend = {
|
|
@@ -3514,17 +4070,53 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3514
4070
|
productsByUid: {}
|
|
3515
4071
|
};
|
|
3516
4072
|
}
|
|
3517
|
-
await this.
|
|
4073
|
+
const promotionPayload = await this.evaluatePromotion();
|
|
3518
4074
|
this.applyDiscount();
|
|
3519
4075
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
3520
4076
|
await this.recalculateSummary({
|
|
3521
4077
|
createIfMissing: true
|
|
3522
4078
|
});
|
|
3523
4079
|
this.persistTempOrder();
|
|
4080
|
+
this.emitPromotionApplied(promotionPayload);
|
|
3524
4081
|
this.logInfo('clearOrderCartLines success', {});
|
|
3525
4082
|
return tempOrder;
|
|
3526
4083
|
}
|
|
3527
4084
|
|
|
4085
|
+
/**
|
|
4086
|
+
* 切换购物车结算单位时清理所有会影响新币种的订单状态,但保留当前客户。
|
|
4087
|
+
*/
|
|
4088
|
+
async clearOrderForSettlementSwitch() {
|
|
4089
|
+
const tempOrder = this.ensureTempOrder();
|
|
4090
|
+
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
4091
|
+
tempOrder.products = [];
|
|
4092
|
+
tempOrder.bookings = [];
|
|
4093
|
+
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
4094
|
+
tempOrder.discount_list = [];
|
|
4095
|
+
tempOrder.payments = [];
|
|
4096
|
+
tempOrder.refunds = [];
|
|
4097
|
+
tempOrder.shop_discount = '0.00';
|
|
4098
|
+
tempOrder.surcharges = [];
|
|
4099
|
+
(0, _virtualSettlement.releaseTempOrderSettlementState)(tempOrder);
|
|
4100
|
+
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
4101
|
+
if (tempOrder._extend && typeof tempOrder._extend === 'object') {
|
|
4102
|
+
tempOrder._extend = {
|
|
4103
|
+
...tempOrder._extend,
|
|
4104
|
+
productsByUid: {}
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
await this.store.discount?.setDiscountList([]);
|
|
4108
|
+
await this.store.discount?.setOriginalDiscountList([]);
|
|
4109
|
+
this.hasActiveCustomerBoundDiscount = false;
|
|
4110
|
+
this.lastUnfulfilledPromotions = [];
|
|
4111
|
+
this.lastGiftActions = null;
|
|
4112
|
+
await this.recalculateSummary({
|
|
4113
|
+
createIfMissing: true
|
|
4114
|
+
});
|
|
4115
|
+
this.persistTempOrder();
|
|
4116
|
+
this.logInfo('clearOrderForSettlementSwitch success', {});
|
|
4117
|
+
return tempOrder;
|
|
4118
|
+
}
|
|
4119
|
+
|
|
3528
4120
|
// ─── TempOrder: 提交 ───
|
|
3529
4121
|
|
|
3530
4122
|
buildCurrentSubmitPayloadForLocalPrint(params) {
|
|
@@ -3614,9 +4206,14 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3614
4206
|
}
|
|
3615
4207
|
async runSubmitTempOrder(params) {
|
|
3616
4208
|
const tempOrder = this.ensureTempOrder();
|
|
4209
|
+
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
4210
|
+
const isOnlineStorePlatform = this.isOnlineStorePlatform();
|
|
3617
4211
|
const shouldConfirmPendingVoucherPayments = params?.confirmPendingVoucherPayments !== false;
|
|
3618
4212
|
const hasPaymentOverride = params?.payments !== undefined;
|
|
3619
|
-
|
|
4213
|
+
let preparedPaymentOverride;
|
|
4214
|
+
if (hasPaymentOverride) {
|
|
4215
|
+
preparedPaymentOverride = isOnlineStorePlatform ? params?.payments || [] : this.prepareVoucherPaymentsForSubmit(params?.payments || [], shouldConfirmPendingVoucherPayments);
|
|
4216
|
+
}
|
|
3620
4217
|
if (!hasPaymentOverride) {
|
|
3621
4218
|
if (shouldConfirmPendingVoucherPayments) {
|
|
3622
4219
|
this.confirmPendingVoucherPayments({
|
|
@@ -3636,6 +4233,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3636
4233
|
})) || this.store.summary || (0, _utils.createEmptySummary)();
|
|
3637
4234
|
const effectiveCacheId = params?.cacheId ?? this.cacheId;
|
|
3638
4235
|
const hasPaymentStatusOverride = params?.paymentStatus !== undefined;
|
|
4236
|
+
const shouldOverridePaymentStatus = hasPaymentStatusOverride && !isOnlineStorePlatform && !shouldConfirmPendingVoucherPayments;
|
|
3639
4237
|
const hasSmallTicketDataFlagOverride = params?.smallTicketDataFlag !== undefined;
|
|
3640
4238
|
const enhancePayload = hasPaymentOverride || hasPaymentStatusOverride || hasSmallTicketDataFlagOverride || params?.enhancePayload ? (payload, ctx) => {
|
|
3641
4239
|
const nextPayload = {
|
|
@@ -3643,7 +4241,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3643
4241
|
...(hasPaymentOverride ? {
|
|
3644
4242
|
payments: preparedPaymentOverride || []
|
|
3645
4243
|
} : {}),
|
|
3646
|
-
...(
|
|
4244
|
+
...(shouldOverridePaymentStatus ? {
|
|
3647
4245
|
payment_status: params?.paymentStatus
|
|
3648
4246
|
} : {}),
|
|
3649
4247
|
...(hasSmallTicketDataFlagOverride ? {
|
|
@@ -3663,6 +4261,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3663
4261
|
type: submitSnapshot.type ?? params?.type,
|
|
3664
4262
|
summary: latestSummary,
|
|
3665
4263
|
request_unique_idempotency_token: params?.request_unique_idempotency_token,
|
|
4264
|
+
includePaymentStatus: !isOnlineStorePlatform,
|
|
3666
4265
|
enhance: enhancePayload
|
|
3667
4266
|
});
|
|
3668
4267
|
if (params?.syncMode) {
|
|
@@ -3709,6 +4308,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3709
4308
|
this.logSubmitBackendRejected(result, payload);
|
|
3710
4309
|
return result;
|
|
3711
4310
|
}
|
|
4311
|
+
const isLocalPendingSubmit = this.isLocalPendingSubmitResult(result);
|
|
4312
|
+
// need_sync=1 仅表示已进入本地同步队列,不能视为远端已确认 Notes。
|
|
4313
|
+
if (Object.prototype.hasOwnProperty.call(payload, 'notes') && !isLocalPendingSubmit) {
|
|
4314
|
+
const salesNotesState = this.ensureSalesNotesRuntimeState(tempOrder);
|
|
4315
|
+
salesNotesState.dirty = false;
|
|
4316
|
+
}
|
|
3712
4317
|
const submittedOrderId = this.extractOrderIdFromSubmitResult(result);
|
|
3713
4318
|
this.logInfo('runSubmitTempOrder: 提交成功', {
|
|
3714
4319
|
submittedOrderId,
|
|
@@ -3722,9 +4327,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3722
4327
|
tempOrder.order_id = submittedOrderId;
|
|
3723
4328
|
const resultRecord = result;
|
|
3724
4329
|
await this.markLocalOrderSynced(submittedOrderId, resultRecord?.data || resultRecord || {});
|
|
3725
|
-
}
|
|
4330
|
+
}
|
|
4331
|
+
if (isLocalPendingSubmit) {
|
|
3726
4332
|
this.store.syncState = 'local';
|
|
3727
|
-
} else {
|
|
4333
|
+
} else if (submittedOrderId === null || submittedOrderId === undefined) {
|
|
3728
4334
|
this.store.syncState = 'submitted';
|
|
3729
4335
|
}
|
|
3730
4336
|
return result;
|
|
@@ -4110,7 +4716,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4110
4716
|
params.forceRemote = false;
|
|
4111
4717
|
}
|
|
4112
4718
|
const res = await this.request.get(`/order/sales/${encodeURIComponent(lookup)}`, {
|
|
4113
|
-
with: ['products', 'bookings', 'payments', 'customer', 'summary', 'contacts_info', 'refunds'],
|
|
4719
|
+
with: ['products', 'bookings', 'payments', 'customer', 'summary', 'contacts_info', 'order_meta_list', 'refunds', 'notes'],
|
|
4114
4720
|
...(params.forceRemote ? {
|
|
4115
4721
|
forceRemote: true
|
|
4116
4722
|
} : {})
|
|
@@ -4163,7 +4769,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4163
4769
|
const isMergedSalesDetailHydrate = options?.source === 'mergedSalesDetail';
|
|
4164
4770
|
const nextTempOrder = this.normalizeTempOrderForRuntime(raw, {
|
|
4165
4771
|
// merge 前已只给远端商品补标记;这里不能把本地未提交商品一并变成 saved item。
|
|
4166
|
-
makeEditMark: !isSessionStorageHydrate && !isMergedSalesDetailHydrate
|
|
4772
|
+
makeEditMark: !isSessionStorageHydrate && !isMergedSalesDetailHydrate,
|
|
4773
|
+
allowUnresolvedSalesNotes: isSessionStorageHydrate
|
|
4167
4774
|
});
|
|
4168
4775
|
this.store.tempOrder = nextTempOrder;
|
|
4169
4776
|
if (isSessionStorageHydrate) {
|
|
@@ -4385,6 +4992,17 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4385
4992
|
nextTempOrder.payments = Array.isArray(raw.payments) ? raw.payments.map(p => ({
|
|
4386
4993
|
...(p || {})
|
|
4387
4994
|
})) : [];
|
|
4995
|
+
const rawHasSalesNotes = Object.prototype.hasOwnProperty.call(raw, 'notes');
|
|
4996
|
+
const restoredSalesNotesState = raw._extend?.salesNotesState;
|
|
4997
|
+
const allowUnresolvedSalesNotes = options?.allowUnresolvedSalesNotes === true || restoredSalesNotesState?.dirty === true || Number(raw.is_draft_order || 0) === 1;
|
|
4998
|
+
const decodedSalesNotes = rawHasSalesNotes ? (0, _salesNotes.decodeSalesNotesSnapshot)(raw.notes, {
|
|
4999
|
+
allowUnresolvedOrderTarget: allowUnresolvedSalesNotes
|
|
5000
|
+
}) : {
|
|
5001
|
+
notes: [],
|
|
5002
|
+
complete: false
|
|
5003
|
+
};
|
|
5004
|
+
const hasUnresolvedSalesNoteOrderTarget = decodedSalesNotes.notes.some(note => note.note_relations.some(relation => relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order' && relation.target_uuid === ''));
|
|
5005
|
+
nextTempOrder.notes = decodedSalesNotes.notes;
|
|
4388
5006
|
nextTempOrder.surcharges = Array.isArray(raw.surcharges) ? raw.surcharges.map(s => ({
|
|
4389
5007
|
...(s || {})
|
|
4390
5008
|
})) : [];
|
|
@@ -4397,6 +5015,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4397
5015
|
nextTempOrder.contacts_info = raw.contacts_info && typeof raw.contacts_info === 'object' && !Array.isArray(raw.contacts_info) ? {
|
|
4398
5016
|
...raw.contacts_info
|
|
4399
5017
|
} : null;
|
|
5018
|
+
nextTempOrder.order_meta_list = (0, _utils.normalizeOrderMetaList)(raw.order_meta_list);
|
|
4400
5019
|
nextTempOrder._extend = raw._extend && typeof raw._extend === 'object' ? {
|
|
4401
5020
|
...raw._extend,
|
|
4402
5021
|
productsByUid: raw._extend.productsByUid || {}
|
|
@@ -4404,6 +5023,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4404
5023
|
productsByUid: {}
|
|
4405
5024
|
};
|
|
4406
5025
|
const tempOrderExtend = nextTempOrder._extend;
|
|
5026
|
+
tempOrderExtend.salesNotesState = {
|
|
5027
|
+
loaded: rawHasSalesNotes ? decodedSalesNotes.complete : restoredSalesNotesState?.loaded === true,
|
|
5028
|
+
dirty: decodedSalesNotes.complete && (restoredSalesNotesState?.dirty === true || allowUnresolvedSalesNotes && hasUnresolvedSalesNoteOrderTarget)
|
|
5029
|
+
};
|
|
4407
5030
|
const productsByUid = tempOrderExtend.productsByUid || {};
|
|
4408
5031
|
for (const [index, product] of nextTempOrder.products.entries()) {
|
|
4409
5032
|
const uid = product.metadata?.unique_identification_number;
|
|
@@ -4550,6 +5173,23 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4550
5173
|
row.metadata.booking_uid = row.booking_uid;
|
|
4551
5174
|
}
|
|
4552
5175
|
row = (0, _bundleDiscountHydration.restoreHydratedBundleDiscounts)(row, _utils.normalizeOrderProductDiscountList);
|
|
5176
|
+
const rawOriginalPrice = Number(row.original_price);
|
|
5177
|
+
const rawSellingPrice = Number(row.selling_price);
|
|
5178
|
+
const hasProductDiscounts = Array.isArray(row.discount_list) && row.discount_list.length > 0;
|
|
5179
|
+
const hasBundleDiscounts = row.product_bundle.some(bundle => Array.isArray(bundle?.discount_list) && bundle.discount_list.length > 0);
|
|
5180
|
+
const isUndiscountedV2Line = String(row.metadata.price_schema_version) === '2' && Number.isFinite(rawOriginalPrice) && Number.isFinite(rawSellingPrice) && new _decimal.default(rawOriginalPrice).eq(rawSellingPrice) && !hasProductDiscounts && !hasBundleDiscounts;
|
|
5181
|
+
if (isUndiscountedV2Line) {
|
|
5182
|
+
const hasPriceValue = value => value !== undefined && value !== null && value !== '';
|
|
5183
|
+
row.product_bundle = row.product_bundle.map(bundle => {
|
|
5184
|
+
if (!bundle || (0, _utils.isMarkdownBundle)(bundle) || hasPriceValue(bundle.original_price) || hasPriceValue(bundle.product_price) || !hasPriceValue(bundle.bundle_selling_price)) {
|
|
5185
|
+
return bundle;
|
|
5186
|
+
}
|
|
5187
|
+
return {
|
|
5188
|
+
...bundle,
|
|
5189
|
+
original_price: bundle.bundle_selling_price
|
|
5190
|
+
};
|
|
5191
|
+
});
|
|
5192
|
+
}
|
|
4553
5193
|
const existingIdentity = row.metadata.unique_identification_number || row.unique_identification_number;
|
|
4554
5194
|
if (!existingIdentity) {
|
|
4555
5195
|
row.metadata.unique_identification_number = (0, _utils.createUuidV4)();
|
|
@@ -4571,14 +5211,14 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4571
5211
|
};
|
|
4572
5212
|
if (result.metadata) delete result.metadata.price_schema_version;
|
|
4573
5213
|
const restored = (0, _bundleDiscountHydration.restoreHydratedBundleDiscounts)(result, _utils.normalizeOrderProductDiscountList);
|
|
4574
|
-
return this.sanitizeOrderProductForTempOrder(restored);
|
|
5214
|
+
return this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(restored));
|
|
4575
5215
|
}
|
|
4576
5216
|
getLastOrderInfo() {
|
|
4577
5217
|
return this.store?.lastOrderInfo;
|
|
4578
5218
|
}
|
|
4579
5219
|
async getOrderInfo(order_id) {
|
|
4580
5220
|
const res = await this.request.get(`/order/sales/${order_id}`, {
|
|
4581
|
-
with: ['products', 'bookings']
|
|
5221
|
+
with: ['products', 'bookings', 'notes']
|
|
4582
5222
|
}, {
|
|
4583
5223
|
osServer: true
|
|
4584
5224
|
});
|