@pisell/pisellos 0.10.31 → 0.10.33
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/OpenData/index.d.ts +1 -1
- package/dist/modules/OpenData/index.js +19 -11
- package/dist/modules/Order/index.d.ts +2 -1
- package/dist/modules/Order/index.js +18 -3
- package/dist/server/index.js +4 -5
- package/dist/server/utils/small-ticket.d.ts +5 -1
- package/dist/server/utils/small-ticket.js +180 -101
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +6 -0
- package/dist/solution/BookingTicket/index.js +548 -485
- package/dist/utils/os-private-payload.d.ts +5 -0
- package/dist/utils/os-private-payload.js +17 -0
- package/lib/modules/OpenData/index.d.ts +1 -1
- package/lib/modules/OpenData/index.js +9 -1
- package/lib/modules/Order/index.d.ts +2 -1
- package/lib/modules/Order/index.js +12 -1
- package/lib/server/index.js +4 -5
- package/lib/server/utils/small-ticket.d.ts +5 -1
- package/lib/server/utils/small-ticket.js +107 -34
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +6 -0
- package/lib/solution/BookingTicket/index.js +32 -3
- package/lib/utils/os-private-payload.d.ts +5 -0
- package/lib/utils/os-private-payload.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
import { cloneDeep } from 'lodash-es';
|
|
3
|
+
var OS_PRIVATE_FIELD_PREFIX = '_os_';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Remove top-level fields reserved for communication with the PisellOS proxy.
|
|
7
|
+
* Nested business payloads are intentionally left untouched.
|
|
8
|
+
*/
|
|
9
|
+
export function stripOsPrivatePayloadFields(data) {
|
|
10
|
+
var next = cloneDeep(data);
|
|
11
|
+
if (!next || _typeof(next) !== 'object' || Array.isArray(next)) return next;
|
|
12
|
+
var record = next;
|
|
13
|
+
Object.keys(record).forEach(function (key) {
|
|
14
|
+
if (key.startsWith(OS_PRIVATE_FIELD_PREFIX)) delete record[key];
|
|
15
|
+
});
|
|
16
|
+
return next;
|
|
17
|
+
}
|
|
@@ -33,7 +33,7 @@ export declare class OpenDataModule extends BaseModule implements Module {
|
|
|
33
33
|
getOpenData(): OpenDataConfig | null;
|
|
34
34
|
getInvoiceLayoutConfig(): InvoiceLayoutConfig;
|
|
35
35
|
getInvoiceTemplateSettings(): InvoiceTemplateSettings;
|
|
36
|
-
ensureInvoiceTemplateSettings(target: string): Promise<InvoiceTemplateSettings>;
|
|
36
|
+
ensureInvoiceTemplateSettings(target: string, openDataConfig?: OpenDataConfig): Promise<InvoiceTemplateSettings>;
|
|
37
37
|
private commitInvoiceTemplateSettings;
|
|
38
38
|
private resolveInvoiceTemplateSettings;
|
|
39
39
|
private buildInvoiceTemplateCacheKey;
|
|
@@ -211,8 +211,16 @@ class OpenDataModule extends _BaseModule.BaseModule {
|
|
|
211
211
|
}
|
|
212
212
|
return (0, _utils.getDefaultInvoiceTemplateSettings)();
|
|
213
213
|
}
|
|
214
|
-
async ensureInvoiceTemplateSettings(target) {
|
|
214
|
+
async ensureInvoiceTemplateSettings(target, openDataConfig) {
|
|
215
215
|
const normalizedTarget = String(target || '').trim();
|
|
216
|
+
if (openDataConfig && openDataConfig !== this.store.data) {
|
|
217
|
+
// 部分解决方案会在初始化参数中直接收到已经拉取完成的 OpenData。
|
|
218
|
+
// 将它纳入模块状态后再解析 Document,避免为了 Invoice 重复请求 setting,
|
|
219
|
+
// 同时让后续同步 getter 能校验同一份 document id 与 target。
|
|
220
|
+
this.fetchRevision += 1;
|
|
221
|
+
this.store.data = openDataConfig;
|
|
222
|
+
this.store.lastFetchedAt = Date.now();
|
|
223
|
+
}
|
|
216
224
|
const config = this.store.data;
|
|
217
225
|
if (!normalizedTarget || !config) {
|
|
218
226
|
return (0, _utils.getDefaultInvoiceTemplateSettings)();
|
|
@@ -535,7 +535,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
535
535
|
generateIdempotencyToken(): string;
|
|
536
536
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
537
537
|
createOrder(params: CommitOrderParams['query']): {
|
|
538
|
-
type: "
|
|
538
|
+
type: "virtual" | "appointment_booking";
|
|
539
539
|
platform: string;
|
|
540
540
|
sales_channel: string;
|
|
541
541
|
order_sales_channel: string;
|
|
@@ -566,6 +566,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
566
566
|
*/
|
|
567
567
|
createOrderByCheckout(params: CheckoutOrderParams): Promise<any>;
|
|
568
568
|
submitSalesOrder<T = any>(params: SubmitSalesOrderParams): Promise<T>;
|
|
569
|
+
private isSalesCheckoutHandledByOsServer;
|
|
569
570
|
/**
|
|
570
571
|
* 发送支付链接邮件。
|
|
571
572
|
*
|
|
@@ -9,6 +9,7 @@ var _types = require("./types");
|
|
|
9
9
|
var _utils = require("./utils");
|
|
10
10
|
var _utils2 = require("../Product/utils");
|
|
11
11
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
12
|
+
var _osPrivatePayload = require("../../utils/os-private-payload");
|
|
12
13
|
var _paymentUtils = require("./payment-utils");
|
|
13
14
|
var _paymentNumber = require("../../utils/payment-number");
|
|
14
15
|
var _cartPromotion = require("../../solution/BaseSales/utils/cartPromotion");
|
|
@@ -4358,11 +4359,21 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4358
4359
|
query
|
|
4359
4360
|
} = params;
|
|
4360
4361
|
const fetchUrl = url || '/order/sales/checkout';
|
|
4361
|
-
|
|
4362
|
+
const requestQuery = this.isSalesCheckoutHandledByOsServer(fetchUrl) ? query : (0, _osPrivatePayload.stripOsPrivatePayloadFields)(query);
|
|
4363
|
+
return this.request.post(fetchUrl, requestQuery, {
|
|
4362
4364
|
osServer: true,
|
|
4363
4365
|
customToast: () => {}
|
|
4364
4366
|
});
|
|
4365
4367
|
}
|
|
4368
|
+
isSalesCheckoutHandledByOsServer(fetchUrl) {
|
|
4369
|
+
const server = this.core?.server;
|
|
4370
|
+
if (!server || typeof server.hasRoute !== 'function') return false;
|
|
4371
|
+
const requestBaseUrl = String(this.request?.baseUrl || '/shop').replace(/\/+$/, '');
|
|
4372
|
+
if (!requestBaseUrl.startsWith('/')) return false;
|
|
4373
|
+
const normalizedFetchUrl = fetchUrl.startsWith('/') ? fetchUrl : `/${fetchUrl}`;
|
|
4374
|
+
const routePath = normalizedFetchUrl === requestBaseUrl || normalizedFetchUrl.startsWith(`${requestBaseUrl}/`) ? normalizedFetchUrl : `${requestBaseUrl}${normalizedFetchUrl}`;
|
|
4375
|
+
return server.hasRoute('post', routePath) === true;
|
|
4376
|
+
}
|
|
4366
4377
|
|
|
4367
4378
|
/**
|
|
4368
4379
|
* 发送支付链接邮件。
|
package/lib/server/index.js
CHANGED
|
@@ -28,6 +28,7 @@ var _smallTicket = require("./utils/small-ticket");
|
|
|
28
28
|
var _BaseSales = require("../solution/BaseSales");
|
|
29
29
|
var _paymentUtils = require("../modules/Order/payment-utils");
|
|
30
30
|
var _orderCollectionIdentity = require("../modules/Order/utils/orderCollectionIdentity");
|
|
31
|
+
var _osPrivatePayload = require("../utils/os-private-payload");
|
|
31
32
|
var _OpenData = require("../modules/OpenData");
|
|
32
33
|
var _modules = require("./modules");
|
|
33
34
|
Object.keys(_modules).forEach(function (key) {
|
|
@@ -642,7 +643,7 @@ class Server {
|
|
|
642
643
|
} = params;
|
|
643
644
|
const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
|
|
644
645
|
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
645
|
-
const checkoutData = this.normalizeCheckoutCollections(this.applyCheckoutFulfillmentBuzzer(numberedData, title));
|
|
646
|
+
const checkoutData = this.normalizeCheckoutCollections((0, _osPrivatePayload.stripOsPrivatePayloadFields)(this.applyCheckoutFulfillmentBuzzer(numberedData, title)));
|
|
646
647
|
const remoteCheckoutData = this.buildRemoteCheckoutData(checkoutData, title);
|
|
647
648
|
const deviceHeaders = await this.buildCheckoutDeviceHeaders(title);
|
|
648
649
|
if (!this.app?.request?.post) {
|
|
@@ -714,11 +715,9 @@ class Server {
|
|
|
714
715
|
return next;
|
|
715
716
|
}
|
|
716
717
|
buildRemoteCheckoutData(data, title) {
|
|
717
|
-
const next = (0,
|
|
718
|
+
const next = (0, _osPrivatePayload.stripOsPrivatePayloadFields)(this.omitCheckoutSyncMode(data));
|
|
718
719
|
if (!next || typeof next !== 'object') return next;
|
|
719
720
|
const record = next;
|
|
720
|
-
delete record[OS_FULFILLMENT_REF_MODE_FIELD];
|
|
721
|
-
delete record[OS_INVOICE_LAYOUT_CONFIG_FIELD];
|
|
722
721
|
this.applyKioskCheckoutOperator(record);
|
|
723
722
|
if (!Array.isArray(record.payments)) return next;
|
|
724
723
|
const originalPayments = record.payments;
|
|
@@ -4294,7 +4293,7 @@ class Server {
|
|
|
4294
4293
|
}
|
|
4295
4294
|
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
4296
4295
|
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
4297
|
-
const checkoutData = this.normalizeCheckoutCollections(this.applyCheckoutFulfillmentBuzzer(numberedData, title));
|
|
4296
|
+
const checkoutData = this.normalizeCheckoutCollections((0, _osPrivatePayload.stripOsPrivatePayloadFields)(this.applyCheckoutFulfillmentBuzzer(numberedData, title)));
|
|
4298
4297
|
const pendingResult = await this.handlePendingSyncCheckoutOrder({
|
|
4299
4298
|
backendPath,
|
|
4300
4299
|
data: checkoutData,
|
|
@@ -33,9 +33,12 @@ export interface SmallTicketProduct {
|
|
|
33
33
|
product_title: string;
|
|
34
34
|
product_quantity: number;
|
|
35
35
|
selling_price: string;
|
|
36
|
+
total_selling_price: string;
|
|
36
37
|
original_price: string;
|
|
37
|
-
base_price
|
|
38
|
+
base_price: string;
|
|
38
39
|
total_original_price: string;
|
|
40
|
+
options_total_price?: string;
|
|
41
|
+
package_items_total_price?: string;
|
|
39
42
|
extension_list: any[];
|
|
40
43
|
product_uid?: string | number;
|
|
41
44
|
booking_uid?: string | number;
|
|
@@ -44,6 +47,7 @@ export interface SmallTicketProduct {
|
|
|
44
47
|
name: string;
|
|
45
48
|
num?: number;
|
|
46
49
|
price?: string;
|
|
50
|
+
total_price: string;
|
|
47
51
|
value?: string;
|
|
48
52
|
}>;
|
|
49
53
|
variant?: string;
|
|
@@ -31,7 +31,7 @@ const LABELS = {
|
|
|
31
31
|
balance: 'Balance',
|
|
32
32
|
remainingAmount: 'Remaining amount',
|
|
33
33
|
redeemPoints: 'Redeem points',
|
|
34
|
-
remainingPoints: '
|
|
34
|
+
remainingPoints: 'Point Balance',
|
|
35
35
|
table: 'Table',
|
|
36
36
|
orderDiscount: 'Order discount',
|
|
37
37
|
manualDiscount: 'Manual discount',
|
|
@@ -64,7 +64,7 @@ const LABELS = {
|
|
|
64
64
|
balance: '余额',
|
|
65
65
|
remainingAmount: '剩余金额',
|
|
66
66
|
redeemPoints: '本次使用积分',
|
|
67
|
-
remainingPoints: '
|
|
67
|
+
remainingPoints: '积分余额',
|
|
68
68
|
table: '桌台',
|
|
69
69
|
orderDiscount: '整单折扣',
|
|
70
70
|
manualDiscount: '手动折扣',
|
|
@@ -97,7 +97,7 @@ const LABELS = {
|
|
|
97
97
|
balance: '餘額',
|
|
98
98
|
remainingAmount: '剩餘金額',
|
|
99
99
|
redeemPoints: '本次使用積分',
|
|
100
|
-
remainingPoints: '
|
|
100
|
+
remainingPoints: '積分餘額',
|
|
101
101
|
table: '桌台',
|
|
102
102
|
orderDiscount: '整單折扣',
|
|
103
103
|
manualDiscount: '手動折扣',
|
|
@@ -128,7 +128,7 @@ const LABELS = {
|
|
|
128
128
|
balance: '残高',
|
|
129
129
|
remainingAmount: '残高',
|
|
130
130
|
redeemPoints: '利用ポイント',
|
|
131
|
-
remainingPoints: '
|
|
131
|
+
remainingPoints: 'ポイント残高',
|
|
132
132
|
table: 'テーブル',
|
|
133
133
|
orderDiscount: '注文割引',
|
|
134
134
|
manualDiscount: '手動割引',
|
|
@@ -160,7 +160,7 @@ const LABELS = {
|
|
|
160
160
|
balance: 'Saldo',
|
|
161
161
|
remainingAmount: 'Saldo restante',
|
|
162
162
|
redeemPoints: 'Pontos utilizados',
|
|
163
|
-
remainingPoints: '
|
|
163
|
+
remainingPoints: 'Saldo de pontos',
|
|
164
164
|
table: 'Mesa',
|
|
165
165
|
orderDiscount: 'Desconto do pedido',
|
|
166
166
|
manualDiscount: 'Desconto manual',
|
|
@@ -269,9 +269,7 @@ function buildBaseData(params) {
|
|
|
269
269
|
payment_status: financials.paymentStatus,
|
|
270
270
|
total_amount: formatMoney(financials.totalAmount, currencySymbol),
|
|
271
271
|
has_pay: formatMoney(financials.netPaymentApplied, currencySymbol),
|
|
272
|
-
|
|
273
|
-
amount_gap: formatMoney(financials.amountGap, currencySymbol)
|
|
274
|
-
} : {}),
|
|
272
|
+
amount_gap: formatCalculatedMoney(financials.amountGap ?? 0, currencySymbol),
|
|
275
273
|
is_repeat: 0,
|
|
276
274
|
buzzer: stringify(order.buzzer || order.pickup_number || order.metadata?.buzzer),
|
|
277
275
|
order_no: orderNumber,
|
|
@@ -323,15 +321,21 @@ function buildProducts(order, locale, productMap) {
|
|
|
323
321
|
});
|
|
324
322
|
const productNote = resolveProductNote(product, locale);
|
|
325
323
|
const basePrice = resolveProductBasePrice(product);
|
|
324
|
+
const resolvedCombinations = Array.isArray(product.combinations) && product.combinations.length ? normalizeExistingCombinations(product.combinations, locale, currencySymbol) : combinations;
|
|
326
325
|
return {
|
|
327
326
|
product_title: productTitle,
|
|
328
327
|
product_quantity: quantity,
|
|
329
328
|
selling_price: formatMoney(sellingPrice, currencySymbol),
|
|
329
|
+
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(sellingPrice)).mul(quantity), currencySymbol),
|
|
330
330
|
original_price: formatMoney(originalPrice, currencySymbol),
|
|
331
|
-
|
|
332
|
-
base_price: formatMoney(basePrice, currencySymbol)
|
|
333
|
-
} : {}),
|
|
331
|
+
base_price: formatCalculatedMoney(basePrice ?? 0, currencySymbol),
|
|
334
332
|
total_original_price: formatMoney(new _decimal.default(toMoneyNumber(originalPrice)).mul(quantity), currencySymbol),
|
|
333
|
+
...(options.length ? {
|
|
334
|
+
options_total_price: sumNormalizedOptionTotals(options, currencySymbol)
|
|
335
|
+
} : {}),
|
|
336
|
+
...(resolvedCombinations.length ? {
|
|
337
|
+
package_items_total_price: sumCombinationTotals(resolvedCombinations, currencySymbol)
|
|
338
|
+
} : {}),
|
|
335
339
|
extension_list: extensionList,
|
|
336
340
|
...(isPresentId(productUid) ? {
|
|
337
341
|
product_uid: productUid
|
|
@@ -348,10 +352,8 @@ function buildProducts(order, locale, productMap) {
|
|
|
348
352
|
...(resolvedVariant ? {
|
|
349
353
|
variant: resolvedVariant
|
|
350
354
|
} : {}),
|
|
351
|
-
...(
|
|
352
|
-
combinations:
|
|
353
|
-
} : combinations.length ? {
|
|
354
|
-
combinations
|
|
355
|
+
...(resolvedCombinations.length ? {
|
|
356
|
+
combinations: resolvedCombinations
|
|
355
357
|
} : {})
|
|
356
358
|
};
|
|
357
359
|
});
|
|
@@ -371,7 +373,10 @@ function normalizeProductDiscounts(params) {
|
|
|
371
373
|
currencySymbol,
|
|
372
374
|
quantity
|
|
373
375
|
} = params;
|
|
374
|
-
return normalizeArray(product.discount_list).
|
|
376
|
+
return normalizeArray(product.discount_list).filter(discount => {
|
|
377
|
+
const amount = discount.amount ?? discount.value ?? discount.discount_amount;
|
|
378
|
+
return isNonZero(amount);
|
|
379
|
+
}).map(discount => {
|
|
375
380
|
const title = resolveDiscountTitleWithPercent(discount, locale);
|
|
376
381
|
const amount = discount.amount ?? discount.value ?? discount.discount_amount;
|
|
377
382
|
const formattedAmount = formatNegativeMoney(new _decimal.default(toMoneyNumber(amount)).mul(quantity), currencySymbol);
|
|
@@ -488,6 +493,7 @@ function normalizeProductOptions(params) {
|
|
|
488
493
|
const rawOptions = Array.isArray(params.options) ? params.options : Array.isArray(product.options) ? product.options : Array.isArray(product.product_sku?.option) ? product.product_sku.option : [];
|
|
489
494
|
return rawOptions.map(option => {
|
|
490
495
|
const price = option.original_price ?? option.add_price ?? option.price;
|
|
496
|
+
const quantity = toNumber(option.num ?? option.quantity ?? 1, 1);
|
|
491
497
|
const value = option.value ?? option.option ?? option.item;
|
|
492
498
|
const name = getProductTitleSource(option, locale) || resolveOptionTitleFromParentProduct({
|
|
493
499
|
option,
|
|
@@ -497,11 +503,12 @@ function normalizeProductOptions(params) {
|
|
|
497
503
|
return {
|
|
498
504
|
name,
|
|
499
505
|
...(option.num !== undefined || option.quantity !== undefined ? {
|
|
500
|
-
num:
|
|
506
|
+
num: quantity
|
|
501
507
|
} : {}),
|
|
502
508
|
...(price !== undefined && price !== null && price !== '' ? {
|
|
503
509
|
price: formatMoney(price, currencySymbol)
|
|
504
510
|
} : {}),
|
|
511
|
+
total_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(price ?? 0)).mul(quantity), currencySymbol),
|
|
505
512
|
...(value !== undefined && value !== null && value !== '' ? {
|
|
506
513
|
value: getLocalizedValue(value, locale)
|
|
507
514
|
} : {})
|
|
@@ -532,12 +539,25 @@ function normalizeProductCombinations(params) {
|
|
|
532
539
|
parentProduct
|
|
533
540
|
});
|
|
534
541
|
const productNote = resolveProductNote(bundle, locale);
|
|
535
|
-
const nestedCombinations = Array.isArray(bundle.combinations) ? normalizeExistingCombinations(bundle.combinations, locale) : [];
|
|
542
|
+
const nestedCombinations = Array.isArray(bundle.combinations) ? normalizeExistingCombinations(bundle.combinations, locale, currencySymbol) : [];
|
|
543
|
+
const quantity = toNumber(bundle.num ?? bundle.quantity ?? 1, 1);
|
|
544
|
+
const formattedPrice = formatBundlePrice(bundle, currencySymbol);
|
|
545
|
+
const optionsTotal = sumNormalizedOptionTotals(combinationsOptions, currencySymbol);
|
|
546
|
+
const explicitBasePrice = firstPresentValue(bundle.base_price, bundle.metadata?.source_product_price);
|
|
547
|
+
const basePrice = isPresentId(explicitBasePrice) ? explicitBasePrice : 0;
|
|
536
548
|
return {
|
|
537
549
|
product_title: baseTitle,
|
|
538
|
-
product_quantity:
|
|
539
|
-
price:
|
|
550
|
+
product_quantity: quantity,
|
|
551
|
+
price: formattedPrice,
|
|
552
|
+
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(formattedPrice)).mul(quantity), currencySymbol),
|
|
553
|
+
base_price: formatCalculatedMoney(basePrice, currencySymbol),
|
|
540
554
|
combinations_options: combinationsOptions,
|
|
555
|
+
...(combinationsOptions.length ? {
|
|
556
|
+
options_total_price: optionsTotal
|
|
557
|
+
} : {}),
|
|
558
|
+
...(nestedCombinations.length ? {
|
|
559
|
+
package_items_total_price: sumCombinationTotals(nestedCombinations, currencySymbol)
|
|
560
|
+
} : {}),
|
|
541
561
|
...(productNote ? {
|
|
542
562
|
product_note: productNote
|
|
543
563
|
} : {}),
|
|
@@ -547,29 +567,65 @@ function normalizeProductCombinations(params) {
|
|
|
547
567
|
};
|
|
548
568
|
});
|
|
549
569
|
}
|
|
550
|
-
function normalizeExistingCombinations(combinations, locale) {
|
|
570
|
+
function normalizeExistingCombinations(combinations, locale, currencySymbol) {
|
|
551
571
|
return combinations.map(combination => {
|
|
552
572
|
if (!combination || typeof combination !== 'object' || Array.isArray(combination)) {
|
|
553
573
|
return combination;
|
|
554
574
|
}
|
|
555
575
|
const productNote = resolveProductNote(combination, locale);
|
|
556
|
-
const
|
|
576
|
+
const rawOptions = Array.isArray(combination.combinations_options) ? combination.combinations_options : Array.isArray(combination.options) ? combination.options : [];
|
|
577
|
+
const normalizedOptions = normalizeProductOptions({
|
|
578
|
+
product: {},
|
|
579
|
+
locale,
|
|
580
|
+
currencySymbol,
|
|
581
|
+
options: rawOptions
|
|
582
|
+
});
|
|
583
|
+
const nestedCombinations = Array.isArray(combination.combinations) ? normalizeExistingCombinations(combination.combinations, locale, currencySymbol) : [];
|
|
557
584
|
const snapshot = {
|
|
558
585
|
...combination
|
|
559
586
|
};
|
|
560
587
|
delete snapshot.product_note;
|
|
561
588
|
delete snapshot.note;
|
|
589
|
+
delete snapshot.combinations;
|
|
590
|
+
const quantity = toNumber(combination.product_quantity ?? combination.num ?? combination.quantity ?? 1, 1);
|
|
591
|
+
const unitPrice = firstPresentValue(combination.selling_price, combination.price, combination.original_price) ?? 0;
|
|
592
|
+
const optionsAmount = sumMoneyValues(normalizedOptions.map(option => option.total_price));
|
|
593
|
+
const explicitBasePrice = firstPresentValue(combination.base_price);
|
|
594
|
+
const basePrice = isPresentId(explicitBasePrice) ? explicitBasePrice : 0;
|
|
562
595
|
return {
|
|
563
596
|
...snapshot,
|
|
597
|
+
product_quantity: quantity,
|
|
598
|
+
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(unitPrice)).mul(quantity), currencySymbol),
|
|
599
|
+
base_price: formatCalculatedMoney(basePrice, currencySymbol),
|
|
600
|
+
...(Array.isArray(combination.combinations_options) ? {
|
|
601
|
+
combinations_options: normalizedOptions
|
|
602
|
+
} : Array.isArray(combination.options) ? {
|
|
603
|
+
options: normalizedOptions
|
|
604
|
+
} : {}),
|
|
605
|
+
...(normalizedOptions.length ? {
|
|
606
|
+
options_total_price: formatCalculatedMoney(optionsAmount, currencySymbol)
|
|
607
|
+
} : {}),
|
|
608
|
+
...(nestedCombinations.length ? {
|
|
609
|
+
package_items_total_price: sumCombinationTotals(nestedCombinations, currencySymbol)
|
|
610
|
+
} : {}),
|
|
564
611
|
...(productNote ? {
|
|
565
612
|
product_note: productNote
|
|
566
613
|
} : {}),
|
|
567
|
-
...(nestedCombinations ? {
|
|
614
|
+
...(nestedCombinations.length ? {
|
|
568
615
|
combinations: nestedCombinations
|
|
569
616
|
} : {})
|
|
570
617
|
};
|
|
571
618
|
});
|
|
572
619
|
}
|
|
620
|
+
function sumMoneyValues(values) {
|
|
621
|
+
return values.reduce((sum, value) => sum.plus(toMoneyNumber(value)), new _decimal.default(0));
|
|
622
|
+
}
|
|
623
|
+
function sumNormalizedOptionTotals(options, currencySymbol) {
|
|
624
|
+
return formatCalculatedMoney(sumMoneyValues(options.map(option => option.total_price)), currencySymbol);
|
|
625
|
+
}
|
|
626
|
+
function sumCombinationTotals(combinations, currencySymbol) {
|
|
627
|
+
return formatCalculatedMoney(sumMoneyValues(combinations.map(combination => combination.total_selling_price)), currencySymbol);
|
|
628
|
+
}
|
|
573
629
|
function resolveProductNote(product, locale) {
|
|
574
630
|
const productNote = getLocalizedValue(product.product_note, locale).trim();
|
|
575
631
|
if (productNote) return productNote;
|
|
@@ -816,12 +872,14 @@ function buildFees(params) {
|
|
|
816
872
|
const productExpectAmount = firstPresentValue(summary.product_expect_amount, summary.product_amount, order.product_expect_amount);
|
|
817
873
|
const productOriginalAmount = firstPresentValue(summary.product_original_amount, order.product_original_amount) ?? calculateProductOriginalAmount(order);
|
|
818
874
|
const totalSavingsAmount = new _decimal.default(toMoneyNumber(productOriginalAmount)).minus(toMoneyNumber(productExpectAmount)).plus(toMoneyNumber(discountAmount));
|
|
875
|
+
const itemDiscountAmount = new _decimal.default(toMoneyNumber(productExpectAmount ?? 0)).minus(toMoneyNumber(productOriginalAmount));
|
|
819
876
|
return {
|
|
820
877
|
fees,
|
|
821
878
|
countFee: {
|
|
822
879
|
total_amount: formatMoney(firstPresentValue(summary.total_amount, order.total_amount) ?? 0, currencySymbol),
|
|
823
880
|
original_item_amount: formatMoney(productOriginalAmount, currencySymbol),
|
|
824
881
|
product_expect_amount: formatMoney(productExpectAmount ?? 0, currencySymbol),
|
|
882
|
+
item_discount_amount: formatCalculatedMoney(itemDiscountAmount, currencySymbol),
|
|
825
883
|
expect_amount: formatMoney(financials.totalAmount, currencySymbol),
|
|
826
884
|
product_quantity: toNumber(firstPresentValue(summary.product_quantity, products.reduce((sum, product) => sum + product.product_quantity, 0)), 0),
|
|
827
885
|
has_pay: formatMoney(financials.orderPaidAmount, currencySymbol),
|
|
@@ -1004,7 +1062,9 @@ function buildPaymentData(params) {
|
|
|
1004
1062
|
payment,
|
|
1005
1063
|
locale: params.locale,
|
|
1006
1064
|
currencySymbol: params.currencySymbol,
|
|
1007
|
-
includeFundRecordBalance: false
|
|
1065
|
+
includeFundRecordBalance: false,
|
|
1066
|
+
includeFundRecordUsage: true,
|
|
1067
|
+
includePaymentAmount: true
|
|
1008
1068
|
}));
|
|
1009
1069
|
}
|
|
1010
1070
|
function buildRefundData(params) {
|
|
@@ -1093,7 +1153,9 @@ function buildWallets(params) {
|
|
|
1093
1153
|
payment,
|
|
1094
1154
|
locale: params.locale,
|
|
1095
1155
|
currencySymbol: params.currencySymbol,
|
|
1096
|
-
includeFundRecordBalance: true
|
|
1156
|
+
includeFundRecordBalance: true,
|
|
1157
|
+
includeFundRecordUsage: false,
|
|
1158
|
+
includePaymentAmount: false
|
|
1097
1159
|
}));
|
|
1098
1160
|
const displayedWalletPassIds = collectDisplayedWalletPassIds(displayedWalletPayments);
|
|
1099
1161
|
return [...paymentWallets, ...buildVoucherAssets(params), ...buildPointCardSnapshotAssets({
|
|
@@ -1212,12 +1274,14 @@ function buildPaymentItems(params) {
|
|
|
1212
1274
|
payment,
|
|
1213
1275
|
locale,
|
|
1214
1276
|
currencySymbol,
|
|
1215
|
-
includeFundRecordBalance
|
|
1277
|
+
includeFundRecordBalance,
|
|
1278
|
+
includeFundRecordUsage,
|
|
1279
|
+
includePaymentAmount
|
|
1216
1280
|
} = params;
|
|
1217
1281
|
const serviceFee = getPaymentServiceFee(payment);
|
|
1218
1282
|
const items = [{
|
|
1219
1283
|
item: paymentMethodName(payment, locale),
|
|
1220
|
-
value: formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol)
|
|
1284
|
+
value: includePaymentAmount ? formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol) : ''
|
|
1221
1285
|
}];
|
|
1222
1286
|
items.push(...buildCashChangePaymentItems({
|
|
1223
1287
|
payment,
|
|
@@ -1237,7 +1301,8 @@ function buildPaymentItems(params) {
|
|
|
1237
1301
|
fundRecord,
|
|
1238
1302
|
locale,
|
|
1239
1303
|
currencySymbol,
|
|
1240
|
-
includeBalance: includeFundRecordBalance
|
|
1304
|
+
includeBalance: includeFundRecordBalance,
|
|
1305
|
+
includeUsage: includeFundRecordUsage
|
|
1241
1306
|
}));
|
|
1242
1307
|
} else {
|
|
1243
1308
|
const remainingAmount = payment.remaining_amount ?? payment.balance ?? payment.metadata?.remaining_amount;
|
|
@@ -1301,17 +1366,20 @@ function buildFundRecordPaymentItems(params) {
|
|
|
1301
1366
|
fundRecord,
|
|
1302
1367
|
locale,
|
|
1303
1368
|
currencySymbol,
|
|
1304
|
-
includeBalance
|
|
1369
|
+
includeBalance,
|
|
1370
|
+
includeUsage
|
|
1305
1371
|
} = params;
|
|
1306
1372
|
const items = [];
|
|
1307
1373
|
const usingBeforeValue = fundRecord.using_before_value;
|
|
1308
1374
|
const usingAfterValue = fundRecord.using_after_value;
|
|
1309
1375
|
if (isPointCardPayment(payment) && usingBeforeValue !== undefined && usingAfterValue !== undefined) {
|
|
1310
1376
|
const usedPoints = new _decimal.default(toMoneyNumber(usingBeforeValue)).minus(toMoneyNumber(usingAfterValue));
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1377
|
+
if (includeUsage) {
|
|
1378
|
+
items.push({
|
|
1379
|
+
item: label(locale, 'redeemPoints'),
|
|
1380
|
+
value: trimDecimal(usedPoints)
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1315
1383
|
if (includeBalance) {
|
|
1316
1384
|
items.push({
|
|
1317
1385
|
item: label(locale, 'remainingPoints'),
|
|
@@ -1322,7 +1390,7 @@ function buildFundRecordPaymentItems(params) {
|
|
|
1322
1390
|
}
|
|
1323
1391
|
if (includeBalance && usingAfterValue !== undefined && usingAfterValue !== null) {
|
|
1324
1392
|
items.push({
|
|
1325
|
-
item: label(locale, '
|
|
1393
|
+
item: label(locale, 'balance'),
|
|
1326
1394
|
value: formatMoney(usingAfterValue, currencySymbol)
|
|
1327
1395
|
});
|
|
1328
1396
|
}
|
|
@@ -1436,6 +1504,11 @@ function formatMoney(value, currencySymbol) {
|
|
|
1436
1504
|
const amount = new _decimal.default(toMoneyNumber(value));
|
|
1437
1505
|
return `${currencySymbol}${amount.toFixed(2)}`;
|
|
1438
1506
|
}
|
|
1507
|
+
function formatCalculatedMoney(value, currencySymbol) {
|
|
1508
|
+
const amount = new _decimal.default(toMoneyNumber(value));
|
|
1509
|
+
const sign = amount.isNegative() ? '-' : '';
|
|
1510
|
+
return `${sign}${currencySymbol}${amount.abs().toFixed(2)}`;
|
|
1511
|
+
}
|
|
1439
1512
|
function formatNegativeMoney(value, currencySymbol) {
|
|
1440
1513
|
const amount = new _decimal.default(toMoneyNumber(value)).abs();
|
|
1441
1514
|
return `-${currencySymbol}${amount.toFixed(2)}`;
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 5 | 4 | 3 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -45,6 +45,12 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
45
45
|
*/
|
|
46
46
|
protected createSubModule(moduleName: string): Module | null;
|
|
47
47
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
48
|
+
private getInjectedOpenDataConfig;
|
|
49
|
+
/**
|
|
50
|
+
* 在解决方案对外 ready 前准备 Invoice Document;失败只降级模板,不阻断销售。
|
|
51
|
+
* 已由页面取得的 OpenData 直接交给模块接管,没有注入数据时再走 target-scoped 加载。
|
|
52
|
+
*/
|
|
53
|
+
private prepareInvoiceTemplateAtSolutionReady;
|
|
48
54
|
protected getBookingTicketBusinessCode(): string | null;
|
|
49
55
|
private getIdGeneratorPlugin;
|
|
50
56
|
private loadOpenDataConfig;
|
|
@@ -193,10 +193,37 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
193
193
|
throw new Error('bookingTicket解决方案需要 request 插件支持');
|
|
194
194
|
}
|
|
195
195
|
this.platform = this.otherParams?.platform;
|
|
196
|
+
await this.prepareInvoiceTemplateAtSolutionReady(this.getInjectedOpenDataConfig());
|
|
196
197
|
await this.configureIdGeneratorFromOpenData();
|
|
197
198
|
}
|
|
199
|
+
getInjectedOpenDataConfig() {
|
|
200
|
+
const openData = this.otherParams?.openData;
|
|
201
|
+
return openData && typeof openData === 'object' && !Array.isArray(openData) ? openData : undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 在解决方案对外 ready 前准备 Invoice Document;失败只降级模板,不阻断销售。
|
|
206
|
+
* 已由页面取得的 OpenData 直接交给模块接管,没有注入数据时再走 target-scoped 加载。
|
|
207
|
+
*/
|
|
208
|
+
async prepareInvoiceTemplateAtSolutionReady(injectedOpenData) {
|
|
209
|
+
const businessCode = this.getBookingTicketBusinessCode();
|
|
210
|
+
if (!businessCode || !this.store.openData) return;
|
|
211
|
+
const channel = this.getSubmitOrderSalesChannel();
|
|
212
|
+
const target = `${businessCode}+${channel}`;
|
|
213
|
+
try {
|
|
214
|
+
if (injectedOpenData && typeof this.store.openData.ensureInvoiceTemplateSettings === 'function') {
|
|
215
|
+
this.openDataTarget = target;
|
|
216
|
+
await this.store.openData.ensureInvoiceTemplateSettings(target, injectedOpenData);
|
|
217
|
+
this.otherParams.openData = injectedOpenData;
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
await this.loadOpenDataConfig();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.warn('[BookingTicket] Invoice 模板预加载失败,使用默认配置', error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
198
225
|
getBookingTicketBusinessCode() {
|
|
199
|
-
const candidates = [this.otherParams?.businessCode, this.otherParams?.business_code, this.getOrderHeader()?.business_code, this.store.order?.getTempOrder()?.business_code, this.getSalesOrder()?.raw?.business_code];
|
|
226
|
+
const candidates = [this.otherParams?.businessCode, this.otherParams?.business_code, this.getOrderHeader()?.business_code, typeof this.store.order?.getTempOrder === 'function' ? this.store.order.getTempOrder()?.business_code : undefined, this.getSalesOrder()?.raw?.business_code];
|
|
200
227
|
for (const candidate of candidates) {
|
|
201
228
|
if (candidate === undefined || candidate === null) continue;
|
|
202
229
|
const normalized = String(candidate).trim();
|
|
@@ -1784,10 +1811,12 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
1784
1811
|
await super.setOtherParams(params, {
|
|
1785
1812
|
cover
|
|
1786
1813
|
});
|
|
1814
|
+
const invoiceContextChanged = params?.businessCode !== undefined || params?.business_code !== undefined || params?.channel !== undefined || params?.platform !== undefined || Object.prototype.hasOwnProperty.call(params, 'openData');
|
|
1815
|
+
if (invoiceContextChanged) {
|
|
1816
|
+
await this.prepareInvoiceTemplateAtSolutionReady(Object.prototype.hasOwnProperty.call(params, 'openData') ? this.getInjectedOpenDataConfig() : undefined);
|
|
1817
|
+
}
|
|
1787
1818
|
if (params?.businessCode !== undefined || params?.business_code !== undefined) {
|
|
1788
1819
|
await this.configureIdGeneratorFromOpenData();
|
|
1789
|
-
} else if (params?.channel !== undefined) {
|
|
1790
|
-
await this.loadOpenDataConfig();
|
|
1791
1820
|
}
|
|
1792
1821
|
}
|
|
1793
1822
|
getDeviceTaskPlugin() {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.stripOsPrivatePayloadFields = stripOsPrivatePayloadFields;
|
|
7
|
+
var _lodashEs = require("lodash-es");
|
|
8
|
+
const OS_PRIVATE_FIELD_PREFIX = '_os_';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Remove top-level fields reserved for communication with the PisellOS proxy.
|
|
12
|
+
* Nested business payloads are intentionally left untouched.
|
|
13
|
+
*/
|
|
14
|
+
function stripOsPrivatePayloadFields(data) {
|
|
15
|
+
const next = (0, _lodashEs.cloneDeep)(data);
|
|
16
|
+
if (!next || typeof next !== 'object' || Array.isArray(next)) return next;
|
|
17
|
+
const record = next;
|
|
18
|
+
Object.keys(record).forEach(key => {
|
|
19
|
+
if (key.startsWith(OS_PRIVATE_FIELD_PREFIX)) delete record[key];
|
|
20
|
+
});
|
|
21
|
+
return next;
|
|
22
|
+
}
|