UNPKG

@pisell/pisellos

Version:

一个可扩展的前端模块化SDK框架,支持插件系统

1,115 lines (1,047 loc) 62.8 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } import Decimal from 'decimal.js'; import { isNormalProduct } from "../Product/utils"; import dayjs from 'dayjs'; export var calculatePriceDetails = function calculatePriceDetails(shopInfo, items, isInScheduleByDate, surchargeList, scheduleById) { var subtotal = new Decimal(calculateSubtotal(items)); var subOriginTotal = new Decimal(calculateOriginSubtotal(items)); var totalTaxFee = new Decimal(calculateTaxFee(shopInfo, items)); // 订单附加费列表 var surcharge = getSurcharge({ service: items, addons: [], bookingDetail: null, bookingId: undefined }, { isEdit: false, isInScheduleByDate: isInScheduleByDate, surcharge_list: surchargeList, scheduleById: scheduleById }); // 订单附加费金额 var surchargeAmount = new Decimal(getSurchargeAmount({ bookingDetail: null, bookingId: undefined }, surcharge, { isEdit: false })); // 税费 var _getTax = getTax({ service: items, bookingDetail: null, bookingId: undefined }, { computed: { productExpectAmount: subtotal.toNumber(), shopDiscount: 0 }, isEdit: false, tax_rate: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.tax_rate, is_price_include_tax: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.is_price_include_tax }), tax = _getTax.tax, originTax = _getTax.originTax; var total = shopInfo !== null && shopInfo !== void 0 && shopInfo.is_price_include_tax ? subtotal.plus(surchargeAmount) : subtotal.plus(tax).plus(surchargeAmount); // 计算总价 不包含折扣卡商品券折扣信息价格 var originTotal = shopInfo !== null && shopInfo !== void 0 && shopInfo.is_price_include_tax ? subOriginTotal.plus(surchargeAmount) : subOriginTotal.plus(totalTaxFee).plus(surchargeAmount); // 计算定金 var deposit = calculateDeposit(items); return { subtotal: subtotal.toFixed(2), total: total.toFixed(2), originTotal: originTotal.toFixed(2), taxTitle: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.tax_title, taxRate: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.tax_rate, totalTaxFee: tax, isPriceIncludeTax: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.is_price_include_tax, surcharge: surcharge, surchargeAmount: surchargeAmount.toFixed(2), deposit: deposit }; }; /** * 获取子商品折扣信息 * @param item */ export var getBundleDiscountList = function getBundleDiscountList(bundle) { if (!bundle) { return []; } var discountList = []; bundle.forEach(function (d) { if (d.discount_list && Array.isArray(d.discount_list)) { discountList.push.apply(discountList, _toConsumableArray(d.discount_list.filter(function (item) { return !item.id; }))); } }); return discountList; }; export var calcDiscountListDifference = function calcDiscountListDifference(discountList) { return discountList.reduce(function (pre, cur) { var _cur$metadata; return pre + ((cur === null || cur === void 0 || (_cur$metadata = cur.metadata) === null || _cur$metadata === void 0 ? void 0 : _cur$metadata.product_discount_difference) || 0); }, 0); }; export var getProductDiscountProductDiscountDifference = function getProductDiscountProductDiscountDifference(item) { var _item$_origin, _item$_origin2; var mainDiscountList = ((_item$_origin = item._origin) === null || _item$_origin === void 0 || (_item$_origin = _item$_origin.product) === null || _item$_origin === void 0 ? void 0 : _item$_origin.discount_list) || []; var bundleDiscountList = getBundleDiscountList(((_item$_origin2 = item._origin) === null || _item$_origin2 === void 0 || (_item$_origin2 = _item$_origin2.product) === null || _item$_origin2 === void 0 ? void 0 : _item$_origin2.product_bundle) || []); var discountList = [].concat(_toConsumableArray(mainDiscountList), _toConsumableArray(bundleDiscountList)); return calcDiscountListDifference(discountList); }; /** * 计算订单税费(折扣前/折扣后),并把单品税费信息回写到商品数据上(用于明细展示/后续计算)。 * * - **折扣前税费**:`originTax` * - **折扣后税费**:`tax`(会考虑 `computed.shopDiscount` 对每个商品的分摊影响) * - **税率/是否含税**:优先取 `bookingDetail.tax_rate` / `bookingDetail.is_price_include_tax`,取不到再回退到 `options.tax_rate` / `options.is_price_include_tax` * * **副作用(会修改入参商品对象)**: * - 主商品:写入 `item.original_tax_fee` / `item.tax_fee`(四舍五入保留两位) * - bundle 原价子商品:写入 `bundleItem.original_tax_fee` / `bundleItem.tax_fee` * - 加时商品(`relation_details`):写入 `atItem.tax_fee` * - 税费舍入差值:追加到最后一个“含税商品”的 `tax_fee_rounding_remainder` / `original_tax_fee_rounding_remainder` * * @param params 入参集合(RORO) * @param params.service 服务商品数组(主商品)。通常是购物车商品结构(可能包含 `bundle` / `relation_details`) * @param params.addons 附加商品数组(可选)。结构同商品数组 * @param params.bookingDetail 订单详情(编辑/详情场景用于读取后端税率配置),可选 * @param params.bookingId 订单/预约 ID(编辑/详情场景识别用),可选 * @param options 计算选项 * @param options.isEdit 是否处于“编辑中”。当前实现不强依赖该值(历史逻辑保留),但建议按真实状态传入 * @param options.computed 预计算结果(用于折扣分摊) * @param options.computed.productExpectAmount 商品期望总金额(用于按比例分摊折扣) * @param options.computed.shopDiscount 店铺折扣总额(用于按比例分摊到商品) * @param options.tax_rate 管理端税率(百分比,如 5 表示 5%)。仅当 `bookingDetail.tax_rate` 不存在时生效 * @param options.is_price_include_tax 是否含税:`0` 不含税、`1` 含税。仅当 `bookingDetail.is_price_include_tax` 不存在时生效 * @returns 税费汇总(number,金额单位与商品价格一致,四舍五入保留两位) * @returns.originTax 折扣前税费合计 * @returns.tax 折扣后税费合计 */ export var getTax = function getTax(_ref, options) { var service = _ref.service, addons = _ref.addons, bookingDetail = _ref.bookingDetail, bookingId = _ref.bookingId; var isEdit = options.isEdit, computed = options.computed, tax_rate = options.tax_rate, is_price_include_tax = options.is_price_include_tax; // 详情时未编辑的状态下, 取后端的值 // if (!isEdit) { // return { tax: Number(bookingDetail?.tax_fee) || 0 }; // } var totalOriginTax = new Decimal(0); var totalTax = new Decimal(0); if (service || addons) { // 处理服务商品 if (service !== null && service !== void 0 && service.length) { var serviceResult = processItemsTax(service.map(function (item) { return _objectSpread(_objectSpread({}, item), {}, { option: (item === null || item === void 0 ? void 0 : item.option) || (item === null || item === void 0 ? void 0 : item.options) || [], bundle: (item === null || item === void 0 ? void 0 : item.bundle) || (item === null || item === void 0 ? void 0 : item.bundles) || [] }); }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax, computed: computed }); totalOriginTax = totalOriginTax.plus(serviceResult.originTax); totalTax = totalTax.plus(serviceResult.tax); } // 处理附加商品 if (addons !== null && addons !== void 0 && addons.length) { var addonsResult = processItemsTax(addons, { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax, computed: computed }); totalOriginTax = totalOriginTax.plus(addonsResult.originTax); totalTax = totalTax.plus(addonsResult.tax); } } return { originTax: totalOriginTax.toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber(), tax: totalTax.toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber() }; }; function getDiscountedTaxableBase(input) { var basePrice = input.basePrice, discount = input.discount, surchargeFee = input.surchargeFee; if (surchargeFee.lte(0) && basePrice.lte(0)) return new Decimal(0); var discountedBase = basePrice.minus(discount); if (discountedBase.lte(0)) return surchargeFee; return discountedBase.plus(surchargeFee); } /** * 处理商品税费计算(折扣前后) * 支持税费舍入差值追加到最后一个含税商品的 tax_fee_rounding_remainder / original_tax_fee_rounding_remainder 字段 * @param items 商品数组 * @param state 状态 * @param options 选项 * @param computed 计算结果 * @returns 累积的税费信息 */ var processItemsTax = function processItemsTax(items, _ref2, options) { var bookingDetail = _ref2.bookingDetail, bookingId = _ref2.bookingId; var tax_rate = options.tax_rate, is_price_include_tax = options.is_price_include_tax, computed = options.computed; var shopDiscount = computed.shopDiscount, productExpectAmount = computed.productExpectAmount; // 精确税费累加(不四舍五入) var preciseOriginTax = new Decimal(0); var preciseTax = new Decimal(0); // 四舍五入后的税费累加 var roundedOriginTax = new Decimal(0); var roundedTax = new Decimal(0); /** * 最后一个含税商品的引用(按物理位置) * 用于追加税费舍入差值 */ var lastTaxableItem = null; var _iterator = _createForOfIteratorHelper(items), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var item = _step.value; var quantity = new Decimal(item.num || 1); var unitPrice = new Decimal(item.total || 0); var mainProductPrice = new Decimal(getMainProductTotal(_objectSpread(_objectSpread({}, item), {}, { option: (item === null || item === void 0 ? void 0 : item.option) || (item === null || item === void 0 ? void 0 : item.options) || [], bundle: (item === null || item === void 0 ? void 0 : item.bundle) || (item === null || item === void 0 ? void 0 : item.bundles) || [] })) || 0); // 计算原始税费(折扣前)- 单个商品(精确值) var originalTaxableBase = getDiscountedTaxableBase({ basePrice: mainProductPrice, discount: new Decimal(0), surchargeFee: new Decimal((item === null || item === void 0 ? void 0 : item.surcharge_fee) || 0) }); var originalTaxPerItemPrecise = getProductItemTax(_objectSpread(_objectSpread({}, item), {}, { total: originalTaxableBase.toNumber(), quantity: 1 }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax }); // 计算平摊到该商品的折扣 var itemDiscount = new Decimal(0); if (productExpectAmount > 0) { itemDiscount = unitPrice.dividedBy(productExpectAmount).times(shopDiscount); } // 按比例计算主商品应分摊的折扣 var mainItemDiscount = new Decimal(0); if (unitPrice.greaterThan(0)) { mainItemDiscount = mainProductPrice.dividedBy(productExpectAmount).times(shopDiscount); } var mainItemDiscountedUnitPrice = getDiscountedTaxableBase({ basePrice: mainProductPrice, discount: mainItemDiscount, surchargeFee: new Decimal((item === null || item === void 0 ? void 0 : item.surcharge_fee) || 0) }); // 计算折后税费(折扣后)- 主商品的税费(精确值) var maxDiscountedTaxPerItemPrecise = getProductItemTax(_objectSpread(_objectSpread({}, item), {}, { total: mainItemDiscountedUnitPrice.toNumber(), price: item.total, quantity: 1 }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax }); // 四舍五入后的值 var maxDiscountedTaxPerItemRounded = maxDiscountedTaxPerItemPrecise.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); // 保存到商品扩展信息中(保留两位小数) item.main_product_attached_bundle_tax_fee = maxDiscountedTaxPerItemRounded.toNumber(); // 如果主商品有税费,记录为最后一个含税商品 if (maxDiscountedTaxPerItemPrecise.gt(0)) { lastTaxableItem = { type: 'main', item: item }; } // 注意:加时商品独立计算,不考虑主商品数量 var addTimePreciseTax = new Decimal(0); var addTimeRoundedTax = new Decimal(0); if (Array.isArray(item.relation_details)) { var _iterator2 = _createForOfIteratorHelper(item.relation_details), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var atItem = _step2.value; // 计算单件加时商品折扣后价格 var _originTotal = new Decimal(atItem.selling_price || atItem.price || 0); var addTimeDiscount = productExpectAmount > 0 ? _originTotal.dividedBy(productExpectAmount).times(shopDiscount) : new Decimal(0); var _discountedTotal = getDiscountedTaxableBase({ basePrice: _originTotal, discount: addTimeDiscount, surchargeFee: new Decimal((atItem === null || atItem === void 0 ? void 0 : atItem.surcharge_fee) || 0) }); var addTimeTaxPerItemPrecise = getProductItemTax(_objectSpread(_objectSpread({}, atItem), {}, { total: _discountedTotal.toNumber(), quantity: atItem.product_quantity || atItem.num || 1 }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax }); var addTimeTaxPerItemRounded = addTimeTaxPerItemPrecise.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); // 保存到加时商品上(四舍五入后的值) atItem.tax_fee = addTimeTaxPerItemRounded.toNumber(); addTimePreciseTax = addTimePreciseTax.plus(addTimeTaxPerItemPrecise); addTimeRoundedTax = addTimeRoundedTax.plus(addTimeTaxPerItemRounded); // 如果加时商品有税费,记录为最后一个含税商品 if (addTimeTaxPerItemPrecise.gt(0)) { lastTaxableItem = { type: 'addTime', item: atItem }; } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } // 处理 bundle 子商品(仅原价子商品) var bundlePreciseOriginTax = new Decimal(0); var bundlePreciseTax = new Decimal(0); var bundleRoundedOriginTax = new Decimal(0); var bundleRoundedTax = new Decimal(0); if (Array.isArray(item === null || item === void 0 ? void 0 : item.bundle)) { var _iterator3 = _createForOfIteratorHelper(item === null || item === void 0 ? void 0 : item.bundle), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var bundleItem = _step3.value; // 只处理原价的子商品 if (getBundleItemIsOriginalPrice(bundleItem)) { var _ref3, _bundleItem$bundle_se; var bundleQuantity = new Decimal(bundleItem.num || bundleItem.quantity || 1); var bundleUnitPrice = new Decimal((_ref3 = (_bundleItem$bundle_se = bundleItem.bundle_selling_price) !== null && _bundleItem$bundle_se !== void 0 ? _bundleItem$bundle_se : bundleItem.price) !== null && _ref3 !== void 0 ? _ref3 : 0); // 计算原始税费(折扣前)- 单个商品(精确值) var bundleOriginalTaxableBase = getDiscountedTaxableBase({ basePrice: bundleUnitPrice, discount: new Decimal(0), surchargeFee: new Decimal((bundleItem === null || bundleItem === void 0 ? void 0 : bundleItem.surcharge_fee) || 0) }); var bundleOriginalTaxPerItemPrecise = getProductItemTax(_objectSpread(_objectSpread({}, bundleItem), {}, { total: bundleOriginalTaxableBase.toNumber(), quantity: 1 }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax }); // 计算平摊到该bundle商品的折扣 var bundleItemDiscount = new Decimal(0); if (productExpectAmount > 0) { bundleItemDiscount = bundleUnitPrice.dividedBy(productExpectAmount).times(shopDiscount); } // bundle商品折后单价 var bundleDiscountedUnitPrice = getDiscountedTaxableBase({ basePrice: bundleUnitPrice, discount: bundleItemDiscount, surchargeFee: new Decimal((bundleItem === null || bundleItem === void 0 ? void 0 : bundleItem.surcharge_fee) || 0) }); // 计算折后税费(折扣后)- 单个商品(精确值) var bundleDiscountedTaxPerItemPrecise = getProductItemTax(_objectSpread(_objectSpread({}, bundleItem), {}, { total: bundleDiscountedUnitPrice.toNumber(), quantity: 1 }), { bookingDetail: bookingDetail, bookingId: bookingId }, { tax_rate: tax_rate, is_price_include_tax: is_price_include_tax }); // 四舍五入后的值 var bundleOriginalTaxPerItemRounded = bundleOriginalTaxPerItemPrecise.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); var bundleDiscountedTaxPerItemRounded = bundleDiscountedTaxPerItemPrecise.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); // 保存到bundle商品上(单个商品的税费,四舍五入后) bundleItem.original_tax_fee = bundleOriginalTaxPerItemRounded.toNumber(); bundleItem.tax_fee = bundleDiscountedTaxPerItemRounded.toNumber(); // 累加bundle税费(需要乘以bundle数量) bundlePreciseOriginTax = bundlePreciseOriginTax.plus(bundleOriginalTaxPerItemPrecise.times(bundleQuantity)); bundlePreciseTax = bundlePreciseTax.plus(bundleDiscountedTaxPerItemPrecise.times(bundleQuantity)); bundleRoundedOriginTax = bundleRoundedOriginTax.plus(bundleOriginalTaxPerItemRounded.times(bundleQuantity)); bundleRoundedTax = bundleRoundedTax.plus(bundleDiscountedTaxPerItemRounded.times(bundleQuantity)); // 如果bundle商品有税费,记录为最后一个含税商品 if (bundleDiscountedTaxPerItemPrecise.gt(0)) { lastTaxableItem = { type: 'bundle', item: bundleItem }; } } } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } } // 主商品的原始税费和折后税费(精确值) var originalTaxFeePrecise = originalTaxPerItemPrecise.plus(bundlePreciseOriginTax); var taxFeePrecise = maxDiscountedTaxPerItemPrecise.plus(bundlePreciseTax); // 主商品的原始税费和折后税费(四舍五入后) var originalTaxFeeRounded = originalTaxPerItemPrecise.toDecimalPlaces(2, Decimal.ROUND_HALF_UP).plus(bundleRoundedOriginTax); var taxFeeRounded = maxDiscountedTaxPerItemRounded.plus(bundleRoundedTax); // 保存到商品扩展信息中(四舍五入后的值) item.original_tax_fee = originalTaxFeeRounded.toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber(); item.tax_fee = taxFeeRounded.toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber(); // 累加到总税费(乘以数量) preciseOriginTax = preciseOriginTax.plus(originalTaxFeePrecise.times(quantity)).plus(addTimePreciseTax); preciseTax = preciseTax.plus(taxFeePrecise.times(quantity)).plus(addTimePreciseTax); roundedOriginTax = roundedOriginTax.plus(originalTaxFeeRounded.times(quantity)).plus(addTimeRoundedTax); roundedTax = roundedTax.plus(taxFeeRounded.times(quantity)).plus(addTimeRoundedTax); } // 计算期望的总税费(精确累加后四舍五入) } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var expectedOriginTax = preciseOriginTax.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); var expectedTax = preciseTax.toDecimalPlaces(2, Decimal.ROUND_HALF_UP); // 计算舍入差值 var originTaxRemainder = expectedOriginTax.minus(roundedOriginTax).toNumber(); var taxRemainder = expectedTax.minus(roundedTax).toNumber(); // 将差值追加到最后一个含税商品 if (lastTaxableItem) { if (originTaxRemainder !== 0) { if (lastTaxableItem.type === 'main') { lastTaxableItem.item.original_tax_fee_rounding_remainder = originTaxRemainder; } else { lastTaxableItem.item.original_tax_fee_rounding_remainder = originTaxRemainder; } } if (taxRemainder !== 0) { if (lastTaxableItem.type === 'main') { lastTaxableItem.item.tax_fee_rounding_remainder = taxRemainder; } else { lastTaxableItem.item.tax_fee_rounding_remainder = taxRemainder; } } } return { originTax: expectedOriginTax, tax: expectedTax }; }; /** * 计算单个商品的税费(返回精确值,不四舍五入) * @param item 商品信息 * @param state 状态 * @param options 选项 * @returns 精确的税费值(Decimal类型) */ var getProductItemTax = function getProductItemTax(item, state, options) { var _ref4, _item$quantity, _bookingDetail$tax_ra, _ref5, _bookingDetail$is_pri; var bookingDetail = state.bookingDetail; var tax_rate = options.tax_rate, is_price_include_tax = options.is_price_include_tax; // 折扣后的金额 = 商品金额 - 商品折扣 var productDiscountPrice = new Decimal(item.total || 0); /** * 注意:该函数被多处以“单件税费”方式调用(调用方会显式传入 quantity: 1), * 因此这里必须优先使用 `item.quantity`,否则会出现数量被重复相乘(外层再乘一次 num)的情况。 */ var quantity = new Decimal((_ref4 = (_item$quantity = item.quantity) !== null && _item$quantity !== void 0 ? _item$quantity : item.num) !== null && _ref4 !== void 0 ? _ref4 : 1); // 如果商品金额小于或等于0,不计算税费 if (productDiscountPrice.lte(0)) { return new Decimal(0); } // 优先从 bookingDetail 取税率和是否含税设置,取不到则从 options 中取(兼容新增模式) // 注意:bookingDetail中的tax_rate不需要除以100,options 中的tax_rate需要除以100 var currentTaxRate = new Decimal((_bookingDetail$tax_ra = bookingDetail === null || bookingDetail === void 0 ? void 0 : bookingDetail.tax_rate) !== null && _bookingDetail$tax_ra !== void 0 ? _bookingDetail$tax_ra : tax_rate ? tax_rate / 100 : 0); var currentIsPriceIncludeTax = (_ref5 = (_bookingDetail$is_pri = bookingDetail === null || bookingDetail === void 0 ? void 0 : bookingDetail.is_price_include_tax) !== null && _bookingDetail$is_pri !== void 0 ? _bookingDetail$is_pri : is_price_include_tax) !== null && _ref5 !== void 0 ? _ref5 : 0; var singleItemTax = new Decimal(0); // 计算单个商品税费, 一次性商品 is_charge_tax 可能为空 if (item.is_charge_tax === 0 || !item.is_charge_tax) { // 该商品不需要收税 singleItemTax = new Decimal(0); } else { // 该商品需要收税 if (currentIsPriceIncludeTax === 0) { // 价格不含税:管理端填写的单价是不含税的价格 singleItemTax = productDiscountPrice.times(currentTaxRate); } else { // 价格含税:管理端填写的单价是含税的价格 // 含税总价 = 不含税价 + (不含税价 * 税率) = 不含税价 * (1 + 税率) // 商品不含税价 = 含税总价 / (1 + 税率) // 税 = 不含税价 * 税率 var divisor = new Decimal(1).plus(currentTaxRate); if (divisor.lte(0)) { // 如果 (1 + 税率) <= 0,说明税率异常,不计算税费 singleItemTax = new Decimal(0); } else { singleItemTax = productDiscountPrice.dividedBy(divisor).times(currentTaxRate); } } } // 结果 = 单个商品税费 × 数量(返回精确值,不四舍五入) return singleItemTax.times(quantity); }; /** * 计算商品小计(不含其他费用) * @param items - 购物车商品数组 * @returns 商品总价字符串,保留2位小数 */ export var calculateSubtotal = function calculateSubtotal(items) { if (!(items !== null && items !== void 0 && items.length)) { return '0.00'; } var subtotal = items.reduce(function (sum, item) { var cartItemTotalPrice = new Decimal(item.summaryTotal || 0); var productDiscountProductDiscountDifference = getProductDiscountProductDiscountDifference(item); return sum.plus(cartItemTotalPrice).sub(productDiscountProductDiscountDifference); }, new Decimal(0)); return subtotal.toFixed(2); }; /** * 计算商品小计(不含其他费用 不包含折扣卡商品券抵扣金额) * @param items - 购物车商品数组 * @returns 商品总价字符串,保留2位小数 */ export var calculateOriginSubtotal = function calculateOriginSubtotal(items) { if (!(items !== null && items !== void 0 && items.length)) { return '0.00'; } var subtotal = items.reduce(function (sum, item) { var cartItemTotalPrice = new Decimal(item.summaryOriginTotal || 0); return sum.plus(cartItemTotalPrice); }, new Decimal(0)); return subtotal.toFixed(2); }; /** * @title: 单个商品的税费 * @description: * 单个商品的税费 = 商品销售单价(折扣后) * 税率 * is_charge_tax /( 1+ 税率 * is_price_include_tax) * $taxFee = $price * $taxRate * $isChargeTax / (1 + $taxRate * $isPriceIncludeTax); * @return {*} * @Author: xiangfeng.xue */ export var calculateTaxFee = function calculateTaxFee(shopInfo, items) { if (!(items !== null && items !== void 0 && items.length)) { return '0.00'; } var _ref6 = shopInfo || {}, is_price_include_tax = _ref6.is_price_include_tax, tax_rate = _ref6.tax_rate; var totalTaxFee = items.reduce(function (sum, item) { var cartItemTotalPrice = new Decimal(item.summaryTotal || 0); var taxRate = new Decimal(tax_rate || 0).div(100); var productTaxRate = cartItemTotalPrice.times(taxRate).times((item === null || item === void 0 ? void 0 : item.is_charge_tax) || 0).div(taxRate.times(is_price_include_tax || 0).plus(1)); return sum.plus(productTaxRate); }, new Decimal(0)); return totalTaxFee; }; /** * @title: 计算定金 * @param items - 购物车商品数组 * @returns 定金字符串,保留2位小数 */ export var calculateDeposit = function calculateDeposit(items) { if (!(items !== null && items !== void 0 && items.length)) { return undefined; } var protocols = []; var hasDeposit = false; var total = items.reduce(function (sum, item) { if (item !== null && item !== void 0 && item.deposit) { var _item$deposit, _item$deposit2; hasDeposit = true; var cartItemTotalPrice = new Decimal((item === null || item === void 0 || (_item$deposit = item.deposit) === null || _item$deposit === void 0 ? void 0 : _item$deposit.total) || 0); // 将协议数据去重合并 item === null || item === void 0 || (_item$deposit2 = item.deposit) === null || _item$deposit2 === void 0 || (_item$deposit2 = _item$deposit2.protocols) === null || _item$deposit2 === void 0 || _item$deposit2.forEach(function (protocol) { if (protocols.findIndex(function (p) { return p.id === protocol.id; }) === -1) { protocols.push(protocol); } }); return sum.plus(cartItemTotalPrice); } return sum; }, new Decimal(0)); if (hasDeposit) { return { total: total.toFixed(2), protocols: protocols, hasDeposit: hasDeposit }; } return undefined; }; /** * 计算订单附加费金额(订单级别合计)。 * * - **详情未编辑**(`!options.isEdit && bookingId`)且存在后端详情时:直接返回 `bookingDetail.surcharge_fee` * - **新增/编辑**时:对 `surcharge`(通常为 `getSurcharge` 的返回值)按 `item.value` 求和 * * @param params 入参集合(RORO) * @param params.bookingDetail 订单详情(详情未编辑时用于读取后端的 `surcharge_fee`),可选 * @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选 * @param surcharge 附加费列表(通常来自 `getSurcharge`),元素结构至少包含 `value: number` * @param options 计算选项 * @param options.isEdit 是否处于“编辑中”。`false` 时会优先走后端金额直取逻辑(若存在) * @returns 订单附加费金额(number,金额单位与商品价格一致) */ export var getSurchargeAmount = function getSurchargeAmount(_ref7, surcharge, options) { var bookingDetail = _ref7.bookingDetail, bookingId = _ref7.bookingId; var isEdit = options.isEdit; // 订单未变更过 if (!isEdit) { // 有后端数据则直接使用后端的数据 if (bookingDetail && bookingId) { return Number(bookingDetail.surcharge_fee); } } if (!Array.isArray(surcharge)) return 0; // 新增状态使用 getSurcharge 的返回值进行求和 return surcharge.reduce(function (total, item) { return total + (item.value || 0); }, 0); }; // bundle商品是否是原价 var getBundleItemIsOriginalPrice = function getBundleItemIsOriginalPrice(item) { return (item === null || item === void 0 ? void 0 : item.price_type) === 'markup' && (item === null || item === void 0 ? void 0 : item.price_type_ext) === 'product_price'; }; // bundle商品是否是加价 var getBundleItemIsMarkupPrice = function getBundleItemIsMarkupPrice(item) { return (item === null || item === void 0 ? void 0 : item.price_type) === 'markup' && ((item === null || item === void 0 ? void 0 : item.price_type_ext) === '' || !(item !== null && item !== void 0 && item.price_type_ext)); }; // bundle商品是否是减价 var getBundleItemIsDiscountPrice = function getBundleItemIsDiscountPrice(item) { return (item === null || item === void 0 ? void 0 : item.price_type) === 'markdown' && ((item === null || item === void 0 ? void 0 : item.price_type_ext) === '' || !(item !== null && item !== void 0 && item.price_type_ext)); }; // bundle商品是否是加价或减价 var getBundleItemIsMarkupOrDiscountPrice = function getBundleItemIsMarkupOrDiscountPrice(item) { return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item); }; var getDiscountAmount = function getDiscountAmount(discounts) { return (discounts || []).reduce(function (total, discount) { return total.add(new Decimal(discount.amount || 0)); }, new Decimal(0)).toNumber(); }; /** * 获取主商品加价减价后的总价 (主商品价格 + 子商品加价减价) */ var getMainProductTotal = function getMainProductTotal(item) { var _ref8, _ref9, _item$main_product_se, _item$metadata, _item$_origin3, _item$_originData; var total = new Decimal((_ref8 = (_ref9 = (_item$main_product_se = item === null || item === void 0 ? void 0 : item.main_product_selling_price) !== null && _item$main_product_se !== void 0 ? _item$main_product_se : item === null || item === void 0 || (_item$metadata = item.metadata) === null || _item$metadata === void 0 ? void 0 : _item$metadata.main_product_selling_price) !== null && _ref9 !== void 0 ? _ref9 : item.price) !== null && _ref8 !== void 0 ? _ref8 : 0); var discount = (item === null || item === void 0 || (_item$_origin3 = item._origin) === null || _item$_origin3 === void 0 || (_item$_origin3 = _item$_origin3.product) === null || _item$_origin3 === void 0 ? void 0 : _item$_origin3.discount_list) || (item === null || item === void 0 || (_item$_originData = item._originData) === null || _item$_originData === void 0 || (_item$_originData = _item$_originData.product) === null || _item$_originData === void 0 || (_item$_originData = _item$_originData.discount_list) === null || _item$_originData === void 0 ? void 0 : _item$_originData.filter(function (item) { var _item$metadata2; return !(item !== null && item !== void 0 && (_item$metadata2 = item.metadata) !== null && _item$metadata2 !== void 0 && _item$metadata2.custom_product_bundle_map_id); })) || []; var mainProductDiscountAmount = getDiscountAmount(discount); total = total.minus(mainProductDiscountAmount); // 单规格 if (item !== null && item !== void 0 && item.option && Array.isArray(item === null || item === void 0 ? void 0 : item.option)) { total = total.add(item === null || item === void 0 ? void 0 : item.option.reduce(function (t, option) { return t.add(new Decimal(option.price || 0).mul(option.num || 1)); }, new Decimal(0))); } var _iterator4 = _createForOfIteratorHelper((item === null || item === void 0 ? void 0 : item.bundle) || []), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var bundleItem = _step4.value; if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) { var _ref10, _bundleItem$bundle_se2; // IMPORTANT: 套餐子商品如果应用了 discount,bundle_selling_price和 price 其实都已经是折后价格了,不需要单独再减一次 var bundleItemTotal = new Decimal((_ref10 = (_bundleItem$bundle_se2 = bundleItem.bundle_selling_price) !== null && _bundleItem$bundle_se2 !== void 0 ? _bundleItem$bundle_se2 : bundleItem.price) !== null && _ref10 !== void 0 ? _ref10 : 0); total = total.add(bundleItemTotal); } } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } return total.toNumber(); }; /** * 判断商品是否符合附加费条件 */ var isProductMatchSurchargeCondition = function isProductMatchSurchargeCondition(item, options) { var isInScheduleByDate = options === null || options === void 0 ? void 0 : options.isInScheduleByDate; var surchargeConfig = options.surchargeConfig, _options$scheduleById = options.scheduleById, scheduleById = _options$scheduleById === void 0 ? {} : _options$scheduleById; var startDate = item.startDate, product_id = item.product_id, isCustomItem = item.isCustomItem; var _surchargeConfig$open = surchargeConfig.open_product, open_product = _surchargeConfig$open === void 0 ? 0 : _surchargeConfig$open, _surchargeConfig$is_a = surchargeConfig.is_all, is_all = _surchargeConfig$is_a === void 0 ? 0 : _surchargeConfig$is_a, _surchargeConfig$avai = surchargeConfig.available_product_ids, available_product_ids = _surchargeConfig$avai === void 0 ? [] : _surchargeConfig$avai, _surchargeConfig$open2 = surchargeConfig.open_schedule, open_schedule = _surchargeConfig$open2 === void 0 ? 0 : _surchargeConfig$open2, schedule_type = surchargeConfig.schedule_type, _surchargeConfig$avai2 = surchargeConfig.available_schedule_ids, available_schedule_ids = _surchargeConfig$avai2 === void 0 ? [] : _surchargeConfig$avai2; // 判断商品是否符合条件 var isProductMatch = false; if (open_product === 0) { // 未开启商品限制,所有商品都符合 isProductMatch = true; } else { // 开启了商品限制 if (is_all === 1) { // 所有商品都收取附加费 isProductMatch = true; } else { // 指定商品收取附加费 if (isCustomItem) { // 自定义商品:如果是指定商品模式,自定义商品不符合条件 // 因为自定义商品没有 product_id,无法匹配到指定商品列表 isProductMatch = false; } else { // 普通商品:检查是否在指定商品列表中 isProductMatch = available_product_ids.includes(product_id); } } } // 判断日程是否符合条件 var isScheduleMatch = false; if (open_schedule === 0) { // 未开启日程限制,所有日程都符合 isScheduleMatch = true; } else { // 开启了日程限制 if (schedule_type === 'all') { // 所有日程都收取附加费 isScheduleMatch = true; } else { // 指定日程收取附加费 for (var j = 0; j < available_schedule_ids.length; j++) { var scheduleId = available_schedule_ids[j]; var schedule = scheduleById[scheduleId]; if (schedule) { var isInSchedule = isInScheduleByDate({ // date: startDate?.format('YYYY-MM-DD HH:mm:ss') || '', date: startDate || '', schedule: schedule }); if (isInSchedule) { isScheduleMatch = true; break; } } } } } // 商品和日程条件都要满足(取交集) return isProductMatch && isScheduleMatch; }; /** * 订单附加费各项信息 * * - **详情未编辑**(`!options.isEdit && bookingId`)时:直接返回 `bookingDetail.surcharge`(后端计算结果) * - **新增/编辑**时:按 `options.surcharge_list` 逐条配置计算本次订单的附加费 * * 规则要点: * - 匹配范围包含:主商品(`service`)、原价 bundle 子商品(`item.bundle`)、加时商品(`item.relation_details`)、以及 addons(`addons.value`) * - 固定附加费 `fixed`:只加一次,再按商品数量分摊(向下取整保留两位),剩余小数会以 `surcharge_rounding_remainder` 形式抹平到最后一个商品 * - 百分比附加费 `percentage`:按每个商品(价格 * 数量)分别计算再累加 * - 当 `open_product === 0`:不回写到商品,只在订单级别累加;否则会把单品附加费回写到商品 * * **副作用(可能修改入参商品对象)**: * - 当 `open_product !== 0` 时:写入 `item.surcharge_fee`(单品单数量附加费,保留两位、向下取整) * - 写入 `item.relation_surcharge_ids`(关联到的 surcharge 配置 id 列表) * - 写入 `item.surcharge_rounding_remainder`(用于抹平固定附加费/总额舍入差) * * @param params 入参集合(RORO) * @param params.service 服务商品数组(主商品)。元素可能包含 `bundle` / `relation_details` * @param params.addons 附加商品容器。当前实现读取 `addons.value` 作为商品数组(所以通常传 `{ value: CartItem[] }`) * @param params.bookingDetail 订单详情(详情未编辑时用于直接取后端的 surcharge 列表),可选 * @param params.bookingId 订单/预约 ID(详情未编辑时生效),可选 * @param options 计算选项 * @param options.isEdit 是否处于“编辑中”。`false` 且存在 `bookingId` 时会走详情直取逻辑 * @param options.surcharge_list 附加费配置列表(后端下发)。缺失/为空则返回空数组 * @param options.isInScheduleByDate 判断日期是否落在某个 schedule 内的方法(通常来自 ScheduleModule) * @param options.scheduleById schedule 映射表:`{ [scheduleId]: schedule }`(用于根据配置的 `available_schedule_ids` 做日程匹配) * @returns 附加费列表(仅返回金额 > 0 的项) */ export var getSurcharge = function getSurcharge(_ref11, options) { var _service$filter; var service = _ref11.service, addons = _ref11.addons, bookingDetail = _ref11.bookingDetail, bookingId = _ref11.bookingId; var isEdit = options.isEdit, isInScheduleByDate = options.isInScheduleByDate, surcharge_list = options.surcharge_list, scheduleById = options.scheduleById; // 在所有商品里试着找 start_date,如果没有则用当前时间 var firstAppointmentCartItem = (_service$filter = service.filter(function (n) { return !isNormalProduct(n._productOrigin); })) === null || _service$filter === void 0 ? void 0 : _service$filter[0]; var startDate = ''; if (firstAppointmentCartItem) { startDate = firstAppointmentCartItem.start_date + ' ' + firstAppointmentCartItem.start_time + ':00'; } else { startDate = dayjs().format('YYYY-MM-DD HH:mm:ss'); } // 编辑状态, 且未修改商品时直接从详情取出 if (!isEdit && bookingId) { if (Array.isArray(bookingDetail === null || bookingDetail === void 0 ? void 0 : bookingDetail.surcharge)) { return ((bookingDetail === null || bookingDetail === void 0 ? void 0 : bookingDetail.surcharge) || []).filter(function (d) { return Number(d.amount) > 0; }).map(function (d, index) { return { key: "custom_surcharge_".concat(index), // label: // d.name[state.locale || 'en'] || // d.name['en'] || // d.name['original'], label: d.name, value: d.amount, name: d.name, surcharge_id: d.id, description: d.description, // 后端说这个固定传 default type: 'default', fixed: d.fixed, amount: d.amount, percentage: d.percentage }; }); } return []; } // 用于“计算总价”的场景:每次调用都应重新计算(避免重复调用导致 surcharge_fee 累加) // 注意:同一次调用内仍会在多条 surcharge 配置之间累加 resetItemsSurchargeSideEffects({ service: service, addons: addons }); // 无附加费规则 if (!Array.isArray(surcharge_list) || !(surcharge_list !== null && surcharge_list !== void 0 && surcharge_list.length)) return []; // 分别计算每种附加费总和 var surchargeWithAmount = []; // 遍历每种附加费配置 for (var i = 0; i < surcharge_list.length; i++) { var surchargeConfig = surcharge_list[i]; var _surchargeConfig$perc = surchargeConfig.percentage, percentage = _surchargeConfig$perc === void 0 ? '0' : _surchargeConfig$perc, _surchargeConfig$fixe = surchargeConfig.fixed, fixed = _surchargeConfig$fixe === void 0 ? '0' : _surchargeConfig$fixe, id = surchargeConfig.id, type = surchargeConfig.type, description = surchargeConfig.description, open_product = surchargeConfig.open_product; // 收集所有符合条件的商品 var matchedItems = []; // 检查service中符合条件的商品 if (Array.isArray(service)) { var _iterator5 = _createForOfIteratorHelper(service), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { var item = _step5.value; // 主商品符合附加费条件 if (isProductMatchSurchargeCondition({ isCustomItem: item.isCustomItem, startDate: startDate, product_id: item.id }, { surchargeConfig: surchargeConfig, scheduleById: scheduleById || {}, isInScheduleByDate: isInScheduleByDate })) { // 主商品加价减价后的总价 var total = getMainProductTotal(_objectSpread(_objectSpread({}, item), {}, { option: (item === null || item === void 0 ? void 0 : item.option) || (item === null || item === void 0 ? void 0 : item.options) || [], bundle: (item === null || item === void 0 ? void 0 : item.bundle) || (item === null || item === void 0 ? void 0 : item.bundles) || [] })); var mainQuantity = item.num || 1; matchedItems.push({ total: total, // addTimeTotal: getRelationDetailsTotal( // item._extend.relation_details || [] // ), isMain: true, quantity: mainQuantity, item: item, mainQuantity: mainQuantity // 主商品的mainQuantity等于自己的quantity }); } var arr = (item === null || item === void 0 ? void 0 : item.bundle) || (item === null || item === void 0 ? void 0 : item.bundles) || []; // 遍历子商品 原价商品符合附加费条件 var _iterator6 = _createForOfIteratorHelper(arr), _step6; try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { var bundleItem = _step6.value; // bundle商品是原价且符合附加费条件 if (getBundleItemIsOriginalPrice(bundleItem) && isProductMatchSurchargeCondition({ isCustomItem: false, startDate: startDate, product_id: bundleItem._bundle_product_id }, { surchargeConfig: surchargeConfig, scheduleById: scheduleById || {}, isInScheduleByDate: isInScheduleByDate })) { var _ref12, _bundleItem$bundle_se3; var _mainQuantity = item.num || 1; matchedItems.push({ isMain: false, total: Number((_ref12 = (_bundleItem$bundle_se3 = bundleItem.bundle_selling_price) !== null && _bundleItem$bundle_se3 !== void 0 ? _bundleItem$bundle_se3 : bundleItem.price) !== null && _ref12 !== void 0 ? _ref12 : 0), quantity: bundleItem.num || bundleItem.quantity || 1, item: bundleItem, mainQuantity: _mainQuantity // 子商品的mainQuantity是所属主商品的quantity }); } } // 加时商品符合附加费条件 } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } var _iterator7 = _createForOfIteratorHelper(item.relation_details || []), _step7; try { for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { var relationDetail = _step7.value; if (isProductMatchSurchargeCondition({ isCustomItem: false, startDate: startDate, product_id: relationDetail.product_id }, { surchargeConfig: surchargeConfig, scheduleById: scheduleById || {}, isInScheduleByDate: isInScheduleByDate })) { var _relationDetail$metad; matchedItems.push({ isMain: false, total: Number((relationDetail === null || relationDetail === void 0 ? void 0 : relationDetail.price) || (relationDetail === null || relationDetail === void 0 || (_relationDetail$metad = relationDetail.metadata) === null || _relationDetail$metad === void 0 ? void 0 : _relationDetail$metad.main_product_attached_bundle_selling_price)), quantity: relationDetail.num || relationDetail.quantity || 1, item: relationDetail, mainQuantity: 1 // 加时商品不受主商品数量影响 }); } } } catch (err) { _iterator7.e(err); } finally { _iterator7.f(); } } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } } // 检查addons中符合条件的商品 if (Array.isArray(addons === null || addons === void 0 ? void 0 : addons.value)) { var _iterator8 = _createForOfIteratorHelper(addons.value), _step8; try { for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { var _item = _step8.value; if (isProductMatchSurchargeCondition(_objectSpread(_objectSpread({}, _item), {}, { startDate: startDate }), { surchargeConfig: surchargeConfig, scheduleById: scheduleById || {}, isInScheduleByDate: isInScheduleByDate })) { matchedItems.push({ isMain: true, total: Number(_item.total), quantity: _item.num || 1, item: _item, mainQuantity: 1 // addons独立商品,mainQuantity为1 }); } } } catch (err) { _iterator8.e(err); } finally { _iterator8.f(); } } var finalAmount = 0; // 计算商品总数:主商品和addons按quantity计算,子商品(bundle item)需要乘以主商品数量 var productCount = matchedItems.reduce(function (total, item) { if (item.isMain) { // 主商品和addons商品 return total + (item.num || item.quantity || 1); } else { // 子商品(bundle item)和加时商品 // 加时商品的 mainQuantity = 1,所以不受影响 // bundle item 的 mainQuantity = 主商品数量,需要乘以实际数量 return total + (item.num || item.quantity || 1) * (item.mainQuantity || 1); } }, 0); // 追加进入的固定附加费总值 var fixedTotal = new Decimal(0); // 追加到商品的附加费总值 用于追加抹平字段 var productTotalSurcharge = new Decimal(0); if (matchedItems.length > 0) { // 基于每个商品计算附加费:max(0, 商品价格) * rate + fixed var configTotal = new Decimal(0); // 计算固定附加费 - 只加一次 if (fixed && new Decimal(fixed).gt(0)) { configTotal = configTotal.plus(fixed); } // 计算百分比附加费 - 对每个商品单独计算 if (percentage && new Decimal(percentage).gt(0) || fixed) { var percentageRate = new Decimal(percentage); var _iterator9 = _createForOfIteratorHelper(matchedItems.entries()), _step9; try { for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { var _step9$value = _slicedToArray(_step9.value, 2), index = _step9$value[0], _item2 = _step9$value[1]; var isLast = index === matchedItems.length - 1; // 对每个商品:max(0, 价格) * 数量 * 费率 var itemPrice = new Decimal(Math.max(0, _item2.total || 0)); var itemQuantity = new Decimal(_item2.isMain ? _item2.quantity || 1 : _item2.quantity * _item2.mainQuantity || 1); var addTimeTotal = new