@pisell/pisellos 2.1.107 → 2.1.108
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/walletPass/type.d.ts +9 -2
- package/dist/model/strategy/adapter/walletPass/utils.d.ts +10 -10
- package/dist/model/strategy/adapter/walletPass/utils.js +105 -78
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/lib/model/strategy/adapter/walletPass/type.d.ts +9 -2
- package/lib/model/strategy/adapter/walletPass/utils.d.ts +10 -10
- package/lib/model/strategy/adapter/walletPass/utils.js +110 -46
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -41,7 +41,7 @@ export interface Voucher {
|
|
|
41
41
|
allowCrossProduct: boolean;
|
|
42
42
|
/** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
|
|
43
43
|
applicableProductLimit: number;
|
|
44
|
-
/**
|
|
44
|
+
/** 单订单行每单位可用同一 Wallet Pass 券次数;该行总券次上限 = maxPassesPerItem × 该行 quantity(按行唯一键区分)。0 表示不限制。 */
|
|
45
45
|
maxPassesPerItem: number;
|
|
46
46
|
};
|
|
47
47
|
}
|
|
@@ -50,6 +50,10 @@ export interface Voucher {
|
|
|
50
50
|
*/
|
|
51
51
|
export interface Product {
|
|
52
52
|
product_id: number;
|
|
53
|
+
/** 订单明细 id,参与行唯一键兜底解析 */
|
|
54
|
+
id?: number;
|
|
55
|
+
/** 行级唯一串,参与行唯一键解析 */
|
|
56
|
+
product_unique_string?: string;
|
|
53
57
|
price: number;
|
|
54
58
|
quantity: number;
|
|
55
59
|
name?: string;
|
|
@@ -61,6 +65,9 @@ export interface Product {
|
|
|
61
65
|
/** 主商品税费 */
|
|
62
66
|
tax_fee: number;
|
|
63
67
|
metadata: {
|
|
68
|
+
/** 行唯一标识,优先用于 Wallet Pass 按行配额 */
|
|
69
|
+
product_unique?: string;
|
|
70
|
+
unique_identification_number?: string;
|
|
64
71
|
main_product_attached_bundle_tax_fee?: number;
|
|
65
72
|
main_product_attached_bundle_surcharge_fee?: number;
|
|
66
73
|
surcharge_rounding_remainder?: number;
|
|
@@ -129,7 +136,7 @@ export interface EvaluatorInput {
|
|
|
129
136
|
allowCrossProduct: boolean;
|
|
130
137
|
/** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
|
|
131
138
|
applicableProductLimit: number;
|
|
132
|
-
/**
|
|
139
|
+
/** 单订单行每单位可用同一 Wallet Pass 券次数;行总上限 = maxPassesPerItem × 该行 quantity(按行唯一键计)。0 表示不限制。 */
|
|
133
140
|
maxPassesPerItem: number;
|
|
134
141
|
}>[];
|
|
135
142
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Product, Voucher } from './type';
|
|
2
|
+
/** 订单商品数量 */
|
|
3
|
+
export declare const getProductQuantity: (product: any) => any;
|
|
4
|
+
/**
|
|
5
|
+
* 订单商品行唯一键,用于 maxPassesPerItem 按行、按件配额(同 SPU 不同规格视为不同行)。
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveWalletPassLineKey(product: any, indexInOrder: number): string;
|
|
2
8
|
export declare const getApplicableProductIds: (voucher: Voucher) => number[] | null;
|
|
3
9
|
/**
|
|
4
10
|
* 优惠券处理函数
|
|
@@ -24,26 +30,20 @@ export declare function recalculateVouchers(allVouchers: any[], selectedVouchers
|
|
|
24
30
|
selectedWithDetails: any[];
|
|
25
31
|
};
|
|
26
32
|
/**
|
|
27
|
-
*
|
|
33
|
+
* 获取主商品价格(单价,不含舍入余数)
|
|
28
34
|
* @param product 商品
|
|
29
35
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
30
|
-
* @returns
|
|
36
|
+
* @returns 商品单价
|
|
31
37
|
*/
|
|
32
38
|
export declare const getMainProductPrice: (product: Product, isDeductTaxAndFee: boolean) => number;
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
40
|
+
* 获取套餐子商品价格(不含舍入余数)
|
|
35
41
|
* @param bundleItem 套餐子商品
|
|
36
42
|
* @param parentQuantity 父商品数量
|
|
37
43
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
38
|
-
* @returns
|
|
44
|
+
* @returns 子商品总价格(不含舍入余数)
|
|
39
45
|
*/
|
|
40
46
|
export declare const getBundleItemPrice: (bundleItem: any, parentQuantity: number, isDeductTaxAndFee: boolean) => number;
|
|
41
|
-
/**
|
|
42
|
-
* 获取商品数量
|
|
43
|
-
* @param product 商品
|
|
44
|
-
* @returns 商品数量
|
|
45
|
-
*/
|
|
46
|
-
export declare const getProductQuantity: (product: any) => any;
|
|
47
47
|
export declare const getBundleItemIsOriginalPrice: (item: any) => boolean;
|
|
48
48
|
export declare const getBundleItemIsMarkupPrice: (item: any) => boolean;
|
|
49
49
|
export declare const getBundleItemIsDiscountPrice: (item: any) => boolean;
|
|
@@ -12,6 +12,63 @@ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symb
|
|
|
12
12
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
13
13
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
14
14
|
import Decimal from 'decimal.js';
|
|
15
|
+
/** 订单商品数量 */
|
|
16
|
+
export var getProductQuantity = function getProductQuantity(product) {
|
|
17
|
+
return product.quantity || product.product_quantity || 1;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 订单商品行唯一键,用于 maxPassesPerItem 按行、按件配额(同 SPU 不同规格视为不同行)。
|
|
22
|
+
*/
|
|
23
|
+
export function resolveWalletPassLineKey(product, indexInOrder) {
|
|
24
|
+
var m = (product === null || product === void 0 ? void 0 : product.metadata) || {};
|
|
25
|
+
var u1 = m.product_unique;
|
|
26
|
+
if (u1 != null && String(u1).length > 0) return String(u1);
|
|
27
|
+
var u2 = m.unique_identification_number;
|
|
28
|
+
if (u2 != null && String(u2).length > 0) return String(u2);
|
|
29
|
+
if ((product === null || product === void 0 ? void 0 : product.id) != null && String(product.id).length > 0) return "order_item:".concat(product.id);
|
|
30
|
+
if ((product === null || product === void 0 ? void 0 : product.product_unique_string) != null && String(product.product_unique_string).length > 0) {
|
|
31
|
+
return String(product.product_unique_string);
|
|
32
|
+
}
|
|
33
|
+
return "order_line_".concat(indexInOrder);
|
|
34
|
+
}
|
|
35
|
+
function getExpandedOrderLineQuantity(p) {
|
|
36
|
+
if ((p === null || p === void 0 ? void 0 : p._orderLineQuantity) != null && p._orderLineQuantity > 0) return p._orderLineQuantity;
|
|
37
|
+
return getProductQuantity(p);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 该行允许消耗的「券次」上限:maxPassesPerItem × 订单行件数 */
|
|
41
|
+
function getMaxPassSlotsForExpandedLine(maxPassesPerItem, p) {
|
|
42
|
+
if (maxPassesPerItem <= 0) return Infinity;
|
|
43
|
+
return maxPassesPerItem * getExpandedOrderLineQuantity(p);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 本次抵扣占用多少「券次」配额:有抵扣时至少占 1,并与按金额折算的件数挂钩,不超过剩余额度。
|
|
48
|
+
*/
|
|
49
|
+
function computePassSlotsIncrement(deductAmount, deductQty, maxPassesPerItem, orderLineQuantity, currentUsage) {
|
|
50
|
+
if (maxPassesPerItem <= 0 || !deductAmount.greaterThan(0)) return 0;
|
|
51
|
+
var cap = maxPassesPerItem * orderLineQuantity;
|
|
52
|
+
var room = Math.max(0, cap - currentUsage);
|
|
53
|
+
if (room <= 0) return 0;
|
|
54
|
+
var raw = Math.max(1, Math.ceil(Number(deductQty)) || 1);
|
|
55
|
+
return Math.min(raw, room);
|
|
56
|
+
}
|
|
57
|
+
function applyMaxPassUsageIncrements(usageMap, walletPassProductId, maxPassesPerItem, deductionDetails) {
|
|
58
|
+
deductionDetails.forEach(function (detail) {
|
|
59
|
+
var _usageMap$get;
|
|
60
|
+
var lineKey = detail.lineKey;
|
|
61
|
+
if (!lineKey || maxPassesPerItem <= 0) return;
|
|
62
|
+
var orderLineQty = detail.orderLineQuantity != null && detail.orderLineQuantity > 0 ? detail.orderLineQuantity : 1;
|
|
63
|
+
var cur = ((_usageMap$get = usageMap.get(walletPassProductId)) === null || _usageMap$get === void 0 ? void 0 : _usageMap$get.get(lineKey)) || 0;
|
|
64
|
+
var inc = computePassSlotsIncrement(new Decimal(detail.deductAmount), detail.deductQuantity, maxPassesPerItem, orderLineQty, cur);
|
|
65
|
+
if (inc <= 0) return;
|
|
66
|
+
if (!usageMap.has(walletPassProductId)) usageMap.set(walletPassProductId, new Map());
|
|
67
|
+
var inner = usageMap.get(walletPassProductId);
|
|
68
|
+
inner.set(lineKey, cur + inc);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
15
72
|
// 辅助函数:根据 deductTaxAndFee 配置获取推荐使用金额
|
|
16
73
|
var getRecommendedAmount = function getRecommendedAmount(voucher) {
|
|
17
74
|
var _config$deductTaxAndF;
|
|
@@ -101,18 +158,6 @@ var getApplicableProducts = function getApplicableProducts(voucher, productsData
|
|
|
101
158
|
});
|
|
102
159
|
};
|
|
103
160
|
|
|
104
|
-
/**
|
|
105
|
-
* 计算指定 product_id 在展开后的商品列表中的总 quantity
|
|
106
|
-
* 处理同一 product_id 可能分散在多条记录中的情况(如3个独立的 quantity=1 条目)
|
|
107
|
-
*/
|
|
108
|
-
var getTotalQuantityByProductId = function getTotalQuantityByProductId(allProducts, productId) {
|
|
109
|
-
return allProducts.filter(function (p) {
|
|
110
|
-
return p.product_id === productId;
|
|
111
|
-
}).reduce(function (sum, p) {
|
|
112
|
-
return sum + getProductQuantity(p);
|
|
113
|
-
}, 0);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
161
|
/**
|
|
117
162
|
* 优惠券处理函数
|
|
118
163
|
* @param applicableVouchers 可用的券列表
|
|
@@ -130,29 +175,19 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
130
175
|
var productsCopy = expandProductsWithBundleItems(products, true);
|
|
131
176
|
var remainingOrderAmount = new Decimal(orderTotalAmount); // 订单剩余应付金额
|
|
132
177
|
|
|
133
|
-
// ========== 辅助工具:maxPassesPerItem
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return ((_usageMap$get = usageMap.get(walletPassProductId)) === null || _usageMap$get === void 0 ? void 0 : _usageMap$get.get(orderItemProductId)) || 0;
|
|
178
|
+
// ========== 辅助工具:maxPassesPerItem(按订单行 + 件数)追踪 ==========
|
|
179
|
+
var getItemPassUsage = function getItemPassUsage(usageMap, walletPassProductId, lineKey) {
|
|
180
|
+
var _usageMap$get2;
|
|
181
|
+
return ((_usageMap$get2 = usageMap.get(walletPassProductId)) === null || _usageMap$get2 === void 0 ? void 0 : _usageMap$get2.get(lineKey)) || 0;
|
|
138
182
|
};
|
|
139
183
|
|
|
140
|
-
//
|
|
141
|
-
var
|
|
142
|
-
|
|
143
|
-
if (!usageMap.has(walletPassProductId)) {
|
|
144
|
-
usageMap.set(walletPassProductId, new Map());
|
|
145
|
-
}
|
|
146
|
-
var innerMap = usageMap.get(walletPassProductId);
|
|
147
|
-
innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// 按 maxPassesPerItem 过滤商品:排除已达到单商品可用卡券上限的商品
|
|
151
|
-
// maxPassesPerItem 是 per-unit 的限制,总上限 = maxPassesPerItem × 该 product_id 的总 quantity
|
|
152
|
-
var filterByMaxPassesPerItem = function filterByMaxPassesPerItem(products, allProducts, usageMap, walletPassProductId, maxPassesPerItem) {
|
|
153
|
-
if (maxPassesPerItem <= 0) return products; // 0 = 不限制
|
|
184
|
+
// 按 maxPassesPerItem 过滤:排除已达到该行「券次」上限的展开行(按 _walletPassLineKey)
|
|
185
|
+
var filterByMaxPassesPerItem = function filterByMaxPassesPerItem(products, usageMap, walletPassProductId, maxPassesPerItem) {
|
|
186
|
+
if (maxPassesPerItem <= 0) return products;
|
|
154
187
|
return products.filter(function (p) {
|
|
155
|
-
|
|
188
|
+
var lineKey = p._walletPassLineKey;
|
|
189
|
+
if (!lineKey) return true;
|
|
190
|
+
return getItemPassUsage(usageMap, walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
156
191
|
});
|
|
157
192
|
};
|
|
158
193
|
// ================================================================
|
|
@@ -189,7 +224,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
189
224
|
|
|
190
225
|
// 按 maxPassesPerItem 过滤:排除已达到单商品可用卡券上限的商品
|
|
191
226
|
if (itemPassUsage) {
|
|
192
|
-
applicableProducts = filterByMaxPassesPerItem(applicableProducts,
|
|
227
|
+
applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsage, voucher.product_id, maxPassesPerItem);
|
|
193
228
|
}
|
|
194
229
|
if (applicableProducts.length === 0) {
|
|
195
230
|
return new Decimal(0);
|
|
@@ -301,7 +336,9 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
301
336
|
var availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter(function (p) {
|
|
302
337
|
return p[amountField].greaterThan(0);
|
|
303
338
|
}).filter(function (p) {
|
|
304
|
-
|
|
339
|
+
var lineKey = p._walletPassLineKey;
|
|
340
|
+
if (!lineKey) return true;
|
|
341
|
+
return getItemPassUsage(itemPassUsage, product_id, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
305
342
|
});
|
|
306
343
|
if (availableAfterPassLimit.length === 0) {
|
|
307
344
|
return {
|
|
@@ -337,7 +374,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
337
374
|
// 重置商品余额追踪(同时维护含税和不含税两个金额池)
|
|
338
375
|
var productsForRecommendation = expandProductsWithBundleItems(products, true);
|
|
339
376
|
remainingOrderAmount = new Decimal(orderTotalAmount);
|
|
340
|
-
// 追踪推荐阶段每个 Wallet Pass
|
|
377
|
+
// 追踪推荐阶段每个 Wallet Pass 商品对每个订单商品行的已使用卡券次数(按行唯一键)
|
|
341
378
|
var itemPassUsageMap = new Map();
|
|
342
379
|
|
|
343
380
|
/**
|
|
@@ -398,7 +435,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
398
435
|
});
|
|
399
436
|
|
|
400
437
|
// 按 maxPassesPerItem 过滤:排除已达到单商品可用卡券上限的商品
|
|
401
|
-
applicableProducts = filterByMaxPassesPerItem(applicableProducts,
|
|
438
|
+
applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsageMap, product_id, maxPassesPerItem);
|
|
402
439
|
if (applicableProducts.length === 0) return false;
|
|
403
440
|
|
|
404
441
|
// ========== 关键修改:在应用券之前,基于当前剩余金额计算 _available_max_amount ==========
|
|
@@ -492,6 +529,8 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
492
529
|
product_id: _product.product_id,
|
|
493
530
|
parent_product_id: _product.parent_product_id || null,
|
|
494
531
|
is_bundle_item: _product.is_bundle_item || false,
|
|
532
|
+
lineKey: _product._walletPassLineKey,
|
|
533
|
+
orderLineQuantity: getExpandedOrderLineQuantity(_product),
|
|
495
534
|
deductAmount: actualDeductAmount.toNumber(),
|
|
496
535
|
// 转换为数字
|
|
497
536
|
deductQuantity: actualDeductQty // 抵扣涉及的数量(用于记录)
|
|
@@ -525,6 +564,8 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
525
564
|
product_id: targetProduct.product_id,
|
|
526
565
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
527
566
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
567
|
+
lineKey: targetProduct._walletPassLineKey,
|
|
568
|
+
orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
|
|
528
569
|
deductAmount: _actualDeductAmount.toNumber(),
|
|
529
570
|
deductQuantity: _actualDeductQty
|
|
530
571
|
});
|
|
@@ -536,11 +577,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
536
577
|
|
|
537
578
|
// 更新券使用次数(按 product_id 统计)
|
|
538
579
|
usedVoucherCounts.set(product_id, (usedVoucherCounts.get(product_id) || 0) + 1);
|
|
539
|
-
|
|
540
|
-
// 更新 maxPassesPerItem 追踪:按实际抵扣数量递增
|
|
541
|
-
deductionDetails.forEach(function (detail) {
|
|
542
|
-
incrementItemPassUsage(itemPassUsageMap, product_id, detail.product_id, detail.deductQuantity);
|
|
543
|
-
});
|
|
580
|
+
applyMaxPassUsageIncrements(itemPassUsageMap, product_id, maxPassesPerItem, deductionDetails);
|
|
544
581
|
|
|
545
582
|
// 添加到推荐列表(包含基于当前剩余金额计算的 available_max_amount)
|
|
546
583
|
recommendedVouchers.push(_objectSpread(_objectSpread({}, voucher), {}, {
|
|
@@ -623,25 +660,18 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
623
660
|
var remainingOrderAmount = new Decimal(orderTotalAmount);
|
|
624
661
|
var selectedWithDetails = [];
|
|
625
662
|
|
|
626
|
-
// 追踪每个 Wallet Pass
|
|
627
|
-
// Map<walletPassProductId, Map<orderItemProductId, usedCount>>
|
|
663
|
+
// 追踪每个 Wallet Pass 商品对每个订单商品行的已使用卡券次数(按行唯一键)
|
|
628
664
|
var itemPassUsageMap = new Map();
|
|
629
|
-
var
|
|
665
|
+
var getItemPassUsageRecalc = function getItemPassUsageRecalc(walletPassProductId, lineKey) {
|
|
630
666
|
var _itemPassUsageMap$get;
|
|
631
|
-
return ((_itemPassUsageMap$get = itemPassUsageMap.get(walletPassProductId)) === null || _itemPassUsageMap$get === void 0 ? void 0 : _itemPassUsageMap$get.get(
|
|
632
|
-
};
|
|
633
|
-
var incrementItemPassUsage = function incrementItemPassUsage(walletPassProductId, orderItemProductId) {
|
|
634
|
-
var count = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
635
|
-
if (!itemPassUsageMap.has(walletPassProductId)) {
|
|
636
|
-
itemPassUsageMap.set(walletPassProductId, new Map());
|
|
637
|
-
}
|
|
638
|
-
var innerMap = itemPassUsageMap.get(walletPassProductId);
|
|
639
|
-
innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
|
|
667
|
+
return ((_itemPassUsageMap$get = itemPassUsageMap.get(walletPassProductId)) === null || _itemPassUsageMap$get === void 0 ? void 0 : _itemPassUsageMap$get.get(lineKey)) || 0;
|
|
640
668
|
};
|
|
641
|
-
var
|
|
642
|
-
if (maxPassesPerItem <= 0) return products;
|
|
669
|
+
var filterByMaxPassesPerItemRecalc = function filterByMaxPassesPerItemRecalc(products, walletPassProductId, maxPassesPerItem) {
|
|
670
|
+
if (maxPassesPerItem <= 0) return products;
|
|
643
671
|
return products.filter(function (p) {
|
|
644
|
-
|
|
672
|
+
var lineKey = p._walletPassLineKey;
|
|
673
|
+
if (!lineKey) return true;
|
|
674
|
+
return getItemPassUsageRecalc(walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
645
675
|
});
|
|
646
676
|
};
|
|
647
677
|
|
|
@@ -666,8 +696,8 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
666
696
|
return p[amountField].greaterThan(0);
|
|
667
697
|
});
|
|
668
698
|
|
|
669
|
-
// 按 maxPassesPerItem
|
|
670
|
-
applicableProducts =
|
|
699
|
+
// 按 maxPassesPerItem 过滤:排除已达到该行券次上限的展开行
|
|
700
|
+
applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, selectedVoucher.product_id, maxPassesPerItem);
|
|
671
701
|
if (applicableProducts.length === 0) {
|
|
672
702
|
// 无适用商品,跳过
|
|
673
703
|
selectedWithDetails.push(_objectSpread(_objectSpread({}, selectedVoucher), {}, {
|
|
@@ -718,6 +748,8 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
718
748
|
product_id: product.product_id,
|
|
719
749
|
parent_product_id: product.parent_product_id || null,
|
|
720
750
|
is_bundle_item: product.is_bundle_item || false,
|
|
751
|
+
lineKey: product._walletPassLineKey,
|
|
752
|
+
orderLineQuantity: getExpandedOrderLineQuantity(product),
|
|
721
753
|
deductAmount: actualDeductAmount.toNumber(),
|
|
722
754
|
// 转换为数字
|
|
723
755
|
deductQuantity: actualDeductQty // 抵扣涉及的数量(用于记录)
|
|
@@ -751,6 +783,8 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
751
783
|
product_id: targetProduct.product_id,
|
|
752
784
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
753
785
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
786
|
+
lineKey: targetProduct._walletPassLineKey,
|
|
787
|
+
orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
|
|
754
788
|
deductAmount: _actualDeductAmount2.toNumber(),
|
|
755
789
|
deductQuantity: _actualDeductQty2
|
|
756
790
|
});
|
|
@@ -759,11 +793,7 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
759
793
|
|
|
760
794
|
// 更新订单剩余金额
|
|
761
795
|
remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
|
|
762
|
-
|
|
763
|
-
// 更新 maxPassesPerItem 追踪:按实际抵扣数量递增
|
|
764
|
-
deductionDetails.forEach(function (detail) {
|
|
765
|
-
incrementItemPassUsage(selectedVoucher.product_id, detail.product_id, detail.deductQuantity);
|
|
766
|
-
});
|
|
796
|
+
applyMaxPassUsageIncrements(itemPassUsageMap, selectedVoucher.product_id, maxPassesPerItem, deductionDetails);
|
|
767
797
|
selectedWithDetails.push(_objectSpread(_objectSpread({}, selectedVoucher), {}, {
|
|
768
798
|
actualDeduction: totalDeducted.toNumber(),
|
|
769
799
|
// 转换为数字
|
|
@@ -836,7 +866,7 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
836
866
|
});
|
|
837
867
|
|
|
838
868
|
// 按 maxPassesPerItem 过滤:排除已达到单商品可用卡券上限的商品
|
|
839
|
-
applicableProducts =
|
|
869
|
+
applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, product_id, maxPassesPerItem);
|
|
840
870
|
if (applicableProducts.length === 0) {
|
|
841
871
|
isAvailable = false;
|
|
842
872
|
reasonCode = 'not_meet_the_required_conditions';
|
|
@@ -910,10 +940,10 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
910
940
|
}
|
|
911
941
|
|
|
912
942
|
/**
|
|
913
|
-
*
|
|
943
|
+
* 获取主商品价格(单价,不含舍入余数)
|
|
914
944
|
* @param product 商品
|
|
915
945
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
916
|
-
* @returns
|
|
946
|
+
* @returns 商品单价
|
|
917
947
|
*/
|
|
918
948
|
export var getMainProductPrice = function getMainProductPrice(product, isDeductTaxAndFee) {
|
|
919
949
|
var _product$metadata, _product$metadata2, _product$metadata3, _product$metadata4, _product$metadata5;
|
|
@@ -956,11 +986,11 @@ export var getMainProductPrice = function getMainProductPrice(product, isDeductT
|
|
|
956
986
|
};
|
|
957
987
|
|
|
958
988
|
/**
|
|
959
|
-
*
|
|
989
|
+
* 获取套餐子商品价格(不含舍入余数)
|
|
960
990
|
* @param bundleItem 套餐子商品
|
|
961
991
|
* @param parentQuantity 父商品数量
|
|
962
992
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
963
|
-
* @returns
|
|
993
|
+
* @returns 子商品总价格(不含舍入余数)
|
|
964
994
|
*/
|
|
965
995
|
export var getBundleItemPrice = function getBundleItemPrice(bundleItem, parentQuantity, isDeductTaxAndFee) {
|
|
966
996
|
var _bundleItem$bundle_se2;
|
|
@@ -991,8 +1021,9 @@ export var getBundleItemPrice = function getBundleItemPrice(bundleItem, parentQu
|
|
|
991
1021
|
*/
|
|
992
1022
|
var expandProductsWithBundleItems = function expandProductsWithBundleItems(products, deductTaxAndFee) {
|
|
993
1023
|
var expandedProducts = [];
|
|
994
|
-
products.forEach(function (product) {
|
|
1024
|
+
products.forEach(function (product, indexInOrder) {
|
|
995
1025
|
var productQuantity = getProductQuantity(product);
|
|
1026
|
+
var parentLineKey = resolveWalletPassLineKey(product, indexInOrder);
|
|
996
1027
|
|
|
997
1028
|
// 计算主商品单价(含税和不含税)
|
|
998
1029
|
var unitPriceWithTax = getMainProductPrice(product, true);
|
|
@@ -1002,6 +1033,8 @@ var expandProductsWithBundleItems = function expandProductsWithBundleItems(produ
|
|
|
1002
1033
|
expandedProducts.push(_objectSpread(_objectSpread({}, product), {}, {
|
|
1003
1034
|
is_bundle_item: false,
|
|
1004
1035
|
parent_product_id: null,
|
|
1036
|
+
_walletPassLineKey: parentLineKey,
|
|
1037
|
+
_orderLineQuantity: productQuantity,
|
|
1005
1038
|
// 单价(用于按 quantity 计算抵扣)
|
|
1006
1039
|
unitPriceWithTax: new Decimal(unitPriceWithTax),
|
|
1007
1040
|
unitPricePure: new Decimal(unitPricePure),
|
|
@@ -1018,6 +1051,7 @@ var expandProductsWithBundleItems = function expandProductsWithBundleItems(produ
|
|
|
1018
1051
|
product.product_bundle.forEach(function (bundleItem) {
|
|
1019
1052
|
if (getBundleItemIsOriginalPrice(bundleItem)) {
|
|
1020
1053
|
var bundleQuantity = bundleItem.num * productQuantity;
|
|
1054
|
+
var bundleLineKey = "".concat(parentLineKey, "#bundle:").concat(bundleItem.bundle_id, ":").concat(bundleItem.bundle_product_id);
|
|
1021
1055
|
// 计算子商品单价(注意:getBundleItemPrice 返回的是总价,需要除以数量得到单价)
|
|
1022
1056
|
var bundleUnitPriceWithTax = new Decimal(getBundleItemPrice(bundleItem, 1, true)).dividedBy(bundleItem.num);
|
|
1023
1057
|
var bundleUnitPricePure = new Decimal(getBundleItemPrice(bundleItem, 1, false)).dividedBy(bundleItem.num);
|
|
@@ -1030,6 +1064,8 @@ var expandProductsWithBundleItems = function expandProductsWithBundleItems(produ
|
|
|
1030
1064
|
parent_product_id: product.product_id,
|
|
1031
1065
|
quantity: bundleQuantity,
|
|
1032
1066
|
// 子商品数量 * 主商品数量
|
|
1067
|
+
_walletPassLineKey: bundleLineKey,
|
|
1068
|
+
_orderLineQuantity: bundleQuantity,
|
|
1033
1069
|
// 单价(用于按 quantity 计算抵扣)
|
|
1034
1070
|
unitPriceWithTax: bundleUnitPriceWithTax,
|
|
1035
1071
|
unitPricePure: bundleUnitPricePure,
|
|
@@ -1047,15 +1083,6 @@ var expandProductsWithBundleItems = function expandProductsWithBundleItems(produ
|
|
|
1047
1083
|
return expandedProducts;
|
|
1048
1084
|
};
|
|
1049
1085
|
|
|
1050
|
-
/**
|
|
1051
|
-
* 获取商品数量
|
|
1052
|
-
* @param product 商品
|
|
1053
|
-
* @returns 商品数量
|
|
1054
|
-
*/
|
|
1055
|
-
export var getProductQuantity = function getProductQuantity(product) {
|
|
1056
|
-
return product.quantity || product.product_quantity || 1;
|
|
1057
|
-
};
|
|
1058
|
-
|
|
1059
1086
|
// bundle商品是否是原价
|
|
1060
1087
|
export var getBundleItemIsOriginalPrice = function getBundleItemIsOriginalPrice(item) {
|
|
1061
1088
|
return (item === null || item === void 0 ? void 0 : item.price_type) === 'markup' && (item === null || item === void 0 ? void 0 : item.price_type_ext) === 'product_price';
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "duration" | "session" | "normal";
|
|
53
53
|
}
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
358
358
|
};
|
|
359
359
|
setOtherData(key: string, value: any): void;
|
|
360
360
|
getOtherData(key: string): any;
|
|
361
|
-
getProductTypeById(id: number): Promise<"
|
|
361
|
+
getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
|
|
362
362
|
/**
|
|
363
363
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
364
364
|
*
|
|
@@ -115,7 +115,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
|
|
|
115
115
|
* 获取当前的客户搜索条件
|
|
116
116
|
* @returns 当前搜索条件
|
|
117
117
|
*/
|
|
118
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
118
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
119
119
|
/**
|
|
120
120
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
121
121
|
* @returns 客户状态
|
|
@@ -41,7 +41,7 @@ export interface Voucher {
|
|
|
41
41
|
allowCrossProduct: boolean;
|
|
42
42
|
/** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
|
|
43
43
|
applicableProductLimit: number;
|
|
44
|
-
/**
|
|
44
|
+
/** 单订单行每单位可用同一 Wallet Pass 券次数;该行总券次上限 = maxPassesPerItem × 该行 quantity(按行唯一键区分)。0 表示不限制。 */
|
|
45
45
|
maxPassesPerItem: number;
|
|
46
46
|
};
|
|
47
47
|
}
|
|
@@ -50,6 +50,10 @@ export interface Voucher {
|
|
|
50
50
|
*/
|
|
51
51
|
export interface Product {
|
|
52
52
|
product_id: number;
|
|
53
|
+
/** 订单明细 id,参与行唯一键兜底解析 */
|
|
54
|
+
id?: number;
|
|
55
|
+
/** 行级唯一串,参与行唯一键解析 */
|
|
56
|
+
product_unique_string?: string;
|
|
53
57
|
price: number;
|
|
54
58
|
quantity: number;
|
|
55
59
|
name?: string;
|
|
@@ -61,6 +65,9 @@ export interface Product {
|
|
|
61
65
|
/** 主商品税费 */
|
|
62
66
|
tax_fee: number;
|
|
63
67
|
metadata: {
|
|
68
|
+
/** 行唯一标识,优先用于 Wallet Pass 按行配额 */
|
|
69
|
+
product_unique?: string;
|
|
70
|
+
unique_identification_number?: string;
|
|
64
71
|
main_product_attached_bundle_tax_fee?: number;
|
|
65
72
|
main_product_attached_bundle_surcharge_fee?: number;
|
|
66
73
|
surcharge_rounding_remainder?: number;
|
|
@@ -129,7 +136,7 @@ export interface EvaluatorInput {
|
|
|
129
136
|
allowCrossProduct: boolean;
|
|
130
137
|
/** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
|
|
131
138
|
applicableProductLimit: number;
|
|
132
|
-
/**
|
|
139
|
+
/** 单订单行每单位可用同一 Wallet Pass 券次数;行总上限 = maxPassesPerItem × 该行 quantity(按行唯一键计)。0 表示不限制。 */
|
|
133
140
|
maxPassesPerItem: number;
|
|
134
141
|
}>[];
|
|
135
142
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Product, Voucher } from './type';
|
|
2
|
+
/** 订单商品数量 */
|
|
3
|
+
export declare const getProductQuantity: (product: any) => any;
|
|
4
|
+
/**
|
|
5
|
+
* 订单商品行唯一键,用于 maxPassesPerItem 按行、按件配额(同 SPU 不同规格视为不同行)。
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveWalletPassLineKey(product: any, indexInOrder: number): string;
|
|
2
8
|
export declare const getApplicableProductIds: (voucher: Voucher) => number[] | null;
|
|
3
9
|
/**
|
|
4
10
|
* 优惠券处理函数
|
|
@@ -24,26 +30,20 @@ export declare function recalculateVouchers(allVouchers: any[], selectedVouchers
|
|
|
24
30
|
selectedWithDetails: any[];
|
|
25
31
|
};
|
|
26
32
|
/**
|
|
27
|
-
*
|
|
33
|
+
* 获取主商品价格(单价,不含舍入余数)
|
|
28
34
|
* @param product 商品
|
|
29
35
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
30
|
-
* @returns
|
|
36
|
+
* @returns 商品单价
|
|
31
37
|
*/
|
|
32
38
|
export declare const getMainProductPrice: (product: Product, isDeductTaxAndFee: boolean) => number;
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
40
|
+
* 获取套餐子商品价格(不含舍入余数)
|
|
35
41
|
* @param bundleItem 套餐子商品
|
|
36
42
|
* @param parentQuantity 父商品数量
|
|
37
43
|
* @param isDeductTaxAndFee 是否抵扣税费与附加费
|
|
38
|
-
* @returns
|
|
44
|
+
* @returns 子商品总价格(不含舍入余数)
|
|
39
45
|
*/
|
|
40
46
|
export declare const getBundleItemPrice: (bundleItem: any, parentQuantity: number, isDeductTaxAndFee: boolean) => number;
|
|
41
|
-
/**
|
|
42
|
-
* 获取商品数量
|
|
43
|
-
* @param product 商品
|
|
44
|
-
* @returns 商品数量
|
|
45
|
-
*/
|
|
46
|
-
export declare const getProductQuantity: (product: any) => any;
|
|
47
47
|
export declare const getBundleItemIsOriginalPrice: (item: any) => boolean;
|
|
48
48
|
export declare const getBundleItemIsMarkupPrice: (item: any) => boolean;
|
|
49
49
|
export declare const getBundleItemIsDiscountPrice: (item: any) => boolean;
|
|
@@ -38,10 +38,72 @@ __export(utils_exports, {
|
|
|
38
38
|
getMainProductPrice: () => getMainProductPrice,
|
|
39
39
|
getProductQuantity: () => getProductQuantity,
|
|
40
40
|
processVouchers: () => processVouchers,
|
|
41
|
-
recalculateVouchers: () => recalculateVouchers
|
|
41
|
+
recalculateVouchers: () => recalculateVouchers,
|
|
42
|
+
resolveWalletPassLineKey: () => resolveWalletPassLineKey
|
|
42
43
|
});
|
|
43
44
|
module.exports = __toCommonJS(utils_exports);
|
|
44
45
|
var import_decimal = __toESM(require("decimal.js"));
|
|
46
|
+
var getProductQuantity = (product) => {
|
|
47
|
+
return product.quantity || product.product_quantity || 1;
|
|
48
|
+
};
|
|
49
|
+
function resolveWalletPassLineKey(product, indexInOrder) {
|
|
50
|
+
const m = (product == null ? void 0 : product.metadata) || {};
|
|
51
|
+
const u1 = m.product_unique;
|
|
52
|
+
if (u1 != null && String(u1).length > 0)
|
|
53
|
+
return String(u1);
|
|
54
|
+
const u2 = m.unique_identification_number;
|
|
55
|
+
if (u2 != null && String(u2).length > 0)
|
|
56
|
+
return String(u2);
|
|
57
|
+
if ((product == null ? void 0 : product.id) != null && String(product.id).length > 0)
|
|
58
|
+
return `order_item:${product.id}`;
|
|
59
|
+
if ((product == null ? void 0 : product.product_unique_string) != null && String(product.product_unique_string).length > 0) {
|
|
60
|
+
return String(product.product_unique_string);
|
|
61
|
+
}
|
|
62
|
+
return `order_line_${indexInOrder}`;
|
|
63
|
+
}
|
|
64
|
+
function getExpandedOrderLineQuantity(p) {
|
|
65
|
+
if ((p == null ? void 0 : p._orderLineQuantity) != null && p._orderLineQuantity > 0)
|
|
66
|
+
return p._orderLineQuantity;
|
|
67
|
+
return getProductQuantity(p);
|
|
68
|
+
}
|
|
69
|
+
function getMaxPassSlotsForExpandedLine(maxPassesPerItem, p) {
|
|
70
|
+
if (maxPassesPerItem <= 0)
|
|
71
|
+
return Infinity;
|
|
72
|
+
return maxPassesPerItem * getExpandedOrderLineQuantity(p);
|
|
73
|
+
}
|
|
74
|
+
function computePassSlotsIncrement(deductAmount, deductQty, maxPassesPerItem, orderLineQuantity, currentUsage) {
|
|
75
|
+
if (maxPassesPerItem <= 0 || !deductAmount.greaterThan(0))
|
|
76
|
+
return 0;
|
|
77
|
+
const cap = maxPassesPerItem * orderLineQuantity;
|
|
78
|
+
const room = Math.max(0, cap - currentUsage);
|
|
79
|
+
if (room <= 0)
|
|
80
|
+
return 0;
|
|
81
|
+
const raw = Math.max(1, Math.ceil(Number(deductQty)) || 1);
|
|
82
|
+
return Math.min(raw, room);
|
|
83
|
+
}
|
|
84
|
+
function applyMaxPassUsageIncrements(usageMap, walletPassProductId, maxPassesPerItem, deductionDetails) {
|
|
85
|
+
deductionDetails.forEach((detail) => {
|
|
86
|
+
var _a;
|
|
87
|
+
const lineKey = detail.lineKey;
|
|
88
|
+
if (!lineKey || maxPassesPerItem <= 0)
|
|
89
|
+
return;
|
|
90
|
+
const orderLineQty = detail.orderLineQuantity != null && detail.orderLineQuantity > 0 ? detail.orderLineQuantity : 1;
|
|
91
|
+
const cur = ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
|
|
92
|
+
const inc = computePassSlotsIncrement(
|
|
93
|
+
new import_decimal.default(detail.deductAmount),
|
|
94
|
+
detail.deductQuantity,
|
|
95
|
+
maxPassesPerItem,
|
|
96
|
+
orderLineQty,
|
|
97
|
+
cur
|
|
98
|
+
);
|
|
99
|
+
if (inc <= 0)
|
|
100
|
+
return;
|
|
101
|
+
if (!usageMap.has(walletPassProductId))
|
|
102
|
+
usageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
|
|
103
|
+
const inner = usageMap.get(walletPassProductId);
|
|
104
|
+
inner.set(lineKey, cur + inc);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
45
107
|
var getRecommendedAmount = (voucher) => {
|
|
46
108
|
console.log("voucher312", voucher);
|
|
47
109
|
const { config, recommended_usage_amount, recommended_pure_product_usage_amount } = voucher;
|
|
@@ -82,30 +144,23 @@ var getApplicableProducts = (voucher, productsData) => {
|
|
|
82
144
|
}
|
|
83
145
|
return productsData.filter((p) => applicableProductIds.includes(p.product_id));
|
|
84
146
|
};
|
|
85
|
-
var getTotalQuantityByProductId = (allProducts, productId) => {
|
|
86
|
-
return allProducts.filter((p) => p.product_id === productId).reduce((sum, p) => sum + getProductQuantity(p), 0);
|
|
87
|
-
};
|
|
88
147
|
function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
89
148
|
console.log(products, "products123");
|
|
90
149
|
const productsCopy = expandProductsWithBundleItems(products, true);
|
|
91
150
|
let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
|
|
92
|
-
const getItemPassUsage = (usageMap, walletPassProductId,
|
|
151
|
+
const getItemPassUsage = (usageMap, walletPassProductId, lineKey) => {
|
|
93
152
|
var _a;
|
|
94
|
-
return ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(
|
|
153
|
+
return ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
|
|
95
154
|
};
|
|
96
|
-
const
|
|
97
|
-
if (!usageMap.has(walletPassProductId)) {
|
|
98
|
-
usageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
|
|
99
|
-
}
|
|
100
|
-
const innerMap = usageMap.get(walletPassProductId);
|
|
101
|
-
innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
|
|
102
|
-
};
|
|
103
|
-
const filterByMaxPassesPerItem = (products2, allProducts, usageMap, walletPassProductId, maxPassesPerItem) => {
|
|
155
|
+
const filterByMaxPassesPerItem = (products2, usageMap, walletPassProductId, maxPassesPerItem) => {
|
|
104
156
|
if (maxPassesPerItem <= 0)
|
|
105
157
|
return products2;
|
|
106
|
-
return products2.filter(
|
|
107
|
-
|
|
108
|
-
|
|
158
|
+
return products2.filter((p) => {
|
|
159
|
+
const lineKey = p._walletPassLineKey;
|
|
160
|
+
if (!lineKey)
|
|
161
|
+
return true;
|
|
162
|
+
return getItemPassUsage(usageMap, walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
163
|
+
});
|
|
109
164
|
};
|
|
110
165
|
const calculateAvailableMaxAmount = (voucher, productsData, itemPassUsage) => {
|
|
111
166
|
const { config } = voucher;
|
|
@@ -119,7 +174,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
119
174
|
const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
|
|
120
175
|
let applicableProducts = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0));
|
|
121
176
|
if (itemPassUsage) {
|
|
122
|
-
applicableProducts = filterByMaxPassesPerItem(applicableProducts,
|
|
177
|
+
applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsage, voucher.product_id, maxPassesPerItem);
|
|
123
178
|
}
|
|
124
179
|
if (applicableProducts.length === 0) {
|
|
125
180
|
return new import_decimal.default(0);
|
|
@@ -185,7 +240,12 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
185
240
|
if (maxPassesPerItem > 0 && itemPassUsage) {
|
|
186
241
|
const deductTaxAndFee = (config == null ? void 0 : config.deductTaxAndFee) ?? true;
|
|
187
242
|
const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
|
|
188
|
-
const availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0)).filter((p) =>
|
|
243
|
+
const availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0)).filter((p) => {
|
|
244
|
+
const lineKey = p._walletPassLineKey;
|
|
245
|
+
if (!lineKey)
|
|
246
|
+
return true;
|
|
247
|
+
return getItemPassUsage(itemPassUsage, product_id, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
248
|
+
});
|
|
189
249
|
if (availableAfterPassLimit.length === 0) {
|
|
190
250
|
return { isAvailable: false, reasonCode: "max_passes_per_item_reached" };
|
|
191
251
|
}
|
|
@@ -235,7 +295,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
235
295
|
voucher,
|
|
236
296
|
productsForRecommendation
|
|
237
297
|
).filter((p) => p[amountField].greaterThan(0));
|
|
238
|
-
applicableProducts = filterByMaxPassesPerItem(applicableProducts,
|
|
298
|
+
applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsageMap, product_id, maxPassesPerItem);
|
|
239
299
|
if (applicableProducts.length === 0)
|
|
240
300
|
return false;
|
|
241
301
|
const usageAmount = typeof voucher.edit_current_amount === "number" ? voucher.edit_current_amount : getRecommendedAmount(voucher);
|
|
@@ -313,6 +373,8 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
313
373
|
product_id: product.product_id,
|
|
314
374
|
parent_product_id: product.parent_product_id || null,
|
|
315
375
|
is_bundle_item: product.is_bundle_item || false,
|
|
376
|
+
lineKey: product._walletPassLineKey,
|
|
377
|
+
orderLineQuantity: getExpandedOrderLineQuantity(product),
|
|
316
378
|
deductAmount: actualDeductAmount.toNumber(),
|
|
317
379
|
// 转换为数字
|
|
318
380
|
deductQuantity: actualDeductQty
|
|
@@ -338,6 +400,8 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
338
400
|
product_id: targetProduct.product_id,
|
|
339
401
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
340
402
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
403
|
+
lineKey: targetProduct._walletPassLineKey,
|
|
404
|
+
orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
|
|
341
405
|
deductAmount: actualDeductAmount.toNumber(),
|
|
342
406
|
deductQuantity: actualDeductQty
|
|
343
407
|
});
|
|
@@ -346,9 +410,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
|
|
|
346
410
|
if (totalDeducted.greaterThan(0)) {
|
|
347
411
|
remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
|
|
348
412
|
usedVoucherCounts.set(product_id, (usedVoucherCounts.get(product_id) || 0) + 1);
|
|
349
|
-
|
|
350
|
-
incrementItemPassUsage(itemPassUsageMap, product_id, detail.product_id, detail.deductQuantity);
|
|
351
|
-
});
|
|
413
|
+
applyMaxPassUsageIncrements(itemPassUsageMap, product_id, maxPassesPerItem, deductionDetails);
|
|
352
414
|
recommendedVouchers.push({
|
|
353
415
|
...voucher,
|
|
354
416
|
actualDeduction: totalDeducted.toNumber(),
|
|
@@ -391,23 +453,19 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
|
|
|
391
453
|
let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
|
|
392
454
|
const selectedWithDetails = [];
|
|
393
455
|
const itemPassUsageMap = /* @__PURE__ */ new Map();
|
|
394
|
-
const
|
|
456
|
+
const getItemPassUsageRecalc = (walletPassProductId, lineKey) => {
|
|
395
457
|
var _a;
|
|
396
|
-
return ((_a = itemPassUsageMap.get(walletPassProductId)) == null ? void 0 : _a.get(
|
|
458
|
+
return ((_a = itemPassUsageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
|
|
397
459
|
};
|
|
398
|
-
const
|
|
399
|
-
if (!itemPassUsageMap.has(walletPassProductId)) {
|
|
400
|
-
itemPassUsageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
|
|
401
|
-
}
|
|
402
|
-
const innerMap = itemPassUsageMap.get(walletPassProductId);
|
|
403
|
-
innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
|
|
404
|
-
};
|
|
405
|
-
const filterByMaxPassesPerItem = (products2, walletPassProductId, maxPassesPerItem) => {
|
|
460
|
+
const filterByMaxPassesPerItemRecalc = (products2, walletPassProductId, maxPassesPerItem) => {
|
|
406
461
|
if (maxPassesPerItem <= 0)
|
|
407
462
|
return products2;
|
|
408
|
-
return products2.filter(
|
|
409
|
-
|
|
410
|
-
|
|
463
|
+
return products2.filter((p) => {
|
|
464
|
+
const lineKey = p._walletPassLineKey;
|
|
465
|
+
if (!lineKey)
|
|
466
|
+
return true;
|
|
467
|
+
return getItemPassUsageRecalc(walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
|
|
468
|
+
});
|
|
411
469
|
};
|
|
412
470
|
selectedVouchers.forEach((selectedVoucher) => {
|
|
413
471
|
const { config, id } = selectedVoucher;
|
|
@@ -418,7 +476,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
|
|
|
418
476
|
selectedVoucher,
|
|
419
477
|
productsForCalc
|
|
420
478
|
).filter((p) => p[amountField].greaterThan(0));
|
|
421
|
-
applicableProducts =
|
|
479
|
+
applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, selectedVoucher.product_id, maxPassesPerItem);
|
|
422
480
|
if (applicableProducts.length === 0) {
|
|
423
481
|
selectedWithDetails.push({
|
|
424
482
|
...selectedVoucher,
|
|
@@ -461,6 +519,8 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
|
|
|
461
519
|
product_id: product.product_id,
|
|
462
520
|
parent_product_id: product.parent_product_id || null,
|
|
463
521
|
is_bundle_item: product.is_bundle_item || false,
|
|
522
|
+
lineKey: product._walletPassLineKey,
|
|
523
|
+
orderLineQuantity: getExpandedOrderLineQuantity(product),
|
|
464
524
|
deductAmount: actualDeductAmount.toNumber(),
|
|
465
525
|
// 转换为数字
|
|
466
526
|
deductQuantity: actualDeductQty
|
|
@@ -486,15 +546,15 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
|
|
|
486
546
|
product_id: targetProduct.product_id,
|
|
487
547
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
488
548
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
549
|
+
lineKey: targetProduct._walletPassLineKey,
|
|
550
|
+
orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
|
|
489
551
|
deductAmount: actualDeductAmount.toNumber(),
|
|
490
552
|
deductQuantity: actualDeductQty
|
|
491
553
|
});
|
|
492
554
|
}
|
|
493
555
|
const totalDeducted = maxDeduction.minus(deductionLeft);
|
|
494
556
|
remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
|
|
495
|
-
|
|
496
|
-
incrementItemPassUsage(selectedVoucher.product_id, detail.product_id, detail.deductQuantity);
|
|
497
|
-
});
|
|
557
|
+
applyMaxPassUsageIncrements(itemPassUsageMap, selectedVoucher.product_id, maxPassesPerItem, deductionDetails);
|
|
498
558
|
selectedWithDetails.push({
|
|
499
559
|
...selectedVoucher,
|
|
500
560
|
actualDeduction: totalDeducted.toNumber(),
|
|
@@ -544,7 +604,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
|
|
|
544
604
|
voucher,
|
|
545
605
|
productsForCalc
|
|
546
606
|
).filter((p) => p[amountField].greaterThan(0));
|
|
547
|
-
applicableProducts =
|
|
607
|
+
applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, product_id, maxPassesPerItem);
|
|
548
608
|
if (applicableProducts.length === 0) {
|
|
549
609
|
isAvailable = false;
|
|
550
610
|
reasonCode = "not_meet_the_required_conditions";
|
|
@@ -649,14 +709,17 @@ var getBundleItemPrice = (bundleItem, parentQuantity, isDeductTaxAndFee) => {
|
|
|
649
709
|
};
|
|
650
710
|
var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
|
|
651
711
|
const expandedProducts = [];
|
|
652
|
-
products.forEach((product) => {
|
|
712
|
+
products.forEach((product, indexInOrder) => {
|
|
653
713
|
const productQuantity = getProductQuantity(product);
|
|
714
|
+
const parentLineKey = resolveWalletPassLineKey(product, indexInOrder);
|
|
654
715
|
const unitPriceWithTax = getMainProductPrice(product, true);
|
|
655
716
|
const unitPricePure = getMainProductPrice(product, false);
|
|
656
717
|
expandedProducts.push({
|
|
657
718
|
...product,
|
|
658
719
|
is_bundle_item: false,
|
|
659
720
|
parent_product_id: null,
|
|
721
|
+
_walletPassLineKey: parentLineKey,
|
|
722
|
+
_orderLineQuantity: productQuantity,
|
|
660
723
|
// 单价(用于按 quantity 计算抵扣)
|
|
661
724
|
unitPriceWithTax: new import_decimal.default(unitPriceWithTax),
|
|
662
725
|
unitPricePure: new import_decimal.default(unitPricePure),
|
|
@@ -671,6 +734,7 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
|
|
|
671
734
|
product.product_bundle.forEach((bundleItem) => {
|
|
672
735
|
if (getBundleItemIsOriginalPrice(bundleItem)) {
|
|
673
736
|
const bundleQuantity = bundleItem.num * productQuantity;
|
|
737
|
+
const bundleLineKey = `${parentLineKey}#bundle:${bundleItem.bundle_id}:${bundleItem.bundle_product_id}`;
|
|
674
738
|
const bundleUnitPriceWithTax = new import_decimal.default(getBundleItemPrice(bundleItem, 1, true)).dividedBy(bundleItem.num);
|
|
675
739
|
const bundleUnitPricePure = new import_decimal.default(getBundleItemPrice(bundleItem, 1, false)).dividedBy(bundleItem.num);
|
|
676
740
|
expandedProducts.push({
|
|
@@ -681,6 +745,8 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
|
|
|
681
745
|
parent_product_id: product.product_id,
|
|
682
746
|
quantity: bundleQuantity,
|
|
683
747
|
// 子商品数量 * 主商品数量
|
|
748
|
+
_walletPassLineKey: bundleLineKey,
|
|
749
|
+
_orderLineQuantity: bundleQuantity,
|
|
684
750
|
// 单价(用于按 quantity 计算抵扣)
|
|
685
751
|
unitPriceWithTax: bundleUnitPriceWithTax,
|
|
686
752
|
unitPricePure: bundleUnitPricePure,
|
|
@@ -697,9 +763,6 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
|
|
|
697
763
|
});
|
|
698
764
|
return expandedProducts;
|
|
699
765
|
};
|
|
700
|
-
var getProductQuantity = (product) => {
|
|
701
|
-
return product.quantity || product.product_quantity || 1;
|
|
702
|
-
};
|
|
703
766
|
var getBundleItemIsOriginalPrice = (item) => {
|
|
704
767
|
return (item == null ? void 0 : item.price_type) === "markup" && (item == null ? void 0 : item.price_type_ext) === "product_price";
|
|
705
768
|
};
|
|
@@ -723,5 +786,6 @@ var getBundleItemIsMarkupOrDiscountPrice = (item) => {
|
|
|
723
786
|
getMainProductPrice,
|
|
724
787
|
getProductQuantity,
|
|
725
788
|
processVouchers,
|
|
726
|
-
recalculateVouchers
|
|
789
|
+
recalculateVouchers,
|
|
790
|
+
resolveWalletPassLineKey
|
|
727
791
|
});
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "duration" | "session" | "normal";
|
|
53
53
|
}
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
358
358
|
};
|
|
359
359
|
setOtherData(key: string, value: any): void;
|
|
360
360
|
getOtherData(key: string): any;
|
|
361
|
-
getProductTypeById(id: number): Promise<"
|
|
361
|
+
getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
|
|
362
362
|
/**
|
|
363
363
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
364
364
|
*
|
|
@@ -115,7 +115,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
|
|
|
115
115
|
* 获取当前的客户搜索条件
|
|
116
116
|
* @returns 当前搜索条件
|
|
117
117
|
*/
|
|
118
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
118
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
119
119
|
/**
|
|
120
120
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
121
121
|
* @returns 客户状态
|