@pisell/pisellos 2.1.169 → 2.1.170
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/model/strategy/adapter/dataVariant/evaluator.js +100 -13
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +1 -0
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/VenueBooking/index.d.ts +9 -0
- package/dist/solution/VenueBooking/index.js +222 -105
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/smartPricing.js +78 -9
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +91 -8
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +1 -0
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/VenueBooking/index.d.ts +9 -0
- package/lib/solution/VenueBooking/index.js +107 -4
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/smartPricing.js +46 -1
- package/package.json +1 -1
|
@@ -16,6 +16,7 @@ export interface VenueBookingSmartPricingContext {
|
|
|
16
16
|
orderType?: string;
|
|
17
17
|
strategy_context?: Record<string, any>;
|
|
18
18
|
strategyConfigs?: StrategyConfig[];
|
|
19
|
+
debugLog?: (title: string, payload?: Record<string, any>) => void;
|
|
19
20
|
}
|
|
20
21
|
/** 从商品上读取展示/算价用的 price 字段 */
|
|
21
22
|
export declare function extractProductPrice(product: DataVariantProduct): string | null;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
4
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
1
5
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
2
6
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
3
7
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
@@ -29,7 +33,8 @@ export function buildDataVariantBusinessData(products, context, scheduleDateTime
|
|
|
29
33
|
channel: (_context$channel = context.channel) !== null && _context$channel !== void 0 ? _context$channel : strategyContext.channel,
|
|
30
34
|
orderType: (_ref2 = (_context$orderType = context.orderType) !== null && _context$orderType !== void 0 ? _context$orderType : strategyContext.orderType) !== null && _ref2 !== void 0 ? _ref2 : strategyContext.order_type,
|
|
31
35
|
businessCode: (_ref3 = (_context$businessCode = context.businessCode) !== null && _context$businessCode !== void 0 ? _context$businessCode : strategyContext.business_code) !== null && _ref3 !== void 0 ? _ref3 : strategyContext.businessCode,
|
|
32
|
-
custom: strategyContext
|
|
36
|
+
custom: strategyContext,
|
|
37
|
+
debugLog: context === null || context === void 0 ? void 0 : context.debugLog
|
|
33
38
|
};
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -38,6 +43,7 @@ export function buildDataVariantBusinessData(products, context, scheduleDateTime
|
|
|
38
43
|
* evaluator 未注入时原样返回并打 warning。
|
|
39
44
|
*/
|
|
40
45
|
export function formatProductsWithDataVariant(products, context, scheduleDateTime) {
|
|
46
|
+
var _context$debugLog, _context$debugLog2, _result$globalEffecti, _result$globalEffecti2;
|
|
41
47
|
var evaluator = context.evaluator;
|
|
42
48
|
if (!evaluator || typeof evaluator.resolveProducts !== 'function') {
|
|
43
49
|
console.warn('[VenueBooking][smartPricing] dataVariantEvaluator 未注入,跳过智能定价格式化');
|
|
@@ -45,7 +51,35 @@ export function formatProductsWithDataVariant(products, context, scheduleDateTim
|
|
|
45
51
|
}
|
|
46
52
|
var resolvedAt = scheduleDateTime || dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
47
53
|
var businessData = buildDataVariantBusinessData(products, context, resolvedAt);
|
|
54
|
+
(_context$debugLog = context.debugLog) === null || _context$debugLog === void 0 || _context$debugLog.call(context, '[VenueBooking][smartPricing] formatProducts input', {
|
|
55
|
+
scheduleDateTime: resolvedAt,
|
|
56
|
+
customerId: businessData.customerId,
|
|
57
|
+
availableWalletIds: businessData.availableWalletIds,
|
|
58
|
+
channel: businessData.channel,
|
|
59
|
+
businessCode: businessData.businessCode,
|
|
60
|
+
orderType: businessData.orderType,
|
|
61
|
+
productCount: products.length,
|
|
62
|
+
products: products.map(function (product) {
|
|
63
|
+
var _product$id;
|
|
64
|
+
return {
|
|
65
|
+
productId: (_product$id = product === null || product === void 0 ? void 0 : product.id) !== null && _product$id !== void 0 ? _product$id : product === null || product === void 0 ? void 0 : product.product_id,
|
|
66
|
+
price: product === null || product === void 0 ? void 0 : product.price,
|
|
67
|
+
sellingPrice: product === null || product === void 0 ? void 0 : product.selling_price,
|
|
68
|
+
dataVariants: Array.isArray(product === null || product === void 0 ? void 0 : product.data_variants) ? product.data_variants.map(function (variant) {
|
|
69
|
+
return {
|
|
70
|
+
dataVariantRuleId: variant === null || variant === void 0 ? void 0 : variant.data_variant_rule_id,
|
|
71
|
+
data: variant === null || variant === void 0 ? void 0 : variant.data
|
|
72
|
+
};
|
|
73
|
+
}) : []
|
|
74
|
+
};
|
|
75
|
+
})
|
|
76
|
+
});
|
|
48
77
|
var result = evaluator.resolveProducts(businessData);
|
|
78
|
+
(_context$debugLog2 = context.debugLog) === null || _context$debugLog2 === void 0 || _context$debugLog2.call(context, '[VenueBooking][smartPricing] formatProducts output', {
|
|
79
|
+
scheduleDateTime: resolvedAt,
|
|
80
|
+
effectiveRuleIds: Array.from((result === null || result === void 0 || (_result$globalEffecti = result.globalEffectiveRuleMap) === null || _result$globalEffecti === void 0 || (_result$globalEffecti2 = _result$globalEffecti.keys) === null || _result$globalEffecti2 === void 0 ? void 0 : _result$globalEffecti2.call(_result$globalEffecti)) || []),
|
|
81
|
+
resultProducts: (result === null || result === void 0 ? void 0 : result.products) || []
|
|
82
|
+
});
|
|
49
83
|
return Array.isArray(result === null || result === void 0 ? void 0 : result.products) ? result.products : products;
|
|
50
84
|
}
|
|
51
85
|
|
|
@@ -121,6 +155,7 @@ export function buildSlotStartDatetime(date, label, config) {
|
|
|
121
155
|
* key: `${productId}:${slotStart}`,value: price | null
|
|
122
156
|
*/
|
|
123
157
|
export function buildSlotPriceMapByScheduleSegments(params) {
|
|
158
|
+
var _context$debugLog3, _context$debugLog4;
|
|
124
159
|
var products = params.products,
|
|
125
160
|
productIds = params.productIds,
|
|
126
161
|
date = params.date,
|
|
@@ -141,10 +176,18 @@ export function buildSlotPriceMapByScheduleSegments(params) {
|
|
|
141
176
|
scheduleTimePoints: scheduleTimePoints
|
|
142
177
|
});
|
|
143
178
|
var priceCache = new Map();
|
|
179
|
+
(_context$debugLog3 = context.debugLog) === null || _context$debugLog3 === void 0 || _context$debugLog3.call(context, '[VenueBooking][smartPricing] slot price evaluation started', {
|
|
180
|
+
date: date,
|
|
181
|
+
productIds: productIds,
|
|
182
|
+
scheduleTimePoints: scheduleTimePoints,
|
|
183
|
+
evalDatetimes: evalDatetimes,
|
|
184
|
+
timeLabels: timeLabels
|
|
185
|
+
});
|
|
144
186
|
var _iterator3 = _createForOfIteratorHelper(evalDatetimes),
|
|
145
187
|
_step3;
|
|
146
188
|
try {
|
|
147
|
-
|
|
189
|
+
var _loop = function _loop() {
|
|
190
|
+
var _context$debugLog5;
|
|
148
191
|
var evalDt = _step3.value;
|
|
149
192
|
var resolved = formatProductsWithDataVariant(products, context, evalDt);
|
|
150
193
|
var priceByProductId = new Map();
|
|
@@ -163,6 +206,20 @@ export function buildSlotPriceMapByScheduleSegments(params) {
|
|
|
163
206
|
_iterator5.f();
|
|
164
207
|
}
|
|
165
208
|
priceCache.set(evalDt, priceByProductId);
|
|
209
|
+
(_context$debugLog5 = context.debugLog) === null || _context$debugLog5 === void 0 || _context$debugLog5.call(context, '[VenueBooking][smartPricing] slot segment prices resolved', {
|
|
210
|
+
date: date,
|
|
211
|
+
evalDatetime: evalDt,
|
|
212
|
+
prices: productIds.map(function (productId) {
|
|
213
|
+
var _priceByProductId$get;
|
|
214
|
+
return {
|
|
215
|
+
productId: productId,
|
|
216
|
+
price: (_priceByProductId$get = priceByProductId.get(productId)) !== null && _priceByProductId$get !== void 0 ? _priceByProductId$get : null
|
|
217
|
+
};
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
222
|
+
_loop();
|
|
166
223
|
}
|
|
167
224
|
} catch (err) {
|
|
168
225
|
_iterator3.e(err);
|
|
@@ -176,15 +233,15 @@ export function buildSlotPriceMapByScheduleSegments(params) {
|
|
|
176
233
|
var label = _step4.value;
|
|
177
234
|
var slotStart = buildSlotStartDatetime(date, label, config);
|
|
178
235
|
var segmentEvalDt = findSegmentEvalDatetime(slotStart, evalDatetimes);
|
|
179
|
-
var
|
|
236
|
+
var priceByProductId = priceCache.get(segmentEvalDt);
|
|
180
237
|
var _iterator6 = _createForOfIteratorHelper(productIds),
|
|
181
238
|
_step6;
|
|
182
239
|
try {
|
|
183
240
|
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
184
|
-
var _priceByProductId$
|
|
185
|
-
var
|
|
186
|
-
var key = "".concat(
|
|
187
|
-
var price = (_priceByProductId$
|
|
241
|
+
var _priceByProductId$get2;
|
|
242
|
+
var productId = _step6.value;
|
|
243
|
+
var key = "".concat(productId, ":").concat(slotStart);
|
|
244
|
+
var price = (_priceByProductId$get2 = priceByProductId === null || priceByProductId === void 0 ? void 0 : priceByProductId.get(productId)) !== null && _priceByProductId$get2 !== void 0 ? _priceByProductId$get2 : null;
|
|
188
245
|
if (price !== null) {
|
|
189
246
|
map.set(key, price);
|
|
190
247
|
}
|
|
@@ -200,6 +257,18 @@ export function buildSlotPriceMapByScheduleSegments(params) {
|
|
|
200
257
|
} finally {
|
|
201
258
|
_iterator4.f();
|
|
202
259
|
}
|
|
260
|
+
(_context$debugLog4 = context.debugLog) === null || _context$debugLog4 === void 0 || _context$debugLog4.call(context, '[VenueBooking][smartPricing] slot price map completed', {
|
|
261
|
+
date: date,
|
|
262
|
+
entries: Array.from(map.entries()).map(function (_ref4) {
|
|
263
|
+
var _ref5 = _slicedToArray(_ref4, 2),
|
|
264
|
+
key = _ref5[0],
|
|
265
|
+
price = _ref5[1];
|
|
266
|
+
return {
|
|
267
|
+
key: key,
|
|
268
|
+
price: price
|
|
269
|
+
};
|
|
270
|
+
})
|
|
271
|
+
});
|
|
203
272
|
return map;
|
|
204
273
|
}
|
|
205
274
|
|
|
@@ -207,7 +276,7 @@ export function buildSlotPriceMapByScheduleSegments(params) {
|
|
|
207
276
|
* 指定商品在某一 datetime 的智能定价(addon / 单点重算用)。
|
|
208
277
|
*/
|
|
209
278
|
export function getPriceForProductAtDatetime(params) {
|
|
210
|
-
var
|
|
279
|
+
var _ref6, _extractProductPrice;
|
|
211
280
|
var products = params.products,
|
|
212
281
|
context = params.context,
|
|
213
282
|
productId = params.productId,
|
|
@@ -217,7 +286,7 @@ export function getPriceForProductAtDatetime(params) {
|
|
|
217
286
|
var product = resolved.find(function (item) {
|
|
218
287
|
return Number(item.id) === Number(productId);
|
|
219
288
|
});
|
|
220
|
-
return (
|
|
289
|
+
return (_ref6 = (_extractProductPrice = extractProductPrice(product || {})) !== null && _extractProductPrice !== void 0 ? _extractProductPrice : fallbackPrice) !== null && _ref6 !== void 0 ? _ref6 : '0.00';
|
|
221
290
|
}
|
|
222
291
|
|
|
223
292
|
/** 从 slot 价格 Map 读取单价,找不到则回退 fallback */
|
|
@@ -46,6 +46,7 @@ var DataVariantEvaluator = class {
|
|
|
46
46
|
* 先执行全局预计算,再只针对商品自身 data_variants 引用到的规则做商品级判断。
|
|
47
47
|
*/
|
|
48
48
|
resolveProducts(businessData) {
|
|
49
|
+
var _a;
|
|
49
50
|
const strategyConfigs = businessData.strategyConfigs ? this.normalizeStrategyConfigs(businessData.strategyConfigs) : this.strategyConfigs;
|
|
50
51
|
const menuScopeMap = this.buildMenuScopeMap(businessData.menuList || []);
|
|
51
52
|
const scheduleTimePoints = this.buildScheduleTimePoints(
|
|
@@ -57,12 +58,14 @@ var DataVariantEvaluator = class {
|
|
|
57
58
|
businessData,
|
|
58
59
|
menuScopeMap
|
|
59
60
|
);
|
|
61
|
+
const productDiagnostics = businessData.debugLog ? [] : void 0;
|
|
60
62
|
const products = businessData.products.map((product) => {
|
|
61
63
|
const resolvedProduct = this.resolveProduct(
|
|
62
64
|
product,
|
|
63
65
|
businessData,
|
|
64
66
|
globalEffectiveRuleMap,
|
|
65
|
-
menuScopeMap
|
|
67
|
+
menuScopeMap,
|
|
68
|
+
productDiagnostics
|
|
66
69
|
);
|
|
67
70
|
return this.resolveProductBundleItems(
|
|
68
71
|
resolvedProduct,
|
|
@@ -71,6 +74,32 @@ var DataVariantEvaluator = class {
|
|
|
71
74
|
menuScopeMap
|
|
72
75
|
);
|
|
73
76
|
});
|
|
77
|
+
(_a = businessData == null ? void 0 : businessData.debugLog) == null ? void 0 : _a.call(businessData, "[VenueBooking][smartPricing] evaluator result", {
|
|
78
|
+
scheduleDateTime: businessData.scheduleDateTime,
|
|
79
|
+
strategyConfigs: strategyConfigs.map((config) => {
|
|
80
|
+
var _a2, _b, _c, _d;
|
|
81
|
+
return {
|
|
82
|
+
ruleId: String((_a2 = config == null ? void 0 : config.metadata) == null ? void 0 : _a2.id),
|
|
83
|
+
name: (_b = config == null ? void 0 : config.metadata) == null ? void 0 : _b.name,
|
|
84
|
+
status: (_d = (_c = config == null ? void 0 : config.metadata) == null ? void 0 : _c.custom) == null ? void 0 : _d.status,
|
|
85
|
+
priority: this.getStrategyPriority(config),
|
|
86
|
+
conditions: config == null ? void 0 : config.conditions
|
|
87
|
+
};
|
|
88
|
+
}),
|
|
89
|
+
globalRuleResults: rawResults.map((result) => {
|
|
90
|
+
var _a2, _b, _c, _d;
|
|
91
|
+
return {
|
|
92
|
+
ruleId: String((_b = (_a2 = result == null ? void 0 : result.config) == null ? void 0 : _a2.metadata) == null ? void 0 : _b.id),
|
|
93
|
+
name: (_d = (_c = result == null ? void 0 : result.config) == null ? void 0 : _c.metadata) == null ? void 0 : _d.name,
|
|
94
|
+
applicable: result == null ? void 0 : result.applicable,
|
|
95
|
+
code: result == null ? void 0 : result.code,
|
|
96
|
+
message: result == null ? void 0 : result.message,
|
|
97
|
+
matched: result == null ? void 0 : result.matched
|
|
98
|
+
};
|
|
99
|
+
}),
|
|
100
|
+
effectiveRuleIds: Array.from(globalEffectiveRuleMap.keys()),
|
|
101
|
+
productDiagnostics: productDiagnostics || []
|
|
102
|
+
});
|
|
74
103
|
return {
|
|
75
104
|
products,
|
|
76
105
|
globalEffectiveRuleMap,
|
|
@@ -177,20 +206,57 @@ var DataVariantEvaluator = class {
|
|
|
177
206
|
}
|
|
178
207
|
return { globalEffectiveRuleMap, rawResults };
|
|
179
208
|
}
|
|
180
|
-
resolveProduct(product, businessData, globalEffectiveRuleMap, menuScopeMap) {
|
|
209
|
+
resolveProduct(product, businessData, globalEffectiveRuleMap, menuScopeMap, diagnostics) {
|
|
210
|
+
var _a, _b;
|
|
181
211
|
const dataVariants = this.getProductDataVariants(product);
|
|
182
|
-
|
|
212
|
+
const productId = (product == null ? void 0 : product.id) ?? (product == null ? void 0 : product.product_id);
|
|
213
|
+
if (!dataVariants.length) {
|
|
214
|
+
diagnostics == null ? void 0 : diagnostics.push({
|
|
215
|
+
productId,
|
|
216
|
+
originalPrice: (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price),
|
|
217
|
+
finalPrice: (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price),
|
|
218
|
+
reason: "product has no data_variants",
|
|
219
|
+
variants: []
|
|
220
|
+
});
|
|
183
221
|
return product;
|
|
222
|
+
}
|
|
184
223
|
const matchedVariants = [];
|
|
224
|
+
const variantDiagnostics = [];
|
|
185
225
|
for (const variant of dataVariants) {
|
|
226
|
+
const ruleId = String(variant.data_variant_rule_id);
|
|
186
227
|
const rule = globalEffectiveRuleMap.get(
|
|
187
|
-
|
|
228
|
+
ruleId
|
|
188
229
|
);
|
|
189
|
-
if (!rule)
|
|
230
|
+
if (!rule) {
|
|
231
|
+
variantDiagnostics.push({
|
|
232
|
+
ruleId,
|
|
233
|
+
variantData: variant.data || {},
|
|
234
|
+
globalRuleEffective: false,
|
|
235
|
+
productRulesMatched: false,
|
|
236
|
+
reason: "referenced rule is missing or its global conditions did not match"
|
|
237
|
+
});
|
|
190
238
|
continue;
|
|
191
|
-
|
|
239
|
+
}
|
|
240
|
+
const productRulesMatched = this.evaluateProductRules(rule, product, businessData, menuScopeMap);
|
|
241
|
+
if (!productRulesMatched) {
|
|
242
|
+
variantDiagnostics.push({
|
|
243
|
+
ruleId,
|
|
244
|
+
variantData: variant.data || {},
|
|
245
|
+
globalRuleEffective: true,
|
|
246
|
+
productRulesMatched: false,
|
|
247
|
+
productRules: rule.productRules,
|
|
248
|
+
reason: "product-level conditions did not match"
|
|
249
|
+
});
|
|
192
250
|
continue;
|
|
193
251
|
}
|
|
252
|
+
variantDiagnostics.push({
|
|
253
|
+
ruleId,
|
|
254
|
+
variantData: variant.data || {},
|
|
255
|
+
globalRuleEffective: true,
|
|
256
|
+
productRulesMatched: true,
|
|
257
|
+
priority: rule.priority,
|
|
258
|
+
reason: "variant matched and will be merged into the product"
|
|
259
|
+
});
|
|
194
260
|
matchedVariants.push({
|
|
195
261
|
ruleId: rule.ruleId,
|
|
196
262
|
priority: rule.priority,
|
|
@@ -198,9 +264,26 @@ var DataVariantEvaluator = class {
|
|
|
198
264
|
variant
|
|
199
265
|
});
|
|
200
266
|
}
|
|
201
|
-
if (!matchedVariants.length)
|
|
267
|
+
if (!matchedVariants.length) {
|
|
268
|
+
diagnostics == null ? void 0 : diagnostics.push({
|
|
269
|
+
productId,
|
|
270
|
+
originalPrice: (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price),
|
|
271
|
+
finalPrice: (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price),
|
|
272
|
+
reason: "no data_variant matched",
|
|
273
|
+
variants: variantDiagnostics
|
|
274
|
+
});
|
|
202
275
|
return product;
|
|
203
|
-
|
|
276
|
+
}
|
|
277
|
+
const resolvedProduct = this.mergeMatchedVariants(product, matchedVariants);
|
|
278
|
+
diagnostics == null ? void 0 : diagnostics.push({
|
|
279
|
+
productId,
|
|
280
|
+
originalPrice: (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price),
|
|
281
|
+
finalPrice: (resolvedProduct == null ? void 0 : resolvedProduct.price) ?? (resolvedProduct == null ? void 0 : resolvedProduct.selling_price),
|
|
282
|
+
appliedRuleIds: ((_a = resolvedProduct == null ? void 0 : resolvedProduct._dataVariant) == null ? void 0 : _a.appliedRuleIds) || [],
|
|
283
|
+
appliedFields: ((_b = resolvedProduct == null ? void 0 : resolvedProduct._dataVariant) == null ? void 0 : _b.appliedFields) || [],
|
|
284
|
+
variants: variantDiagnostics
|
|
285
|
+
});
|
|
286
|
+
return resolvedProduct;
|
|
204
287
|
}
|
|
205
288
|
/**
|
|
206
289
|
* 解析套餐子商品上的 Data Variant 覆盖。
|
|
@@ -105,6 +105,7 @@ export interface DataVariantBusinessData {
|
|
|
105
105
|
/** 当前客户可用 wallet/pass id 合并列表,对应策略条件 field: available_wallet_ids */
|
|
106
106
|
availableWalletIds?: Array<number | string>;
|
|
107
107
|
custom?: Record<string, any>;
|
|
108
|
+
debugLog?: (title: string, payload?: Record<string, any>) => void;
|
|
108
109
|
}
|
|
109
110
|
/**
|
|
110
111
|
* 全局预计算后的规则信息。
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
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/model/strategy/adapter/promotion/index.ts
|
|
30
|
-
var promotion_exports = {};
|
|
31
|
-
__export(promotion_exports, {
|
|
32
|
-
BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
|
|
33
|
-
PromotionAdapter: () => import_adapter.PromotionAdapter,
|
|
34
|
-
PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
|
|
35
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
|
|
36
|
-
default: () => import_adapter2.default
|
|
37
|
-
});
|
|
38
|
-
module.exports = __toCommonJS(promotion_exports);
|
|
39
|
-
var import_evaluator = require("./evaluator");
|
|
40
|
-
var import_adapter = require("./adapter");
|
|
41
|
-
var import_adapter2 = __toESM(require("./adapter"));
|
|
42
|
-
var import_examples = require("./examples");
|
|
43
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
44
|
-
0 && (module.exports = {
|
|
45
|
-
BUY_X_GET_Y_FREE_STRATEGY,
|
|
46
|
-
PromotionAdapter,
|
|
47
|
-
PromotionEvaluator,
|
|
48
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY
|
|
49
|
-
});
|
|
@@ -310,7 +310,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
310
310
|
date: string;
|
|
311
311
|
status: string;
|
|
312
312
|
week: string;
|
|
313
|
-
weekNum: 0 | 1 | 5 | 4 |
|
|
313
|
+
weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
|
|
314
314
|
}[]>;
|
|
315
315
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
316
316
|
private getScheduleDataByIds;
|
|
@@ -329,7 +329,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
329
329
|
count: number;
|
|
330
330
|
left: number;
|
|
331
331
|
summaryCount: number;
|
|
332
|
-
status: "
|
|
332
|
+
status: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
333
333
|
}[];
|
|
334
334
|
/**
|
|
335
335
|
* 找到多个资源的公共可用时间段
|
|
@@ -18,6 +18,7 @@ interface VenueBookingItemRuleRuntimeConfig {
|
|
|
18
18
|
custom?: Record<string, any>;
|
|
19
19
|
}
|
|
20
20
|
export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
21
|
+
private static readonly PRICING_DEBUG_CACHE_ID;
|
|
21
22
|
protected defaultName: string;
|
|
22
23
|
protected defaultVersion: string;
|
|
23
24
|
isSolution: boolean;
|
|
@@ -53,6 +54,14 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
53
54
|
private pickErrorMessage;
|
|
54
55
|
private serializeError;
|
|
55
56
|
private addVenueBookingLog;
|
|
57
|
+
/**
|
|
58
|
+
* 临时线上排查日志:
|
|
59
|
+
* - 仅对指定页面 cacheId 开启,避免影响其他页面
|
|
60
|
+
* - 不 await,且吞掉日志上报异常,保证日志系统不会阻断登录/商品加载主流程
|
|
61
|
+
*/
|
|
62
|
+
private logPricingDiagnostics;
|
|
63
|
+
private isPricingDiagnosticsEnabled;
|
|
64
|
+
private getAvailableWalletIdsForDiagnostics;
|
|
56
65
|
private logMethodStart;
|
|
57
66
|
private logMethodSuccess;
|
|
58
67
|
private logMethodError;
|
|
@@ -190,6 +190,36 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
190
190
|
extra
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* 临时线上排查日志:
|
|
195
|
+
* - 仅对指定页面 cacheId 开启,避免影响其他页面
|
|
196
|
+
* - 不 await,且吞掉日志上报异常,保证日志系统不会阻断登录/商品加载主流程
|
|
197
|
+
*/
|
|
198
|
+
logPricingDiagnostics(title, payload = {}) {
|
|
199
|
+
if (!this.isPricingDiagnosticsEnabled())
|
|
200
|
+
return;
|
|
201
|
+
void this.addVenueBookingLog({
|
|
202
|
+
level: "info",
|
|
203
|
+
title,
|
|
204
|
+
payload
|
|
205
|
+
}).catch((error) => {
|
|
206
|
+
console.warn("[VenueBooking] pricing diagnostic log failed", error);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
isPricingDiagnosticsEnabled() {
|
|
210
|
+
return String(this.cacheId || "") === _VenueBookingImpl.PRICING_DEBUG_CACHE_ID;
|
|
211
|
+
}
|
|
212
|
+
getAvailableWalletIdsForDiagnostics() {
|
|
213
|
+
var _a, _b;
|
|
214
|
+
try {
|
|
215
|
+
return (_b = (_a = this.store.order) == null ? void 0 : _a.getAvailableWalletIds) == null ? void 0 : _b.call(_a);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return {
|
|
218
|
+
readFailed: true,
|
|
219
|
+
error: this.serializeError(error)
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
193
223
|
logMethodStart(method, payload = {}) {
|
|
194
224
|
void this.addVenueBookingLog({
|
|
195
225
|
level: "info",
|
|
@@ -280,8 +310,18 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
280
310
|
this.clearLoginEffectListeners();
|
|
281
311
|
const createHandleLogin = () => async (payload) => {
|
|
282
312
|
const customerId = this.resolveCustomerIdFromLoginPayload(payload);
|
|
283
|
-
|
|
313
|
+
this.logPricingDiagnostics("[VenueBooking] customer login event received", {
|
|
314
|
+
customerId,
|
|
315
|
+
hasLoadAllProductsInFlight: !!this.loadAllProductsInFlight,
|
|
316
|
+
productsLoaded: this.productsLoaded,
|
|
317
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length
|
|
318
|
+
});
|
|
319
|
+
if (!customerId) {
|
|
320
|
+
this.logPricingDiagnostics(
|
|
321
|
+
"[VenueBooking] customer login event skipped customerId not found in login payload"
|
|
322
|
+
);
|
|
284
323
|
return;
|
|
324
|
+
}
|
|
285
325
|
await this.refreshOrderMarketingAfterLogin({ customerId });
|
|
286
326
|
};
|
|
287
327
|
this.registerLoginEffect(_VenueBookingImpl.PISELL1_LOGIN_SUCCESS, createHandleLogin());
|
|
@@ -291,8 +331,21 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
291
331
|
async refreshOrderMarketingAfterLogin(params) {
|
|
292
332
|
if (!this.store.order)
|
|
293
333
|
throw new Error("order 模块未初始化");
|
|
334
|
+
this.logPricingDiagnostics("[VenueBooking] refreshOrderMarketingAfterLogin entered", {
|
|
335
|
+
customerId: params.customerId,
|
|
336
|
+
hasCustomerLoginRefreshInFlight: !!this.customerLoginRefreshInFlight,
|
|
337
|
+
customerLoginRefreshIdInFlight: this.customerLoginRefreshIdInFlight,
|
|
338
|
+
hasLoadAllProductsInFlight: !!this.loadAllProductsInFlight,
|
|
339
|
+
productsLoaded: this.productsLoaded,
|
|
340
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length,
|
|
341
|
+
note: "This login refresh recalculates the loaded catalog and does not call loadAllProducts"
|
|
342
|
+
});
|
|
294
343
|
if (this.customerLoginRefreshInFlight) {
|
|
295
344
|
if (this.customerLoginRefreshIdInFlight === params.customerId) {
|
|
345
|
+
this.logPricingDiagnostics("[VenueBooking] customer login refresh reused", {
|
|
346
|
+
customerId: params.customerId,
|
|
347
|
+
reason: "same customer refresh is already in flight"
|
|
348
|
+
});
|
|
296
349
|
await this.customerLoginRefreshInFlight;
|
|
297
350
|
return;
|
|
298
351
|
}
|
|
@@ -349,6 +402,12 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
349
402
|
this.store.slotConfig = { ...this.baseSlotConfig };
|
|
350
403
|
this.otherParams = options.otherParams || {};
|
|
351
404
|
this.cacheId = (_c = this.otherParams) == null ? void 0 : _c.cacheId;
|
|
405
|
+
this.logPricingDiagnostics("[VenueBooking] initialize product loading state", {
|
|
406
|
+
hasLoadAllProductsInFlight: !!this.loadAllProductsInFlight,
|
|
407
|
+
productsLoaded: this.productsLoaded,
|
|
408
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length,
|
|
409
|
+
note: "initialize currently does not reset the product loading state"
|
|
410
|
+
});
|
|
352
411
|
this.itemRuleRuntimeConfig = ((_d = this.otherParams) == null ? void 0 : _d.venueBookingItemRule) || ((_e = this.otherParams) == null ? void 0 : _e.itemRule) || {};
|
|
353
412
|
this.itemRuleConfigs = [];
|
|
354
413
|
this.itemRuleConfigsPromise = null;
|
|
@@ -591,7 +650,10 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
591
650
|
channel: (_f = this.otherParams) == null ? void 0 : _f.channel,
|
|
592
651
|
businessCode: (_g = this.otherParams) == null ? void 0 : _g.businessCode,
|
|
593
652
|
orderType: ((_h = this.otherParams) == null ? void 0 : _h.orderType) || ((_i = this.otherParams) == null ? void 0 : _i.type),
|
|
594
|
-
strategy_context: (_j = this.otherParams) == null ? void 0 : _j.strategy_context
|
|
653
|
+
strategy_context: (_j = this.otherParams) == null ? void 0 : _j.strategy_context,
|
|
654
|
+
...this.isPricingDiagnosticsEnabled() ? {
|
|
655
|
+
debugLog: (title, payload = {}) => this.logPricingDiagnostics(title, payload)
|
|
656
|
+
} : {}
|
|
595
657
|
};
|
|
596
658
|
}
|
|
597
659
|
/** venue + addon 全量商品,供智能定价评估 */
|
|
@@ -635,9 +697,30 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
635
697
|
}
|
|
636
698
|
// ─── 场地商品 & 附加商品 ───
|
|
637
699
|
async loadAllProducts() {
|
|
638
|
-
|
|
700
|
+
this.logPricingDiagnostics("[VenueBooking] loadAllProducts called", {
|
|
701
|
+
hasLoadAllProductsInFlight: !!this.loadAllProductsInFlight,
|
|
702
|
+
productsLoaded: this.productsLoaded,
|
|
703
|
+
smartPricingCustomerId: this.smartPricingCustomerId,
|
|
704
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length,
|
|
705
|
+
venueProducts: !this.store.venueProducts,
|
|
706
|
+
addonProducts: !this.store.addonProducts
|
|
707
|
+
});
|
|
708
|
+
if (this.loadAllProductsInFlight) {
|
|
709
|
+
this.logPricingDiagnostics("[VenueBooking] loadAllProducts request skipped", {
|
|
710
|
+
reason: "reusing existing loadAllProductsInFlight promise",
|
|
711
|
+
productsLoaded: this.productsLoaded
|
|
712
|
+
});
|
|
639
713
|
return this.loadAllProductsInFlight;
|
|
714
|
+
}
|
|
715
|
+
this.logPricingDiagnostics("[VenueBooking] loadAllProducts request starting", {
|
|
716
|
+
productsLoaded: this.productsLoaded,
|
|
717
|
+
smartPricingCustomerId: this.smartPricingCustomerId
|
|
718
|
+
});
|
|
640
719
|
this.loadAllProductsInFlight = this._doLoadAllProducts().finally(() => {
|
|
720
|
+
this.logPricingDiagnostics("[VenueBooking] loadAllProducts request settled", {
|
|
721
|
+
productsLoaded: this.productsLoaded,
|
|
722
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length
|
|
723
|
+
});
|
|
641
724
|
this.loadAllProductsInFlight = null;
|
|
642
725
|
});
|
|
643
726
|
return this.loadAllProductsInFlight;
|
|
@@ -667,11 +750,21 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
667
750
|
const rawList = Array.isArray(allProducts) ? allProducts : [];
|
|
668
751
|
let list = rawList;
|
|
669
752
|
this.smartPricingProductCatalog = rawList.slice();
|
|
753
|
+
const smartPricingContext = this.buildSmartPricingContext();
|
|
670
754
|
list = (0, import_smartPricing.formatProductsWithDataVariant)(
|
|
671
755
|
list,
|
|
672
|
-
|
|
756
|
+
smartPricingContext,
|
|
673
757
|
(0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
674
758
|
);
|
|
759
|
+
if (this.isPricingDiagnosticsEnabled()) {
|
|
760
|
+
this.logPricingDiagnostics("[VenueBooking] loadAllProducts smart pricing context", {
|
|
761
|
+
smartPricingContext,
|
|
762
|
+
rawList,
|
|
763
|
+
list,
|
|
764
|
+
otherParams: this.otherParams,
|
|
765
|
+
availableWalletIds: this.getAvailableWalletIdsForDiagnostics()
|
|
766
|
+
});
|
|
767
|
+
}
|
|
675
768
|
this.clearSlotPriceMapCache();
|
|
676
769
|
const venueList = list.filter((p) => p.duration != null);
|
|
677
770
|
const addonList = list.filter((p) => p.duration == null);
|
|
@@ -695,6 +788,10 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
695
788
|
}
|
|
696
789
|
}
|
|
697
790
|
async loadVenueProducts() {
|
|
791
|
+
this.logPricingDiagnostics("[VenueBooking] loadVenueProducts called", {
|
|
792
|
+
hasLoadAllProductsInFlight: !!this.loadAllProductsInFlight,
|
|
793
|
+
productsLoaded: this.productsLoaded
|
|
794
|
+
});
|
|
698
795
|
const result = await this.loadAllProducts();
|
|
699
796
|
return result.venueProducts;
|
|
700
797
|
}
|
|
@@ -1707,6 +1804,11 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1707
1804
|
}
|
|
1708
1805
|
async getProductList() {
|
|
1709
1806
|
if (this.productsLoaded) {
|
|
1807
|
+
this.logPricingDiagnostics("[VenueBooking] getProductList loadAllProducts skipped", {
|
|
1808
|
+
reason: "productsLoaded is true",
|
|
1809
|
+
addonProductCount: this.getAddonProductsList().length,
|
|
1810
|
+
smartPricingProductCatalogCount: this.smartPricingProductCatalog.length
|
|
1811
|
+
});
|
|
1710
1812
|
return (0, import_utils.attachItemRuleLimitsToTopLevelProducts)(
|
|
1711
1813
|
this.getAddonProductsList(),
|
|
1712
1814
|
this.store.itemRuleQuantityLimits || []
|
|
@@ -2086,6 +2188,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
2086
2188
|
}
|
|
2087
2189
|
};
|
|
2088
2190
|
var VenueBookingImpl = _VenueBookingImpl;
|
|
2191
|
+
VenueBookingImpl.PRICING_DEBUG_CACHE_ID = "031596279011848516";
|
|
2089
2192
|
VenueBookingImpl.OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
|
|
2090
2193
|
VenueBookingImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
|
|
2091
2194
|
// ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
|
|
@@ -16,6 +16,7 @@ export interface VenueBookingSmartPricingContext {
|
|
|
16
16
|
orderType?: string;
|
|
17
17
|
strategy_context?: Record<string, any>;
|
|
18
18
|
strategyConfigs?: StrategyConfig[];
|
|
19
|
+
debugLog?: (title: string, payload?: Record<string, any>) => void;
|
|
19
20
|
}
|
|
20
21
|
/** 从商品上读取展示/算价用的 price 字段 */
|
|
21
22
|
export declare function extractProductPrice(product: DataVariantProduct): string | null;
|