@pisell/pisellos 0.0.571 → 0.0.572
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/effects/index.d.ts +2 -2
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +3 -3
- package/dist/model/strategy/adapter/itemRule/type.d.ts +6 -6
- package/dist/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/dist/model/strategy/adapter/promotion/type.d.ts +5 -5
- package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -2
- package/dist/model/strategy/type.d.ts +1 -1
- package/dist/modules/BookingContext/types.d.ts +4 -4
- package/dist/modules/BookingContext/utils/resourceErrors.d.ts +1 -1
- package/dist/modules/Customer/types.d.ts +1 -1
- package/dist/modules/Discount/availability.d.ts +7 -0
- package/dist/modules/Discount/availability.js +52 -0
- package/dist/modules/Discount/entitlementPass.d.ts +34 -0
- package/dist/modules/Discount/entitlementPass.js +147 -0
- package/dist/modules/Discount/entitlementState.d.ts +8 -0
- package/dist/modules/Discount/entitlementState.js +205 -0
- package/dist/modules/Discount/index.d.ts +5 -2
- package/dist/modules/Discount/index.js +124 -25
- package/dist/modules/Discount/types.d.ts +29 -6
- package/dist/modules/Holder/types.d.ts +1 -1
- package/dist/modules/OpenData/types.d.ts +1 -1
- package/dist/modules/Order/types.d.ts +5 -5
- package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +1 -1
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +1 -1
- package/dist/modules/Order/utils.d.ts +1 -1
- package/dist/modules/Payment/types.d.ts +7 -7
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/modules/ResourcePlanner/types.d.ts +4 -4
- package/dist/modules/Rules/entitlementLines.d.ts +8 -0
- package/dist/modules/Rules/entitlementLines.js +159 -0
- package/dist/modules/Rules/index.d.ts +13 -3
- package/dist/modules/Rules/index.js +617 -342
- package/dist/modules/Rules/types.d.ts +4 -4
- package/dist/modules/ScanOrderLogger/types.d.ts +2 -2
- package/dist/modules/Schedule/getDateIsInSchedule.d.ts +1 -1
- package/dist/modules/Schedule/type.d.ts +7 -7
- package/dist/modules/Schedule/types.d.ts +9 -9
- package/dist/plugins/app.d.ts +1 -1
- package/dist/plugins/request.d.ts +2 -2
- package/dist/plugins/window.d.ts +2 -2
- package/dist/server/modules/floor-plan/types.d.ts +1 -1
- package/dist/server/modules/menu/types.d.ts +1 -1
- package/dist/server/modules/order/types.d.ts +16 -16
- package/dist/server/modules/products/types.d.ts +1 -1
- package/dist/server/modules/resource/types.d.ts +1 -1
- package/dist/server/modules/schedule/utils.d.ts +1 -1
- package/dist/server/types.d.ts +4 -4
- package/dist/server/utils/small-ticket.d.ts +1 -1
- package/dist/solution/BaseSales/index.d.ts +1 -1
- package/dist/solution/BaseSales/types.d.ts +7 -7
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/utils/resources.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +13 -1
- package/dist/solution/BookingTicket/types.d.ts +3 -3
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +1 -1
- package/dist/solution/Sales/types.d.ts +4 -4
- package/dist/solution/ScanOrder/types.d.ts +5 -5
- package/dist/solution/ShopDiscount/index.d.ts +3 -0
- package/dist/solution/ShopDiscount/index.js +161 -78
- package/dist/solution/ShopDiscount/types.d.ts +1 -1
- package/dist/solution/ShopDiscount/utils.d.ts +3 -2
- package/dist/solution/ShopDiscount/utils.js +40 -1
- package/dist/solution/UnifiedBookingSales/types.d.ts +1 -1
- package/dist/solution/VenueBooking/types.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/task.d.ts +2 -2
- package/dist/utils/watch.d.ts +2 -2
- package/lib/effects/index.d.ts +2 -2
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +3 -3
- package/lib/model/strategy/adapter/itemRule/type.d.ts +6 -6
- package/lib/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/lib/model/strategy/adapter/promotion/type.d.ts +5 -5
- package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -0
- package/lib/model/strategy/type.d.ts +1 -1
- package/lib/modules/BookingContext/types.d.ts +4 -4
- package/lib/modules/BookingContext/utils/resourceErrors.d.ts +1 -1
- package/lib/modules/Customer/types.d.ts +1 -1
- package/lib/modules/Discount/availability.d.ts +7 -0
- package/lib/modules/Discount/availability.js +46 -0
- package/lib/modules/Discount/entitlementPass.d.ts +34 -0
- package/lib/modules/Discount/entitlementPass.js +141 -0
- package/lib/modules/Discount/entitlementState.d.ts +8 -0
- package/lib/modules/Discount/entitlementState.js +150 -0
- package/lib/modules/Discount/index.d.ts +5 -2
- package/lib/modules/Discount/index.js +59 -14
- package/lib/modules/Discount/types.d.ts +29 -6
- package/lib/modules/Holder/types.d.ts +1 -1
- package/lib/modules/OpenData/types.d.ts +1 -1
- package/lib/modules/Order/types.d.ts +5 -5
- package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +1 -1
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +1 -1
- package/lib/modules/Order/utils.d.ts +1 -1
- package/lib/modules/Payment/types.d.ts +7 -7
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/modules/ResourcePlanner/types.d.ts +4 -4
- package/lib/modules/Rules/entitlementLines.d.ts +8 -0
- package/lib/modules/Rules/entitlementLines.js +128 -0
- package/lib/modules/Rules/index.d.ts +13 -3
- package/lib/modules/Rules/index.js +284 -61
- package/lib/modules/Rules/types.d.ts +4 -4
- package/lib/modules/ScanOrderLogger/types.d.ts +2 -2
- package/lib/modules/Schedule/getDateIsInSchedule.d.ts +1 -1
- package/lib/modules/Schedule/type.d.ts +7 -7
- package/lib/modules/Schedule/types.d.ts +9 -9
- package/lib/plugins/app.d.ts +1 -1
- package/lib/plugins/request.d.ts +2 -2
- package/lib/plugins/window.d.ts +2 -2
- package/lib/server/modules/floor-plan/types.d.ts +1 -1
- package/lib/server/modules/menu/types.d.ts +1 -1
- package/lib/server/modules/order/types.d.ts +16 -16
- package/lib/server/modules/products/types.d.ts +1 -1
- package/lib/server/modules/resource/types.d.ts +1 -1
- package/lib/server/modules/schedule/utils.d.ts +1 -1
- package/lib/server/types.d.ts +4 -4
- package/lib/server/utils/small-ticket.d.ts +1 -1
- package/lib/solution/BaseSales/index.d.ts +1 -1
- package/lib/solution/BaseSales/types.d.ts +7 -7
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -1
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/utils/resources.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +13 -1
- package/lib/solution/BookingTicket/types.d.ts +3 -3
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +1 -1
- package/lib/solution/Sales/types.d.ts +4 -4
- package/lib/solution/ScanOrder/types.d.ts +5 -5
- package/lib/solution/ShopDiscount/index.d.ts +3 -0
- package/lib/solution/ShopDiscount/index.js +55 -18
- package/lib/solution/ShopDiscount/types.d.ts +1 -1
- package/lib/solution/ShopDiscount/utils.d.ts +3 -2
- package/lib/solution/ShopDiscount/utils.js +39 -3
- package/lib/solution/UnifiedBookingSales/types.d.ts +1 -1
- package/lib/solution/VenueBooking/types.d.ts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/utils/task.d.ts +2 -2
- package/lib/utils/watch.d.ts +2 -2
- package/package.json +19 -18
|
@@ -8,6 +8,8 @@ var _utils = require("../../solution/ShopDiscount/utils");
|
|
|
8
8
|
var _BaseModule = require("../BaseModule");
|
|
9
9
|
var _types = require("./types");
|
|
10
10
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
11
|
+
var _entitlementPass = require("./entitlementPass");
|
|
12
|
+
var _availability = require("./availability");
|
|
11
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
14
|
class DiscountModule extends _BaseModule.BaseModule {
|
|
13
15
|
defaultName = 'discount';
|
|
@@ -82,10 +84,13 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
82
84
|
with_available_wallet_flag: params.with_available_wallet_flag ?? 1,
|
|
83
85
|
with_available_wallet_pass_flag: params.with_available_wallet_pass_flag ?? 1
|
|
84
86
|
});
|
|
85
|
-
const
|
|
87
|
+
const entitlementPassList = params.with_entitlement_pass ? prepareConfig?.data?.entitlement_pass_list || [] : [];
|
|
88
|
+
const ids = new Set(entitlementPassList.map(item => String(item.id)));
|
|
89
|
+
const rawDiscountList = [...entitlementPassList, ...(prepareConfig?.data?.good_pass_list || []).filter(item => !ids.has(String(item.id))), ...(prepareConfig?.data?.discount_card_list || []).filter(item => !ids.has(String(item.id)))].filter(item => params.with_entitlement_pass || !(0, _entitlementPass.isEntitlementPass)(item));
|
|
86
90
|
const availableWalletList = [...(prepareConfig?.data?.avaiable_wallet_list || []), ...(prepareConfig?.data?.available_wallet_list || [])];
|
|
87
91
|
const availableWalletPassList = prepareConfig?.data?.available_wallet_pass_list || [];
|
|
88
92
|
const availableWalletIds = this.normalizePositiveNumberIds([...availableWalletList.map(item => item?.wallet_id), ...availableWalletPassList.map(item => item?.product_id)]);
|
|
93
|
+
if (params.with_entitlement_pass) await this.setOriginalDiscountList(rawDiscountList);
|
|
89
94
|
const goodPassList = this.filterEnabledDiscountList(rawDiscountList) || [];
|
|
90
95
|
|
|
91
96
|
// this.setDiscountList(goodPassList);
|
|
@@ -102,16 +107,19 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
102
107
|
const walletPassProductIds = availableWalletPassList.map(item => Number(item?.product_id)).filter(id => Number.isFinite(id) && id > 0);
|
|
103
108
|
return Array.from(new Set([...walletIds, ...walletPassProductIds]));
|
|
104
109
|
}
|
|
105
|
-
async batchSearch(code,
|
|
110
|
+
async batchSearch(code, customerIdOrOptions) {
|
|
106
111
|
const {
|
|
107
112
|
customerId,
|
|
108
|
-
orderId
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
orderId,
|
|
114
|
+
withEntitlementPass
|
|
115
|
+
} = typeof customerIdOrOptions === 'number' ? {
|
|
116
|
+
customerId: customerIdOrOptions,
|
|
117
|
+
orderId: undefined,
|
|
118
|
+
withEntitlementPass: false
|
|
119
|
+
} : customerIdOrOptions || {};
|
|
120
|
+
const params = {
|
|
111
121
|
code,
|
|
112
122
|
translate_flag: 1,
|
|
113
|
-
tags: ['good_pass', 'product_discount_card'],
|
|
114
|
-
// available: 1,
|
|
115
123
|
relation_product: 1,
|
|
116
124
|
with: ['extensionData', 'customScheduleSnapshot', 'holder.detail'],
|
|
117
125
|
order_behavior_count: 1,
|
|
@@ -121,9 +129,42 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
121
129
|
order_behavior_count_order_id: orderId
|
|
122
130
|
} : {}),
|
|
123
131
|
request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
};
|
|
133
|
+
if (!withEntitlementPass) {
|
|
134
|
+
const result = await this.request.get(`/machinecode/batch-search`, {
|
|
135
|
+
...params,
|
|
136
|
+
tags: ['good_pass', 'product_discount_card']
|
|
137
|
+
});
|
|
138
|
+
return this.filterEnabledDiscountListWithReason((result?.data || []).filter(item => !(0, _entitlementPass.isEntitlementPass)(item)));
|
|
139
|
+
}
|
|
140
|
+
// 保留 develop 的旧券查询参数,多次卡单独查询并携带跨店状态。
|
|
141
|
+
const search = query => this.request.get(`/machinecode/batch-search`, query).then(value => ({
|
|
142
|
+
status: 'fulfilled',
|
|
143
|
+
value
|
|
144
|
+
}), reason => ({
|
|
145
|
+
status: 'rejected',
|
|
146
|
+
reason
|
|
147
|
+
}));
|
|
148
|
+
const [legacy, entitlement] = await Promise.all([search({
|
|
149
|
+
...params,
|
|
150
|
+
tags: ['good_pass', 'product_discount_card']
|
|
151
|
+
}), search({
|
|
152
|
+
...params,
|
|
153
|
+
tags: ['entitlement_pass'],
|
|
154
|
+
with_franchisor_data: 1,
|
|
155
|
+
unified_status_info_flag: 1,
|
|
156
|
+
with: [...params.with, 'franchiseeWalletPass:shop_id,source_shop_id,product_id,use']
|
|
157
|
+
})]);
|
|
158
|
+
const entitlementList = (entitlement.status === 'fulfilled' ? entitlement.value?.data || [] : []).filter(_entitlementPass.isEntitlementPass);
|
|
159
|
+
const legacyList = legacy.status === 'fulfilled' ? legacy.value?.data || [] : [];
|
|
160
|
+
const ids = new Set(entitlementList.map(item => String(item.id)));
|
|
161
|
+
const result = this.filterEnabledDiscountListWithReason([...entitlementList, ...legacyList.filter(item => !(0, _entitlementPass.isEntitlementPass)(item) && !ids.has(String(item.id)))]);
|
|
162
|
+
// 任一类型查到可用卡即可继续,另一类型的查询失败不阻断该卡。
|
|
163
|
+
if (!result.discountList.length) {
|
|
164
|
+
if (legacy.status === 'rejected') throw legacy.reason;
|
|
165
|
+
if (entitlement.status === 'rejected') throw entitlement.reason;
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
127
168
|
}
|
|
128
169
|
async batchSearchByProductIds(productIds) {
|
|
129
170
|
const result = await this.request.get(`/machinecode/batch-search`, {
|
|
@@ -135,7 +176,7 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
135
176
|
return result?.data || [];
|
|
136
177
|
}
|
|
137
178
|
filterEnabledDiscountList(discountList) {
|
|
138
|
-
return discountList.filter(discount => discount.limit_status === 'enable' && new _decimal.default(discount?.par_value || 0).minus(new _decimal.default(discount?.used_par_value || 0)).greaterThan(0) && this.checkUsageCreditsLimit(discount));
|
|
179
|
+
return discountList.filter(discount => (0, _entitlementPass.isEntitlementPass)(discount) ? !(0, _availability.getDiscountLifecycleReason)(discount) : discount.limit_status === 'enable' && new _decimal.default(discount?.par_value || 0).minus(new _decimal.default(discount?.used_par_value || 0)).greaterThan(0) && this.checkUsageCreditsLimit(discount));
|
|
139
180
|
}
|
|
140
181
|
|
|
141
182
|
// 检查使用次数限制
|
|
@@ -195,7 +236,8 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
195
236
|
|
|
196
237
|
// 过滤启用且可用的优惠券,并返回校验失败原因
|
|
197
238
|
filterEnabledDiscountListWithReason(discountList) {
|
|
198
|
-
|
|
239
|
+
const entitlementPasses = discountList.filter(item => (0, _entitlementPass.isEntitlementPass)(item) && !(0, _availability.getDiscountLifecycleReason)(item));
|
|
240
|
+
let lists = discountList.filter(item => !(0, _entitlementPass.isEntitlementPass)(item)).filter(discount => discount.limit_status === 'enable').filter(discount => {
|
|
199
241
|
const remaining = new _decimal.default(discount?.par_value || 0).minus(new _decimal.default(discount?.used_par_value || 0)).greaterThan(0);
|
|
200
242
|
return remaining;
|
|
201
243
|
}).map(discount => {
|
|
@@ -211,8 +253,11 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
211
253
|
// 不可用数据
|
|
212
254
|
const currentFailDiscount = lists.find(item => item.usageLimitFailKey);
|
|
213
255
|
return {
|
|
214
|
-
discountList:
|
|
215
|
-
|
|
256
|
+
discountList: [...entitlementPasses.map(item => ({
|
|
257
|
+
...item,
|
|
258
|
+
usageLimitFailKey: (0, _availability.getDiscountUsageLimitFailKey)(item)
|
|
259
|
+
})), ...availableLists],
|
|
260
|
+
unavailableReasonKey: currentFailDiscount?.usageLimitFailKey || discountList.filter(_entitlementPass.isEntitlementPass).map(_availability.getDiscountLifecycleReason).find(Boolean) || null
|
|
216
261
|
};
|
|
217
262
|
}
|
|
218
263
|
|
|
@@ -45,6 +45,8 @@ interface ApplicableProductDetails {
|
|
|
45
45
|
num: number;
|
|
46
46
|
metadata?: {
|
|
47
47
|
product_discount_difference?: number;
|
|
48
|
+
num?: number;
|
|
49
|
+
custom_product_bundle_map_id?: string;
|
|
48
50
|
};
|
|
49
51
|
discount?: {
|
|
50
52
|
fixed_amount?: number;
|
|
@@ -63,10 +65,17 @@ interface UsageCreditsValue {
|
|
|
63
65
|
max_per_week: number;
|
|
64
66
|
max_per_month: number;
|
|
65
67
|
}
|
|
66
|
-
export
|
|
68
|
+
export type IncludedUses = {
|
|
69
|
+
type: 'limited';
|
|
70
|
+
value: number;
|
|
71
|
+
} | {
|
|
72
|
+
type: 'unlimited';
|
|
73
|
+
value: null;
|
|
74
|
+
};
|
|
75
|
+
export type DiscountFilterRejectKey = 'total_credits' | 'per_user_limit' | 'max_per_day' | 'max_per_week' | 'max_per_month';
|
|
67
76
|
export interface DiscountWithReason {
|
|
68
77
|
discountList: Discount[];
|
|
69
|
-
unavailableReasonKey: DiscountFilterRejectKey | null;
|
|
78
|
+
unavailableReasonKey: DiscountFilterRejectKey | string | null;
|
|
70
79
|
}
|
|
71
80
|
export interface DiscountPrepareConfigResult {
|
|
72
81
|
discountList: Discount[];
|
|
@@ -97,20 +106,34 @@ export interface Discount {
|
|
|
97
106
|
used_par_value: string;
|
|
98
107
|
limit_status: string;
|
|
99
108
|
limited_relation_product_data: Limitedrelationproductdata;
|
|
100
|
-
balance
|
|
109
|
+
balance?: string | number | null;
|
|
101
110
|
format_title: Formattitle;
|
|
102
111
|
metadata?: {
|
|
103
112
|
num?: number;
|
|
104
113
|
discount_card_type?: 'fixed_amount' | 'percent';
|
|
105
114
|
custom_product_bundle_map_id?: string;
|
|
106
115
|
validity_type?: "custom_schedule_validity" | "fixed_validity";
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
included_uses?: IncludedUses;
|
|
117
|
+
discount_calculation_mode?: 'item_level' | 'order_level';
|
|
118
|
+
holder?: {
|
|
109
119
|
type: "customer" | "custom";
|
|
110
120
|
};
|
|
111
121
|
};
|
|
112
122
|
product: Product;
|
|
113
|
-
type:
|
|
123
|
+
type: 'product' | 'good_pass' | 'entitlement_pass' | 'discount_card' | 'product_discount_card';
|
|
124
|
+
shop_id?: number;
|
|
125
|
+
holder?: {
|
|
126
|
+
holder_type?: string;
|
|
127
|
+
holder_id?: number | string | Array<number | string>;
|
|
128
|
+
[key: string]: any;
|
|
129
|
+
};
|
|
130
|
+
reason?: string;
|
|
131
|
+
reasonCode?: string;
|
|
132
|
+
is_franchisor_pass?: number;
|
|
133
|
+
franchisee_wallet_pass?: {
|
|
134
|
+
use?: string;
|
|
135
|
+
};
|
|
136
|
+
committedAppliedProductDetails?: ApplicableProductDetails[];
|
|
114
137
|
resource_id?: number;
|
|
115
138
|
savedAmount?: number;
|
|
116
139
|
isEditMode?: boolean;
|
|
@@ -39,7 +39,7 @@ export interface IFormItemData {
|
|
|
39
39
|
/**
|
|
40
40
|
* form_id 为 key 的 map 结构,如 948: { records: [], form: {} }
|
|
41
41
|
*/
|
|
42
|
-
export
|
|
42
|
+
export type HolderFormMap = Record<string, IFormItemData>;
|
|
43
43
|
/**
|
|
44
44
|
* Holder 模块 reactive store,仅 holderMap 会触发 changed 事件
|
|
45
45
|
*/
|
|
@@ -61,7 +61,7 @@ export interface OpenDataApiResponse {
|
|
|
61
61
|
message: string;
|
|
62
62
|
data: OpenDataConfig;
|
|
63
63
|
}
|
|
64
|
-
export
|
|
64
|
+
export type OpenDataUnavailableReason = 'shop_disabled' | 'paused' | 'closed' | 'reservation_disabled';
|
|
65
65
|
export interface OpenDataAvailabilityResult {
|
|
66
66
|
available: boolean;
|
|
67
67
|
reason: OpenDataUnavailableReason | null;
|
|
@@ -69,7 +69,7 @@ export interface OrderGiftSelectResult {
|
|
|
69
69
|
*
|
|
70
70
|
* 返回数组时沿用旧协议,只写 tempOrder.products;返回对象时可同时写入预约 bookings。
|
|
71
71
|
*/
|
|
72
|
-
export
|
|
72
|
+
export type OrderGiftSelectResolver = (ctx: OrderGiftSelectContext) => Promise<Partial<OrderProduct>[] | OrderGiftSelectResult | null>;
|
|
73
73
|
/** 未满足的促销策略(购物车底部 alert 渲染源) */
|
|
74
74
|
export interface OrderUnfulfilledPromotion {
|
|
75
75
|
strategyId: string;
|
|
@@ -318,7 +318,7 @@ export interface ReplaceTempOrderOptions {
|
|
|
318
318
|
persist?: boolean;
|
|
319
319
|
saveDraft?: boolean;
|
|
320
320
|
}
|
|
321
|
-
export
|
|
321
|
+
export type AddProductBookingInput = Record<string, any>;
|
|
322
322
|
/** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 unique_identification_number / 选项指纹等 */
|
|
323
323
|
export interface UpdateOrderProductParams {
|
|
324
324
|
product_id: number | null;
|
|
@@ -376,7 +376,7 @@ export interface OrderProductMergeDecisionContext {
|
|
|
376
376
|
booking?: AddProductBookingInput;
|
|
377
377
|
defaultShouldMerge: boolean;
|
|
378
378
|
}
|
|
379
|
-
export
|
|
379
|
+
export type OrderProductMergeDecisionResult = boolean | {
|
|
380
380
|
shouldMerge: boolean;
|
|
381
381
|
reason?: string;
|
|
382
382
|
[key: string]: any;
|
|
@@ -524,11 +524,11 @@ export interface OrderPaymentData {
|
|
|
524
524
|
created_at?: string;
|
|
525
525
|
updated_at?: string;
|
|
526
526
|
}
|
|
527
|
-
export
|
|
527
|
+
export type OrderPaymentSource = PaymentItem | OrderPaymentData | Record<string, any>;
|
|
528
528
|
export interface MapOrderPaymentsOptions {
|
|
529
529
|
includeVoided?: boolean;
|
|
530
530
|
}
|
|
531
|
-
export
|
|
531
|
+
export type OrderSyncState = 'local' | 'submitting' | 'submitted' | 'failed' | 'remoteLoaded';
|
|
532
532
|
export interface LoadSalesDetailParams {
|
|
533
533
|
orderId?: number | string;
|
|
534
534
|
orderNumber?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OrderProductDiscountItem } from '../types';
|
|
2
|
-
|
|
2
|
+
type NormalizeDiscountList = (discountList?: unknown[] | null) => OrderProductDiscountItem[];
|
|
3
3
|
export declare function restoreHydratedBundleDiscounts<T extends Record<string, any>>(product: T, normalizeDiscountList: NormalizeDiscountList): T;
|
|
4
4
|
export declare function expandHydratedProductsForDiscountCollection(products: any[] | undefined | null): any[];
|
|
5
5
|
export {};
|
|
@@ -209,7 +209,7 @@ export interface SubmitPayloadEnhancerContext {
|
|
|
209
209
|
bookingUuid: string;
|
|
210
210
|
now: Date;
|
|
211
211
|
}
|
|
212
|
-
export
|
|
212
|
+
export type SubmitPayloadEnhancer = (payload: OrderSubmitPayload, ctx: SubmitPayloadEnhancerContext) => OrderSubmitPayload;
|
|
213
213
|
export declare function buildSubmitPayload(params: {
|
|
214
214
|
tempOrder: OrderTempOrder;
|
|
215
215
|
cacheId?: string;
|
|
@@ -629,12 +629,12 @@ export declare enum PaymentHooks {
|
|
|
629
629
|
OnOrderAmountChanged = "payment:onOrderAmountChanged",
|
|
630
630
|
OnPaymentSyncError = "payment:onPaymentSyncError",
|
|
631
631
|
OnPaymentSyncSuccess = "payment:onPaymentSyncSuccess",
|
|
632
|
-
OnWalletRecommendListUpdated =
|
|
633
|
-
OnWalletRecommendListCleared =
|
|
634
|
-
OnUserIdentificationCodesUpdated =
|
|
635
|
-
OnUserIdentificationCodesCleared =
|
|
636
|
-
OnWalletCacheCleared =
|
|
637
|
-
OnSearchIdentificationCodeCompleted =
|
|
632
|
+
OnWalletRecommendListUpdated = "wallet:onWalletRecommendListUpdated",
|
|
633
|
+
OnWalletRecommendListCleared = "wallet:onWalletRecommendListCleared",
|
|
634
|
+
OnUserIdentificationCodesUpdated = "wallet:onUserIdentificationCodesUpdated",
|
|
635
|
+
OnUserIdentificationCodesCleared = "wallet:onUserIdentificationCodesCleared",
|
|
636
|
+
OnWalletCacheCleared = "wallet:onWalletCacheCleared",
|
|
637
|
+
OnSearchIdentificationCodeCompleted = "wallet:onSearchIdentificationCodeCompleted"
|
|
638
638
|
}
|
|
639
639
|
/**
|
|
640
640
|
* 钱包推荐扣款请求参数
|
|
@@ -797,7 +797,7 @@ export interface SearchIdentificationCodeResponse {
|
|
|
797
797
|
/**
|
|
798
798
|
* 搜索识别码结果类型
|
|
799
799
|
*/
|
|
800
|
-
export
|
|
800
|
+
export type SearchIdentificationCodeResult = {
|
|
801
801
|
type: 'walletCode';
|
|
802
802
|
data: SearchIdentificationCodeItem[];
|
|
803
803
|
} | {
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "normal" | "duration" | "session";
|
|
53
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
1
|
+
export type ResourcePlannerMode = 'appointment' | 'scan_order' | 'venue_grid';
|
|
2
|
+
export type ResourcePlannerProductKind = 'normal' | 'duration' | 'session' | 'venue_slot';
|
|
3
|
+
export type ResourcePlannerResourceType = 'single' | 'multiple' | 'capacity';
|
|
4
|
+
export type ResourcePlannerStatus = 'available' | 'limited' | 'full' | 'conflict' | 'unavailable' | 'past';
|
|
5
5
|
export interface ResourcePlannerTimeRange {
|
|
6
6
|
start_at: string;
|
|
7
7
|
end_at: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RulesParamsHooks } from './types';
|
|
2
|
+
export declare function isEntitlementRuntimeLine(product: any, mappedProduct?: any): boolean;
|
|
3
|
+
/** 仅同步本次多次卡行的数量与价格,沿用 Rules 的主商品、套餐计算结果。 */
|
|
4
|
+
export declare function rebuildEntitlementLine(origin: any, bundle: any[], hooks: RulesParamsHooks, count?: number): any;
|
|
5
|
+
/** 重算只还原本次多次卡;套餐和多 Holder 按父商品份数计算,不再合并商品行。 */
|
|
6
|
+
export declare function prepareEntitlementLines(products: any[], hooks: RulesParamsHooks, canUseEntitlement: (product: any) => boolean): any[];
|
|
7
|
+
/** 客户端钩子可能保留原 _id,只给新增的重复行补标识,保留拆分结果。 */
|
|
8
|
+
export declare function finalizeEntitlementLines(products: any[], hooks: RulesParamsHooks): any[];
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.finalizeEntitlementLines = finalizeEntitlementLines;
|
|
7
|
+
exports.isEntitlementRuntimeLine = isEntitlementRuntimeLine;
|
|
8
|
+
exports.prepareEntitlementLines = prepareEntitlementLines;
|
|
9
|
+
exports.rebuildEntitlementLine = rebuildEntitlementLine;
|
|
10
|
+
var _lodashEs = require("lodash-es");
|
|
11
|
+
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
12
|
+
var _entitlementPass = require("../Discount/entitlementPass");
|
|
13
|
+
var _entitlementState = require("../Discount/entitlementState");
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
const SOURCE = 'entitlement_source_identity';
|
|
16
|
+
function isManualDiscount(data) {
|
|
17
|
+
return data.isManualDiscount ?? (data.total != data.origin_total && (data.bundle || []).every(item => !item.discount_list?.length) && (!data.discount_list?.length || data.discount_list.every(item => item.type === 'product')));
|
|
18
|
+
}
|
|
19
|
+
function isEntitlementRuntimeLine(product, mappedProduct) {
|
|
20
|
+
return product.metadata?.[SOURCE] != null && !(0, _entitlementState.isPersistedEntitlementLine)(product, mappedProduct) && !isManualDiscount(mappedProduct ?? product);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 仅同步本次多次卡行的数量与价格,沿用 Rules 的主商品、套餐计算结果。 */
|
|
24
|
+
function rebuildEntitlementLine(origin, bundle, hooks, count) {
|
|
25
|
+
const data = hooks.getProduct(origin);
|
|
26
|
+
const quantity = count ?? data.quantity ?? data.num ?? 1;
|
|
27
|
+
const discounts = (data.discount_list || []).map(item => (0, _entitlementPass.isEntitlementPass)(item) && !item.metadata?.custom_product_bundle_map_id ? {
|
|
28
|
+
...item,
|
|
29
|
+
_num: quantity,
|
|
30
|
+
metadata: {
|
|
31
|
+
...item.metadata,
|
|
32
|
+
num: quantity
|
|
33
|
+
}
|
|
34
|
+
} : item);
|
|
35
|
+
const mainDiscount = discounts.filter(item => !item.metadata?.custom_product_bundle_map_id).reduce((sum, item) => sum.plus(item.metadata?.mainProductDiscountAmount ?? item.amount ?? 0), new _decimal.default(0));
|
|
36
|
+
const originalPrice = new _decimal.default(data.original_price ?? data.price ?? 0);
|
|
37
|
+
const sourceSellingPrice = originalPrice.minus(mainDiscount).toNumber();
|
|
38
|
+
const optionPrice = (data.options || []).reduce((sum, item) => sum.plus(new _decimal.default(item.price ?? item.add_price ?? 0).times(item.num ?? item.quantity ?? 1)), new _decimal.default(0));
|
|
39
|
+
const bundleTotal = bundle.reduce((sum, item) => sum.plus(new _decimal.default(item.price || 0).times(item.num || 1)), new _decimal.default(0));
|
|
40
|
+
const bundleOriginalTotal = bundle.reduce((sum, item) => sum.plus(new _decimal.default(item.original_price ?? item.price ?? 0).times(item.num || 1)), new _decimal.default(0));
|
|
41
|
+
return hooks.setProduct(origin, {
|
|
42
|
+
quantity,
|
|
43
|
+
discount_list: discounts,
|
|
44
|
+
bundle,
|
|
45
|
+
price: sourceSellingPrice,
|
|
46
|
+
main_product_selling_price: sourceSellingPrice,
|
|
47
|
+
total: new _decimal.default(sourceSellingPrice).plus(optionPrice).plus(bundleTotal).toNumber(),
|
|
48
|
+
origin_total: originalPrice.plus(optionPrice).plus(bundleOriginalTotal).toNumber()
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function setLineIdentity(row, id) {
|
|
52
|
+
row._id = id;
|
|
53
|
+
row.metadata = {
|
|
54
|
+
...row.metadata,
|
|
55
|
+
unique_identification_number: id
|
|
56
|
+
};
|
|
57
|
+
if (row._extend) row._extend.unique_identification_number = id;
|
|
58
|
+
return row;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 重算只还原本次多次卡;套餐和多 Holder 按父商品份数计算,不再合并商品行。 */
|
|
62
|
+
function prepareEntitlementLines(products, hooks, canUseEntitlement) {
|
|
63
|
+
return products.flatMap(original => {
|
|
64
|
+
const data = hooks.getProduct(original);
|
|
65
|
+
if ((0, _entitlementState.isPersistedEntitlementLine)(original, data) || isManualDiscount(data)) return [original];
|
|
66
|
+
const applicable = canUseEntitlement(original);
|
|
67
|
+
if (!original.metadata?.[SOURCE] && !(0, _entitlementState.hasEntitlementDiscount)(data) && !applicable) return [original];
|
|
68
|
+
const origin = (0, _lodashEs.cloneDeep)(original);
|
|
69
|
+
origin.metadata = {
|
|
70
|
+
...origin.metadata,
|
|
71
|
+
[SOURCE]: origin.metadata?.[SOURCE] ?? data._id
|
|
72
|
+
};
|
|
73
|
+
const bundle = (data.bundle || []).map(item => {
|
|
74
|
+
const entitlement = (item.discount_list || []).find(_entitlementPass.isEntitlementPass);
|
|
75
|
+
if (!entitlement) return item;
|
|
76
|
+
const discounts = (item.discount_list || []).filter(discount => !(0, _entitlementPass.isEntitlementPass)(discount));
|
|
77
|
+
const originalPrice = item.original_price ?? entitlement.discount?.original_amount ?? item.product_price ?? item.price ?? 0;
|
|
78
|
+
const amount = discounts.reduce((sum, discount) => sum.plus(discount.amount || 0), new _decimal.default(0));
|
|
79
|
+
const price = new _decimal.default(originalPrice).minus(amount.div(item.num || 1)).toNumber();
|
|
80
|
+
return {
|
|
81
|
+
...item,
|
|
82
|
+
original_price: originalPrice,
|
|
83
|
+
price,
|
|
84
|
+
bundle_selling_price: price,
|
|
85
|
+
discount_list: discounts
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
const mainEntitlement = data.discount_list?.find(_entitlementPass.isEntitlementPass);
|
|
89
|
+
const restored = hooks.setProduct(origin, {
|
|
90
|
+
original_price: data.original_price ?? mainEntitlement?.discount?.original_amount ?? data.price,
|
|
91
|
+
discount_list: (data.discount_list || []).filter(item => !(0, _entitlementPass.isEntitlementPass)(item)),
|
|
92
|
+
bundle
|
|
93
|
+
});
|
|
94
|
+
const row = rebuildEntitlementLine(restored, bundle, hooks);
|
|
95
|
+
const count = Math.max(1, Math.floor(Number(data.quantity || data.num || 1)));
|
|
96
|
+
if (!applicable || count <= 1 || !bundle.length && !Array.isArray(data.holder_id)) return [row];
|
|
97
|
+
return Array.from({
|
|
98
|
+
length: count
|
|
99
|
+
}, (_, index) => {
|
|
100
|
+
const unit = (0, _lodashEs.cloneDeep)(row);
|
|
101
|
+
// booking 使用 _extend.holder_id,appointmentBooking 使用购物车 Holder。
|
|
102
|
+
for (const source of [unit, unit._extend]) {
|
|
103
|
+
if (Array.isArray(source?.holder_id)) source.holder_id = source.holder_id.slice(index, index + 1);
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(unit._origin?.holder?.form_record)) {
|
|
106
|
+
const records = unit._origin.holder.form_record;
|
|
107
|
+
// 单 Holder 的多份商品仍归属同一人;多个 Holder 才按份对应。
|
|
108
|
+
if (records.length > 1) unit._origin.holder.form_record = records.slice(index, index + 1);
|
|
109
|
+
}
|
|
110
|
+
return setLineIdentity(rebuildEntitlementLine(unit, hooks.getProduct(unit).bundle || [], hooks, 1), `${data._id}:entitlement-unit:${index}`);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 客户端钩子可能保留原 _id,只给新增的重复行补标识,保留拆分结果。 */
|
|
116
|
+
function finalizeEntitlementLines(products, hooks) {
|
|
117
|
+
const runtime = item => isEntitlementRuntimeLine(item, hooks.getProduct(item));
|
|
118
|
+
const seen = new Set(products.filter(item => !runtime(item)).map(item => String(item._id)));
|
|
119
|
+
return products.map((origin, index) => {
|
|
120
|
+
if (!runtime(origin)) return origin;
|
|
121
|
+
const base = String(origin._id ?? hooks.getProduct(origin)._id);
|
|
122
|
+
let id = base;
|
|
123
|
+
let ordinal = index;
|
|
124
|
+
while (seen.has(id)) id = `${base}:entitlement-split:${ordinal++}`;
|
|
125
|
+
seen.add(id);
|
|
126
|
+
return id === String(origin._id) ? origin : setLineIdentity((0, _lodashEs.cloneDeep)(origin), id);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -2,6 +2,7 @@ import { Module, PisellCore, ModuleOptions } from '../../types';
|
|
|
2
2
|
import { BaseModule } from '../BaseModule';
|
|
3
3
|
import { Rules, RulesModuleAPI, DiscountResult, RulesFormSubject, RulesCalcDiscountOptions, UnavailableReason } from './types';
|
|
4
4
|
import { Discount } from '../Discount/types';
|
|
5
|
+
import { WalletPassEvaluator } from '../../model/strategy/adapter/walletPass/evaluator';
|
|
5
6
|
import { WindowPlugin } from '../../plugins';
|
|
6
7
|
export declare class RulesModule extends BaseModule implements Module, RulesModuleAPI {
|
|
7
8
|
protected defaultName: string;
|
|
@@ -9,11 +10,19 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
|
|
|
9
10
|
private store;
|
|
10
11
|
window: WindowPlugin;
|
|
11
12
|
private hooks;
|
|
13
|
+
private entitlementPassEnabled;
|
|
14
|
+
private defaultWalletPassEvaluator?;
|
|
15
|
+
setEntitlementPassEnabled(enabled: boolean): void;
|
|
12
16
|
constructor(name?: string, version?: string);
|
|
13
17
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
14
18
|
setRulesList(rulesList: Rules[]): Promise<void>;
|
|
15
19
|
getRulesList(): Rules[];
|
|
16
|
-
getWalletPassEvaluator():
|
|
20
|
+
getWalletPassEvaluator(): WalletPassEvaluator | undefined;
|
|
21
|
+
private normalizeHolderRecordIds;
|
|
22
|
+
/**
|
|
23
|
+
* 商品未开启 Holder 选择时跳过匹配;已开启时,特定 form Holder 卡
|
|
24
|
+
* 只适用于同一 Holder Record,是否必填不影响匹配规则。
|
|
25
|
+
*/
|
|
17
26
|
private checkHolderMatch;
|
|
18
27
|
isDiscountListAvailable({ oldDiscountList, newDiscountList, productList, orderTotalAmount, holders, isFormSubject, }: {
|
|
19
28
|
oldDiscountList: Discount[];
|
|
@@ -21,7 +30,7 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
|
|
|
21
30
|
productList: any[];
|
|
22
31
|
orderTotalAmount: number;
|
|
23
32
|
holders: {
|
|
24
|
-
form_record_id: number;
|
|
33
|
+
form_record_id: number | string;
|
|
25
34
|
}[];
|
|
26
35
|
isFormSubject: RulesFormSubject;
|
|
27
36
|
}): {
|
|
@@ -29,6 +38,7 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
|
|
|
29
38
|
discountList: Discount[];
|
|
30
39
|
productList: any[];
|
|
31
40
|
unavailableReason?: UnavailableReason;
|
|
41
|
+
evaluatedDiscountList?: Discount[];
|
|
32
42
|
};
|
|
33
43
|
filterDiscountListByType(discountList: Discount[], type: string): Discount[];
|
|
34
44
|
/** 剔除指定 type/tag 的折扣项,保留手动改价(type=product) / 券等 */
|
|
@@ -40,7 +50,7 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
|
|
|
40
50
|
discountList: Discount[];
|
|
41
51
|
productList: any[];
|
|
42
52
|
holders: {
|
|
43
|
-
form_record_id: number;
|
|
53
|
+
form_record_id: number | string;
|
|
44
54
|
}[];
|
|
45
55
|
isFormSubject: RulesFormSubject;
|
|
46
56
|
orderTotalAmount: number;
|