@pisell/pisellos 2.2.302 → 2.2.303
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/dist/model/strategy/adapter/itemRule/type.js +19 -1
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
- package/dist/modules/Discount/index.d.ts +2 -0
- package/dist/modules/Discount/index.js +41 -5
- package/dist/modules/Discount/types.d.ts +21 -0
- package/dist/modules/OpenData/index.d.ts +15 -2
- package/dist/modules/OpenData/index.js +307 -19
- package/dist/modules/OpenData/types.d.ts +55 -0
- package/dist/modules/OpenData/types.js +7 -1
- package/dist/modules/OpenData/utils.d.ts +21 -1
- package/dist/modules/OpenData/utils.js +138 -0
- package/dist/modules/Order/index.d.ts +50 -7
- package/dist/modules/Order/index.js +1690 -815
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +117 -10
- package/dist/modules/Order/types.js +6 -1
- package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/dist/modules/Order/utils/virtualSettlement.js +284 -0
- package/dist/modules/Order/utils.d.ts +5 -1
- package/dist/modules/Order/utils.js +138 -33
- package/dist/modules/Payment/walletpass.js +20 -21
- package/dist/modules/Product/types.d.ts +23 -0
- package/dist/modules/ProductList/index.d.ts +2 -1
- package/dist/modules/ProductList/index.js +100 -20
- package/dist/modules/ProductList/types.d.ts +10 -0
- package/dist/modules/Rules/index.d.ts +5 -0
- package/dist/modules/Rules/index.js +30 -14
- package/dist/modules/SalesSummary/index.d.ts +1 -0
- package/dist/modules/SalesSummary/index.js +4 -3
- package/dist/modules/SalesSummary/types.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.js +21 -1
- package/dist/plugins/request.d.ts +2 -1
- package/dist/plugins/request.js +4 -2
- package/dist/server/index.d.ts +21 -0
- package/dist/server/index.js +1774 -1285
- package/dist/server/modules/order/types.d.ts +50 -0
- package/dist/server/modules/order/types.js +2 -0
- package/dist/server/utils/small-ticket.d.ts +4 -1
- package/dist/server/utils/small-ticket.js +461 -96
- package/dist/solution/BaseSales/index.d.ts +24 -3
- package/dist/solution/BaseSales/index.js +1484 -873
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +22 -5
- package/dist/solution/BookingTicket/index.js +558 -443
- package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
- package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
- package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
- package/dist/solution/RegisterAndLogin/config.js +95 -40
- package/dist/solution/RegisterAndLogin/index.js +4 -1
- package/dist/solution/Sales/index.d.ts +16 -1
- package/dist/solution/Sales/index.js +338 -63
- package/dist/solution/Sales/types.d.ts +10 -0
- package/dist/solution/ScanOrder/index.d.ts +1 -0
- package/dist/solution/ScanOrder/index.js +31 -27
- package/dist/solution/ScanOrder/utils.d.ts +1 -0
- package/dist/solution/ScanOrder/utils.js +2 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/dist/solution/UnifiedBookingSales/index.js +874 -527
- package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
- package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/lib/model/strategy/adapter/itemRule/type.js +19 -1
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
- package/lib/modules/Discount/index.d.ts +2 -0
- package/lib/modules/Discount/index.js +34 -2
- package/lib/modules/Discount/types.d.ts +21 -0
- package/lib/modules/OpenData/index.d.ts +15 -2
- package/lib/modules/OpenData/index.js +230 -3
- package/lib/modules/OpenData/types.d.ts +55 -0
- package/lib/modules/OpenData/types.js +9 -1
- package/lib/modules/OpenData/utils.d.ts +21 -1
- package/lib/modules/OpenData/utils.js +126 -0
- package/lib/modules/Order/index.d.ts +50 -7
- package/lib/modules/Order/index.js +704 -64
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +117 -10
- package/lib/modules/Order/types.js +5 -1
- package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/lib/modules/Order/utils/virtualSettlement.js +262 -0
- package/lib/modules/Order/utils.d.ts +5 -1
- package/lib/modules/Order/utils.js +127 -21
- package/lib/modules/Payment/walletpass.js +14 -11
- package/lib/modules/Product/types.d.ts +23 -0
- package/lib/modules/ProductList/index.d.ts +2 -1
- package/lib/modules/ProductList/index.js +47 -2
- package/lib/modules/ProductList/types.d.ts +10 -0
- package/lib/modules/Rules/index.d.ts +5 -0
- package/lib/modules/Rules/index.js +22 -12
- package/lib/modules/SalesSummary/index.d.ts +1 -0
- package/lib/modules/SalesSummary/index.js +4 -2
- package/lib/modules/SalesSummary/types.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.js +17 -1
- package/lib/plugins/request.d.ts +2 -1
- package/lib/plugins/request.js +3 -2
- package/lib/server/index.d.ts +21 -0
- package/lib/server/index.js +492 -108
- package/lib/server/modules/order/types.d.ts +50 -0
- package/lib/server/modules/order/types.js +1 -0
- package/lib/server/utils/small-ticket.d.ts +4 -1
- package/lib/server/utils/small-ticket.js +427 -72
- package/lib/solution/BaseSales/index.d.ts +24 -3
- package/lib/solution/BaseSales/index.js +433 -30
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +22 -5
- package/lib/solution/BookingTicket/index.js +60 -15
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
- package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
- package/lib/solution/RegisterAndLogin/config.js +49 -8
- package/lib/solution/RegisterAndLogin/index.js +4 -1
- package/lib/solution/Sales/index.d.ts +16 -1
- package/lib/solution/Sales/index.js +168 -1
- package/lib/solution/Sales/types.d.ts +10 -0
- package/lib/solution/ScanOrder/index.d.ts +1 -0
- package/lib/solution/ScanOrder/index.js +5 -1
- package/lib/solution/ScanOrder/utils.d.ts +1 -0
- package/lib/solution/ScanOrder/utils.js +1 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/lib/solution/UnifiedBookingSales/index.js +169 -16
- package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ var _exportNames = {
|
|
|
9
9
|
};
|
|
10
10
|
exports.default = exports.SalesImpl = exports.Sales = void 0;
|
|
11
11
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
12
|
+
var _lodashEs = require("lodash-es");
|
|
12
13
|
var _BaseModule = require("../../modules/BaseModule");
|
|
13
14
|
var _types = require("./types");
|
|
14
15
|
Object.keys(_types).forEach(function (key) {
|
|
@@ -22,8 +23,11 @@ Object.keys(_types).forEach(function (key) {
|
|
|
22
23
|
}
|
|
23
24
|
});
|
|
24
25
|
});
|
|
26
|
+
var _OpenData = require("../../modules/OpenData");
|
|
25
27
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
26
28
|
const UNPAID_PAYMENT_STATUSES = new Set(['unpaid', 'partially_paid', 'payment_processing']);
|
|
29
|
+
const INVOICE_OPEN_DATA_SECTION_CODES = ['documents'];
|
|
30
|
+
const INVOICE_OPEN_DATA_CACHE_TTL = 5 * 60 * 1000;
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Sales 解决方案基础骨架
|
|
@@ -46,11 +50,22 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
46
50
|
otherParams = {};
|
|
47
51
|
request;
|
|
48
52
|
logger; // LoggerManager 实例
|
|
49
|
-
|
|
53
|
+
invoiceOpenDataModule = null;
|
|
54
|
+
invoiceOpenDataTarget = null;
|
|
55
|
+
invoiceOpenDataInFlight = null;
|
|
56
|
+
invoiceOpenDataInFlightTarget = null;
|
|
50
57
|
constructor(name, version) {
|
|
51
58
|
super(name, version);
|
|
52
59
|
}
|
|
53
60
|
async initialize(core, options = {}) {
|
|
61
|
+
if (this.invoiceOpenDataModule) {
|
|
62
|
+
try {
|
|
63
|
+
this.clearOpenDataCache();
|
|
64
|
+
this.invoiceOpenDataModule.destroy();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.warn('[Sales] 旧 Invoice OpenData 子模块销毁失败', error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
54
69
|
this.core = core;
|
|
55
70
|
this.options = options;
|
|
56
71
|
this.otherParams = options.otherParams || {};
|
|
@@ -71,6 +86,18 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
71
86
|
// 在这里补充从 Server/Order 读取 currentDay 原始数据并转换为预约列表。
|
|
72
87
|
|
|
73
88
|
this.logger = appPlugin?.getApp().logger;
|
|
89
|
+
this.invoiceOpenDataTarget = null;
|
|
90
|
+
this.invoiceOpenDataInFlight = null;
|
|
91
|
+
this.invoiceOpenDataInFlightTarget = null;
|
|
92
|
+
this.invoiceOpenDataModule = new _OpenData.OpenDataModule(`${this.name}_invoiceOpenData`);
|
|
93
|
+
this.core.registerModule(this.invoiceOpenDataModule, {
|
|
94
|
+
initialState: {},
|
|
95
|
+
otherParams: {
|
|
96
|
+
fatherModule: this.name,
|
|
97
|
+
openCache: false,
|
|
98
|
+
platform: this.otherParams?.platform
|
|
99
|
+
}
|
|
100
|
+
});
|
|
74
101
|
await this.core.effects.emit(`${this.name}:onInited`, {});
|
|
75
102
|
}
|
|
76
103
|
|
|
@@ -139,11 +166,151 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
139
166
|
return orderModule.changeBookingStatus(params);
|
|
140
167
|
}
|
|
141
168
|
|
|
169
|
+
/**
|
|
170
|
+
* 将显式 channel 或当前运行上下文归一为 Invoice OpenData 使用的销售入口。
|
|
171
|
+
* Legacy Sales 的系统上下文没有可打印的 system target,因此统一回退 pos。
|
|
172
|
+
*/
|
|
173
|
+
getInvoiceSalesChannel(channel) {
|
|
174
|
+
const contextChannel = this.core?.context?.getChannel?.();
|
|
175
|
+
const normalized = String(channel ?? contextChannel ?? '').trim();
|
|
176
|
+
return !normalized || normalized === 'system' ? 'pos' : normalized;
|
|
177
|
+
}
|
|
178
|
+
async loadInvoiceOpenData(businessCode, channel) {
|
|
179
|
+
if (!this.invoiceOpenDataModule) {
|
|
180
|
+
throw new Error('Sales Invoice OpenData 模块未初始化');
|
|
181
|
+
}
|
|
182
|
+
const target = `${businessCode}+${channel}`;
|
|
183
|
+
const cachedData = this.invoiceOpenDataModule.getOpenData();
|
|
184
|
+
const lastFetchedAt = this.invoiceOpenDataModule.getLastFetchedAt();
|
|
185
|
+
if (cachedData && this.invoiceOpenDataTarget === target && typeof lastFetchedAt === 'number' && Date.now() - lastFetchedAt < INVOICE_OPEN_DATA_CACHE_TTL) {
|
|
186
|
+
if (typeof this.invoiceOpenDataModule.ensureInvoiceTemplateSettings === 'function') {
|
|
187
|
+
await this.invoiceOpenDataModule.ensureInvoiceTemplateSettings(target);
|
|
188
|
+
}
|
|
189
|
+
return cachedData;
|
|
190
|
+
}
|
|
191
|
+
if (this.invoiceOpenDataInFlight) {
|
|
192
|
+
if (this.invoiceOpenDataInFlightTarget === target) {
|
|
193
|
+
return this.invoiceOpenDataInFlight;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
await this.invoiceOpenDataInFlight;
|
|
197
|
+
} catch {
|
|
198
|
+
// 另一 target 的失败不应阻断当前 target 获取自己的 Documents 配置。
|
|
199
|
+
}
|
|
200
|
+
return this.loadInvoiceOpenData(businessCode, channel);
|
|
201
|
+
}
|
|
202
|
+
const request = this.invoiceOpenDataModule.fetchOpenData({
|
|
203
|
+
scope: 'board',
|
|
204
|
+
target,
|
|
205
|
+
section_code: [...INVOICE_OPEN_DATA_SECTION_CODES]
|
|
206
|
+
});
|
|
207
|
+
this.invoiceOpenDataInFlight = request;
|
|
208
|
+
this.invoiceOpenDataInFlightTarget = target;
|
|
209
|
+
try {
|
|
210
|
+
const openData = await request;
|
|
211
|
+
// clearOpenDataCache() 或后续请求接管后,旧响应不得复活 target 归属。
|
|
212
|
+
if (this.invoiceOpenDataInFlight === request) {
|
|
213
|
+
this.invoiceOpenDataTarget = target;
|
|
214
|
+
}
|
|
215
|
+
return openData;
|
|
216
|
+
} finally {
|
|
217
|
+
if (this.invoiceOpenDataInFlight === request) {
|
|
218
|
+
this.invoiceOpenDataInFlight = null;
|
|
219
|
+
this.invoiceOpenDataInFlightTarget = null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
logInvoiceOpenDataFallback(error) {
|
|
224
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
225
|
+
if (this.logger?.addLog) {
|
|
226
|
+
this.logger.addLog({
|
|
227
|
+
type: 'warning',
|
|
228
|
+
title: 'Sales Invoice OpenData 加载失败,使用默认配置',
|
|
229
|
+
metadata: {
|
|
230
|
+
message
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
console.warn('[Sales] Invoice OpenData 加载失败,使用默认配置', error);
|
|
236
|
+
}
|
|
237
|
+
async resolveInvoiceConfigs(businessCode, channel) {
|
|
238
|
+
try {
|
|
239
|
+
await this.loadInvoiceOpenData(businessCode, channel);
|
|
240
|
+
if (this.invoiceOpenDataTarget !== `${businessCode}+${channel}`) {
|
|
241
|
+
return {
|
|
242
|
+
invoice: (0, _OpenData.getDefaultInvoiceLayoutConfig)(),
|
|
243
|
+
templateSettings: (0, _OpenData.getDefaultInvoiceTemplateSettings)()
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
invoice: this.invoiceOpenDataModule?.getInvoiceLayoutConfig() ?? (0, _OpenData.getDefaultInvoiceLayoutConfig)(),
|
|
248
|
+
templateSettings: this.invoiceOpenDataModule?.getInvoiceTemplateSettings() ?? (0, _OpenData.getDefaultInvoiceTemplateSettings)()
|
|
249
|
+
};
|
|
250
|
+
} catch (error) {
|
|
251
|
+
this.logInvoiceOpenDataFallback(error);
|
|
252
|
+
return {
|
|
253
|
+
invoice: (0, _OpenData.getDefaultInvoiceLayoutConfig)(),
|
|
254
|
+
templateSettings: (0, _OpenData.getDefaultInvoiceTemplateSettings)()
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async printLocalOrderReceipt(lookup, options) {
|
|
259
|
+
const normalizedLookup = typeof lookup === 'string' ? lookup.trim() : lookup;
|
|
260
|
+
if (normalizedLookup === '' || normalizedLookup === null || normalizedLookup === undefined) {
|
|
261
|
+
throw new Error('Sales 本地小票打印需要订单标识');
|
|
262
|
+
}
|
|
263
|
+
const businessCode = String(options?.businessCode ?? '').trim();
|
|
264
|
+
if (!businessCode) {
|
|
265
|
+
throw new Error('Sales 本地小票打印需要 businessCode');
|
|
266
|
+
}
|
|
267
|
+
const channel = this.getInvoiceSalesChannel(options?.channel);
|
|
268
|
+
const {
|
|
269
|
+
invoice,
|
|
270
|
+
templateSettings
|
|
271
|
+
} = await this.resolveInvoiceConfigs(businessCode, channel);
|
|
272
|
+
const lookupPayload = typeof normalizedLookup === 'number' ? {
|
|
273
|
+
order_id: normalizedLookup
|
|
274
|
+
} : {
|
|
275
|
+
external_sale_number: normalizedLookup
|
|
276
|
+
};
|
|
277
|
+
return this.request.post('/local/print-order', {
|
|
278
|
+
...lookupPayload,
|
|
279
|
+
lookup_order_from_db: 1,
|
|
280
|
+
small_ticket_data_flag: 1,
|
|
281
|
+
business_code: businessCode,
|
|
282
|
+
order_sales_channel: channel,
|
|
283
|
+
invoice: (0, _lodashEs.cloneDeep)(invoice),
|
|
284
|
+
template_settings: (0, _lodashEs.cloneDeep)(templateSettings)
|
|
285
|
+
}, {
|
|
286
|
+
osServer: true,
|
|
287
|
+
customToast: () => {}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** 清除独立 Documents 缓存;下一次打印会按当前 target 重新获取。 */
|
|
292
|
+
clearOpenDataCache() {
|
|
293
|
+
this.invoiceOpenDataInFlight = null;
|
|
294
|
+
this.invoiceOpenDataInFlightTarget = null;
|
|
295
|
+
this.invoiceOpenDataTarget = null;
|
|
296
|
+
this.invoiceOpenDataModule?.clearCache();
|
|
297
|
+
}
|
|
298
|
+
|
|
142
299
|
// -------------------------------------------------------------------------
|
|
143
300
|
// 生命周期
|
|
144
301
|
// -------------------------------------------------------------------------
|
|
145
302
|
|
|
146
303
|
async destroy() {
|
|
304
|
+
this.clearOpenDataCache();
|
|
305
|
+
const invoiceOpenDataModule = this.invoiceOpenDataModule;
|
|
306
|
+
this.invoiceOpenDataModule = null;
|
|
307
|
+
if (invoiceOpenDataModule) {
|
|
308
|
+
try {
|
|
309
|
+
await invoiceOpenDataModule.destroy();
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.warn('[Sales] Invoice OpenData 子模块销毁失败', error);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
147
314
|
await this.core.effects.emit(`${this.name}:onDestroy`, {});
|
|
148
315
|
super.destroy();
|
|
149
316
|
}
|
|
@@ -50,6 +50,12 @@ export interface GetResourceBookingItemParams {
|
|
|
50
50
|
bookingList: BookingData[];
|
|
51
51
|
deviceTime?: string;
|
|
52
52
|
}
|
|
53
|
+
export interface SalesPrintLocalOrderReceiptOptions {
|
|
54
|
+
/** 当前销售业务类型,用于隔离 Documents Invoice 配置。 */
|
|
55
|
+
businessCode: string;
|
|
56
|
+
/** 当前销售入口;缺失或为 system 时按 pos 处理。 */
|
|
57
|
+
channel?: string;
|
|
58
|
+
}
|
|
53
59
|
/**
|
|
54
60
|
* Sales 解决方案状态
|
|
55
61
|
*
|
|
@@ -82,6 +88,10 @@ export interface SalesModuleAPI {
|
|
|
82
88
|
cancelOrder: (orderIds: Array<number | string>) => Promise<any>;
|
|
83
89
|
/** 变更预约状态 */
|
|
84
90
|
changeBookingStatus: (params: ChangeBookingStatusParams) => Promise<any>;
|
|
91
|
+
/** 按本地订单标识打印小票;本地未命中时由 OS Server 负责远端兜底。 */
|
|
92
|
+
printLocalOrderReceipt: <T = any>(lookup: string | number, options: SalesPrintLocalOrderReceiptOptions) => Promise<T>;
|
|
93
|
+
/** 清除 Legacy Sales 独立维护的 Documents OpenData 缓存。 */
|
|
94
|
+
clearOpenDataCache: () => void;
|
|
85
95
|
/** 获取资源维度的预约占用列表 */
|
|
86
96
|
getResourceBookingList: (currentTime: string, bookingList: BookingData[], deviceTime?: string) => Promise<SalesResourceBookingItem[]>;
|
|
87
97
|
/** 获取单个资源维度的预约占用、已完成、未支付列表 */
|
|
@@ -1200,7 +1200,11 @@ class ScanOrderImpl extends _BaseSales.BaseSalesImpl {
|
|
|
1200
1200
|
return sourceMap;
|
|
1201
1201
|
}
|
|
1202
1202
|
getItemRuleRuntimeConfig() {
|
|
1203
|
-
|
|
1203
|
+
const runtimeConfig = this.itemRuleRuntimeConfig || {};
|
|
1204
|
+
return {
|
|
1205
|
+
...runtimeConfig,
|
|
1206
|
+
channel: runtimeConfig.channel ?? runtimeConfig.custom?.channel ?? this.otherParams?.channel
|
|
1207
|
+
};
|
|
1204
1208
|
}
|
|
1205
1209
|
async ensureItemRuleConfigsLoaded() {
|
|
1206
1210
|
if (this.itemRuleConfigs.length > 0) return this.itemRuleConfigs;
|
|
@@ -333,6 +333,7 @@ function buildItemRuleBusinessData(params) {
|
|
|
333
333
|
cartItems,
|
|
334
334
|
historicalItems,
|
|
335
335
|
serviceType: runtimeConfig.serviceType || 'dine-in',
|
|
336
|
+
channel: runtimeConfig.channel ?? runtimeConfig.custom?.channel,
|
|
336
337
|
submissionIndex: typeof runtimeConfig.submissionIndex === 'number' ? toNonNegativeInt(runtimeConfig.submissionIndex) : tempOrder.order_id ? 1 : 0,
|
|
337
338
|
custom: runtimeConfig.custom || {},
|
|
338
339
|
strategyConfigs: itemRuleConfigs
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import type { ProductData } from '../../modules';
|
|
3
|
-
import type
|
|
3
|
+
import { type InvoiceLayoutConfig, type InvoiceTemplateSettings, type OpenDataConfig } from '../../modules/OpenData';
|
|
4
4
|
import type { LoadScheduleAvailableDateParams, ScheduleItem } from '../../modules/Schedule/types';
|
|
5
|
-
import type { ProductListLoadProductsParams } from '../../modules/ProductList';
|
|
5
|
+
import type { ProductListLoadProductsParams, ProductListStoreQueryParams } from '../../modules/ProductList';
|
|
6
6
|
import type { AvailabilityDateRange, AvailabilityOccupancy, AvailabilityProduct, AvailabilityResource, GetProductTimeRangesRequest } from '../../modules/ResourcePlanner';
|
|
7
|
-
import type { AvailabilityContextRef, ContextualAvailabilityQuery, ContextualAvailabilityQueryResult, ContextualCommitAvailabilitySelectionParams, ContextualProductTimeRangeGroup, UnifiedBookingSalesAddRetailProductParams, UnifiedBookingSalesApplyPlannerDiscountsParams, UnifiedBookingSalesCommitAvailabilitySelectionResult, UnifiedBookingSalesDiscountResult, UnifiedBookingSalesLoadProductsByScheduleDateParams, UnifiedBookingSalesLoadOpenDataParams, UnifiedBookingSalesPrepareAvailabilityProjectionParams, UnifiedBookingSalesPolicyResponse, UnifiedBookingSalesStageRetailProductsParams, UnifiedBookingSalesState } from './types';
|
|
7
|
+
import type { AvailabilityContextRef, ContextualAvailabilityQuery, ContextualAvailabilityQueryResult, ContextualCommitAvailabilitySelectionParams, ContextualProductTimeRangeGroup, UnifiedBookingSalesAddRetailProductParams, UnifiedBookingSalesApplyPlannerDiscountsParams, UnifiedBookingSalesCommitAvailabilitySelectionResult, UnifiedBookingSalesDiscountResult, UnifiedBookingSalesLoadProductsByScheduleDateParams, UnifiedBookingSalesLoadOpenDataParams, UnifiedBookingSalesPrepareAvailabilityProjectionParams, UnifiedBookingSalesPolicyResponse, UnifiedBookingSalesResolveProductAllergyRequirementParams, UnifiedBookingSalesStageRetailProductsParams, UnifiedBookingSalesState } from './types';
|
|
8
8
|
import { BookingTicket } from '../BookingTicket';
|
|
9
|
+
import type { AllergyRequirement } from '../../model/strategy/adapter/itemRule';
|
|
9
10
|
export * from './types';
|
|
10
11
|
export { AvailabilityError } from '../../modules/ResourcePlanner';
|
|
11
12
|
/**
|
|
@@ -59,9 +60,6 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
59
60
|
protected defaultVersion: string;
|
|
60
61
|
protected store: UnifiedBookingSalesState;
|
|
61
62
|
private unifiedProductCatalog;
|
|
62
|
-
private openDataTarget;
|
|
63
|
-
private loadOpenDataInFlight;
|
|
64
|
-
private loadOpenDataInFlightTarget;
|
|
65
63
|
private availabilityRuntimeOffsetMinutes;
|
|
66
64
|
private availabilityScheduleCatalog;
|
|
67
65
|
private availabilityProjectionSequence;
|
|
@@ -76,6 +74,9 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
76
74
|
private availabilityRemoteResourceQuerySequence;
|
|
77
75
|
private availabilityRemoteResourceEpoch;
|
|
78
76
|
private availabilityCommitLocks;
|
|
77
|
+
private allergyItemRuleEvaluator;
|
|
78
|
+
private allergyItemRuleConfigs;
|
|
79
|
+
private allergyItemRuleConfigsPromise;
|
|
79
80
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
80
81
|
protected getSubmitOrderSalesChannel(): string;
|
|
81
82
|
private createAvailabilityFacadeError;
|
|
@@ -147,6 +148,18 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
147
148
|
*/
|
|
148
149
|
loadOpenData(params: UnifiedBookingSalesLoadOpenDataParams): Promise<OpenDataConfig>;
|
|
149
150
|
getOpenData(): Promise<OpenDataConfig | null>;
|
|
151
|
+
private resetAllergyItemRuleState;
|
|
152
|
+
private fetchAllergyItemRuleConfigs;
|
|
153
|
+
private ensureAllergyItemRuleConfigsLoaded;
|
|
154
|
+
/**
|
|
155
|
+
* 评估当前渠道与商品是否命中 ALLERGY_CHECK。
|
|
156
|
+
* 只返回优先级最高 Action 中当前商品 Target 的 dataSource,不跨商品或 Action 合并。
|
|
157
|
+
*/
|
|
158
|
+
resolveProductAllergyRequirement(params: UnifiedBookingSalesResolveProductAllergyRequirementParams): Promise<AllergyRequirement | null>;
|
|
159
|
+
clearOpenDataCache(): void;
|
|
160
|
+
getInvoiceLayoutConfig(): Promise<InvoiceLayoutConfig>;
|
|
161
|
+
getInvoiceTemplateSettings(): Promise<InvoiceTemplateSettings>;
|
|
162
|
+
protected isInvoiceOpenDataCacheCurrent(): boolean;
|
|
150
163
|
/**
|
|
151
164
|
* Load a resource policy without depending on the legacy appointmentBooking solution.
|
|
152
165
|
*/
|
|
@@ -159,6 +172,7 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
159
172
|
callback?: (result: any) => void;
|
|
160
173
|
subscriberId?: string;
|
|
161
174
|
}): Promise<ProductData[]>;
|
|
175
|
+
queryProducts(params?: ProductListStoreQueryParams): Promise<ProductData[]>;
|
|
162
176
|
/** Date-first entry point. It delegates protocol details and cache ownership to ScheduleModule. */
|
|
163
177
|
loadScheduleAvailableDate(params: LoadScheduleAvailableDateParams): Promise<import("../../modules/Date/types").ITime[]>;
|
|
164
178
|
/**
|
|
@@ -33,6 +33,7 @@ var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
|
33
33
|
var _lodashEs = require("lodash-es");
|
|
34
34
|
var _modules = require("../../modules");
|
|
35
35
|
var _utils = require("../../modules/BookingContext/utils");
|
|
36
|
+
var _OpenData = require("../../modules/OpenData");
|
|
36
37
|
var _getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
37
38
|
var _ResourcePlanner = require("../../modules/ResourcePlanner");
|
|
38
39
|
var _types = require("./types");
|
|
@@ -51,8 +52,9 @@ var _remoteOccupancyCache = require("./remoteOccupancyCache");
|
|
|
51
52
|
var _BookingTicket = require("../BookingTicket");
|
|
52
53
|
var _localClock = require("../../modules/ResourcePlanner/localClock");
|
|
53
54
|
var _platform = require("../../utils/platform");
|
|
55
|
+
var _itemRule = require("../../model/strategy/adapter/itemRule");
|
|
54
56
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
55
|
-
const OPEN_DATA_SECTION_CODES = ['sale', 'reservation', 'fulfillment', 'menu', 'workflow', 'basic', 'checkout', 'availability'];
|
|
57
|
+
const OPEN_DATA_SECTION_CODES = ['sale', 'reservation', 'fulfillment', 'menu', 'workflow', 'documents', 'basic', 'checkout', 'availability'];
|
|
56
58
|
const OPEN_DATA_CACHE_TTL = 5 * 60 * 1000;
|
|
57
59
|
function normalizePositiveInteger(value) {
|
|
58
60
|
const normalized = Number(value);
|
|
@@ -83,6 +85,22 @@ function getCandidateStartTime(candidate) {
|
|
|
83
85
|
return undefined;
|
|
84
86
|
}
|
|
85
87
|
}
|
|
88
|
+
function normalizePositiveIntegerList(value) {
|
|
89
|
+
if (!Array.isArray(value)) return [];
|
|
90
|
+
return Array.from(new Set(value.map(item => normalizePositiveInteger(item)).filter(item => item !== undefined)));
|
|
91
|
+
}
|
|
92
|
+
function toConfiguredBoolean(value) {
|
|
93
|
+
if (typeof value === 'boolean') return value;
|
|
94
|
+
if (typeof value === 'number') return value !== 0;
|
|
95
|
+
if (typeof value === 'string') {
|
|
96
|
+
return ['1', 'true', 'yes', 'y', 'on'].includes(value.trim().toLowerCase());
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
function normalizeItemRuleStrategyConfigs(value) {
|
|
101
|
+
if (!Array.isArray(value)) return [];
|
|
102
|
+
return value.filter(config => Boolean(config && typeof config === 'object' && config.metadata?.type === 'item_rule'));
|
|
103
|
+
}
|
|
86
104
|
function isRecord(value) {
|
|
87
105
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
88
106
|
}
|
|
@@ -1182,9 +1200,6 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1182
1200
|
defaultVersion = '1.0.0';
|
|
1183
1201
|
store = {};
|
|
1184
1202
|
unifiedProductCatalog = [];
|
|
1185
|
-
openDataTarget = null;
|
|
1186
|
-
loadOpenDataInFlight = null;
|
|
1187
|
-
loadOpenDataInFlightTarget = null;
|
|
1188
1203
|
availabilityRuntimeOffsetMinutes = null;
|
|
1189
1204
|
availabilityScheduleCatalog = null;
|
|
1190
1205
|
availabilityProjectionSequence = 0;
|
|
@@ -1199,11 +1214,15 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1199
1214
|
availabilityRemoteResourceQuerySequence = 0;
|
|
1200
1215
|
availabilityRemoteResourceEpoch = 0;
|
|
1201
1216
|
availabilityCommitLocks = new Set();
|
|
1217
|
+
allergyItemRuleEvaluator = new _itemRule.ItemRuleEvaluator();
|
|
1218
|
+
allergyItemRuleConfigs = [];
|
|
1219
|
+
allergyItemRuleConfigsPromise = null;
|
|
1202
1220
|
async initialize(core, options = {}) {
|
|
1203
1221
|
this.availabilityScheduleCatalog = null;
|
|
1204
1222
|
this.openDataTarget = null;
|
|
1205
1223
|
this.availabilityRuntimeOffsetMinutes = (0, _localClock.captureRuntimeOffsetMinutes)();
|
|
1206
1224
|
this.clearAvailabilityRemoteResourceState();
|
|
1225
|
+
this.resetAllergyItemRuleState();
|
|
1207
1226
|
await super.initialize(core, options);
|
|
1208
1227
|
const openDataBusinessCode = String(this.otherParams?.businessCode ?? this.otherParams?.business_code ?? '').trim();
|
|
1209
1228
|
const openDataChannel = String(this.otherParams?.channel ?? '').trim();
|
|
@@ -1348,6 +1367,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1348
1367
|
cover = false
|
|
1349
1368
|
} = {}) {
|
|
1350
1369
|
const previousScope = this.getAvailabilityScopeDescriptor(this.otherParams || {});
|
|
1370
|
+
const previousItemRuleConfig = this.otherParams?.itemRule;
|
|
1351
1371
|
const explicitlySetsOpenData = Object.prototype.hasOwnProperty.call(params, 'openData');
|
|
1352
1372
|
await super.setOtherParams(params, {
|
|
1353
1373
|
cover
|
|
@@ -1360,11 +1380,15 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1360
1380
|
if (shouldResetAvailabilityState) {
|
|
1361
1381
|
await this.resetAvailabilityProjectionState('set_other_params_reset');
|
|
1362
1382
|
}
|
|
1383
|
+
if (shouldResetAvailabilityState || explicitlySetsOpenData || previousItemRuleConfig !== this.otherParams?.itemRule) {
|
|
1384
|
+
this.resetAllergyItemRuleState();
|
|
1385
|
+
}
|
|
1363
1386
|
}
|
|
1364
1387
|
async destroy() {
|
|
1365
1388
|
this.availabilityScheduleCatalog = null;
|
|
1366
1389
|
this.availabilityRuntimeOffsetMinutes = null;
|
|
1367
1390
|
await this.resetAvailabilityProjectionState('destroy');
|
|
1391
|
+
this.resetAllergyItemRuleState();
|
|
1368
1392
|
await super.destroy();
|
|
1369
1393
|
}
|
|
1370
1394
|
createAvailabilityContextId() {
|
|
@@ -1679,6 +1703,9 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1679
1703
|
const cachedData = this.store.openData.getOpenData();
|
|
1680
1704
|
const lastFetchedAt = this.store.openData.getLastFetchedAt();
|
|
1681
1705
|
if (!params.force && this.openDataTarget === target && cachedData && lastFetchedAt && Date.now() - lastFetchedAt < OPEN_DATA_CACHE_TTL) {
|
|
1706
|
+
if (typeof this.store.openData.ensureInvoiceTemplateSettings === 'function') {
|
|
1707
|
+
await this.store.openData.ensureInvoiceTemplateSettings(target);
|
|
1708
|
+
}
|
|
1682
1709
|
return cachedData;
|
|
1683
1710
|
}
|
|
1684
1711
|
if (this.loadOpenDataInFlight) {
|
|
@@ -1689,35 +1716,155 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1689
1716
|
return this.loadOpenData(params);
|
|
1690
1717
|
}
|
|
1691
1718
|
this.loadOpenDataInFlightTarget = target;
|
|
1692
|
-
|
|
1719
|
+
const request = this.store.openData.fetchOpenData({
|
|
1693
1720
|
scope: 'board',
|
|
1694
1721
|
target,
|
|
1695
1722
|
section_code: [...OPEN_DATA_SECTION_CODES]
|
|
1696
1723
|
});
|
|
1724
|
+
this.loadOpenDataInFlight = request;
|
|
1697
1725
|
try {
|
|
1698
|
-
const openData = await
|
|
1699
|
-
this.
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1726
|
+
const openData = await request;
|
|
1727
|
+
if (this.loadOpenDataInFlight === request) {
|
|
1728
|
+
this.openDataTarget = target;
|
|
1729
|
+
this.otherParams.openData = openData;
|
|
1730
|
+
this.otherParams.businessCode = businessCode;
|
|
1731
|
+
this.otherParams.channel = channel;
|
|
1732
|
+
}
|
|
1703
1733
|
return openData;
|
|
1704
1734
|
} finally {
|
|
1705
|
-
this.loadOpenDataInFlight
|
|
1706
|
-
|
|
1735
|
+
if (this.loadOpenDataInFlight === request) {
|
|
1736
|
+
this.loadOpenDataInFlight = null;
|
|
1737
|
+
this.loadOpenDataInFlightTarget = null;
|
|
1738
|
+
}
|
|
1707
1739
|
}
|
|
1708
1740
|
}
|
|
1709
1741
|
async getOpenData() {
|
|
1710
1742
|
const businessCode = String(this.otherParams?.businessCode || '').trim();
|
|
1711
1743
|
const channel = String(this.otherParams?.channel || '').trim();
|
|
1712
1744
|
if (!businessCode || !channel) return null;
|
|
1713
|
-
const target = `${businessCode}+${channel}`;
|
|
1714
|
-
const cachedData = this.store.openData?.getOpenData() || null;
|
|
1715
|
-
if (cachedData && this.openDataTarget === target) return cachedData;
|
|
1716
1745
|
return this.loadOpenData({
|
|
1717
1746
|
businessCode,
|
|
1718
1747
|
channel
|
|
1719
1748
|
});
|
|
1720
1749
|
}
|
|
1750
|
+
resetAllergyItemRuleState() {
|
|
1751
|
+
this.allergyItemRuleConfigs = [];
|
|
1752
|
+
this.allergyItemRuleConfigsPromise = null;
|
|
1753
|
+
this.allergyItemRuleEvaluator.setStrategyConfigs([]);
|
|
1754
|
+
}
|
|
1755
|
+
async fetchAllergyItemRuleConfigs(strategyModelIds) {
|
|
1756
|
+
if (!strategyModelIds.length) return [];
|
|
1757
|
+
try {
|
|
1758
|
+
const response = await this.request.get('/promotion', {
|
|
1759
|
+
skip: 1,
|
|
1760
|
+
num: 99,
|
|
1761
|
+
status: 'active',
|
|
1762
|
+
ids: strategyModelIds
|
|
1763
|
+
});
|
|
1764
|
+
if (response?.code !== 200 || !Array.isArray(response?.data?.list)) {
|
|
1765
|
+
throw new Error('[UnifiedBookingSales] 商品过敏策略加载失败');
|
|
1766
|
+
}
|
|
1767
|
+
const list = response.data.list;
|
|
1768
|
+
return normalizeItemRuleStrategyConfigs(list.map(item => item?.metadata));
|
|
1769
|
+
} catch (error) {
|
|
1770
|
+
// this.logMethodError('fetchAllergyItemRuleConfigs', error, {
|
|
1771
|
+
// strategyModelIds,
|
|
1772
|
+
// });
|
|
1773
|
+
throw error;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
async ensureAllergyItemRuleConfigsLoaded() {
|
|
1777
|
+
if (this.allergyItemRuleConfigs.length > 0) {
|
|
1778
|
+
return this.allergyItemRuleConfigs;
|
|
1779
|
+
}
|
|
1780
|
+
if (this.allergyItemRuleConfigsPromise) {
|
|
1781
|
+
return this.allergyItemRuleConfigsPromise;
|
|
1782
|
+
}
|
|
1783
|
+
this.allergyItemRuleConfigsPromise = (async () => {
|
|
1784
|
+
const staticConfigs = normalizeItemRuleStrategyConfigs(this.otherParams?.itemRule?.strategyConfigs);
|
|
1785
|
+
if (staticConfigs.length > 0) {
|
|
1786
|
+
this.allergyItemRuleConfigs = staticConfigs;
|
|
1787
|
+
this.allergyItemRuleEvaluator.setStrategyConfigs(staticConfigs);
|
|
1788
|
+
return staticConfigs;
|
|
1789
|
+
}
|
|
1790
|
+
const openData = await this.getOpenData();
|
|
1791
|
+
const enabled = toConfiguredBoolean(openData?.['sale.enable_item_rules']);
|
|
1792
|
+
const strategyModelIds = normalizePositiveIntegerList(openData?.['sale.enabled_item_rules']);
|
|
1793
|
+
if (!enabled || !strategyModelIds.length) {
|
|
1794
|
+
this.allergyItemRuleEvaluator.setStrategyConfigs([]);
|
|
1795
|
+
return [];
|
|
1796
|
+
}
|
|
1797
|
+
const loaded = await this.fetchAllergyItemRuleConfigs(strategyModelIds);
|
|
1798
|
+
this.allergyItemRuleConfigs = loaded;
|
|
1799
|
+
this.allergyItemRuleEvaluator.setStrategyConfigs(loaded);
|
|
1800
|
+
return loaded;
|
|
1801
|
+
})();
|
|
1802
|
+
return this.allergyItemRuleConfigsPromise;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* 评估当前渠道与商品是否命中 ALLERGY_CHECK。
|
|
1807
|
+
* 只返回优先级最高 Action 中当前商品 Target 的 dataSource,不跨商品或 Action 合并。
|
|
1808
|
+
*/
|
|
1809
|
+
async resolveProductAllergyRequirement(params) {
|
|
1810
|
+
const productId = normalizePositiveInteger(params.productId);
|
|
1811
|
+
if (!productId) return null;
|
|
1812
|
+
const strategyConfigs = await this.ensureAllergyItemRuleConfigsLoaded();
|
|
1813
|
+
if (!strategyConfigs.length) return null;
|
|
1814
|
+
const productVariantId = normalizePositiveInteger(params.productVariantId);
|
|
1815
|
+
const runtimeConfig = this.otherParams?.itemRule || {};
|
|
1816
|
+
const runtimePax = runtimeConfig.pax || {};
|
|
1817
|
+
const cartItems = (this.getOrderProducts?.() || []).map(item => ({
|
|
1818
|
+
product_id: Number(item?.product_id ?? item?.id),
|
|
1819
|
+
product_variant_id: Number(item?.product_variant_id ?? 0) || undefined,
|
|
1820
|
+
quantity: Number(item?.num ?? item?.quantity ?? 0)
|
|
1821
|
+
})).filter(item => Number.isFinite(item.product_id) && item.product_id > 0 && Number.isFinite(item.quantity) && item.quantity > 0);
|
|
1822
|
+
return this.allergyItemRuleEvaluator.getAllergyRequirement({
|
|
1823
|
+
pax: {
|
|
1824
|
+
total: Number(runtimePax.total ?? 0) || 0,
|
|
1825
|
+
adult: Number(runtimePax.adult ?? 0) || 0,
|
|
1826
|
+
child: Number(runtimePax.child ?? 0) || 0
|
|
1827
|
+
},
|
|
1828
|
+
cartItems,
|
|
1829
|
+
serviceType: String(runtimeConfig.serviceType ?? this.otherParams?.serviceType ?? ''),
|
|
1830
|
+
channel: String(params.channel ?? this.otherParams?.channel ?? this.otherParams?.platform ?? ''),
|
|
1831
|
+
currentProduct: {
|
|
1832
|
+
product_id: productId,
|
|
1833
|
+
...(productVariantId ? {
|
|
1834
|
+
product_variant_id: productVariantId
|
|
1835
|
+
} : {})
|
|
1836
|
+
},
|
|
1837
|
+
submissionIndex: Number(runtimeConfig.submissionIndex ?? 0) || 0,
|
|
1838
|
+
strategyConfigs,
|
|
1839
|
+
custom: runtimeConfig.custom
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
clearOpenDataCache() {
|
|
1843
|
+
this.openDataTarget = null;
|
|
1844
|
+
this.loadOpenDataInFlight = null;
|
|
1845
|
+
this.loadOpenDataInFlightTarget = null;
|
|
1846
|
+
super.clearOpenDataCache();
|
|
1847
|
+
}
|
|
1848
|
+
async getInvoiceLayoutConfig() {
|
|
1849
|
+
const openData = await this.getOpenData();
|
|
1850
|
+
if (!openData || !this.store.openData) {
|
|
1851
|
+
return (0, _OpenData.getDefaultInvoiceLayoutConfig)();
|
|
1852
|
+
}
|
|
1853
|
+
return this.store.openData.getInvoiceLayoutConfig();
|
|
1854
|
+
}
|
|
1855
|
+
async getInvoiceTemplateSettings() {
|
|
1856
|
+
const openData = await this.getOpenData();
|
|
1857
|
+
if (!openData || !this.store.openData) {
|
|
1858
|
+
return (0, _OpenData.getDefaultInvoiceTemplateSettings)();
|
|
1859
|
+
}
|
|
1860
|
+
return this.store.openData.getInvoiceTemplateSettings();
|
|
1861
|
+
}
|
|
1862
|
+
isInvoiceOpenDataCacheCurrent() {
|
|
1863
|
+
const businessCode = String(this.otherParams?.businessCode || '').trim();
|
|
1864
|
+
const channel = String(this.otherParams?.channel || '').trim();
|
|
1865
|
+
if (!businessCode || !channel) return false;
|
|
1866
|
+
return this.openDataTarget === `${businessCode}+${channel}`;
|
|
1867
|
+
}
|
|
1721
1868
|
|
|
1722
1869
|
/**
|
|
1723
1870
|
* Load a resource policy without depending on the legacy appointmentBooking solution.
|
|
@@ -1754,6 +1901,10 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1754
1901
|
await this.core.effects.emit(`${this.name}:onProductsLoaded`, result);
|
|
1755
1902
|
return result;
|
|
1756
1903
|
}
|
|
1904
|
+
async queryProducts(params = {}) {
|
|
1905
|
+
if (!this.store.products) throw new Error('[UnifiedBookingSales] products 模块未初始化');
|
|
1906
|
+
return this.store.products.queryProducts(params);
|
|
1907
|
+
}
|
|
1757
1908
|
|
|
1758
1909
|
/** Date-first entry point. It delegates protocol details and cache ownership to ScheduleModule. */
|
|
1759
1910
|
async loadScheduleAvailableDate(params) {
|
|
@@ -3304,7 +3455,9 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
3304
3455
|
} else {
|
|
3305
3456
|
const beforeProductLineUids = new Set((this.getTempOrder()?.products || []).map(line => getProductLineUid(line)).filter(Boolean));
|
|
3306
3457
|
const beforeBookingUids = new Set((this.getTempOrder()?.bookings || []).map(item => getBookingUid(item)).filter(Boolean));
|
|
3307
|
-
const products = await this.addProductToOrder(transformed, booking
|
|
3458
|
+
const products = await this.addProductToOrder(transformed, booking, params.salesNotes?.length ? {
|
|
3459
|
+
salesNotes: params.salesNotes
|
|
3460
|
+
} : undefined);
|
|
3308
3461
|
const addedLines = products.filter(line => sameAvailabilityId(line.product_id ?? line.id, refreshedCandidate.productId) && line.metadata?.availability_candidate_key === refreshedCandidate.key && !beforeProductLineUids.has(getProductLineUid(line)));
|
|
3309
3462
|
productLineUids = addedLines.map(line => getProductLineUid(line)).filter(Boolean);
|
|
3310
3463
|
const addedBookings = (this.getTempOrder()?.bookings || []).filter(item => item.metadata?.availability_candidate_key === refreshedCandidate.key && !beforeBookingUids.has(getBookingUid(item)));
|