@pisell/pisellos 0.0.567 → 0.0.568
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.js +6 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +1 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +14 -41
- package/dist/modules/Payment/index.js +142 -270
- package/dist/modules/Payment/walletpass.js +4 -5
- package/dist/modules/Rules/index.js +0 -7
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +88 -121
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/products/index.js +29 -49
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +32 -40
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +5 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -246
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.d.ts +5 -0
- package/dist/solution/VenueBooking/index.js +364 -327
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +130 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +92 -53
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +84 -63
- package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
- package/lib/model/strategy/adapter/promotion/examples.js +139 -159
- package/lib/model/strategy/adapter/promotion/index.js +1 -49
- package/lib/model/strategy/adapter/promotion/type.js +199 -35
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +652 -402
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +22 -45
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +306 -241
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +72 -78
- package/lib/modules/Cart/utils/changePrice.js +26 -62
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +216 -153
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +117 -113
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +63 -74
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +332 -320
- package/lib/modules/Order/types.js +24 -33
- package/lib/modules/Order/utils.js +350 -284
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +566 -432
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +216 -107
- package/lib/modules/Payment/utils.js +50 -47
- package/lib/modules/Payment/walletpass.js +221 -203
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +111 -110
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +60 -82
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/Rules/index.js +1172 -872
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +59 -68
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +176 -193
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -167
- package/lib/modules/Schedule/index.js +97 -107
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -70
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +782 -429
- package/lib/modules/index.js +212 -57
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +882 -623
- package/lib/server/modules/index.js +85 -59
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +195 -231
- package/lib/server/modules/order/types.js +107 -32
- package/lib/server/modules/order/utils/filterBookings.js +174 -140
- package/lib/server/modules/order/utils/filterOrders.js +89 -60
- package/lib/server/modules/products/index.js +430 -335
- package/lib/server/modules/products/types.js +41 -34
- package/lib/server/modules/quotation/index.js +76 -77
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +216 -187
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +134 -119
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1530 -1343
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +147 -122
- package/lib/solution/BookingTicket/types.js +38 -64
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
- package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +227 -158
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +218 -200
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +803 -840
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.js +372 -331
- package/lib/solution/ShopDiscount/index.js +230 -236
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +309 -172
- package/lib/solution/VenueBooking/index.d.ts +5 -0
- package/lib/solution/VenueBooking/index.js +886 -929
- package/lib/solution/VenueBooking/types.js +20 -40
- package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
- package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +102 -37
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,58 +1,32 @@
|
|
|
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/Rules/index.ts
|
|
30
|
-
var Rules_exports = {};
|
|
31
|
-
__export(Rules_exports, {
|
|
32
|
-
RulesModule: () => RulesModule
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
33
5
|
});
|
|
34
|
-
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
6
|
+
exports.RulesModule = void 0;
|
|
7
|
+
var _BaseModule = require("../BaseModule");
|
|
8
|
+
var _types = require("./types");
|
|
9
|
+
var _utils = require("../../solution/ShopDiscount/utils");
|
|
10
|
+
var _utils2 = require("../Cart/utils");
|
|
11
|
+
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
12
|
+
var _lodashEs = require("lodash-es");
|
|
13
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
class RulesModule extends _BaseModule.BaseModule {
|
|
16
|
+
defaultName = 'rules';
|
|
17
|
+
defaultVersion = '1.0.0';
|
|
18
|
+
store;
|
|
19
|
+
window; // WindowPlugin 实例
|
|
20
|
+
hooks;
|
|
45
21
|
constructor(name, version) {
|
|
46
22
|
super(name, version);
|
|
47
|
-
this.defaultName = "rules";
|
|
48
|
-
this.defaultVersion = "1.0.0";
|
|
49
23
|
this.hooks = {};
|
|
50
24
|
}
|
|
51
25
|
async initialize(core, options) {
|
|
52
26
|
this.core = core;
|
|
53
|
-
this.hooks = options
|
|
54
|
-
this.store = options
|
|
55
|
-
this.window = core.getPlugin(
|
|
27
|
+
this.hooks = options?.hooks;
|
|
28
|
+
this.store = options?.store;
|
|
29
|
+
this.window = core.getPlugin('window');
|
|
56
30
|
}
|
|
57
31
|
async setRulesList(rulesList) {
|
|
58
32
|
this.store.rulesList = rulesList;
|
|
@@ -62,22 +36,24 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
62
36
|
return this.store.rulesList;
|
|
63
37
|
}
|
|
64
38
|
getWalletPassEvaluator() {
|
|
65
|
-
|
|
66
|
-
return (_b = (_a = this.window).getWalletPassEvaluator) == null ? void 0 : _b.call(_a);
|
|
39
|
+
return this.window.getWalletPassEvaluator?.();
|
|
67
40
|
}
|
|
41
|
+
|
|
68
42
|
// 商品不需要holder,则不需要判断,直接返回true,商品需要holder但是还没填写,那么暂时不使用带有holder的券,直到填写才去匹配
|
|
69
43
|
checkHolderMatch(discount, product, holders) {
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
const orderHolderId = Array.isArray(holders) && holders.length > 0 ? holders[0].form_record_id :
|
|
44
|
+
// 非表单类型 holder 视为匹配
|
|
45
|
+
if (discount.holder?.holder_type !== 'form') return true;
|
|
46
|
+
// 主预约holder, 目前(20251124)默认只考虑单个holder的情况
|
|
47
|
+
const orderHolderId = Array.isArray(holders) && holders.length > 0 ? holders[0].form_record_id : undefined;
|
|
74
48
|
const productHolderId = Array.isArray(product.holder_id) ? product.holder_id[0] : product.holder_id;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
// 商品不需要选holder,则不对比holder,直接返回true,
|
|
50
|
+
if (!product.isNeedHolder) return true;
|
|
51
|
+
// 商品需要holder,但父预约及商品都无holder,返回false
|
|
52
|
+
if (!orderHolderId && !productHolderId) return false;
|
|
53
|
+
// 最终直接匹配 holder 是否相同
|
|
79
54
|
return (productHolderId || orderHolderId) === discount.holder.holder_id;
|
|
80
55
|
}
|
|
56
|
+
|
|
81
57
|
// 判断discountList 是否可以对当前productList生效
|
|
82
58
|
isDiscountListAvailable({
|
|
83
59
|
oldDiscountList,
|
|
@@ -87,6 +63,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
87
63
|
holders,
|
|
88
64
|
isFormSubject
|
|
89
65
|
}) {
|
|
66
|
+
// 首先检查是否有新的优惠券可应用
|
|
90
67
|
if (!newDiscountList || newDiscountList.length === 0) {
|
|
91
68
|
return {
|
|
92
69
|
isAvailable: false,
|
|
@@ -94,25 +71,24 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
94
71
|
productList
|
|
95
72
|
};
|
|
96
73
|
}
|
|
97
|
-
|
|
98
|
-
|
|
74
|
+
|
|
75
|
+
// 编辑商品已有商品券
|
|
76
|
+
if (productList.every(item => {
|
|
99
77
|
const product = this.hooks.getProduct(item);
|
|
100
|
-
return product.booking_id && (
|
|
78
|
+
return product.booking_id && (product.discount_list?.length || product.total == 0);
|
|
101
79
|
})) {
|
|
102
80
|
return {
|
|
103
81
|
isAvailable: false,
|
|
104
82
|
discountList: oldDiscountList,
|
|
105
83
|
productList,
|
|
106
|
-
unavailableReason:
|
|
84
|
+
unavailableReason: _types.UnavailableReason.AlreadyUsed
|
|
107
85
|
};
|
|
108
86
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
...newDiscountList
|
|
115
|
-
]);
|
|
87
|
+
|
|
88
|
+
// 合并新旧折扣列表,并计算折扣结果,注意,如果旧折扣里有 isEditMode 为 true 的优惠券,则不合并
|
|
89
|
+
// 保留之前扫码得到的商品券(isScan: true)
|
|
90
|
+
const filteredOldDiscountList = oldDiscountList.filter(discount => !discount.isEditMode && (discount.tag !== 'good_pass' || discount.isScan));
|
|
91
|
+
const mergedDiscountList = (0, _utils.uniqueById)([...filteredOldDiscountList, ...newDiscountList]);
|
|
116
92
|
const result = this.calcDiscount({
|
|
117
93
|
discountList: mergedDiscountList,
|
|
118
94
|
productList: [...productList],
|
|
@@ -122,26 +98,31 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
122
98
|
}, {
|
|
123
99
|
scan: true
|
|
124
100
|
});
|
|
101
|
+
|
|
102
|
+
// 检查是否有产品使用了新折扣
|
|
125
103
|
let hasApplicableDiscount = false;
|
|
126
|
-
const newDiscountIds = newDiscountList.map(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
104
|
+
const newDiscountIds = newDiscountList.map(discount => discount.id);
|
|
105
|
+
|
|
106
|
+
// 遍历处理后的产品列表,检查是否有产品使用了新折扣
|
|
107
|
+
result.productList.forEach(product => {
|
|
108
|
+
const {
|
|
109
|
+
discount_list,
|
|
110
|
+
bundle
|
|
111
|
+
} = this.hooks.getProduct(product);
|
|
112
|
+
const allDiscountList = [...(discount_list || [])];
|
|
113
|
+
(bundle || []).forEach(item => {
|
|
114
|
+
allDiscountList.push(...(item?.discount_list || []));
|
|
132
115
|
});
|
|
133
116
|
if (allDiscountList && allDiscountList.length > 0) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
var _a;
|
|
137
|
-
return newDiscountIds.includes((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id);
|
|
138
|
-
}
|
|
139
|
-
);
|
|
117
|
+
// 检查是否有使用新折扣的情况
|
|
118
|
+
const usedNewDiscount = allDiscountList.some(discount => newDiscountIds.includes(discount?.discount?.resource_id));
|
|
140
119
|
if (usedNewDiscount) {
|
|
141
120
|
hasApplicableDiscount = true;
|
|
142
121
|
}
|
|
143
122
|
}
|
|
144
123
|
});
|
|
124
|
+
|
|
125
|
+
// 如果券不可用,判断不可用原因
|
|
145
126
|
let unavailableReason;
|
|
146
127
|
if (!hasApplicableDiscount) {
|
|
147
128
|
unavailableReason = this.getUnavailableReason(newDiscountList, productList);
|
|
@@ -154,39 +135,42 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
154
135
|
};
|
|
155
136
|
}
|
|
156
137
|
filterDiscountListByType(discountList, type) {
|
|
157
|
-
return (discountList || []).filter(
|
|
138
|
+
return (discountList || []).filter(item => item.type === type || item.tag === type);
|
|
158
139
|
}
|
|
140
|
+
|
|
159
141
|
// 获取券不可用的原因
|
|
160
142
|
getUnavailableReason(discountList, productList) {
|
|
161
|
-
|
|
143
|
+
// 检查时间限制
|
|
162
144
|
for (const discount of discountList) {
|
|
163
145
|
for (const item of productList) {
|
|
164
146
|
const product = this.hooks.getProduct(item);
|
|
165
|
-
const bookingTime = (
|
|
166
|
-
const filteredList = (0,
|
|
147
|
+
const bookingTime = (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss');
|
|
148
|
+
const filteredList = (0, _utils.filterDiscountListByBookingTime)([discount], bookingTime);
|
|
167
149
|
if (filteredList.length === 0) {
|
|
168
|
-
return
|
|
150
|
+
return _types.UnavailableReason.TimeLimit;
|
|
169
151
|
}
|
|
170
152
|
}
|
|
171
153
|
}
|
|
154
|
+
|
|
155
|
+
// 检查商品适用性
|
|
172
156
|
for (const discount of discountList) {
|
|
173
157
|
const limitedData = discount.limited_relation_product_data;
|
|
174
158
|
let hasApplicableProduct = false;
|
|
175
159
|
for (const item of productList) {
|
|
176
160
|
const product = this.hooks.getProduct(item);
|
|
177
|
-
if (limitedData.type ===
|
|
161
|
+
if (limitedData.type === 'product_all') {
|
|
178
162
|
hasApplicableProduct = true;
|
|
179
163
|
break;
|
|
180
|
-
} else if (
|
|
164
|
+
} else if (limitedData.product_ids?.includes(product.id)) {
|
|
181
165
|
hasApplicableProduct = true;
|
|
182
166
|
break;
|
|
183
167
|
}
|
|
184
168
|
}
|
|
185
169
|
if (!hasApplicableProduct) {
|
|
186
|
-
return
|
|
170
|
+
return _types.UnavailableReason.ProductNotApplicable;
|
|
187
171
|
}
|
|
188
172
|
}
|
|
189
|
-
return
|
|
173
|
+
return _types.UnavailableReason.Unknown;
|
|
190
174
|
}
|
|
191
175
|
calcDiscount({
|
|
192
176
|
discountList,
|
|
@@ -197,36 +181,45 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
197
181
|
}, options) {
|
|
198
182
|
const editModeDiscount = [];
|
|
199
183
|
const addModeDiscount = [];
|
|
200
|
-
discountList.forEach(
|
|
184
|
+
discountList.forEach(discount => {
|
|
201
185
|
if (discount.isEditMode) {
|
|
202
186
|
editModeDiscount.push(discount);
|
|
203
187
|
} else {
|
|
204
188
|
addModeDiscount.push(discount);
|
|
205
189
|
}
|
|
206
190
|
});
|
|
207
|
-
|
|
208
|
-
editModeDiscount
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
191
|
+
|
|
192
|
+
// 🔥 检查 editModeDiscount 中是否有订单级别的折扣,如果有则禁用 addModeDiscount 中相同 product_id 的折扣卡
|
|
193
|
+
const editModeOrderLevelProductIds = new Set();
|
|
194
|
+
editModeDiscount.forEach(discount => {
|
|
195
|
+
if (discount.discount?.discount_calculation_mode === 'order_level') {
|
|
196
|
+
editModeOrderLevelProductIds.add(discount?.discount?.discount_product_id);
|
|
212
197
|
}
|
|
213
198
|
});
|
|
199
|
+
|
|
200
|
+
// 如果存在订单级别的编辑模式折扣,禁用 addModeDiscount 中相同 product_id 的折扣卡
|
|
214
201
|
if (editModeOrderLevelProductIds.size > 0) {
|
|
215
|
-
addModeDiscount.forEach(
|
|
202
|
+
addModeDiscount.forEach(discount => {
|
|
216
203
|
if (editModeOrderLevelProductIds.has(discount.product_id)) {
|
|
217
204
|
discount.isDisabled = true;
|
|
218
205
|
}
|
|
219
206
|
});
|
|
220
207
|
}
|
|
221
|
-
|
|
208
|
+
|
|
209
|
+
// 过滤掉手动取消false的优惠券,但仅用于应用优惠逻辑
|
|
210
|
+
const filteredDiscountList = addModeDiscount.filter(discount => {
|
|
222
211
|
return !discount.isManualSelect;
|
|
223
212
|
});
|
|
224
|
-
|
|
213
|
+
|
|
214
|
+
// 🔥 扁平化商品列表:将 bundle 子商品展开为虚拟商品
|
|
215
|
+
const flattenProductsWithBundle = productList => {
|
|
225
216
|
const flattened = [];
|
|
226
|
-
|
|
217
|
+
productList.forEach(originProduct => {
|
|
227
218
|
const product = this.hooks.getProduct(originProduct);
|
|
219
|
+
|
|
220
|
+
// 1. 添加主商品
|
|
228
221
|
flattened.push({
|
|
229
|
-
type:
|
|
222
|
+
type: 'main',
|
|
230
223
|
originProduct,
|
|
231
224
|
product,
|
|
232
225
|
price: Number(product.price || 0),
|
|
@@ -237,10 +230,12 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
237
230
|
num: product.num,
|
|
238
231
|
booking_id: product.booking_id
|
|
239
232
|
});
|
|
233
|
+
|
|
234
|
+
// 2. 展开 bundle 子商品
|
|
240
235
|
if (product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0) {
|
|
241
236
|
product.bundle.forEach((bundleItem, bundleIndex) => {
|
|
242
237
|
flattened.push({
|
|
243
|
-
type:
|
|
238
|
+
type: 'bundle',
|
|
244
239
|
originProduct,
|
|
245
240
|
parentProduct: product,
|
|
246
241
|
bundleItem,
|
|
@@ -253,8 +248,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
253
248
|
parentId: product._id,
|
|
254
249
|
num: bundleItem.num || 1,
|
|
255
250
|
quantity: bundleItem.num || 1,
|
|
256
|
-
total: new
|
|
257
|
-
origin_total: new
|
|
251
|
+
total: new _decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
|
|
252
|
+
origin_total: new _decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
|
|
258
253
|
original_price: bundleItem.original_price,
|
|
259
254
|
// 继承主商品属性
|
|
260
255
|
booking_id: bundleItem.booking_id,
|
|
@@ -265,121 +260,161 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
265
260
|
});
|
|
266
261
|
return flattened;
|
|
267
262
|
};
|
|
263
|
+
|
|
264
|
+
// 优惠力度排序,传进来的数据里可能有商品券,也可能有优惠券
|
|
265
|
+
// 新的优先级排序规则(从高到低):
|
|
266
|
+
// 1. 带有Holder的商品券(metadata?.holder?.type === 'custom' && tag === 'good_pass')
|
|
267
|
+
// 2. 带有Holder的商品级折扣卡(metadata?.holder?.type === 'custom' && tag === 'product_discount_card' && discount_calculation_mode !== 'order_level')
|
|
268
|
+
// 3. 带有Holder的订单级折扣卡(metadata?.holder?.type === 'custom' && tag === 'product_discount_card' && discount_calculation_mode === 'order_level')
|
|
269
|
+
// 4. Customer商品券(metadata?.holder?.type !== 'custom' && tag === 'good_pass')
|
|
270
|
+
// 5. Customer商品级折扣卡(metadata?.holder?.type !== 'custom' && tag === 'product_discount_card' && discount_calculation_mode !== 'order_level')
|
|
271
|
+
// 6. Customer订单级固定金额折扣(metadata?.holder?.type !== 'custom' && tag === 'product_discount_card' && discount_calculation_mode === 'order_level')
|
|
272
|
+
// 同一优先级内部:固定金额优先于百分比,金额/折扣力度越大越优先,最后按过期时间排序
|
|
268
273
|
const sortedDiscountList = [...filteredDiscountList].sort((a, b) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const isGoodPass =
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const getPriority =
|
|
274
|
+
// 辅助函数:判断是否是带有Holder的优惠券
|
|
275
|
+
const isHolderDiscount = discount => discount.metadata?.holder?.type === 'custom';
|
|
276
|
+
|
|
277
|
+
// 辅助函数:判断是否是商品券
|
|
278
|
+
const isGoodPass = discount => discount.tag === 'good_pass';
|
|
279
|
+
|
|
280
|
+
// 辅助函数:判断是否是订单级折扣卡
|
|
281
|
+
const isOrderLevelDiscount = discount => discount.tag === 'product_discount_card' && discount.metadata?.discount_calculation_mode === 'order_level';
|
|
282
|
+
|
|
283
|
+
// 辅助函数:判断是否是商品级折扣卡
|
|
284
|
+
const isItemLevelDiscount = discount => discount.tag === 'product_discount_card' && discount.metadata?.discount_calculation_mode !== 'order_level';
|
|
285
|
+
|
|
286
|
+
// 辅助函数:获取优先级(数字越小优先级越高)
|
|
287
|
+
const getPriority = discount => {
|
|
283
288
|
const isHolder = isHolderDiscount(discount);
|
|
284
289
|
if (isHolder) {
|
|
285
|
-
if (isGoodPass(discount))
|
|
286
|
-
|
|
287
|
-
if (
|
|
288
|
-
return 2;
|
|
289
|
-
if (isOrderLevelDiscount(discount))
|
|
290
|
-
return 3;
|
|
290
|
+
if (isGoodPass(discount)) return 1; // 带有Holder的商品券
|
|
291
|
+
if (isItemLevelDiscount(discount)) return 2; // 带有Holder的商品级折扣卡
|
|
292
|
+
if (isOrderLevelDiscount(discount)) return 3; // 带有Holder的订单级折扣卡
|
|
291
293
|
} else {
|
|
292
|
-
if (isGoodPass(discount))
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
return 5;
|
|
296
|
-
if (isOrderLevelDiscount(discount))
|
|
297
|
-
return 6;
|
|
294
|
+
if (isGoodPass(discount)) return 4; // Customer商品券
|
|
295
|
+
if (isItemLevelDiscount(discount)) return 5; // Customer商品级折扣卡
|
|
296
|
+
if (isOrderLevelDiscount(discount)) return 6; // Customer订单级固定金额折扣
|
|
298
297
|
}
|
|
299
|
-
return 7;
|
|
298
|
+
return 7; // 其他情况
|
|
300
299
|
};
|
|
300
|
+
|
|
301
|
+
// 辅助函数:按过期时间比较
|
|
301
302
|
function compareByExpireTime(itemA, itemB) {
|
|
302
303
|
if (itemA.expire_time && itemB.expire_time) {
|
|
303
304
|
const timeA = new Date(itemA.expire_time).getTime();
|
|
304
305
|
const timeB = new Date(itemB.expire_time).getTime();
|
|
305
306
|
return timeA - timeB;
|
|
306
307
|
}
|
|
308
|
+
// 有过期时间的优先级高于永久的
|
|
307
309
|
return itemA.expire_time ? -1 : itemB.expire_time ? 1 : 0;
|
|
308
310
|
}
|
|
311
|
+
|
|
312
|
+
// 辅助函数:同类型折扣卡内部排序(固定金额优先于百分比,金额/折扣力度排序)
|
|
309
313
|
function compareDiscountCardValue(itemA, itemB) {
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (typeA ===
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
const typeA = itemA.metadata?.discount_card_type || 'percent';
|
|
315
|
+
const typeB = itemB.metadata?.discount_card_type || 'percent';
|
|
316
|
+
|
|
317
|
+
// 1. 固定金额优先于百分比
|
|
318
|
+
if (typeA === 'fixed_amount' && typeB === 'percent') return -1;
|
|
319
|
+
if (typeA === 'percent' && typeB === 'fixed_amount') return 1;
|
|
320
|
+
|
|
321
|
+
// 2. 都是固定金额时,金额越大越优先
|
|
322
|
+
if (typeA === 'fixed_amount' && typeB === 'fixed_amount') {
|
|
318
323
|
if (itemA.par_value !== itemB.par_value) {
|
|
319
|
-
const valueA = new
|
|
320
|
-
const valueB = new
|
|
321
|
-
return valueB.minus(valueA).toNumber();
|
|
324
|
+
const valueA = new _decimal.default(itemA.par_value || 0);
|
|
325
|
+
const valueB = new _decimal.default(itemB.par_value || 0);
|
|
326
|
+
return valueB.minus(valueA).toNumber(); // 金额大的在前
|
|
322
327
|
}
|
|
323
328
|
}
|
|
324
|
-
|
|
329
|
+
|
|
330
|
+
// 3. 都是百分比时,折扣越大越优先(par_value越大越优先)
|
|
331
|
+
if (typeA === 'percent' && typeB === 'percent') {
|
|
325
332
|
if (itemA.par_value !== itemB.par_value) {
|
|
326
|
-
const valueA = new
|
|
327
|
-
const valueB = new
|
|
328
|
-
return valueA.minus(valueB).toNumber();
|
|
333
|
+
const valueA = new _decimal.default(100).minus(itemA.par_value || 0);
|
|
334
|
+
const valueB = new _decimal.default(100).minus(itemB.par_value || 0);
|
|
335
|
+
return valueA.minus(valueB).toNumber(); // 折扣大的在前
|
|
329
336
|
}
|
|
330
337
|
}
|
|
331
338
|
return 0;
|
|
332
339
|
}
|
|
340
|
+
|
|
341
|
+
// 1. 先按优先级排序
|
|
333
342
|
const priorityA = getPriority(a);
|
|
334
343
|
const priorityB = getPriority(b);
|
|
335
344
|
if (priorityA !== priorityB) {
|
|
336
345
|
return priorityA - priorityB;
|
|
337
346
|
}
|
|
347
|
+
|
|
348
|
+
// 2. 同一优先级内部排序
|
|
349
|
+
// 如果是商品券(优先级1或4),按过期时间排序
|
|
338
350
|
if (isGoodPass(a) && isGoodPass(b)) {
|
|
339
351
|
return compareByExpireTime(a, b);
|
|
340
352
|
}
|
|
341
|
-
|
|
353
|
+
|
|
354
|
+
// 如果是折扣卡(优先级2、3、5、6),按折扣力度排序,然后按过期时间
|
|
355
|
+
if (a.tag === 'product_discount_card' && b.tag === 'product_discount_card') {
|
|
342
356
|
const valueCompare = compareDiscountCardValue(a, b);
|
|
343
|
-
if (valueCompare !== 0)
|
|
344
|
-
return valueCompare;
|
|
357
|
+
if (valueCompare !== 0) return valueCompare;
|
|
345
358
|
return compareByExpireTime(a, b);
|
|
346
359
|
}
|
|
360
|
+
|
|
361
|
+
// 3. 其他情况按照过期时间排序
|
|
347
362
|
return compareByExpireTime(a, b);
|
|
348
363
|
});
|
|
364
|
+
|
|
365
|
+
// const newProductList = [];
|
|
366
|
+
//
|
|
367
|
+
// productList.forEach(item => {
|
|
368
|
+
// const product = this.hooks.getProduct(item);
|
|
369
|
+
// if (product.quantity > 1) {
|
|
370
|
+
// for (let i = 1; i < product.quantity; i++) {
|
|
371
|
+
// newProductList.push(product)
|
|
372
|
+
// }
|
|
373
|
+
// } else {
|
|
374
|
+
// newProductList.push(item)
|
|
375
|
+
// }
|
|
376
|
+
// })
|
|
377
|
+
|
|
378
|
+
// 🔥 扁平化商品列表(包含主商品和bundle子商品)
|
|
349
379
|
const flattenedList = flattenProductsWithBundle(productList);
|
|
350
|
-
|
|
380
|
+
|
|
381
|
+
// 识别出来是不是在编辑的界面里又新增了商品
|
|
382
|
+
// 这种情况下,如果有可用的优惠券,也会自动勾选上
|
|
383
|
+
const isEditModeAddNewProduct = flattenedList.find(n => n.booking_id) && flattenedList.find(n => !n.booking_id);
|
|
384
|
+
|
|
385
|
+
// 对扁平化后的列表按价格降序排序(用于应用优惠券时优先选择高价商品)
|
|
351
386
|
const sortedFlattenedList = flattenedList.sort((a, b) => {
|
|
352
|
-
|
|
353
|
-
const priceA = new
|
|
354
|
-
|
|
355
|
-
);
|
|
356
|
-
const priceB = new import_decimal.default(
|
|
357
|
-
b.type === "bundle" ? b.original_price ?? b.price ?? "0" : b.price || "0"
|
|
358
|
-
);
|
|
387
|
+
// 子商品优先使用 original_price,主商品使用 price
|
|
388
|
+
const priceA = new _decimal.default(a.type === 'bundle' ? a.original_price ?? a.price ?? '0' : a.price || '0');
|
|
389
|
+
const priceB = new _decimal.default(b.type === 'bundle' ? b.original_price ?? b.price ?? '0' : b.price || '0');
|
|
359
390
|
if (priceA.equals(priceB)) {
|
|
391
|
+
// 价格相同时,主商品优先
|
|
360
392
|
if (a.type !== b.type) {
|
|
361
|
-
return a.type ===
|
|
393
|
+
return a.type === 'main' ? -1 : 1;
|
|
362
394
|
}
|
|
363
|
-
|
|
395
|
+
// 都是主商品时,按原有逻辑排序
|
|
396
|
+
if (a.type === 'main' && b.type === 'main') {
|
|
364
397
|
if (a.product.quantity === b.product.quantity) {
|
|
365
|
-
return (
|
|
398
|
+
return (b.product.discount_list?.length || 0) - (a.product.discount_list?.length || 0);
|
|
366
399
|
}
|
|
367
400
|
return a.product.quantity - b.product.quantity;
|
|
368
401
|
}
|
|
369
|
-
|
|
402
|
+
// 都是bundle时,按数量排序
|
|
403
|
+
if (a.type === 'bundle' && b.type === 'bundle') {
|
|
370
404
|
return (a.num || 1) - (b.num || 1);
|
|
371
405
|
}
|
|
372
406
|
}
|
|
373
407
|
return priceB.minus(priceA).toNumber();
|
|
374
408
|
});
|
|
409
|
+
|
|
410
|
+
// 🔥 为每个折扣卡/商品券执行策略检查并附加config
|
|
375
411
|
const evaluator = this.getWalletPassEvaluator();
|
|
376
412
|
if (evaluator) {
|
|
377
|
-
addModeDiscount.forEach(
|
|
378
|
-
var _a, _b;
|
|
413
|
+
addModeDiscount.forEach(discount => {
|
|
379
414
|
const discountType = discount.tag || discount.type;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
415
|
+
// 只对 good_pass 和 discount_card 类型执行策略检查
|
|
416
|
+
if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
|
|
417
|
+
// 转换 discount 为 Voucher 格式
|
|
383
418
|
const voucher = {
|
|
384
419
|
id: discount.id,
|
|
385
420
|
amount: Number(discount.par_value || 0),
|
|
@@ -387,24 +422,27 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
387
422
|
type: discountType,
|
|
388
423
|
product_id: discount.product_id,
|
|
389
424
|
unified_available_status: 1,
|
|
390
|
-
available_product_type:
|
|
391
|
-
available_product_ids:
|
|
425
|
+
available_product_type: discount.limited_relation_product_data?.type,
|
|
426
|
+
available_product_ids: discount.limited_relation_product_data?.product_ids
|
|
392
427
|
};
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
428
|
+
|
|
429
|
+
// 转换 sortedFlattenedList 为 Product 格式
|
|
430
|
+
const productsForEvaluate = sortedFlattenedList.map(item => ({
|
|
431
|
+
product_id: item.id,
|
|
432
|
+
price: item.price || 0,
|
|
433
|
+
quantity: item.quantity || item.num || 1,
|
|
434
|
+
selling_price: item.price || 0,
|
|
435
|
+
product_options: item.type === 'main' ? item.product?.options : undefined
|
|
436
|
+
}));
|
|
437
|
+
|
|
438
|
+
// 调用策略检查
|
|
403
439
|
const result = evaluator.checkVoucherAvailability({
|
|
404
|
-
orderTotalAmount,
|
|
440
|
+
orderTotalAmount: orderTotalAmount,
|
|
405
441
|
products: productsForEvaluate,
|
|
406
442
|
vouchers: [voucher]
|
|
407
443
|
});
|
|
444
|
+
|
|
445
|
+
// 将 config 附加到 discount 对象
|
|
408
446
|
if (result.isAvailable) {
|
|
409
447
|
discount.config = {
|
|
410
448
|
...result.config,
|
|
@@ -418,35 +456,74 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
418
456
|
}
|
|
419
457
|
});
|
|
420
458
|
}
|
|
459
|
+
// 检查商品是否被排除(全品类)
|
|
421
460
|
const isProductIncludedByLimitedData = (limitedData, productId) => {
|
|
422
|
-
const excludedIds =
|
|
423
|
-
const isExcluded =
|
|
461
|
+
const excludedIds = limitedData?.exclude_product_ids || [];
|
|
462
|
+
const isExcluded = limitedData?.filter === 1 && excludedIds.some(id => String(id) === String(productId));
|
|
424
463
|
return !isExcluded;
|
|
425
464
|
};
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
// 对productList按价格降序排序(用于应用优惠券时优先选择高价商品) 价格相同时使用quantity 排序
|
|
468
|
+
const sortedProductList = [...productList].sort((a, b) => {
|
|
469
|
+
const aProduct = this.hooks.getProduct(a);
|
|
470
|
+
const bProduct = this.hooks.getProduct(b);
|
|
471
|
+
const priceA = new Decimal((aProduct.price as string) || '0');
|
|
472
|
+
const priceB = new Decimal((bProduct.price as string) || '0');
|
|
473
|
+
if (priceA.toNumber() === priceB.toNumber()) {
|
|
474
|
+
if (aProduct.quantity === bProduct.quantity) {
|
|
475
|
+
return bProduct.discount_list?.length - aProduct.discount_list?.length;
|
|
476
|
+
}
|
|
477
|
+
return aProduct.quantity - bProduct.quantity;
|
|
478
|
+
}
|
|
479
|
+
return priceB.toNumber() - priceA.toNumber();
|
|
480
|
+
});
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
// 标记已使用的优惠券
|
|
484
|
+
const usedDiscounts = new Map();
|
|
485
|
+
|
|
486
|
+
// 🔥 统计每个 product_id(商品券商品id)已使用的数量,用于 maxUsagePerOrder 限制
|
|
487
|
+
const usedProductIdCounts = new Map();
|
|
488
|
+
|
|
489
|
+
// 🔥 统计每张折扣卡的 applicableProductLimit 已使用次数(跨商品全局计数)
|
|
490
|
+
const usedDiscountCardLimitCounts = new Map();
|
|
491
|
+
|
|
492
|
+
// 🔥 预先将 editModeDiscount 中的折扣卡计入 applicableProductLimit 已使用次数
|
|
493
|
+
editModeDiscount.forEach(discount => {
|
|
431
494
|
const discountType = discount.tag || discount.type;
|
|
432
|
-
if ([
|
|
495
|
+
if (['discount_card', 'product_discount_card'].includes(discountType)) {
|
|
433
496
|
const currentCount = usedDiscountCardLimitCounts.get(discount.id) || 0;
|
|
434
|
-
usedDiscountCardLimitCounts.set(discount.id, currentCount + (
|
|
497
|
+
usedDiscountCardLimitCounts.set(discount.id, currentCount + (discount.metadata?.num || 1));
|
|
435
498
|
}
|
|
436
499
|
});
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
500
|
+
|
|
501
|
+
// 记录每个优惠券适用的商品ID
|
|
502
|
+
const discountApplicability = new Map();
|
|
503
|
+
|
|
504
|
+
// 记录每个优惠券适用的商品详细信息
|
|
505
|
+
const discountApplicableProducts = new Map();
|
|
506
|
+
|
|
507
|
+
// 初始化每个优惠券的适用性和可抵扣商品
|
|
508
|
+
addModeDiscount.forEach(discount => {
|
|
440
509
|
discountApplicability.set(discount.id, []);
|
|
441
510
|
discountApplicableProducts.set(discount.id, []);
|
|
442
511
|
});
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
512
|
+
|
|
513
|
+
// 预处理 order_level 固定金额折扣卡的分摊信息
|
|
514
|
+
// Map<discountId, Map<productId, { discountAmount, difference }>>
|
|
515
|
+
const orderLevelDiscountAllocations = new Map();
|
|
516
|
+
|
|
517
|
+
// 第一步:收集所有被勾选的 order_level 折扣卡及其适用商品
|
|
518
|
+
// Map<discountId, Set<flatItemId>> - 记录每个折扣卡适用的商品
|
|
519
|
+
const orderLevelDiscountApplicableItems = new Map();
|
|
520
|
+
// Map<flatItemId, Set<discountId>> - 记录每个商品可以被哪些折扣卡使用
|
|
521
|
+
const itemApplicableDiscounts = new Map();
|
|
522
|
+
|
|
523
|
+
// 辅助函数:检查商品是否对某个折扣卡可用
|
|
446
524
|
const checkItemApplicableForDiscount = (flatItem, discount) => {
|
|
447
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
448
525
|
let product;
|
|
449
|
-
if (flatItem.type ===
|
|
526
|
+
if (flatItem.type === 'main') {
|
|
450
527
|
product = flatItem.product;
|
|
451
528
|
} else {
|
|
452
529
|
product = {
|
|
@@ -457,27 +534,38 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
457
534
|
num: flatItem.num,
|
|
458
535
|
booking_id: flatItem.booking_id,
|
|
459
536
|
discount_list: flatItem.discount_list || [],
|
|
460
|
-
startDate:
|
|
537
|
+
startDate: flatItem.parentProduct?.startDate
|
|
461
538
|
};
|
|
462
539
|
}
|
|
463
|
-
|
|
540
|
+
|
|
541
|
+
// 编辑的商品使用了优惠券不可用
|
|
542
|
+
const isAvailableProduct = flatItem.type === 'main' ? !(product?.booking_id && product?.discount_list?.length && product?.discount_list?.every(d => d.id && ['good_pass', 'discount_card', 'product_discount_card'].includes(d.tag || d.type))) : !(flatItem?.booking_id && !!flatItem?.bundleItem?.discount_list?.length && flatItem?.bundleItem?.discount_list?.every(d => d.id));
|
|
464
543
|
if (!isAvailableProduct) {
|
|
465
544
|
return false;
|
|
466
545
|
}
|
|
467
|
-
|
|
546
|
+
|
|
547
|
+
// vouchersApplicable 为 false 的商品不参与订单级别折扣均摊
|
|
548
|
+
if ((0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
|
|
468
549
|
return false;
|
|
469
550
|
}
|
|
551
|
+
|
|
552
|
+
// 商品价格为0时不可用
|
|
470
553
|
if (Number(product.price) <= 0 || !product.price) {
|
|
471
554
|
return false;
|
|
472
555
|
}
|
|
473
556
|
const limitedData = discount.limited_relation_product_data;
|
|
474
|
-
|
|
557
|
+
|
|
558
|
+
// 时间限制检查
|
|
559
|
+
const timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
|
|
475
560
|
if (!timeLimit) {
|
|
476
561
|
return false;
|
|
477
562
|
}
|
|
563
|
+
|
|
564
|
+
// 判断商品是否适用
|
|
478
565
|
let isLimitedProduct = false;
|
|
479
|
-
if (limitedData.type ===
|
|
480
|
-
|
|
566
|
+
if (limitedData.type === 'product_all') {
|
|
567
|
+
// 全品类,但需要检查是否被排除
|
|
568
|
+
if (limitedData.filter === 1 && limitedData.exclude_product_ids?.includes(product.id)) {
|
|
481
569
|
isLimitedProduct = false;
|
|
482
570
|
} else {
|
|
483
571
|
isLimitedProduct = true;
|
|
@@ -485,33 +573,51 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
485
573
|
} else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) {
|
|
486
574
|
isLimitedProduct = true;
|
|
487
575
|
}
|
|
576
|
+
|
|
577
|
+
// 套餐规则检查
|
|
488
578
|
const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem);
|
|
489
579
|
return isLimitedProduct && isBundleAvailable;
|
|
490
580
|
};
|
|
491
|
-
|
|
492
|
-
|
|
581
|
+
|
|
582
|
+
// 收集所有被勾选的 order_level 折扣卡及其适用商品
|
|
583
|
+
const selectedOrderLevelDiscounts = sortedDiscountList.filter(discount => {
|
|
584
|
+
return (0, _utils.isOrderLevelFixedAmountDiscount)(discount) && discount.isSelected !== false;
|
|
493
585
|
});
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
586
|
+
|
|
587
|
+
// 遍历所有被勾选的 order_level 折扣卡,建立双向映射
|
|
588
|
+
selectedOrderLevelDiscounts.forEach(discount => {
|
|
589
|
+
const applicableItemIds = new Set();
|
|
590
|
+
sortedFlattenedList.forEach(flatItem => {
|
|
497
591
|
if (checkItemApplicableForDiscount(flatItem, discount)) {
|
|
498
592
|
applicableItemIds.add(flatItem._id);
|
|
593
|
+
|
|
594
|
+
// 记录商品可以被哪些折扣卡使用
|
|
499
595
|
if (!itemApplicableDiscounts.has(flatItem._id)) {
|
|
500
|
-
itemApplicableDiscounts.set(flatItem._id,
|
|
596
|
+
itemApplicableDiscounts.set(flatItem._id, new Set());
|
|
501
597
|
}
|
|
502
598
|
itemApplicableDiscounts.get(flatItem._id).add(discount.id);
|
|
503
599
|
}
|
|
504
600
|
});
|
|
505
601
|
orderLevelDiscountApplicableItems.set(discount.id, applicableItemIds);
|
|
506
602
|
});
|
|
507
|
-
|
|
508
|
-
|
|
603
|
+
|
|
604
|
+
// 专属折扣卡定义:限定了特定商品(product_ids),而不是全品类(product_all)的折扣卡
|
|
605
|
+
// 如果专属折扣卡被勾选,它适用的商品会被占用,其他折扣卡均摊时应排除这些商品
|
|
606
|
+
// Map<flatItemId, discountId> - 记录被占用的商品及其对应的折扣卡
|
|
607
|
+
const occupiedItems = new Map();
|
|
608
|
+
|
|
609
|
+
// 按排序顺序遍历折扣卡,判断哪些是专属折扣卡
|
|
610
|
+
selectedOrderLevelDiscounts.forEach(discount => {
|
|
509
611
|
const limitedData = discount.limited_relation_product_data;
|
|
510
|
-
|
|
612
|
+
|
|
613
|
+
// 判断是否是专属折扣卡(只能用于特定商品,而不是全品类)
|
|
614
|
+
const isExclusiveDiscount = limitedData.type !== 'product_all';
|
|
511
615
|
if (isExclusiveDiscount) {
|
|
616
|
+
// 专属折扣卡:它适用的所有商品都会被它占用
|
|
512
617
|
const applicableItems = orderLevelDiscountApplicableItems.get(discount.id);
|
|
513
618
|
if (applicableItems) {
|
|
514
|
-
applicableItems.forEach(
|
|
619
|
+
applicableItems.forEach(itemId => {
|
|
620
|
+
// 如果商品还没被占用,则标记为被当前折扣卡占用
|
|
515
621
|
if (!occupiedItems.has(itemId)) {
|
|
516
622
|
occupiedItems.set(itemId, discount.id);
|
|
517
623
|
}
|
|
@@ -519,23 +625,26 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
519
625
|
}
|
|
520
626
|
}
|
|
521
627
|
});
|
|
522
|
-
|
|
523
|
-
sortedDiscountList.forEach(
|
|
524
|
-
if (!(0,
|
|
628
|
+
// 🔥 第三步:识别 order_level 折扣卡并预计算分摊(排除被其他专属折扣卡占用的商品)
|
|
629
|
+
sortedDiscountList.forEach(discount => {
|
|
630
|
+
if (!(0, _utils.isOrderLevelFixedAmountDiscount)(discount)) {
|
|
525
631
|
return;
|
|
526
632
|
}
|
|
633
|
+
|
|
634
|
+
// 收集该折扣卡适用的商品(排除被其他专属折扣卡占用的商品)
|
|
527
635
|
const applicableProducts = [];
|
|
528
|
-
sortedFlattenedList.forEach(
|
|
529
|
-
|
|
636
|
+
sortedFlattenedList.forEach(flatItem => {
|
|
637
|
+
// 🔥 检查该商品是否被其他专属折扣卡占用
|
|
530
638
|
const occupyingDiscountId = occupiedItems.get(flatItem._id);
|
|
531
|
-
if (occupyingDiscountId !==
|
|
639
|
+
if (occupyingDiscountId !== undefined && occupyingDiscountId !== discount.id) {
|
|
640
|
+
// 该商品被其他专属折扣卡占用,跳过
|
|
532
641
|
return;
|
|
533
642
|
}
|
|
534
643
|
if (!checkItemApplicableForDiscount(flatItem, discount)) {
|
|
535
644
|
return;
|
|
536
645
|
}
|
|
537
646
|
let product;
|
|
538
|
-
if (flatItem.type ===
|
|
647
|
+
if (flatItem.type === 'main') {
|
|
539
648
|
product = flatItem.product;
|
|
540
649
|
} else {
|
|
541
650
|
product = {
|
|
@@ -546,34 +655,53 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
546
655
|
num: flatItem.num
|
|
547
656
|
};
|
|
548
657
|
}
|
|
549
|
-
|
|
550
|
-
|
|
658
|
+
|
|
659
|
+
// 对于 bundle 子商品,quantity 需要乘以主商品的购买数量
|
|
660
|
+
const quantity = flatItem.type === 'main' ? product.num || product.quantity || 1 : (product.num || product.quantity || 1) * (flatItem.parentProduct?.num || flatItem.parentProduct?.quantity || 1);
|
|
661
|
+
|
|
662
|
+
// 对于主商品:使用 price
|
|
663
|
+
// 对于子商品:优先使用 flatItem.original_price,否则使用 flatItem.price
|
|
664
|
+
const originalAmount = flatItem.type === 'main' ? Number(product.price ?? 0) : Number(flatItem.original_price ?? flatItem.price ?? 0);
|
|
665
|
+
|
|
666
|
+
// 传递 parentQuantity 用于差值处理时判断是否是真正的"数量为1"
|
|
551
667
|
const productData = {
|
|
552
668
|
productId: flatItem._id,
|
|
553
669
|
amount: originalAmount,
|
|
554
|
-
quantity
|
|
670
|
+
quantity: quantity
|
|
555
671
|
};
|
|
556
|
-
|
|
557
|
-
|
|
672
|
+
|
|
673
|
+
// 子商品需要传递主商品数量
|
|
674
|
+
if (flatItem.type === 'bundle') {
|
|
675
|
+
productData.parentQuantity = flatItem.parentProduct?.quantity || 1;
|
|
558
676
|
}
|
|
559
677
|
applicableProducts.push(productData);
|
|
560
678
|
});
|
|
679
|
+
|
|
680
|
+
// 计算分摊
|
|
561
681
|
if (applicableProducts.length > 0) {
|
|
562
|
-
const allocation = (0,
|
|
682
|
+
const allocation = (0, _utils.calculateOrderLevelDiscountAllocation)(discount, applicableProducts);
|
|
563
683
|
orderLevelDiscountAllocations.set(discount.id, allocation);
|
|
564
684
|
}
|
|
565
685
|
});
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
686
|
+
|
|
687
|
+
// 处理后的商品列表(按排序后的顺序处理,记录优惠信息)
|
|
688
|
+
const processedProductsMap = new Map();
|
|
689
|
+
|
|
690
|
+
// 记录已应用优惠券的商品信息
|
|
691
|
+
const appliedDiscountProducts = new Map();
|
|
692
|
+
|
|
693
|
+
// 首先遍历所有商品和所有优惠券,确定每个优惠券的适用范围,包括isSelected为false的优惠券
|
|
694
|
+
// 🔥 使用扁平化后的列表,包含主商品和bundle子商品
|
|
695
|
+
sortedFlattenedList.forEach(flatItem => {
|
|
696
|
+
// 获取商品数据
|
|
570
697
|
let product, originProduct;
|
|
571
|
-
if (flatItem.type ===
|
|
698
|
+
if (flatItem.type === 'main') {
|
|
572
699
|
product = flatItem.product;
|
|
573
700
|
originProduct = flatItem.originProduct;
|
|
574
701
|
} else {
|
|
702
|
+
// bundle子商品:构造虚拟商品对象
|
|
575
703
|
product = {
|
|
576
|
-
startDate:
|
|
704
|
+
startDate: flatItem?.parentProduct?.startDate,
|
|
577
705
|
_id: flatItem._id,
|
|
578
706
|
id: flatItem.id,
|
|
579
707
|
price: flatItem.price,
|
|
@@ -586,43 +714,45 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
586
714
|
};
|
|
587
715
|
originProduct = flatItem.originProduct;
|
|
588
716
|
}
|
|
589
|
-
addModeDiscount.forEach(
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const _tempVar =
|
|
593
|
-
const isHolderMatch = this.checkHolderMatch(
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
holder_id: (_tempVar == null ? void 0 : _tempVar.holder_id) || product.holder_id
|
|
598
|
-
},
|
|
599
|
-
holders
|
|
600
|
-
);
|
|
717
|
+
addModeDiscount.forEach(discount => {
|
|
718
|
+
const limitedData = discount?.limited_relation_product_data;
|
|
719
|
+
// 拿到discount配置的holder信息 product信息 product.holder 加在 isLimitedProduct
|
|
720
|
+
const _tempVar = flatItem?.type === 'bundle' ? flatItem?.parentProduct : flatItem?.product;
|
|
721
|
+
const isHolderMatch = this.checkHolderMatch(discount, {
|
|
722
|
+
isNeedHolder: isFormSubject && !_tempVar?.isNormalProduct,
|
|
723
|
+
holder_id: _tempVar?.holder_id || product.holder_id
|
|
724
|
+
}, holders);
|
|
601
725
|
let timeLimit = true;
|
|
602
|
-
timeLimit = !!(0,
|
|
603
|
-
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
))) : !((flatItem == null ? void 0 : flatItem.booking_id) && !!((_d = (_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.discount_list) == null ? void 0 : _d.length) && ((_f = (_e = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _e.discount_list) == null ? void 0 : _f.every((discount2) => discount2.id)));
|
|
726
|
+
timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
|
|
727
|
+
// 是符合折扣的商品
|
|
728
|
+
const isLimitedProduct = (limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
|
|
729
|
+
|
|
730
|
+
// 编辑的商品 使用了优惠券不可用
|
|
731
|
+
const isAvailableProduct = flatItem.type === 'main' ? !(product?.booking_id && product?.discount_list?.length && product?.discount_list?.every(discount => discount.id && ['good_pass', 'discount_card', 'product_discount_card'].includes(discount.tag || discount.type))) : !(flatItem?.booking_id && !!flatItem?.bundleItem?.discount_list?.length && flatItem?.bundleItem?.discount_list?.every(discount => discount.id));
|
|
732
|
+
|
|
733
|
+
// 套餐是否可用判断
|
|
611
734
|
const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem);
|
|
612
|
-
|
|
613
|
-
|
|
735
|
+
|
|
736
|
+
// 判断优惠券是否适用于该商品
|
|
737
|
+
if (isAvailableProduct && isLimitedProduct && timeLimit && isBundleAvailable && discount.config?.isAvailable) {
|
|
738
|
+
// 记录此优惠券适用的商品
|
|
739
|
+
discountApplicability.get(discount.id)?.push(product.id);
|
|
740
|
+
|
|
741
|
+
// 记录可抵扣的商品详情
|
|
614
742
|
const applicableProducts = discountApplicableProducts.get(discount.id) || [];
|
|
615
743
|
const discountType = discount.tag || discount.type;
|
|
616
|
-
const isGoodPass = discountType ===
|
|
617
|
-
|
|
744
|
+
const isGoodPass = discountType === 'good_pass';
|
|
745
|
+
|
|
746
|
+
// 使用数量
|
|
747
|
+
const num = isGoodPass || flatItem?.type === 'main' ? 1 : product.num;
|
|
618
748
|
const productData = {
|
|
619
749
|
amount: product.price * num,
|
|
620
750
|
type: discountType,
|
|
621
751
|
tag: discountType,
|
|
622
752
|
discount: {
|
|
623
|
-
discount_card_type:
|
|
753
|
+
discount_card_type: discount?.metadata?.discount_card_type,
|
|
624
754
|
fixed_amount: product.price,
|
|
625
|
-
discount_calculation_mode:
|
|
755
|
+
discount_calculation_mode: discount?.metadata?.discount_calculation_mode,
|
|
626
756
|
resource_id: discount.id,
|
|
627
757
|
title: discount.format_title,
|
|
628
758
|
original_amount: product.price || product.origin_total,
|
|
@@ -631,8 +761,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
631
761
|
discount_product_id: discount.product_id
|
|
632
762
|
},
|
|
633
763
|
metadata: {
|
|
634
|
-
num,
|
|
635
|
-
discount_rule_uncheck_flag: discount
|
|
764
|
+
num: num,
|
|
765
|
+
discount_rule_uncheck_flag: discount?.discount_rule_uncheck_flag
|
|
636
766
|
}
|
|
637
767
|
};
|
|
638
768
|
applicableProducts.push(productData);
|
|
@@ -640,112 +770,132 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
640
770
|
}
|
|
641
771
|
});
|
|
642
772
|
});
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
773
|
+
|
|
774
|
+
// 🔥 用于存储扁平化商品处理结果的Map
|
|
775
|
+
const processedFlatItemsMap = new Map();
|
|
776
|
+
|
|
777
|
+
// 🔥 Option 折扣辅助函数
|
|
778
|
+
const applyDiscountToOptions = (options, discount) => {
|
|
779
|
+
if (!options?.length) return {
|
|
780
|
+
discountedOptions: options,
|
|
781
|
+
optionDiscountAmount: 0
|
|
782
|
+
};
|
|
647
783
|
let optionDiscountAmount = 0;
|
|
648
|
-
const discountedOptions =
|
|
784
|
+
const discountedOptions = options.map(option => {
|
|
785
|
+
// 折前单价:优先 price,缺失再 add_price;已写回折后价时用 _original_price(或旧字段 _original_add_price)
|
|
649
786
|
const rawUnit = option._original_price ?? option._original_add_price ?? option.price ?? option.add_price;
|
|
650
787
|
const baseUnitNum = Number(rawUnit ?? 0);
|
|
651
|
-
if (baseUnitNum <= 0)
|
|
652
|
-
|
|
653
|
-
const discountedPrice = (0, import_utils.getDiscountAmount)(discount, baseUnitNum, baseUnitNum);
|
|
788
|
+
if (baseUnitNum <= 0) return option;
|
|
789
|
+
const discountedPrice = (0, _utils.getDiscountAmount)(discount, baseUnitNum, baseUnitNum);
|
|
654
790
|
const optQty = Number(option.num ?? option.quantity ?? 1);
|
|
655
|
-
optionDiscountAmount = new
|
|
656
|
-
const {
|
|
791
|
+
optionDiscountAmount = new _decimal.default(optionDiscountAmount).plus(new _decimal.default(baseUnitNum).minus(discountedPrice).mul(optQty)).toNumber();
|
|
792
|
+
const {
|
|
793
|
+
_original_add_price,
|
|
794
|
+
...rest
|
|
795
|
+
} = option;
|
|
657
796
|
const tmpl = rest.price ?? rest.add_price;
|
|
658
|
-
const nextPrice = typeof tmpl ===
|
|
797
|
+
const nextPrice = typeof tmpl === 'string' ? String(discountedPrice) : discountedPrice;
|
|
659
798
|
return {
|
|
660
799
|
...rest,
|
|
661
|
-
_original_price: option._original_price ?? (_original_add_price !==
|
|
800
|
+
_original_price: option._original_price ?? (_original_add_price !== undefined ? _original_add_price : rawUnit),
|
|
662
801
|
price: nextPrice
|
|
663
802
|
};
|
|
664
803
|
});
|
|
665
|
-
return {
|
|
804
|
+
return {
|
|
805
|
+
discountedOptions,
|
|
806
|
+
optionDiscountAmount
|
|
807
|
+
};
|
|
666
808
|
};
|
|
667
|
-
const restoreOptionPrices =
|
|
668
|
-
if (!
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
809
|
+
const restoreOptionPrices = options => {
|
|
810
|
+
if (!options?.length) return options;
|
|
811
|
+
return options.map(option => {
|
|
812
|
+
const orig = option._original_price !== undefined ? option._original_price : option._original_add_price;
|
|
813
|
+
if (orig !== undefined) {
|
|
814
|
+
const {
|
|
815
|
+
_original_price,
|
|
816
|
+
_original_add_price,
|
|
817
|
+
...rest
|
|
818
|
+
} = option;
|
|
819
|
+
return {
|
|
820
|
+
...rest,
|
|
821
|
+
price: orig
|
|
822
|
+
};
|
|
675
823
|
}
|
|
676
824
|
return option;
|
|
677
825
|
});
|
|
678
826
|
};
|
|
679
|
-
const getOptionTotal =
|
|
680
|
-
if (!
|
|
681
|
-
|
|
682
|
-
return options2.reduce((sum, opt) => {
|
|
827
|
+
const getOptionTotal = options => {
|
|
828
|
+
if (!options?.length) return 0;
|
|
829
|
+
return options.reduce((sum, opt) => {
|
|
683
830
|
const unit = Number(opt.price ?? opt.add_price ?? 0);
|
|
684
831
|
const n = Number(opt.num ?? opt.quantity ?? 1);
|
|
685
|
-
return new
|
|
832
|
+
return new _decimal.default(sum).plus(new _decimal.default(unit).mul(n)).toNumber();
|
|
686
833
|
}, 0);
|
|
687
834
|
};
|
|
835
|
+
|
|
836
|
+
// 然后再处理应用哪些优惠券,此时只考虑filteredDiscountList中的优惠券
|
|
837
|
+
// 🔥 使用扁平化后的列表进行处理
|
|
688
838
|
sortedFlattenedList.forEach((flatItem, index) => {
|
|
689
|
-
|
|
839
|
+
// 获取商品数据
|
|
690
840
|
let product, originProduct;
|
|
691
|
-
if (flatItem.type ===
|
|
841
|
+
if (flatItem.type === 'main') {
|
|
692
842
|
product = flatItem.product;
|
|
693
843
|
originProduct = flatItem.originProduct;
|
|
694
844
|
} else {
|
|
845
|
+
// bundle子商品
|
|
695
846
|
product = {
|
|
696
|
-
startDate:
|
|
847
|
+
startDate: flatItem?.parentProduct?.startDate,
|
|
697
848
|
_id: flatItem._id,
|
|
698
849
|
id: flatItem.id,
|
|
699
850
|
price: flatItem.price,
|
|
700
851
|
quantity: flatItem.quantity,
|
|
701
852
|
num: flatItem.num,
|
|
702
853
|
total: flatItem.total,
|
|
703
|
-
original_price:
|
|
704
|
-
origin_total:
|
|
854
|
+
original_price: flatItem?.bundleItem?.original_price,
|
|
855
|
+
origin_total: flatItem?.bundleItem?.original_price,
|
|
705
856
|
booking_id: flatItem.booking_id,
|
|
706
|
-
discount_list:
|
|
857
|
+
discount_list: flatItem?.bundleItem?.discount_list || []
|
|
707
858
|
};
|
|
708
859
|
originProduct = flatItem.originProduct;
|
|
709
860
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
)
|
|
714
|
-
))) {
|
|
715
|
-
if (flatItem.type === "main") {
|
|
861
|
+
|
|
862
|
+
// 已有优惠的商品跳过
|
|
863
|
+
if (product?.booking_id && product.discount_list?.length && product?.discount_list?.every(discount => discount.id && ['good_pass', 'discount_card', 'product_discount_card'].includes(discount.tag || discount.type))) {
|
|
864
|
+
if (flatItem.type === 'main') {
|
|
716
865
|
processedProductsMap.set(product._id, [originProduct]);
|
|
717
866
|
} else {
|
|
718
|
-
processedFlatItemsMap.set(flatItem._id, [
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
}
|
|
723
|
-
]);
|
|
867
|
+
processedFlatItemsMap.set(flatItem._id, [{
|
|
868
|
+
...flatItem,
|
|
869
|
+
processed: true
|
|
870
|
+
}]);
|
|
724
871
|
}
|
|
725
872
|
return;
|
|
726
873
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
)) {
|
|
733
|
-
|
|
874
|
+
|
|
875
|
+
// 找到适用于此商品的所有优惠券,仅考虑isSelected不为false的优惠券
|
|
876
|
+
const applicableDiscounts = sortedDiscountList.filter(discount => {
|
|
877
|
+
// 🔥 检查策略可用性(针对 good_pass 和折扣卡)
|
|
878
|
+
const discountType = discount.tag || discount.type;
|
|
879
|
+
if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
|
|
880
|
+
// 如果策略检查后没有config,说明不可用
|
|
881
|
+
if (discount.config === undefined || !discount?.config?.isAvailable) {
|
|
734
882
|
return false;
|
|
735
883
|
}
|
|
736
884
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
885
|
+
|
|
886
|
+
// 如果商品价格为 0,其实不需要使用任何优惠券,直接 return true
|
|
887
|
+
// 商品券时主商品价格为0不可用
|
|
888
|
+
if ((Number(product.price) <= 0 || !product.price) && !product.discount_list?.length && (discount.tag || discount.type) === 'good_pass') return false;
|
|
889
|
+
|
|
890
|
+
// 折扣卡商品价格为0时不可用
|
|
891
|
+
if ((Number(product.price) <= 0 || !product.price) && !product.discount_list?.find(n => n.discount?.resource_id === discount.id) && (discount.tag || discount.type) !== 'good_pass') return false;
|
|
892
|
+
// 如果优惠券已被使用,则跳过
|
|
744
893
|
const targetUsedDiscounts = usedDiscounts.get(discount.id);
|
|
745
|
-
if (targetUsedDiscounts && (discount.tag || discount.type) ===
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
894
|
+
if (targetUsedDiscounts && (discount.tag || discount.type) === 'good_pass') return false;
|
|
895
|
+
|
|
896
|
+
// 🔥 检查 maxUsagePerOrder 限制:同一 product_id 的商品券使用数量不能超过配置值
|
|
897
|
+
if ((discount.tag || discount.type) === 'good_pass') {
|
|
898
|
+
const maxUsagePerOrder = discount.config?.maxUsagePerOrder;
|
|
749
899
|
if (maxUsagePerOrder && maxUsagePerOrder > 0) {
|
|
750
900
|
const currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0;
|
|
751
901
|
if (currentUsedCount >= maxUsagePerOrder) {
|
|
@@ -753,9 +903,11 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
753
903
|
}
|
|
754
904
|
}
|
|
755
905
|
}
|
|
906
|
+
|
|
907
|
+
// 🔥 检查折扣卡的 applicableProductLimit 限制:折扣卡可使用的最大次数(跨商品全局)
|
|
756
908
|
const discountTypeForLimit = discount.tag || discount.type;
|
|
757
|
-
if ([
|
|
758
|
-
const applicableProductLimitConfig =
|
|
909
|
+
if (['discount_card', 'product_discount_card'].includes(discountTypeForLimit)) {
|
|
910
|
+
const applicableProductLimitConfig = discount.config?.applicableProductLimit || 0;
|
|
759
911
|
if (applicableProductLimitConfig > 0) {
|
|
760
912
|
const currentUsedLimitCount = usedDiscountCardLimitCounts.get(discount.id) || 0;
|
|
761
913
|
if (currentUsedLimitCount >= applicableProductLimitConfig) {
|
|
@@ -764,31 +916,34 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
764
916
|
}
|
|
765
917
|
}
|
|
766
918
|
const limitedData = discount.limited_relation_product_data;
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
);
|
|
776
|
-
if (!isHolderMatch)
|
|
777
|
-
return false;
|
|
919
|
+
|
|
920
|
+
// 拿到discount配置的holder信息 product信息 product.holder 不可用return false
|
|
921
|
+
const _tempVar = flatItem?.type === 'bundle' ? flatItem?.parentProduct : flatItem?.product;
|
|
922
|
+
const isHolderMatch = this.checkHolderMatch(discount, {
|
|
923
|
+
isNeedHolder: isFormSubject && !_tempVar?.isNormalProduct,
|
|
924
|
+
holder_id: _tempVar?.holder_id || product.holder_id
|
|
925
|
+
}, holders);
|
|
926
|
+
// 如果 holder 不匹配,则不适用
|
|
927
|
+
if (!isHolderMatch) return false;
|
|
778
928
|
let timeLimit = true;
|
|
779
|
-
timeLimit = !!(0,
|
|
929
|
+
timeLimit = !!(0, _utils.filterDiscountListByBookingTime)([discount], (product.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss')).length;
|
|
780
930
|
if (!timeLimit) {
|
|
781
931
|
return false;
|
|
782
932
|
}
|
|
783
|
-
|
|
933
|
+
|
|
934
|
+
// 判断优惠券是否适用于该商品
|
|
935
|
+
if (limitedData.type === 'product_all') {
|
|
784
936
|
if (!isProductIncludedByLimitedData(limitedData, product.id)) {
|
|
785
937
|
return false;
|
|
786
938
|
}
|
|
939
|
+
|
|
940
|
+
// 检查 package_sub_item_usage_rules
|
|
787
941
|
if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
|
|
788
942
|
return false;
|
|
789
943
|
}
|
|
790
944
|
return true;
|
|
791
945
|
} else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) {
|
|
946
|
+
// 检查 package_sub_item_usage_rules
|
|
792
947
|
if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
|
|
793
948
|
return false;
|
|
794
949
|
}
|
|
@@ -796,273 +951,247 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
796
951
|
}
|
|
797
952
|
return false;
|
|
798
953
|
});
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
954
|
+
|
|
955
|
+
// 选择第一个适用的优惠券(已经按过期时间排序)
|
|
956
|
+
// 如果有 isScan 且 isSelected 的折扣卡,则优先选中,否则再选择第一个
|
|
957
|
+
// 用于处理:先手动扫描了一张折扣卡,扫描完以后带入客户信息,但是之前那张折扣卡不是最优惠的情况
|
|
958
|
+
const selectedDiscountCard = applicableDiscounts.find(n => n.isScan && n.isSelected && (n.tag || n.type) !== 'good_pass');
|
|
802
959
|
const selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
|
|
960
|
+
|
|
961
|
+
// 如果是手动折扣,则不适用优惠券
|
|
803
962
|
let isManualDiscount = false;
|
|
804
|
-
if (flatItem.type ===
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
var _a2;
|
|
808
|
-
return !((_a2 = item.discount_list || []) == null ? void 0 : _a2.length);
|
|
809
|
-
}
|
|
810
|
-
) && (!((_g = product.discount_list) == null ? void 0 : _g.length) || ((_i = (_h = product == null ? void 0 : product.discount_list) == null ? void 0 : _h.every) == null ? void 0 : _i.call(
|
|
811
|
-
_h,
|
|
812
|
-
(item) => item.type === "product"
|
|
813
|
-
)));
|
|
963
|
+
if (flatItem.type === 'main') {
|
|
964
|
+
// 主商品:判断自身是否手动折扣
|
|
965
|
+
isManualDiscount = typeof product.isManualDiscount === 'boolean' ? product.isManualDiscount : product.total != product.origin_total && (product.bundle || []).every(item => !(item.discount_list || [])?.length) && (!product.discount_list?.length || product?.discount_list?.every?.(item => item.type === 'product'));
|
|
814
966
|
if (product.inPromotion) {
|
|
815
967
|
isManualDiscount = false;
|
|
816
968
|
}
|
|
817
969
|
} else {
|
|
970
|
+
// bundle子商品:判断父主商品是否手动折扣
|
|
818
971
|
const parentProduct = flatItem.parentProduct;
|
|
819
972
|
if (parentProduct) {
|
|
820
|
-
isManualDiscount = typeof parentProduct.isManualDiscount ===
|
|
821
|
-
(item) => {
|
|
822
|
-
var _a2;
|
|
823
|
-
return !((_a2 = item.discount_list || []) == null ? void 0 : _a2.length);
|
|
824
|
-
}
|
|
825
|
-
) && (!((_j = parentProduct.discount_list) == null ? void 0 : _j.length) || ((_l = (_k = parentProduct == null ? void 0 : parentProduct.discount_list) == null ? void 0 : _k.every) == null ? void 0 : _l.call(
|
|
826
|
-
_k,
|
|
827
|
-
(item) => item.type === "product"
|
|
828
|
-
)));
|
|
973
|
+
isManualDiscount = typeof parentProduct.isManualDiscount === 'boolean' ? parentProduct.isManualDiscount : parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(item => !(item.discount_list || [])?.length) && (!parentProduct.discount_list?.length || parentProduct?.discount_list?.every?.(item => item.type === 'product'));
|
|
829
974
|
}
|
|
830
975
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
837
|
-
))) {
|
|
976
|
+
|
|
977
|
+
// 勾选时覆盖手动折扣
|
|
978
|
+
if (options?.discountId) {
|
|
979
|
+
// 主商品:检查自己的 discount_list
|
|
980
|
+
if (flatItem.type === 'main' && product.discount_list?.some(item => item.discount?.resource_id === options.discountId)) {
|
|
838
981
|
isManualDiscount = false;
|
|
839
982
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
var _a2;
|
|
844
|
-
return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId;
|
|
845
|
-
}
|
|
846
|
-
)) || ((_p = (_o = flatItem.parentProduct) == null ? void 0 : _o.discount_list) == null ? void 0 : _p.some(
|
|
847
|
-
(item) => {
|
|
848
|
-
var _a2;
|
|
849
|
-
return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId;
|
|
850
|
-
}
|
|
851
|
-
))) {
|
|
983
|
+
// bundle子商品:检查自己的 discount_list 或父主商品的 discount_list
|
|
984
|
+
if (flatItem.type === 'bundle') {
|
|
985
|
+
if (product.discount_list?.some(item => item.discount?.resource_id === options.discountId) || flatItem.parentProduct?.discount_list?.some(item => item.discount?.resource_id === options.discountId)) {
|
|
852
986
|
isManualDiscount = false;
|
|
853
987
|
}
|
|
854
988
|
}
|
|
855
989
|
}
|
|
856
|
-
if (options
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
var _a2;
|
|
860
|
-
return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some(
|
|
861
|
-
(n) => {
|
|
862
|
-
var _a3;
|
|
863
|
-
return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id);
|
|
864
|
-
}
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
))) {
|
|
990
|
+
if (options?.selectedList) {
|
|
991
|
+
// 主商品:检查自己的 discount_list
|
|
992
|
+
if (flatItem.type === 'main' && product.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id))) {
|
|
868
993
|
isManualDiscount = false;
|
|
869
994
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
var _a2;
|
|
874
|
-
return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some(
|
|
875
|
-
(n) => {
|
|
876
|
-
var _a3;
|
|
877
|
-
return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id);
|
|
878
|
-
}
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
)) || ((_t = (_s = flatItem.parentProduct) == null ? void 0 : _s.discount_list) == null ? void 0 : _t.some(
|
|
882
|
-
(item) => {
|
|
883
|
-
var _a2;
|
|
884
|
-
return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some(
|
|
885
|
-
(n) => {
|
|
886
|
-
var _a3;
|
|
887
|
-
return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id);
|
|
888
|
-
}
|
|
889
|
-
);
|
|
890
|
-
}
|
|
891
|
-
))) {
|
|
995
|
+
// bundle子商品:检查自己的 discount_list 或父主商品的 discount_list
|
|
996
|
+
if (flatItem.type === 'bundle') {
|
|
997
|
+
if (product.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id)) || flatItem.parentProduct?.discount_list?.some(item => options?.selectedList?.some(n => n.discountId === item.discount?.resource_id))) {
|
|
892
998
|
isManualDiscount = false;
|
|
893
999
|
}
|
|
894
1000
|
}
|
|
895
1001
|
}
|
|
896
|
-
|
|
897
|
-
|
|
1002
|
+
|
|
1003
|
+
// 如果没有适用的优惠券,或者手动折扣,则不适用优惠券
|
|
1004
|
+
if (applicableDiscounts.length === 0 || isManualDiscount || (0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
|
|
1005
|
+
if (flatItem.type === 'main') {
|
|
1006
|
+
// 主商品:保持原有逻辑,还原 option 价格
|
|
898
1007
|
const restoredOptions = restoreOptionPrices(product.options);
|
|
899
1008
|
if (product.isClient) {
|
|
900
|
-
processedProductsMap.set(product._id, [
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
bundle: product.bundle,
|
|
908
|
-
options: restoredOptions
|
|
909
|
-
}),
|
|
910
|
-
variant: originProduct._productInit.variant,
|
|
911
|
-
original_price: originProduct._productInit.original_price,
|
|
912
|
-
total: (0, import_utils2.getProductTotalPrice)({
|
|
913
|
-
product: {
|
|
914
|
-
price: product.price
|
|
915
|
-
},
|
|
916
|
-
bundle: product.bundle,
|
|
917
|
-
options: restoredOptions
|
|
918
|
-
}),
|
|
919
|
-
price: product.price,
|
|
1009
|
+
processedProductsMap.set(product._id, [this.hooks.setProduct(originProduct, {
|
|
1010
|
+
...(isManualDiscount ? {} : {
|
|
1011
|
+
origin_total: (0, _utils2.getProductOriginTotalPrice)({
|
|
1012
|
+
product: {
|
|
1013
|
+
original_price: product.original_price
|
|
1014
|
+
},
|
|
1015
|
+
bundle: product.bundle,
|
|
920
1016
|
options: restoredOptions
|
|
921
|
-
},
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1017
|
+
}),
|
|
1018
|
+
variant: originProduct._productInit.variant,
|
|
1019
|
+
original_price: originProduct._productInit.original_price,
|
|
1020
|
+
total: (0, _utils2.getProductTotalPrice)({
|
|
1021
|
+
product: {
|
|
1022
|
+
price: product.price
|
|
1023
|
+
},
|
|
1024
|
+
bundle: product.bundle,
|
|
1025
|
+
options: restoredOptions
|
|
1026
|
+
}),
|
|
1027
|
+
price: product.price,
|
|
1028
|
+
options: restoredOptions
|
|
1029
|
+
}),
|
|
1030
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion')
|
|
1031
|
+
})]);
|
|
925
1032
|
} else {
|
|
926
|
-
let total = product.inPromotion ?
|
|
1033
|
+
let total = product.inPromotion ? product?._promotion?.finalPrice ?? product.origin_total ?? product.total : product.origin_total ?? product.total;
|
|
927
1034
|
let main_product_selling_price = product.price ?? product.main_product_selling_price;
|
|
928
|
-
if ((product.discount_list || []).some(
|
|
1035
|
+
if ((product.discount_list || []).some(item => item.type === 'promotion') || (0, _lodashEs.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
|
|
929
1036
|
total = product.total ?? product.origin_total;
|
|
930
1037
|
main_product_selling_price = product.main_product_selling_price ?? main_product_selling_price;
|
|
931
1038
|
}
|
|
932
|
-
processedProductsMap.set(product._id, [
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
})
|
|
946
|
-
]);
|
|
1039
|
+
processedProductsMap.set(product._id, [this.hooks.setProduct(originProduct, {
|
|
1040
|
+
...(isManualDiscount ? {
|
|
1041
|
+
price: product.price
|
|
1042
|
+
} : {
|
|
1043
|
+
_id: product._id.split('___')[0] + '___' + index,
|
|
1044
|
+
total,
|
|
1045
|
+
original_price: product.original_price,
|
|
1046
|
+
price: product.price,
|
|
1047
|
+
main_product_selling_price,
|
|
1048
|
+
options: restoredOptions
|
|
1049
|
+
}),
|
|
1050
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion')
|
|
1051
|
+
})]);
|
|
947
1052
|
}
|
|
948
1053
|
} else {
|
|
1054
|
+
// bundle子商品:保存到扁平化Map
|
|
949
1055
|
processedFlatItemsMap.set(flatItem._id, [{
|
|
950
1056
|
...flatItem,
|
|
951
|
-
discount_list: this.filterDiscountListByType(
|
|
1057
|
+
discount_list: this.filterDiscountListByType(flatItem.bundleItem?.discount_list || [], 'promotion'),
|
|
952
1058
|
price: isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price,
|
|
953
1059
|
processed: true
|
|
954
1060
|
}]);
|
|
955
1061
|
}
|
|
956
1062
|
return;
|
|
957
1063
|
}
|
|
958
|
-
if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect ===
|
|
1064
|
+
if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === 'undefined' && !options?.scan && !isEditModeAddNewProduct) {
|
|
959
1065
|
return;
|
|
960
1066
|
}
|
|
1067
|
+
|
|
1068
|
+
// 是否需要拆分(商品券需要拆分,折扣卡在 applicableProductLimit > 0 时也需要拆分)
|
|
961
1069
|
const discountType = selectedDiscount.tag || selectedDiscount.type;
|
|
962
|
-
const isGoodPass = discountType ===
|
|
963
|
-
const isDiscountCard = [
|
|
964
|
-
const applicableProductLimit =
|
|
1070
|
+
const isGoodPass = discountType === 'good_pass';
|
|
1071
|
+
const isDiscountCard = ['discount_card', 'product_discount_card'].includes(discountType);
|
|
1072
|
+
const applicableProductLimit = selectedDiscount.config?.applicableProductLimit || 0;
|
|
1073
|
+
|
|
1074
|
+
// 商品券始终需要拆分,折扣卡在 applicableProductLimit > 0 时需要拆分
|
|
965
1075
|
const isNeedSplit = isGoodPass || isDiscountCard && applicableProductLimit > 0;
|
|
1076
|
+
|
|
1077
|
+
// 需要拆分出来的数量
|
|
966
1078
|
const totalQuantity = product.quantity || product.num || 1;
|
|
967
|
-
const availableGoodPassCount = applicableDiscounts.filter(
|
|
968
|
-
|
|
969
|
-
|
|
1079
|
+
const availableGoodPassCount = applicableDiscounts.filter(item => (item.tag || item.type) === 'good_pass').length;
|
|
1080
|
+
|
|
1081
|
+
// 🔥 计算最大使用次数限制
|
|
970
1082
|
let maxUsageLimit;
|
|
971
1083
|
if (isGoodPass) {
|
|
1084
|
+
// 商品券:使用 maxUsagePerOrder 限制
|
|
972
1085
|
maxUsageLimit = availableGoodPassCount;
|
|
973
1086
|
if (selectedDiscount.config && selectedDiscount.config.maxUsagePerOrder) {
|
|
974
|
-
maxUsageLimit = Math.min(
|
|
975
|
-
availableGoodPassCount,
|
|
976
|
-
selectedDiscount.config.maxUsagePerOrder
|
|
977
|
-
);
|
|
1087
|
+
maxUsageLimit = Math.min(availableGoodPassCount, selectedDiscount.config.maxUsagePerOrder);
|
|
978
1088
|
}
|
|
979
1089
|
} else if (isDiscountCard && applicableProductLimit > 0) {
|
|
1090
|
+
// 折扣卡:使用 applicableProductLimit 限制(一个商品使用一次折扣卡算1次)
|
|
1091
|
+
// 需要减去已使用次数(跨商品全局计数)
|
|
980
1092
|
const usedLimitCount = usedDiscountCardLimitCounts.get(selectedDiscount.id) || 0;
|
|
981
1093
|
maxUsageLimit = Math.max(0, applicableProductLimit - usedLimitCount);
|
|
982
1094
|
} else {
|
|
1095
|
+
// 其他情况不拆分
|
|
983
1096
|
maxUsageLimit = 1;
|
|
984
1097
|
}
|
|
985
1098
|
const splitCount = isNeedSplit ? Math.min(product.quantity || product.num || 1, maxUsageLimit) : 1;
|
|
986
1099
|
const arr = [];
|
|
987
|
-
|
|
1100
|
+
|
|
1101
|
+
// 🔥 主商品和bundle子商品分别处理
|
|
1102
|
+
if (flatItem.type === 'main') {
|
|
1103
|
+
// 主商品:保持原有逻辑
|
|
988
1104
|
if (splitCount < totalQuantity && isNeedSplit) {
|
|
989
1105
|
let total = product.origin_total ?? product.total;
|
|
990
|
-
if ((product.discount_list || []).some(
|
|
1106
|
+
if ((product.discount_list || []).some(item => item.type === 'promotion')) {
|
|
991
1107
|
total = product.total ?? product.origin_total;
|
|
992
1108
|
}
|
|
993
|
-
arr.push(
|
|
994
|
-
this.
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
})
|
|
1000
|
-
);
|
|
1109
|
+
arr.push(this.hooks.setProduct(originProduct, {
|
|
1110
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1111
|
+
quantity: totalQuantity - splitCount,
|
|
1112
|
+
_id: product._id.split('___')[0],
|
|
1113
|
+
total
|
|
1114
|
+
}));
|
|
1001
1115
|
}
|
|
1002
1116
|
for (let i = 0; i < splitCount; i++) {
|
|
1117
|
+
// 商品券:每个拆分商品使用不同的商品券(从 applicableDiscounts 按索引取)
|
|
1118
|
+
// 折扣卡:所有拆分商品使用同一张折扣卡(selectedDiscountCard 或 applicableDiscounts[0])
|
|
1003
1119
|
const currentSelectedDiscount = isGoodPass ? selectedDiscountCard || applicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[0];
|
|
1120
|
+
// 标记优惠券为已使用
|
|
1004
1121
|
usedDiscounts.set(currentSelectedDiscount.id, true);
|
|
1005
|
-
|
|
1122
|
+
// 🔥 更新 product_id 使用计数
|
|
1123
|
+
if ((currentSelectedDiscount.tag || currentSelectedDiscount.type) === 'good_pass') {
|
|
1006
1124
|
const currentCount = usedProductIdCounts.get(currentSelectedDiscount.product_id) || 0;
|
|
1007
1125
|
usedProductIdCounts.set(currentSelectedDiscount.product_id, currentCount + 1);
|
|
1008
1126
|
}
|
|
1127
|
+
// 🔥 更新折扣卡 applicableProductLimit 使用计数(跨商品全局)
|
|
1009
1128
|
const currentDiscountTypeForCount = currentSelectedDiscount.tag || currentSelectedDiscount.type;
|
|
1010
|
-
if ([
|
|
1129
|
+
if (['discount_card', 'product_discount_card'].includes(currentDiscountTypeForCount)) {
|
|
1011
1130
|
const currentLimitCount = usedDiscountCardLimitCounts.get(currentSelectedDiscount.id) || 0;
|
|
1012
1131
|
usedDiscountCardLimitCounts.set(currentSelectedDiscount.id, currentLimitCount + 1);
|
|
1013
1132
|
}
|
|
1133
|
+
|
|
1134
|
+
// 记录实际应用了优惠券的商品信息
|
|
1014
1135
|
const appliedProducts = appliedDiscountProducts.get(currentSelectedDiscount.id) || [];
|
|
1136
|
+
|
|
1137
|
+
// 优先从 origin_total拿,可能会拿不到(比如用户端预约在没有配置 original_price 的情况下)
|
|
1015
1138
|
let productOriginTotal = product.origin_total || product.total || 0;
|
|
1016
|
-
|
|
1139
|
+
// 如果当前 product 有 discount_list,则先从 origin_total 拿
|
|
1140
|
+
if (this.filterDiscountListByType(product.discount_list, 'promotion').length && product.origin_total) {
|
|
1017
1141
|
productOriginTotal = product.origin_total;
|
|
1018
1142
|
}
|
|
1019
|
-
|
|
1143
|
+
// 如果originProduct?._productInit?.original_price为 0,product.origin_total可能为空,此时取 product.total
|
|
1144
|
+
if (Number(originProduct?._productInit?.original_price || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) {
|
|
1020
1145
|
productOriginTotal = product.total;
|
|
1021
1146
|
}
|
|
1022
|
-
|
|
1147
|
+
|
|
1148
|
+
// 计算使用折扣卡/商品券以后,单个商品的总 total
|
|
1149
|
+
// 🔥 检查是否是 order_level 固定金额折扣卡
|
|
1150
|
+
const isOrderLevel = (0, _utils.isOrderLevelFixedAmountDiscount)(selectedDiscount);
|
|
1023
1151
|
const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
|
|
1024
|
-
const productAllocation = orderLevelAllocation
|
|
1025
|
-
const isDeductOptionPrice = !!
|
|
1152
|
+
const productAllocation = orderLevelAllocation?.get(flatItem._id);
|
|
1153
|
+
const isDeductOptionPrice = !!selectedDiscount.config?.deductOptionPrice;
|
|
1154
|
+
|
|
1155
|
+
// 主商品折后价(不含 option);勿与 option 合计混在同一变量,否则 main_product_selling_price 错误
|
|
1026
1156
|
let mainProductSellingPrice;
|
|
1027
1157
|
let amount;
|
|
1028
1158
|
let productDiscountDifference;
|
|
1029
1159
|
let discountedOptions = product.options;
|
|
1030
1160
|
let optionDiscountAmount = 0;
|
|
1031
1161
|
if (isOrderLevel && productAllocation) {
|
|
1162
|
+
// order_level:使用预计算的分摊金额
|
|
1032
1163
|
amount = productAllocation.discountAmount;
|
|
1033
1164
|
productDiscountDifference = productAllocation.difference;
|
|
1034
|
-
mainProductSellingPrice = Math.max(new
|
|
1165
|
+
mainProductSellingPrice = Math.max(new _decimal.default(product.price).minus(amount).toNumber(), 0);
|
|
1035
1166
|
} else {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
product.price
|
|
1040
|
-
);
|
|
1041
|
-
amount = new import_decimal.default(product.price).minus(new import_decimal.default(mainProductSellingPrice)).toNumber();
|
|
1167
|
+
// item_level 或其他类型:使用原有逻辑
|
|
1168
|
+
mainProductSellingPrice = (0, _utils.getDiscountAmount)(currentSelectedDiscount, product.price, product.price);
|
|
1169
|
+
amount = new _decimal.default(product.price).minus(new _decimal.default(mainProductSellingPrice)).toNumber();
|
|
1042
1170
|
}
|
|
1043
|
-
if (isDeductOptionPrice &&
|
|
1044
|
-
const optionResult = applyDiscountToOptions(
|
|
1045
|
-
product.options,
|
|
1046
|
-
currentSelectedDiscount
|
|
1047
|
-
);
|
|
1171
|
+
if (isDeductOptionPrice && product.options?.length) {
|
|
1172
|
+
const optionResult = applyDiscountToOptions(product.options, currentSelectedDiscount);
|
|
1048
1173
|
discountedOptions = optionResult.discountedOptions;
|
|
1049
1174
|
optionDiscountAmount = optionResult.optionDiscountAmount;
|
|
1050
1175
|
}
|
|
1051
|
-
|
|
1176
|
+
|
|
1177
|
+
// total = 主商品折后 + option 行合计;开启 option 抵扣时必须用 discountedOptions,不能用未折扣的 product.options 再算一遍
|
|
1178
|
+
const optionsForLineTotal = isDeductOptionPrice && product.options?.length ? discountedOptions : product.options;
|
|
1052
1179
|
const optionsLineTotal = getOptionTotal(optionsForLineTotal || []);
|
|
1053
|
-
const total = new
|
|
1180
|
+
const total = new _decimal.default(mainProductSellingPrice).plus(optionsLineTotal).toNumber();
|
|
1181
|
+
|
|
1182
|
+
// discount_list.amount / fixed_amount:行级总优惠 = 主商品优惠 + option 优惠(与 total 变化一致)
|
|
1054
1183
|
const mainProductDiscountAmount = amount;
|
|
1055
|
-
const lineDiscountAmount = new
|
|
1056
|
-
const currentDiscountType = currentSelectedDiscount.tag ===
|
|
1057
|
-
const
|
|
1058
|
-
const currentIsGoodPass = currentDiscountType ===
|
|
1184
|
+
const lineDiscountAmount = new _decimal.default(mainProductDiscountAmount).plus(optionDiscountAmount).toNumber();
|
|
1185
|
+
const currentDiscountType = currentSelectedDiscount.tag === 'product_discount_card' ? 'discount_card' : currentSelectedDiscount.tag;
|
|
1186
|
+
const discountType = selectedDiscount.tag || selectedDiscount.type;
|
|
1187
|
+
const currentIsGoodPass = currentDiscountType === 'good_pass';
|
|
1059
1188
|
const discountDetail = {
|
|
1060
1189
|
amount: lineDiscountAmount,
|
|
1061
|
-
type: selectedDiscount.tag ===
|
|
1190
|
+
type: selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : discountType,
|
|
1062
1191
|
discount: {
|
|
1063
|
-
discount_card_type:
|
|
1192
|
+
discount_card_type: selectedDiscount?.metadata?.discount_card_type,
|
|
1064
1193
|
fixed_amount: lineDiscountAmount,
|
|
1065
|
-
discount_calculation_mode:
|
|
1194
|
+
discount_calculation_mode: selectedDiscount?.metadata?.discount_calculation_mode,
|
|
1066
1195
|
resource_id: selectedDiscount.id,
|
|
1067
1196
|
title: selectedDiscount.format_title,
|
|
1068
1197
|
original_amount: product.price,
|
|
@@ -1072,12 +1201,14 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1072
1201
|
},
|
|
1073
1202
|
// 前端使用的num数量,为了计算优惠金额(拆分时为1)
|
|
1074
1203
|
_num: isNeedSplit ? 1 : product.num,
|
|
1075
|
-
config: currentSelectedDiscount
|
|
1204
|
+
config: currentSelectedDiscount?.config,
|
|
1076
1205
|
metadata: {
|
|
1077
1206
|
num: 1,
|
|
1078
|
-
discount_rule_uncheck_flag: selectedDiscount
|
|
1207
|
+
discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
|
|
1079
1208
|
// 🔥 order_level 分摊差值
|
|
1080
|
-
...productDiscountDifference !==
|
|
1209
|
+
...(productDiscountDifference !== undefined && {
|
|
1210
|
+
product_discount_difference: productDiscountDifference
|
|
1211
|
+
}),
|
|
1081
1212
|
/** 仅主商品上的优惠金额(不含 option) */
|
|
1082
1213
|
mainProductDiscountAmount,
|
|
1083
1214
|
optionDiscountAmount
|
|
@@ -1085,73 +1216,82 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1085
1216
|
};
|
|
1086
1217
|
appliedProducts.push(discountDetail);
|
|
1087
1218
|
appliedDiscountProducts.set(currentSelectedDiscount.id, appliedProducts);
|
|
1219
|
+
|
|
1220
|
+
// 记录应用了优惠券的商品
|
|
1221
|
+
// 后续更新价格改为 getProductTotalPrice getProductOriginTotalPrice逻辑
|
|
1088
1222
|
if (product.isClient) {
|
|
1089
|
-
arr.push(
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
})
|
|
1107
|
-
);
|
|
1223
|
+
arr.push(this.hooks.setProduct(originProduct, {
|
|
1224
|
+
discount_list: [discountDetail],
|
|
1225
|
+
// good_pass:主商品价以折后价为准;勿用 product.price - amount(amount 含 option 优惠时会算错)
|
|
1226
|
+
price: currentIsGoodPass ? mainProductSellingPrice : product.price,
|
|
1227
|
+
quantity: isNeedSplit ? 1 : product.quantity,
|
|
1228
|
+
origin_total: (0, _utils2.getProductOriginTotalPrice)({
|
|
1229
|
+
product: {
|
|
1230
|
+
original_price: product.original_price
|
|
1231
|
+
},
|
|
1232
|
+
bundle: product.bundle,
|
|
1233
|
+
options: restoreOptionPrices(product.options)
|
|
1234
|
+
}),
|
|
1235
|
+
variant: originProduct._productInit.variant,
|
|
1236
|
+
original_price: new _decimal.default(product.price || 0).toNumber(),
|
|
1237
|
+
total: total,
|
|
1238
|
+
options: discountedOptions
|
|
1239
|
+
}));
|
|
1108
1240
|
} else {
|
|
1109
|
-
arr.push(
|
|
1110
|
-
this.
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
})
|
|
1120
|
-
);
|
|
1241
|
+
arr.push(this.hooks.setProduct(originProduct, {
|
|
1242
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion').concat([discountDetail]),
|
|
1243
|
+
_id: product._id.split('___')[0] + '___' + currentSelectedDiscount.id + '_' + i + '_' + index,
|
|
1244
|
+
price: currentIsGoodPass ? 0 : product.price,
|
|
1245
|
+
quantity: isNeedSplit ? 1 : product.quantity,
|
|
1246
|
+
total: total,
|
|
1247
|
+
origin_total: productOriginTotal,
|
|
1248
|
+
main_product_selling_price: mainProductSellingPrice,
|
|
1249
|
+
options: discountedOptions
|
|
1250
|
+
}));
|
|
1121
1251
|
}
|
|
1122
1252
|
}
|
|
1123
1253
|
processedProductsMap.set(product._id, arr);
|
|
1124
1254
|
} else {
|
|
1255
|
+
// 🔥 bundle子商品:支持拆分(商品券和折扣卡在 applicableProductLimit > 0 时都需要拆分)
|
|
1125
1256
|
const processedItems = [];
|
|
1126
1257
|
if (isNeedSplit) {
|
|
1258
|
+
// 需要拆分数量(商品券或折扣卡有 applicableProductLimit 限制)
|
|
1127
1259
|
const discountNum = splitCount;
|
|
1128
1260
|
const normalNum = totalQuantity - discountNum;
|
|
1261
|
+
|
|
1262
|
+
// 生成有折扣的商品(每个拆分商品 num: 1)
|
|
1129
1263
|
for (let i = 0; i < discountNum; i++) {
|
|
1264
|
+
// 商品券:每个拆分商品使用不同的商品券
|
|
1265
|
+
// 折扣卡:所有拆分商品使用同一张折扣卡
|
|
1130
1266
|
const currentBundleDiscount = isGoodPass ? selectedDiscountCard || applicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[0];
|
|
1131
1267
|
usedDiscounts.set(currentBundleDiscount.id, true);
|
|
1132
|
-
|
|
1268
|
+
// 🔥 更新 product_id 使用计数
|
|
1269
|
+
if ((currentBundleDiscount.tag || currentBundleDiscount.type) === 'good_pass') {
|
|
1133
1270
|
const currentCount = usedProductIdCounts.get(currentBundleDiscount.product_id) || 0;
|
|
1134
1271
|
usedProductIdCounts.set(currentBundleDiscount.product_id, currentCount + 1);
|
|
1135
1272
|
}
|
|
1273
|
+
// 🔥 更新折扣卡 applicableProductLimit 使用计数(跨商品全局)
|
|
1136
1274
|
const bundleDiscountTypeForCount = currentBundleDiscount.tag || currentBundleDiscount.type;
|
|
1137
|
-
if ([
|
|
1275
|
+
if (['discount_card', 'product_discount_card'].includes(bundleDiscountTypeForCount)) {
|
|
1138
1276
|
const currentBundleLimitCount = usedDiscountCardLimitCounts.get(currentBundleDiscount.id) || 0;
|
|
1139
1277
|
usedDiscountCardLimitCounts.set(currentBundleDiscount.id, currentBundleLimitCount + 1);
|
|
1140
1278
|
}
|
|
1279
|
+
|
|
1280
|
+
// 🔥 生成唯一的 _id
|
|
1141
1281
|
const uniqueId = `${flatItem._id}_split_${i}`;
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
const bundleDiscountType = currentBundleDiscount.tag ===
|
|
1282
|
+
|
|
1283
|
+
// 计算折扣后的价格(使用 getDiscountAmount,内部已处理 maxDeductionAmount)
|
|
1284
|
+
const discountedPrice = (0, _utils.getDiscountAmount)(currentBundleDiscount, product.origin_total, product.origin_total);
|
|
1285
|
+
const bundleDiscountAmount = new _decimal.default(product.origin_total || 0).minus(discountedPrice).toNumber();
|
|
1286
|
+
|
|
1287
|
+
// 确定折扣类型
|
|
1288
|
+
const bundleDiscountType = currentBundleDiscount.tag === 'product_discount_card' ? 'discount_card' : currentBundleDiscount.tag;
|
|
1149
1289
|
const discountDetail = {
|
|
1150
1290
|
amount: bundleDiscountAmount,
|
|
1151
1291
|
type: bundleDiscountType,
|
|
1152
1292
|
discount: {
|
|
1153
|
-
discount_card_type:
|
|
1154
|
-
discount_calculation_mode:
|
|
1293
|
+
discount_card_type: currentBundleDiscount?.metadata?.discount_card_type,
|
|
1294
|
+
discount_calculation_mode: currentBundleDiscount?.metadata?.discount_calculation_mode,
|
|
1155
1295
|
fixed_amount: bundleDiscountAmount,
|
|
1156
1296
|
resource_id: currentBundleDiscount.id,
|
|
1157
1297
|
title: currentBundleDiscount.format_title,
|
|
@@ -1163,12 +1303,14 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1163
1303
|
metadata: {
|
|
1164
1304
|
// 🔥 使用拆分后的唯一 _id
|
|
1165
1305
|
custom_product_bundle_map_id: uniqueId,
|
|
1166
|
-
discount_rule_uncheck_flag: selectedDiscount
|
|
1306
|
+
discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
|
|
1167
1307
|
num: 1
|
|
1168
1308
|
},
|
|
1169
1309
|
_num: 1,
|
|
1170
|
-
config: currentBundleDiscount
|
|
1310
|
+
config: currentBundleDiscount?.config
|
|
1171
1311
|
};
|
|
1312
|
+
|
|
1313
|
+
// 记录实际应用的折扣
|
|
1172
1314
|
const appliedProducts = appliedDiscountProducts.get(currentBundleDiscount.id) || [];
|
|
1173
1315
|
appliedProducts.push(discountDetail);
|
|
1174
1316
|
appliedDiscountProducts.set(currentBundleDiscount.id, appliedProducts);
|
|
@@ -1186,28 +1328,29 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1186
1328
|
_discountId: currentBundleDiscount.id
|
|
1187
1329
|
});
|
|
1188
1330
|
}
|
|
1331
|
+
|
|
1332
|
+
// 🔥 对拆分后的剩余商品继续匹配其他可用折扣(而不是等到下次执行才应用)
|
|
1189
1333
|
let remainingNum = normalNum;
|
|
1190
1334
|
let continueSplitIndex = discountNum;
|
|
1191
1335
|
while (remainingNum > 0) {
|
|
1192
|
-
|
|
1193
|
-
|
|
1336
|
+
// 重新查找适用于剩余商品的可用折扣(已使用的会被自动过滤掉)
|
|
1337
|
+
const nextApplicableDiscounts = sortedDiscountList.filter(nextDiscount => {
|
|
1194
1338
|
const nextDiscountType = nextDiscount.tag || nextDiscount.type;
|
|
1195
|
-
|
|
1196
|
-
|
|
1339
|
+
// 检查策略可用性
|
|
1340
|
+
if (['good_pass', 'discount_card', 'product_discount_card'].includes(nextDiscountType)) {
|
|
1341
|
+
if (nextDiscount.config === undefined || !nextDiscount?.config?.isAvailable) {
|
|
1197
1342
|
return false;
|
|
1198
1343
|
}
|
|
1199
1344
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
if (
|
|
1208
|
-
|
|
1209
|
-
if (nextDiscountType === "good_pass") {
|
|
1210
|
-
const maxUsagePerOrder = (_c2 = nextDiscount.config) == null ? void 0 : _c2.maxUsagePerOrder;
|
|
1345
|
+
// 折扣卡时总价为0时不可用
|
|
1346
|
+
if ((Number(product.total) <= 0 || !product.total) && !product.discount_list?.find(n => n.discount?.resource_id === nextDiscount.id) && nextDiscountType !== 'good_pass') return false;
|
|
1347
|
+
|
|
1348
|
+
// 商品券已被使用则跳过
|
|
1349
|
+
if (usedDiscounts.get(nextDiscount.id) && nextDiscountType === 'good_pass') return false;
|
|
1350
|
+
|
|
1351
|
+
// 检查 maxUsagePerOrder 限制
|
|
1352
|
+
if (nextDiscountType === 'good_pass') {
|
|
1353
|
+
const maxUsagePerOrder = nextDiscount.config?.maxUsagePerOrder;
|
|
1211
1354
|
if (maxUsagePerOrder && maxUsagePerOrder > 0) {
|
|
1212
1355
|
const currentUsedCount = usedProductIdCounts.get(nextDiscount.product_id) || 0;
|
|
1213
1356
|
if (currentUsedCount >= maxUsagePerOrder) {
|
|
@@ -1215,8 +1358,10 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1215
1358
|
}
|
|
1216
1359
|
}
|
|
1217
1360
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1361
|
+
|
|
1362
|
+
// 检查折扣卡的 applicableProductLimit 限制
|
|
1363
|
+
if (['discount_card', 'product_discount_card'].includes(nextDiscountType)) {
|
|
1364
|
+
const limitConfig = nextDiscount.config?.applicableProductLimit || 0;
|
|
1220
1365
|
if (limitConfig > 0) {
|
|
1221
1366
|
const currentUsedLimitCount = usedDiscountCardLimitCounts.get(nextDiscount.id) || 0;
|
|
1222
1367
|
if (currentUsedLimitCount >= limitConfig) {
|
|
@@ -1225,7 +1370,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1225
1370
|
}
|
|
1226
1371
|
}
|
|
1227
1372
|
const limitedData = nextDiscount.limited_relation_product_data;
|
|
1228
|
-
if (limitedData.type ===
|
|
1373
|
+
if (limitedData.type === 'product_all') {
|
|
1229
1374
|
if (limitedData.filter === 1 && limitedData.exclude_product_ids.includes(product.id)) {
|
|
1230
1375
|
return false;
|
|
1231
1376
|
}
|
|
@@ -1241,6 +1386,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1241
1386
|
}
|
|
1242
1387
|
return false;
|
|
1243
1388
|
});
|
|
1389
|
+
|
|
1390
|
+
// 没有更多可用折扣,剩余商品无折扣存储
|
|
1244
1391
|
if (nextApplicableDiscounts.length === 0) {
|
|
1245
1392
|
processedItems.push({
|
|
1246
1393
|
...flatItem,
|
|
@@ -1252,37 +1399,40 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1252
1399
|
});
|
|
1253
1400
|
break;
|
|
1254
1401
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
);
|
|
1402
|
+
|
|
1403
|
+
// 选择最优折扣
|
|
1404
|
+
const nextSelectedDiscountCard = nextApplicableDiscounts.find(n => n.isScan && n.isSelected && (n.tag || n.type) !== 'good_pass');
|
|
1258
1405
|
const nextSelectedDiscount = nextSelectedDiscountCard || nextApplicableDiscounts[0];
|
|
1406
|
+
|
|
1407
|
+
// 判断新折扣是否需要拆分
|
|
1259
1408
|
const nextDiscType = nextSelectedDiscount.tag || nextSelectedDiscount.type;
|
|
1260
|
-
const nextIsGoodPass = nextDiscType ===
|
|
1261
|
-
const nextIsDiscountCard = [
|
|
1262
|
-
const nextApplicableProductLimit =
|
|
1409
|
+
const nextIsGoodPass = nextDiscType === 'good_pass';
|
|
1410
|
+
const nextIsDiscountCard = ['discount_card', 'product_discount_card'].includes(nextDiscType);
|
|
1411
|
+
const nextApplicableProductLimit = nextSelectedDiscount.config?.applicableProductLimit || 0;
|
|
1263
1412
|
const nextIsNeedSplit = nextIsGoodPass || nextIsDiscountCard && nextApplicableProductLimit > 0;
|
|
1264
1413
|
if (!nextIsNeedSplit) {
|
|
1414
|
+
// 🔥 不需要拆分:直接应用折扣到所有剩余商品
|
|
1265
1415
|
const nextBundleDiscount = nextSelectedDiscountCard || nextApplicableDiscounts[0];
|
|
1266
1416
|
usedDiscounts.set(nextBundleDiscount.id, true);
|
|
1267
|
-
if ((nextBundleDiscount.tag || nextBundleDiscount.type) ===
|
|
1417
|
+
if ((nextBundleDiscount.tag || nextBundleDiscount.type) === 'good_pass') {
|
|
1268
1418
|
const curCount = usedProductIdCounts.get(nextBundleDiscount.product_id) || 0;
|
|
1269
1419
|
usedProductIdCounts.set(nextBundleDiscount.product_id, curCount + 1);
|
|
1270
1420
|
}
|
|
1271
1421
|
const nextNoSplitType = nextBundleDiscount.tag || nextBundleDiscount.type;
|
|
1272
|
-
if ([
|
|
1422
|
+
if (['discount_card', 'product_discount_card'].includes(nextNoSplitType)) {
|
|
1273
1423
|
const curCount = usedDiscountCardLimitCounts.get(nextBundleDiscount.id) || 0;
|
|
1274
1424
|
usedDiscountCardLimitCounts.set(nextBundleDiscount.id, curCount + remainingNum);
|
|
1275
1425
|
}
|
|
1276
1426
|
const nextOriginTotal = product.original_price || product.price || 0;
|
|
1277
|
-
const nextTargetTotal = (0,
|
|
1278
|
-
const nextDiscountAmount = new
|
|
1427
|
+
const nextTargetTotal = (0, _utils.getDiscountAmount)(nextBundleDiscount, nextOriginTotal, nextOriginTotal);
|
|
1428
|
+
const nextDiscountAmount = new _decimal.default(nextOriginTotal).minus(nextTargetTotal).toNumber();
|
|
1279
1429
|
const nextUniqueId = `${flatItem._id}_split_${continueSplitIndex}`;
|
|
1280
|
-
const nextBundleDiscType = nextBundleDiscount.tag ===
|
|
1430
|
+
const nextBundleDiscType = nextBundleDiscount.tag === 'product_discount_card' ? 'discount_card' : nextBundleDiscount.tag;
|
|
1281
1431
|
const nextDiscountDetail = {
|
|
1282
1432
|
amount: nextDiscountAmount * remainingNum,
|
|
1283
1433
|
type: nextBundleDiscType,
|
|
1284
1434
|
discount: {
|
|
1285
|
-
discount_card_type:
|
|
1435
|
+
discount_card_type: nextBundleDiscount?.metadata?.discount_card_type,
|
|
1286
1436
|
fixed_amount: nextDiscountAmount,
|
|
1287
1437
|
resource_id: nextBundleDiscount.id,
|
|
1288
1438
|
title: nextBundleDiscount.format_title,
|
|
@@ -1295,8 +1445,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1295
1445
|
custom_product_bundle_map_id: nextUniqueId,
|
|
1296
1446
|
num: remainingNum
|
|
1297
1447
|
},
|
|
1298
|
-
config: nextBundleDiscount
|
|
1299
|
-
_num: remainingNum * (
|
|
1448
|
+
config: nextBundleDiscount?.config,
|
|
1449
|
+
_num: remainingNum * (flatItem?.parentProduct?.num || 1)
|
|
1300
1450
|
};
|
|
1301
1451
|
const nextAppliedProducts = appliedDiscountProducts.get(nextBundleDiscount.id) || [];
|
|
1302
1452
|
nextAppliedProducts.push(nextDiscountDetail);
|
|
@@ -1307,25 +1457,22 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1307
1457
|
num: remainingNum,
|
|
1308
1458
|
quantity: remainingNum,
|
|
1309
1459
|
total: nextTargetTotal,
|
|
1310
|
-
price: new
|
|
1460
|
+
price: new _decimal.default(nextOriginTotal || 0).minus(nextDiscountDetail.discount.fixed_amount).toNumber(),
|
|
1311
1461
|
discount_list: [nextDiscountDetail],
|
|
1312
1462
|
processed: true
|
|
1313
1463
|
});
|
|
1314
1464
|
remainingNum = 0;
|
|
1315
1465
|
break;
|
|
1316
1466
|
}
|
|
1467
|
+
|
|
1468
|
+
// 🔥 需要拆分:计算最大使用次数
|
|
1317
1469
|
let nextMaxUsageLimit;
|
|
1318
1470
|
if (nextIsGoodPass) {
|
|
1319
|
-
const nextGoodPassCount = nextApplicableDiscounts.filter(
|
|
1320
|
-
(item) => (item.tag || item.type) === "good_pass"
|
|
1321
|
-
).length;
|
|
1471
|
+
const nextGoodPassCount = nextApplicableDiscounts.filter(item => (item.tag || item.type) === 'good_pass').length;
|
|
1322
1472
|
nextMaxUsageLimit = nextGoodPassCount;
|
|
1323
|
-
if (
|
|
1473
|
+
if (nextSelectedDiscount.config?.maxUsagePerOrder) {
|
|
1324
1474
|
const usedCount = usedProductIdCounts.get(nextSelectedDiscount.product_id) || 0;
|
|
1325
|
-
nextMaxUsageLimit = Math.min(
|
|
1326
|
-
nextGoodPassCount,
|
|
1327
|
-
Math.max(0, nextSelectedDiscount.config.maxUsagePerOrder - usedCount)
|
|
1328
|
-
);
|
|
1475
|
+
nextMaxUsageLimit = Math.min(nextGoodPassCount, Math.max(0, nextSelectedDiscount.config.maxUsagePerOrder - usedCount));
|
|
1329
1476
|
}
|
|
1330
1477
|
} else if (nextIsDiscountCard && nextApplicableProductLimit > 0) {
|
|
1331
1478
|
const usedLimitCount = usedDiscountCardLimitCounts.get(nextSelectedDiscount.id) || 0;
|
|
@@ -1335,6 +1482,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1335
1482
|
}
|
|
1336
1483
|
const nextSplitCount = Math.min(remainingNum, nextMaxUsageLimit);
|
|
1337
1484
|
if (nextSplitCount === 0) {
|
|
1485
|
+
// 已达使用上限,剩余商品无折扣存储
|
|
1338
1486
|
processedItems.push({
|
|
1339
1487
|
...flatItem,
|
|
1340
1488
|
_id: `${flatItem._id}_split_rest`,
|
|
@@ -1345,31 +1493,29 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1345
1493
|
});
|
|
1346
1494
|
break;
|
|
1347
1495
|
}
|
|
1496
|
+
|
|
1497
|
+
// 生成有折扣的商品
|
|
1348
1498
|
for (let j = 0; j < nextSplitCount; j++) {
|
|
1349
1499
|
const nextBundleDiscount = nextIsGoodPass ? nextSelectedDiscountCard || nextApplicableDiscounts[j] : nextSelectedDiscountCard || nextApplicableDiscounts[0];
|
|
1350
1500
|
usedDiscounts.set(nextBundleDiscount.id, true);
|
|
1351
|
-
if ((nextBundleDiscount.tag || nextBundleDiscount.type) ===
|
|
1501
|
+
if ((nextBundleDiscount.tag || nextBundleDiscount.type) === 'good_pass') {
|
|
1352
1502
|
const curCount = usedProductIdCounts.get(nextBundleDiscount.product_id) || 0;
|
|
1353
1503
|
usedProductIdCounts.set(nextBundleDiscount.product_id, curCount + 1);
|
|
1354
1504
|
}
|
|
1355
1505
|
const nextBundleDiscTypeForCount = nextBundleDiscount.tag || nextBundleDiscount.type;
|
|
1356
|
-
if ([
|
|
1506
|
+
if (['discount_card', 'product_discount_card'].includes(nextBundleDiscTypeForCount)) {
|
|
1357
1507
|
const curLimitCount = usedDiscountCardLimitCounts.get(nextBundleDiscount.id) || 0;
|
|
1358
1508
|
usedDiscountCardLimitCounts.set(nextBundleDiscount.id, curLimitCount + 1);
|
|
1359
1509
|
}
|
|
1360
1510
|
const nextUniqueId = `${flatItem._id}_split_${continueSplitIndex}`;
|
|
1361
|
-
const nextDiscountedPrice = (0,
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
product.origin_total
|
|
1365
|
-
);
|
|
1366
|
-
const nextBundleDiscAmount = new import_decimal.default(product.origin_total || 0).minus(nextDiscountedPrice).toNumber();
|
|
1367
|
-
const nextBundleDiscTypeStr = nextBundleDiscount.tag === "product_discount_card" ? "discount_card" : nextBundleDiscount.tag;
|
|
1511
|
+
const nextDiscountedPrice = (0, _utils.getDiscountAmount)(nextBundleDiscount, product.origin_total, product.origin_total);
|
|
1512
|
+
const nextBundleDiscAmount = new _decimal.default(product.origin_total || 0).minus(nextDiscountedPrice).toNumber();
|
|
1513
|
+
const nextBundleDiscTypeStr = nextBundleDiscount.tag === 'product_discount_card' ? 'discount_card' : nextBundleDiscount.tag;
|
|
1368
1514
|
const nextDiscountDetail = {
|
|
1369
1515
|
amount: nextBundleDiscAmount,
|
|
1370
1516
|
type: nextBundleDiscTypeStr,
|
|
1371
1517
|
discount: {
|
|
1372
|
-
discount_card_type:
|
|
1518
|
+
discount_card_type: nextBundleDiscount?.metadata?.discount_card_type,
|
|
1373
1519
|
fixed_amount: nextBundleDiscAmount,
|
|
1374
1520
|
resource_id: nextBundleDiscount.id,
|
|
1375
1521
|
title: nextBundleDiscount.format_title,
|
|
@@ -1383,7 +1529,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1383
1529
|
num: 1
|
|
1384
1530
|
},
|
|
1385
1531
|
_num: 1,
|
|
1386
|
-
config: nextBundleDiscount
|
|
1532
|
+
config: nextBundleDiscount?.config
|
|
1387
1533
|
};
|
|
1388
1534
|
const nextAppliedProducts = appliedDiscountProducts.get(nextBundleDiscount.id) || [];
|
|
1389
1535
|
nextAppliedProducts.push(nextDiscountDetail);
|
|
@@ -1404,46 +1550,53 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1404
1550
|
remainingNum -= nextSplitCount;
|
|
1405
1551
|
}
|
|
1406
1552
|
} else {
|
|
1553
|
+
// 不拆分:直接应用折扣
|
|
1407
1554
|
const currentBundleDiscount = selectedDiscountCard || applicableDiscounts[0];
|
|
1408
1555
|
usedDiscounts.set(currentBundleDiscount.id, true);
|
|
1409
|
-
|
|
1556
|
+
// 🔥 更新 product_id 使用计数
|
|
1557
|
+
if ((currentBundleDiscount.tag || currentBundleDiscount.type) === 'good_pass') {
|
|
1410
1558
|
const currentCount = usedProductIdCounts.get(currentBundleDiscount.product_id) || 0;
|
|
1411
1559
|
usedProductIdCounts.set(currentBundleDiscount.product_id, currentCount + 1);
|
|
1412
1560
|
}
|
|
1561
|
+
// 🔥 更新折扣卡 applicableProductLimit 使用计数(不拆分时按商品数量计数)
|
|
1413
1562
|
const noSplitDiscountType = currentBundleDiscount.tag || currentBundleDiscount.type;
|
|
1414
|
-
if ([
|
|
1563
|
+
if (['discount_card', 'product_discount_card'].includes(noSplitDiscountType)) {
|
|
1415
1564
|
const bundleQuantity = product.num || 1;
|
|
1416
1565
|
const currentNoSplitCount = usedDiscountCardLimitCounts.get(currentBundleDiscount.id) || 0;
|
|
1417
1566
|
usedDiscountCardLimitCounts.set(currentBundleDiscount.id, currentNoSplitCount + bundleQuantity);
|
|
1418
1567
|
}
|
|
1419
1568
|
const productOriginTotal = product.original_price || product.price || 0;
|
|
1420
|
-
|
|
1569
|
+
|
|
1570
|
+
// 🔥 检查是否是 order_level 固定金额折扣卡
|
|
1571
|
+
const isOrderLevel = (0, _utils.isOrderLevelFixedAmountDiscount)(selectedDiscount);
|
|
1421
1572
|
const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
|
|
1422
|
-
const productAllocation = orderLevelAllocation
|
|
1573
|
+
const productAllocation = orderLevelAllocation?.get(flatItem._id);
|
|
1423
1574
|
let targetProductTotal;
|
|
1424
1575
|
let fixedAmountPerItem;
|
|
1425
1576
|
let productDiscountDifference;
|
|
1426
1577
|
if (isOrderLevel && productAllocation) {
|
|
1578
|
+
// order_level:使用预计算的单价折扣金额(已经是单价,无需再除以数量)
|
|
1427
1579
|
fixedAmountPerItem = productAllocation.discountAmount;
|
|
1428
1580
|
productDiscountDifference = productAllocation.difference;
|
|
1429
|
-
targetProductTotal = Math.max(new
|
|
1581
|
+
targetProductTotal = Math.max(new _decimal.default(productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
|
|
1430
1582
|
} else {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
productOriginTotal
|
|
1435
|
-
);
|
|
1436
|
-
fixedAmountPerItem = new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
|
|
1583
|
+
// item_level 或其他类型:使用原有逻辑
|
|
1584
|
+
targetProductTotal = (0, _utils.getDiscountAmount)(currentBundleDiscount, productOriginTotal, productOriginTotal);
|
|
1585
|
+
fixedAmountPerItem = new _decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
|
|
1437
1586
|
}
|
|
1438
|
-
|
|
1587
|
+
|
|
1588
|
+
// 计算实际折扣金额
|
|
1589
|
+
const bundleActualDiscountAmount = new _decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
|
|
1590
|
+
|
|
1591
|
+
// 🔥 使用当前的 _id 作为唯一标识
|
|
1439
1592
|
const uniqueId = flatItem._id;
|
|
1440
1593
|
const discountDetail = {
|
|
1441
1594
|
amount: bundleActualDiscountAmount * (product.num || 1),
|
|
1442
|
-
type: currentBundleDiscount.tag ===
|
|
1595
|
+
type: currentBundleDiscount.tag === 'product_discount_card' ? 'discount_card' : currentBundleDiscount.tag,
|
|
1443
1596
|
discount: {
|
|
1444
|
-
discount_card_type:
|
|
1597
|
+
discount_card_type: currentBundleDiscount?.metadata?.discount_card_type,
|
|
1445
1598
|
fixed_amount: bundleActualDiscountAmount,
|
|
1446
|
-
discount_calculation_mode:
|
|
1599
|
+
discount_calculation_mode: currentBundleDiscount?.metadata?.discount_calculation_mode,
|
|
1447
1600
|
resource_id: currentBundleDiscount.id,
|
|
1448
1601
|
title: currentBundleDiscount.format_title,
|
|
1449
1602
|
original_amount: product.original_price,
|
|
@@ -1454,41 +1607,50 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1454
1607
|
metadata: {
|
|
1455
1608
|
// 🔥 使用唯一的 _id
|
|
1456
1609
|
custom_product_bundle_map_id: uniqueId,
|
|
1457
|
-
discount_rule_uncheck_flag: selectedDiscount
|
|
1610
|
+
discount_rule_uncheck_flag: selectedDiscount?.discount_rule_uncheck_flag,
|
|
1458
1611
|
num: product.num || 1,
|
|
1459
1612
|
// 🔥 order_level 分摊差值
|
|
1460
|
-
...productDiscountDifference !==
|
|
1613
|
+
...(productDiscountDifference !== undefined && {
|
|
1614
|
+
product_discount_difference: productDiscountDifference
|
|
1615
|
+
})
|
|
1461
1616
|
},
|
|
1462
|
-
config: currentBundleDiscount
|
|
1463
|
-
_num: (product.num || 1) * (
|
|
1617
|
+
config: currentBundleDiscount?.config,
|
|
1618
|
+
_num: (product.num || 1) * (flatItem?.parentProduct?.num || 1)
|
|
1464
1619
|
};
|
|
1620
|
+
|
|
1621
|
+
// 记录实际应用的折扣
|
|
1465
1622
|
const appliedProducts = appliedDiscountProducts.get(currentBundleDiscount.id) || [];
|
|
1466
1623
|
appliedProducts.push(discountDetail);
|
|
1467
1624
|
appliedDiscountProducts.set(currentBundleDiscount.id, appliedProducts);
|
|
1468
1625
|
processedItems.push({
|
|
1469
1626
|
...flatItem,
|
|
1470
1627
|
total: targetProductTotal,
|
|
1471
|
-
price: new
|
|
1472
|
-
discount_list: this.filterDiscountListByType(flatItem.discount_list,
|
|
1628
|
+
price: new _decimal.default(productOriginTotal || 0).minus(fixedAmountPerItem).toNumber(),
|
|
1629
|
+
discount_list: this.filterDiscountListByType(flatItem.discount_list, 'promotion').concat([discountDetail]),
|
|
1473
1630
|
processed: true
|
|
1474
1631
|
});
|
|
1475
1632
|
}
|
|
1476
1633
|
processedFlatItemsMap.set(flatItem._id, processedItems);
|
|
1477
1634
|
}
|
|
1478
1635
|
});
|
|
1479
|
-
|
|
1636
|
+
|
|
1637
|
+
// 🔥 重组:将处理后的bundle子商品重新组装回主商品
|
|
1638
|
+
const reconstructProductsWithBundle = (processedProductsMap, processedFlatItemsMap, originalProductList) => {
|
|
1480
1639
|
const result = [];
|
|
1481
|
-
originalProductList.forEach(
|
|
1640
|
+
originalProductList.forEach(originProduct => {
|
|
1482
1641
|
const product = this.hooks.getProduct(originProduct);
|
|
1483
|
-
|
|
1642
|
+
|
|
1643
|
+
// 获取主商品处理结果
|
|
1644
|
+
const mainProductArr = processedProductsMap.get(product._id);
|
|
1484
1645
|
if (!mainProductArr || mainProductArr.length === 0) {
|
|
1646
|
+
// 如果没有处理结果,返回默认商品(还原 option 价格)
|
|
1485
1647
|
const getDefaultProduct = () => {
|
|
1486
1648
|
const restoredOptions = restoreOptionPrices(product.options);
|
|
1487
1649
|
if (product.isClient) {
|
|
1488
1650
|
return this.hooks.setProduct(originProduct, {
|
|
1489
|
-
discount_list: this.filterDiscountListByType(product.discount_list,
|
|
1651
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1490
1652
|
price: product.price,
|
|
1491
|
-
origin_total: (0,
|
|
1653
|
+
origin_total: (0, _utils2.getProductOriginTotalPrice)({
|
|
1492
1654
|
product: {
|
|
1493
1655
|
original_price: product.original_price
|
|
1494
1656
|
},
|
|
@@ -1497,7 +1659,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1497
1659
|
}),
|
|
1498
1660
|
variant: originProduct._productInit.variant,
|
|
1499
1661
|
original_price: originProduct._productInit.original_price,
|
|
1500
|
-
total: (0,
|
|
1662
|
+
total: (0, _utils2.getProductTotalPrice)({
|
|
1501
1663
|
product: {
|
|
1502
1664
|
price: product.price
|
|
1503
1665
|
},
|
|
@@ -1508,7 +1670,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1508
1670
|
});
|
|
1509
1671
|
} else {
|
|
1510
1672
|
return this.hooks.setProduct(originProduct, {
|
|
1511
|
-
discount_list: this.filterDiscountListByType(product.discount_list,
|
|
1673
|
+
discount_list: this.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1512
1674
|
total: product.total,
|
|
1513
1675
|
origin_total: product.origin_total,
|
|
1514
1676
|
price: product.price,
|
|
@@ -1519,332 +1681,360 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1519
1681
|
result.push(getDefaultProduct());
|
|
1520
1682
|
return;
|
|
1521
1683
|
}
|
|
1684
|
+
|
|
1685
|
+
// 检查是否有bundle子商品需要重组
|
|
1522
1686
|
const hasBundle = product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0;
|
|
1523
1687
|
if (!hasBundle) {
|
|
1688
|
+
// 没有bundle,直接使用主商品处理结果
|
|
1524
1689
|
result.push(...mainProductArr);
|
|
1525
1690
|
} else {
|
|
1526
|
-
|
|
1527
|
-
|
|
1691
|
+
// 🔥 有bundle,需要检查子商品是否应用了商品券
|
|
1692
|
+
// 1. 先收集所有bundle子商品的处理结果
|
|
1693
|
+
const bundleProcessingInfo = new Map();
|
|
1694
|
+
let hasGoodPassApplied = false; // 标记是否有子商品应用了商品券
|
|
1695
|
+
|
|
1528
1696
|
if (product.bundle && Array.isArray(product.bundle)) {
|
|
1529
1697
|
product.bundle.forEach((bundleItem, bundleIndex) => {
|
|
1530
1698
|
const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
|
|
1531
|
-
const processedBundleItems =
|
|
1699
|
+
const processedBundleItems = processedFlatItemsMap.get(bundleItemId);
|
|
1532
1700
|
if (!processedBundleItems || processedBundleItems.length === 0) {
|
|
1701
|
+
// 未处理的bundle item,保持原样
|
|
1533
1702
|
bundleProcessingInfo.set(bundleIndex, [bundleItem]);
|
|
1534
1703
|
} else {
|
|
1704
|
+
// 处理过的bundle item
|
|
1535
1705
|
bundleProcessingInfo.set(bundleIndex, processedBundleItems);
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
var _a;
|
|
1539
|
-
return (_a = item.discount_list) == null ? void 0 : _a.some(
|
|
1540
|
-
(discount) => discount.type === "good_pass" || discount.tag === "good_pass"
|
|
1541
|
-
);
|
|
1542
|
-
}
|
|
1543
|
-
);
|
|
1706
|
+
// 🔥 检查是否应用了商品券(good_pass)
|
|
1707
|
+
const hasGoodPass = processedBundleItems.some(item => item.discount_list?.some(discount => discount.type === 'good_pass' || discount.tag === 'good_pass'));
|
|
1544
1708
|
if (hasGoodPass) {
|
|
1545
1709
|
hasGoodPassApplied = true;
|
|
1546
1710
|
}
|
|
1547
1711
|
}
|
|
1548
1712
|
});
|
|
1549
1713
|
}
|
|
1714
|
+
|
|
1715
|
+
// 🔥 2. 如果有子商品应用了商品券,且主商品数量大于1,需要拆分主商品
|
|
1550
1716
|
const mainProductQuantity = mainProductArr[0] ? this.hooks.getProduct(mainProductArr[0]).quantity : 1;
|
|
1551
1717
|
if (hasGoodPassApplied && mainProductArr.length === 1 && mainProductQuantity > 1) {
|
|
1552
1718
|
const mainProduct = mainProductArr[0];
|
|
1553
1719
|
const mainProductData = this.hooks.getProduct(mainProduct);
|
|
1720
|
+
|
|
1721
|
+
// 🔥 方案:拆分成2个主商品
|
|
1722
|
+
// 1. 一个主商品(qty=1)包含拆分后的bundle
|
|
1723
|
+
// 2. 一个主商品(qty=原quantity-1)包含原始未拆分的bundle
|
|
1724
|
+
|
|
1725
|
+
// 第一个:包含拆分后的bundle (qty=1)
|
|
1554
1726
|
const newBundleWithDiscount = [];
|
|
1555
|
-
(product.bundle || []).forEach(
|
|
1556
|
-
(
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
...discount,
|
|
1566
|
-
metadata: {
|
|
1567
|
-
...discount.metadata,
|
|
1568
|
-
num: item.num,
|
|
1569
|
-
custom_product_bundle_map_id: (_a = item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id
|
|
1570
|
-
}
|
|
1571
|
-
// num: item.num, // 使用拆分后的 num
|
|
1572
|
-
};
|
|
1573
|
-
});
|
|
1574
|
-
newBundleWithDiscount.push({
|
|
1575
|
-
...bundleItem,
|
|
1576
|
-
_id: item._id,
|
|
1577
|
-
product_id: bundleItem.product_id,
|
|
1578
|
-
price: item.price,
|
|
1727
|
+
(product.bundle || []).forEach((bundleItem, bundleIndex) => {
|
|
1728
|
+
const processedItems = bundleProcessingInfo.get(bundleIndex) || [bundleItem];
|
|
1729
|
+
if (processedItems.length > 1) {
|
|
1730
|
+
// 被拆分的子商品,添加所有拆分项
|
|
1731
|
+
processedItems.forEach(item => {
|
|
1732
|
+
// 🔥 更新 discount_list 中的 num,使其与拆分后的 item.num 一致
|
|
1733
|
+
const updatedDiscountList = (item.discount_list || []).map(discount => ({
|
|
1734
|
+
...discount,
|
|
1735
|
+
metadata: {
|
|
1736
|
+
...discount.metadata,
|
|
1579
1737
|
num: item.num,
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1738
|
+
custom_product_bundle_map_id: item.metadata?.custom_product_bundle_map_id
|
|
1739
|
+
}
|
|
1740
|
+
// num: item.num, // 使用拆分后的 num
|
|
1741
|
+
}));
|
|
1742
|
+
newBundleWithDiscount.push({
|
|
1743
|
+
...bundleItem,
|
|
1744
|
+
_id: item._id,
|
|
1745
|
+
product_id: bundleItem.product_id,
|
|
1746
|
+
price: item.price,
|
|
1747
|
+
num: item.num,
|
|
1748
|
+
quantity: item.num,
|
|
1749
|
+
discount_list: updatedDiscountList
|
|
1583
1750
|
});
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
custom_product_bundle_map_id: (_a = item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id
|
|
1595
|
-
}
|
|
1596
|
-
// num: item.num, // 使用当前的 num
|
|
1597
|
-
};
|
|
1598
|
-
});
|
|
1599
|
-
newBundleWithDiscount.push({
|
|
1600
|
-
...bundleItem,
|
|
1601
|
-
_id: item._id,
|
|
1602
|
-
product_id: bundleItem.product_id,
|
|
1603
|
-
price: item.price,
|
|
1751
|
+
});
|
|
1752
|
+
} else {
|
|
1753
|
+
// 未拆分的子商品,保持原样
|
|
1754
|
+
const item = processedItems[0];
|
|
1755
|
+
if (item.processed) {
|
|
1756
|
+
// 🔥 同样需要更新 discount_list 中的 num
|
|
1757
|
+
const updatedDiscountList = (item.discount_list || []).map(discount => ({
|
|
1758
|
+
...discount,
|
|
1759
|
+
metadata: {
|
|
1760
|
+
...discount.metadata,
|
|
1604
1761
|
num: item.num,
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1762
|
+
custom_product_bundle_map_id: item.metadata?.custom_product_bundle_map_id
|
|
1763
|
+
}
|
|
1764
|
+
// num: item.num, // 使用当前的 num
|
|
1765
|
+
}));
|
|
1766
|
+
newBundleWithDiscount.push({
|
|
1767
|
+
...bundleItem,
|
|
1768
|
+
_id: item._id,
|
|
1769
|
+
product_id: bundleItem.product_id,
|
|
1770
|
+
price: item.price,
|
|
1771
|
+
num: item.num,
|
|
1772
|
+
quantity: item.num,
|
|
1773
|
+
discount_list: updatedDiscountList
|
|
1774
|
+
});
|
|
1775
|
+
} else {
|
|
1776
|
+
newBundleWithDiscount.push(item);
|
|
1611
1777
|
}
|
|
1612
1778
|
}
|
|
1613
|
-
);
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
// 计算第一个主商品的总价(包含拆分后的bundle)
|
|
1614
1782
|
let newTotalWithDiscount = Number(mainProductData.price || 0);
|
|
1615
|
-
let newOriginTotalWithDiscount = Number(
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
const updatedMainDiscountList = mainProductData.discount_list.map(
|
|
1619
|
-
|
|
1620
|
-
|
|
1783
|
+
let newOriginTotalWithDiscount = Number(mainProductData.original_price || mainProductData.price || 0);
|
|
1784
|
+
|
|
1785
|
+
// 🔥 更新主商品自己的 discount_list 中的 num(quantity=1)
|
|
1786
|
+
const updatedMainDiscountList = mainProductData.discount_list.map(discount => {
|
|
1787
|
+
if (discount?.metadata?.custom_product_bundle_map_id) {
|
|
1788
|
+
// bundle的discount_list保持不变
|
|
1621
1789
|
return discount;
|
|
1622
1790
|
}
|
|
1791
|
+
// 主商品自己的discount,更新num为1
|
|
1623
1792
|
return {
|
|
1624
1793
|
...discount,
|
|
1625
1794
|
// num: 1,
|
|
1626
1795
|
metadata: {
|
|
1627
1796
|
...discount.metadata,
|
|
1628
|
-
custom_product_bundle_map_id:
|
|
1797
|
+
custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id,
|
|
1629
1798
|
num: 1
|
|
1630
1799
|
}
|
|
1631
1800
|
};
|
|
1632
1801
|
});
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
return !((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id);
|
|
1637
|
-
}
|
|
1638
|
-
);
|
|
1802
|
+
|
|
1803
|
+
// 🔥 使用更新后的列表计算折扣金额
|
|
1804
|
+
const mainDiscountList = updatedMainDiscountList.filter(item => !item?.metadata?.custom_product_bundle_map_id);
|
|
1639
1805
|
if (mainDiscountList && mainDiscountList.length > 0) {
|
|
1640
|
-
const allDiscountAmount = (0,
|
|
1641
|
-
newTotalWithDiscount = new
|
|
1806
|
+
const allDiscountAmount = (0, _utils.getDiscountListAmountTotal)(mainDiscountList);
|
|
1807
|
+
newTotalWithDiscount = new _decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalWithDiscount;
|
|
1642
1808
|
newOriginTotalWithDiscount = mainProductData.origin_total ?? newOriginTotalWithDiscount;
|
|
1643
1809
|
}
|
|
1810
|
+
|
|
1811
|
+
// 累加bundle的价格(只累加一次)
|
|
1644
1812
|
if (newBundleWithDiscount.length > 0) {
|
|
1645
|
-
newBundleWithDiscount.forEach(
|
|
1813
|
+
newBundleWithDiscount.forEach(item => {
|
|
1646
1814
|
newTotalWithDiscount += Number(item.price) * Number(item.num);
|
|
1647
1815
|
});
|
|
1648
|
-
newBundleWithDiscount.forEach(
|
|
1649
|
-
|
|
1650
|
-
const originalPrice = ((_c = (_b = (_a = item.discount_list) == null ? void 0 : _a[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
|
|
1816
|
+
newBundleWithDiscount.forEach(item => {
|
|
1817
|
+
const originalPrice = item.discount_list?.[0]?.discount?.original_amount || item.price;
|
|
1651
1818
|
newOriginTotalWithDiscount += Number(originalPrice) * Number(item.num);
|
|
1652
1819
|
});
|
|
1653
1820
|
}
|
|
1654
|
-
|
|
1821
|
+
|
|
1822
|
+
// 累加options的价格(options不参与折扣,在最终设置total时处理)
|
|
1823
|
+
if (product?.options) {
|
|
1655
1824
|
newTotalWithDiscount = product.options.reduce((accumulator, currentValue) => {
|
|
1656
|
-
const currentPrice = new
|
|
1657
|
-
const currentNum = new
|
|
1825
|
+
const currentPrice = new _decimal.default(currentValue.price || 0);
|
|
1826
|
+
const currentNum = new _decimal.default(currentValue.num || 0);
|
|
1658
1827
|
return accumulator.add(currentPrice.mul(currentNum));
|
|
1659
|
-
}, new
|
|
1828
|
+
}, new _decimal.default(newTotalWithDiscount)).toNumber();
|
|
1660
1829
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
);
|
|
1830
|
+
|
|
1831
|
+
// 添加第一个主商品:qty=1,包含拆分后的bundle
|
|
1832
|
+
result.push(this.hooks.setProduct(mainProduct, {
|
|
1833
|
+
...mainProductData,
|
|
1834
|
+
_id: `${mainProductData._id.split('___')[0]}___split_discount`,
|
|
1835
|
+
quantity: 1,
|
|
1836
|
+
discount_list: updatedMainDiscountList,
|
|
1837
|
+
bundle: newBundleWithDiscount,
|
|
1838
|
+
total: new _decimal.default(newTotalWithDiscount).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber(),
|
|
1839
|
+
origin_total: new _decimal.default(newOriginTotalWithDiscount).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber()
|
|
1840
|
+
}));
|
|
1841
|
+
|
|
1842
|
+
// 第二个:包含原始bundle (qty=原quantity-1)
|
|
1672
1843
|
if (mainProductQuantity > 1) {
|
|
1673
1844
|
const newBundleOriginal = [];
|
|
1674
|
-
(product.bundle || []).forEach(
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1845
|
+
(product.bundle || []).forEach((bundleItem, bundleIndex) => {
|
|
1846
|
+
// 使用原始的bundle配置,不包含拆分
|
|
1847
|
+
newBundleOriginal.push({
|
|
1848
|
+
...bundleItem,
|
|
1849
|
+
discount_list: []
|
|
1850
|
+
});
|
|
1851
|
+
});
|
|
1852
|
+
|
|
1853
|
+
// 计算第二个主商品的总价
|
|
1682
1854
|
let newTotalOriginal = Number(mainProductData.price || 0);
|
|
1683
|
-
let newOriginTotalOriginal = Number(
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
const updatedMainDiscountListOriginal = mainProductData.discount_list.map(
|
|
1687
|
-
|
|
1688
|
-
|
|
1855
|
+
let newOriginTotalOriginal = Number(mainProductData.original_price || mainProductData.price || 0);
|
|
1856
|
+
|
|
1857
|
+
// 🔥 更新主商品自己的 discount_list 中的 num(quantity=原quantity-1)
|
|
1858
|
+
const updatedMainDiscountListOriginal = mainProductData.discount_list.map(discount => {
|
|
1859
|
+
if (discount?.metadata?.custom_product_bundle_map_id) {
|
|
1860
|
+
// bundle的discount_list保持不变
|
|
1689
1861
|
return discount;
|
|
1690
1862
|
}
|
|
1863
|
+
// 主商品自己的discount,更新num为 mainProductQuantity - 1
|
|
1691
1864
|
return {
|
|
1692
1865
|
...discount,
|
|
1693
1866
|
metadata: {
|
|
1694
1867
|
...discount.metadata,
|
|
1695
1868
|
num: mainProductQuantity - 1,
|
|
1696
|
-
custom_product_bundle_map_id:
|
|
1869
|
+
custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id
|
|
1697
1870
|
}
|
|
1698
1871
|
// num: mainProductQuantity - 1,
|
|
1699
1872
|
};
|
|
1700
1873
|
});
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
return !((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id);
|
|
1705
|
-
}
|
|
1706
|
-
);
|
|
1874
|
+
|
|
1875
|
+
// 🔥 使用更新后的列表计算折扣金额
|
|
1876
|
+
const mainDiscountListOriginal = updatedMainDiscountListOriginal.filter(item => !item?.metadata?.custom_product_bundle_map_id);
|
|
1707
1877
|
if (mainDiscountListOriginal && mainDiscountListOriginal.length > 0) {
|
|
1708
|
-
const allDiscountAmount = (0,
|
|
1709
|
-
|
|
1710
|
-
);
|
|
1711
|
-
newTotalOriginal = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalOriginal;
|
|
1878
|
+
const allDiscountAmount = (0, _utils.getDiscountListAmount)(mainDiscountListOriginal);
|
|
1879
|
+
newTotalOriginal = new _decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalOriginal;
|
|
1712
1880
|
newOriginTotalOriginal = mainProductData.origin_total ?? newOriginTotalOriginal;
|
|
1713
1881
|
}
|
|
1882
|
+
|
|
1883
|
+
// 累加bundle的价格(只累加一次)
|
|
1714
1884
|
if (newBundleOriginal.length > 0) {
|
|
1715
|
-
newBundleOriginal.forEach(
|
|
1885
|
+
newBundleOriginal.forEach(item => {
|
|
1716
1886
|
newTotalOriginal += Number(item.price) * Number(item.num);
|
|
1717
1887
|
newOriginTotalOriginal += Number(item.price) * Number(item.num);
|
|
1718
1888
|
});
|
|
1719
1889
|
}
|
|
1720
|
-
|
|
1890
|
+
|
|
1891
|
+
// 累加options的价格(options不参与折扣,在最终设置total时处理)
|
|
1892
|
+
if (product?.options) {
|
|
1721
1893
|
newTotalOriginal = product.options.reduce((accumulator, currentValue) => {
|
|
1722
|
-
const currentPrice = new
|
|
1723
|
-
const currentNum = new
|
|
1894
|
+
const currentPrice = new _decimal.default(currentValue.price || 0);
|
|
1895
|
+
const currentNum = new _decimal.default(currentValue.num || 0);
|
|
1724
1896
|
return accumulator.add(currentPrice.mul(currentNum));
|
|
1725
|
-
}, new
|
|
1897
|
+
}, new _decimal.default(newTotalOriginal)).toNumber();
|
|
1726
1898
|
}
|
|
1727
|
-
newTotalOriginal = new
|
|
1728
|
-
newOriginTotalOriginal = new
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
);
|
|
1899
|
+
newTotalOriginal = new _decimal.default(newTotalOriginal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
1900
|
+
newOriginTotalOriginal = new _decimal.default(newOriginTotalOriginal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
1901
|
+
|
|
1902
|
+
// 添加第二个主商品:qty=原quantity-1,包含原始bundle
|
|
1903
|
+
result.push(this.hooks.setProduct(mainProduct, {
|
|
1904
|
+
...mainProductData,
|
|
1905
|
+
_id: `${mainProductData._id.split('___')[0]}___split_normal`,
|
|
1906
|
+
quantity: mainProductQuantity - 1,
|
|
1907
|
+
discount_list: updatedMainDiscountListOriginal,
|
|
1908
|
+
bundle: newBundleOriginal,
|
|
1909
|
+
total: newTotalOriginal,
|
|
1910
|
+
origin_total: newOriginTotalOriginal
|
|
1911
|
+
}));
|
|
1740
1912
|
}
|
|
1741
1913
|
} else {
|
|
1742
|
-
|
|
1743
|
-
|
|
1914
|
+
// 🔥 没有子商品被拆分,使用原有逻辑
|
|
1915
|
+
mainProductArr.forEach(mainProduct => {
|
|
1744
1916
|
const mainProductData = this.hooks.getProduct(mainProduct);
|
|
1917
|
+
|
|
1918
|
+
// 重组bundle
|
|
1745
1919
|
const newBundle = [];
|
|
1746
1920
|
if (product.bundle && Array.isArray(product.bundle)) {
|
|
1747
1921
|
product.bundle.forEach((bundleItem, bundleIndex) => {
|
|
1748
1922
|
const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
|
|
1749
|
-
const processedBundleItems =
|
|
1923
|
+
const processedBundleItems = processedFlatItemsMap.get(bundleItemId);
|
|
1750
1924
|
if (!processedBundleItems || processedBundleItems.length === 0) {
|
|
1925
|
+
// 未处理的bundle item,保持原样
|
|
1751
1926
|
newBundle.push(bundleItem);
|
|
1752
1927
|
} else {
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
});
|
|
1928
|
+
// 🔥 关键:拆分后的bundle item
|
|
1929
|
+
processedBundleItems.forEach(item => {
|
|
1930
|
+
// 🔥 更新 discount_list 中的 num,使其与拆分后的 item.num 一致
|
|
1931
|
+
const updatedDiscountList = (item.discount_list || []).map(discount => ({
|
|
1932
|
+
...discount,
|
|
1933
|
+
metadata: {
|
|
1934
|
+
...discount.metadata,
|
|
1935
|
+
num: item.num,
|
|
1936
|
+
custom_product_bundle_map_id: discount?.metadata?.custom_product_bundle_map_id
|
|
1937
|
+
}
|
|
1938
|
+
// num: item.num, // 使用拆分后的 num
|
|
1939
|
+
}));
|
|
1766
1940
|
newBundle.push({
|
|
1767
1941
|
...bundleItem,
|
|
1768
1942
|
_id: item._id,
|
|
1769
1943
|
product_id: bundleItem.product_id,
|
|
1770
1944
|
price: item.price,
|
|
1771
1945
|
num: item.num,
|
|
1772
|
-
discount_list:
|
|
1773
|
-
bundle_selling_price: bundleItem.bundle_selling_price !==
|
|
1946
|
+
discount_list: updatedDiscountList,
|
|
1947
|
+
bundle_selling_price: bundleItem.bundle_selling_price !== undefined ? item.price : undefined
|
|
1774
1948
|
});
|
|
1775
1949
|
});
|
|
1776
1950
|
}
|
|
1777
1951
|
});
|
|
1778
1952
|
}
|
|
1953
|
+
|
|
1954
|
+
// 🔥 重新计算主商品的总价(包含bundle)
|
|
1779
1955
|
let newTotal = Number(mainProductData.price || 0);
|
|
1780
1956
|
let newOriginTotal = Number(mainProductData.original_price || mainProductData.price || 0);
|
|
1781
|
-
|
|
1957
|
+
|
|
1958
|
+
// 判断是否是手动折扣
|
|
1959
|
+
const isManualDiscount = typeof mainProductData.isManualDiscount === 'boolean' ? mainProductData.isManualDiscount : mainProductData.total != mainProductData.origin_total && (!mainProductData.discount_list?.length || mainProductData?.discount_list?.every?.(item => item.type === 'product'));
|
|
1960
|
+
|
|
1961
|
+
// 如果是手动折扣,使用原有的total和origin_total,不重新计算
|
|
1782
1962
|
if (isManualDiscount) {
|
|
1783
1963
|
newTotal = mainProductData.total ?? newTotal;
|
|
1784
1964
|
newOriginTotal = mainProductData.origin_total ?? newOriginTotal;
|
|
1785
1965
|
} else {
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1791
|
-
);
|
|
1966
|
+
// 不是手动折扣时,才重新计算
|
|
1967
|
+
const mainDiscountList = mainProductData.discount_list.filter(item => !item?.metadata?.custom_product_bundle_map_id);
|
|
1968
|
+
|
|
1969
|
+
// 如果主商品本身有折扣,需要重新计算主商品价格
|
|
1792
1970
|
if (mainDiscountList && mainDiscountList.length > 0) {
|
|
1793
|
-
const allDiscountAmount = (0,
|
|
1794
|
-
newTotal = new
|
|
1971
|
+
const allDiscountAmount = (0, _utils.getDiscountListAmount)(mainDiscountList);
|
|
1972
|
+
newTotal = new _decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotal;
|
|
1795
1973
|
newOriginTotal = mainProductData.origin_total ?? newOriginTotal;
|
|
1796
1974
|
}
|
|
1975
|
+
|
|
1976
|
+
// 累加bundle的价格(只累加一次)
|
|
1797
1977
|
if (newBundle.length > 0) {
|
|
1798
|
-
newBundle.forEach(
|
|
1799
|
-
var _a2, _b2, _c2;
|
|
1978
|
+
newBundle.forEach(item => {
|
|
1800
1979
|
newTotal += Number(item.price) * Number(item.num);
|
|
1801
|
-
const originalPrice =
|
|
1980
|
+
const originalPrice = item.discount_list?.[0]?.discount?.original_amount || item.price;
|
|
1802
1981
|
newOriginTotal += Number(originalPrice) * Number(item.num);
|
|
1803
1982
|
});
|
|
1804
1983
|
}
|
|
1805
1984
|
}
|
|
1806
|
-
|
|
1985
|
+
|
|
1986
|
+
// 累加options的价格(options不参与折扣,在最终设置total时处理)
|
|
1987
|
+
if (product?.options) {
|
|
1807
1988
|
newTotal = product.options.reduce((accumulator, currentValue) => {
|
|
1808
|
-
const currentPrice = new
|
|
1809
|
-
const currentNum = new
|
|
1989
|
+
const currentPrice = new _decimal.default(currentValue.price || 0);
|
|
1990
|
+
const currentNum = new _decimal.default(currentValue.num || 0);
|
|
1810
1991
|
return accumulator.add(currentPrice.mul(currentNum));
|
|
1811
|
-
}, new
|
|
1992
|
+
}, new _decimal.default(newTotal)).toNumber();
|
|
1812
1993
|
}
|
|
1813
|
-
newTotal = new
|
|
1814
|
-
newOriginTotal = new
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
);
|
|
1994
|
+
newTotal = new _decimal.default(newTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
1995
|
+
newOriginTotal = new _decimal.default(newOriginTotal).toDecimalPlaces(2, _decimal.default.ROUND_HALF_UP).toNumber();
|
|
1996
|
+
|
|
1997
|
+
// 生成最终的主商品
|
|
1998
|
+
result.push(this.hooks.setProduct(mainProduct, {
|
|
1999
|
+
...mainProductData,
|
|
2000
|
+
bundle: newBundle,
|
|
2001
|
+
total: newTotal,
|
|
2002
|
+
origin_total: newOriginTotal
|
|
2003
|
+
}));
|
|
1823
2004
|
});
|
|
1824
2005
|
}
|
|
1825
2006
|
}
|
|
1826
2007
|
});
|
|
1827
2008
|
return result;
|
|
1828
2009
|
};
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
const updatedDiscountList = addModeDiscount.map(
|
|
2010
|
+
|
|
2011
|
+
// 按原始顺序构建处理后的商品列表
|
|
2012
|
+
const processedProductList = reconstructProductsWithBundle(processedProductsMap, processedFlatItemsMap, productList);
|
|
2013
|
+
|
|
2014
|
+
// 按原始顺序更新优惠券列表,标记已使用和可用的优惠券
|
|
2015
|
+
const updatedDiscountList = addModeDiscount.map(discount => {
|
|
2016
|
+
// 获取此优惠券适用的商品列表
|
|
1835
2017
|
const applicableProducts = discountApplicability.get(discount.id) || [];
|
|
2018
|
+
|
|
2019
|
+
// 获取此优惠券适用的商品详情
|
|
1836
2020
|
const applicableProductDetails = discountApplicableProducts.get(discount.id) || [];
|
|
2021
|
+
|
|
2022
|
+
// 获取此优惠券实际应用的商品详情
|
|
1837
2023
|
const appliedProductDetails = appliedDiscountProducts.get(discount.id) || [];
|
|
2024
|
+
|
|
2025
|
+
// 根据是否有适用商品决定isAvailable
|
|
1838
2026
|
const isAvailable = applicableProducts.length > 0;
|
|
1839
|
-
|
|
2027
|
+
|
|
2028
|
+
// 如果此优惠券被明确设置为不选中,保持其状态,但正确设置isAvailable
|
|
2029
|
+
if (typeof discount.isSelected === 'boolean' && discount.isSelected === false && discount.isManualSelect) {
|
|
1840
2030
|
return {
|
|
1841
2031
|
...discount,
|
|
1842
2032
|
isSelected: false,
|
|
1843
|
-
isAvailable,
|
|
2033
|
+
isAvailable: isAvailable,
|
|
1844
2034
|
// 正确设置可用性
|
|
1845
2035
|
applicableProductIds: applicableProducts,
|
|
1846
2036
|
// 添加可抵扣的商品详情
|
|
1847
|
-
applicableProductDetails,
|
|
2037
|
+
applicableProductDetails: applicableProductDetails,
|
|
1848
2038
|
// 添加实际抵扣的商品详情(对于未选中的优惠券,为空数组)
|
|
1849
2039
|
appliedProductDetails: []
|
|
1850
2040
|
};
|
|
@@ -1853,18 +2043,20 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1853
2043
|
return {
|
|
1854
2044
|
...discount,
|
|
1855
2045
|
isSelected: true,
|
|
1856
|
-
isManualSelect:
|
|
2046
|
+
isManualSelect: options?.scan ? false : discount.isManualSelect,
|
|
1857
2047
|
// 标记为可用,因为它已被应用
|
|
1858
2048
|
isAvailable: true,
|
|
1859
2049
|
// 记录适用的商品IDs
|
|
1860
2050
|
applicableProductIds: applicableProducts,
|
|
1861
2051
|
// 添加可抵扣的商品详情
|
|
1862
|
-
applicableProductDetails,
|
|
2052
|
+
applicableProductDetails: applicableProductDetails,
|
|
1863
2053
|
// 添加实际抵扣的商品详情
|
|
1864
|
-
appliedProductDetails
|
|
2054
|
+
appliedProductDetails: appliedProductDetails
|
|
1865
2055
|
};
|
|
1866
2056
|
}
|
|
1867
|
-
let isSelected = typeof discount.isSelected ===
|
|
2057
|
+
let isSelected = typeof discount.isSelected === 'boolean' ? discount.isSelected : undefined;
|
|
2058
|
+
|
|
2059
|
+
// 如果是可用的 并且没有手动标记 则设置为选中
|
|
1868
2060
|
if (isAvailable && appliedProductDetails.length && !discount.isManualSelect) {
|
|
1869
2061
|
isSelected = true;
|
|
1870
2062
|
} else if (!appliedProductDetails.length) {
|
|
@@ -1873,24 +2065,24 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1873
2065
|
return {
|
|
1874
2066
|
...discount,
|
|
1875
2067
|
// 如果有适用的商品,标记为可用
|
|
1876
|
-
isAvailable,
|
|
2068
|
+
isAvailable: isAvailable,
|
|
1877
2069
|
isSelected,
|
|
1878
2070
|
// 如果是扫码进来的,要手动设置为手动选择:false
|
|
1879
|
-
isManualSelect:
|
|
2071
|
+
isManualSelect: options?.scan ? false : discount.isManualSelect,
|
|
1880
2072
|
// 记录适用的商品IDs
|
|
1881
2073
|
applicableProductIds: applicableProducts,
|
|
1882
2074
|
// 添加可抵扣的商品详情
|
|
1883
|
-
applicableProductDetails,
|
|
2075
|
+
applicableProductDetails: applicableProductDetails,
|
|
1884
2076
|
// 添加实际抵扣的商品详情(对于未使用的优惠券,为空数组)
|
|
1885
2077
|
appliedProductDetails: []
|
|
1886
2078
|
};
|
|
1887
2079
|
});
|
|
1888
|
-
console.log(processedProductList, "processedProductList");
|
|
1889
2080
|
return {
|
|
1890
2081
|
productList: processedProductList,
|
|
1891
2082
|
discountList: [...editModeDiscount, ...updatedDiscountList]
|
|
1892
2083
|
};
|
|
1893
2084
|
}
|
|
2085
|
+
|
|
1894
2086
|
/**
|
|
1895
2087
|
* 检查优惠是否符合 PackageSubItemUsageRules 配置
|
|
1896
2088
|
* @param discount 优惠券
|
|
@@ -1898,92 +2090,200 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1898
2090
|
* @returns 是否可用
|
|
1899
2091
|
*/
|
|
1900
2092
|
checkPackageSubItemUsageRules(discount, flatItem) {
|
|
1901
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1902
2093
|
const limitedData = discount.limited_relation_product_data;
|
|
1903
|
-
const usageRules = limitedData
|
|
1904
|
-
const rules = [
|
|
2094
|
+
const usageRules = limitedData?.package_sub_item_usage_rules;
|
|
2095
|
+
const rules = ['original_price', ...(usageRules?.rules || [])];
|
|
2096
|
+
|
|
2097
|
+
// 如果没有配置 package_sub_item_usage_rules,则默认可用
|
|
1905
2098
|
if (!usageRules) {
|
|
1906
2099
|
return true;
|
|
1907
2100
|
}
|
|
1908
2101
|
const ruleType = usageRules.type;
|
|
1909
|
-
|
|
1910
|
-
const
|
|
1911
|
-
const
|
|
1912
|
-
|
|
2102
|
+
// 套餐适用范围配置
|
|
2103
|
+
const packageScope = usageRules?.package_scope;
|
|
2104
|
+
const {
|
|
2105
|
+
type: scopeType,
|
|
2106
|
+
exclude_bundle_product_ids = [],
|
|
2107
|
+
include_bundle_product_ids = [],
|
|
2108
|
+
filter = 0
|
|
2109
|
+
} = packageScope || {};
|
|
2110
|
+
const isMainProduct = flatItem.type === 'main'; // 单独购买
|
|
2111
|
+
const isBundleItem = flatItem.type === 'bundle'; // 套餐中购买
|
|
2112
|
+
|
|
2113
|
+
// 主商品直接可用
|
|
1913
2114
|
if (isMainProduct) {
|
|
1914
2115
|
return true;
|
|
1915
2116
|
}
|
|
1916
|
-
|
|
2117
|
+
|
|
2118
|
+
// universal_discount: 单独购买和套餐中(子商品为原价)均可使用
|
|
2119
|
+
if (ruleType === 'universal_discount') {
|
|
1917
2120
|
if (isMainProduct) {
|
|
1918
|
-
return true;
|
|
2121
|
+
return true; // 单独购买时可用
|
|
1919
2122
|
}
|
|
1920
2123
|
if (isBundleItem) {
|
|
1921
|
-
|
|
1922
|
-
const
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
const
|
|
2124
|
+
// 套餐中购买时,判断是否为原价
|
|
2125
|
+
const priceType = flatItem.bundleItem?.price_type;
|
|
2126
|
+
const priceTypeExt = flatItem.bundleItem?.price_type_ext;
|
|
2127
|
+
// 主商品id
|
|
2128
|
+
const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
|
|
2129
|
+
// original_price 对应:
|
|
2130
|
+
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
2131
|
+
// markup_price 对应:
|
|
2132
|
+
// price_type: "markup" && price_type_ext: ""
|
|
2133
|
+
/** 原价 */
|
|
2134
|
+
const isOriginalPrice = priceType === 'markup' && priceTypeExt === 'product_price';
|
|
2135
|
+
/** 加价 */
|
|
2136
|
+
const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
|
|
2137
|
+
|
|
2138
|
+
// 检查 rules
|
|
1926
2139
|
if (rules.length > 0) {
|
|
1927
|
-
const _isOriginalPrice = isOriginalPrice && rules.includes(
|
|
1928
|
-
const _isMarkupPrice = isMarkupPrice && rules.includes(
|
|
2140
|
+
const _isOriginalPrice = isOriginalPrice && rules.includes('original_price');
|
|
2141
|
+
const _isMarkupPrice = isMarkupPrice && rules.includes('markup_price');
|
|
2142
|
+
// 价格是否符合规则:原价或加价
|
|
1929
2143
|
const isPriceValid = _isOriginalPrice || _isMarkupPrice;
|
|
2144
|
+
// 套餐适用范围校验
|
|
1930
2145
|
let isScopeValid = false;
|
|
1931
|
-
|
|
2146
|
+
|
|
2147
|
+
// 排除套餐判断, product_all值兼容旧数据
|
|
2148
|
+
if (scopeType === 'all_packages' || scopeType === 'product_all') {
|
|
2149
|
+
// 所有套餐可用
|
|
1932
2150
|
if (!filter) {
|
|
1933
2151
|
isScopeValid = true;
|
|
1934
2152
|
} else {
|
|
1935
2153
|
isScopeValid = !exclude_bundle_product_ids.includes(Number(mainProductId));
|
|
1936
2154
|
}
|
|
1937
2155
|
}
|
|
1938
|
-
|
|
2156
|
+
|
|
2157
|
+
// 包含套餐判断, products值兼容旧数据
|
|
2158
|
+
if (scopeType === 'specific_packages' || scopeType === 'products') {
|
|
1939
2159
|
isScopeValid = include_bundle_product_ids.includes(Number(mainProductId));
|
|
1940
2160
|
}
|
|
2161
|
+
|
|
2162
|
+
// 价格和套餐适用范围都符合,则可用
|
|
1941
2163
|
if (isPriceValid && isScopeValid) {
|
|
1942
2164
|
return true;
|
|
1943
2165
|
}
|
|
2166
|
+
|
|
2167
|
+
// 检查原价
|
|
2168
|
+
// if (isOriginalPrice && rules.includes('original_price')) {
|
|
2169
|
+
// return true;
|
|
2170
|
+
// }
|
|
2171
|
+
|
|
2172
|
+
// 检查加价
|
|
2173
|
+
// if (isMarkupPrice && rules.includes('markup_price')) {
|
|
2174
|
+
// return true;
|
|
2175
|
+
// }
|
|
2176
|
+
|
|
2177
|
+
// 如果都不匹配,则不可用
|
|
1944
2178
|
return false;
|
|
1945
2179
|
}
|
|
2180
|
+
|
|
2181
|
+
// 原价包括:price_type: "markup" && price_type_ext: "product_price"
|
|
1946
2182
|
return isOriginalPrice;
|
|
1947
2183
|
}
|
|
1948
2184
|
return true;
|
|
1949
2185
|
}
|
|
1950
|
-
|
|
2186
|
+
|
|
2187
|
+
// package_exclusive: 仅在套餐中(子商品为原价)时可使用
|
|
2188
|
+
if (ruleType === 'package_exclusive') {
|
|
1951
2189
|
if (isMainProduct) {
|
|
1952
|
-
return false;
|
|
2190
|
+
return false; // 单独购买时不可用
|
|
1953
2191
|
}
|
|
1954
2192
|
if (isBundleItem) {
|
|
1955
|
-
|
|
1956
|
-
const
|
|
1957
|
-
const
|
|
1958
|
-
|
|
2193
|
+
// 套餐中购买时,判断是否为原价
|
|
2194
|
+
const priceType = flatItem.bundleItem?.price_type;
|
|
2195
|
+
const priceTypeExt = flatItem.bundleItem?.price_type_ext;
|
|
2196
|
+
|
|
2197
|
+
// original_price 对应:
|
|
2198
|
+
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
2199
|
+
// markup_price 对应:
|
|
2200
|
+
// price_type: "markup" && price_type_ext: ""
|
|
2201
|
+
/** 原价 */
|
|
2202
|
+
const isOriginalPrice = priceType === 'markup' && priceTypeExt === 'product_price';
|
|
2203
|
+
/** 加价 */
|
|
2204
|
+
const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
|
|
2205
|
+
|
|
2206
|
+
// 检查 rules
|
|
1959
2207
|
if (rules.length > 0) {
|
|
1960
|
-
|
|
2208
|
+
// 检查原价
|
|
2209
|
+
if (isOriginalPrice && rules.includes('original_price')) {
|
|
1961
2210
|
return true;
|
|
1962
2211
|
}
|
|
1963
|
-
|
|
2212
|
+
|
|
2213
|
+
// 检查加价
|
|
2214
|
+
if (isMarkupPrice && rules.includes('markup_price')) {
|
|
1964
2215
|
return true;
|
|
1965
2216
|
}
|
|
2217
|
+
|
|
2218
|
+
// 如果都不匹配,则不可用
|
|
1966
2219
|
return false;
|
|
1967
2220
|
}
|
|
2221
|
+
|
|
2222
|
+
// 原价包括:price_type: "markup" && price_type_ext: "product_price"
|
|
1968
2223
|
return isOriginalPrice;
|
|
1969
2224
|
}
|
|
1970
2225
|
return false;
|
|
1971
2226
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
2227
|
+
|
|
2228
|
+
// single_item_promo: 仅在单独购买时可使用
|
|
2229
|
+
if (ruleType === 'single_item_promo') {
|
|
2230
|
+
return isMainProduct; // 只有单独购买时可用
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
/*
|
|
2234
|
+
// custom_usage_rules: 根据自定义规则判断
|
|
2235
|
+
if (ruleType === 'custom_usage_rules') {
|
|
2236
|
+
const customRules = usageRules.custom_usage_rules;
|
|
2237
|
+
if (!customRules) {
|
|
2238
|
+
return true; // 如果没有自定义规则,默认可用
|
|
2239
|
+
}
|
|
2240
|
+
const { types, package_sub_item_rules } = customRules;
|
|
2241
|
+
// 判断商品类型是否在允许的类型中
|
|
2242
|
+
if (isMainProduct) {
|
|
2243
|
+
// 主商品对应 standalone_product
|
|
2244
|
+
if (!types.includes('standalone_product')) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
return true; // 主商品不需要判断 package_sub_item_rules
|
|
2248
|
+
}
|
|
2249
|
+
if (isBundleItem) {
|
|
2250
|
+
// bundle子商品对应 package_sub_item
|
|
2251
|
+
if (!types.includes('package_sub_item')) {
|
|
2252
|
+
return false;
|
|
2253
|
+
}
|
|
2254
|
+
// 如果包含 package_sub_item,还需要判断 price_type
|
|
2255
|
+
const priceType = flatItem.bundleItem?.price_type;
|
|
2256
|
+
const priceTypeExt = flatItem.bundleItem?.price_type_ext;
|
|
2257
|
+
// 检查 package_sub_item_rules
|
|
2258
|
+
if (package_sub_item_rules && package_sub_item_rules.length > 0) {
|
|
2259
|
+
// original_price 对应:
|
|
2260
|
+
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
2261
|
+
// markup_price 对应:
|
|
2262
|
+
// price_type: "markup" && price_type_ext: ""
|
|
2263
|
+
const isOriginalPrice = (priceType === 'markup' && priceTypeExt === 'product_price');
|
|
2264
|
+
const isMarkupPrice = priceType === 'markup' && (priceTypeExt === '' || !priceTypeExt);
|
|
2265
|
+
if (isOriginalPrice && package_sub_item_rules.includes('original_price')) {
|
|
2266
|
+
return true;
|
|
2267
|
+
}
|
|
2268
|
+
if (isMarkupPrice && package_sub_item_rules.includes('markup_price')) {
|
|
2269
|
+
return true;
|
|
2270
|
+
}
|
|
2271
|
+
// 如果都不匹配,则不可用
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2274
|
+
return true; // 如果没有 package_sub_item_rules 配置,默认可用
|
|
2275
|
+
}
|
|
2276
|
+
return true;
|
|
1974
2277
|
}
|
|
2278
|
+
* */
|
|
2279
|
+
|
|
2280
|
+
// 默认可用
|
|
1975
2281
|
return true;
|
|
1976
2282
|
}
|
|
1977
2283
|
async destroy() {
|
|
1978
2284
|
this.core.effects.offByModuleDestroy(this.name);
|
|
1979
2285
|
await this.core.effects.emit(`${this.name}:onDestroy`, {});
|
|
1980
|
-
console.log("[Rules] 已销毁");
|
|
1981
2286
|
}
|
|
1982
|
-
async clear() {
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
};
|
|
1986
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1987
|
-
0 && (module.exports = {
|
|
1988
|
-
RulesModule
|
|
1989
|
-
});
|
|
2287
|
+
async clear() {}
|
|
2288
|
+
}
|
|
2289
|
+
exports.RulesModule = RulesModule;
|