@pisell/pisellos 0.0.377 → 0.0.379
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/utils.js +257 -107
- package/dist/modules/Rules/index.js +59 -13
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/ShopDiscount/utils.js +10 -8
- package/lib/model/strategy/adapter/walletPass/utils.js +154 -57
- package/lib/modules/Rules/index.js +74 -36
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/ShopDiscount/utils.js +1 -7
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
3
2
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
3
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
4
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
7
6
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
8
8
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
9
9
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
10
10
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
@@ -49,19 +49,21 @@ export var getApplicableProductIds = function getApplicableProductIds(voucher) {
|
|
|
49
49
|
return [];
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
//
|
|
52
|
+
// 辅助函数:计算适用商品的总金额(基于剩余金额)
|
|
53
53
|
var getApplicableProductsAmount = function getApplicableProductsAmount(voucher, productsData) {
|
|
54
54
|
var _config$deductTaxAndF2;
|
|
55
55
|
var applicableProductIds = getApplicableProductIds(voucher);
|
|
56
56
|
var config = voucher.config;
|
|
57
57
|
var deductTaxAndFee = (_config$deductTaxAndF2 = config === null || config === void 0 ? void 0 : config.deductTaxAndFee) !== null && _config$deductTaxAndF2 !== void 0 ? _config$deductTaxAndF2 : true;
|
|
58
58
|
|
|
59
|
-
//
|
|
59
|
+
// 根据券的配置选择使用哪个金额字段
|
|
60
60
|
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
61
61
|
|
|
62
62
|
// 如果为 null,适用于所有商品
|
|
63
63
|
if (applicableProductIds === null) {
|
|
64
|
-
return productsData.
|
|
64
|
+
return productsData.filter(function (p) {
|
|
65
|
+
return p[amountField].greaterThan(0);
|
|
66
|
+
}).reduce(function (sum, p) {
|
|
65
67
|
return sum.plus(p[amountField]);
|
|
66
68
|
}, new Decimal(0));
|
|
67
69
|
}
|
|
@@ -73,7 +75,7 @@ var getApplicableProductsAmount = function getApplicableProductsAmount(voucher,
|
|
|
73
75
|
|
|
74
76
|
// 计算指定商品的总金额
|
|
75
77
|
return productsData.filter(function (p) {
|
|
76
|
-
return applicableProductIds.includes(p.product_id);
|
|
78
|
+
return applicableProductIds.includes(p.product_id) && p[amountField].greaterThan(0);
|
|
77
79
|
}).reduce(function (sum, p) {
|
|
78
80
|
return sum.plus(p[amountField]);
|
|
79
81
|
}, new Decimal(0));
|
|
@@ -135,39 +137,64 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
135
137
|
// 基础值 = min(recommendedAmount, maxDeductionAmount)
|
|
136
138
|
var baseAmount = Decimal.min(new Decimal(recommendedAmount), new Decimal(maxDeductionAmount));
|
|
137
139
|
|
|
138
|
-
//
|
|
139
|
-
var
|
|
140
|
+
// 根据券的配置选择使用哪个单价字段和金额字段
|
|
141
|
+
var unitPriceField = deductTaxAndFee ? 'unitPriceWithTax' : 'unitPricePure';
|
|
142
|
+
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
143
|
+
|
|
144
|
+
// 获取适用商品列表(只筛选有剩余金额的商品)
|
|
145
|
+
var applicableProducts = getApplicableProducts(voucher, productsData).filter(function (p) {
|
|
146
|
+
return p[amountField].greaterThan(0);
|
|
147
|
+
});
|
|
140
148
|
if (applicableProducts.length === 0) {
|
|
141
149
|
return new Decimal(0);
|
|
142
150
|
}
|
|
143
151
|
|
|
144
|
-
// 根据券的配置选择使用哪个金额字段
|
|
145
|
-
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
146
|
-
|
|
147
152
|
// 根据跨商品配置计算适用商品金额
|
|
148
153
|
var finalApplicableAmount = new Decimal(0);
|
|
149
154
|
if (allowCrossProduct) {
|
|
150
155
|
// 跨商品券:可以抵扣多个商品
|
|
151
156
|
if (applicableProductLimit > 0) {
|
|
152
|
-
//
|
|
157
|
+
// 有数量限制:按单价从高到低排序,按动态计算的可抵扣数量累计直到达到 limit
|
|
153
158
|
var sortedProducts = _toConsumableArray(applicableProducts).sort(function (a, b) {
|
|
154
|
-
return a[
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
return a[unitPriceField].comparedTo(b[unitPriceField]) > 0 ? -1 : 1;
|
|
160
|
+
});
|
|
161
|
+
var remainingLimit = applicableProductLimit;
|
|
162
|
+
var _iterator = _createForOfIteratorHelper(sortedProducts),
|
|
163
|
+
_step;
|
|
164
|
+
try {
|
|
165
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
166
|
+
var product = _step.value;
|
|
167
|
+
if (remainingLimit <= 0) break;
|
|
168
|
+
// 动态计算当前可抵扣数量 = ceil(剩余金额 / 单价)
|
|
169
|
+
var currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
|
|
170
|
+
var deductQty = Math.min(currentAvailableQty, remainingLimit);
|
|
171
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
172
|
+
var deductAmount = Decimal.min(product[unitPriceField].times(deductQty), product[amountField]);
|
|
173
|
+
finalApplicableAmount = finalApplicableAmount.plus(deductAmount);
|
|
174
|
+
remainingLimit -= deductQty;
|
|
175
|
+
}
|
|
176
|
+
} catch (err) {
|
|
177
|
+
_iterator.e(err);
|
|
178
|
+
} finally {
|
|
179
|
+
_iterator.f();
|
|
180
|
+
}
|
|
159
181
|
} else {
|
|
160
|
-
//
|
|
182
|
+
// 无数量限制:所有适用商品的剩余金额总和
|
|
161
183
|
finalApplicableAmount = applicableProducts.reduce(function (sum, p) {
|
|
162
184
|
return sum.plus(p[amountField]);
|
|
163
185
|
}, new Decimal(0));
|
|
164
186
|
}
|
|
165
187
|
} else {
|
|
166
|
-
//
|
|
188
|
+
// 非跨商品券:只能抵扣单个商品(单价最高的)
|
|
167
189
|
var maxProduct = applicableProducts.reduce(function (max, p) {
|
|
168
|
-
return p[
|
|
190
|
+
return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
|
|
169
191
|
});
|
|
170
|
-
|
|
192
|
+
// 动态计算当前可抵扣数量
|
|
193
|
+
var _currentAvailableQty = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
|
|
194
|
+
// 非跨商品券也受 applicableProductLimit 限制
|
|
195
|
+
var _deductQty = applicableProductLimit > 0 ? Math.min(_currentAvailableQty, applicableProductLimit) : _currentAvailableQty;
|
|
196
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
197
|
+
finalApplicableAmount = Decimal.min(maxProduct[unitPriceField].times(_deductQty), maxProduct[amountField]);
|
|
171
198
|
}
|
|
172
199
|
|
|
173
200
|
// 返回最小值
|
|
@@ -292,38 +319,63 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
292
319
|
_ref3$deductTaxAndFee = _ref3.deductTaxAndFee,
|
|
293
320
|
deductTaxAndFee = _ref3$deductTaxAndFee === void 0 ? true : _ref3$deductTaxAndFee;
|
|
294
321
|
|
|
295
|
-
//
|
|
322
|
+
// 根据券的配置选择使用哪个单价字段和金额字段
|
|
323
|
+
var unitPriceField = deductTaxAndFee ? 'unitPriceWithTax' : 'unitPricePure';
|
|
296
324
|
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
297
325
|
|
|
298
|
-
//
|
|
326
|
+
// 获取适用商品(只筛选有剩余金额的商品)
|
|
299
327
|
var applicableProducts = getApplicableProducts(voucher, productsForRecommendation).filter(function (p) {
|
|
300
328
|
return p[amountField].greaterThan(0);
|
|
301
329
|
});
|
|
302
330
|
if (applicableProducts.length === 0) return false;
|
|
303
331
|
|
|
304
|
-
// 考虑 applicableProductLimit
|
|
305
|
-
if (allowCrossProduct && applicableProductLimit > 0) {
|
|
306
|
-
applicableProducts = applicableProducts.sort(function (a, b) {
|
|
307
|
-
return a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1;
|
|
308
|
-
}).slice(0, applicableProductLimit);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
332
|
// ========== 关键修改:在应用券之前,基于当前剩余金额计算 _available_max_amount ==========
|
|
312
333
|
// 优先使用用户手动编辑的金额,否则根据 deductTaxAndFee 配置获取推荐金额
|
|
313
334
|
var usageAmount = typeof voucher.edit_current_amount === 'number' ? voucher.edit_current_amount : getRecommendedAmount(voucher);
|
|
314
335
|
var baseAmount = Decimal.min(new Decimal(usageAmount), new Decimal(maxDeductionAmount));
|
|
315
336
|
var calculatedAvailableMaxAmount = new Decimal(0);
|
|
316
337
|
if (allowCrossProduct) {
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
338
|
+
// 跨商品券:按 quantity 限制计算可抵扣金额
|
|
339
|
+
if (applicableProductLimit > 0) {
|
|
340
|
+
var sortedProducts = _toConsumableArray(applicableProducts).sort(function (a, b) {
|
|
341
|
+
return a[unitPriceField].comparedTo(b[unitPriceField]) > 0 ? -1 : 1;
|
|
342
|
+
});
|
|
343
|
+
var remainingLimit = applicableProductLimit;
|
|
344
|
+
var _iterator2 = _createForOfIteratorHelper(sortedProducts),
|
|
345
|
+
_step2;
|
|
346
|
+
try {
|
|
347
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
348
|
+
var product = _step2.value;
|
|
349
|
+
if (remainingLimit <= 0) break;
|
|
350
|
+
// 动态计算当前可抵扣数量 = ceil(剩余金额 / 单价)
|
|
351
|
+
var currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
|
|
352
|
+
var deductQty = Math.min(currentAvailableQty, remainingLimit);
|
|
353
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
354
|
+
var deductAmount = Decimal.min(product[unitPriceField].times(deductQty), product[amountField]);
|
|
355
|
+
calculatedAvailableMaxAmount = calculatedAvailableMaxAmount.plus(deductAmount);
|
|
356
|
+
remainingLimit -= deductQty;
|
|
357
|
+
}
|
|
358
|
+
} catch (err) {
|
|
359
|
+
_iterator2.e(err);
|
|
360
|
+
} finally {
|
|
361
|
+
_iterator2.f();
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
// 无数量限制:所有适用商品的剩余金额总和
|
|
365
|
+
calculatedAvailableMaxAmount = applicableProducts.reduce(function (sum, p) {
|
|
366
|
+
return sum.plus(p[amountField]);
|
|
367
|
+
}, new Decimal(0));
|
|
368
|
+
}
|
|
321
369
|
} else {
|
|
322
|
-
//
|
|
370
|
+
// 非跨商品券:单个最高单价商品,也受 applicableProductLimit 限制
|
|
323
371
|
var maxProduct = applicableProducts.reduce(function (max, p) {
|
|
324
|
-
return p[
|
|
372
|
+
return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
|
|
325
373
|
});
|
|
326
|
-
|
|
374
|
+
// 动态计算当前可抵扣数量
|
|
375
|
+
var _currentAvailableQty2 = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
|
|
376
|
+
var _deductQty2 = applicableProductLimit > 0 ? Math.min(_currentAvailableQty2, applicableProductLimit) : _currentAvailableQty2;
|
|
377
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
378
|
+
calculatedAvailableMaxAmount = Decimal.min(maxProduct[unitPriceField].times(_deductQty2), maxProduct[amountField]);
|
|
327
379
|
}
|
|
328
380
|
|
|
329
381
|
// 取最小值:min(recommended_usage_amount, maxDeductionAmount, 适用商品金额, 订单剩余金额)
|
|
@@ -335,44 +387,74 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
|
|
|
335
387
|
var deductionLeft = maxDeduction;
|
|
336
388
|
var deductionDetails = [];
|
|
337
389
|
if (allowCrossProduct) {
|
|
338
|
-
//
|
|
339
|
-
var
|
|
340
|
-
return a[
|
|
390
|
+
// 跨商品券:按单价从高到低抵扣,受 applicableProductLimit 限制
|
|
391
|
+
var _sortedProducts = _toConsumableArray(applicableProducts).sort(function (a, b) {
|
|
392
|
+
return a[unitPriceField].comparedTo(b[unitPriceField]) > 0 ? -1 : 1;
|
|
341
393
|
});
|
|
342
|
-
var
|
|
343
|
-
|
|
394
|
+
var _remainingLimit = applicableProductLimit > 0 ? applicableProductLimit : Infinity;
|
|
395
|
+
var _iterator3 = _createForOfIteratorHelper(_sortedProducts),
|
|
396
|
+
_step3;
|
|
344
397
|
try {
|
|
345
|
-
for (
|
|
346
|
-
var
|
|
347
|
-
if (deductionLeft.lessThanOrEqualTo(0)) break;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
398
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
399
|
+
var _product = _step3.value;
|
|
400
|
+
if (deductionLeft.lessThanOrEqualTo(0) || _remainingLimit <= 0) break;
|
|
401
|
+
|
|
402
|
+
// 动态计算当前可抵扣数量 = ceil(剩余金额 / 单价)
|
|
403
|
+
var _currentAvailableQty3 = Math.ceil(_product[amountField].dividedBy(_product[unitPriceField]).toNumber());
|
|
404
|
+
var availableQty = Math.min(_currentAvailableQty3, _remainingLimit);
|
|
405
|
+
|
|
406
|
+
// 计算本商品最大可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
407
|
+
var maxDeductForProduct = Decimal.min(_product[unitPriceField].times(availableQty), _product[amountField]);
|
|
408
|
+
var actualDeductAmount = Decimal.min(deductionLeft, maxDeductForProduct);
|
|
409
|
+
|
|
410
|
+
// 计算实际抵扣的数量(用于记录和配额计算)
|
|
411
|
+
var actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(_product[unitPriceField]).toNumber());
|
|
412
|
+
|
|
413
|
+
// 只更新商品的剩余金额,不更新 remainingQuantity
|
|
414
|
+
_product[amountField] = _product[amountField].minus(actualDeductAmount);
|
|
415
|
+
deductionLeft = deductionLeft.minus(actualDeductAmount);
|
|
416
|
+
_remainingLimit -= actualDeductQty;
|
|
351
417
|
deductionDetails.push({
|
|
352
|
-
product_id:
|
|
353
|
-
parent_product_id:
|
|
354
|
-
is_bundle_item:
|
|
355
|
-
deductAmount:
|
|
418
|
+
product_id: _product.product_id,
|
|
419
|
+
parent_product_id: _product.parent_product_id || null,
|
|
420
|
+
is_bundle_item: _product.is_bundle_item || false,
|
|
421
|
+
deductAmount: actualDeductAmount.toNumber(),
|
|
422
|
+
// 转换为数字
|
|
423
|
+
deductQuantity: actualDeductQty // 抵扣涉及的数量(用于记录)
|
|
356
424
|
});
|
|
357
425
|
}
|
|
358
426
|
} catch (err) {
|
|
359
|
-
|
|
427
|
+
_iterator3.e(err);
|
|
360
428
|
} finally {
|
|
361
|
-
|
|
429
|
+
_iterator3.f();
|
|
362
430
|
}
|
|
363
431
|
} else {
|
|
364
|
-
//
|
|
432
|
+
// 非跨商品券:只抵扣一个商品(单价最高的),也受 applicableProductLimit 限制
|
|
365
433
|
var targetProduct = applicableProducts.reduce(function (max, p) {
|
|
366
|
-
return p[
|
|
434
|
+
return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
|
|
367
435
|
});
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
436
|
+
|
|
437
|
+
// 动态计算当前可抵扣数量
|
|
438
|
+
var _currentAvailableQty4 = Math.ceil(targetProduct[amountField].dividedBy(targetProduct[unitPriceField]).toNumber());
|
|
439
|
+
var _availableQty = applicableProductLimit > 0 ? Math.min(_currentAvailableQty4, applicableProductLimit) : _currentAvailableQty4;
|
|
440
|
+
|
|
441
|
+
// 计算本商品最大可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
442
|
+
var _maxDeductForProduct = Decimal.min(targetProduct[unitPriceField].times(_availableQty), targetProduct[amountField]);
|
|
443
|
+
var _actualDeductAmount = Decimal.min(deductionLeft, _maxDeductForProduct);
|
|
444
|
+
|
|
445
|
+
// 计算实际抵扣的数量
|
|
446
|
+
var _actualDeductQty = Math.ceil(_actualDeductAmount.dividedBy(targetProduct[unitPriceField]).toNumber());
|
|
447
|
+
|
|
448
|
+
// 只更新商品的剩余金额,不更新 remainingQuantity
|
|
449
|
+
targetProduct[amountField] = targetProduct[amountField].minus(_actualDeductAmount);
|
|
450
|
+
deductionLeft = deductionLeft.minus(_actualDeductAmount);
|
|
371
451
|
deductionDetails.push({
|
|
372
452
|
product_id: targetProduct.product_id,
|
|
373
453
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
374
454
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
375
|
-
deductAmount:
|
|
455
|
+
deductAmount: _actualDeductAmount.toNumber(),
|
|
456
|
+
// 转换为数字
|
|
457
|
+
deductQuantity: _actualDeductQty // 抵扣涉及的数量(用于记录)
|
|
376
458
|
});
|
|
377
459
|
}
|
|
378
460
|
var totalDeducted = maxDeduction.minus(deductionLeft);
|
|
@@ -474,10 +556,11 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
474
556
|
_config$deductTaxAndF3 = config.deductTaxAndFee,
|
|
475
557
|
deductTaxAndFee = _config$deductTaxAndF3 === void 0 ? true : _config$deductTaxAndF3;
|
|
476
558
|
|
|
477
|
-
//
|
|
559
|
+
// 根据券的配置选择使用哪个单价字段和金额字段
|
|
560
|
+
var unitPriceField = deductTaxAndFee ? 'unitPriceWithTax' : 'unitPricePure';
|
|
478
561
|
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
479
562
|
|
|
480
|
-
//
|
|
563
|
+
// 获取适用商品(只筛选有剩余金额的商品)
|
|
481
564
|
var applicableProducts = getApplicableProducts(selectedVoucher, productsForCalc).filter(function (p) {
|
|
482
565
|
return p[amountField].greaterThan(0);
|
|
483
566
|
});
|
|
@@ -493,13 +576,6 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
493
576
|
return;
|
|
494
577
|
}
|
|
495
578
|
|
|
496
|
-
// 考虑 applicableProductLimit
|
|
497
|
-
if (allowCrossProduct && applicableProductLimit > 0) {
|
|
498
|
-
applicableProducts = applicableProducts.sort(function (a, b) {
|
|
499
|
-
return a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1;
|
|
500
|
-
}).slice(0, applicableProductLimit);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
579
|
// 计算本次抵扣金额
|
|
504
580
|
// 优先使用用户手动编辑的金额,否则根据 deductTaxAndFee 配置获取推荐金额
|
|
505
581
|
var usageAmount = typeof selectedVoucher.edit_current_amount === 'number' ? selectedVoucher.edit_current_amount : getRecommendedAmount(selectedVoucher);
|
|
@@ -507,44 +583,74 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
507
583
|
var deductionLeft = maxDeduction;
|
|
508
584
|
var deductionDetails = [];
|
|
509
585
|
if (allowCrossProduct) {
|
|
510
|
-
//
|
|
586
|
+
// 跨商品券:按单价从高到低抵扣,受 applicableProductLimit 限制
|
|
511
587
|
var sortedProducts = _toConsumableArray(applicableProducts).sort(function (a, b) {
|
|
512
|
-
return a[
|
|
588
|
+
return a[unitPriceField].comparedTo(b[unitPriceField]) > 0 ? -1 : 1;
|
|
513
589
|
});
|
|
514
|
-
var
|
|
515
|
-
|
|
590
|
+
var remainingLimit = applicableProductLimit > 0 ? applicableProductLimit : Infinity;
|
|
591
|
+
var _iterator4 = _createForOfIteratorHelper(sortedProducts),
|
|
592
|
+
_step4;
|
|
516
593
|
try {
|
|
517
|
-
for (
|
|
518
|
-
var product =
|
|
519
|
-
if (deductionLeft.lessThanOrEqualTo(0)) break;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
594
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
595
|
+
var product = _step4.value;
|
|
596
|
+
if (deductionLeft.lessThanOrEqualTo(0) || remainingLimit <= 0) break;
|
|
597
|
+
|
|
598
|
+
// 动态计算当前可抵扣数量 = ceil(剩余金额 / 单价)
|
|
599
|
+
var currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
|
|
600
|
+
var availableQty = Math.min(currentAvailableQty, remainingLimit);
|
|
601
|
+
|
|
602
|
+
// 计算本商品最大可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
603
|
+
var maxDeductForProduct = Decimal.min(product[unitPriceField].times(availableQty), product[amountField]);
|
|
604
|
+
var actualDeductAmount = Decimal.min(deductionLeft, maxDeductForProduct);
|
|
605
|
+
|
|
606
|
+
// 计算实际抵扣的数量(用于记录和配额计算)
|
|
607
|
+
var actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(product[unitPriceField]).toNumber());
|
|
608
|
+
|
|
609
|
+
// 只更新商品的剩余金额,不更新 remainingQuantity
|
|
610
|
+
product[amountField] = product[amountField].minus(actualDeductAmount);
|
|
611
|
+
deductionLeft = deductionLeft.minus(actualDeductAmount);
|
|
612
|
+
remainingLimit -= actualDeductQty;
|
|
523
613
|
deductionDetails.push({
|
|
524
614
|
product_id: product.product_id,
|
|
525
615
|
parent_product_id: product.parent_product_id || null,
|
|
526
616
|
is_bundle_item: product.is_bundle_item || false,
|
|
527
|
-
deductAmount:
|
|
617
|
+
deductAmount: actualDeductAmount.toNumber(),
|
|
618
|
+
// 转换为数字
|
|
619
|
+
deductQuantity: actualDeductQty // 抵扣涉及的数量(用于记录)
|
|
528
620
|
});
|
|
529
621
|
}
|
|
530
622
|
} catch (err) {
|
|
531
|
-
|
|
623
|
+
_iterator4.e(err);
|
|
532
624
|
} finally {
|
|
533
|
-
|
|
625
|
+
_iterator4.f();
|
|
534
626
|
}
|
|
535
627
|
} else {
|
|
536
|
-
//
|
|
628
|
+
// 非跨商品券:只抵扣一个商品(单价最高的),也受 applicableProductLimit 限制
|
|
537
629
|
var targetProduct = applicableProducts.reduce(function (max, p) {
|
|
538
|
-
return p[
|
|
630
|
+
return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
|
|
539
631
|
});
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
632
|
+
|
|
633
|
+
// 动态计算当前可抵扣数量
|
|
634
|
+
var _currentAvailableQty5 = Math.ceil(targetProduct[amountField].dividedBy(targetProduct[unitPriceField]).toNumber());
|
|
635
|
+
var _availableQty2 = applicableProductLimit > 0 ? Math.min(_currentAvailableQty5, applicableProductLimit) : _currentAvailableQty5;
|
|
636
|
+
|
|
637
|
+
// 计算本商品最大可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
638
|
+
var _maxDeductForProduct2 = Decimal.min(targetProduct[unitPriceField].times(_availableQty2), targetProduct[amountField]);
|
|
639
|
+
var _actualDeductAmount2 = Decimal.min(deductionLeft, _maxDeductForProduct2);
|
|
640
|
+
|
|
641
|
+
// 计算实际抵扣的数量
|
|
642
|
+
var _actualDeductQty2 = Math.ceil(_actualDeductAmount2.dividedBy(targetProduct[unitPriceField]).toNumber());
|
|
643
|
+
|
|
644
|
+
// 只更新商品的剩余金额,不更新 remainingQuantity
|
|
645
|
+
targetProduct[amountField] = targetProduct[amountField].minus(_actualDeductAmount2);
|
|
646
|
+
deductionLeft = deductionLeft.minus(_actualDeductAmount2);
|
|
543
647
|
deductionDetails.push({
|
|
544
648
|
product_id: targetProduct.product_id,
|
|
545
649
|
parent_product_id: targetProduct.parent_product_id || null,
|
|
546
650
|
is_bundle_item: targetProduct.is_bundle_item || false,
|
|
547
|
-
deductAmount:
|
|
651
|
+
deductAmount: _actualDeductAmount2.toNumber(),
|
|
652
|
+
// 转换为数字
|
|
653
|
+
deductQuantity: _actualDeductQty2 // 抵扣涉及的数量(用于记录)
|
|
548
654
|
});
|
|
549
655
|
}
|
|
550
656
|
var totalDeducted = maxDeduction.minus(deductionLeft);
|
|
@@ -588,7 +694,8 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
588
694
|
_config$deductTaxAndF4 = config.deductTaxAndFee,
|
|
589
695
|
deductTaxAndFee = _config$deductTaxAndF4 === void 0 ? true : _config$deductTaxAndF4;
|
|
590
696
|
|
|
591
|
-
//
|
|
697
|
+
// 根据券的配置选择使用哪个单价字段和金额字段
|
|
698
|
+
var unitPriceField = deductTaxAndFee ? 'unitPriceWithTax' : 'unitPricePure';
|
|
592
699
|
var amountField = deductTaxAndFee ? 'remainingAmountWithTax' : 'remainingAmountPure';
|
|
593
700
|
|
|
594
701
|
// 根据 deductTaxAndFee 配置获取推荐金额
|
|
@@ -614,7 +721,7 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
614
721
|
}
|
|
615
722
|
}
|
|
616
723
|
if (isAvailable) {
|
|
617
|
-
//
|
|
724
|
+
// 获取适用商品(只筛选有剩余金额的商品)
|
|
618
725
|
var applicableProducts = getApplicableProducts(voucher, productsForCalc).filter(function (p) {
|
|
619
726
|
return p[amountField].greaterThan(0);
|
|
620
727
|
});
|
|
@@ -626,22 +733,46 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
626
733
|
var baseAmount = Decimal.min(new Decimal(recommendedAmount), new Decimal(maxDeductionAmount));
|
|
627
734
|
if (allowCrossProduct) {
|
|
628
735
|
if (applicableProductLimit > 0) {
|
|
736
|
+
// 按单价从高到低排序,按动态计算的可抵扣数量累计直到达到 limit
|
|
629
737
|
var sortedProducts = _toConsumableArray(applicableProducts).sort(function (a, b) {
|
|
630
|
-
return a[
|
|
631
|
-
})
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
738
|
+
return a[unitPriceField].comparedTo(b[unitPriceField]) > 0 ? -1 : 1;
|
|
739
|
+
});
|
|
740
|
+
var remainingLimit = applicableProductLimit;
|
|
741
|
+
var _iterator5 = _createForOfIteratorHelper(sortedProducts),
|
|
742
|
+
_step5;
|
|
743
|
+
try {
|
|
744
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
745
|
+
var product = _step5.value;
|
|
746
|
+
if (remainingLimit <= 0) break;
|
|
747
|
+
// 动态计算当前可抵扣数量 = ceil(剩余金额 / 单价)
|
|
748
|
+
var currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
|
|
749
|
+
var deductQty = Math.min(currentAvailableQty, remainingLimit);
|
|
750
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
751
|
+
var deductAmount = Decimal.min(product[unitPriceField].times(deductQty), product[amountField]);
|
|
752
|
+
calculatedMaxAmount = calculatedMaxAmount.plus(deductAmount);
|
|
753
|
+
remainingLimit -= deductQty;
|
|
754
|
+
}
|
|
755
|
+
} catch (err) {
|
|
756
|
+
_iterator5.e(err);
|
|
757
|
+
} finally {
|
|
758
|
+
_iterator5.f();
|
|
759
|
+
}
|
|
635
760
|
} else {
|
|
761
|
+
// 无数量限制:所有适用商品的剩余金额总和
|
|
636
762
|
calculatedMaxAmount = applicableProducts.reduce(function (sum, p) {
|
|
637
763
|
return sum.plus(p[amountField]);
|
|
638
764
|
}, new Decimal(0));
|
|
639
765
|
}
|
|
640
766
|
} else {
|
|
767
|
+
// 非跨商品券:单个最高单价商品,也受 applicableProductLimit 限制
|
|
641
768
|
var maxProduct = applicableProducts.reduce(function (max, p) {
|
|
642
|
-
return p[
|
|
769
|
+
return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
|
|
643
770
|
});
|
|
644
|
-
|
|
771
|
+
// 动态计算当前可抵扣数量
|
|
772
|
+
var _currentAvailableQty6 = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
|
|
773
|
+
var _deductQty3 = applicableProductLimit > 0 ? Math.min(_currentAvailableQty6, applicableProductLimit) : _currentAvailableQty6;
|
|
774
|
+
// 实际可抵扣金额 = min(数量 * 单价, 剩余金额)
|
|
775
|
+
calculatedMaxAmount = Decimal.min(maxProduct[unitPriceField].times(_deductQty3), maxProduct[amountField]);
|
|
645
776
|
}
|
|
646
777
|
calculatedMaxAmount = Decimal.min(baseAmount, calculatedMaxAmount, remainingOrderAmount);
|
|
647
778
|
if (calculatedMaxAmount.lessThanOrEqualTo(0)) {
|
|
@@ -674,11 +805,11 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
|
|
|
674
805
|
export var getMainProductPrice = function getMainProductPrice(product, isDeductTaxAndFee) {
|
|
675
806
|
var _product$metadata, _product$metadata2, _product$metadata3;
|
|
676
807
|
var mainProductPrice = new Decimal((product === null || product === void 0 ? void 0 : product.main_product_selling_price) || ((_product$metadata = product.metadata) === null || _product$metadata === void 0 ? void 0 : _product$metadata.main_product_selling_price) || 0);
|
|
677
|
-
var
|
|
678
|
-
|
|
808
|
+
var _iterator6 = _createForOfIteratorHelper((product === null || product === void 0 ? void 0 : product.product_bundle) || []),
|
|
809
|
+
_step6;
|
|
679
810
|
try {
|
|
680
|
-
for (
|
|
681
|
-
var bundleItem =
|
|
811
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
812
|
+
var bundleItem = _step6.value;
|
|
682
813
|
// 子商品是加价或减价才需要计算
|
|
683
814
|
if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
|
|
684
815
|
var _bundleItem$bundle_se;
|
|
@@ -690,9 +821,9 @@ export var getMainProductPrice = function getMainProductPrice(product, isDeductT
|
|
|
690
821
|
|
|
691
822
|
// 税费
|
|
692
823
|
} catch (err) {
|
|
693
|
-
|
|
824
|
+
_iterator6.e(err);
|
|
694
825
|
} finally {
|
|
695
|
-
|
|
826
|
+
_iterator6.f();
|
|
696
827
|
}
|
|
697
828
|
var taxFee = new Decimal((product === null || product === void 0 ? void 0 : product.tax_fee) || (product === null || product === void 0 || (_product$metadata2 = product.metadata) === null || _product$metadata2 === void 0 ? void 0 : _product$metadata2.main_product_attached_bundle_tax_fee) || 0);
|
|
698
829
|
// 附加费
|
|
@@ -737,35 +868,54 @@ export var getBundleItemPrice = function getBundleItemPrice(bundleItem, parentQu
|
|
|
737
868
|
* 将商品数据拆分,包含主商品和原价子商品
|
|
738
869
|
* @param products 原始商品列表
|
|
739
870
|
* @param deductTaxAndFee 是否抵扣税费与附加费(已废弃,保留参数以兼容旧代码)
|
|
740
|
-
* @returns
|
|
871
|
+
* @returns 拆分后的商品数据(包含主商品和子商品,同时维护含税和不含税两个金额池,以及单价和剩余数量)
|
|
741
872
|
*/
|
|
742
873
|
var expandProductsWithBundleItems = function expandProductsWithBundleItems(products, deductTaxAndFee) {
|
|
743
874
|
var expandedProducts = [];
|
|
744
875
|
products.forEach(function (product) {
|
|
745
876
|
var productQuantity = getProductQuantity(product);
|
|
746
877
|
|
|
747
|
-
//
|
|
878
|
+
// 计算主商品单价(含税和不含税)
|
|
879
|
+
var unitPriceWithTax = getMainProductPrice(product, true);
|
|
880
|
+
var unitPricePure = getMainProductPrice(product, false);
|
|
881
|
+
|
|
882
|
+
// 1. 添加主商品(同时计算含税和不含税两个金额,以及单价和剩余数量)
|
|
748
883
|
expandedProducts.push(_objectSpread(_objectSpread({}, product), {}, {
|
|
749
884
|
is_bundle_item: false,
|
|
750
885
|
parent_product_id: null,
|
|
886
|
+
// 单价(用于按 quantity 计算抵扣)
|
|
887
|
+
unitPriceWithTax: new Decimal(unitPriceWithTax),
|
|
888
|
+
unitPricePure: new Decimal(unitPricePure),
|
|
889
|
+
// 剩余可抵扣数量
|
|
890
|
+
remainingQuantity: productQuantity,
|
|
751
891
|
// 含税费的剩余金额
|
|
752
|
-
remainingAmountWithTax: new Decimal(
|
|
892
|
+
remainingAmountWithTax: new Decimal(unitPriceWithTax).times(productQuantity),
|
|
753
893
|
// 纯商品金额(不含税费)
|
|
754
|
-
remainingAmountPure: new Decimal(
|
|
894
|
+
remainingAmountPure: new Decimal(unitPricePure).times(productQuantity)
|
|
755
895
|
}));
|
|
756
896
|
|
|
757
897
|
// 2. 添加原价子商品(作为独立商品项)
|
|
758
898
|
if (product.product_bundle && product.product_bundle.length > 0) {
|
|
759
899
|
product.product_bundle.forEach(function (bundleItem) {
|
|
760
900
|
if (getBundleItemIsOriginalPrice(bundleItem)) {
|
|
901
|
+
var bundleQuantity = bundleItem.num * productQuantity;
|
|
902
|
+
// 计算子商品单价(注意:getBundleItemPrice 返回的是总价,需要除以数量得到单价)
|
|
903
|
+
var bundleUnitPriceWithTax = new Decimal(getBundleItemPrice(bundleItem, 1, true)).dividedBy(bundleItem.num);
|
|
904
|
+
var bundleUnitPricePure = new Decimal(getBundleItemPrice(bundleItem, 1, false)).dividedBy(bundleItem.num);
|
|
905
|
+
|
|
761
906
|
// 原价子商品作为独立商品
|
|
762
907
|
expandedProducts.push(_objectSpread(_objectSpread({}, bundleItem), {}, {
|
|
763
908
|
product_id: bundleItem.bundle_product_id,
|
|
764
909
|
// 使用 bundle_product_id 作为 product_id
|
|
765
910
|
is_bundle_item: true,
|
|
766
911
|
parent_product_id: product.product_id,
|
|
767
|
-
quantity:
|
|
912
|
+
quantity: bundleQuantity,
|
|
768
913
|
// 子商品数量 * 主商品数量
|
|
914
|
+
// 单价(用于按 quantity 计算抵扣)
|
|
915
|
+
unitPriceWithTax: bundleUnitPriceWithTax,
|
|
916
|
+
unitPricePure: bundleUnitPricePure,
|
|
917
|
+
// 剩余可抵扣数量
|
|
918
|
+
remainingQuantity: bundleQuantity,
|
|
769
919
|
// 含税费的剩余金额
|
|
770
920
|
remainingAmountWithTax: new Decimal(getBundleItemPrice(bundleItem, productQuantity, true)),
|
|
771
921
|
// 纯商品金额(不含税费)
|