@pisell/pisellos 2.1.163 → 2.1.165
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/index.d.ts +0 -1
- package/dist/index.js +0 -3
- package/dist/model/strategy/adapter/index.d.ts +0 -4
- package/dist/model/strategy/adapter/index.js +1 -5
- package/dist/modules/Discount/index.d.ts +2 -5
- package/dist/modules/Discount/index.js +1 -21
- package/dist/modules/Discount/types.d.ts +0 -4
- package/dist/modules/Order/index.d.ts +0 -1
- package/dist/modules/Order/index.js +6 -18
- package/dist/modules/Order/types.d.ts +0 -2
- package/dist/modules/ProductList/index.d.ts +1 -3
- package/dist/modules/ProductList/index.js +11 -22
- package/dist/modules/Schedule/getDateIsInSchedule.js +0 -5
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/ScanOrder/index.js +1 -1
- package/dist/solution/ShopDiscount/index.js +15 -16
- package/dist/solution/VenueBooking/index.d.ts +8 -23
- package/dist/solution/VenueBooking/index.js +476 -528
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +9 -3
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -3
- package/lib/model/strategy/adapter/index.d.ts +0 -4
- package/lib/model/strategy/adapter/index.js +2 -13
- package/lib/model/strategy/adapter/promotion/index.js +49 -0
- package/lib/modules/Discount/index.d.ts +2 -5
- package/lib/modules/Discount/index.js +1 -11
- package/lib/modules/Discount/types.d.ts +0 -4
- package/lib/modules/Order/index.d.ts +0 -1
- package/lib/modules/Order/index.js +1 -11
- package/lib/modules/Order/types.d.ts +0 -2
- package/lib/modules/ProductList/index.d.ts +1 -3
- package/lib/modules/ProductList/index.js +39 -45
- package/lib/modules/Schedule/getDateIsInSchedule.js +0 -4
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/ScanOrder/index.js +1 -1
- package/lib/solution/ShopDiscount/index.js +2 -3
- package/lib/solution/VenueBooking/index.d.ts +8 -23
- package/lib/solution/VenueBooking/index.js +87 -164
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/lib/solution/VenueBooking/utils/dateSummary.js +10 -5
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +4 -3
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/lib/solution/VenueBooking/utils/timeSlot.js +3 -7
- package/package.json +1 -1
- package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
- package/dist/model/strategy/adapter/dataVariant/adapter.js +0 -167
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +0 -780
- package/dist/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
- package/dist/model/strategy/adapter/dataVariant/examples.js +0 -277
- package/dist/model/strategy/adapter/dataVariant/index.d.ts +0 -4
- package/dist/model/strategy/adapter/dataVariant/index.js +0 -4
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +0 -148
- package/dist/model/strategy/adapter/dataVariant/type.js +0 -54
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
- package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
- package/lib/model/strategy/adapter/dataVariant/adapter.js +0 -149
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +0 -583
- package/lib/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
- package/lib/model/strategy/adapter/dataVariant/examples.js +0 -293
- package/lib/model/strategy/adapter/dataVariant/index.d.ts +0 -4
- package/lib/model/strategy/adapter/dataVariant/index.js +0 -38
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +0 -148
- package/lib/model/strategy/adapter/dataVariant/type.js +0 -31
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/lib/solution/VenueBooking/utils/smartPricing.js +0 -180
|
@@ -3,7 +3,6 @@ import { BaseModule } from '../../modules/BaseModule';
|
|
|
3
3
|
import { VenueBookingAddLogParams, VenueBookingSlotConfig, VenueDateSummaryItem, VenueSlotSelection, VenueTimeSlotGrid } from './types';
|
|
4
4
|
import type { ScanOrderOrderProduct, ScanOrderOrderProductIdentity } from '../ScanOrder/types';
|
|
5
5
|
import type { UpdateProductInOrderParams } from '../../modules/Order/types';
|
|
6
|
-
import type { ScheduleItem } from '../../modules/Schedule/types';
|
|
7
6
|
import type { OpenDataAvailabilityResult } from '../../modules/OpenData';
|
|
8
7
|
import type { ProductData } from '../../modules/Product/types';
|
|
9
8
|
import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
@@ -41,10 +40,6 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
41
40
|
private productsLoaded;
|
|
42
41
|
private loadOpenDataConfigInFlight;
|
|
43
42
|
private static readonly OPEN_DATA_CACHE_TTL;
|
|
44
|
-
/** 按日期缓存 slot 智能定价 Map,避免同周重复 resolveProducts */
|
|
45
|
-
private slotPriceMapCache;
|
|
46
|
-
/** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
|
|
47
|
-
private smartPricingProductCatalog;
|
|
48
43
|
private getLoggerContext;
|
|
49
44
|
private safeStringify;
|
|
50
45
|
private pickErrorMessage;
|
|
@@ -73,22 +68,6 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
73
68
|
passed: boolean | null;
|
|
74
69
|
failures: QuantityCheckResult[];
|
|
75
70
|
};
|
|
76
|
-
/** 清除 slot 价格分段缓存(商品重载 / 登录后 customerId 变化时调用) */
|
|
77
|
-
private clearSlotPriceMapCache;
|
|
78
|
-
/** 读取当前登录 customerId */
|
|
79
|
-
private resolveCustomerIdForSmartPricing;
|
|
80
|
-
private resolveAvailableWalletIdsForSmartPricing;
|
|
81
|
-
/** 读取 schedule 全量列表,供智能定价 schedule_match 使用 */
|
|
82
|
-
private getScheduleListForSmartPricing;
|
|
83
|
-
/** 构建智能定价上下文,对齐 OS Server buildProductFormatterContext */
|
|
84
|
-
private buildSmartPricingContext;
|
|
85
|
-
/** venue + addon 全量商品,供智能定价评估 */
|
|
86
|
-
private getAllProductsForSmartPricing;
|
|
87
|
-
private getSlotPriceMapCacheKey;
|
|
88
|
-
/**
|
|
89
|
-
* 按 schedule 分段构建 slot 价格 Map,带实例级缓存。
|
|
90
|
-
*/
|
|
91
|
-
private buildSlotPriceMapForDate;
|
|
92
71
|
loadAllProducts(): Promise<{
|
|
93
72
|
venueProducts: ProductData[];
|
|
94
73
|
addonProducts: ProductData[];
|
|
@@ -161,7 +140,8 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
161
140
|
setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
|
|
162
141
|
getSlotConfig(): VenueBookingSlotConfig;
|
|
163
142
|
loadSchedules(): Promise<void>;
|
|
164
|
-
|
|
143
|
+
private injectScheduleResolverToQuotation;
|
|
144
|
+
getScheduleListByIds(ids: number[]): import("../../modules/Schedule/types").ScheduleItem[];
|
|
165
145
|
getTempOrder(): import("./types").ScanOrderTempOrder | null;
|
|
166
146
|
updateTempOrderNote(note: string): string;
|
|
167
147
|
updateTempOrderContactsInfo(contactsInfo: any[]): any[];
|
|
@@ -169,7 +149,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
169
149
|
onCustomerLogin(params: {
|
|
170
150
|
customerId: number;
|
|
171
151
|
}): Promise<void>;
|
|
172
|
-
private
|
|
152
|
+
private recalculateOrderPricesFromQuotation;
|
|
173
153
|
scanCode(code: string, customerId?: number): Promise<{
|
|
174
154
|
isAvailable: boolean;
|
|
175
155
|
discountList: import("../../modules/Discount").Discount[];
|
|
@@ -188,6 +168,11 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
188
168
|
getOrderProducts(): ScanOrderOrderProduct[];
|
|
189
169
|
getSummary(): Promise<import("./types").ScanOrderSummary>;
|
|
190
170
|
submitOrder<T = any>(): Promise<T>;
|
|
171
|
+
/**
|
|
172
|
+
* 0 元订单免费领取(非定金场景)
|
|
173
|
+
* 与 appointment getFreeProduct 同接口:POST /pay/order/free-pay/:id
|
|
174
|
+
*/
|
|
175
|
+
submitFreeOrder(id: string | number): Promise<any>;
|
|
191
176
|
addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
192
177
|
updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
|
|
193
178
|
removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
@@ -50,7 +50,6 @@ var import_resource = require("./utils/resource");
|
|
|
50
50
|
var import_timeSlot = require("./utils/timeSlot");
|
|
51
51
|
var import_dateSummary = require("./utils/dateSummary");
|
|
52
52
|
var import_slotMerge = require("./utils/slotMerge");
|
|
53
|
-
var import_smartPricing = require("./utils/smartPricing");
|
|
54
53
|
var import_utils3 = require("../../modules/Order/utils");
|
|
55
54
|
var import_Order = require("../../modules/Order");
|
|
56
55
|
var import_types4 = require("../RegisterAndLogin/types");
|
|
@@ -111,10 +110,6 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
111
110
|
this.loadAllProductsInFlight = null;
|
|
112
111
|
this.productsLoaded = false;
|
|
113
112
|
this.loadOpenDataConfigInFlight = null;
|
|
114
|
-
/** 按日期缓存 slot 智能定价 Map,避免同周重复 resolveProducts */
|
|
115
|
-
this.slotPriceMapCache = /* @__PURE__ */ new Map();
|
|
116
|
-
/** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
|
|
117
|
-
this.smartPricingProductCatalog = [];
|
|
118
113
|
}
|
|
119
114
|
getLoggerContext() {
|
|
120
115
|
return {
|
|
@@ -303,11 +298,16 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
303
298
|
}
|
|
304
299
|
this.customerLoginRefreshIdInFlight = params.customerId;
|
|
305
300
|
const refreshTask = (async () => {
|
|
301
|
+
var _a;
|
|
302
|
+
if (this.store.quotation) {
|
|
303
|
+
await this.store.quotation.loadQuotations({
|
|
304
|
+
channel: (_a = this.otherParams) == null ? void 0 : _a.channel
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
this.recalculateOrderPricesFromQuotation();
|
|
306
308
|
await this.store.order.loadDiscountConfig({
|
|
307
309
|
customerId: params.customerId
|
|
308
310
|
});
|
|
309
|
-
this.clearSlotPriceMapCache();
|
|
310
|
-
this.recalculateOrderPricesFromSmartPricing();
|
|
311
311
|
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
312
312
|
this.store.order.persistTempOrder();
|
|
313
313
|
await this.refreshItemRuleQuantityLimits();
|
|
@@ -326,7 +326,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
async initialize(core, options = {}) {
|
|
329
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
329
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
330
330
|
this.logMethodStart("initialize");
|
|
331
331
|
this.core = core;
|
|
332
332
|
this.initializeOptions = options || {};
|
|
@@ -462,6 +462,10 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
462
462
|
await this.loadRuntimeConfigs();
|
|
463
463
|
if (this.store.schedule) {
|
|
464
464
|
await this.store.schedule.loadAllSchedule();
|
|
465
|
+
this.injectScheduleResolverToQuotation();
|
|
466
|
+
(_k = this.store.quotation) == null ? void 0 : _k.loadQuotations({
|
|
467
|
+
channel: (_j = this.otherParams) == null ? void 0 : _j.channel
|
|
468
|
+
});
|
|
465
469
|
}
|
|
466
470
|
await this.refreshItemRuleQuantityLimits();
|
|
467
471
|
this.store.status = "ready";
|
|
@@ -537,93 +541,6 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
537
541
|
getCartValidation() {
|
|
538
542
|
return this.store.cartValidation || { passed: null, failures: [] };
|
|
539
543
|
}
|
|
540
|
-
/** 清除 slot 价格分段缓存(商品重载 / 登录后 customerId 变化时调用) */
|
|
541
|
-
clearSlotPriceMapCache() {
|
|
542
|
-
this.slotPriceMapCache.clear();
|
|
543
|
-
}
|
|
544
|
-
/** 读取当前登录 customerId */
|
|
545
|
-
resolveCustomerIdForSmartPricing() {
|
|
546
|
-
var _a, _b, _c;
|
|
547
|
-
try {
|
|
548
|
-
const userPlugin = (_a = this.core) == null ? void 0 : _a.getPlugin("user");
|
|
549
|
-
const customerId = Number((_c = (_b = userPlugin == null ? void 0 : userPlugin.get) == null ? void 0 : _b.call(userPlugin)) == null ? void 0 : _c.id);
|
|
550
|
-
return Number.isFinite(customerId) && customerId > 0 ? customerId : void 0;
|
|
551
|
-
} catch {
|
|
552
|
-
return void 0;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
resolveAvailableWalletIdsForSmartPricing() {
|
|
556
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
557
|
-
const orderWalletIds = (_b = (_a = this.store.order) == null ? void 0 : _a.getAvailableWalletIds) == null ? void 0 : _b.call(_a);
|
|
558
|
-
const fallbackWalletIds = ((_c = this.otherParams) == null ? void 0 : _c.available_wallet_ids) || ((_d = this.otherParams) == null ? void 0 : _d.availableWalletIds) || ((_f = (_e = this.otherParams) == null ? void 0 : _e.strategy_context) == null ? void 0 : _f.available_wallet_ids) || ((_h = (_g = this.otherParams) == null ? void 0 : _g.strategy_context) == null ? void 0 : _h.availableWalletIds);
|
|
559
|
-
const source = Array.isArray(orderWalletIds) && orderWalletIds.length ? orderWalletIds : fallbackWalletIds;
|
|
560
|
-
if (!Array.isArray(source))
|
|
561
|
-
return [];
|
|
562
|
-
const ids = source.map((item) => Number(item)).filter((item) => Number.isFinite(item) && item > 0);
|
|
563
|
-
return Array.from(new Set(ids));
|
|
564
|
-
}
|
|
565
|
-
/** 读取 schedule 全量列表,供智能定价 schedule_match 使用 */
|
|
566
|
-
getScheduleListForSmartPricing() {
|
|
567
|
-
var _a;
|
|
568
|
-
const scheduleModule = this.store.schedule;
|
|
569
|
-
const list = (_a = scheduleModule == null ? void 0 : scheduleModule.store) == null ? void 0 : _a.scheduleList;
|
|
570
|
-
return Array.isArray(list) ? list : [];
|
|
571
|
-
}
|
|
572
|
-
/** 构建智能定价上下文,对齐 OS Server buildProductFormatterContext */
|
|
573
|
-
buildSmartPricingContext(customerId) {
|
|
574
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
575
|
-
const evaluator = (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.dataVariantEvaluator;
|
|
576
|
-
return {
|
|
577
|
-
evaluator,
|
|
578
|
-
scheduleList: this.getScheduleListForSmartPricing(),
|
|
579
|
-
menuList: ((_c = this.otherParams) == null ? void 0 : _c.menuList) || ((_e = (_d = this.otherParams) == null ? void 0 : _d.openData) == null ? void 0 : _e.menuList) || [],
|
|
580
|
-
customerId: customerId ?? this.resolveCustomerIdForSmartPricing(),
|
|
581
|
-
availableWalletIds: this.resolveAvailableWalletIdsForSmartPricing(),
|
|
582
|
-
channel: (_f = this.otherParams) == null ? void 0 : _f.channel,
|
|
583
|
-
businessCode: (_g = this.otherParams) == null ? void 0 : _g.businessCode,
|
|
584
|
-
orderType: ((_h = this.otherParams) == null ? void 0 : _h.orderType) || ((_i = this.otherParams) == null ? void 0 : _i.type),
|
|
585
|
-
strategy_context: (_j = this.otherParams) == null ? void 0 : _j.strategy_context
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
/** venue + addon 全量商品,供智能定价评估 */
|
|
589
|
-
getAllProductsForSmartPricing() {
|
|
590
|
-
if (this.smartPricingProductCatalog.length) {
|
|
591
|
-
return this.smartPricingProductCatalog;
|
|
592
|
-
}
|
|
593
|
-
const venueList = this.getVenueProducts();
|
|
594
|
-
const addonList = this.getAddonProductsList();
|
|
595
|
-
return [...venueList, ...addonList];
|
|
596
|
-
}
|
|
597
|
-
getSlotPriceMapCacheKey(date, context) {
|
|
598
|
-
return [
|
|
599
|
-
date,
|
|
600
|
-
context.customerId ?? "",
|
|
601
|
-
(context.availableWalletIds || []).join(","),
|
|
602
|
-
context.channel ?? "",
|
|
603
|
-
context.businessCode ?? ""
|
|
604
|
-
].join("|");
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* 按 schedule 分段构建 slot 价格 Map,带实例级缓存。
|
|
608
|
-
*/
|
|
609
|
-
buildSlotPriceMapForDate(date, config, productIds) {
|
|
610
|
-
const context = this.buildSmartPricingContext();
|
|
611
|
-
const cacheKey = this.getSlotPriceMapCacheKey(date, context);
|
|
612
|
-
const cached = this.slotPriceMapCache.get(cacheKey);
|
|
613
|
-
if (cached)
|
|
614
|
-
return cached;
|
|
615
|
-
const timeLabels = (0, import_timeSlot.generateTimeLabels)(config);
|
|
616
|
-
const slotPriceMap = (0, import_smartPricing.buildSlotPriceMapByScheduleSegments)({
|
|
617
|
-
products: this.getAllProductsForSmartPricing(),
|
|
618
|
-
productIds,
|
|
619
|
-
date,
|
|
620
|
-
timeLabels,
|
|
621
|
-
config,
|
|
622
|
-
context
|
|
623
|
-
});
|
|
624
|
-
this.slotPriceMapCache.set(cacheKey, slotPriceMap);
|
|
625
|
-
return slotPriceMap;
|
|
626
|
-
}
|
|
627
544
|
// ─── 场地商品 & 附加商品 ───
|
|
628
545
|
async loadAllProducts() {
|
|
629
546
|
if (this.loadAllProductsInFlight)
|
|
@@ -652,18 +569,9 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
652
569
|
menu_list_ids: menuListIds,
|
|
653
570
|
cacheId: this.cacheId,
|
|
654
571
|
schedule_date: (0, import_dayjs.default)().format("YYYY-MM-DD"),
|
|
655
|
-
schedule_datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
656
|
-
with_extra: ["dataVariants"]
|
|
572
|
+
schedule_datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
657
573
|
});
|
|
658
|
-
const
|
|
659
|
-
let list = rawList;
|
|
660
|
-
this.smartPricingProductCatalog = rawList.slice();
|
|
661
|
-
list = (0, import_smartPricing.formatProductsWithDataVariant)(
|
|
662
|
-
list,
|
|
663
|
-
this.buildSmartPricingContext(),
|
|
664
|
-
(0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
665
|
-
);
|
|
666
|
-
this.clearSlotPriceMapCache();
|
|
574
|
+
const list = Array.isArray(allProducts) ? allProducts : [];
|
|
667
575
|
const venueList = list.filter((p) => p.duration != null);
|
|
668
576
|
const addonList = list.filter((p) => p.duration == null);
|
|
669
577
|
const venueStore = (_c = this.store.venueProducts) == null ? void 0 : _c.store;
|
|
@@ -844,24 +752,29 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
844
752
|
config: this.baseSlotConfig,
|
|
845
753
|
rawResources: this.store.rawResourceData,
|
|
846
754
|
resourceProductMap: this.resourceProductMap,
|
|
847
|
-
|
|
848
|
-
|
|
755
|
+
quotationModule: this.store.quotation,
|
|
756
|
+
resolveConfig: (date) => this.resolveSlotConfigForDate(date)
|
|
849
757
|
});
|
|
850
758
|
}
|
|
851
759
|
getTimeSlotGrid(date) {
|
|
852
760
|
const resolvedSlotConfig = this.syncOperatingHoursToSlotConfig(date);
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
761
|
+
let quotationPriceMap;
|
|
762
|
+
if (this.store.quotation) {
|
|
763
|
+
const productIds = [
|
|
764
|
+
...new Set(
|
|
765
|
+
[...this.resourceProductMap.values()].flat().map((m) => m.productId)
|
|
766
|
+
)
|
|
767
|
+
];
|
|
768
|
+
const timeLabels = (0, import_timeSlot.generateTimeLabels)(resolvedSlotConfig);
|
|
769
|
+
const timePoints = timeLabels.map((label) => `${date} ${label}`);
|
|
770
|
+
quotationPriceMap = this.store.quotation.buildProductPriceMap({ productIds, timePoints });
|
|
771
|
+
}
|
|
859
772
|
return (0, import_timeSlot.buildTimeSlotGrid)({
|
|
860
773
|
date,
|
|
861
774
|
config: resolvedSlotConfig,
|
|
862
775
|
rawResources: this.store.rawResourceData,
|
|
863
776
|
resourceProductMap: this.resourceProductMap,
|
|
864
|
-
|
|
777
|
+
quotationPriceMap
|
|
865
778
|
});
|
|
866
779
|
}
|
|
867
780
|
// ─── 时间槽订单操作 ───
|
|
@@ -1146,7 +1059,8 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1146
1059
|
booking_uid: bookingUuid,
|
|
1147
1060
|
price_breakdown: (0, import_slotMerge.buildPriceBreakdown)({
|
|
1148
1061
|
group,
|
|
1149
|
-
productId: mapping.productId
|
|
1062
|
+
productId: mapping.productId,
|
|
1063
|
+
quotation: this.store.quotation
|
|
1150
1064
|
})
|
|
1151
1065
|
},
|
|
1152
1066
|
_origin: {
|
|
@@ -1239,12 +1153,20 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1239
1153
|
if (!this.store.schedule)
|
|
1240
1154
|
throw new Error("schedule 模块未初始化");
|
|
1241
1155
|
await this.store.schedule.loadAllSchedule();
|
|
1156
|
+
this.injectScheduleResolverToQuotation();
|
|
1242
1157
|
this.logMethodSuccess("loadSchedules");
|
|
1243
1158
|
} catch (error) {
|
|
1244
1159
|
this.logMethodError("loadSchedules", error);
|
|
1245
1160
|
throw error;
|
|
1246
1161
|
}
|
|
1247
1162
|
}
|
|
1163
|
+
injectScheduleResolverToQuotation() {
|
|
1164
|
+
if (this.store.quotation && this.store.schedule) {
|
|
1165
|
+
this.store.quotation.setScheduleResolver(
|
|
1166
|
+
(id) => this.store.schedule.getScheduleListByIds([id])[0]
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1248
1170
|
getScheduleListByIds(ids) {
|
|
1249
1171
|
if (!this.store.schedule)
|
|
1250
1172
|
return [];
|
|
@@ -1283,16 +1205,14 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1283
1205
|
throw error;
|
|
1284
1206
|
}
|
|
1285
1207
|
}
|
|
1286
|
-
|
|
1208
|
+
recalculateOrderPricesFromQuotation() {
|
|
1287
1209
|
var _a, _b;
|
|
1288
|
-
if (!this.store.order)
|
|
1210
|
+
if (!this.store.order || !this.store.quotation)
|
|
1289
1211
|
return;
|
|
1290
1212
|
const tempOrder = this.store.order.getTempOrder();
|
|
1291
1213
|
if (!((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length))
|
|
1292
1214
|
return;
|
|
1293
1215
|
const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
1294
|
-
const catalog = this.getAllProductsForSmartPricing();
|
|
1295
|
-
const context = this.buildSmartPricingContext();
|
|
1296
1216
|
for (const product of tempOrder.products) {
|
|
1297
1217
|
if ((_b = product.metadata) == null ? void 0 : _b.venue_booking) {
|
|
1298
1218
|
const mappings = this.resourceProductMap.get(product.metadata.resource_id);
|
|
@@ -1305,49 +1225,34 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1305
1225
|
product,
|
|
1306
1226
|
this.store.slotConfig.slotDurationMinutes
|
|
1307
1227
|
);
|
|
1308
|
-
const
|
|
1309
|
-
...
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
for (const slotDate of uniqueDates) {
|
|
1313
|
-
slotPriceMaps.set(
|
|
1314
|
-
slotDate,
|
|
1315
|
-
this.buildSlotPriceMapForDate(slotDate, this.store.slotConfig, [mapping.productId])
|
|
1316
|
-
);
|
|
1317
|
-
}
|
|
1318
|
-
const updatedSlots = slots.map((slot) => {
|
|
1319
|
-
const slotDate = (0, import_dayjs.default)(slot.startTime).format("YYYY-MM-DD");
|
|
1320
|
-
const slotPriceMap = slotPriceMaps.get(slotDate);
|
|
1321
|
-
return {
|
|
1322
|
-
...slot,
|
|
1228
|
+
const updatedSlots = slots.map((slot) => ({
|
|
1229
|
+
...slot,
|
|
1230
|
+
productId: mapping.productId,
|
|
1231
|
+
price: this.store.quotation.getPriceForProduct({
|
|
1323
1232
|
productId: mapping.productId,
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
slotStartTime: slot.startTime,
|
|
1328
|
-
fallbackPrice: mapping.price
|
|
1329
|
-
}) : mapping.price
|
|
1330
|
-
};
|
|
1331
|
-
});
|
|
1233
|
+
datetime: slot.startTime
|
|
1234
|
+
}) ?? mapping.price
|
|
1235
|
+
}));
|
|
1332
1236
|
const merged = (0, import_slotMerge.mergeConsecutiveSlots)(updatedSlots);
|
|
1333
1237
|
if (merged.length === 1) {
|
|
1334
1238
|
product.selling_price = merged[0].totalPrice;
|
|
1335
1239
|
product.original_price = merged[0].totalPrice;
|
|
1336
1240
|
product.metadata.price_breakdown = (0, import_slotMerge.buildPriceBreakdown)({
|
|
1337
1241
|
group: merged[0],
|
|
1338
|
-
productId: mapping.productId
|
|
1242
|
+
productId: mapping.productId,
|
|
1243
|
+
quotation: this.store.quotation
|
|
1339
1244
|
});
|
|
1340
1245
|
}
|
|
1341
1246
|
} else if (product.product_id != null) {
|
|
1342
|
-
const
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
datetime: now,
|
|
1347
|
-
fallbackPrice: product.selling_price
|
|
1247
|
+
const quotationPrice = this.store.quotation.getPriceForProduct({
|
|
1248
|
+
productId: product.product_id,
|
|
1249
|
+
variantId: product.product_variant_id ?? void 0,
|
|
1250
|
+
datetime: now
|
|
1348
1251
|
});
|
|
1349
|
-
|
|
1350
|
-
|
|
1252
|
+
if (quotationPrice !== null) {
|
|
1253
|
+
product.selling_price = quotationPrice;
|
|
1254
|
+
product.original_price = quotationPrice;
|
|
1255
|
+
}
|
|
1351
1256
|
}
|
|
1352
1257
|
}
|
|
1353
1258
|
}
|
|
@@ -1532,8 +1437,26 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1532
1437
|
throw error;
|
|
1533
1438
|
}
|
|
1534
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* 0 元订单免费领取(非定金场景)
|
|
1442
|
+
* 与 appointment getFreeProduct 同接口:POST /pay/order/free-pay/:id
|
|
1443
|
+
*/
|
|
1444
|
+
async submitFreeOrder(id) {
|
|
1445
|
+
this.logMethodStart("submitFreeOrder", { id });
|
|
1446
|
+
try {
|
|
1447
|
+
if (!id) {
|
|
1448
|
+
throw new Error("订单 ID 不能为空");
|
|
1449
|
+
}
|
|
1450
|
+
const res = await this.request.post(`/pay/order/free-pay/${id}`);
|
|
1451
|
+
this.logMethodSuccess("submitFreeOrder", { id, status: res == null ? void 0 : res.status });
|
|
1452
|
+
return res;
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
this.logMethodError("submitFreeOrder", error);
|
|
1455
|
+
throw error;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1535
1458
|
async addProductToOrder(product) {
|
|
1536
|
-
var _a
|
|
1459
|
+
var _a;
|
|
1537
1460
|
this.logMethodStart("addProductToOrder", {
|
|
1538
1461
|
product_id: product.product_id,
|
|
1539
1462
|
product_variant_id: product.product_variant_id
|
|
@@ -1541,18 +1464,18 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
|
|
|
1541
1464
|
try {
|
|
1542
1465
|
if (!this.store.order)
|
|
1543
1466
|
throw new Error("order 模块未初始化");
|
|
1544
|
-
if (!((_a = product.metadata) == null ? void 0 : _a.venue_booking) && product.product_id != null) {
|
|
1545
|
-
const
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss"),
|
|
1550
|
-
fallbackPrice: product.selling_price
|
|
1467
|
+
if (!((_a = product.metadata) == null ? void 0 : _a.venue_booking) && this.store.quotation && product.product_id != null) {
|
|
1468
|
+
const quotationPrice = this.store.quotation.getPriceForProduct({
|
|
1469
|
+
productId: product.product_id,
|
|
1470
|
+
variantId: product.product_variant_id ?? void 0,
|
|
1471
|
+
datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
1551
1472
|
});
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1473
|
+
if (quotationPrice !== null) {
|
|
1474
|
+
product.selling_price = quotationPrice;
|
|
1475
|
+
product.original_price = quotationPrice;
|
|
1476
|
+
} else if (product.selling_price != null) {
|
|
1477
|
+
product.original_price = product.selling_price;
|
|
1478
|
+
}
|
|
1556
1479
|
}
|
|
1557
1480
|
const products = await this.store.order.addProductToOrder(product);
|
|
1558
1481
|
await this.refreshItemRuleQuantityLimits();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { VenueBookingSlotConfig, VenueResourceRawData, VenueDateSummaryItem, ResourceProductMapping } from '../types';
|
|
2
|
+
import type { QuotationModule } from '../../../modules/Quotation';
|
|
2
3
|
export declare function buildDateRangeSummary(params: {
|
|
3
4
|
startDate: string;
|
|
4
5
|
endDate: string;
|
|
5
6
|
config: VenueBookingSlotConfig;
|
|
6
7
|
rawResources: VenueResourceRawData[];
|
|
7
8
|
resourceProductMap: Map<number | string, ResourceProductMapping[]>;
|
|
9
|
+
quotationModule?: QuotationModule;
|
|
8
10
|
resolveConfig?: (date: string) => VenueBookingSlotConfig;
|
|
9
|
-
/** 按日期构建 slot 智能定价 Map */
|
|
10
|
-
buildSlotPriceMap?: (date: string, config: VenueBookingSlotConfig, productIds: number[]) => Map<string, string | null>;
|
|
11
11
|
}): VenueDateSummaryItem[];
|
|
@@ -41,23 +41,28 @@ function buildDateRangeSummary(params) {
|
|
|
41
41
|
config,
|
|
42
42
|
rawResources,
|
|
43
43
|
resourceProductMap,
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
quotationModule,
|
|
45
|
+
resolveConfig
|
|
46
46
|
} = params;
|
|
47
47
|
const result = [];
|
|
48
|
-
const productIds =
|
|
48
|
+
const productIds = quotationModule ? [...new Set([...resourceProductMap.values()].flat().map((m) => m.productId))] : [];
|
|
49
49
|
let cursor = (0, import_dayjs.default)(startDate);
|
|
50
50
|
const end = (0, import_dayjs.default)(endDate);
|
|
51
51
|
while (!cursor.isAfter(end)) {
|
|
52
52
|
const date = cursor.format("YYYY-MM-DD");
|
|
53
53
|
const effectiveConfig = (resolveConfig == null ? void 0 : resolveConfig(date)) || config;
|
|
54
|
-
|
|
54
|
+
let quotationPriceMap;
|
|
55
|
+
if (quotationModule && productIds.length) {
|
|
56
|
+
const timeLabels = (0, import_timeSlot.generateTimeLabels)(effectiveConfig);
|
|
57
|
+
const timePoints = timeLabels.map((label) => `${date} ${label}`);
|
|
58
|
+
quotationPriceMap = quotationModule.buildProductPriceMap({ productIds, timePoints });
|
|
59
|
+
}
|
|
55
60
|
const grid = (0, import_timeSlot.buildTimeSlotGrid)({
|
|
56
61
|
date,
|
|
57
62
|
config: effectiveConfig,
|
|
58
63
|
rawResources,
|
|
59
64
|
resourceProductMap,
|
|
60
|
-
|
|
65
|
+
quotationPriceMap
|
|
61
66
|
});
|
|
62
67
|
let totalSlots = 0;
|
|
63
68
|
let availableSlots = 0;
|
|
@@ -5,6 +5,12 @@ export declare function mergeConsecutiveSlots(slots: VenueSlotSelection[]): Merg
|
|
|
5
5
|
export declare function buildPriceBreakdown(params: {
|
|
6
6
|
group: MergedSlotGroup;
|
|
7
7
|
productId: number;
|
|
8
|
+
quotation?: {
|
|
9
|
+
getQuotationShelfId: (p: {
|
|
10
|
+
productId: number;
|
|
11
|
+
datetime: string;
|
|
12
|
+
}) => number;
|
|
13
|
+
};
|
|
8
14
|
}): PriceBreakdownEntry[];
|
|
9
15
|
export interface BuildVenueBookingParams {
|
|
10
16
|
group: MergedSlotGroup;
|
|
@@ -82,16 +82,17 @@ function mergeConsecutiveSlots(slots) {
|
|
|
82
82
|
return groups;
|
|
83
83
|
}
|
|
84
84
|
function buildPriceBreakdown(params) {
|
|
85
|
-
const { group } = params;
|
|
85
|
+
const { group, productId, quotation } = params;
|
|
86
86
|
if (!group.slots.length)
|
|
87
87
|
return [];
|
|
88
88
|
const entries = [];
|
|
89
89
|
for (const slot of group.slots) {
|
|
90
90
|
const unitPrice = Number(slot.price || "0");
|
|
91
|
+
const shelfId = quotation ? quotation.getQuotationShelfId({ productId, datetime: slot.startTime }) : 0;
|
|
91
92
|
const startHm = (0, import_dayjs.default)(slot.startTime, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD HH:mm");
|
|
92
93
|
const endHm = (0, import_dayjs.default)(slot.endTime, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD HH:mm");
|
|
93
94
|
const last = entries[entries.length - 1];
|
|
94
|
-
if (last && last.unit_price === unitPrice && last.quotation_shelf_id ===
|
|
95
|
+
if (last && last.unit_price === unitPrice && last.quotation_shelf_id === shelfId && last.end_time === startHm) {
|
|
95
96
|
last.end_time = endHm;
|
|
96
97
|
last.quantity += 1;
|
|
97
98
|
} else {
|
|
@@ -99,7 +100,7 @@ function buildPriceBreakdown(params) {
|
|
|
99
100
|
start_time: startHm,
|
|
100
101
|
end_time: endHm,
|
|
101
102
|
unit_price: unitPrice,
|
|
102
|
-
quotation_shelf_id:
|
|
103
|
+
quotation_shelf_id: shelfId,
|
|
103
104
|
quantity: 1
|
|
104
105
|
});
|
|
105
106
|
}
|
|
@@ -27,8 +27,6 @@ export declare function buildTimeSlotGrid(params: {
|
|
|
27
27
|
config: VenueBookingSlotConfig;
|
|
28
28
|
rawResources: VenueResourceRawData[];
|
|
29
29
|
resourceProductMap: Map<number | string, ResourceProductMapping[]>;
|
|
30
|
-
/** @deprecated 使用 slotPriceMap */
|
|
31
30
|
quotationPriceMap?: Map<string, string | null>;
|
|
32
|
-
slotPriceMap?: Map<string, string | null>;
|
|
33
31
|
}): VenueTimeSlotGrid;
|
|
34
32
|
export {};
|
|
@@ -168,7 +168,6 @@ function buildProductSlots(params) {
|
|
|
168
168
|
now,
|
|
169
169
|
crossDay,
|
|
170
170
|
quotationPriceMap,
|
|
171
|
-
slotPriceMap,
|
|
172
171
|
childRawResources,
|
|
173
172
|
childTimesCache,
|
|
174
173
|
childEventsCache,
|
|
@@ -232,12 +231,11 @@ function buildProductSlots(params) {
|
|
|
232
231
|
}
|
|
233
232
|
const isBookable = status === "available" || status === "partially_occupied";
|
|
234
233
|
const slotStartStr = slotStart.format("YYYY-MM-DD HH:mm");
|
|
235
|
-
const resolvedPriceMap = slotPriceMap ?? quotationPriceMap;
|
|
236
234
|
slots.push({
|
|
237
235
|
startTime: slotStartStr,
|
|
238
236
|
endTime: slotEnd.format("YYYY-MM-DD HH:mm"),
|
|
239
237
|
status,
|
|
240
|
-
price: isBookable ? (
|
|
238
|
+
price: isBookable ? (quotationPriceMap == null ? void 0 : quotationPriceMap.get(`${mapping.productId}:${slotStartStr}`)) ?? mapping.price : null,
|
|
241
239
|
resourceId: resource.resourceId,
|
|
242
240
|
resourceFormId: resource.formId,
|
|
243
241
|
capacity: status === "past" || status === "unavailable" ? null : resCapacity,
|
|
@@ -248,8 +246,7 @@ function buildProductSlots(params) {
|
|
|
248
246
|
return slots;
|
|
249
247
|
}
|
|
250
248
|
function buildTimeSlotGrid(params) {
|
|
251
|
-
const { date, config, rawResources, resourceProductMap, quotationPriceMap
|
|
252
|
-
const resolvedPriceMap = slotPriceMap ?? quotationPriceMap;
|
|
249
|
+
const { date, config, rawResources, resourceProductMap, quotationPriceMap } = params;
|
|
253
250
|
const timeLabels = generateTimeLabels(config);
|
|
254
251
|
const now = (0, import_dayjs.default)();
|
|
255
252
|
const crossDay = isBusinessHoursCrossDay(config);
|
|
@@ -282,8 +279,7 @@ function buildTimeSlotGrid(params) {
|
|
|
282
279
|
resCapacity,
|
|
283
280
|
now,
|
|
284
281
|
crossDay,
|
|
285
|
-
quotationPriceMap
|
|
286
|
-
slotPriceMap: resolvedPriceMap,
|
|
282
|
+
quotationPriceMap,
|
|
287
283
|
childRawResources,
|
|
288
284
|
childTimesCache,
|
|
289
285
|
childEventsCache,
|
package/package.json
CHANGED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { EvaluationResult, RuntimeContext } from '../../type';
|
|
2
|
-
import type { BusinessAdapter } from '../type';
|
|
3
|
-
import type { DataVariantBusinessData, DataVariantProduct } from './type';
|
|
4
|
-
/**
|
|
5
|
-
* Data Variant 适配器。
|
|
6
|
-
*
|
|
7
|
-
* 负责把智能定价运行态数据转换为 StrategyEngine 能识别的 attributes。
|
|
8
|
-
*/
|
|
9
|
-
export declare class DataVariantAdapter implements BusinessAdapter {
|
|
10
|
-
name: string;
|
|
11
|
-
version: string;
|
|
12
|
-
/**
|
|
13
|
-
* 准备批量全局上下文。
|
|
14
|
-
*
|
|
15
|
-
* 这里只放不依赖单个商品的字段,用于预计算 schedule/channel/orderType 等条件。
|
|
16
|
-
*/
|
|
17
|
-
prepareContext(businessData: DataVariantBusinessData): RuntimeContext;
|
|
18
|
-
/**
|
|
19
|
-
* 准备全局预计算上下文。
|
|
20
|
-
*/
|
|
21
|
-
prepareGlobalContext(businessData: DataVariantBusinessData): RuntimeContext;
|
|
22
|
-
/**
|
|
23
|
-
* 准备单商品上下文。
|
|
24
|
-
*
|
|
25
|
-
* 商品级条件只在当前商品 data_variants 引用到对应规则后才评估。
|
|
26
|
-
*/
|
|
27
|
-
prepareProductContext(businessData: DataVariantBusinessData, product: DataVariantProduct): RuntimeContext;
|
|
28
|
-
transformResult(result: EvaluationResult): EvaluationResult;
|
|
29
|
-
formatConfig(result: EvaluationResult, businessData?: DataVariantBusinessData): {
|
|
30
|
-
result: EvaluationResult;
|
|
31
|
-
businessData?: DataVariantBusinessData;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* 构建 menu_match 使用的轻量商品对象。
|
|
35
|
-
*
|
|
36
|
-
* collection_ids 来自商品 collection 字段,避免 operator 读取复杂商品对象。
|
|
37
|
-
*/
|
|
38
|
-
buildProductValue(product: DataVariantProduct): {
|
|
39
|
-
id: number;
|
|
40
|
-
product_variant_id: number;
|
|
41
|
-
collection_ids: number[];
|
|
42
|
-
};
|
|
43
|
-
private toNumber;
|
|
44
|
-
/**
|
|
45
|
-
* 归一化客户 id:无效值返回 undefined,有效值统一为 number。
|
|
46
|
-
*/
|
|
47
|
-
private normalizeCustomerId;
|
|
48
|
-
private normalizeNumberArray;
|
|
49
|
-
}
|
|
50
|
-
export default DataVariantAdapter;
|