@pisell/pisellos 2.2.233 → 2.2.234
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/modules/Order/index.d.ts +36 -1
- package/dist/modules/Order/index.js +496 -308
- package/dist/modules/Order/types.d.ts +11 -0
- package/dist/modules/Order/utils.d.ts +1 -0
- package/dist/modules/Order/utils.js +1 -1
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +855 -633
- package/dist/server/modules/order/index.d.ts +2 -0
- package/dist/server/modules/order/index.js +86 -32
- package/dist/solution/BaseSales/index.d.ts +6 -0
- package/dist/solution/BaseSales/index.js +240 -197
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +38 -2
- package/dist/solution/BookingTicket/index.js +642 -313
- package/dist/solution/BookingTicket/types.d.ts +62 -0
- package/dist/solution/BookingTicket/types.js +30 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/dist/solution/BookingTicket/utils/cartView.js +76 -5
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +9 -13
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +42 -33
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/Order/index.d.ts +36 -1
- package/lib/modules/Order/index.js +98 -10
- package/lib/modules/Order/types.d.ts +11 -0
- package/lib/modules/Order/utils.d.ts +1 -0
- package/lib/modules/Order/utils.js +1 -1
- package/lib/server/index.d.ts +5 -0
- package/lib/server/index.js +224 -63
- package/lib/server/modules/order/index.d.ts +2 -0
- package/lib/server/modules/order/index.js +43 -1
- package/lib/solution/BaseSales/index.d.ts +6 -0
- package/lib/solution/BaseSales/index.js +20 -1
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +38 -2
- package/lib/solution/BookingTicket/index.js +194 -3
- package/lib/solution/BookingTicket/types.d.ts +62 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
- package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/lib/solution/BookingTicket/utils/cartView.js +48 -2
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +9 -13
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +41 -28
- package/package.json +1 -1
|
@@ -1279,13 +1279,13 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1279
1279
|
throw new Error("BaseSales 解决方案需要 order 模块支持");
|
|
1280
1280
|
}
|
|
1281
1281
|
const inferredPaymentStatus = this.getSubmitPaymentStatus(params == null ? void 0 : params.paymentStatus);
|
|
1282
|
-
debugger;
|
|
1283
1282
|
const submitParams = {
|
|
1284
1283
|
cacheId: this.cacheId,
|
|
1285
1284
|
platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
|
|
1286
1285
|
businessCode: ((_b = this.otherParams) == null ? void 0 : _b.businessCode) || ((_c = this.otherParams) == null ? void 0 : _c.business_code),
|
|
1287
1286
|
channel: this.getSubmitOrderSalesChannel(),
|
|
1288
1287
|
type: (_d = this.otherParams) == null ? void 0 : _d.type,
|
|
1288
|
+
request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
|
|
1289
1289
|
...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
|
|
1290
1290
|
...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
|
|
1291
1291
|
...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
|
|
@@ -1293,6 +1293,25 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1293
1293
|
};
|
|
1294
1294
|
return this.store.order.submitTempOrder(submitParams);
|
|
1295
1295
|
}
|
|
1296
|
+
async submitTempOrderAsync(params) {
|
|
1297
|
+
var _a, _b, _c, _d;
|
|
1298
|
+
if (!this.store.order) {
|
|
1299
|
+
throw new Error("BaseSales 解决方案需要 order 模块支持");
|
|
1300
|
+
}
|
|
1301
|
+
const inferredPaymentStatus = this.getSubmitPaymentStatus(params == null ? void 0 : params.paymentStatus);
|
|
1302
|
+
const submitParams = {
|
|
1303
|
+
cacheId: this.cacheId,
|
|
1304
|
+
platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
|
|
1305
|
+
businessCode: ((_b = this.otherParams) == null ? void 0 : _b.businessCode) || ((_c = this.otherParams) == null ? void 0 : _c.business_code),
|
|
1306
|
+
channel: this.getSubmitOrderSalesChannel(),
|
|
1307
|
+
type: (_d = this.otherParams) == null ? void 0 : _d.type,
|
|
1308
|
+
...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
|
|
1309
|
+
...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
|
|
1310
|
+
...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
|
|
1311
|
+
...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
|
|
1312
|
+
};
|
|
1313
|
+
return this.store.order.submitTempOrderAsync(submitParams);
|
|
1314
|
+
}
|
|
1296
1315
|
async printLocalOrderReceipt(lookup) {
|
|
1297
1316
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1298
1317
|
if (!this.store.order) {
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 2 | 1 | 5 | 3 | 4 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import { BookingTicketCartView, BookingTicketProductCatalogView, BookingTicketState, IGetCustomerListParams, ICustomer, ILoadProductsParams, ILoadProductDetailParams, IScanResult } from './types';
|
|
3
3
|
import type { ProductData } from '../../modules';
|
|
4
|
+
import type { OpenDataConfig } from '../../modules/OpenData';
|
|
4
5
|
import { type BookingContextConfig, type BookingContextDateInput, type BookingContextResource, type BookingContextResourceMap, type BookingContextState, type InitBookingContextParams, type LoadBookingConfigParams, type LoadBookingResourcesParams, type ResourceError, type BookingCalcContext } from '../../modules/BookingContext';
|
|
5
6
|
import type { OrderCustomerView } from '../../modules/Order/types';
|
|
6
7
|
import { BaseSalesImpl } from '../BaseSales';
|
|
7
8
|
import type { BaseSalesScanCodeResult } from '../BaseSales/types';
|
|
8
9
|
import type { ISalesDetail } from '../BaseSales/utils/parseSalesResponse';
|
|
9
10
|
import type { LoadSalesDetailParams } from '../../modules/Order/types';
|
|
10
|
-
import type { GlobalScanHandleResult, GlobalScanHostBridge } from './types';
|
|
11
|
+
import type { AddAddTimeProductToBookingInput, AddAddTimeProductsToBookingInput, GlobalScanHandleResult, GlobalScanHostBridge } from './types';
|
|
11
12
|
import { AddProductDecideContext, AddProductRequiresDetailPayload } from './utils/addProductDecision';
|
|
12
13
|
import { type BuildCacheItemFromOrderLineInput } from '../../modules/BookingContext/utils/buildCacheItemFromOrderLine';
|
|
13
14
|
import { type BuildNormalProductCacheItemFromOrderLineInput } from '../../modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine';
|
|
@@ -25,6 +26,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
25
26
|
private platform;
|
|
26
27
|
private scan;
|
|
27
28
|
private productCatalog;
|
|
29
|
+
private addTimeProductsCatalog;
|
|
28
30
|
private orderCustomerDiscountRefreshInFlight;
|
|
29
31
|
private orderCustomerDiscountRefreshCustomerId;
|
|
30
32
|
private loadOpenDataConfigInFlight;
|
|
@@ -43,6 +45,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
43
45
|
private getBookingTicketBusinessCode;
|
|
44
46
|
private getIdGeneratorPlugin;
|
|
45
47
|
private loadOpenDataConfig;
|
|
48
|
+
getOpenData(): Promise<OpenDataConfig | null>;
|
|
46
49
|
private getShortNumberOrDeviceId;
|
|
47
50
|
private configureIdGeneratorFromOpenData;
|
|
48
51
|
private normalizePositiveInteger;
|
|
@@ -319,7 +322,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
319
322
|
* 获取当前的客户搜索条件
|
|
320
323
|
* @returns 当前搜索条件
|
|
321
324
|
*/
|
|
322
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
325
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
323
326
|
/**
|
|
324
327
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
325
328
|
* @returns 客户状态
|
|
@@ -512,6 +515,39 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
512
515
|
*/
|
|
513
516
|
handleGlobalScanCode(code: string, bridge?: GlobalScanHostBridge): Promise<GlobalScanHandleResult>;
|
|
514
517
|
resolveBestAddTimePlan(addTimeProducts: any[], targetMinutes: number): any;
|
|
518
|
+
/**
|
|
519
|
+
* 构造一条绑定到已有 booking 的加时商品行。
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* const line = this.buildAddTimeOrderLine({ product, product_add_schedule_time: 30 }, 'booking-1');
|
|
523
|
+
*/
|
|
524
|
+
private buildAddTimeOrderLine;
|
|
525
|
+
/**
|
|
526
|
+
* 将加时商品作为独立商品行绑定到已有 booking。
|
|
527
|
+
*
|
|
528
|
+
* 与预约商品加车不同,本方法不会把当前 booking 作为 `addProductToOrder` 第二参数传入,
|
|
529
|
+
* 避免 OrderModule 新建 booking 或重写已有 booking.product_uid。
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* await bookingTicket.addAddTimeProductToBooking({
|
|
533
|
+
* booking,
|
|
534
|
+
* product,
|
|
535
|
+
* num: 1,
|
|
536
|
+
* price: '10.00',
|
|
537
|
+
* product_add_schedule_time: 30,
|
|
538
|
+
* });
|
|
539
|
+
*/
|
|
540
|
+
addAddTimeProductToBooking(input: AddAddTimeProductToBookingInput): Promise<OrderProduct[]>;
|
|
541
|
+
/**
|
|
542
|
+
* 批量将加时商品作为独立商品行绑定到已有 booking,并只触发一次购物车重算。
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* await bookingTicket.addAddTimeProductsToBooking({
|
|
546
|
+
* booking,
|
|
547
|
+
* products: [{ product, product_add_schedule_time: 30 }],
|
|
548
|
+
* });
|
|
549
|
+
*/
|
|
550
|
+
addAddTimeProductsToBooking(input: AddAddTimeProductsToBookingInput): Promise<OrderProduct[]>;
|
|
515
551
|
/**
|
|
516
552
|
* 销毁模块:先调用父类(销毁所有 store 内子模块 + emit destroy + super.destroy()),
|
|
517
553
|
* 再清理 BookingTicket 自有资源(scan 监听 + scan 内存缓存)。
|
|
@@ -34,6 +34,7 @@ __export(BookingTicket_exports, {
|
|
|
34
34
|
BookingTicketImpl: () => BookingTicketImpl
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(BookingTicket_exports);
|
|
37
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
37
38
|
var import_types = require("./types");
|
|
38
39
|
var import_BookingContext = require("../../modules/BookingContext");
|
|
39
40
|
var import_BaseSales = require("../BaseSales");
|
|
@@ -54,6 +55,57 @@ var import_resolveBestAddTimePlan = require("./utils/resolveBestAddTimePlan");
|
|
|
54
55
|
__reExport(BookingTicket_exports, require("./types"), module.exports);
|
|
55
56
|
var OPEN_DATA_SECTION_CODES = ["sale", "reservation", "fulfillment", "menu", "workflow"];
|
|
56
57
|
var OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
|
|
58
|
+
function resolveBookingUidForAddTime(booking) {
|
|
59
|
+
var _a;
|
|
60
|
+
const uid = (_a = booking == null ? void 0 : booking.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
61
|
+
return uid === void 0 || uid === null ? "" : String(uid);
|
|
62
|
+
}
|
|
63
|
+
function normalizeAddTimeQuantity(value) {
|
|
64
|
+
const parsed = Math.floor(Number(value));
|
|
65
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
|
|
66
|
+
}
|
|
67
|
+
function resolveAddTimeScheduleMinutes(explicitValue, product) {
|
|
68
|
+
const raw = explicitValue ?? (product == null ? void 0 : product.product_add_schedule_time);
|
|
69
|
+
if (raw === void 0 || raw === null || raw === "")
|
|
70
|
+
return void 0;
|
|
71
|
+
const parsed = Number(raw);
|
|
72
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
73
|
+
}
|
|
74
|
+
function resolveAddTimeProductPrice(explicitValue, product) {
|
|
75
|
+
return explicitValue ?? (product == null ? void 0 : product.price) ?? (product == null ? void 0 : product.selling_price) ?? (product == null ? void 0 : product.base_price);
|
|
76
|
+
}
|
|
77
|
+
function normalizeCoveredMinutes(value) {
|
|
78
|
+
const parsed = Math.ceil(Number(value));
|
|
79
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
80
|
+
}
|
|
81
|
+
function buildAddTimeBookingTimePatch(booking, coveredMinutes) {
|
|
82
|
+
if (coveredMinutes <= 0)
|
|
83
|
+
return null;
|
|
84
|
+
const endDate = booking == null ? void 0 : booking.end_date;
|
|
85
|
+
const endTime = booking == null ? void 0 : booking.end_time;
|
|
86
|
+
if (!endDate || !endTime) {
|
|
87
|
+
throw new Error("[BookingTicket] addAddTimeProductsToBooking: booking.end_date/end_time 缺失");
|
|
88
|
+
}
|
|
89
|
+
const currentEnd = (0, import_dayjs.default)(`${endDate} ${endTime}`);
|
|
90
|
+
if (!currentEnd.isValid()) {
|
|
91
|
+
throw new Error("[BookingTicket] addAddTimeProductsToBooking: booking.end_date/end_time 无效");
|
|
92
|
+
}
|
|
93
|
+
const nextEnd = currentEnd.add(coveredMinutes, "minute");
|
|
94
|
+
const currentDuration = Number(booking == null ? void 0 : booking.duration);
|
|
95
|
+
let duration = Number.isFinite(currentDuration) ? currentDuration + coveredMinutes : coveredMinutes;
|
|
96
|
+
if ((booking == null ? void 0 : booking.start_date) && (booking == null ? void 0 : booking.start_time)) {
|
|
97
|
+
const start = (0, import_dayjs.default)(`${booking.start_date} ${booking.start_time}`);
|
|
98
|
+
if (start.isValid()) {
|
|
99
|
+
const diffMinutes = nextEnd.diff(start, "minute");
|
|
100
|
+
duration = diffMinutes > 0 ? diffMinutes : duration;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
end_date: nextEnd.format("YYYY-MM-DD"),
|
|
105
|
+
end_time: nextEnd.format("HH:mm"),
|
|
106
|
+
duration
|
|
107
|
+
};
|
|
108
|
+
}
|
|
57
109
|
function withProductOptionString(cacheItem) {
|
|
58
110
|
var _a;
|
|
59
111
|
const productOptionString = (0, import_orderLineDisplay.buildProductOptionStringFromOrderLine)(cacheItem);
|
|
@@ -79,6 +131,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
79
131
|
*/
|
|
80
132
|
this.store = {};
|
|
81
133
|
this.productCatalog = [];
|
|
134
|
+
this.addTimeProductsCatalog = [];
|
|
82
135
|
this.orderCustomerDiscountRefreshInFlight = null;
|
|
83
136
|
this.orderCustomerDiscountRefreshCustomerId = null;
|
|
84
137
|
this.loadOpenDataConfigInFlight = null;
|
|
@@ -164,6 +217,10 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
164
217
|
this.loadOpenDataConfigInFlight = null;
|
|
165
218
|
}
|
|
166
219
|
}
|
|
220
|
+
async getOpenData() {
|
|
221
|
+
var _a;
|
|
222
|
+
return (_a = this.store.openData) == null ? void 0 : _a.getOpenData();
|
|
223
|
+
}
|
|
167
224
|
async getShortNumberOrDeviceId() {
|
|
168
225
|
const getAsyncIotDeviceInfo = this.getAppData("async_iot_device_info");
|
|
169
226
|
if (getAsyncIotDeviceInfo) {
|
|
@@ -520,10 +577,12 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
520
577
|
* const products = await bookingTicket.getAddTimeProducts({ schedule_date: '2026-06-16' });
|
|
521
578
|
*/
|
|
522
579
|
async getAddTimeProducts(params = {}) {
|
|
523
|
-
|
|
580
|
+
const result = await this.store.products.getAddTimeProducts({
|
|
524
581
|
...params,
|
|
525
582
|
cacheId: this.cacheId
|
|
526
583
|
});
|
|
584
|
+
this.addTimeProductsCatalog = Array.isArray(result) ? [...result] : [];
|
|
585
|
+
return result;
|
|
527
586
|
}
|
|
528
587
|
/**
|
|
529
588
|
* 只读查询单商品详情:走 ProductList 报价查询,但不写 productCatalog、
|
|
@@ -610,11 +669,23 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
610
669
|
* tempOrder 仍是 checkout 协议对象;商品行直接透传 products,bookings 附带关联商品。
|
|
611
670
|
*/
|
|
612
671
|
getCart() {
|
|
613
|
-
var _a;
|
|
672
|
+
var _a, _b;
|
|
614
673
|
const tempOrder = ((_a = this.store.order) == null ? void 0 : _a.getTempOrder()) ?? null;
|
|
615
674
|
const salesDetail = this.getSalesOrder();
|
|
616
675
|
const bookings = (salesDetail == null ? void 0 : salesDetail.bookings) ?? ((tempOrder == null ? void 0 : tempOrder.bookings) || []);
|
|
617
|
-
|
|
676
|
+
let operatingDayBoundary;
|
|
677
|
+
try {
|
|
678
|
+
operatingDayBoundary = this.getAppData("operating_day_boundary");
|
|
679
|
+
} catch {
|
|
680
|
+
operatingDayBoundary = void 0;
|
|
681
|
+
}
|
|
682
|
+
const shopOpeningHours = (operatingDayBoundary == null ? void 0 : operatingDayBoundary.type) === "start_time" ? "23:59" : operatingDayBoundary == null ? void 0 : operatingDayBoundary.time;
|
|
683
|
+
return (0, import_cartView.buildCartView)((tempOrder == null ? void 0 : tempOrder.products) || [], bookings, {
|
|
684
|
+
addTimeProducts: this.addTimeProductsCatalog,
|
|
685
|
+
bookingConfig: this.getBookingConfig(),
|
|
686
|
+
productsByUid: (_b = tempOrder == null ? void 0 : tempOrder._extend) == null ? void 0 : _b.productsByUid,
|
|
687
|
+
shopOpeningHours
|
|
688
|
+
});
|
|
618
689
|
}
|
|
619
690
|
/**
|
|
620
691
|
* 获取当前下单客户(与 OrderModule.tempOrder snapshot 一致)。
|
|
@@ -1304,6 +1375,126 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1304
1375
|
resolveBestAddTimePlan(addTimeProducts, targetMinutes) {
|
|
1305
1376
|
return (0, import_resolveBestAddTimePlan.resolveBestAddTimePlan)(addTimeProducts, targetMinutes);
|
|
1306
1377
|
}
|
|
1378
|
+
/**
|
|
1379
|
+
* 构造一条绑定到已有 booking 的加时商品行。
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* const line = this.buildAddTimeOrderLine({ product, product_add_schedule_time: 30 }, 'booking-1');
|
|
1383
|
+
*/
|
|
1384
|
+
buildAddTimeOrderLine(input, bookingUid) {
|
|
1385
|
+
var _a;
|
|
1386
|
+
const product = input == null ? void 0 : input.product;
|
|
1387
|
+
if (!product || typeof product !== "object") {
|
|
1388
|
+
throw new Error("[BookingTicket] addAddTimeProductToBooking: product 不能为空");
|
|
1389
|
+
}
|
|
1390
|
+
const quantity = normalizeAddTimeQuantity(input.num ?? product.num);
|
|
1391
|
+
const price = resolveAddTimeProductPrice(input.price, product);
|
|
1392
|
+
const addScheduleTime = resolveAddTimeScheduleMinutes(
|
|
1393
|
+
input.product_add_schedule_time,
|
|
1394
|
+
product
|
|
1395
|
+
);
|
|
1396
|
+
const payload = {
|
|
1397
|
+
id: product.id ?? product.product_id,
|
|
1398
|
+
product_id: product.product_id ?? product.id,
|
|
1399
|
+
product_variant_id: product.product_variant_id ?? product.variant_id ?? 0,
|
|
1400
|
+
variant_id: product.variant_id ?? product.product_variant_id ?? 0,
|
|
1401
|
+
quantity,
|
|
1402
|
+
num: quantity,
|
|
1403
|
+
price,
|
|
1404
|
+
selling_price: price,
|
|
1405
|
+
original_price: product.original_price ?? price,
|
|
1406
|
+
line_total: price,
|
|
1407
|
+
total: price,
|
|
1408
|
+
product_sku: product.product_sku,
|
|
1409
|
+
option: product.option ?? product.options ?? ((_a = product.product_sku) == null ? void 0 : _a.option) ?? [],
|
|
1410
|
+
bundle: product.bundle ?? product.bundles ?? product.product_bundle ?? []
|
|
1411
|
+
};
|
|
1412
|
+
const orderLine = this.transformBaseProductToOrderProduct({
|
|
1413
|
+
payload,
|
|
1414
|
+
fallbackProductId: product.id ?? product.product_id,
|
|
1415
|
+
sourceProduct: product,
|
|
1416
|
+
sourceItem: product
|
|
1417
|
+
});
|
|
1418
|
+
if (!orderLine) {
|
|
1419
|
+
throw new Error(
|
|
1420
|
+
"[BookingTicket] addAddTimeProductToBooking: product transform failed"
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
const metadata = {
|
|
1424
|
+
...orderLine.metadata || {},
|
|
1425
|
+
...addScheduleTime !== void 0 ? { product_add_schedule_time: addScheduleTime } : {},
|
|
1426
|
+
booking_uid: bookingUid
|
|
1427
|
+
};
|
|
1428
|
+
return {
|
|
1429
|
+
...orderLine,
|
|
1430
|
+
booking_uid: bookingUid,
|
|
1431
|
+
metadata
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* 将加时商品作为独立商品行绑定到已有 booking。
|
|
1436
|
+
*
|
|
1437
|
+
* 与预约商品加车不同,本方法不会把当前 booking 作为 `addProductToOrder` 第二参数传入,
|
|
1438
|
+
* 避免 OrderModule 新建 booking 或重写已有 booking.product_uid。
|
|
1439
|
+
*
|
|
1440
|
+
* @example
|
|
1441
|
+
* await bookingTicket.addAddTimeProductToBooking({
|
|
1442
|
+
* booking,
|
|
1443
|
+
* product,
|
|
1444
|
+
* num: 1,
|
|
1445
|
+
* price: '10.00',
|
|
1446
|
+
* product_add_schedule_time: 30,
|
|
1447
|
+
* });
|
|
1448
|
+
*/
|
|
1449
|
+
async addAddTimeProductToBooking(input) {
|
|
1450
|
+
return this.addAddTimeProductsToBooking({
|
|
1451
|
+
booking: input.booking,
|
|
1452
|
+
products: [input],
|
|
1453
|
+
coveredMinutes: input.coveredMinutes,
|
|
1454
|
+
bookingPatch: input.bookingPatch
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* 批量将加时商品作为独立商品行绑定到已有 booking,并只触发一次购物车重算。
|
|
1459
|
+
*
|
|
1460
|
+
* @example
|
|
1461
|
+
* await bookingTicket.addAddTimeProductsToBooking({
|
|
1462
|
+
* booking,
|
|
1463
|
+
* products: [{ product, product_add_schedule_time: 30 }],
|
|
1464
|
+
* });
|
|
1465
|
+
*/
|
|
1466
|
+
async addAddTimeProductsToBooking(input) {
|
|
1467
|
+
const bookingUid = resolveBookingUidForAddTime(input == null ? void 0 : input.booking);
|
|
1468
|
+
if (!bookingUid) {
|
|
1469
|
+
throw new Error(
|
|
1470
|
+
"[BookingTicket] addAddTimeProductToBooking: booking.metadata.unique_identification_number 缺失"
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
const orderLines = (input.products || []).map((line) => ({
|
|
1474
|
+
product: this.buildAddTimeOrderLine(line, bookingUid)
|
|
1475
|
+
}));
|
|
1476
|
+
if (!this.store.order)
|
|
1477
|
+
throw new Error("order 模块未初始化");
|
|
1478
|
+
const coveredMinutes = normalizeCoveredMinutes(input.coveredMinutes);
|
|
1479
|
+
const bookingTimePatch = input.bookingPatch ?? buildAddTimeBookingTimePatch(input.booking, coveredMinutes);
|
|
1480
|
+
if (bookingTimePatch) {
|
|
1481
|
+
this.store.order.updateOrderBooking({
|
|
1482
|
+
unique_identification_number: bookingUid,
|
|
1483
|
+
updates: bookingTimePatch
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
if (typeof this.store.order.addProductsToOrder === "function") {
|
|
1487
|
+
return this.store.order.addProductsToOrder(orderLines, {
|
|
1488
|
+
skipEditDiscountConfigRefresh: true,
|
|
1489
|
+
skipDiscountRecalculation: true
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
const result = [];
|
|
1493
|
+
for (const line of orderLines) {
|
|
1494
|
+
result.splice(0, result.length, ...await this.addProductToOrder(line.product));
|
|
1495
|
+
}
|
|
1496
|
+
return result;
|
|
1497
|
+
}
|
|
1307
1498
|
/**
|
|
1308
1499
|
* 销毁模块:先调用父类(销毁所有 store 内子模块 + emit destroy + super.destroy()),
|
|
1309
1500
|
* 再清理 BookingTicket 自有资源(scan 监听 + scan 内存缓存)。
|
|
@@ -112,6 +112,8 @@ export type BookingTicketCartItemView = BaseSalesOrderProduct;
|
|
|
112
112
|
export interface BookingTicketCartBookingView extends ISalesBooking {
|
|
113
113
|
_extend: {
|
|
114
114
|
product: BookingTicketCartItemView | null;
|
|
115
|
+
addTimeProduct: BookingTicketCartItemView[];
|
|
116
|
+
canAddTime: boolean;
|
|
115
117
|
};
|
|
116
118
|
}
|
|
117
119
|
/**
|
|
@@ -139,6 +141,66 @@ export interface BookingTicketCustomerView {
|
|
|
139
141
|
export interface BookingTicketProductCatalogView {
|
|
140
142
|
products: ProductData[];
|
|
141
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* 添加加时商品到已有 booking 的输入。
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* await bookingTicket.addAddTimeProductToBooking({
|
|
149
|
+
* booking,
|
|
150
|
+
* product,
|
|
151
|
+
* num: 1,
|
|
152
|
+
* price: '10.00',
|
|
153
|
+
* product_add_schedule_time: 30,
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
156
|
+
export interface AddAddTimeProductToBookingInput {
|
|
157
|
+
/** 当前购物车中已存在的 booking,必须带 metadata.unique_identification_number。 */
|
|
158
|
+
booking: Record<string, any>;
|
|
159
|
+
/** 加时商品原始数据,保留完整商品信息供 OrderModule 缓存原始快照。 */
|
|
160
|
+
product: ProductData & Record<string, any>;
|
|
161
|
+
/** 本次添加数量,缺省为 1。 */
|
|
162
|
+
num?: number;
|
|
163
|
+
/** 本次加时商品价格,缺省回退 product.price。 */
|
|
164
|
+
price?: number | string;
|
|
165
|
+
/** 加时时长,单位分钟;最终写入 product.metadata.product_add_schedule_time。 */
|
|
166
|
+
product_add_schedule_time?: number;
|
|
167
|
+
/** 本次加时方案实际覆盖分钟数,用于同步更新 booking 结束时间与 duration。 */
|
|
168
|
+
coveredMinutes?: number;
|
|
169
|
+
/** 直接写入 booking 的时间补丁,restart 场景使用。 */
|
|
170
|
+
bookingPatch?: {
|
|
171
|
+
start_date?: string;
|
|
172
|
+
start_time?: string;
|
|
173
|
+
end_date?: string;
|
|
174
|
+
end_time?: string;
|
|
175
|
+
duration?: number;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* 批量添加加时商品到已有 booking 的单行输入。
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* const line: AddAddTimeProductLineInput = { product, product_add_schedule_time: 30 };
|
|
183
|
+
*/
|
|
184
|
+
export type AddAddTimeProductLineInput = Omit<AddAddTimeProductToBookingInput, 'booking' | 'coveredMinutes'>;
|
|
185
|
+
/**
|
|
186
|
+
* 批量添加加时商品到已有 booking 的输入。
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* await bookingTicket.addAddTimeProductsToBooking({
|
|
190
|
+
* booking,
|
|
191
|
+
* products: [{ product, product_add_schedule_time: 30 }],
|
|
192
|
+
* });
|
|
193
|
+
*/
|
|
194
|
+
export interface AddAddTimeProductsToBookingInput {
|
|
195
|
+
/** 当前购物车中已存在的 booking,必须带 metadata.unique_identification_number。 */
|
|
196
|
+
booking: Record<string, any>;
|
|
197
|
+
/** 需要一次性写入购物车的加时商品行。 */
|
|
198
|
+
products: AddAddTimeProductLineInput[];
|
|
199
|
+
/** 本次加时方案实际覆盖分钟数,用于同步更新 booking 结束时间与 duration。 */
|
|
200
|
+
coveredMinutes?: number;
|
|
201
|
+
/** 直接写入 booking 的时间补丁,restart 场景使用。 */
|
|
202
|
+
bookingPatch?: AddAddTimeProductToBookingInput['bookingPatch'];
|
|
203
|
+
}
|
|
142
204
|
/** 扫码宿主桥接:SalesSdk 在 pubsub 订阅回调里注入,OS 需要 UI 时直接调用 */
|
|
143
205
|
export interface GlobalScanHostBridge {
|
|
144
206
|
openProductDetail?: (payload: Record<string, any>) => Promise<any | null>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BaseSalesOrderProduct } from '../../BaseSales';
|
|
2
|
+
import type { ISalesBooking } from '../../BaseSales/utils/parseSalesResponse';
|
|
3
|
+
export interface BuildAddTimeCurrentItemParams {
|
|
4
|
+
booking: ISalesBooking;
|
|
5
|
+
product: BaseSalesOrderProduct | null;
|
|
6
|
+
productsByUid?: Record<string, {
|
|
7
|
+
origin?: Record<string, any>;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolveBookingCanAddTimeParams extends BuildAddTimeCurrentItemParams {
|
|
11
|
+
addTimeProducts?: any[];
|
|
12
|
+
bookingConfig?: Record<string, any> | null;
|
|
13
|
+
shopOpeningHours?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 从 booking 与其关联商品行构建旧 `isUsableProduct` 所需的当前商品快照。
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const currentItem = buildAddTimeCurrentItem({ booking, product, productsByUid });
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildAddTimeCurrentItem({ booking, product, productsByUid, }: BuildAddTimeCurrentItemParams): Record<string, any> | null;
|
|
22
|
+
/**
|
|
23
|
+
* 判断当前 booking 是否允许打开加时入口,保持与旧 ticketBooking 的商品适用规则一致。
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const canAddTime = resolveBookingCanAddTime({ booking, product, addTimeProducts, bookingConfig });
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveBookingCanAddTime(params: ResolveBookingCanAddTimeParams): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 判断一个加时商品是否适用于当前预约商品。
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const usable = isUsableAddTimeProduct(addTime.add_time, currentItem, '23:59');
|
|
34
|
+
*/
|
|
35
|
+
export declare function isUsableAddTimeProduct(addTime: any, currentItem: Record<string, any> | null | undefined, shopOpeningHours?: string): boolean;
|
|
@@ -0,0 +1,125 @@
|
|
|
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/solution/BookingTicket/utils/addTimeAvailability.ts
|
|
30
|
+
var addTimeAvailability_exports = {};
|
|
31
|
+
__export(addTimeAvailability_exports, {
|
|
32
|
+
buildAddTimeCurrentItem: () => buildAddTimeCurrentItem,
|
|
33
|
+
isUsableAddTimeProduct: () => isUsableAddTimeProduct,
|
|
34
|
+
resolveBookingCanAddTime: () => resolveBookingCanAddTime
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(addTimeAvailability_exports);
|
|
37
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
38
|
+
var import_lodash_es = require("lodash-es");
|
|
39
|
+
var import_serviceTimes = require("../../../modules/BookingContext/utils/serviceTimes");
|
|
40
|
+
var import_timeSlices = require("../../../modules/BookingContext/utils/timeSlices");
|
|
41
|
+
function buildAddTimeCurrentItem({
|
|
42
|
+
booking,
|
|
43
|
+
product,
|
|
44
|
+
productsByUid
|
|
45
|
+
}) {
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
if (!booking || !product)
|
|
48
|
+
return null;
|
|
49
|
+
const uid = (_a = product.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
50
|
+
const origin = uid ? (_b = productsByUid == null ? void 0 : productsByUid[String(uid)]) == null ? void 0 : _b.origin : void 0;
|
|
51
|
+
const sourceProduct = origin || booking.product || {};
|
|
52
|
+
const startAt = booking.start_date && booking.start_time ? `${booking.start_date} ${booking.start_time}` : booking.start_date;
|
|
53
|
+
const endAt = booking.end_date && booking.end_time ? `${booking.end_date} ${booking.end_time}` : booking.end_date;
|
|
54
|
+
return {
|
|
55
|
+
...sourceProduct,
|
|
56
|
+
...booking.product,
|
|
57
|
+
product_id: product.product_id ?? sourceProduct.product_id ?? sourceProduct.id,
|
|
58
|
+
id: sourceProduct.id ?? product.product_id,
|
|
59
|
+
collection: sourceProduct.collection || ((_c = booking.product) == null ? void 0 : _c.collection) || [],
|
|
60
|
+
duration: sourceProduct.duration || booking.duration,
|
|
61
|
+
_extend: {
|
|
62
|
+
...sourceProduct._extend || {},
|
|
63
|
+
startDate: startAt ? (0, import_dayjs.default)(startAt) : void 0,
|
|
64
|
+
endDate: endAt ? (0, import_dayjs.default)(endAt) : void 0,
|
|
65
|
+
start_date: booking.start_date,
|
|
66
|
+
end_date: booking.end_date,
|
|
67
|
+
start_time: booking.start_time,
|
|
68
|
+
end_time: booking.end_time,
|
|
69
|
+
sub_type: booking.sub_type
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function resolveBookingCanAddTime(params) {
|
|
74
|
+
var _a, _b, _c, _d;
|
|
75
|
+
const quickTime = (_d = (_c = (_b = (_a = params.bookingConfig) == null ? void 0 : _a.config) == null ? void 0 : _b.information_tab) == null ? void 0 : _c.appointment_card) == null ? void 0 : _d.quick_time;
|
|
76
|
+
if (quickTime !== void 0 && quickTime !== 1)
|
|
77
|
+
return false;
|
|
78
|
+
const currentItem = buildAddTimeCurrentItem(params);
|
|
79
|
+
if (!currentItem || (0, import_serviceTimes.isMultiDayProduct)(currentItem))
|
|
80
|
+
return false;
|
|
81
|
+
return (params.addTimeProducts || []).some(
|
|
82
|
+
(item) => isUsableAddTimeProduct(item == null ? void 0 : item.add_time, currentItem, params.shopOpeningHours)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function isUsableAddTimeProduct(addTime, currentItem, shopOpeningHours) {
|
|
86
|
+
var _a, _b;
|
|
87
|
+
if (!addTime || !currentItem)
|
|
88
|
+
return false;
|
|
89
|
+
if (addTime.additional_time_options === "unlimited") {
|
|
90
|
+
const startDate = (0, import_dayjs.default)((_a = currentItem._extend) == null ? void 0 : _a.startDate);
|
|
91
|
+
const endDate = (0, import_dayjs.default)((_b = currentItem._extend) == null ? void 0 : _b.endDate);
|
|
92
|
+
if (!startDate.isValid() || !endDate.isValid())
|
|
93
|
+
return false;
|
|
94
|
+
const maxEndDate = (0, import_timeSlices.getEndDate)(startDate, "flexible", "", shopOpeningHours);
|
|
95
|
+
if (endDate.isAfter(maxEndDate))
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const relationProduct = addTime.relation_product || {};
|
|
99
|
+
const type = relationProduct.type;
|
|
100
|
+
const products = Array.isArray(relationProduct.products) ? relationProduct.products : [];
|
|
101
|
+
if (type === "product_all")
|
|
102
|
+
return true;
|
|
103
|
+
if (type === "product_collection") {
|
|
104
|
+
return Boolean(
|
|
105
|
+
(0, import_lodash_es.intersectionBy)(
|
|
106
|
+
products.map((item) => ({
|
|
107
|
+
...item,
|
|
108
|
+
id: item.product_collection_id
|
|
109
|
+
})),
|
|
110
|
+
currentItem.collection || [],
|
|
111
|
+
"id"
|
|
112
|
+
).length
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (type === "products") {
|
|
116
|
+
return products.some((item) => item.product_id == currentItem.product_id);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
121
|
+
0 && (module.exports = {
|
|
122
|
+
buildAddTimeCurrentItem,
|
|
123
|
+
isUsableAddTimeProduct,
|
|
124
|
+
resolveBookingCanAddTime
|
|
125
|
+
});
|
|
@@ -2,6 +2,14 @@ import type { BaseSalesOrderProduct } from '../../BaseSales';
|
|
|
2
2
|
import type { ISalesBooking } from '../../BaseSales/utils/parseSalesResponse';
|
|
3
3
|
import type { BookingTicketCartView, BookingTicketCustomerView, ICustomer } from '../types';
|
|
4
4
|
import type { ScanOrderTempOrder } from '../../ScanOrder/types';
|
|
5
|
+
export interface BuildCartViewOptions {
|
|
6
|
+
addTimeProducts?: any[];
|
|
7
|
+
bookingConfig?: Record<string, any> | null;
|
|
8
|
+
productsByUid?: Record<string, {
|
|
9
|
+
origin?: Record<string, any>;
|
|
10
|
+
}>;
|
|
11
|
+
shopOpeningHours?: string;
|
|
12
|
+
}
|
|
5
13
|
/**
|
|
6
14
|
* 仅按 booking.product_uid 建索引,避免发明 booking 与商品行之间的其它等价关系。
|
|
7
15
|
*/
|
|
@@ -13,7 +21,7 @@ export declare function indexBookingsByProductUid(bookings: ISalesBooking[] | un
|
|
|
13
21
|
* 关联规则(1:1):booking.product_uid ↔ line.metadata.unique_identification_number;
|
|
14
22
|
* 同一 uid 已被更早的 booking 占用时,后续 booking 的 product 为 null。
|
|
15
23
|
*/
|
|
16
|
-
export declare function buildCartView(lines: BaseSalesOrderProduct[] | undefined | null, bookings: ISalesBooking[] | undefined | null): BookingTicketCartView;
|
|
24
|
+
export declare function buildCartView(lines: BaseSalesOrderProduct[] | undefined | null, bookings: ISalesBooking[] | undefined | null, options?: BuildCartViewOptions): BookingTicketCartView;
|
|
17
25
|
export declare function isWalkInCustomer(customer: Pick<ICustomer, 'id'> | null | undefined): boolean;
|
|
18
26
|
/**
|
|
19
27
|
* selected 优先,缺失时回退 tempOrder.customer_*,统一输出 UI 客户视图。
|