@pisell/pisellos 2.3.73 → 2.3.75
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.d.ts +7 -0
- package/dist/core/index.js +111 -71
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- 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 +2 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +36 -64
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/modules/Rules/index.js +1 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.d.ts +1 -0
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.d.ts +8 -2
- package/dist/server/index.js +303 -269
- package/dist/server/modules/floor-plan/index.d.ts +4 -0
- package/dist/server/modules/floor-plan/index.js +240 -98
- package/dist/server/modules/menu/index.js +75 -59
- package/dist/server/modules/order/index.d.ts +17 -7
- package/dist/server/modules/order/index.js +421 -211
- package/dist/server/modules/products/index.d.ts +8 -2
- package/dist/server/modules/products/index.js +191 -117
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +24 -17
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BaseSales/index.js +38 -41
- 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.js +0 -2
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -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 -252
- 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.js +45 -55
- 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.d.ts +7 -0
- package/lib/core/index.js +149 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- 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 +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +1 -0
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- 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 +588 -378
- 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 +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- 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 +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- 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 +122 -127
- 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 +70 -76
- 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 +1713 -2118
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils.js +814 -647
- 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 +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- 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 +113 -123
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +110 -103
- 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/ResourcePlanner/index.js +25 -23
- package/lib/modules/ResourcePlanner/localClock.js +54 -119
- package/lib/modules/ResourcePlanner/planner.js +589 -770
- package/lib/modules/ResourcePlanner/types.js +10 -29
- package/lib/modules/Rules/index.js +1218 -959
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +85 -90
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +355 -430
- 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 -163
- package/lib/modules/Schedule/index.js +100 -114
- 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 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.d.ts +1 -0
- 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.d.ts +8 -2
- package/lib/server/index.js +3083 -2663
- package/lib/server/modules/floor-plan/index.d.ts +4 -0
- package/lib/server/modules/floor-plan/index.js +159 -127
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +170 -124
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.d.ts +17 -7
- package/lib/server/modules/order/index.js +916 -977
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.d.ts +8 -2
- package/lib/server/modules/products/index.js +656 -471
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +225 -186
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- 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/small-ticket.js +479 -456
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.js +1186 -1410
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.js +642 -498
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
- package/lib/solution/BaseSales/utils.js +158 -143
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1527 -1340
- 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.js +607 -522
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- 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 +228 -156
- 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 +328 -324
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +832 -864
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +409 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
- package/lib/solution/UnifiedBookingSales/types.js +10 -32
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,479 +1,756 @@
|
|
|
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 : subOriginTotal.plus(totalTaxFee);
|
|
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
|
-
|
|
392
|
-
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* @title: 计算定金
|
|
609
|
+
* @param items - 购物车商品数组
|
|
610
|
+
* @returns 定金字符串,保留2位小数
|
|
611
|
+
*/
|
|
612
|
+
exports.calculateTaxFee = calculateTaxFee;
|
|
613
|
+
const calculateDeposit = items => {
|
|
614
|
+
if (!items?.length) {
|
|
615
|
+
return undefined;
|
|
393
616
|
}
|
|
394
617
|
const protocols = [];
|
|
395
618
|
let hasDeposit = false;
|
|
396
619
|
const total = items.reduce((sum, item) => {
|
|
397
|
-
|
|
398
|
-
if (item == null ? void 0 : item.deposit) {
|
|
620
|
+
if (item?.deposit) {
|
|
399
621
|
hasDeposit = true;
|
|
400
|
-
const cartItemTotalPrice = new
|
|
401
|
-
|
|
402
|
-
|
|
622
|
+
const cartItemTotalPrice = new _decimal.default(item?.deposit?.total || 0);
|
|
623
|
+
// 将协议数据去重合并
|
|
624
|
+
item?.deposit?.protocols?.forEach(protocol => {
|
|
625
|
+
if (protocols.findIndex(p => p.id === protocol.id) === -1) {
|
|
403
626
|
protocols.push(protocol);
|
|
404
627
|
}
|
|
405
628
|
});
|
|
406
629
|
return sum.plus(cartItemTotalPrice);
|
|
407
630
|
}
|
|
408
631
|
return sum;
|
|
409
|
-
}, new
|
|
632
|
+
}, new _decimal.default(0));
|
|
410
633
|
if (hasDeposit) {
|
|
411
|
-
return {
|
|
634
|
+
return {
|
|
635
|
+
total: total.toFixed(2),
|
|
636
|
+
protocols,
|
|
637
|
+
hasDeposit
|
|
638
|
+
};
|
|
412
639
|
}
|
|
413
|
-
return
|
|
640
|
+
return undefined;
|
|
414
641
|
};
|
|
415
|
-
|
|
416
|
-
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* 计算订单附加费金额(订单级别合计)。
|
|
645
|
+
*
|
|
646
|
+
* - **详情未编辑**(`!options.isEdit && bookingId`)且存在后端详情时:直接返回 `bookingDetail.surcharge_fee`
|
|
647
|
+
* - **新增/编辑**时:对 `surcharge`(通常为 `getSurcharge` 的返回值)按 `item.value` 求和
|
|
648
|
+
*
|
|
649
|
+
* @param params 入参集合(RORO)
|
|
650
|
+
* @param params.bookingDetail 订单详情(详情未编辑时用于读取后端的 `surcharge_fee`),可选
|
|
651
|
+
* @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选
|
|
652
|
+
* @param surcharge 附加费列表(通常来自 `getSurcharge`),元素结构至少包含 `value: number`
|
|
653
|
+
* @param options 计算选项
|
|
654
|
+
* @param options.isEdit 是否处于“编辑中”。`false` 时会优先走后端金额直取逻辑(若存在)
|
|
655
|
+
* @returns 订单附加费金额(number,金额单位与商品价格一致)
|
|
656
|
+
*/
|
|
657
|
+
exports.calculateDeposit = calculateDeposit;
|
|
658
|
+
const getSurchargeAmount = ({
|
|
659
|
+
bookingDetail,
|
|
660
|
+
bookingId
|
|
661
|
+
}, surcharge, options) => {
|
|
662
|
+
const {
|
|
663
|
+
isEdit
|
|
664
|
+
} = options;
|
|
665
|
+
// 订单未变更过
|
|
417
666
|
if (!isEdit) {
|
|
667
|
+
// 有后端数据则直接使用后端的数据
|
|
418
668
|
if (bookingDetail && bookingId) {
|
|
419
669
|
return Number(bookingDetail.surcharge_fee);
|
|
420
670
|
}
|
|
421
671
|
}
|
|
422
|
-
if (!Array.isArray(surcharge))
|
|
423
|
-
|
|
672
|
+
if (!Array.isArray(surcharge)) return 0;
|
|
673
|
+
// 新增状态使用 getSurcharge 的返回值进行求和
|
|
424
674
|
return surcharge.reduce((total, item) => {
|
|
425
675
|
return total.plus(item.value || 0);
|
|
426
|
-
}, new
|
|
676
|
+
}, new _decimal.default(0)).toNumber();
|
|
427
677
|
};
|
|
428
|
-
|
|
429
|
-
|
|
678
|
+
|
|
679
|
+
// bundle商品是否是原价
|
|
680
|
+
exports.getSurchargeAmount = getSurchargeAmount;
|
|
681
|
+
const getBundleItemIsOriginalPrice = item => {
|
|
682
|
+
return item?.price_type === 'markup' && item?.price_type_ext === 'product_price';
|
|
430
683
|
};
|
|
431
|
-
|
|
432
|
-
|
|
684
|
+
|
|
685
|
+
// bundle商品是否是加价
|
|
686
|
+
const getBundleItemIsMarkupPrice = item => {
|
|
687
|
+
return item?.price_type === 'markup' && (item?.price_type_ext === '' || !item?.price_type_ext);
|
|
433
688
|
};
|
|
434
|
-
|
|
435
|
-
|
|
689
|
+
|
|
690
|
+
// bundle商品是否是减价
|
|
691
|
+
const getBundleItemIsDiscountPrice = item => {
|
|
692
|
+
return item?.price_type === 'markdown' && (item?.price_type_ext === '' || !item?.price_type_ext);
|
|
436
693
|
};
|
|
437
|
-
|
|
694
|
+
|
|
695
|
+
// bundle商品是否是加价或减价
|
|
696
|
+
const getBundleItemIsMarkupOrDiscountPrice = item => {
|
|
438
697
|
return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item);
|
|
439
698
|
};
|
|
440
|
-
|
|
699
|
+
const getDiscountAmount = discounts => {
|
|
441
700
|
return (discounts || []).reduce((total, discount) => {
|
|
442
|
-
return total.add(new
|
|
443
|
-
}, new
|
|
701
|
+
return total.add(new _decimal.default(discount.amount || 0));
|
|
702
|
+
}, new _decimal.default(0)).toNumber();
|
|
444
703
|
};
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* 获取主商品加价减价后的总价 (主商品价格 + 子商品加价减价)
|
|
707
|
+
*/
|
|
708
|
+
const getMainProductTotal = item => {
|
|
709
|
+
// 新语义 v2 下 `main_product_selling_price` / `metadata.main_product_selling_price`
|
|
710
|
+
// 已经是"含 option、含主商品折扣"的主价,直接作为主商品基准,无需再减折扣或加 option。
|
|
711
|
+
// 仅需叠加 markup / markdown 类 bundle(原价 bundle 的税费单独处理)。
|
|
712
|
+
let total = new _decimal.default(item?.main_product_selling_price ?? item?.metadata?.main_product_selling_price ?? item?.metadata?.main_product_original_price ?? 0);
|
|
713
|
+
|
|
714
|
+
// 做个兜底 如果新语义价格字段都没有,则切换回老逻辑
|
|
715
|
+
const hasMainProductPrice = item?.main_product_selling_price != null || item?.metadata?.main_product_selling_price != null || item?.metadata?.main_product_original_price != null;
|
|
451
716
|
if (!hasMainProductPrice) {
|
|
452
|
-
total = new
|
|
453
|
-
const discount =
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
})) || [];
|
|
717
|
+
total = new _decimal.default(item?.main_product_selling_price ?? item?.metadata?.main_product_selling_price ?? item.price ?? 0);
|
|
718
|
+
const discount = item?._origin?.product?.discount_list || item?._originData?.product?.discount_list?.filter(item => {
|
|
719
|
+
return !item?.metadata?.custom_product_bundle_map_id;
|
|
720
|
+
}) || [];
|
|
457
721
|
const mainProductDiscountAmount = getDiscountAmount(discount);
|
|
458
722
|
total = total.minus(mainProductDiscountAmount);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
723
|
+
|
|
724
|
+
// 单规格
|
|
725
|
+
if (item?.option && Array.isArray(item?.option)) {
|
|
726
|
+
total = total.add(item?.option.reduce((t, option) => {
|
|
727
|
+
return t.add(new _decimal.default(option.price || 0).mul(option.num || 1));
|
|
728
|
+
}, new _decimal.default(0)));
|
|
463
729
|
}
|
|
464
730
|
}
|
|
465
|
-
for (let bundleItem of
|
|
731
|
+
for (let bundleItem of item?.bundle || []) {
|
|
466
732
|
if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
|
|
467
|
-
|
|
733
|
+
// IMPORTANT: 套餐子商品如果应用了 discount,bundle_selling_price 和 price 其实都已经是折后价格了,不需要单独再减一次
|
|
734
|
+
const bundleItemTotal = new _decimal.default(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
468
735
|
total = total.add(bundleItemTotal);
|
|
469
736
|
}
|
|
470
737
|
}
|
|
471
738
|
return total.toNumber();
|
|
472
739
|
};
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
740
|
+
/**
|
|
741
|
+
* 判断商品是否符合附加费条件
|
|
742
|
+
*/
|
|
743
|
+
const isProductMatchSurchargeCondition = (item, options) => {
|
|
744
|
+
const isInScheduleByDate = options?.isInScheduleByDate;
|
|
745
|
+
const {
|
|
746
|
+
surchargeConfig,
|
|
747
|
+
scheduleById = {}
|
|
748
|
+
} = options;
|
|
749
|
+
const {
|
|
750
|
+
startDate,
|
|
751
|
+
product_id,
|
|
752
|
+
isCustomItem
|
|
753
|
+
} = item;
|
|
477
754
|
const {
|
|
478
755
|
open_product = 0,
|
|
479
756
|
// 1 | 0
|
|
@@ -487,35 +764,50 @@ var isProductMatchSurchargeCondition = (item, options) => {
|
|
|
487
764
|
// custom | all(所有日程)
|
|
488
765
|
available_schedule_ids = []
|
|
489
766
|
} = surchargeConfig;
|
|
767
|
+
|
|
768
|
+
// 判断商品是否符合条件
|
|
490
769
|
let isProductMatch = false;
|
|
491
770
|
if (open_product === 0) {
|
|
771
|
+
// 未开启商品限制,所有商品都符合
|
|
492
772
|
isProductMatch = true;
|
|
493
773
|
} else {
|
|
774
|
+
// 开启了商品限制
|
|
494
775
|
if (is_all === 1) {
|
|
776
|
+
// 所有商品都收取附加费
|
|
495
777
|
isProductMatch = true;
|
|
496
778
|
} else {
|
|
779
|
+
// 指定商品收取附加费
|
|
497
780
|
if (isCustomItem) {
|
|
781
|
+
// 自定义商品:如果是指定商品模式,自定义商品不符合条件
|
|
782
|
+
// 因为自定义商品没有 product_id,无法匹配到指定商品列表
|
|
498
783
|
isProductMatch = false;
|
|
499
784
|
} else {
|
|
785
|
+
// 普通商品:检查是否在指定商品列表中
|
|
500
786
|
isProductMatch = available_product_ids.includes(product_id);
|
|
501
787
|
}
|
|
502
788
|
}
|
|
503
789
|
}
|
|
790
|
+
|
|
791
|
+
// 判断日程是否符合条件
|
|
504
792
|
let isScheduleMatch = false;
|
|
505
793
|
if (open_schedule === 0) {
|
|
794
|
+
// 未开启日程限制,所有日程都符合
|
|
506
795
|
isScheduleMatch = true;
|
|
507
796
|
} else {
|
|
508
|
-
|
|
797
|
+
// 开启了日程限制
|
|
798
|
+
if (schedule_type === 'all') {
|
|
799
|
+
// 所有日程都收取附加费
|
|
509
800
|
isScheduleMatch = true;
|
|
510
801
|
} else {
|
|
802
|
+
// 指定日程收取附加费
|
|
511
803
|
for (let j = 0; j < available_schedule_ids.length; j++) {
|
|
512
804
|
const scheduleId = available_schedule_ids[j];
|
|
513
805
|
const schedule = scheduleById[scheduleId];
|
|
514
806
|
if (schedule) {
|
|
515
807
|
const isInSchedule = isInScheduleByDate({
|
|
516
808
|
// date: startDate?.format('YYYY-MM-DD HH:mm:ss') || '',
|
|
517
|
-
date: startDate ||
|
|
518
|
-
schedule
|
|
809
|
+
date: startDate || '',
|
|
810
|
+
schedule: schedule
|
|
519
811
|
});
|
|
520
812
|
if (isInSchedule) {
|
|
521
813
|
isScheduleMatch = true;
|
|
@@ -525,195 +817,264 @@ var isProductMatchSurchargeCondition = (item, options) => {
|
|
|
525
817
|
}
|
|
526
818
|
}
|
|
527
819
|
}
|
|
820
|
+
|
|
821
|
+
// 商品和日程条件都要满足(取交集)
|
|
528
822
|
return isProductMatch && isScheduleMatch;
|
|
529
823
|
};
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* 订单附加费各项信息
|
|
827
|
+
*
|
|
828
|
+
* - **详情未编辑**(`!options.isEdit && bookingId`)时:直接返回 `bookingDetail.surcharge`(后端计算结果)
|
|
829
|
+
* - **新增/编辑**时:按 `options.surcharge_list` 逐条配置计算本次订单的附加费
|
|
830
|
+
*
|
|
831
|
+
* 规则要点:
|
|
832
|
+
* - 匹配范围包含:主商品(`service`)、原价 bundle 子商品(`item.bundle`)、加时商品(`item.relation_details`)、以及 addons(`addons.value`)
|
|
833
|
+
* - 固定附加费 `fixed`:只加一次,再按商品数量分摊(向下取整保留两位),剩余小数会以 `surcharge_rounding_remainder` 形式抹平到最后一个商品
|
|
834
|
+
* - 百分比附加费 `percentage`:按每个商品(价格 * 数量)分别计算再累加
|
|
835
|
+
* - 当 `open_product === 0`:不回写到商品,只在订单级别累加;否则会把单品附加费回写到商品
|
|
836
|
+
*
|
|
837
|
+
* **副作用(可能修改入参商品对象)**:
|
|
838
|
+
* - 当 `open_product !== 0` 时:写入 `item.surcharge_fee`(单品单数量附加费,保留两位、向下取整)
|
|
839
|
+
* - 写入 `item.relation_surcharge_ids`(关联到的 surcharge 配置 id 列表)
|
|
840
|
+
* - 写入 `item.surcharge_rounding_remainder`(用于抹平固定附加费/总额舍入差)
|
|
841
|
+
*
|
|
842
|
+
* @param params 入参集合(RORO)
|
|
843
|
+
* @param params.service 服务商品数组(主商品)。元素可能包含 `bundle` / `relation_details`
|
|
844
|
+
* @param params.addons 附加商品容器。当前实现读取 `addons.value` 作为商品数组(所以通常传 `{ value: CartItem[] }`)
|
|
845
|
+
* @param params.bookingDetail 订单详情(详情未编辑时用于直接取后端的 surcharge 列表),可选
|
|
846
|
+
* @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选
|
|
847
|
+
* @param options 计算选项
|
|
848
|
+
* @param options.isEdit 是否处于“编辑中”。`false` 且存在 `bookingId` 时会走详情直取逻辑
|
|
849
|
+
* @param options.surcharge_list 附加费配置列表(后端下发)。缺失/为空则返回空数组
|
|
850
|
+
* @param options.isInScheduleByDate 判断日期是否落在某个 schedule 内的方法(通常来自 ScheduleModule)
|
|
851
|
+
* @param options.scheduleById schedule 映射表:`{ [scheduleId]: schedule }`(用于根据配置的 `available_schedule_ids` 做日程匹配)
|
|
852
|
+
* @returns 附加费列表(仅返回金额 > 0 的项)
|
|
853
|
+
*/
|
|
854
|
+
const getSurcharge = ({
|
|
855
|
+
service,
|
|
856
|
+
addons,
|
|
857
|
+
bookingDetail,
|
|
858
|
+
bookingId
|
|
859
|
+
}, options) => {
|
|
860
|
+
const {
|
|
861
|
+
isEdit,
|
|
862
|
+
isInScheduleByDate,
|
|
863
|
+
surcharge_list,
|
|
864
|
+
scheduleById
|
|
865
|
+
} = options;
|
|
866
|
+
// 在所有商品里试着找 start_date,如果没有则用当前时间
|
|
867
|
+
const firstAppointmentCartItem = service.filter(n => !(0, _utils.isNormalProduct)(n._productOrigin))?.[0];
|
|
868
|
+
let startDate = '';
|
|
537
869
|
if (firstAppointmentCartItem) {
|
|
538
|
-
startDate = firstAppointmentCartItem.start_date +
|
|
870
|
+
startDate = firstAppointmentCartItem.start_date + ' ' + firstAppointmentCartItem.start_time + ':00';
|
|
539
871
|
} else {
|
|
540
|
-
startDate = (0,
|
|
872
|
+
startDate = (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss');
|
|
541
873
|
}
|
|
874
|
+
// 编辑状态, 且未修改商品时直接从详情取出
|
|
542
875
|
if (!isEdit && bookingId) {
|
|
543
|
-
if (Array.isArray(bookingDetail
|
|
544
|
-
return (
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
);
|
|
876
|
+
if (Array.isArray(bookingDetail?.surcharge)) {
|
|
877
|
+
return (bookingDetail?.surcharge || []).filter(d => Number(d.amount) > 0).map((d, index) => {
|
|
878
|
+
return {
|
|
879
|
+
key: `custom_surcharge_${index}`,
|
|
880
|
+
// label:
|
|
881
|
+
// d.name[state.locale || 'en'] ||
|
|
882
|
+
// d.name['en'] ||
|
|
883
|
+
// d.name['original'],
|
|
884
|
+
label: d.name,
|
|
885
|
+
value: d.amount,
|
|
886
|
+
name: d.name,
|
|
887
|
+
surcharge_id: d.id,
|
|
888
|
+
description: d.description,
|
|
889
|
+
// 后端说这个固定传 default
|
|
890
|
+
type: 'default',
|
|
891
|
+
fixed: d.fixed,
|
|
892
|
+
amount: d.amount,
|
|
893
|
+
percentage: d.percentage
|
|
894
|
+
};
|
|
895
|
+
});
|
|
565
896
|
}
|
|
566
897
|
return [];
|
|
567
898
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
899
|
+
|
|
900
|
+
// 用于“计算总价”的场景:每次调用都应重新计算(避免重复调用导致 surcharge_fee 累加)
|
|
901
|
+
// 注意:同一次调用内仍会在多条 surcharge 配置之间累加
|
|
902
|
+
resetItemsSurchargeSideEffects({
|
|
903
|
+
service,
|
|
904
|
+
addons
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
// 无附加费规则
|
|
908
|
+
if (!Array.isArray(surcharge_list) || !surcharge_list?.length) return [];
|
|
909
|
+
|
|
910
|
+
// 分别计算每种附加费总和
|
|
571
911
|
const surchargeWithAmount = [];
|
|
912
|
+
|
|
913
|
+
// 遍历每种附加费配置
|
|
572
914
|
for (let i = 0; i < surcharge_list.length; i++) {
|
|
573
915
|
const surchargeConfig = surcharge_list[i];
|
|
574
916
|
const {
|
|
575
|
-
percentage =
|
|
576
|
-
fixed =
|
|
917
|
+
percentage = '0',
|
|
918
|
+
fixed = '0',
|
|
577
919
|
id,
|
|
578
920
|
type,
|
|
579
921
|
description,
|
|
580
922
|
open_product
|
|
581
923
|
} = surchargeConfig;
|
|
924
|
+
|
|
925
|
+
// 收集所有符合条件的商品
|
|
582
926
|
const matchedItems = [];
|
|
927
|
+
|
|
928
|
+
// 检查service中符合条件的商品
|
|
583
929
|
if (Array.isArray(service)) {
|
|
584
930
|
for (let item of service) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
)) {
|
|
931
|
+
// 主商品符合附加费条件
|
|
932
|
+
if (isProductMatchSurchargeCondition({
|
|
933
|
+
isCustomItem: item.isCustomItem,
|
|
934
|
+
startDate,
|
|
935
|
+
product_id: item.id
|
|
936
|
+
}, {
|
|
937
|
+
surchargeConfig,
|
|
938
|
+
scheduleById: scheduleById || {},
|
|
939
|
+
isInScheduleByDate: isInScheduleByDate
|
|
940
|
+
})) {
|
|
941
|
+
// 主商品加价减价后的总价
|
|
597
942
|
const total = getMainProductTotal({
|
|
598
943
|
...item,
|
|
599
|
-
option:
|
|
600
|
-
bundle:
|
|
944
|
+
option: item?.option || item?.options || [],
|
|
945
|
+
bundle: item?.bundle || item?.bundles || []
|
|
601
946
|
});
|
|
602
947
|
const mainQuantity = item.num || 1;
|
|
603
948
|
matchedItems.push({
|
|
604
|
-
total,
|
|
949
|
+
total: total,
|
|
605
950
|
// addTimeTotal: getRelationDetailsTotal(
|
|
606
951
|
// item._extend.relation_details || []
|
|
607
952
|
// ),
|
|
608
953
|
isMain: true,
|
|
609
954
|
quantity: mainQuantity,
|
|
610
955
|
item,
|
|
611
|
-
mainQuantity
|
|
612
|
-
// 主商品的mainQuantity等于自己的quantity
|
|
956
|
+
mainQuantity: mainQuantity // 主商品的mainQuantity等于自己的quantity
|
|
613
957
|
});
|
|
614
958
|
}
|
|
615
|
-
const arr =
|
|
959
|
+
const arr = item?.bundle || item?.bundles || [];
|
|
960
|
+
// 遍历子商品 原价商品符合附加费条件
|
|
616
961
|
for (let bundleItem of arr) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
}
|
|
628
|
-
)) {
|
|
962
|
+
// bundle商品是原价且符合附加费条件
|
|
963
|
+
if (getBundleItemIsOriginalPrice(bundleItem) && isProductMatchSurchargeCondition({
|
|
964
|
+
isCustomItem: false,
|
|
965
|
+
startDate,
|
|
966
|
+
product_id: bundleItem._bundle_product_id
|
|
967
|
+
}, {
|
|
968
|
+
surchargeConfig,
|
|
969
|
+
scheduleById: scheduleById || {},
|
|
970
|
+
isInScheduleByDate: isInScheduleByDate
|
|
971
|
+
})) {
|
|
629
972
|
const mainQuantity = item.num || 1;
|
|
630
973
|
matchedItems.push({
|
|
631
974
|
isMain: false,
|
|
632
|
-
total: Number(
|
|
633
|
-
bundleItem.bundle_selling_price ?? bundleItem.price ?? 0
|
|
634
|
-
),
|
|
975
|
+
total: Number(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0),
|
|
635
976
|
quantity: bundleItem.num || bundleItem.quantity || 1,
|
|
636
977
|
item: bundleItem,
|
|
637
|
-
mainQuantity
|
|
638
|
-
// 子商品的mainQuantity是所属主商品的quantity
|
|
978
|
+
mainQuantity: mainQuantity // 子商品的mainQuantity是所属主商品的quantity
|
|
639
979
|
});
|
|
640
980
|
}
|
|
641
981
|
}
|
|
982
|
+
|
|
983
|
+
// 加时商品符合附加费条件
|
|
642
984
|
for (let relationDetail of item.relation_details || []) {
|
|
643
|
-
if (isProductMatchSurchargeCondition(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
{
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
isInScheduleByDate
|
|
653
|
-
}
|
|
654
|
-
)) {
|
|
985
|
+
if (isProductMatchSurchargeCondition({
|
|
986
|
+
isCustomItem: false,
|
|
987
|
+
startDate,
|
|
988
|
+
product_id: relationDetail.product_id
|
|
989
|
+
}, {
|
|
990
|
+
surchargeConfig,
|
|
991
|
+
scheduleById: scheduleById || {},
|
|
992
|
+
isInScheduleByDate: isInScheduleByDate
|
|
993
|
+
})) {
|
|
655
994
|
matchedItems.push({
|
|
656
995
|
isMain: false,
|
|
657
|
-
total: Number(
|
|
658
|
-
(relationDetail == null ? void 0 : relationDetail.price) || ((_b = relationDetail == null ? void 0 : relationDetail.metadata) == null ? void 0 : _b.main_product_attached_bundle_selling_price)
|
|
659
|
-
),
|
|
996
|
+
total: Number(relationDetail?.price || relationDetail?.metadata?.main_product_attached_bundle_selling_price),
|
|
660
997
|
quantity: relationDetail.num || relationDetail.quantity || 1,
|
|
661
998
|
item: relationDetail,
|
|
662
|
-
mainQuantity: 1
|
|
663
|
-
// 加时商品不受主商品数量影响
|
|
999
|
+
mainQuantity: 1 // 加时商品不受主商品数量影响
|
|
664
1000
|
});
|
|
665
1001
|
}
|
|
666
1002
|
}
|
|
667
1003
|
}
|
|
668
1004
|
}
|
|
669
|
-
|
|
1005
|
+
|
|
1006
|
+
// 检查addons中符合条件的商品
|
|
1007
|
+
if (Array.isArray(addons?.value)) {
|
|
670
1008
|
for (let item of addons.value) {
|
|
671
|
-
if (isProductMatchSurchargeCondition({
|
|
1009
|
+
if (isProductMatchSurchargeCondition({
|
|
1010
|
+
...item,
|
|
1011
|
+
startDate
|
|
1012
|
+
}, {
|
|
672
1013
|
surchargeConfig,
|
|
673
1014
|
scheduleById: scheduleById || {},
|
|
674
|
-
isInScheduleByDate
|
|
1015
|
+
isInScheduleByDate: isInScheduleByDate
|
|
675
1016
|
})) {
|
|
676
1017
|
matchedItems.push({
|
|
677
1018
|
isMain: true,
|
|
678
1019
|
total: Number(item.total),
|
|
679
1020
|
quantity: item.num || 1,
|
|
680
|
-
item,
|
|
681
|
-
mainQuantity: 1
|
|
682
|
-
// addons独立商品,mainQuantity为1
|
|
1021
|
+
item: item,
|
|
1022
|
+
mainQuantity: 1 // addons独立商品,mainQuantity为1
|
|
683
1023
|
});
|
|
684
1024
|
}
|
|
685
1025
|
}
|
|
686
1026
|
}
|
|
687
1027
|
let finalAmount = 0;
|
|
1028
|
+
|
|
1029
|
+
// 计算商品总数:主商品和addons按quantity计算,子商品(bundle item)需要乘以主商品数量
|
|
688
1030
|
const productCount = matchedItems.reduce((total, item) => {
|
|
689
1031
|
if (item.isMain) {
|
|
1032
|
+
// 主商品和addons商品
|
|
690
1033
|
return total + (item.num || item.quantity || 1);
|
|
691
1034
|
} else {
|
|
1035
|
+
// 子商品(bundle item)和加时商品
|
|
1036
|
+
// 加时商品的 mainQuantity = 1,所以不受影响
|
|
1037
|
+
// bundle item 的 mainQuantity = 主商品数量,需要乘以实际数量
|
|
692
1038
|
return total + (item.num || item.quantity || 1) * (item.mainQuantity || 1);
|
|
693
1039
|
}
|
|
694
1040
|
}, 0);
|
|
695
|
-
|
|
696
|
-
|
|
1041
|
+
|
|
1042
|
+
// 追加进入的固定附加费总值
|
|
1043
|
+
let fixedTotal = new _decimal.default(0);
|
|
1044
|
+
// 追加到商品的附加费总值 用于追加抹平字段
|
|
1045
|
+
let productTotalSurcharge = new _decimal.default(0);
|
|
697
1046
|
if (matchedItems.length > 0) {
|
|
698
|
-
|
|
699
|
-
|
|
1047
|
+
// 基于每个商品计算附加费:max(0, 商品价格) * rate + fixed
|
|
1048
|
+
let configTotal = new _decimal.default(0);
|
|
1049
|
+
|
|
1050
|
+
// 计算固定附加费 - 只加一次
|
|
1051
|
+
if (fixed && new _decimal.default(fixed).gt(0)) {
|
|
700
1052
|
configTotal = configTotal.plus(fixed);
|
|
701
1053
|
}
|
|
702
|
-
|
|
703
|
-
|
|
1054
|
+
|
|
1055
|
+
// 计算百分比附加费 - 对每个商品单独计算
|
|
1056
|
+
if (percentage && new _decimal.default(percentage).gt(0) || fixed) {
|
|
1057
|
+
const percentageRate = new _decimal.default(percentage);
|
|
704
1058
|
for (let [index, item] of matchedItems.entries()) {
|
|
705
1059
|
const isLast = index === matchedItems.length - 1;
|
|
706
|
-
|
|
707
|
-
const
|
|
708
|
-
const
|
|
1060
|
+
// 对每个商品:max(0, 价格) * 数量 * 费率
|
|
1061
|
+
const itemPrice = new _decimal.default(Math.max(0, item.total || 0));
|
|
1062
|
+
const itemQuantity = new _decimal.default(item.isMain ? item.quantity || 1 : item.quantity * item.mainQuantity || 1);
|
|
1063
|
+
const addTimeTotal = new _decimal.default(item.addTimeTotal || 0);
|
|
1064
|
+
// 单个商品总附加费
|
|
709
1065
|
const itemTotalSurcharge = itemPrice.times(itemQuantity).plus(addTimeTotal).times(percentageRate);
|
|
710
1066
|
configTotal = configTotal.plus(itemTotalSurcharge);
|
|
1067
|
+
|
|
1068
|
+
// 单个商品单数量附加费
|
|
711
1069
|
const itemSurcharge = itemPrice.times(percentageRate);
|
|
712
|
-
|
|
1070
|
+
|
|
1071
|
+
// 固定附加费 = 1 / 商品数量 * 固定附加费(向下取整保留两位小数)
|
|
1072
|
+
const fixedSurcharge = new _decimal.default(1).div(productCount).times(fixed).times(100).floor().div(100).toFixed(2);
|
|
713
1073
|
const quantity = item.isMain ? item.quantity : item.quantity * item.mainQuantity;
|
|
714
|
-
fixedTotal = fixedTotal.plus(new
|
|
1074
|
+
fixedTotal = fixedTotal.plus(new _decimal.default(fixedSurcharge).times(quantity).toNumber());
|
|
1075
|
+
// 如果是最后一个商品 判断fixed - fixedTotal 是否有剩余小数 如果有的话,追加抹平字段
|
|
715
1076
|
if (isLast && fixedTotal.gt(0)) {
|
|
716
|
-
const remaining = new
|
|
1077
|
+
const remaining = new _decimal.default(fixed).minus(fixedTotal).toNumber();
|
|
717
1078
|
if (remaining > 0) {
|
|
718
1079
|
productTotalSurcharge = productTotalSurcharge.plus(remaining);
|
|
719
1080
|
if (item.isMain) {
|
|
@@ -723,36 +1084,44 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
723
1084
|
}
|
|
724
1085
|
}
|
|
725
1086
|
}
|
|
1087
|
+
// 只有当 open_product !== 0 时,才将附加费追加到商品身上
|
|
1088
|
+
// open_product === 0 表示商品未开启该附加费,只在订单级别累加
|
|
726
1089
|
if (open_product !== 0) {
|
|
727
1090
|
if (item.isMain) {
|
|
728
|
-
const originSurchargeFee = new
|
|
729
|
-
|
|
730
|
-
|
|
1091
|
+
const originSurchargeFee = new _decimal.default(item.item.surcharge_fee || 0);
|
|
1092
|
+
// 保留两位小数
|
|
1093
|
+
const surchargeFee = originSurchargeFee.plus(itemSurcharge).plus(fixedSurcharge).toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
|
|
1094
|
+
productTotalSurcharge = productTotalSurcharge.plus(new _decimal.default(surchargeFee).times(itemQuantity).toNumber());
|
|
731
1095
|
item.item.surcharge_fee = surchargeFee;
|
|
732
|
-
item.item.relation_surcharge_ids = [...(
|
|
1096
|
+
item.item.relation_surcharge_ids = [...(item.item?.relation_surcharge_ids || []), id];
|
|
733
1097
|
} else {
|
|
734
|
-
const originSurchargeFee = new
|
|
735
|
-
|
|
736
|
-
|
|
1098
|
+
const originSurchargeFee = new _decimal.default(item.item.surcharge_fee || 0);
|
|
1099
|
+
// 保留两位小数
|
|
1100
|
+
const surchargeFee = originSurchargeFee.plus(itemSurcharge).plus(fixedSurcharge).toDecimalPlaces(2, _decimal.default.ROUND_DOWN).toNumber();
|
|
1101
|
+
productTotalSurcharge = productTotalSurcharge.plus(new _decimal.default(surchargeFee).times(itemQuantity).toNumber());
|
|
737
1102
|
item.item.surcharge_fee = surchargeFee;
|
|
738
|
-
item.item.relation_surcharge_ids = [...(
|
|
1103
|
+
item.item.relation_surcharge_ids = [...(item.item?.relation_surcharge_ids || []), id];
|
|
739
1104
|
}
|
|
740
1105
|
}
|
|
1106
|
+
// 最后一个商品 判断configTotal - productTotalSurcharge 是否有剩余小数 如果有的话,追加抹平字段
|
|
741
1107
|
if (isLast && configTotal.minus(productTotalSurcharge).gt(0)) {
|
|
742
|
-
|
|
1108
|
+
// 四舍五入configTotal
|
|
1109
|
+
const configTotalRounded = configTotal.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP);
|
|
743
1110
|
if (item.isMain) {
|
|
744
|
-
let newRoundingRemainder = new
|
|
1111
|
+
let newRoundingRemainder = new _decimal.default(item.item.surcharge_rounding_remainder || 0);
|
|
745
1112
|
newRoundingRemainder = newRoundingRemainder.plus(configTotalRounded.minus(productTotalSurcharge));
|
|
746
1113
|
item.item.surcharge_rounding_remainder = newRoundingRemainder.toNumber();
|
|
747
1114
|
} else {
|
|
748
|
-
let newRoundingRemainder = new
|
|
1115
|
+
let newRoundingRemainder = new _decimal.default(item.item.surcharge_rounding_remainder || 0);
|
|
749
1116
|
newRoundingRemainder = newRoundingRemainder.plus(configTotalRounded.minus(productTotalSurcharge));
|
|
750
1117
|
item.item.surcharge_rounding_remainder = newRoundingRemainder.toNumber();
|
|
751
1118
|
}
|
|
752
1119
|
}
|
|
753
1120
|
}
|
|
754
1121
|
}
|
|
755
|
-
|
|
1122
|
+
|
|
1123
|
+
// 如果该配置有金额,则添加到结果中
|
|
1124
|
+
finalAmount = configTotal.toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
756
1125
|
}
|
|
757
1126
|
const name = surchargeConfig.name || {};
|
|
758
1127
|
if (Number(finalAmount) <= 0) {
|
|
@@ -767,7 +1136,7 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
767
1136
|
surcharge_id: id,
|
|
768
1137
|
description,
|
|
769
1138
|
// 后端说固定传 default
|
|
770
|
-
type:
|
|
1139
|
+
type: 'default',
|
|
771
1140
|
fixed,
|
|
772
1141
|
amount: finalAmount,
|
|
773
1142
|
percentage,
|
|
@@ -778,10 +1147,13 @@ var getSurcharge = ({ service, addons, bookingDetail, bookingId }, options) => {
|
|
|
778
1147
|
}
|
|
779
1148
|
return surchargeWithAmount;
|
|
780
1149
|
};
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1150
|
+
exports.getSurcharge = getSurcharge;
|
|
1151
|
+
function resetItemsSurchargeSideEffects({
|
|
1152
|
+
service,
|
|
1153
|
+
addons
|
|
1154
|
+
}) {
|
|
1155
|
+
const resetItem = item => {
|
|
1156
|
+
if (!item) return;
|
|
785
1157
|
item.surcharge_fee = 0;
|
|
786
1158
|
item.surcharge_rounding_remainder = 0;
|
|
787
1159
|
item.relation_surcharge_ids = [];
|
|
@@ -789,29 +1161,12 @@ function resetItemsSurchargeSideEffects({ service, addons }) {
|
|
|
789
1161
|
if (Array.isArray(service)) {
|
|
790
1162
|
for (let item of service) {
|
|
791
1163
|
resetItem(item);
|
|
792
|
-
const arr =
|
|
793
|
-
for (let bundleItem of arr)
|
|
794
|
-
|
|
795
|
-
for (let relationDetail of (item == null ? void 0 : item.relation_details) || [])
|
|
796
|
-
resetItem(relationDetail);
|
|
1164
|
+
const arr = item?.bundle || item?.bundles || [];
|
|
1165
|
+
for (let bundleItem of arr) resetItem(bundleItem);
|
|
1166
|
+
for (let relationDetail of item?.relation_details || []) resetItem(relationDetail);
|
|
797
1167
|
}
|
|
798
1168
|
}
|
|
799
|
-
if (Array.isArray(addons
|
|
800
|
-
for (let item of addons.value)
|
|
801
|
-
resetItem(item);
|
|
1169
|
+
if (Array.isArray(addons?.value)) {
|
|
1170
|
+
for (let item of addons.value) resetItem(item);
|
|
802
1171
|
}
|
|
803
|
-
}
|
|
804
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
805
|
-
0 && (module.exports = {
|
|
806
|
-
calcDiscountListDifference,
|
|
807
|
-
calculateDeposit,
|
|
808
|
-
calculateOriginSubtotal,
|
|
809
|
-
calculatePriceDetails,
|
|
810
|
-
calculateSubtotal,
|
|
811
|
-
calculateTaxFee,
|
|
812
|
-
getBundleDiscountList,
|
|
813
|
-
getProductDiscountProductDiscountDifference,
|
|
814
|
-
getSurcharge,
|
|
815
|
-
getSurchargeAmount,
|
|
816
|
-
getTax
|
|
817
|
-
});
|
|
1172
|
+
}
|