@pisell/pisellos 0.10.43 → 0.10.44
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/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/modules/Order/index.d.ts +41 -9
- package/dist/modules/Order/index.js +1438 -878
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +105 -8
- package/dist/modules/Order/types.js +6 -1
- package/dist/modules/Order/utils.d.ts +3 -1
- package/dist/modules/Order/utils.js +191 -71
- package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
- package/dist/modules/Payment/cashRecommendationAlgorithm.js +17 -367
- 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/server/index.d.ts +7 -0
- package/dist/server/index.js +45 -3
- package/dist/server/modules/order/index.js +6 -0
- package/dist/server/modules/order/types.d.ts +9 -0
- package/dist/server/utils/small-ticket.d.ts +1 -0
- package/dist/server/utils/small-ticket.js +142 -14
- package/dist/solution/BaseSales/index.d.ts +15 -1
- package/dist/solution/BaseSales/index.js +1240 -877
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -0
- package/dist/solution/BookingTicket/index.js +37 -16
- 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/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 +15 -2
- package/dist/solution/UnifiedBookingSales/index.js +777 -510
- package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- 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/modules/Order/index.d.ts +41 -9
- package/lib/modules/Order/index.js +434 -61
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +105 -8
- package/lib/modules/Order/types.js +5 -1
- package/lib/modules/Order/utils.d.ts +3 -1
- package/lib/modules/Order/utils.js +114 -1
- package/lib/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +9 -354
- 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/server/index.d.ts +7 -0
- package/lib/server/index.js +39 -3
- package/lib/server/modules/order/index.js +6 -0
- package/lib/server/modules/order/types.d.ts +9 -0
- package/lib/server/utils/small-ticket.d.ts +1 -0
- package/lib/server/utils/small-ticket.js +136 -12
- package/lib/solution/BaseSales/index.d.ts +15 -1
- package/lib/solution/BaseSales/index.js +192 -22
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -0
- package/lib/solution/BookingTicket/index.js +23 -5
- 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/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 +15 -2
- package/lib/solution/UnifiedBookingSales/index.js +125 -1
- package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
package/lib/server/index.d.ts
CHANGED
|
@@ -421,6 +421,7 @@ declare class Server {
|
|
|
421
421
|
private shouldUseLocalOrderQuery;
|
|
422
422
|
/**
|
|
423
423
|
* 预约查询是否走本地:
|
|
424
|
+
* - 日历周/月/资源视图通过 compact_fields 显式标识,始终走远端;
|
|
424
425
|
* - 当 sales_time_between 的开始和结束都不是今天时,走远端;
|
|
425
426
|
* - 其余情况走本地。
|
|
426
427
|
*/
|
|
@@ -524,6 +525,12 @@ declare class Server {
|
|
|
524
525
|
private stringifyCheckoutResourceIdentifier;
|
|
525
526
|
private normalizeCheckoutSubmitData;
|
|
526
527
|
private ensureCheckoutOrderNumbers;
|
|
528
|
+
/**
|
|
529
|
+
* Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
|
|
530
|
+
* shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
|
|
531
|
+
* 都使用同一份完整快照。
|
|
532
|
+
*/
|
|
533
|
+
private finalizeCheckoutSalesNotes;
|
|
527
534
|
private dispatchCheckoutSyncTask;
|
|
528
535
|
private dispatchPrintOtherReceiptTask;
|
|
529
536
|
private buildPrintOtherReceiptIdempotencyKey;
|
package/lib/server/index.js
CHANGED
|
@@ -27,6 +27,7 @@ var _filterBookings = require("./modules/order/utils/filterBookings");
|
|
|
27
27
|
var _smallTicket = require("./utils/small-ticket");
|
|
28
28
|
var _BaseSales = require("../solution/BaseSales");
|
|
29
29
|
var _paymentUtils = require("../modules/Order/payment-utils");
|
|
30
|
+
var _salesNotes = require("../modules/Order/salesNotes");
|
|
30
31
|
var _orderCollectionIdentity = require("../modules/Order/utils/orderCollectionIdentity");
|
|
31
32
|
var _osPrivatePayload = require("../utils/os-private-payload");
|
|
32
33
|
var _OpenData = require("../modules/OpenData");
|
|
@@ -2172,10 +2173,12 @@ class Server {
|
|
|
2172
2173
|
|
|
2173
2174
|
/**
|
|
2174
2175
|
* 预约查询是否走本地:
|
|
2176
|
+
* - 日历周/月/资源视图通过 compact_fields 显式标识,始终走远端;
|
|
2175
2177
|
* - 当 sales_time_between 的开始和结束都不是今天时,走远端;
|
|
2176
2178
|
* - 其余情况走本地。
|
|
2177
2179
|
*/
|
|
2178
2180
|
shouldUseLocalBookingQuery(data) {
|
|
2181
|
+
if (data?.compact_fields === true) return false;
|
|
2179
2182
|
const range = data?.sales_time_between;
|
|
2180
2183
|
if (!Array.isArray(range) || range.length < 2) return true;
|
|
2181
2184
|
return !this.isRangeBothNotToday(range[0], range[1]);
|
|
@@ -3682,14 +3685,16 @@ class Server {
|
|
|
3682
3685
|
};
|
|
3683
3686
|
const needsShopOrderNumber = next.shop_order_number === undefined || next.shop_order_number === null || next.shop_order_number === '';
|
|
3684
3687
|
const needsShopFullOrderNumber = next.shop_full_order_number === undefined || next.shop_full_order_number === null || next.shop_full_order_number === '';
|
|
3685
|
-
if (!needsShopOrderNumber && !needsShopFullOrderNumber)
|
|
3688
|
+
if (!needsShopOrderNumber && !needsShopFullOrderNumber) {
|
|
3689
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3690
|
+
}
|
|
3686
3691
|
const idGenerator = this.getIdGeneratorPlugin();
|
|
3687
3692
|
if (!idGenerator) {
|
|
3688
3693
|
this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
|
|
3689
3694
|
needsShopOrderNumber,
|
|
3690
3695
|
needsShopFullOrderNumber
|
|
3691
3696
|
});
|
|
3692
|
-
return next;
|
|
3697
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3693
3698
|
}
|
|
3694
3699
|
try {
|
|
3695
3700
|
if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
|
|
@@ -3711,7 +3716,38 @@ class Server {
|
|
|
3711
3716
|
error: error instanceof Error ? error.message : String(error)
|
|
3712
3717
|
});
|
|
3713
3718
|
}
|
|
3714
|
-
return next;
|
|
3719
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
/**
|
|
3723
|
+
* Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
|
|
3724
|
+
* shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
|
|
3725
|
+
* 都使用同一份完整快照。
|
|
3726
|
+
*/
|
|
3727
|
+
finalizeCheckoutSalesNotes(data, title) {
|
|
3728
|
+
if (!data || typeof data !== 'object') return data;
|
|
3729
|
+
if (!Object.prototype.hasOwnProperty.call(data, 'notes')) return data;
|
|
3730
|
+
if (data.notes === undefined || data.notes === null) return data;
|
|
3731
|
+
if (!Array.isArray(data.notes)) {
|
|
3732
|
+
throw new Error('[Order Notes] checkout notes 必须为数组');
|
|
3733
|
+
}
|
|
3734
|
+
if (data.notes.length === 0) return data;
|
|
3735
|
+
const productTargetUuids = (Array.isArray(data.products) ? data.products : []).map(product => product?.metadata?.unique_identification_number ?? product?.unique_identification_number).filter(targetUuid => targetUuid !== undefined && targetUuid !== null && String(targetUuid).trim().length > 0).map(targetUuid => String(targetUuid));
|
|
3736
|
+
const shopOrderNumber = String(data.shop_order_number ?? '').trim();
|
|
3737
|
+
const notes = (0, _salesNotes.finalizeSalesNotesForCheckout)({
|
|
3738
|
+
notes: data.notes,
|
|
3739
|
+
shopOrderNumber,
|
|
3740
|
+
productTargetUuids
|
|
3741
|
+
});
|
|
3742
|
+
this.logInfo(`${title}: checkout Notes 已绑定订单号`, {
|
|
3743
|
+
shop_order_number: shopOrderNumber,
|
|
3744
|
+
note_count: notes.length
|
|
3745
|
+
});
|
|
3746
|
+
return {
|
|
3747
|
+
...data,
|
|
3748
|
+
shop_order_number: shopOrderNumber,
|
|
3749
|
+
notes
|
|
3750
|
+
};
|
|
3715
3751
|
}
|
|
3716
3752
|
async dispatchCheckoutSyncTask(params) {
|
|
3717
3753
|
this.registerDeviceTaskActions();
|
|
@@ -2017,6 +2017,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2017
2017
|
mergedRecord[field] = (0, _lodashEs.cloneDeep)(incomingRecord[field]);
|
|
2018
2018
|
}
|
|
2019
2019
|
|
|
2020
|
+
// order_meta_list 是一次性生成的完整业务快照。incoming 明确携带时
|
|
2021
|
+
// 必须整体覆盖(包括 null / 空对象 / 空数组);省略时才保留 existing。
|
|
2022
|
+
if (Object.prototype.hasOwnProperty.call(incomingRecord, 'order_meta_list')) {
|
|
2023
|
+
mergedRecord.order_meta_list = (0, _lodashEs.cloneDeep)(incomingRecord.order_meta_list);
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2020
2026
|
// 子项数组遵循完整快照语义:incoming 自有且为数组(包括 [])时权威替换;
|
|
2021
2027
|
// 字段缺席或不是数组时视为稀疏 patch,继续保留 existing。
|
|
2022
2028
|
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
@@ -456,6 +456,15 @@ export interface OrderData {
|
|
|
456
456
|
par_value: string;
|
|
457
457
|
used_par_value: string;
|
|
458
458
|
}>;
|
|
459
|
+
virtual_currency_snapshot?: Array<{
|
|
460
|
+
id: number | string;
|
|
461
|
+
tag: 'virtual_currency';
|
|
462
|
+
product_id?: number | string;
|
|
463
|
+
product_name: string;
|
|
464
|
+
par_value: string;
|
|
465
|
+
used_par_value: string;
|
|
466
|
+
name: Record<string, string>;
|
|
467
|
+
}>;
|
|
459
468
|
};
|
|
460
469
|
/**
|
|
461
470
|
* 金额汇总(仅输出)。
|
|
@@ -311,6 +311,7 @@ function buildBaseData(params) {
|
|
|
311
311
|
}
|
|
312
312
|
function buildProducts(order, locale, productMap) {
|
|
313
313
|
const products = Array.isArray(order.products) ? order.products : [];
|
|
314
|
+
const allergyByProductUid = buildProductAllergyMap(order, locale);
|
|
314
315
|
return products.map(rawProduct => {
|
|
315
316
|
const product = restoreReceiptDiscountHierarchy(rawProduct);
|
|
316
317
|
const quantity = toNumber(product.product_quantity ?? product.quantity ?? product.num ?? 1, 1);
|
|
@@ -351,6 +352,7 @@ function buildProducts(order, locale, productMap) {
|
|
|
351
352
|
originalPrice
|
|
352
353
|
});
|
|
353
354
|
const productNote = resolveProductNote(product, locale);
|
|
355
|
+
const allergy = isPresentId(productUid) ? allergyByProductUid.get(String(productUid).trim()) || '' : '';
|
|
354
356
|
const basePrice = resolveProductBasePrice(product);
|
|
355
357
|
const resolvedCombinations = Array.isArray(product.combinations) && product.combinations.length ? normalizeExistingCombinations(product.combinations, locale, currencySymbol) : combinations;
|
|
356
358
|
const shouldIncludeBasePrice = options.length > 0 || resolvedCombinations.length > 0 || hasProductDiscount(product, extensionList);
|
|
@@ -380,6 +382,9 @@ function buildProducts(order, locale, productMap) {
|
|
|
380
382
|
...(productNote ? {
|
|
381
383
|
product_note: productNote
|
|
382
384
|
} : {}),
|
|
385
|
+
...(allergy ? {
|
|
386
|
+
allergy
|
|
387
|
+
} : {}),
|
|
383
388
|
...(options.length ? {
|
|
384
389
|
options
|
|
385
390
|
} : {}),
|
|
@@ -782,6 +787,21 @@ function resolveProductNote(product, locale) {
|
|
|
782
787
|
if (productNote) return productNote;
|
|
783
788
|
return getLocalizedValue(product.note, locale).trim();
|
|
784
789
|
}
|
|
790
|
+
function buildProductAllergyMap(order, locale) {
|
|
791
|
+
const allergyByProductUid = new Map();
|
|
792
|
+
for (const note of normalizeArray(order.notes)) {
|
|
793
|
+
if (!note || typeof note !== 'object' || Array.isArray(note) || String(note.note_type || '').trim() !== 'allergy') {
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
const content = getLocalizedValue(note.content?.text, locale).trim();
|
|
797
|
+
if (!content) continue;
|
|
798
|
+
const relation = normalizeArray(note.note_relations).find(item => item && typeof item === 'object' && !Array.isArray(item) && item.relation_type === 'about' && item.target_type === 'order_detail' && Number(item.is_primary) === 1);
|
|
799
|
+
const productUid = String(relation?.target_uuid ?? '').trim();
|
|
800
|
+
if (!productUid || allergyByProductUid.has(productUid)) continue;
|
|
801
|
+
allergyByProductUid.set(productUid, content);
|
|
802
|
+
}
|
|
803
|
+
return allergyByProductUid;
|
|
804
|
+
}
|
|
785
805
|
function resolveBundleProductTitle(params) {
|
|
786
806
|
const {
|
|
787
807
|
bundle,
|
|
@@ -1358,20 +1378,30 @@ function resolveRefundPayment(refund, payments) {
|
|
|
1358
1378
|
return matchedPayment || refund;
|
|
1359
1379
|
}
|
|
1360
1380
|
function buildWallets(params) {
|
|
1381
|
+
const virtualCurrencySnapshots = collectVirtualCurrencySnapshots(params.order);
|
|
1361
1382
|
const displayedWalletPayments = normalizeArray(params.order.payments).filter(payment => isPrintablePayment(payment) && !!getFundRecord(payment));
|
|
1362
|
-
const paymentWallets = displayedWalletPayments.map(payment =>
|
|
1363
|
-
payment,
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1383
|
+
const paymentWallets = displayedWalletPayments.map(payment => {
|
|
1384
|
+
const virtualCurrencySnapshot = findVirtualCurrencySnapshotForPayment(payment, virtualCurrencySnapshots.byId);
|
|
1385
|
+
return buildPaymentItems({
|
|
1386
|
+
payment,
|
|
1387
|
+
locale: params.locale,
|
|
1388
|
+
currencySymbol: params.currencySymbol,
|
|
1389
|
+
includeFundRecordBalance: true,
|
|
1390
|
+
includeFundRecordUsage: false,
|
|
1391
|
+
includePaymentAmount: false,
|
|
1392
|
+
virtualCurrencyUnit: virtualCurrencySnapshot ? getVirtualCurrencySnapshotUnit(virtualCurrencySnapshot, params.locale) : undefined
|
|
1393
|
+
});
|
|
1394
|
+
});
|
|
1370
1395
|
const displayedWalletPassIds = collectDisplayedWalletPassIds(displayedWalletPayments);
|
|
1371
1396
|
return [...paymentWallets, ...buildVoucherAssets(params), ...buildPointCardSnapshotAssets({
|
|
1372
1397
|
order: params.order,
|
|
1373
1398
|
locale: params.locale,
|
|
1374
1399
|
displayedWalletPassIds
|
|
1400
|
+
}), ...buildVirtualCurrencySnapshotAssets({
|
|
1401
|
+
snapshots: virtualCurrencySnapshots.items,
|
|
1402
|
+
order: params.order,
|
|
1403
|
+
locale: params.locale,
|
|
1404
|
+
displayedWalletPassIds
|
|
1375
1405
|
})];
|
|
1376
1406
|
}
|
|
1377
1407
|
function collectDisplayedWalletPassIds(payments) {
|
|
@@ -1418,6 +1448,88 @@ function buildPointCardSnapshotAssets(params) {
|
|
|
1418
1448
|
return [rows];
|
|
1419
1449
|
});
|
|
1420
1450
|
}
|
|
1451
|
+
function collectVirtualCurrencySnapshots(order) {
|
|
1452
|
+
const items = [];
|
|
1453
|
+
const byId = new Map();
|
|
1454
|
+
const snapshots = order.order_meta_list?.virtual_currency_snapshot;
|
|
1455
|
+
if (!Array.isArray(snapshots)) return {
|
|
1456
|
+
items,
|
|
1457
|
+
byId
|
|
1458
|
+
};
|
|
1459
|
+
snapshots.forEach(snapshot => {
|
|
1460
|
+
if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return;
|
|
1461
|
+
const virtualCurrency = snapshot;
|
|
1462
|
+
if (stringify(virtualCurrency.tag).trim().toLowerCase() !== 'virtual_currency') return;
|
|
1463
|
+
const id = normalizeWalletPassId(virtualCurrency.id);
|
|
1464
|
+
if (!id || byId.has(id)) return;
|
|
1465
|
+
byId.set(id, virtualCurrency);
|
|
1466
|
+
items.push(virtualCurrency);
|
|
1467
|
+
});
|
|
1468
|
+
return {
|
|
1469
|
+
items,
|
|
1470
|
+
byId
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
function findVirtualCurrencySnapshotForPayment(payment, snapshotsById) {
|
|
1474
|
+
const fundRecord = getFundRecord(payment);
|
|
1475
|
+
for (const value of [fundRecord?.voucher_id, payment.voucher_id]) {
|
|
1476
|
+
const id = normalizeWalletPassId(value);
|
|
1477
|
+
if (!id) continue;
|
|
1478
|
+
const snapshot = snapshotsById.get(id);
|
|
1479
|
+
if (snapshot) return snapshot;
|
|
1480
|
+
}
|
|
1481
|
+
return undefined;
|
|
1482
|
+
}
|
|
1483
|
+
function buildVirtualCurrencySnapshotAssets(params) {
|
|
1484
|
+
const snapshotTime = firstPresentValue(params.order.updated_at, params.order.created_at);
|
|
1485
|
+
return params.snapshots.flatMap(virtualCurrency => {
|
|
1486
|
+
const id = normalizeWalletPassId(virtualCurrency.id);
|
|
1487
|
+
if (!id || params.displayedWalletPassIds.has(id)) return [];
|
|
1488
|
+
const rows = [{
|
|
1489
|
+
item: stringify(virtualCurrency.product_name).trim(),
|
|
1490
|
+
value: ''
|
|
1491
|
+
}];
|
|
1492
|
+
const balance = getVirtualCurrencySnapshotBalance(virtualCurrency);
|
|
1493
|
+
if (balance) {
|
|
1494
|
+
rows.push({
|
|
1495
|
+
item: label(params.locale, 'balance'),
|
|
1496
|
+
value: formatVirtualCurrencyBalance(balance, getVirtualCurrencySnapshotUnit(virtualCurrency, params.locale))
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
if (isPresentId(snapshotTime)) {
|
|
1500
|
+
rows.push({
|
|
1501
|
+
item: formatDateTime(snapshotTime, params.locale),
|
|
1502
|
+
value: ''
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
return [rows];
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
function getVirtualCurrencySnapshotBalance(snapshot) {
|
|
1509
|
+
if (!isNumericAmount(snapshot.par_value) || !isNumericAmount(snapshot.used_par_value)) {
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
return _decimal.default.max(new _decimal.default(snapshot.par_value).minus(new _decimal.default(snapshot.used_par_value)), 0);
|
|
1513
|
+
}
|
|
1514
|
+
function getVirtualCurrencySnapshotUnit(snapshot, locale) {
|
|
1515
|
+
return getNonEmptyLocalizedValue(snapshot.name, locale);
|
|
1516
|
+
}
|
|
1517
|
+
function getNonEmptyLocalizedValue(value, locale) {
|
|
1518
|
+
if (value === undefined || value === null) return '';
|
|
1519
|
+
if (typeof value !== 'object' || Array.isArray(value)) return stringify(value).trim();
|
|
1520
|
+
const dashedLocale = locale.replace('_', '-');
|
|
1521
|
+
const underscoredLocale = locale.replace('-', '_');
|
|
1522
|
+
for (const candidate of [value[locale], value[dashedLocale], value[underscoredLocale], value.original, value.auto, value.default, value.en]) {
|
|
1523
|
+
const text = stringify(candidate).trim();
|
|
1524
|
+
if (text) return text;
|
|
1525
|
+
}
|
|
1526
|
+
return '';
|
|
1527
|
+
}
|
|
1528
|
+
function formatVirtualCurrencyBalance(value, unit) {
|
|
1529
|
+
const amount = trimDecimal(value);
|
|
1530
|
+
const normalizedUnit = unit.trim();
|
|
1531
|
+
return normalizedUnit ? `${amount} ${normalizedUnit}` : amount;
|
|
1532
|
+
}
|
|
1421
1533
|
function normalizeWalletPassId(value) {
|
|
1422
1534
|
if (typeof value === 'number') return Number.isFinite(value) ? String(value) : null;
|
|
1423
1535
|
if (typeof value !== 'string') return null;
|
|
@@ -1470,8 +1582,9 @@ function buildVoucherAssets(params) {
|
|
|
1470
1582
|
}, ...(timeRow ? [timeRow] : [])]];
|
|
1471
1583
|
});
|
|
1472
1584
|
}
|
|
1585
|
+
const TICKET_VOUCHER_TAGS = new Set(['ticket', 'product_package_ticket', 'appointment_ticket', 'session_ticket']);
|
|
1473
1586
|
function isTicketVoucher(voucher) {
|
|
1474
|
-
return stringify(voucher.tag).trim().toLowerCase()
|
|
1587
|
+
return TICKET_VOUCHER_TAGS.has(stringify(voucher.tag).trim().toLowerCase());
|
|
1475
1588
|
}
|
|
1476
1589
|
function getVoucherValidity(voucher, locale) {
|
|
1477
1590
|
const availableTime = firstPresentValue(voucher.available_time, voucher.avaliable_time, voucher.metadata?.available_time, voucher.metadata?.avaliable_time);
|
|
@@ -1583,7 +1696,8 @@ function buildPaymentItems(params) {
|
|
|
1583
1696
|
currencySymbol,
|
|
1584
1697
|
includeFundRecordBalance,
|
|
1585
1698
|
includeFundRecordUsage,
|
|
1586
|
-
includePaymentAmount
|
|
1699
|
+
includePaymentAmount,
|
|
1700
|
+
virtualCurrencyUnit
|
|
1587
1701
|
} = params;
|
|
1588
1702
|
const serviceFee = getPaymentServiceFee(payment);
|
|
1589
1703
|
const items = [{
|
|
@@ -1609,7 +1723,8 @@ function buildPaymentItems(params) {
|
|
|
1609
1723
|
locale,
|
|
1610
1724
|
currencySymbol,
|
|
1611
1725
|
includeBalance: includeFundRecordBalance,
|
|
1612
|
-
includeUsage: includeFundRecordUsage
|
|
1726
|
+
includeUsage: includeFundRecordUsage,
|
|
1727
|
+
virtualCurrencyUnit
|
|
1613
1728
|
}));
|
|
1614
1729
|
} else {
|
|
1615
1730
|
const remainingAmount = payment.remaining_amount ?? payment.balance ?? payment.metadata?.remaining_amount;
|
|
@@ -1674,7 +1789,8 @@ function buildFundRecordPaymentItems(params) {
|
|
|
1674
1789
|
locale,
|
|
1675
1790
|
currencySymbol,
|
|
1676
1791
|
includeBalance,
|
|
1677
|
-
includeUsage
|
|
1792
|
+
includeUsage,
|
|
1793
|
+
virtualCurrencyUnit
|
|
1678
1794
|
} = params;
|
|
1679
1795
|
const items = [];
|
|
1680
1796
|
const usingBeforeValue = fundRecord.using_before_value;
|
|
@@ -1696,6 +1812,14 @@ function buildFundRecordPaymentItems(params) {
|
|
|
1696
1812
|
return items;
|
|
1697
1813
|
}
|
|
1698
1814
|
if (includeBalance && usingAfterValue !== undefined && usingAfterValue !== null) {
|
|
1815
|
+
if (virtualCurrencyUnit !== undefined) {
|
|
1816
|
+
if (!isNumericAmount(usingAfterValue)) return items;
|
|
1817
|
+
items.push({
|
|
1818
|
+
item: label(locale, 'balance'),
|
|
1819
|
+
value: formatVirtualCurrencyBalance(new _decimal.default(usingAfterValue), virtualCurrencyUnit)
|
|
1820
|
+
});
|
|
1821
|
+
return items;
|
|
1822
|
+
}
|
|
1699
1823
|
items.push({
|
|
1700
1824
|
item: label(locale, 'balance'),
|
|
1701
1825
|
value: formatMoney(usingAfterValue, currencySymbol)
|
|
@@ -2,7 +2,7 @@ import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
3
|
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
|
-
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions } from '../../modules/Order/types';
|
|
5
|
+
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, ShopServiceData, ShopServiceType } from '../../modules/Order/types';
|
|
6
6
|
import type { SubmitPayloadEnhancer } from '../../modules/Order/utils';
|
|
7
7
|
import type { Discount, VirtualCurrencyAsset } from '../../modules/Discount/types';
|
|
8
8
|
import { RequestPlugin, WindowPlugin } from '../../plugins';
|
|
@@ -232,6 +232,12 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
232
232
|
getOrderSyncState(): import("../../modules/Order/types").OrderSyncState;
|
|
233
233
|
getOrderAmountSnapshot(): import("../../modules/Order/types").OrderAmountSnapshot | null;
|
|
234
234
|
getTempOrderNote(): string;
|
|
235
|
+
getSalesNotes(): SalesNote[];
|
|
236
|
+
createSalesNotesMutationSnapshot(): SalesNotesMutationSnapshot;
|
|
237
|
+
restoreSalesNotesMutationSnapshot(snapshot: SalesNotesMutationSnapshot): void;
|
|
238
|
+
setSalesNote(input: SetSalesNoteInput): Promise<SalesNote>;
|
|
239
|
+
removeSalesNote(uuid: string): Promise<void>;
|
|
240
|
+
clearSalesNotes(): Promise<void>;
|
|
235
241
|
updateTempOrderNote(note: string): string;
|
|
236
242
|
updateTempOrderNote(note: string, sync: true): Promise<string>;
|
|
237
243
|
updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
|
|
@@ -240,6 +246,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
240
246
|
setPickupRef(buzzer: string): string;
|
|
241
247
|
updateTempOrderShopDiscount(amount: string | number): string;
|
|
242
248
|
updateTempOrderDepositAmount(amount: string | number): OrderSummary;
|
|
249
|
+
setPickupReferenceMode(mode: PickupReferenceMode): ShopServiceData;
|
|
250
|
+
setServiceType(serviceType: ShopServiceType): ShopServiceData;
|
|
243
251
|
updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
|
|
244
252
|
/** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化。 */
|
|
245
253
|
setEnableTempOrderPersist(enabled: boolean): void;
|
|
@@ -263,6 +271,12 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
263
271
|
private mergeHistoricalDiscountList;
|
|
264
272
|
private shouldSkipAutoApplyFetchedDiscountsInEditMode;
|
|
265
273
|
private mergeCurrentDiscountSelectionState;
|
|
274
|
+
private resolveDiscountConfigCustomerId;
|
|
275
|
+
/**
|
|
276
|
+
* Stable across notifyTempOrderChanged's immutable object replacement, while
|
|
277
|
+
* still distinguishing two local orders for the same customer.
|
|
278
|
+
*/
|
|
279
|
+
private getDiscountConfigOrderIdentityKey;
|
|
266
280
|
loadDiscountConfig(params?: {
|
|
267
281
|
customerId?: number;
|
|
268
282
|
action?: 'create' | 'edit';
|