@pisell/pisellos 0.0.567 → 0.0.568
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/core/index.js +6 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +1 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +14 -41
- package/dist/modules/Payment/index.js +142 -270
- package/dist/modules/Payment/walletpass.js +4 -5
- package/dist/modules/Rules/index.js +0 -7
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +88 -121
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/products/index.js +29 -49
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +32 -40
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +5 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -246
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.d.ts +5 -0
- package/dist/solution/VenueBooking/index.js +364 -327
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +130 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +92 -53
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +84 -63
- package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
- package/lib/model/strategy/adapter/promotion/examples.js +139 -159
- package/lib/model/strategy/adapter/promotion/index.js +1 -49
- package/lib/model/strategy/adapter/promotion/type.js +199 -35
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +652 -402
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +22 -45
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +306 -241
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +72 -78
- package/lib/modules/Cart/utils/changePrice.js +26 -62
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +216 -153
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +117 -113
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +63 -74
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +332 -320
- package/lib/modules/Order/types.js +24 -33
- package/lib/modules/Order/utils.js +350 -284
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +566 -432
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +216 -107
- package/lib/modules/Payment/utils.js +50 -47
- package/lib/modules/Payment/walletpass.js +221 -203
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +111 -110
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +60 -82
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/Rules/index.js +1172 -872
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +59 -68
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +176 -193
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -167
- package/lib/modules/Schedule/index.js +97 -107
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -70
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +782 -429
- package/lib/modules/index.js +212 -57
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +882 -623
- package/lib/server/modules/index.js +85 -59
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +195 -231
- package/lib/server/modules/order/types.js +107 -32
- package/lib/server/modules/order/utils/filterBookings.js +174 -140
- package/lib/server/modules/order/utils/filterOrders.js +89 -60
- package/lib/server/modules/products/index.js +430 -335
- package/lib/server/modules/products/types.js +41 -34
- package/lib/server/modules/quotation/index.js +76 -77
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +216 -187
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +134 -119
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1530 -1343
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +147 -122
- package/lib/solution/BookingTicket/types.js +38 -64
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
- package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +227 -158
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +218 -200
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +803 -840
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.js +372 -331
- package/lib/solution/ShopDiscount/index.js +230 -236
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +309 -172
- package/lib/solution/VenueBooking/index.d.ts +5 -0
- package/lib/solution/VenueBooking/index.js +886 -929
- package/lib/solution/VenueBooking/types.js +20 -40
- package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
- package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +102 -37
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,499 +1,774 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/modules/Summary/utils.ts
|
|
30
|
-
var utils_exports = {};
|
|
31
|
-
__export(utils_exports, {
|
|
32
|
-
calcDiscountListDifference: () => calcDiscountListDifference,
|
|
33
|
-
calculateDeposit: () => calculateDeposit,
|
|
34
|
-
calculateOriginSubtotal: () => calculateOriginSubtotal,
|
|
35
|
-
calculatePriceDetails: () => calculatePriceDetails,
|
|
36
|
-
calculateSubtotal: () => calculateSubtotal,
|
|
37
|
-
calculateTaxFee: () => calculateTaxFee,
|
|
38
|
-
getBundleDiscountList: () => getBundleDiscountList,
|
|
39
|
-
getProductDiscountProductDiscountDifference: () => getProductDiscountProductDiscountDifference,
|
|
40
|
-
getSurcharge: () => getSurcharge,
|
|
41
|
-
getSurchargeAmount: () => getSurchargeAmount,
|
|
42
|
-
getTax: () => getTax
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
43
5
|
});
|
|
44
|
-
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const
|
|
6
|
+
exports.getTax = exports.getSurchargeAmount = exports.getSurcharge = exports.getProductDiscountProductDiscountDifference = exports.getBundleDiscountList = exports.calculateTaxFee = exports.calculateSubtotal = exports.calculatePriceDetails = exports.calculateOriginSubtotal = exports.calculateDeposit = exports.calcDiscountListDifference = void 0;
|
|
7
|
+
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
8
|
+
var _utils = require("../Product/utils");
|
|
9
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
const calculatePriceDetails = (shopInfo, items, isInScheduleByDate, surchargeList, scheduleById) => {
|
|
12
|
+
const subtotal = new _decimal.default(calculateSubtotal(items));
|
|
13
|
+
const subOriginTotal = new _decimal.default(calculateOriginSubtotal(items));
|
|
14
|
+
const totalTaxFee = new _decimal.default(calculateTaxFee(shopInfo, items));
|
|
15
|
+
// 订单附加费列表
|
|
16
|
+
const surcharge = getSurcharge({
|
|
17
|
+
service: items,
|
|
18
|
+
addons: [],
|
|
19
|
+
bookingDetail: null,
|
|
20
|
+
bookingId: undefined
|
|
21
|
+
}, {
|
|
22
|
+
isEdit: false,
|
|
23
|
+
isInScheduleByDate,
|
|
24
|
+
surcharge_list: surchargeList,
|
|
25
|
+
scheduleById
|
|
26
|
+
});
|
|
27
|
+
// 订单附加费金额
|
|
28
|
+
const surchargeAmount = new _decimal.default(getSurchargeAmount({
|
|
29
|
+
bookingDetail: null,
|
|
30
|
+
bookingId: undefined
|
|
31
|
+
}, surcharge, {
|
|
32
|
+
isEdit: false
|
|
33
|
+
}));
|
|
34
|
+
// 税费
|
|
35
|
+
const {
|
|
36
|
+
tax,
|
|
37
|
+
originTax
|
|
38
|
+
} = getTax({
|
|
39
|
+
service: items,
|
|
40
|
+
bookingDetail: null,
|
|
41
|
+
bookingId: undefined
|
|
42
|
+
}, {
|
|
55
43
|
computed: {
|
|
56
44
|
productExpectAmount: subtotal.toNumber(),
|
|
57
45
|
shopDiscount: 0
|
|
58
46
|
},
|
|
59
47
|
isEdit: false,
|
|
60
|
-
tax_rate: shopInfo
|
|
61
|
-
is_price_include_tax: shopInfo
|
|
48
|
+
tax_rate: shopInfo?.tax_rate,
|
|
49
|
+
is_price_include_tax: shopInfo?.is_price_include_tax
|
|
62
50
|
});
|
|
63
|
-
const total =
|
|
64
|
-
|
|
51
|
+
const total = shopInfo?.is_price_include_tax ? subtotal.plus(surchargeAmount) : subtotal.plus(tax).plus(surchargeAmount);
|
|
52
|
+
|
|
53
|
+
// 计算总价 不包含折扣卡商品券折扣信息价格
|
|
54
|
+
const originTotal = shopInfo?.is_price_include_tax ? subOriginTotal.plus(surchargeAmount) : subOriginTotal.plus(totalTaxFee).plus(surchargeAmount);
|
|
55
|
+
|
|
56
|
+
// 计算定金
|
|
65
57
|
const deposit = calculateDeposit(items);
|
|
66
58
|
return {
|
|
67
59
|
subtotal: subtotal.toFixed(2),
|
|
68
60
|
total: total.toFixed(2),
|
|
69
61
|
originTotal: originTotal.toFixed(2),
|
|
70
|
-
taxTitle: shopInfo
|
|
71
|
-
taxRate: shopInfo
|
|
62
|
+
taxTitle: shopInfo?.tax_title,
|
|
63
|
+
taxRate: shopInfo?.tax_rate,
|
|
72
64
|
totalTaxFee: tax,
|
|
73
|
-
isPriceIncludeTax: shopInfo
|
|
65
|
+
isPriceIncludeTax: shopInfo?.is_price_include_tax,
|
|
74
66
|
surcharge,
|
|
75
67
|
surchargeAmount: surchargeAmount.toFixed(2),
|
|
76
68
|
deposit
|
|
77
69
|
};
|
|
78
70
|
};
|
|
79
|
-
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 获取子商品折扣信息
|
|
74
|
+
* @param item
|
|
75
|
+
*/
|
|
76
|
+
exports.calculatePriceDetails = calculatePriceDetails;
|
|
77
|
+
const getBundleDiscountList = bundle => {
|
|
80
78
|
if (!bundle) {
|
|
81
79
|
return [];
|
|
82
80
|
}
|
|
83
81
|
let discountList = [];
|
|
84
|
-
bundle.forEach(
|
|
82
|
+
bundle.forEach(d => {
|
|
85
83
|
if (d.discount_list && Array.isArray(d.discount_list)) {
|
|
86
|
-
discountList.push(...d.discount_list.filter(
|
|
84
|
+
discountList.push(...d.discount_list.filter(item => !item.id));
|
|
87
85
|
}
|
|
88
86
|
});
|
|
89
87
|
return discountList;
|
|
90
88
|
};
|
|
91
|
-
|
|
89
|
+
exports.getBundleDiscountList = getBundleDiscountList;
|
|
90
|
+
const calcDiscountListDifference = discountList => {
|
|
92
91
|
return discountList.reduce((pre, cur) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}, new import_decimal.default(0)).toNumber();
|
|
92
|
+
return pre.plus(cur?.metadata?.product_discount_difference || 0);
|
|
93
|
+
}, new _decimal.default(0)).toNumber();
|
|
96
94
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const mainDiscountList =
|
|
100
|
-
const bundleDiscountList = getBundleDiscountList(
|
|
95
|
+
exports.calcDiscountListDifference = calcDiscountListDifference;
|
|
96
|
+
const getProductDiscountProductDiscountDifference = item => {
|
|
97
|
+
const mainDiscountList = item._origin?.product?.discount_list || [];
|
|
98
|
+
const bundleDiscountList = getBundleDiscountList(item._origin?.product?.product_bundle || []);
|
|
101
99
|
const discountList = [...mainDiscountList, ...bundleDiscountList];
|
|
102
100
|
return calcDiscountListDifference(discountList);
|
|
103
101
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 计算订单税费(折扣前/折扣后),并把单品税费信息回写到商品数据上(用于明细展示/后续计算)。
|
|
105
|
+
*
|
|
106
|
+
* - **折扣前税费**:`originTax`
|
|
107
|
+
* - **折扣后税费**:`tax`(会考虑 `computed.shopDiscount` 对每个商品的分摊影响)
|
|
108
|
+
* - **税率/是否含税**:优先取 `bookingDetail.tax_rate` / `bookingDetail.is_price_include_tax`,取不到再回退到 `options.tax_rate` / `options.is_price_include_tax`
|
|
109
|
+
*
|
|
110
|
+
* **副作用(会修改入参商品对象)**:
|
|
111
|
+
* - 主商品:写入 `item.original_tax_fee` / `item.tax_fee`(四舍五入保留两位)
|
|
112
|
+
* - bundle 原价子商品:写入 `bundleItem.original_tax_fee` / `bundleItem.tax_fee`
|
|
113
|
+
* - 加时商品(`relation_details`):写入 `atItem.tax_fee`
|
|
114
|
+
* - 税费舍入差值:追加到最后一个“含税商品”的 `tax_fee_rounding_remainder` / `original_tax_fee_rounding_remainder`
|
|
115
|
+
*
|
|
116
|
+
* @param params 入参集合(RORO)
|
|
117
|
+
* @param params.service 服务商品数组(主商品)。通常是购物车商品结构(可能包含 `bundle` / `relation_details`)
|
|
118
|
+
* @param params.addons 附加商品数组(可选)。结构同商品数组
|
|
119
|
+
* @param params.bookingDetail 订单详情(编辑/详情场景用于读取后端税率配置),可选
|
|
120
|
+
* @param params.bookingId 订单/预约 ID(编辑/详情场景识别用),可选
|
|
121
|
+
* @param options 计算选项
|
|
122
|
+
* @param options.isEdit 是否处于“编辑中”。当前实现不强依赖该值(历史逻辑保留),但建议按真实状态传入
|
|
123
|
+
* @param options.computed 预计算结果(用于折扣分摊)
|
|
124
|
+
* @param options.computed.productExpectAmount 商品期望总金额(用于按比例分摊折扣)
|
|
125
|
+
* @param options.computed.shopDiscount 店铺折扣总额(用于按比例分摊到商品)
|
|
126
|
+
* @param options.tax_rate 管理端税率(百分比,如 5 表示 5%)。仅当 `bookingDetail.tax_rate` 不存在时生效
|
|
127
|
+
* @param options.is_price_include_tax 是否含税:`0` 不含税、`1` 含税。仅当 `bookingDetail.is_price_include_tax` 不存在时生效
|
|
128
|
+
* @returns 税费汇总(number,金额单位与商品价格一致,四舍五入保留两位)
|
|
129
|
+
* @returns.originTax 折扣前税费合计
|
|
130
|
+
* @returns.tax 折扣后税费合计
|
|
131
|
+
*/
|
|
132
|
+
exports.getProductDiscountProductDiscountDifference = getProductDiscountProductDiscountDifference;
|
|
133
|
+
const getTax = ({
|
|
134
|
+
service,
|
|
135
|
+
addons,
|
|
136
|
+
bookingDetail,
|
|
137
|
+
bookingId
|
|
138
|
+
}, options) => {
|
|
139
|
+
const {
|
|
140
|
+
isEdit,
|
|
141
|
+
computed,
|
|
142
|
+
tax_rate,
|
|
143
|
+
is_price_include_tax
|
|
144
|
+
} = options;
|
|
145
|
+
|
|
146
|
+
// 详情时未编辑的状态下, 取后端的值
|
|
147
|
+
// if (!isEdit) {
|
|
148
|
+
// return { tax: Number(bookingDetail?.tax_fee) || 0 };
|
|
149
|
+
// }
|
|
150
|
+
|
|
151
|
+
let totalOriginTax = new _decimal.default(0);
|
|
152
|
+
let totalTax = new _decimal.default(0);
|
|
108
153
|
if (service || addons) {
|
|
109
|
-
|
|
110
|
-
|
|
154
|
+
// 处理服务商品
|
|
155
|
+
if (service?.length) {
|
|
156
|
+
const serviceResult = processItemsTax(service.map(item => {
|
|
111
157
|
return {
|
|
112
158
|
...item,
|
|
113
|
-
option:
|
|
114
|
-
bundle:
|
|
159
|
+
option: item?.option || item?.options || [],
|
|
160
|
+
bundle: item?.bundle || item?.bundles || []
|
|
115
161
|
};
|
|
116
|
-
}), {
|
|
162
|
+
}), {
|
|
163
|
+
bookingDetail,
|
|
164
|
+
bookingId
|
|
165
|
+
}, {
|
|
117
166
|
tax_rate,
|
|
118
167
|
is_price_include_tax,
|
|
119
|
-
computed
|
|
168
|
+
computed: computed
|
|
120
169
|
});
|
|
121
170
|
totalOriginTax = totalOriginTax.plus(serviceResult.originTax);
|
|
122
171
|
totalTax = totalTax.plus(serviceResult.tax);
|
|
123
172
|
}
|
|
124
|
-
|
|
125
|
-
|
|
173
|
+
|
|
174
|
+
// 处理附加商品
|
|
175
|
+
if (addons?.length) {
|
|
176
|
+
const addonsResult = processItemsTax(addons, {
|
|
177
|
+
bookingDetail,
|
|
178
|
+
bookingId
|
|
179
|
+
}, {
|
|
126
180
|
tax_rate,
|
|
127
181
|
is_price_include_tax,
|
|
128
|
-
computed
|
|
182
|
+
computed: computed
|
|
129
183
|
});
|
|
130
184
|
totalOriginTax = totalOriginTax.plus(addonsResult.originTax);
|
|
131
185
|
totalTax = totalTax.plus(addonsResult.tax);
|
|
132
186
|
}
|
|
133
187
|
}
|
|
134
188
|
return {
|
|
135
|
-
originTax: totalOriginTax.toDecimalPlaces(2,
|
|
136
|
-
tax: totalTax.toDecimalPlaces(2,
|
|
189
|
+
originTax: totalOriginTax.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber(),
|
|
190
|
+
tax: totalTax.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber()
|
|
137
191
|
};
|
|
138
192
|
};
|
|
193
|
+
exports.getTax = getTax;
|
|
139
194
|
function getDiscountedTaxableBase(input) {
|
|
140
|
-
const {
|
|
141
|
-
|
|
142
|
-
|
|
195
|
+
const {
|
|
196
|
+
basePrice,
|
|
197
|
+
discount,
|
|
198
|
+
surchargeFee
|
|
199
|
+
} = input;
|
|
200
|
+
if (surchargeFee.lte(0) && basePrice.lte(0)) return new _decimal.default(0);
|
|
143
201
|
const discountedBase = basePrice.minus(discount);
|
|
144
|
-
if (discountedBase.lte(0))
|
|
145
|
-
return surchargeFee;
|
|
202
|
+
if (discountedBase.lte(0)) return surchargeFee;
|
|
146
203
|
return discountedBase.plus(surchargeFee);
|
|
147
204
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 处理商品税费计算(折扣前后)
|
|
208
|
+
* 支持税费舍入差值追加到最后一个含税商品的 tax_fee_rounding_remainder / original_tax_fee_rounding_remainder 字段
|
|
209
|
+
* @param items 商品数组
|
|
210
|
+
* @param state 状态
|
|
211
|
+
* @param options 选项
|
|
212
|
+
* @param computed 计算结果
|
|
213
|
+
* @returns 累积的税费信息
|
|
214
|
+
*/
|
|
215
|
+
const processItemsTax = (items, {
|
|
216
|
+
bookingDetail,
|
|
217
|
+
bookingId
|
|
218
|
+
}, options) => {
|
|
219
|
+
const {
|
|
220
|
+
tax_rate,
|
|
221
|
+
is_price_include_tax,
|
|
222
|
+
computed
|
|
223
|
+
} = options;
|
|
224
|
+
const {
|
|
225
|
+
shopDiscount,
|
|
226
|
+
productExpectAmount
|
|
227
|
+
} = computed;
|
|
228
|
+
|
|
229
|
+
// 精确税费累加(不四舍五入)
|
|
230
|
+
let preciseOriginTax = new _decimal.default(0);
|
|
231
|
+
let preciseTax = new _decimal.default(0);
|
|
232
|
+
// 四舍五入后的税费累加
|
|
233
|
+
let roundedOriginTax = new _decimal.default(0);
|
|
234
|
+
let roundedTax = new _decimal.default(0);
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* 最后一个含税商品的引用(按物理位置)
|
|
238
|
+
* 用于追加税费舍入差值
|
|
239
|
+
*/
|
|
155
240
|
let lastTaxableItem = null;
|
|
156
241
|
for (let item of items) {
|
|
157
|
-
const quantity = new
|
|
158
|
-
const unitPrice = new
|
|
159
|
-
const mainProductPrice = new
|
|
242
|
+
const quantity = new _decimal.default(item.num || 1);
|
|
243
|
+
const unitPrice = new _decimal.default(item.total || 0);
|
|
244
|
+
const mainProductPrice = new _decimal.default(getMainProductTotal({
|
|
160
245
|
...item,
|
|
161
|
-
option:
|
|
162
|
-
bundle:
|
|
246
|
+
option: item?.option || item?.options || [],
|
|
247
|
+
bundle: item?.bundle || item?.bundles || []
|
|
163
248
|
}) || 0);
|
|
249
|
+
|
|
250
|
+
// 计算原始税费(折扣前)- 单个商品(精确值)
|
|
164
251
|
const originalTaxableBase = getDiscountedTaxableBase({
|
|
165
252
|
basePrice: mainProductPrice,
|
|
166
|
-
discount: new
|
|
167
|
-
surchargeFee: new
|
|
253
|
+
discount: new _decimal.default(0),
|
|
254
|
+
surchargeFee: new _decimal.default(item?.surcharge_fee || 0)
|
|
255
|
+
});
|
|
256
|
+
let originalTaxPerItemPrecise = getProductItemTax({
|
|
257
|
+
...item,
|
|
258
|
+
total: originalTaxableBase.toNumber(),
|
|
259
|
+
quantity: 1
|
|
260
|
+
}, {
|
|
261
|
+
bookingDetail,
|
|
262
|
+
bookingId
|
|
263
|
+
}, {
|
|
264
|
+
tax_rate,
|
|
265
|
+
is_price_include_tax
|
|
168
266
|
});
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
total: originalTaxableBase.toNumber(),
|
|
173
|
-
quantity: 1
|
|
174
|
-
},
|
|
175
|
-
{ bookingDetail, bookingId },
|
|
176
|
-
{ tax_rate, is_price_include_tax }
|
|
177
|
-
);
|
|
178
|
-
let itemDiscount = new import_decimal.default(0);
|
|
267
|
+
|
|
268
|
+
// 计算平摊到该商品的折扣
|
|
269
|
+
let itemDiscount = new _decimal.default(0);
|
|
179
270
|
if (productExpectAmount > 0) {
|
|
180
271
|
itemDiscount = unitPrice.dividedBy(productExpectAmount).times(shopDiscount);
|
|
181
272
|
}
|
|
182
|
-
|
|
273
|
+
|
|
274
|
+
// 按比例计算主商品应分摊的折扣
|
|
275
|
+
let mainItemDiscount = new _decimal.default(0);
|
|
183
276
|
if (unitPrice.greaterThan(0)) {
|
|
184
277
|
mainItemDiscount = mainProductPrice.dividedBy(productExpectAmount).times(shopDiscount);
|
|
185
278
|
}
|
|
186
279
|
const mainItemDiscountedUnitPrice = getDiscountedTaxableBase({
|
|
187
280
|
basePrice: mainProductPrice,
|
|
188
281
|
discount: mainItemDiscount,
|
|
189
|
-
surchargeFee: new
|
|
282
|
+
surchargeFee: new _decimal.default(item?.surcharge_fee || 0)
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// 计算折后税费(折扣后)- 主商品的税费(精确值)
|
|
286
|
+
const maxDiscountedTaxPerItemPrecise = getProductItemTax({
|
|
287
|
+
...item,
|
|
288
|
+
total: mainItemDiscountedUnitPrice.toNumber(),
|
|
289
|
+
price: item.total,
|
|
290
|
+
quantity: 1
|
|
291
|
+
}, {
|
|
292
|
+
bookingDetail,
|
|
293
|
+
bookingId
|
|
294
|
+
}, {
|
|
295
|
+
tax_rate,
|
|
296
|
+
is_price_include_tax
|
|
190
297
|
});
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
quantity: 1
|
|
197
|
-
},
|
|
198
|
-
{ bookingDetail, bookingId },
|
|
199
|
-
{ tax_rate, is_price_include_tax }
|
|
200
|
-
);
|
|
201
|
-
const maxDiscountedTaxPerItemRounded = maxDiscountedTaxPerItemPrecise.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
|
|
298
|
+
|
|
299
|
+
// 四舍五入后的值
|
|
300
|
+
const maxDiscountedTaxPerItemRounded = maxDiscountedTaxPerItemPrecise.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
301
|
+
|
|
302
|
+
// 保存到商品扩展信息中(保留两位小数)
|
|
202
303
|
item.main_product_attached_bundle_tax_fee = maxDiscountedTaxPerItemRounded.toNumber();
|
|
304
|
+
|
|
305
|
+
// 如果主商品有税费,记录为最后一个含税商品
|
|
203
306
|
if (maxDiscountedTaxPerItemPrecise.gt(0)) {
|
|
204
|
-
lastTaxableItem = {
|
|
307
|
+
lastTaxableItem = {
|
|
308
|
+
type: 'main',
|
|
309
|
+
item
|
|
310
|
+
};
|
|
205
311
|
}
|
|
206
|
-
|
|
207
|
-
|
|
312
|
+
|
|
313
|
+
// 注意:加时商品独立计算,不考虑主商品数量
|
|
314
|
+
let addTimePreciseTax = new _decimal.default(0);
|
|
315
|
+
let addTimeRoundedTax = new _decimal.default(0);
|
|
208
316
|
if (Array.isArray(item.relation_details)) {
|
|
209
317
|
for (let atItem of item.relation_details) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
213
|
-
const addTimeDiscount = productExpectAmount > 0 ? _originTotal.dividedBy(productExpectAmount).times(shopDiscount) : new import_decimal.default(0);
|
|
318
|
+
// 计算单件加时商品折扣后价格
|
|
319
|
+
const _originTotal = new _decimal.default(atItem.selling_price || atItem.price || 0);
|
|
320
|
+
const addTimeDiscount = productExpectAmount > 0 ? _originTotal.dividedBy(productExpectAmount).times(shopDiscount) : new _decimal.default(0);
|
|
214
321
|
const _discountedTotal = getDiscountedTaxableBase({
|
|
215
322
|
basePrice: _originTotal,
|
|
216
323
|
discount: addTimeDiscount,
|
|
217
|
-
surchargeFee: new
|
|
324
|
+
surchargeFee: new _decimal.default(atItem?.surcharge_fee || 0)
|
|
325
|
+
});
|
|
326
|
+
const addTimeTaxPerItemPrecise = getProductItemTax({
|
|
327
|
+
...atItem,
|
|
328
|
+
total: _discountedTotal.toNumber(),
|
|
329
|
+
quantity: atItem.product_quantity || atItem.num || 1
|
|
330
|
+
}, {
|
|
331
|
+
bookingDetail,
|
|
332
|
+
bookingId
|
|
333
|
+
}, {
|
|
334
|
+
tax_rate,
|
|
335
|
+
is_price_include_tax
|
|
218
336
|
});
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
total: _discountedTotal.toNumber(),
|
|
223
|
-
quantity: atItem.product_quantity || atItem.num || 1
|
|
224
|
-
},
|
|
225
|
-
{ bookingDetail, bookingId },
|
|
226
|
-
{ tax_rate, is_price_include_tax }
|
|
227
|
-
);
|
|
228
|
-
const addTimeTaxPerItemRounded = addTimeTaxPerItemPrecise.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
|
|
337
|
+
const addTimeTaxPerItemRounded = addTimeTaxPerItemPrecise.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
338
|
+
|
|
339
|
+
// 保存到加时商品上(四舍五入后的值)
|
|
229
340
|
atItem.tax_fee = addTimeTaxPerItemRounded.toNumber();
|
|
230
341
|
addTimePreciseTax = addTimePreciseTax.plus(addTimeTaxPerItemPrecise);
|
|
231
342
|
addTimeRoundedTax = addTimeRoundedTax.plus(addTimeTaxPerItemRounded);
|
|
343
|
+
|
|
344
|
+
// 如果加时商品有税费,记录为最后一个含税商品
|
|
232
345
|
if (addTimeTaxPerItemPrecise.gt(0)) {
|
|
233
|
-
lastTaxableItem = {
|
|
346
|
+
lastTaxableItem = {
|
|
347
|
+
type: 'addTime',
|
|
348
|
+
item: atItem
|
|
349
|
+
};
|
|
234
350
|
}
|
|
235
351
|
}
|
|
236
352
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
let
|
|
240
|
-
let
|
|
241
|
-
|
|
242
|
-
|
|
353
|
+
|
|
354
|
+
// 处理 bundle 子商品(仅原价子商品)
|
|
355
|
+
let bundlePreciseOriginTax = new _decimal.default(0);
|
|
356
|
+
let bundlePreciseTax = new _decimal.default(0);
|
|
357
|
+
let bundleRoundedOriginTax = new _decimal.default(0);
|
|
358
|
+
let bundleRoundedTax = new _decimal.default(0);
|
|
359
|
+
if (Array.isArray(item?.bundle)) {
|
|
360
|
+
for (let bundleItem of item?.bundle) {
|
|
361
|
+
// 只处理原价的子商品
|
|
243
362
|
if (getBundleItemIsOriginalPrice(bundleItem)) {
|
|
244
|
-
const bundleQuantity = new
|
|
245
|
-
const bundleUnitPrice = new
|
|
246
|
-
|
|
247
|
-
|
|
363
|
+
const bundleQuantity = new _decimal.default(bundleItem.num || bundleItem.quantity || 1);
|
|
364
|
+
const bundleUnitPrice = new _decimal.default(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
365
|
+
|
|
366
|
+
// 计算原始税费(折扣前)- 单个商品(精确值)
|
|
248
367
|
const bundleOriginalTaxableBase = getDiscountedTaxableBase({
|
|
249
368
|
basePrice: bundleUnitPrice,
|
|
250
|
-
discount: new
|
|
251
|
-
surchargeFee: new
|
|
369
|
+
discount: new _decimal.default(0),
|
|
370
|
+
surchargeFee: new _decimal.default(bundleItem?.surcharge_fee || 0)
|
|
371
|
+
});
|
|
372
|
+
const bundleOriginalTaxPerItemPrecise = getProductItemTax({
|
|
373
|
+
...bundleItem,
|
|
374
|
+
total: bundleOriginalTaxableBase.toNumber(),
|
|
375
|
+
quantity: 1
|
|
376
|
+
}, {
|
|
377
|
+
bookingDetail,
|
|
378
|
+
bookingId
|
|
379
|
+
}, {
|
|
380
|
+
tax_rate,
|
|
381
|
+
is_price_include_tax
|
|
252
382
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
total: bundleOriginalTaxableBase.toNumber(),
|
|
257
|
-
quantity: 1
|
|
258
|
-
},
|
|
259
|
-
{ bookingDetail, bookingId },
|
|
260
|
-
{ tax_rate, is_price_include_tax }
|
|
261
|
-
);
|
|
262
|
-
let bundleItemDiscount = new import_decimal.default(0);
|
|
383
|
+
|
|
384
|
+
// 计算平摊到该bundle商品的折扣
|
|
385
|
+
let bundleItemDiscount = new _decimal.default(0);
|
|
263
386
|
if (productExpectAmount > 0) {
|
|
264
387
|
bundleItemDiscount = bundleUnitPrice.dividedBy(productExpectAmount).times(shopDiscount);
|
|
265
388
|
}
|
|
389
|
+
|
|
390
|
+
// bundle商品折后单价
|
|
266
391
|
const bundleDiscountedUnitPrice = getDiscountedTaxableBase({
|
|
267
392
|
basePrice: bundleUnitPrice,
|
|
268
393
|
discount: bundleItemDiscount,
|
|
269
|
-
surchargeFee: new
|
|
394
|
+
surchargeFee: new _decimal.default(bundleItem?.surcharge_fee || 0)
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// 计算折后税费(折扣后)- 单个商品(精确值)
|
|
398
|
+
const bundleDiscountedTaxPerItemPrecise = getProductItemTax({
|
|
399
|
+
...bundleItem,
|
|
400
|
+
total: bundleDiscountedUnitPrice.toNumber(),
|
|
401
|
+
quantity: 1
|
|
402
|
+
}, {
|
|
403
|
+
bookingDetail,
|
|
404
|
+
bookingId
|
|
405
|
+
}, {
|
|
406
|
+
tax_rate,
|
|
407
|
+
is_price_include_tax
|
|
270
408
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
{ bookingDetail, bookingId },
|
|
278
|
-
{ tax_rate, is_price_include_tax }
|
|
279
|
-
);
|
|
280
|
-
const bundleOriginalTaxPerItemRounded = bundleOriginalTaxPerItemPrecise.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
|
|
281
|
-
const bundleDiscountedTaxPerItemRounded = bundleDiscountedTaxPerItemPrecise.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
|
|
409
|
+
|
|
410
|
+
// 四舍五入后的值
|
|
411
|
+
const bundleOriginalTaxPerItemRounded = bundleOriginalTaxPerItemPrecise.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
412
|
+
const bundleDiscountedTaxPerItemRounded = bundleDiscountedTaxPerItemPrecise.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
413
|
+
|
|
414
|
+
// 保存到bundle商品上(单个商品的税费,四舍五入后)
|
|
282
415
|
bundleItem.original_tax_fee = bundleOriginalTaxPerItemRounded.toNumber();
|
|
283
416
|
bundleItem.tax_fee = bundleDiscountedTaxPerItemRounded.toNumber();
|
|
417
|
+
|
|
418
|
+
// 累加bundle税费(需要乘以bundle数量)
|
|
284
419
|
bundlePreciseOriginTax = bundlePreciseOriginTax.plus(bundleOriginalTaxPerItemPrecise.times(bundleQuantity));
|
|
285
420
|
bundlePreciseTax = bundlePreciseTax.plus(bundleDiscountedTaxPerItemPrecise.times(bundleQuantity));
|
|
286
421
|
bundleRoundedOriginTax = bundleRoundedOriginTax.plus(bundleOriginalTaxPerItemRounded.times(bundleQuantity));
|
|
287
422
|
bundleRoundedTax = bundleRoundedTax.plus(bundleDiscountedTaxPerItemRounded.times(bundleQuantity));
|
|
423
|
+
|
|
424
|
+
// 如果bundle商品有税费,记录为最后一个含税商品
|
|
288
425
|
if (bundleDiscountedTaxPerItemPrecise.gt(0)) {
|
|
289
|
-
lastTaxableItem = {
|
|
426
|
+
lastTaxableItem = {
|
|
427
|
+
type: 'bundle',
|
|
428
|
+
item: bundleItem
|
|
429
|
+
};
|
|
290
430
|
}
|
|
291
431
|
}
|
|
292
432
|
}
|
|
293
433
|
}
|
|
434
|
+
// 主商品的原始税费和折后税费(精确值)
|
|
294
435
|
const originalTaxFeePrecise = originalTaxPerItemPrecise.plus(bundlePreciseOriginTax);
|
|
295
436
|
const taxFeePrecise = maxDiscountedTaxPerItemPrecise.plus(bundlePreciseTax);
|
|
296
|
-
|
|
437
|
+
|
|
438
|
+
// 主商品的原始税费和折后税费(四舍五入后)
|
|
439
|
+
const originalTaxFeeRounded = originalTaxPerItemPrecise.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).plus(bundleRoundedOriginTax);
|
|
297
440
|
const taxFeeRounded = maxDiscountedTaxPerItemRounded.plus(bundleRoundedTax);
|
|
298
|
-
|
|
299
|
-
|
|
441
|
+
|
|
442
|
+
// 保存到商品扩展信息中(四舍五入后的值)
|
|
443
|
+
item.original_tax_fee = originalTaxFeeRounded.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
444
|
+
item.tax_fee = taxFeeRounded.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
445
|
+
|
|
446
|
+
// 累加到总税费(乘以数量)
|
|
300
447
|
preciseOriginTax = preciseOriginTax.plus(originalTaxFeePrecise.times(quantity)).plus(addTimePreciseTax);
|
|
301
448
|
preciseTax = preciseTax.plus(taxFeePrecise.times(quantity)).plus(addTimePreciseTax);
|
|
302
449
|
roundedOriginTax = roundedOriginTax.plus(originalTaxFeeRounded.times(quantity)).plus(addTimeRoundedTax);
|
|
303
450
|
roundedTax = roundedTax.plus(taxFeeRounded.times(quantity)).plus(addTimeRoundedTax);
|
|
304
451
|
}
|
|
305
|
-
|
|
306
|
-
|
|
452
|
+
|
|
453
|
+
// 计算期望的总税费(精确累加后四舍五入)
|
|
454
|
+
const expectedOriginTax = preciseOriginTax.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
455
|
+
const expectedTax = preciseTax.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
456
|
+
|
|
457
|
+
// 计算舍入差值
|
|
307
458
|
const originTaxRemainder = expectedOriginTax.minus(roundedOriginTax).toNumber();
|
|
308
459
|
const taxRemainder = expectedTax.minus(roundedTax).toNumber();
|
|
460
|
+
|
|
461
|
+
// 将差值追加到最后一个含税商品
|
|
309
462
|
if (lastTaxableItem) {
|
|
310
463
|
if (originTaxRemainder !== 0) {
|
|
311
|
-
if (lastTaxableItem.type ===
|
|
464
|
+
if (lastTaxableItem.type === 'main') {
|
|
312
465
|
lastTaxableItem.item.original_tax_fee_rounding_remainder = originTaxRemainder;
|
|
313
466
|
} else {
|
|
314
467
|
lastTaxableItem.item.original_tax_fee_rounding_remainder = originTaxRemainder;
|
|
315
468
|
}
|
|
316
469
|
}
|
|
317
470
|
if (taxRemainder !== 0) {
|
|
318
|
-
if (lastTaxableItem.type ===
|
|
471
|
+
if (lastTaxableItem.type === 'main') {
|
|
319
472
|
lastTaxableItem.item.tax_fee_rounding_remainder = taxRemainder;
|
|
320
473
|
} else {
|
|
321
474
|
lastTaxableItem.item.tax_fee_rounding_remainder = taxRemainder;
|
|
322
475
|
}
|
|
323
476
|
}
|
|
324
477
|
}
|
|
325
|
-
return {
|
|
478
|
+
return {
|
|
479
|
+
originTax: expectedOriginTax,
|
|
480
|
+
tax: expectedTax
|
|
481
|
+
};
|
|
326
482
|
};
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* 计算单个商品的税费(返回精确值,不四舍五入)
|
|
486
|
+
* @param item 商品信息
|
|
487
|
+
* @param state 状态
|
|
488
|
+
* @param options 选项
|
|
489
|
+
* @returns 精确的税费值(Decimal类型)
|
|
490
|
+
*/
|
|
491
|
+
const getProductItemTax = (item, state, options) => {
|
|
492
|
+
const {
|
|
493
|
+
bookingDetail
|
|
494
|
+
} = state;
|
|
495
|
+
const {
|
|
496
|
+
tax_rate,
|
|
497
|
+
is_price_include_tax
|
|
498
|
+
} = options;
|
|
499
|
+
|
|
500
|
+
// 折扣后的金额 = 商品金额 - 商品折扣
|
|
501
|
+
const productDiscountPrice = new _decimal.default(item.total || 0);
|
|
502
|
+
/**
|
|
503
|
+
* 注意:该函数被多处以“单件税费”方式调用(调用方会显式传入 quantity: 1),
|
|
504
|
+
* 因此这里必须优先使用 `item.quantity`,否则会出现数量被重复相乘(外层再乘一次 num)的情况。
|
|
505
|
+
*/
|
|
506
|
+
const quantity = new _decimal.default(item.quantity ?? item.num ?? 1);
|
|
507
|
+
|
|
508
|
+
// 如果商品金额小于或等于0,不计算税费
|
|
332
509
|
if (productDiscountPrice.lte(0)) {
|
|
333
|
-
return new
|
|
510
|
+
return new _decimal.default(0);
|
|
334
511
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
512
|
+
|
|
513
|
+
// 优先从 bookingDetail 取税率和是否含税设置,取不到则从 options 中取(兼容新增模式)
|
|
514
|
+
// 注意:bookingDetail中的tax_rate不需要除以100,options 中的tax_rate需要除以100
|
|
515
|
+
const currentTaxRate = new _decimal.default(bookingDetail?.tax_rate ?? (tax_rate ? tax_rate / 100 : 0));
|
|
516
|
+
const currentIsPriceIncludeTax = bookingDetail?.is_price_include_tax ?? is_price_include_tax ?? 0;
|
|
517
|
+
let singleItemTax = new _decimal.default(0);
|
|
518
|
+
|
|
519
|
+
// 计算单个商品税费, 一次性商品 is_charge_tax 可能为空
|
|
340
520
|
if (item.is_charge_tax === 0 || !item.is_charge_tax) {
|
|
341
|
-
|
|
521
|
+
// 该商品不需要收税
|
|
522
|
+
singleItemTax = new _decimal.default(0);
|
|
342
523
|
} else {
|
|
524
|
+
// 该商品需要收税
|
|
343
525
|
if (currentIsPriceIncludeTax === 0) {
|
|
526
|
+
// 价格不含税:管理端填写的单价是不含税的价格
|
|
344
527
|
singleItemTax = productDiscountPrice.times(currentTaxRate);
|
|
345
528
|
} else {
|
|
346
|
-
|
|
529
|
+
// 价格含税:管理端填写的单价是含税的价格
|
|
530
|
+
// 含税总价 = 不含税价 + (不含税价 * 税率) = 不含税价 * (1 + 税率)
|
|
531
|
+
// 商品不含税价 = 含税总价 / (1 + 税率)
|
|
532
|
+
// 税 = 不含税价 * 税率
|
|
533
|
+
const divisor = new _decimal.default(1).plus(currentTaxRate);
|
|
347
534
|
if (divisor.lte(0)) {
|
|
348
|
-
|
|
535
|
+
// 如果 (1 + 税率) <= 0,说明税率异常,不计算税费
|
|
536
|
+
singleItemTax = new _decimal.default(0);
|
|
349
537
|
} else {
|
|
350
538
|
singleItemTax = productDiscountPrice.dividedBy(divisor).times(currentTaxRate);
|
|
351
539
|
}
|
|
352
540
|
}
|
|
353
541
|
}
|
|
542
|
+
|
|
543
|
+
// 结果 = 单个商品税费 × 数量(返回精确值,不四舍五入)
|
|
354
544
|
return singleItemTax.times(quantity);
|
|
355
545
|
};
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* 计算商品小计(不含其他费用)
|
|
549
|
+
* @param items - 购物车商品数组
|
|
550
|
+
* @returns 商品总价字符串,保留2位小数
|
|
551
|
+
*/
|
|
552
|
+
const calculateSubtotal = items => {
|
|
553
|
+
if (!items?.length) {
|
|
554
|
+
return '0.00';
|
|
359
555
|
}
|
|
360
556
|
const subtotal = items.reduce((sum, item) => {
|
|
361
|
-
const cartItemTotalPrice = new
|
|
557
|
+
const cartItemTotalPrice = new _decimal.default(item.summaryTotal || 0);
|
|
362
558
|
const productDiscountProductDiscountDifference = getProductDiscountProductDiscountDifference(item);
|
|
363
559
|
return sum.plus(cartItemTotalPrice).sub(productDiscountProductDiscountDifference);
|
|
364
|
-
}, new
|
|
560
|
+
}, new _decimal.default(0));
|
|
365
561
|
return subtotal.toFixed(2);
|
|
366
562
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* 计算商品小计(不含其他费用 不包含折扣卡商品券抵扣金额)
|
|
566
|
+
* @param items - 购物车商品数组
|
|
567
|
+
* @returns 商品总价字符串,保留2位小数
|
|
568
|
+
*/
|
|
569
|
+
exports.calculateSubtotal = calculateSubtotal;
|
|
570
|
+
const calculateOriginSubtotal = items => {
|
|
571
|
+
if (!items?.length) {
|
|
572
|
+
return '0.00';
|
|
370
573
|
}
|
|
371
574
|
const subtotal = items.reduce((sum, item) => {
|
|
372
|
-
const cartItemTotalPrice = new
|
|
575
|
+
const cartItemTotalPrice = new _decimal.default(item.summaryOriginTotal || 0);
|
|
373
576
|
return sum.plus(cartItemTotalPrice);
|
|
374
|
-
}, new
|
|
577
|
+
}, new _decimal.default(0));
|
|
375
578
|
return subtotal.toFixed(2);
|
|
376
579
|
};
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* @title: 单个商品的税费
|
|
583
|
+
* @description:
|
|
584
|
+
* 单个商品的税费 = 商品销售单价(折扣后) * 税率 * is_charge_tax /( 1+ 税率 * is_price_include_tax)
|
|
585
|
+
* $taxFee = $price * $taxRate * $isChargeTax / (1 + $taxRate * $isPriceIncludeTax);
|
|
586
|
+
* @return {*}
|
|
587
|
+
* @Author: xiangfeng.xue
|
|
588
|
+
*/
|
|
589
|
+
exports.calculateOriginSubtotal = calculateOriginSubtotal;
|
|
590
|
+
const calculateTaxFee = (shopInfo, items) => {
|
|
591
|
+
if (!items?.length) {
|
|
592
|
+
return '0.00';
|
|
380
593
|
}
|
|
381
|
-
const {
|
|
594
|
+
const {
|
|
595
|
+
is_price_include_tax,
|
|
596
|
+
tax_rate
|
|
597
|
+
} = shopInfo || {};
|
|
382
598
|
const totalTaxFee = items.reduce((sum, item) => {
|
|
383
|
-
const cartItemTotalPrice = new
|
|
384
|
-
const taxRate = new
|
|
385
|
-
const productTaxRate = cartItemTotalPrice.times(taxRate).times(
|
|
599
|
+
const cartItemTotalPrice = new _decimal.default(item.summaryTotal || 0);
|
|
600
|
+
const taxRate = new _decimal.default(tax_rate || 0).div(100);
|
|
601
|
+
const productTaxRate = cartItemTotalPrice.times(taxRate).times(item?.is_charge_tax || 0).div(taxRate.times(is_price_include_tax || 0).plus(1));
|
|
386
602
|
return sum.plus(productTaxRate);
|
|
387
|
-
}, new
|
|
603
|
+
}, new _decimal.default(0));
|
|
388
604
|
return totalTaxFee;
|
|
389
605
|
};
|
|
390
|
-
|
|
391
|
-
|
|
606
|
+
exports.calculateTaxFee = calculateTaxFee;
|
|
607
|
+
const getCartItemDepositData = item => {
|
|
392
608
|
const target = item;
|
|
393
|
-
return
|
|
609
|
+
return target?._productOrigin?.custom_deposit_data || target?._origin?.custom_deposit_data || target?._origin?.product?.custom_deposit_data;
|
|
394
610
|
};
|
|
395
|
-
|
|
396
|
-
return new
|
|
611
|
+
const getCartItemQuantity = item => {
|
|
612
|
+
return new _decimal.default(item?.num || 1);
|
|
397
613
|
};
|
|
398
|
-
|
|
399
|
-
var _a;
|
|
614
|
+
const calculateCartItemDepositTotal = item => {
|
|
400
615
|
const depositData = getCartItemDepositData(item);
|
|
401
|
-
if (
|
|
402
|
-
const lineTotal = new
|
|
616
|
+
if (depositData?.has_deposit == 1 && typeof depositData?.deposit_fixed === 'string' && typeof depositData?.deposit_percentage === 'string') {
|
|
617
|
+
const lineTotal = new _decimal.default(item.summaryTotal ?? item.total ?? 0);
|
|
403
618
|
const quantity = getCartItemQuantity(item);
|
|
404
|
-
const fixedTotal = new
|
|
405
|
-
const percentageTotal = new
|
|
619
|
+
const fixedTotal = new _decimal.default(depositData.deposit_fixed || 0).times(quantity);
|
|
620
|
+
const percentageTotal = new _decimal.default(depositData.deposit_percentage || 0).times(lineTotal);
|
|
406
621
|
return fixedTotal.plus(percentageTotal);
|
|
407
622
|
}
|
|
408
|
-
return new
|
|
623
|
+
return new _decimal.default(item?.deposit?.total || 0);
|
|
409
624
|
};
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* @title: 计算定金
|
|
628
|
+
* @param items - 购物车商品数组
|
|
629
|
+
* @returns 定金字符串,保留2位小数
|
|
630
|
+
*/
|
|
631
|
+
const calculateDeposit = items => {
|
|
632
|
+
if (!items?.length) {
|
|
633
|
+
return undefined;
|
|
413
634
|
}
|
|
414
635
|
const protocols = [];
|
|
415
636
|
let hasDeposit = false;
|
|
416
637
|
const total = items.reduce((sum, item) => {
|
|
417
|
-
|
|
418
|
-
if (item == null ? void 0 : item.deposit) {
|
|
638
|
+
if (item?.deposit) {
|
|
419
639
|
hasDeposit = true;
|
|
420
640
|
const cartItemTotalPrice = calculateCartItemDepositTotal(item);
|
|
421
|
-
|
|
422
|
-
|
|
641
|
+
// 将协议数据去重合并
|
|
642
|
+
item?.deposit?.protocols?.forEach(protocol => {
|
|
643
|
+
if (protocols.findIndex(p => p.id === protocol.id) === -1) {
|
|
423
644
|
protocols.push(protocol);
|
|
424
645
|
}
|
|
425
646
|
});
|
|
426
647
|
return sum.plus(cartItemTotalPrice);
|
|
427
648
|
}
|
|
428
649
|
return sum;
|
|
429
|
-
}, new
|
|
650
|
+
}, new _decimal.default(0));
|
|
430
651
|
if (hasDeposit) {
|
|
431
|
-
return {
|
|
652
|
+
return {
|
|
653
|
+
total: total.toFixed(2),
|
|
654
|
+
protocols,
|
|
655
|
+
hasDeposit
|
|
656
|
+
};
|
|
432
657
|
}
|
|
433
|
-
return
|
|
658
|
+
return undefined;
|
|
434
659
|
};
|
|
435
|
-
|
|
436
|
-
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* 计算订单附加费金额(订单级别合计)。
|
|
663
|
+
*
|
|
664
|
+
* - **详情未编辑**(`!options.isEdit && bookingId`)且存在后端详情时:直接返回 `bookingDetail.surcharge_fee`
|
|
665
|
+
* - **新增/编辑**时:对 `surcharge`(通常为 `getSurcharge` 的返回值)按 `item.value` 求和
|
|
666
|
+
*
|
|
667
|
+
* @param params 入参集合(RORO)
|
|
668
|
+
* @param params.bookingDetail 订单详情(详情未编辑时用于读取后端的 `surcharge_fee`),可选
|
|
669
|
+
* @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选
|
|
670
|
+
* @param surcharge 附加费列表(通常来自 `getSurcharge`),元素结构至少包含 `value: number`
|
|
671
|
+
* @param options 计算选项
|
|
672
|
+
* @param options.isEdit 是否处于“编辑中”。`false` 时会优先走后端金额直取逻辑(若存在)
|
|
673
|
+
* @returns 订单附加费金额(number,金额单位与商品价格一致)
|
|
674
|
+
*/
|
|
675
|
+
exports.calculateDeposit = calculateDeposit;
|
|
676
|
+
const getSurchargeAmount = ({
|
|
677
|
+
bookingDetail,
|
|
678
|
+
bookingId
|
|
679
|
+
}, surcharge, options) => {
|
|
680
|
+
const {
|
|
681
|
+
isEdit
|
|
682
|
+
} = options;
|
|
683
|
+
// 订单未变更过
|
|
437
684
|
if (!isEdit) {
|
|
685
|
+
// 有后端数据则直接使用后端的数据
|
|
438
686
|
if (bookingDetail && bookingId) {
|
|
439
687
|
return Number(bookingDetail.surcharge_fee);
|
|
440
688
|
}
|
|
441
689
|
}
|
|
442
|
-
if (!Array.isArray(surcharge))
|
|
443
|
-
|
|
690
|
+
if (!Array.isArray(surcharge)) return 0;
|
|
691
|
+
// 新增状态使用 getSurcharge 的返回值进行求和
|
|
444
692
|
return surcharge.reduce((total, item) => {
|
|
445
693
|
return total.plus(item.value || 0);
|
|
446
|
-
}, new
|
|
694
|
+
}, new _decimal.default(0)).toNumber();
|
|
447
695
|
};
|
|
448
|
-
|
|
449
|
-
|
|
696
|
+
|
|
697
|
+
// bundle商品是否是原价
|
|
698
|
+
exports.getSurchargeAmount = getSurchargeAmount;
|
|
699
|
+
const getBundleItemIsOriginalPrice = item => {
|
|
700
|
+
return item?.price_type === 'markup' && item?.price_type_ext === 'product_price';
|
|
450
701
|
};
|
|
451
|
-
|
|
452
|
-
|
|
702
|
+
|
|
703
|
+
// bundle商品是否是加价
|
|
704
|
+
const getBundleItemIsMarkupPrice = item => {
|
|
705
|
+
return item?.price_type === 'markup' && (item?.price_type_ext === '' || !item?.price_type_ext);
|
|
453
706
|
};
|
|
454
|
-
|
|
455
|
-
|
|
707
|
+
|
|
708
|
+
// bundle商品是否是减价
|
|
709
|
+
const getBundleItemIsDiscountPrice = item => {
|
|
710
|
+
return item?.price_type === 'markdown' && (item?.price_type_ext === '' || !item?.price_type_ext);
|
|
456
711
|
};
|
|
457
|
-
|
|
712
|
+
|
|
713
|
+
// bundle商品是否是加价或减价
|
|
714
|
+
const getBundleItemIsMarkupOrDiscountPrice = item => {
|
|
458
715
|
return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item);
|
|
459
716
|
};
|
|
460
|
-
|
|
717
|
+
const getDiscountAmount = discounts => {
|
|
461
718
|
return (discounts || []).reduce((total, discount) => {
|
|
462
|
-
return total.add(new
|
|
463
|
-
}, new
|
|
719
|
+
return total.add(new _decimal.default(discount.amount || 0));
|
|
720
|
+
}, new _decimal.default(0)).toNumber();
|
|
464
721
|
};
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* 获取主商品加价减价后的总价 (主商品价格 + 子商品加价减价)
|
|
725
|
+
*/
|
|
726
|
+
const getMainProductTotal = item => {
|
|
727
|
+
// 新语义 v2 下 `main_product_selling_price` / `metadata.main_product_selling_price`
|
|
728
|
+
// 已经是"含 option、含主商品折扣"的主价,直接作为主商品基准,无需再减折扣或加 option。
|
|
729
|
+
// 仅需叠加 markup / markdown 类 bundle(原价 bundle 的税费单独处理)。
|
|
730
|
+
let total = new _decimal.default(item?.main_product_selling_price ?? item?.metadata?.main_product_selling_price ?? item?.metadata?.main_product_original_price ?? 0);
|
|
731
|
+
|
|
732
|
+
// 做个兜底 如果新语义价格字段都没有,则切换回老逻辑
|
|
733
|
+
const hasMainProductPrice = item?.main_product_selling_price != null || item?.metadata?.main_product_selling_price != null || item?.metadata?.main_product_original_price != null;
|
|
471
734
|
if (!hasMainProductPrice) {
|
|
472
|
-
total = new
|
|
473
|
-
const discount =
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
})) || [];
|
|
735
|
+
total = new _decimal.default(item?.main_product_selling_price ?? item?.metadata?.main_product_selling_price ?? item.price ?? 0);
|
|
736
|
+
const discount = item?._origin?.product?.discount_list || item?._originData?.product?.discount_list?.filter(item => {
|
|
737
|
+
return !item?.metadata?.custom_product_bundle_map_id;
|
|
738
|
+
}) || [];
|
|
477
739
|
const mainProductDiscountAmount = getDiscountAmount(discount);
|
|
478
740
|
total = total.minus(mainProductDiscountAmount);
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
741
|
+
|
|
742
|
+
// 单规格
|
|
743
|
+
if (item?.option && Array.isArray(item?.option)) {
|
|
744
|
+
total = total.add(item?.option.reduce((t, option) => {
|
|
745
|
+
return t.add(new _decimal.default(option.price || 0).mul(option.num || 1));
|
|
746
|
+
}, new _decimal.default(0)));
|
|
483
747
|
}
|
|
484
748
|
}
|
|
485
|
-
for (let bundleItem of
|
|
749
|
+
for (let bundleItem of item?.bundle || []) {
|
|
486
750
|
if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
|
|
487
|
-
|
|
751
|
+
// IMPORTANT: 套餐子商品如果应用了 discount,bundle_selling_price 和 price 其实都已经是折后价格了,不需要单独再减一次
|
|
752
|
+
const bundleItemTotal = new _decimal.default(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
488
753
|
total = total.add(bundleItemTotal);
|
|
489
754
|
}
|
|
490
755
|
}
|
|
491
756
|
return total.toNumber();
|
|
492
757
|
};
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
758
|
+
/**
|
|
759
|
+
* 判断商品是否符合附加费条件
|
|
760
|
+
*/
|
|
761
|
+
const isProductMatchSurchargeCondition = (item, options) => {
|
|
762
|
+
const isInScheduleByDate = options?.isInScheduleByDate;
|
|
763
|
+
const {
|
|
764
|
+
surchargeConfig,
|
|
765
|
+
scheduleById = {}
|
|
766
|
+
} = options;
|
|
767
|
+
const {
|
|
768
|
+
startDate,
|
|
769
|
+
product_id,
|
|
770
|
+
isCustomItem
|
|
771
|
+
} = item;
|
|
497
772
|
const {
|
|
498
773
|
open_product = 0,
|
|
499
774
|
// 1 | 0
|
|
@@ -507,35 +782,50 @@ var isProductMatchSurchargeCondition = (item, options) => {
|
|
|
507
782
|
// custom | all(所有日程)
|
|
508
783
|
available_schedule_ids = []
|
|
509
784
|
} = surchargeConfig;
|
|
785
|
+
|
|
786
|
+
// 判断商品是否符合条件
|
|
510
787
|
let isProductMatch = false;
|
|
511
788
|
if (open_product === 0) {
|
|
789
|
+
// 未开启商品限制,所有商品都符合
|
|
512
790
|
isProductMatch = true;
|
|
513
791
|
} else {
|
|
792
|
+
// 开启了商品限制
|
|
514
793
|
if (is_all === 1) {
|
|
794
|
+
// 所有商品都收取附加费
|
|
515
795
|
isProductMatch = true;
|
|
516
796
|
} else {
|
|
797
|
+
// 指定商品收取附加费
|
|
517
798
|
if (isCustomItem) {
|
|
799
|
+
// 自定义商品:如果是指定商品模式,自定义商品不符合条件
|
|
800
|
+
// 因为自定义商品没有 product_id,无法匹配到指定商品列表
|
|
518
801
|
isProductMatch = false;
|
|
519
802
|
} else {
|
|
803
|
+
// 普通商品:检查是否在指定商品列表中
|
|
520
804
|
isProductMatch = available_product_ids.includes(product_id);
|
|
521
805
|
}
|
|
522
806
|
}
|
|
523
807
|
}
|
|
808
|
+
|
|
809
|
+
// 判断日程是否符合条件
|
|
524
810
|
let isScheduleMatch = false;
|
|
525
811
|
if (open_schedule === 0) {
|
|
812
|
+
// 未开启日程限制,所有日程都符合
|
|
526
813
|
isScheduleMatch = true;
|
|
527
814
|
} else {
|
|
528
|
-
|
|
815
|
+
// 开启了日程限制
|
|
816
|
+
if (schedule_type === 'all') {
|
|
817
|
+
// 所有日程都收取附加费
|
|
529
818
|
isScheduleMatch = true;
|
|
530
819
|
} else {
|
|
820
|
+
// 指定日程收取附加费
|
|
531
821
|
for (let j = 0; j < available_schedule_ids.length; j++) {
|
|
532
822
|
const scheduleId = available_schedule_ids[j];
|
|
533
823
|
const schedule = scheduleById[scheduleId];
|
|
534
824
|
if (schedule) {
|
|
535
825
|
const isInSchedule = isInScheduleByDate({
|
|
536
826
|
// date: startDate?.format('YYYY-MM-DD HH:mm:ss') || '',
|
|
537
|
-
date: startDate ||
|
|
538
|
-
schedule
|
|
827
|
+
date: startDate || '',
|
|
828
|
+
schedule: schedule
|
|
539
829
|
});
|
|
540
830
|
if (isInSchedule) {
|
|
541
831
|
isScheduleMatch = true;
|
|
@@ -545,195 +835,264 @@ var isProductMatchSurchargeCondition = (item, options) => {
|
|
|
545
835
|
}
|
|
546
836
|
}
|
|
547
837
|
}
|
|
838
|
+
|
|
839
|
+
// 商品和日程条件都要满足(取交集)
|
|
548
840
|
return isProductMatch && isScheduleMatch;
|
|
549
841
|
};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* 订单附加费各项信息
|
|
845
|
+
*
|
|
846
|
+
* - **详情未编辑**(`!options.isEdit && bookingId`)时:直接返回 `bookingDetail.surcharge`(后端计算结果)
|
|
847
|
+
* - **新增/编辑**时:按 `options.surcharge_list` 逐条配置计算本次订单的附加费
|
|
848
|
+
*
|
|
849
|
+
* 规则要点:
|
|
850
|
+
* - 匹配范围包含:主商品(`service`)、原价 bundle 子商品(`item.bundle`)、加时商品(`item.relation_details`)、以及 addons(`addons.value`)
|
|
851
|
+
* - 固定附加费 `fixed`:只加一次,再按商品数量分摊(向下取整保留两位),剩余小数会以 `surcharge_rounding_remainder` 形式抹平到最后一个商品
|
|
852
|
+
* - 百分比附加费 `percentage`:按每个商品(价格 * 数量)分别计算再累加
|
|
853
|
+
* - 当 `open_product === 0`:不回写到商品,只在订单级别累加;否则会把单品附加费回写到商品
|
|
854
|
+
*
|
|
855
|
+
* **副作用(可能修改入参商品对象)**:
|
|
856
|
+
* - 当 `open_product !== 0` 时:写入 `item.surcharge_fee`(单品单数量附加费,保留两位、向下取整)
|
|
857
|
+
* - 写入 `item.relation_surcharge_ids`(关联到的 surcharge 配置 id 列表)
|
|
858
|
+
* - 写入 `item.surcharge_rounding_remainder`(用于抹平固定附加费/总额舍入差)
|
|
859
|
+
*
|
|
860
|
+
* @param params 入参集合(RORO)
|
|
861
|
+
* @param params.service 服务商品数组(主商品)。元素可能包含 `bundle` / `relation_details`
|
|
862
|
+
* @param params.addons 附加商品容器。当前实现读取 `addons.value` 作为商品数组(所以通常传 `{ value: CartItem[] }`)
|
|
863
|
+
* @param params.bookingDetail 订单详情(详情未编辑时用于直接取后端的 surcharge 列表),可选
|
|
864
|
+
* @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选
|
|
865
|
+
* @param options 计算选项
|
|
866
|
+
* @param options.isEdit 是否处于“编辑中”。`false` 且存在 `bookingId` 时会走详情直取逻辑
|
|
867
|
+
* @param options.surcharge_list 附加费配置列表(后端下发)。缺失/为空则返回空数组
|
|
868
|
+
* @param options.isInScheduleByDate 判断日期是否落在某个 schedule 内的方法(通常来自 ScheduleModule)
|
|
869
|
+
* @param options.scheduleById schedule 映射表:`{ [scheduleId]: schedule }`(用于根据配置的 `available_schedule_ids` 做日程匹配)
|
|
870
|
+
* @returns 附加费列表(仅返回金额 > 0 的项)
|
|
871
|
+
*/
|
|
872
|
+
const getSurcharge = ({
|
|
873
|
+
service,
|
|
874
|
+
addons,
|
|
875
|
+
bookingDetail,
|
|
876
|
+
bookingId
|
|
877
|
+
}, options) => {
|
|
878
|
+
const {
|
|
879
|
+
isEdit,
|
|
880
|
+
isInScheduleByDate,
|
|
881
|
+
surcharge_list,
|
|
882
|
+
scheduleById
|
|
883
|
+
} = options;
|
|
884
|
+
// 在所有商品里试着找 start_date,如果没有则用当前时间
|
|
885
|
+
const firstAppointmentCartItem = service.filter(n => !(0, _utils.isNormalProduct)(n._productOrigin))?.[0];
|
|
886
|
+
let startDate = '';
|
|
557
887
|
if (firstAppointmentCartItem) {
|
|
558
|
-
startDate = firstAppointmentCartItem.start_date +
|
|
888
|
+
startDate = firstAppointmentCartItem.start_date + ' ' + firstAppointmentCartItem.start_time + ':00';
|
|
559
889
|
} else {
|
|
560
|
-
startDate = (0,
|
|
890
|
+
startDate = (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss');
|
|
561
891
|
}
|
|
892
|
+
// 编辑状态, 且未修改商品时直接从详情取出
|
|
562
893
|
if (!isEdit && bookingId) {
|
|
563
|
-
if (Array.isArray(bookingDetail
|
|
564
|
-
return (
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
}
|
|
584
|
-
);
|
|
894
|
+
if (Array.isArray(bookingDetail?.surcharge)) {
|
|
895
|
+
return (bookingDetail?.surcharge || []).filter(d => Number(d.amount) > 0).map((d, index) => {
|
|
896
|
+
return {
|
|
897
|
+
key: `custom_surcharge_${index}`,
|
|
898
|
+
// label:
|
|
899
|
+
// d.name[state.locale || 'en'] ||
|
|
900
|
+
// d.name['en'] ||
|
|
901
|
+
// d.name['original'],
|
|
902
|
+
label: d.name,
|
|
903
|
+
value: d.amount,
|
|
904
|
+
name: d.name,
|
|
905
|
+
surcharge_id: d.id,
|
|
906
|
+
description: d.description,
|
|
907
|
+
// 后端说这个固定传 default
|
|
908
|
+
type: 'default',
|
|
909
|
+
fixed: d.fixed,
|
|
910
|
+
amount: d.amount,
|
|
911
|
+
percentage: d.percentage
|
|
912
|
+
};
|
|
913
|
+
});
|
|
585
914
|
}
|
|
586
915
|
return [];
|
|
587
916
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
917
|
+
|
|
918
|
+
// 用于“计算总价”的场景:每次调用都应重新计算(避免重复调用导致 surcharge_fee 累加)
|
|
919
|
+
// 注意:同一次调用内仍会在多条 surcharge 配置之间累加
|
|
920
|
+
resetItemsSurchargeSideEffects({
|
|
921
|
+
service,
|
|
922
|
+
addons
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
// 无附加费规则
|
|
926
|
+
if (!Array.isArray(surcharge_list) || !surcharge_list?.length) return [];
|
|
927
|
+
|
|
928
|
+
// 分别计算每种附加费总和
|
|
591
929
|
const surchargeWithAmount = [];
|
|
930
|
+
|
|
931
|
+
// 遍历每种附加费配置
|
|
592
932
|
for (let i = 0; i < surcharge_list.length; i++) {
|
|
593
933
|
const surchargeConfig = surcharge_list[i];
|
|
594
934
|
const {
|
|
595
|
-
percentage =
|
|
596
|
-
fixed =
|
|
935
|
+
percentage = '0',
|
|
936
|
+
fixed = '0',
|
|
597
937
|
id,
|
|
598
938
|
type,
|
|
599
939
|
description,
|
|
600
940
|
open_product
|
|
601
941
|
} = surchargeConfig;
|
|
942
|
+
|
|
943
|
+
// 收集所有符合条件的商品
|
|
602
944
|
const matchedItems = [];
|
|
945
|
+
|
|
946
|
+
// 检查service中符合条件的商品
|
|
603
947
|
if (Array.isArray(service)) {
|
|
604
948
|
for (let item of service) {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
)) {
|
|
949
|
+
// 主商品符合附加费条件
|
|
950
|
+
if (isProductMatchSurchargeCondition({
|
|
951
|
+
isCustomItem: item.isCustomItem,
|
|
952
|
+
startDate,
|
|
953
|
+
product_id: item.id
|
|
954
|
+
}, {
|
|
955
|
+
surchargeConfig,
|
|
956
|
+
scheduleById: scheduleById || {},
|
|
957
|
+
isInScheduleByDate: isInScheduleByDate
|
|
958
|
+
})) {
|
|
959
|
+
// 主商品加价减价后的总价
|
|
617
960
|
const total = getMainProductTotal({
|
|
618
961
|
...item,
|
|
619
|
-
option:
|
|
620
|
-
bundle:
|
|
962
|
+
option: item?.option || item?.options || [],
|
|
963
|
+
bundle: item?.bundle || item?.bundles || []
|
|
621
964
|
});
|
|
622
965
|
const mainQuantity = item.num || 1;
|
|
623
966
|
matchedItems.push({
|
|
624
|
-
total,
|
|
967
|
+
total: total,
|
|
625
968
|
// addTimeTotal: getRelationDetailsTotal(
|
|
626
969
|
// item._extend.relation_details || []
|
|
627
970
|
// ),
|
|
628
971
|
isMain: true,
|
|
629
972
|
quantity: mainQuantity,
|
|
630
973
|
item,
|
|
631
|
-
mainQuantity
|
|
632
|
-
// 主商品的mainQuantity等于自己的quantity
|
|
974
|
+
mainQuantity: mainQuantity // 主商品的mainQuantity等于自己的quantity
|
|
633
975
|
});
|
|
634
976
|
}
|
|
635
|
-
const arr =
|
|
977
|
+
const arr = item?.bundle || item?.bundles || [];
|
|
978
|
+
// 遍历子商品 原价商品符合附加费条件
|
|
636
979
|
for (let bundleItem of arr) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
)) {
|
|
980
|
+
// bundle商品是原价且符合附加费条件
|
|
981
|
+
if (getBundleItemIsOriginalPrice(bundleItem) && isProductMatchSurchargeCondition({
|
|
982
|
+
isCustomItem: false,
|
|
983
|
+
startDate,
|
|
984
|
+
product_id: bundleItem._bundle_product_id
|
|
985
|
+
}, {
|
|
986
|
+
surchargeConfig,
|
|
987
|
+
scheduleById: scheduleById || {},
|
|
988
|
+
isInScheduleByDate: isInScheduleByDate
|
|
989
|
+
})) {
|
|
649
990
|
const mainQuantity = item.num || 1;
|
|
650
991
|
matchedItems.push({
|
|
651
992
|
isMain: false,
|
|
652
|
-
total: Number(
|
|
653
|
-
bundleItem.bundle_selling_price ?? bundleItem.price ?? 0
|
|
654
|
-
),
|
|
993
|
+
total: Number(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0),
|
|
655
994
|
quantity: bundleItem.num || bundleItem.quantity || 1,
|
|
656
995
|
item: bundleItem,
|
|
657
|
-
mainQuantity
|
|
658
|
-
// 子商品的mainQuantity是所属主商品的quantity
|
|
996
|
+
mainQuantity: mainQuantity // 子商品的mainQuantity是所属主商品的quantity
|
|
659
997
|
});
|
|
660
998
|
}
|
|
661
999
|
}
|
|
1000
|
+
|
|
1001
|
+
// 加时商品符合附加费条件
|
|
662
1002
|
for (let relationDetail of item.relation_details || []) {
|
|
663
|
-
if (isProductMatchSurchargeCondition(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
{
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
isInScheduleByDate
|
|
673
|
-
}
|
|
674
|
-
)) {
|
|
1003
|
+
if (isProductMatchSurchargeCondition({
|
|
1004
|
+
isCustomItem: false,
|
|
1005
|
+
startDate,
|
|
1006
|
+
product_id: relationDetail.product_id
|
|
1007
|
+
}, {
|
|
1008
|
+
surchargeConfig,
|
|
1009
|
+
scheduleById: scheduleById || {},
|
|
1010
|
+
isInScheduleByDate: isInScheduleByDate
|
|
1011
|
+
})) {
|
|
675
1012
|
matchedItems.push({
|
|
676
1013
|
isMain: false,
|
|
677
|
-
total: Number(
|
|
678
|
-
(relationDetail == null ? void 0 : relationDetail.price) || ((_b = relationDetail == null ? void 0 : relationDetail.metadata) == null ? void 0 : _b.main_product_attached_bundle_selling_price)
|
|
679
|
-
),
|
|
1014
|
+
total: Number(relationDetail?.price || relationDetail?.metadata?.main_product_attached_bundle_selling_price),
|
|
680
1015
|
quantity: relationDetail.num || relationDetail.quantity || 1,
|
|
681
1016
|
item: relationDetail,
|
|
682
|
-
mainQuantity: 1
|
|
683
|
-
// 加时商品不受主商品数量影响
|
|
1017
|
+
mainQuantity: 1 // 加时商品不受主商品数量影响
|
|
684
1018
|
});
|
|
685
1019
|
}
|
|
686
1020
|
}
|
|
687
1021
|
}
|
|
688
1022
|
}
|
|
689
|
-
|
|
1023
|
+
|
|
1024
|
+
// 检查addons中符合条件的商品
|
|
1025
|
+
if (Array.isArray(addons?.value)) {
|
|
690
1026
|
for (let item of addons.value) {
|
|
691
|
-
if (isProductMatchSurchargeCondition({
|
|
1027
|
+
if (isProductMatchSurchargeCondition({
|
|
1028
|
+
...item,
|
|
1029
|
+
startDate
|
|
1030
|
+
}, {
|
|
692
1031
|
surchargeConfig,
|
|
693
1032
|
scheduleById: scheduleById || {},
|
|
694
|
-
isInScheduleByDate
|
|
1033
|
+
isInScheduleByDate: isInScheduleByDate
|
|
695
1034
|
})) {
|
|
696
1035
|
matchedItems.push({
|
|
697
1036
|
isMain: true,
|
|
698
1037
|
total: Number(item.total),
|
|
699
1038
|
quantity: item.num || 1,
|
|
700
|
-
item,
|
|
701
|
-
mainQuantity: 1
|
|
702
|
-
// addons独立商品,mainQuantity为1
|
|
1039
|
+
item: item,
|
|
1040
|
+
mainQuantity: 1 // addons独立商品,mainQuantity为1
|
|
703
1041
|
});
|
|
704
1042
|
}
|
|
705
1043
|
}
|
|
706
1044
|
}
|
|
707
1045
|
let finalAmount = 0;
|
|
1046
|
+
|
|
1047
|
+
// 计算商品总数:主商品和addons按quantity计算,子商品(bundle item)需要乘以主商品数量
|
|
708
1048
|
const productCount = matchedItems.reduce((total, item) => {
|
|
709
1049
|
if (item.isMain) {
|
|
1050
|
+
// 主商品和addons商品
|
|
710
1051
|
return total + (item.num || item.quantity || 1);
|
|
711
1052
|
} else {
|
|
1053
|
+
// 子商品(bundle item)和加时商品
|
|
1054
|
+
// 加时商品的 mainQuantity = 1,所以不受影响
|
|
1055
|
+
// bundle item 的 mainQuantity = 主商品数量,需要乘以实际数量
|
|
712
1056
|
return total + (item.num || item.quantity || 1) * (item.mainQuantity || 1);
|
|
713
1057
|
}
|
|
714
1058
|
}, 0);
|
|
715
|
-
|
|
716
|
-
|
|
1059
|
+
|
|
1060
|
+
// 追加进入的固定附加费总值
|
|
1061
|
+
let fixedTotal = new _decimal.default(0);
|
|
1062
|
+
// 追加到商品的附加费总值 用于追加抹平字段
|
|
1063
|
+
let productTotalSurcharge = new _decimal.default(0);
|
|
717
1064
|
if (matchedItems.length > 0) {
|
|
718
|
-
|
|
719
|
-
|
|
1065
|
+
// 基于每个商品计算附加费:max(0, 商品价格) * rate + fixed
|
|
1066
|
+
let configTotal = new _decimal.default(0);
|
|
1067
|
+
|
|
1068
|
+
// 计算固定附加费 - 只加一次
|
|
1069
|
+
if (fixed && new _decimal.default(fixed).gt(0)) {
|
|
720
1070
|
configTotal = configTotal.plus(fixed);
|
|
721
1071
|
}
|
|
722
|
-
|
|
723
|
-
|
|
1072
|
+
|
|
1073
|
+
// 计算百分比附加费 - 对每个商品单独计算
|
|
1074
|
+
if (percentage && new _decimal.default(percentage).gt(0) || fixed) {
|
|
1075
|
+
const percentageRate = new _decimal.default(percentage);
|
|
724
1076
|
for (let [index, item] of matchedItems.entries()) {
|
|
725
1077
|
const isLast = index === matchedItems.length - 1;
|
|
726
|
-
|
|
727
|
-
const
|
|
728
|
-
const
|
|
1078
|
+
// 对每个商品:max(0, 价格) * 数量 * 费率
|
|
1079
|
+
const itemPrice = new _decimal.default(Math.max(0, item.total || 0));
|
|
1080
|
+
const itemQuantity = new _decimal.default(item.isMain ? item.quantity || 1 : item.quantity * item.mainQuantity || 1);
|
|
1081
|
+
const addTimeTotal = new _decimal.default(item.addTimeTotal || 0);
|
|
1082
|
+
// 单个商品总附加费
|
|
729
1083
|
const itemTotalSurcharge = itemPrice.times(itemQuantity).plus(addTimeTotal).times(percentageRate);
|
|
730
1084
|
configTotal = configTotal.plus(itemTotalSurcharge);
|
|
1085
|
+
|
|
1086
|
+
// 单个商品单数量附加费
|
|
731
1087
|
const itemSurcharge = itemPrice.times(percentageRate);
|
|
732
|
-
|
|
1088
|
+
|
|
1089
|
+
// 固定附加费 = 1 / 商品数量 * 固定附加费(向下取整保留两位小数)
|
|
1090
|
+
const fixedSurcharge = new _decimal.default(1).div(productCount).times(fixed).times(100).floor().div(100).toFixed(2);
|
|
733
1091
|
const quantity = item.isMain ? item.quantity : item.quantity * item.mainQuantity;
|
|
734
|
-
fixedTotal = fixedTotal.plus(new
|
|
1092
|
+
fixedTotal = fixedTotal.plus(new _decimal.default(fixedSurcharge).times(quantity).toNumber());
|
|
1093
|
+
// 如果是最后一个商品 判断fixed - fixedTotal 是否有剩余小数 如果有的话,追加抹平字段
|
|
735
1094
|
if (isLast && fixedTotal.gt(0)) {
|
|
736
|
-
const remaining = new
|
|
1095
|
+
const remaining = new _decimal.default(fixed).minus(fixedTotal).toNumber();
|
|
737
1096
|
if (remaining > 0) {
|
|
738
1097
|
productTotalSurcharge = productTotalSurcharge.plus(remaining);
|
|
739
1098
|
if (item.isMain) {
|
|
@@ -743,36 +1102,44 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
743
1102
|
}
|
|
744
1103
|
}
|
|
745
1104
|
}
|
|
1105
|
+
// 只有当 open_product !== 0 时,才将附加费追加到商品身上
|
|
1106
|
+
// open_product === 0 表示商品未开启该附加费,只在订单级别累加
|
|
746
1107
|
if (open_product !== 0) {
|
|
747
1108
|
if (item.isMain) {
|
|
748
|
-
const originSurchargeFee = new
|
|
749
|
-
|
|
750
|
-
|
|
1109
|
+
const originSurchargeFee = new _decimal.default(item.item.surcharge_fee || 0);
|
|
1110
|
+
// 保留两位小数
|
|
1111
|
+
const surchargeFee = originSurchargeFee.plus(itemSurcharge).plus(fixedSurcharge).toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
|
|
1112
|
+
productTotalSurcharge = productTotalSurcharge.plus(new _decimal.default(surchargeFee).times(itemQuantity).toNumber());
|
|
751
1113
|
item.item.surcharge_fee = surchargeFee;
|
|
752
|
-
item.item.relation_surcharge_ids = [...(
|
|
1114
|
+
item.item.relation_surcharge_ids = [...(item.item?.relation_surcharge_ids || []), id];
|
|
753
1115
|
} else {
|
|
754
|
-
const originSurchargeFee = new
|
|
755
|
-
|
|
756
|
-
|
|
1116
|
+
const originSurchargeFee = new _decimal.default(item.item.surcharge_fee || 0);
|
|
1117
|
+
// 保留两位小数
|
|
1118
|
+
const surchargeFee = originSurchargeFee.plus(itemSurcharge).plus(fixedSurcharge).toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
|
|
1119
|
+
productTotalSurcharge = productTotalSurcharge.plus(new _decimal.default(surchargeFee).times(itemQuantity).toNumber());
|
|
757
1120
|
item.item.surcharge_fee = surchargeFee;
|
|
758
|
-
item.item.relation_surcharge_ids = [...(
|
|
1121
|
+
item.item.relation_surcharge_ids = [...(item.item?.relation_surcharge_ids || []), id];
|
|
759
1122
|
}
|
|
760
1123
|
}
|
|
1124
|
+
// 最后一个商品 判断configTotal - productTotalSurcharge 是否有剩余小数 如果有的话,追加抹平字段
|
|
761
1125
|
if (isLast && configTotal.minus(productTotalSurcharge).gt(0)) {
|
|
762
|
-
|
|
1126
|
+
// 四舍五入configTotal
|
|
1127
|
+
const configTotalRounded = configTotal.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
763
1128
|
if (item.isMain) {
|
|
764
|
-
let newRoundingRemainder = new
|
|
1129
|
+
let newRoundingRemainder = new _decimal.default(item.item.surcharge_rounding_remainder || 0);
|
|
765
1130
|
newRoundingRemainder = newRoundingRemainder.plus(configTotalRounded.minus(productTotalSurcharge));
|
|
766
1131
|
item.item.surcharge_rounding_remainder = newRoundingRemainder.toNumber();
|
|
767
1132
|
} else {
|
|
768
|
-
let newRoundingRemainder = new
|
|
1133
|
+
let newRoundingRemainder = new _decimal.default(item.item.surcharge_rounding_remainder || 0);
|
|
769
1134
|
newRoundingRemainder = newRoundingRemainder.plus(configTotalRounded.minus(productTotalSurcharge));
|
|
770
1135
|
item.item.surcharge_rounding_remainder = newRoundingRemainder.toNumber();
|
|
771
1136
|
}
|
|
772
1137
|
}
|
|
773
1138
|
}
|
|
774
1139
|
}
|
|
775
|
-
|
|
1140
|
+
|
|
1141
|
+
// 如果该配置有金额,则添加到结果中
|
|
1142
|
+
finalAmount = configTotal.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
776
1143
|
}
|
|
777
1144
|
const name = surchargeConfig.name || {};
|
|
778
1145
|
if (Number(finalAmount) <= 0) {
|
|
@@ -787,7 +1154,7 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
787
1154
|
surcharge_id: id,
|
|
788
1155
|
description,
|
|
789
1156
|
// 后端说固定传 default
|
|
790
|
-
type:
|
|
1157
|
+
type: 'default',
|
|
791
1158
|
fixed,
|
|
792
1159
|
amount: finalAmount,
|
|
793
1160
|
percentage,
|
|
@@ -798,10 +1165,13 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
798
1165
|
}
|
|
799
1166
|
return surchargeWithAmount;
|
|
800
1167
|
};
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1168
|
+
exports.getSurcharge = getSurcharge;
|
|
1169
|
+
function resetItemsSurchargeSideEffects({
|
|
1170
|
+
service,
|
|
1171
|
+
addons
|
|
1172
|
+
}) {
|
|
1173
|
+
const resetItem = item => {
|
|
1174
|
+
if (!item) return;
|
|
805
1175
|
item.surcharge_fee = 0;
|
|
806
1176
|
item.surcharge_rounding_remainder = 0;
|
|
807
1177
|
item.relation_surcharge_ids = [];
|
|
@@ -809,29 +1179,12 @@ function resetItemsSurchargeSideEffects({ service, addons }) {
|
|
|
809
1179
|
if (Array.isArray(service)) {
|
|
810
1180
|
for (let item of service) {
|
|
811
1181
|
resetItem(item);
|
|
812
|
-
const arr =
|
|
813
|
-
for (let bundleItem of arr)
|
|
814
|
-
|
|
815
|
-
for (let relationDetail of (item == null ? void 0 : item.relation_details) || [])
|
|
816
|
-
resetItem(relationDetail);
|
|
1182
|
+
const arr = item?.bundle || item?.bundles || [];
|
|
1183
|
+
for (let bundleItem of arr) resetItem(bundleItem);
|
|
1184
|
+
for (let relationDetail of item?.relation_details || []) resetItem(relationDetail);
|
|
817
1185
|
}
|
|
818
1186
|
}
|
|
819
|
-
if (Array.isArray(addons
|
|
820
|
-
for (let item of addons.value)
|
|
821
|
-
resetItem(item);
|
|
1187
|
+
if (Array.isArray(addons?.value)) {
|
|
1188
|
+
for (let item of addons.value) resetItem(item);
|
|
822
1189
|
}
|
|
823
|
-
}
|
|
824
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
825
|
-
0 && (module.exports = {
|
|
826
|
-
calcDiscountListDifference,
|
|
827
|
-
calculateDeposit,
|
|
828
|
-
calculateOriginSubtotal,
|
|
829
|
-
calculatePriceDetails,
|
|
830
|
-
calculateSubtotal,
|
|
831
|
-
calculateTaxFee,
|
|
832
|
-
getBundleDiscountList,
|
|
833
|
-
getProductDiscountProductDiscountDifference,
|
|
834
|
-
getSurcharge,
|
|
835
|
-
getSurchargeAmount,
|
|
836
|
-
getTax
|
|
837
|
-
});
|
|
1190
|
+
}
|