@pisell/pisellos 0.0.507 → 0.0.509
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 +1 -1
- package/dist/modules/Order/index.js +2 -2
- package/dist/modules/Order/utils.d.ts +2 -0
- package/dist/modules/Order/utils.js +8 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/ScanOrder/index.d.ts +21 -1
- package/dist/solution/ScanOrder/index.js +948 -497
- package/dist/solution/ScanOrder/types.d.ts +6 -0
- package/dist/solution/ScanOrder/types.js +3 -1
- package/dist/solution/ScanOrder/utils.d.ts +5 -0
- package/dist/solution/ScanOrder/utils.js +32 -0
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +3 -1
- package/lib/modules/Order/utils.d.ts +2 -0
- package/lib/modules/Order/utils.js +8 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/ScanOrder/index.d.ts +21 -1
- package/lib/solution/ScanOrder/index.js +259 -14
- package/lib/solution/ScanOrder/types.d.ts +6 -0
- package/lib/solution/ScanOrder/utils.d.ts +5 -0
- package/lib/solution/ScanOrder/utils.js +26 -0
- package/package.json +1 -1
|
@@ -235,3 +235,9 @@ export interface ScanOrderLoggerRuntimeConfig {
|
|
|
235
235
|
}
|
|
236
236
|
export interface ScanOrderAddLogParams extends ScanOrderLogInput {
|
|
237
237
|
}
|
|
238
|
+
/** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
|
|
239
|
+
export interface ScanOrderScanCodeResult {
|
|
240
|
+
isAvailable: boolean;
|
|
241
|
+
type?: 'server' | string;
|
|
242
|
+
unavailableReason?: 'time_limit' | string;
|
|
243
|
+
}
|
|
@@ -17,4 +17,6 @@ export var ScanOrderHooks = /*#__PURE__*/function (ScanOrderHooks) {
|
|
|
17
17
|
|
|
18
18
|
/** `resource_capacity[i].capacity_list[j]` */
|
|
19
19
|
|
|
20
|
-
/** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
|
|
20
|
+
/** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
|
|
21
|
+
|
|
22
|
+
/** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
|
|
@@ -129,3 +129,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
|
|
|
129
129
|
min?: number;
|
|
130
130
|
max?: number;
|
|
131
131
|
} | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
134
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
135
|
+
*/
|
|
136
|
+
export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
|
|
@@ -580,4 +580,36 @@ export function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
580
580
|
_iterator9.f();
|
|
581
581
|
}
|
|
582
582
|
return undefined;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
587
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
588
|
+
*/
|
|
589
|
+
export function pickFirstCustomCapacityDimensionId(products) {
|
|
590
|
+
var _iterator10 = _createForOfIteratorHelper(products),
|
|
591
|
+
_step10;
|
|
592
|
+
try {
|
|
593
|
+
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
|
594
|
+
var p = _step10.value;
|
|
595
|
+
var cap = p === null || p === void 0 ? void 0 : p.capacity;
|
|
596
|
+
if (!cap || cap.type !== 'custom') continue;
|
|
597
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
|
|
598
|
+
var row = cap.custom[0];
|
|
599
|
+
if (!row || _typeof(row) !== 'object') continue;
|
|
600
|
+
var id = row.id;
|
|
601
|
+
if (id === null || id === undefined || id === '') continue;
|
|
602
|
+
if (typeof id === 'number' && Number.isFinite(id)) return id;
|
|
603
|
+
if (typeof id === 'string') {
|
|
604
|
+
var trimmed = id.trim();
|
|
605
|
+
if (!trimmed) continue;
|
|
606
|
+
return trimmed;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
} catch (err) {
|
|
610
|
+
_iterator10.e(err);
|
|
611
|
+
} finally {
|
|
612
|
+
_iterator10.f();
|
|
613
|
+
}
|
|
614
|
+
return undefined;
|
|
583
615
|
}
|
|
@@ -86,7 +86,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
86
86
|
enhancePayload?: SubmitPayloadEnhancer;
|
|
87
87
|
}): Promise<T>;
|
|
88
88
|
createOrder(params: CommitOrderParams['query']): {
|
|
89
|
-
type: "
|
|
89
|
+
type: "virtual" | "appointment_booking";
|
|
90
90
|
platform: string;
|
|
91
91
|
sales_channel: string;
|
|
92
92
|
order_sales_channel: string;
|
|
@@ -477,7 +477,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
477
477
|
});
|
|
478
478
|
let result;
|
|
479
479
|
if (tempOrder.order_id) {
|
|
480
|
-
|
|
480
|
+
let products = (0, import_utils.formatV1Product)(
|
|
481
|
+
(0, import_utils.filterProductsForScanOrderMore)(payload.products)
|
|
482
|
+
);
|
|
481
483
|
const moreResult = await this.scanOrderMore({
|
|
482
484
|
query: {
|
|
483
485
|
order_id: tempOrder.order_id,
|
|
@@ -72,6 +72,8 @@ export declare function buildSubmitPayload(params: {
|
|
|
72
72
|
type?: string;
|
|
73
73
|
enhance?: SubmitPayloadEnhancer;
|
|
74
74
|
}): ScanOrderSubmitPayload;
|
|
75
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
76
|
+
export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
|
|
75
77
|
export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
76
78
|
bundle: any[];
|
|
77
79
|
key: number | null;
|
|
@@ -34,6 +34,7 @@ __export(utils_exports, {
|
|
|
34
34
|
createDefaultTempOrder: () => createDefaultTempOrder,
|
|
35
35
|
createEmptySummary: () => import_utils2.createEmptySummary,
|
|
36
36
|
createUuidV4: () => createUuidV4,
|
|
37
|
+
filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
|
|
37
38
|
formatDateTime: () => formatDateTime,
|
|
38
39
|
formatV1Product: () => formatV1Product,
|
|
39
40
|
generateDuration: () => generateDuration,
|
|
@@ -366,6 +367,12 @@ function buildSubmitPayload(params) {
|
|
|
366
367
|
};
|
|
367
368
|
return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
|
|
368
369
|
}
|
|
370
|
+
function filterProductsForScanOrderMore(products) {
|
|
371
|
+
return (products || []).filter((p) => {
|
|
372
|
+
var _a;
|
|
373
|
+
return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
|
|
374
|
+
});
|
|
375
|
+
}
|
|
369
376
|
function formatV1Product(products) {
|
|
370
377
|
return products.map((product) => {
|
|
371
378
|
return {
|
|
@@ -388,6 +395,7 @@ function formatV1Product(products) {
|
|
|
388
395
|
createDefaultTempOrder,
|
|
389
396
|
createEmptySummary,
|
|
390
397
|
createUuidV4,
|
|
398
|
+
filterProductsForScanOrderMore,
|
|
391
399
|
formatDateTime,
|
|
392
400
|
formatV1Product,
|
|
393
401
|
generateDuration,
|
|
@@ -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 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -131,7 +131,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
|
|
|
131
131
|
* 获取当前的客户搜索条件
|
|
132
132
|
* @returns 当前搜索条件
|
|
133
133
|
*/
|
|
134
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
134
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
135
135
|
/**
|
|
136
136
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
137
137
|
* @returns 客户状态
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
|
-
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity } from './types';
|
|
3
|
+
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult } from './types';
|
|
4
|
+
import type { Discount } from '../../modules/Discount/types';
|
|
4
5
|
import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
5
6
|
import type { StrategyConfig } from '../../model/strategy/type';
|
|
6
7
|
export * from './types';
|
|
@@ -29,6 +30,10 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
29
30
|
private itemRuleRuntimeConfig;
|
|
30
31
|
/** 最近一次 checkResourceAvailable 从预约规则 link 拉取的商品快照 */
|
|
31
32
|
private enabledReservationRuleProducts;
|
|
33
|
+
private loginEffectDisposers;
|
|
34
|
+
private customerLoginRefreshInFlight;
|
|
35
|
+
private customerLoginRefreshIdInFlight;
|
|
36
|
+
private static readonly PISELL1_LOGIN_SUCCESS;
|
|
32
37
|
private getScanOrderLoggerContext;
|
|
33
38
|
private serializeError;
|
|
34
39
|
private addScanOrderLog;
|
|
@@ -36,6 +41,12 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
36
41
|
private logMethodSuccess;
|
|
37
42
|
private logMethodError;
|
|
38
43
|
addLog(params: ScanOrderAddLogParams): Promise<void>;
|
|
44
|
+
private normalizeCustomerId;
|
|
45
|
+
private resolveCustomerIdFromLoginPayload;
|
|
46
|
+
private clearLoginEffectListeners;
|
|
47
|
+
private registerLoginEffect;
|
|
48
|
+
private registerCustomerLoginListeners;
|
|
49
|
+
private refreshOrderMarketingAfterLogin;
|
|
39
50
|
constructor(name?: string, version?: string);
|
|
40
51
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
41
52
|
destroy(): Promise<void>;
|
|
@@ -62,6 +73,15 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
62
73
|
restoreOrder(): Promise<import("./types").ScanOrderTempOrder>;
|
|
63
74
|
getOrderProducts(): ScanOrderOrderProduct[];
|
|
64
75
|
getSummary(): Promise<import("./types").ScanOrderSummary>;
|
|
76
|
+
getDiscountList(): Discount[];
|
|
77
|
+
scanCode(code: string, customerId?: number): Promise<ScanOrderScanCodeResult>;
|
|
78
|
+
setDiscountSelected(params: {
|
|
79
|
+
discountId: number;
|
|
80
|
+
isSelected: boolean;
|
|
81
|
+
}): Promise<void>;
|
|
82
|
+
onCustomerLogin(params: {
|
|
83
|
+
customerId: number;
|
|
84
|
+
}): Promise<void>;
|
|
65
85
|
private buildSubmitPayloadEnhancer;
|
|
66
86
|
submitScanOrder<T = any>(): Promise<T>;
|
|
67
87
|
addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
@@ -35,8 +35,12 @@ __export(ScanOrder_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(ScanOrder_exports);
|
|
36
36
|
var import_BaseModule = require("../../modules/BaseModule");
|
|
37
37
|
var import_types = require("./types");
|
|
38
|
+
var import_Order = require("../../modules/Order");
|
|
39
|
+
var import_types2 = require("../../modules/Account/types");
|
|
40
|
+
var import_types3 = require("../RegisterAndLogin/types");
|
|
41
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
38
42
|
var import_utils = require("./utils");
|
|
39
|
-
var
|
|
43
|
+
var import_types4 = require("../BookingByStep/types");
|
|
40
44
|
var import_ProductList = require("../../modules/ProductList");
|
|
41
45
|
var import_Schedule = require("../../modules/Schedule");
|
|
42
46
|
var import_getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
@@ -74,6 +78,9 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
74
78
|
this.itemRuleRuntimeConfig = {};
|
|
75
79
|
/** 最近一次 checkResourceAvailable 从预约规则 link 拉取的商品快照 */
|
|
76
80
|
this.enabledReservationRuleProducts = [];
|
|
81
|
+
this.loginEffectDisposers = [];
|
|
82
|
+
this.customerLoginRefreshInFlight = null;
|
|
83
|
+
this.customerLoginRefreshIdInFlight = null;
|
|
77
84
|
}
|
|
78
85
|
getScanOrderLoggerContext() {
|
|
79
86
|
return {
|
|
@@ -157,6 +164,102 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
157
164
|
}
|
|
158
165
|
});
|
|
159
166
|
}
|
|
167
|
+
normalizeCustomerId(value) {
|
|
168
|
+
const customerId = Number(value);
|
|
169
|
+
if (!Number.isFinite(customerId) || customerId <= 0)
|
|
170
|
+
return null;
|
|
171
|
+
return customerId;
|
|
172
|
+
}
|
|
173
|
+
resolveCustomerIdFromLoginPayload(payload) {
|
|
174
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
175
|
+
const candidates = [
|
|
176
|
+
payload == null ? void 0 : payload.customerId,
|
|
177
|
+
payload == null ? void 0 : payload.customer_id,
|
|
178
|
+
payload == null ? void 0 : payload.id,
|
|
179
|
+
(_a = payload == null ? void 0 : payload.user) == null ? void 0 : _a.customerId,
|
|
180
|
+
(_b = payload == null ? void 0 : payload.user) == null ? void 0 : _b.customer_id,
|
|
181
|
+
(_c = payload == null ? void 0 : payload.user) == null ? void 0 : _c.id,
|
|
182
|
+
(_e = (_d = payload == null ? void 0 : payload.user) == null ? void 0 : _d._origin) == null ? void 0 : _e.customer_id,
|
|
183
|
+
(_f = payload == null ? void 0 : payload.account) == null ? void 0 : _f.customerId,
|
|
184
|
+
(_g = payload == null ? void 0 : payload.account) == null ? void 0 : _g.customer_id,
|
|
185
|
+
(_h = payload == null ? void 0 : payload.account) == null ? void 0 : _h.id,
|
|
186
|
+
(_i = payload == null ? void 0 : payload._origin) == null ? void 0 : _i.customer_id
|
|
187
|
+
];
|
|
188
|
+
for (const candidate of candidates) {
|
|
189
|
+
const customerId = this.normalizeCustomerId(candidate);
|
|
190
|
+
if (customerId)
|
|
191
|
+
return customerId;
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
clearLoginEffectListeners() {
|
|
196
|
+
for (const dispose of this.loginEffectDisposers) {
|
|
197
|
+
dispose();
|
|
198
|
+
}
|
|
199
|
+
this.loginEffectDisposers = [];
|
|
200
|
+
}
|
|
201
|
+
registerLoginEffect(event, callback) {
|
|
202
|
+
var _a;
|
|
203
|
+
const effects = (_a = this.core) == null ? void 0 : _a.effects;
|
|
204
|
+
if (!(effects == null ? void 0 : effects.on))
|
|
205
|
+
return;
|
|
206
|
+
effects.on(event, callback);
|
|
207
|
+
this.loginEffectDisposers.push(() => {
|
|
208
|
+
if (typeof effects.off === "function") {
|
|
209
|
+
effects.off(event, callback);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
registerCustomerLoginListeners() {
|
|
214
|
+
this.clearLoginEffectListeners();
|
|
215
|
+
const createHandleLogin = () => async (payload) => {
|
|
216
|
+
const customerId = this.resolveCustomerIdFromLoginPayload(payload);
|
|
217
|
+
if (!customerId)
|
|
218
|
+
return;
|
|
219
|
+
await this.refreshOrderMarketingAfterLogin({ customerId });
|
|
220
|
+
};
|
|
221
|
+
this.registerLoginEffect(
|
|
222
|
+
_ScanOrderImpl.PISELL1_LOGIN_SUCCESS,
|
|
223
|
+
createHandleLogin()
|
|
224
|
+
);
|
|
225
|
+
this.registerLoginEffect(import_types2.AccountHooks.OnLogin, createHandleLogin());
|
|
226
|
+
this.registerLoginEffect(
|
|
227
|
+
import_types3.RegisterAndLoginHooks.onLoginSuccess,
|
|
228
|
+
createHandleLogin()
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
async refreshOrderMarketingAfterLogin(params) {
|
|
232
|
+
if (!this.store.order)
|
|
233
|
+
throw new Error("order 模块未初始化");
|
|
234
|
+
if (this.customerLoginRefreshInFlight) {
|
|
235
|
+
if (this.customerLoginRefreshIdInFlight === params.customerId) {
|
|
236
|
+
await this.customerLoginRefreshInFlight;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
await this.customerLoginRefreshInFlight;
|
|
240
|
+
}
|
|
241
|
+
this.customerLoginRefreshIdInFlight = params.customerId;
|
|
242
|
+
const refreshTask = (async () => {
|
|
243
|
+
await this.store.order.loadDiscountConfig({
|
|
244
|
+
customerId: params.customerId
|
|
245
|
+
});
|
|
246
|
+
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
247
|
+
this.store.order.persistTempOrder();
|
|
248
|
+
await this.refreshItemRuleQuantityLimits();
|
|
249
|
+
await this.refreshCartValidationPassed();
|
|
250
|
+
})();
|
|
251
|
+
this.customerLoginRefreshInFlight = refreshTask;
|
|
252
|
+
try {
|
|
253
|
+
await refreshTask;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw error;
|
|
256
|
+
} finally {
|
|
257
|
+
if (this.customerLoginRefreshInFlight === refreshTask) {
|
|
258
|
+
this.customerLoginRefreshInFlight = null;
|
|
259
|
+
this.customerLoginRefreshIdInFlight = null;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
160
263
|
async initialize(core, options = {}) {
|
|
161
264
|
var _a, _b, _c, _d, _e, _f;
|
|
162
265
|
this.logMethodStart("initialize");
|
|
@@ -195,7 +298,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
195
298
|
];
|
|
196
299
|
moduleArr.forEach((step) => {
|
|
197
300
|
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
198
|
-
const targetModule = (0,
|
|
301
|
+
const targetModule = (0, import_types4.createModule)(step, this.name);
|
|
199
302
|
if (targetModule) {
|
|
200
303
|
this.store[step] = targetModule;
|
|
201
304
|
const initialState = step === "salesSummary" ? {
|
|
@@ -236,6 +339,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
236
339
|
fatherModule: this.name
|
|
237
340
|
}
|
|
238
341
|
});
|
|
342
|
+
this.registerCustomerLoginListeners();
|
|
239
343
|
console.log("[ScanOrder] 初始化开始");
|
|
240
344
|
try {
|
|
241
345
|
await ((_e = this.store.order) == null ? void 0 : _e.recalculateSummary({ createIfMissing: false }));
|
|
@@ -269,6 +373,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
269
373
|
}
|
|
270
374
|
async destroy() {
|
|
271
375
|
this.logMethodStart("destroy");
|
|
376
|
+
this.clearLoginEffectListeners();
|
|
272
377
|
await this.core.effects.emit(import_types.ScanOrderHooks.onDestroy, {});
|
|
273
378
|
console.log("[ScanOrder] 已销毁");
|
|
274
379
|
this.logMethodSuccess("destroy");
|
|
@@ -494,6 +599,127 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
494
599
|
throw error;
|
|
495
600
|
}
|
|
496
601
|
}
|
|
602
|
+
getDiscountList() {
|
|
603
|
+
if (!this.store.order)
|
|
604
|
+
return [];
|
|
605
|
+
return this.store.order.getDiscountList();
|
|
606
|
+
}
|
|
607
|
+
async scanCode(code, customerId) {
|
|
608
|
+
this.logMethodStart("scanCode", { code });
|
|
609
|
+
try {
|
|
610
|
+
if (!this.store.order)
|
|
611
|
+
throw new Error("order 模块未初始化");
|
|
612
|
+
const raw = await this.store.order.scanCode(code, customerId);
|
|
613
|
+
if (raw.isAvailable) {
|
|
614
|
+
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
615
|
+
this.store.order.persistTempOrder();
|
|
616
|
+
}
|
|
617
|
+
this.logMethodSuccess("scanCode", { isAvailable: raw.isAvailable });
|
|
618
|
+
return {
|
|
619
|
+
isAvailable: raw.isAvailable,
|
|
620
|
+
type: raw.type,
|
|
621
|
+
unavailableReason: raw.unavailableReason
|
|
622
|
+
};
|
|
623
|
+
} catch (error) {
|
|
624
|
+
this.logMethodError("scanCode", error);
|
|
625
|
+
throw error;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
async setDiscountSelected(params) {
|
|
629
|
+
var _a, _b, _c;
|
|
630
|
+
this.logMethodStart("setDiscountSelected", params);
|
|
631
|
+
try {
|
|
632
|
+
if (!this.store.order)
|
|
633
|
+
throw new Error("order 模块未初始化");
|
|
634
|
+
const list = this.store.order.getDiscountList();
|
|
635
|
+
const updated = list.map(
|
|
636
|
+
(d) => d.id === params.discountId ? {
|
|
637
|
+
...d,
|
|
638
|
+
isSelected: params.isSelected,
|
|
639
|
+
isManualSelect: !params.isSelected
|
|
640
|
+
} : d
|
|
641
|
+
);
|
|
642
|
+
const tempOrder = this.store.order.ensureTempOrder();
|
|
643
|
+
const orderStore = this.store.order.store || {};
|
|
644
|
+
const discountModule = orderStore.discount;
|
|
645
|
+
const rulesModule = orderStore.rules;
|
|
646
|
+
const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
|
|
647
|
+
let nextDiscountList = updated;
|
|
648
|
+
await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
|
|
649
|
+
if (rulesModule) {
|
|
650
|
+
const result = rulesModule.calcDiscount(
|
|
651
|
+
{
|
|
652
|
+
productList: tempOrder.products,
|
|
653
|
+
discountList: updated,
|
|
654
|
+
holders,
|
|
655
|
+
isFormSubject: !!((_b = tempOrder.holder) == null ? void 0 : _b.type) && tempOrder.holder.type === "form"
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
discountId: params.discountId,
|
|
659
|
+
isSelected: params.isSelected
|
|
660
|
+
}
|
|
661
|
+
) || { productList: tempOrder.products, discountList: updated };
|
|
662
|
+
if (result == null ? void 0 : result.productList) {
|
|
663
|
+
tempOrder.products = result.productList;
|
|
664
|
+
}
|
|
665
|
+
if (result == null ? void 0 : result.discountList) {
|
|
666
|
+
nextDiscountList = result.discountList;
|
|
667
|
+
if (!params.isSelected) {
|
|
668
|
+
const beforeSelectedIds = new Set(
|
|
669
|
+
updated.filter((d) => d.isSelected).map((d) => d.id)
|
|
670
|
+
);
|
|
671
|
+
for (const d of nextDiscountList) {
|
|
672
|
+
if (d.isSelected && !beforeSelectedIds.has(d.id)) {
|
|
673
|
+
d.isSelected = false;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
const selectedResourceIds = new Set(
|
|
680
|
+
nextDiscountList.filter((d) => d.isSelected).map((d) => d.id)
|
|
681
|
+
);
|
|
682
|
+
for (const product of tempOrder.products) {
|
|
683
|
+
if ((_c = product._origin) == null ? void 0 : _c.isManualDiscount)
|
|
684
|
+
continue;
|
|
685
|
+
product.discount_list = (product.discount_list || []).filter((pd) => {
|
|
686
|
+
var _a2;
|
|
687
|
+
const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
|
|
688
|
+
return rid != null && selectedResourceIds.has(rid);
|
|
689
|
+
});
|
|
690
|
+
const totalPerUnitDiscount = (product.discount_list || []).reduce(
|
|
691
|
+
(sum, pd) => sum + (pd.amount || 0),
|
|
692
|
+
0
|
|
693
|
+
);
|
|
694
|
+
const newSellingPrice = new import_decimal.default(product.original_price || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
|
|
695
|
+
product.selling_price = newSellingPrice;
|
|
696
|
+
if (product.metadata) {
|
|
697
|
+
product.metadata.main_product_selling_price = newSellingPrice;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
import_Order.OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
|
|
701
|
+
await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
|
|
702
|
+
tempOrder.discount_list = (nextDiscountList || []).filter((d) => d.isSelected);
|
|
703
|
+
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
704
|
+
this.store.order.persistTempOrder();
|
|
705
|
+
this.logMethodSuccess("setDiscountSelected", params);
|
|
706
|
+
} catch (error) {
|
|
707
|
+
this.logMethodError("setDiscountSelected", error);
|
|
708
|
+
throw error;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async onCustomerLogin(params) {
|
|
712
|
+
this.logMethodStart("onCustomerLogin", { customerId: params.customerId });
|
|
713
|
+
try {
|
|
714
|
+
await this.refreshOrderMarketingAfterLogin({
|
|
715
|
+
customerId: params.customerId
|
|
716
|
+
});
|
|
717
|
+
this.logMethodSuccess("onCustomerLogin", { customerId: params.customerId });
|
|
718
|
+
} catch (error) {
|
|
719
|
+
this.logMethodError("onCustomerLogin", error);
|
|
720
|
+
throw error;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
497
723
|
// ScanOrder 提交 payload enhancer:
|
|
498
724
|
// - 给所有 booking 注入 appointment_status: 'started'(扫码点餐语义)
|
|
499
725
|
// - 给所有 booking 的 metadata 注入 resource_select_type(来自预约规则商品的 resource.type)
|
|
@@ -515,7 +741,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
515
741
|
return 1;
|
|
516
742
|
};
|
|
517
743
|
return (payload, { bookingUuid, tempOrder }) => {
|
|
518
|
-
var _a;
|
|
744
|
+
var _a, _b;
|
|
519
745
|
const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
|
|
520
746
|
const pickOriginal = (value) => {
|
|
521
747
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
@@ -536,20 +762,31 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
536
762
|
metadata: {}
|
|
537
763
|
} : void 0;
|
|
538
764
|
const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
|
|
539
|
-
const
|
|
765
|
+
const rawCollectPax = (_b = tempOrder.metadata) == null ? void 0 : _b.collect_pax;
|
|
766
|
+
const hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== void 0 && rawCollectPax !== "";
|
|
767
|
+
const bookingCapacityValue = hasCollectPaxForCapacity ? (0, import_utils2.normalizeSubmitCollectPaxValue)(rawCollectPax) : resolveResourceCapacity();
|
|
768
|
+
const bookingCapacityDimensionId = (0, import_utils.pickFirstCustomCapacityDimensionId)(this.enabledReservationRuleProducts) ?? 0;
|
|
540
769
|
const nextBookings = (payload.bookings || []).map((booking, idx) => ({
|
|
541
770
|
...booking,
|
|
542
771
|
appointment_status: "started",
|
|
543
772
|
metadata: {
|
|
544
773
|
...booking.metadata || {},
|
|
545
774
|
...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
|
|
546
|
-
...resourceSelectType ? {
|
|
775
|
+
...resourceSelectType ? {
|
|
776
|
+
capacity: [
|
|
777
|
+
{
|
|
778
|
+
id: bookingCapacityDimensionId,
|
|
779
|
+
value: bookingCapacityValue,
|
|
780
|
+
name: ""
|
|
781
|
+
}
|
|
782
|
+
]
|
|
783
|
+
} : {}
|
|
547
784
|
},
|
|
548
785
|
...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
|
|
549
786
|
...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
|
|
550
787
|
}));
|
|
551
788
|
const nextProducts = [...payload.products || []];
|
|
552
|
-
if (ruleProduct && ruleProductUid) {
|
|
789
|
+
if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
|
|
553
790
|
const sellingPrice = String(ruleProduct.price ?? "0.00");
|
|
554
791
|
const originalPrice = String(
|
|
555
792
|
ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
|
|
@@ -1035,7 +1272,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1035
1272
|
const relationId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_record_id);
|
|
1036
1273
|
const tableFormId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_id);
|
|
1037
1274
|
const formRecord = (detail == null ? void 0 : detail.form_record) ?? null;
|
|
1038
|
-
const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["
|
|
1275
|
+
const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["sale.allow_add_items"]) || false;
|
|
1039
1276
|
const deskmateValid = false;
|
|
1040
1277
|
const isExclusive = resourceSelectType === "single";
|
|
1041
1278
|
const isFull = (0, import_utils.computeResourceIsFull)({
|
|
@@ -1394,10 +1631,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1394
1631
|
readUIStateBucket() {
|
|
1395
1632
|
var _a;
|
|
1396
1633
|
const key = this.getUIStateBucketKey();
|
|
1397
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1634
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1398
1635
|
return {};
|
|
1399
1636
|
try {
|
|
1400
|
-
const raw = this.window.
|
|
1637
|
+
const raw = this.window.localStorage.getItem(key) || "{}";
|
|
1401
1638
|
const parsed = JSON.parse(raw);
|
|
1402
1639
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
1403
1640
|
} catch {
|
|
@@ -1407,10 +1644,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1407
1644
|
writeUIStateBucket(bucket) {
|
|
1408
1645
|
var _a;
|
|
1409
1646
|
const key = this.getUIStateBucketKey();
|
|
1410
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1647
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1411
1648
|
return;
|
|
1412
1649
|
try {
|
|
1413
|
-
this.window.
|
|
1650
|
+
this.window.localStorage.setItem(key, JSON.stringify(bucket));
|
|
1414
1651
|
} catch (error) {
|
|
1415
1652
|
console.warn("[ScanOrder] writeUIStateBucket failed", error);
|
|
1416
1653
|
}
|
|
@@ -1441,10 +1678,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1441
1678
|
clearUIState() {
|
|
1442
1679
|
var _a;
|
|
1443
1680
|
const key = this.getUIStateBucketKey();
|
|
1444
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1681
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1445
1682
|
return;
|
|
1446
1683
|
try {
|
|
1447
|
-
this.window.
|
|
1684
|
+
this.window.localStorage.removeItem(key);
|
|
1448
1685
|
} catch (error) {
|
|
1449
1686
|
console.warn("[ScanOrder] clearUIState failed", error);
|
|
1450
1687
|
}
|
|
@@ -1499,11 +1736,19 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1499
1736
|
}
|
|
1500
1737
|
};
|
|
1501
1738
|
var ScanOrderImpl = _ScanOrderImpl;
|
|
1502
|
-
|
|
1739
|
+
ScanOrderImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
|
|
1740
|
+
// ─── UI 状态缓存(按 cacheId 分桶,localStorage) ───
|
|
1503
1741
|
//
|
|
1504
1742
|
// 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
|
|
1505
1743
|
// 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
|
|
1506
1744
|
// 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
|
|
1745
|
+
//
|
|
1746
|
+
// 之所以用 localStorage 而不是 sessionStorage:
|
|
1747
|
+
// 1. 与 Order 模块 openCache 下的 tempOrder 同栈,购物车在 / UIState 在,行为对齐;
|
|
1748
|
+
// 2. pisell1.login 整页 OAuth 跳转在 H5 壳 / iOS Safari 场景下可能丢 sessionStorage,
|
|
1749
|
+
// 导致登录回跳后 gate 标记失效、pax 弹窗重开、落点错误;localStorage 稳定不受影响。
|
|
1750
|
+
// 3. 失效由上层显式控制:提交成功 clearStepCache / entryContext 不一致 clearUIState /
|
|
1751
|
+
// pendingStep 登录回调 deleteUIState,足够约束生命周期。
|
|
1507
1752
|
ScanOrderImpl.UI_STATE_KEY_PREFIX = "pisell.scanOrder.uiState:";
|
|
1508
1753
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1509
1754
|
0 && (module.exports = {
|
|
@@ -235,3 +235,9 @@ export interface ScanOrderLoggerRuntimeConfig {
|
|
|
235
235
|
}
|
|
236
236
|
export interface ScanOrderAddLogParams extends ScanOrderLogInput {
|
|
237
237
|
}
|
|
238
|
+
/** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
|
|
239
|
+
export interface ScanOrderScanCodeResult {
|
|
240
|
+
isAvailable: boolean;
|
|
241
|
+
type?: 'server' | string;
|
|
242
|
+
unavailableReason?: 'time_limit' | string;
|
|
243
|
+
}
|
|
@@ -129,3 +129,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
|
|
|
129
129
|
min?: number;
|
|
130
130
|
max?: number;
|
|
131
131
|
} | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
134
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
135
|
+
*/
|
|
136
|
+
export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
|
|
@@ -47,6 +47,7 @@ __export(utils_exports, {
|
|
|
47
47
|
normalizeEnabledItemRuleIds: () => normalizeEnabledItemRuleIds,
|
|
48
48
|
normalizeItemRuleStrategies: () => normalizeItemRuleStrategies,
|
|
49
49
|
normalizeOrderProduct: () => normalizeOrderProduct,
|
|
50
|
+
pickFirstCustomCapacityDimensionId: () => pickFirstCustomCapacityDimensionId,
|
|
50
51
|
pickFirstCustomCapacityPaxBounds: () => pickFirstCustomCapacityPaxBounds,
|
|
51
52
|
pickFirstDurationMinutesFromProducts: () => pickFirstDurationMinutesFromProducts,
|
|
52
53
|
resolveSkuMatchedQuantityLimits: () => resolveSkuMatchedQuantityLimits,
|
|
@@ -474,6 +475,30 @@ function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
474
475
|
}
|
|
475
476
|
return void 0;
|
|
476
477
|
}
|
|
478
|
+
function pickFirstCustomCapacityDimensionId(products) {
|
|
479
|
+
for (const p of products) {
|
|
480
|
+
const cap = p == null ? void 0 : p.capacity;
|
|
481
|
+
if (!cap || cap.type !== "custom")
|
|
482
|
+
continue;
|
|
483
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0)
|
|
484
|
+
continue;
|
|
485
|
+
const row = cap.custom[0];
|
|
486
|
+
if (!row || typeof row !== "object")
|
|
487
|
+
continue;
|
|
488
|
+
const id = row.id;
|
|
489
|
+
if (id === null || id === void 0 || id === "")
|
|
490
|
+
continue;
|
|
491
|
+
if (typeof id === "number" && Number.isFinite(id))
|
|
492
|
+
return id;
|
|
493
|
+
if (typeof id === "string") {
|
|
494
|
+
const trimmed = id.trim();
|
|
495
|
+
if (!trimmed)
|
|
496
|
+
continue;
|
|
497
|
+
return trimmed;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return void 0;
|
|
501
|
+
}
|
|
477
502
|
// Annotate the CommonJS export names for ESM import in node:
|
|
478
503
|
0 && (module.exports = {
|
|
479
504
|
aggregateItemRuleLimit,
|
|
@@ -494,6 +519,7 @@ function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
494
519
|
normalizeEnabledItemRuleIds,
|
|
495
520
|
normalizeItemRuleStrategies,
|
|
496
521
|
normalizeOrderProduct,
|
|
522
|
+
pickFirstCustomCapacityDimensionId,
|
|
497
523
|
pickFirstCustomCapacityPaxBounds,
|
|
498
524
|
pickFirstDurationMinutesFromProducts,
|
|
499
525
|
resolveSkuMatchedQuantityLimits,
|