@pisell/pisellos 0.10.46 → 0.10.48
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/Discount/types.d.ts +2 -0
- package/dist/modules/Rules/index.d.ts +2 -2
- package/dist/modules/Rules/index.js +129 -65
- package/dist/server/modules/order/types.d.ts +2 -0
- package/dist/server/utils/small-ticket.js +441 -64
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/Discount/types.d.ts +2 -0
- package/lib/modules/Rules/index.d.ts +2 -2
- package/lib/modules/Rules/index.js +71 -7
- package/lib/server/modules/order/types.d.ts +2 -0
- package/lib/server/utils/small-ticket.js +331 -51
- package/package.json +1 -1
|
@@ -9,15 +9,31 @@ var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
|
9
9
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
10
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
11
|
const DEFAULT_LOCALES = ['en', 'zh_CN'];
|
|
12
|
+
const SERVICE_TYPE_LABEL_KEYS = {
|
|
13
|
+
takeaway: 'takeAway',
|
|
14
|
+
pick_up: 'pickUp',
|
|
15
|
+
table_service: 'tableService',
|
|
16
|
+
delivery: 'delivery',
|
|
17
|
+
room_service: 'roomService',
|
|
18
|
+
dine_in: 'dineIn',
|
|
19
|
+
delivery_by_uber: 'deliveryByUber',
|
|
20
|
+
delivery_by_panda: 'deliveryByPanda',
|
|
21
|
+
delivery_by_merchant: 'deliveryByMerchant'
|
|
22
|
+
};
|
|
12
23
|
const LABELS = {
|
|
13
24
|
en: {
|
|
14
25
|
contactName: 'Contact name',
|
|
15
26
|
contactMobile: 'Contact Mobile',
|
|
16
27
|
email: 'email',
|
|
17
|
-
dineIn: 'Dine
|
|
18
|
-
takeAway: '
|
|
28
|
+
dineIn: 'Dine in',
|
|
29
|
+
takeAway: 'Takeaway',
|
|
19
30
|
delivery: 'Delivery',
|
|
20
|
-
pickUp: '
|
|
31
|
+
pickUp: 'Pickup',
|
|
32
|
+
tableService: 'Table Service',
|
|
33
|
+
roomService: 'Room Service',
|
|
34
|
+
deliveryByUber: 'Uber Eats Delivery',
|
|
35
|
+
deliveryByPanda: 'HungryPanda Delivery',
|
|
36
|
+
deliveryByMerchant: 'Merchant Delivery',
|
|
21
37
|
shopService: 'Dine-in',
|
|
22
38
|
pickUpTime: 'Pick-up time',
|
|
23
39
|
asap: 'ASAP',
|
|
@@ -33,6 +49,7 @@ const LABELS = {
|
|
|
33
49
|
remainingAmount: 'Remaining amount',
|
|
34
50
|
redeemPoints: 'Redeem points',
|
|
35
51
|
remainingPoints: 'Points balance',
|
|
52
|
+
entitlementRemaining: 'Remaining',
|
|
36
53
|
table: 'Table',
|
|
37
54
|
bookingId: 'Booking ID',
|
|
38
55
|
bookingDateTime: 'Date & time',
|
|
@@ -56,7 +73,12 @@ const LABELS = {
|
|
|
56
73
|
dineIn: '堂食',
|
|
57
74
|
takeAway: '外带',
|
|
58
75
|
delivery: '配送',
|
|
59
|
-
pickUp: '
|
|
76
|
+
pickUp: '自取',
|
|
77
|
+
tableService: '送餐到桌',
|
|
78
|
+
roomService: '客房服务',
|
|
79
|
+
deliveryByUber: 'Uber 配送',
|
|
80
|
+
deliveryByPanda: '熊猫外卖配送',
|
|
81
|
+
deliveryByMerchant: '商家配送',
|
|
60
82
|
shopService: '堂食',
|
|
61
83
|
pickUpTime: '取餐时间',
|
|
62
84
|
asap: '尽快',
|
|
@@ -72,6 +94,7 @@ const LABELS = {
|
|
|
72
94
|
remainingAmount: '剩余金额',
|
|
73
95
|
redeemPoints: '本次使用积分',
|
|
74
96
|
remainingPoints: '积分余额',
|
|
97
|
+
entitlementRemaining: '剩余次数',
|
|
75
98
|
table: '桌台',
|
|
76
99
|
bookingId: '预约编号',
|
|
77
100
|
bookingDateTime: '日期和时间',
|
|
@@ -96,6 +119,11 @@ const LABELS = {
|
|
|
96
119
|
takeAway: '外帶',
|
|
97
120
|
delivery: '配送',
|
|
98
121
|
pickUp: '自取',
|
|
122
|
+
tableService: '送餐到桌',
|
|
123
|
+
roomService: '客房服務',
|
|
124
|
+
deliveryByUber: 'Uber 配送',
|
|
125
|
+
deliveryByPanda: '熊貓外賣配送',
|
|
126
|
+
deliveryByMerchant: '商家配送',
|
|
99
127
|
shopService: '堂食',
|
|
100
128
|
pickUpTime: '取餐時間',
|
|
101
129
|
asap: '盡快',
|
|
@@ -111,6 +139,7 @@ const LABELS = {
|
|
|
111
139
|
remainingAmount: '剩餘金額',
|
|
112
140
|
redeemPoints: '本次使用積分',
|
|
113
141
|
remainingPoints: '積分餘額',
|
|
142
|
+
entitlementRemaining: '剩餘次數',
|
|
114
143
|
table: '桌台',
|
|
115
144
|
bookingId: '預約編號',
|
|
116
145
|
bookingDateTime: '日期和時間',
|
|
@@ -135,6 +164,11 @@ const LABELS = {
|
|
|
135
164
|
takeAway: 'テイクアウト',
|
|
136
165
|
delivery: '配達',
|
|
137
166
|
pickUp: '受け取り',
|
|
167
|
+
tableService: 'テーブルサービス',
|
|
168
|
+
roomService: 'ルームサービス',
|
|
169
|
+
deliveryByUber: 'Uber Eats 配達',
|
|
170
|
+
deliveryByPanda: 'HungryPanda 配達',
|
|
171
|
+
deliveryByMerchant: '店舗による配達',
|
|
138
172
|
shopService: '店内飲食',
|
|
139
173
|
pickUpTime: '受取時間',
|
|
140
174
|
asap: 'できるだけ早く',
|
|
@@ -148,6 +182,7 @@ const LABELS = {
|
|
|
148
182
|
remainingAmount: '残高',
|
|
149
183
|
redeemPoints: '利用ポイント',
|
|
150
184
|
remainingPoints: 'ポイント残高',
|
|
185
|
+
entitlementRemaining: '残り回数',
|
|
151
186
|
table: 'テーブル',
|
|
152
187
|
bookingId: '予約ID',
|
|
153
188
|
bookingDateTime: '日時',
|
|
@@ -173,6 +208,11 @@ const LABELS = {
|
|
|
173
208
|
takeAway: 'Para levar',
|
|
174
209
|
delivery: 'Entrega',
|
|
175
210
|
pickUp: 'Recolha',
|
|
211
|
+
tableService: 'Serviço à mesa',
|
|
212
|
+
roomService: 'Serviço de quarto',
|
|
213
|
+
deliveryByUber: 'Entrega pela Uber Eats',
|
|
214
|
+
deliveryByPanda: 'Entrega pela HungryPanda',
|
|
215
|
+
deliveryByMerchant: 'Entrega pelo comerciante',
|
|
176
216
|
shopService: 'Consumo no local',
|
|
177
217
|
pickUpTime: 'Hora de recolha',
|
|
178
218
|
asap: 'Assim que possível',
|
|
@@ -186,6 +226,7 @@ const LABELS = {
|
|
|
186
226
|
remainingAmount: 'Saldo restante',
|
|
187
227
|
redeemPoints: 'Pontos utilizados',
|
|
188
228
|
remainingPoints: 'Saldo de pontos',
|
|
229
|
+
entitlementRemaining: 'Utilizações restantes',
|
|
189
230
|
table: 'Mesa',
|
|
190
231
|
bookingId: 'ID da reserva',
|
|
191
232
|
bookingDateTime: 'Data e hora',
|
|
@@ -1128,9 +1169,8 @@ function normalizeCustomerDisplayValue(value) {
|
|
|
1128
1169
|
return text;
|
|
1129
1170
|
}
|
|
1130
1171
|
function buildDelivery(order, locale) {
|
|
1131
|
-
const
|
|
1132
|
-
const
|
|
1133
|
-
const serviceTypeLabelKey = resolveServiceTypeLabelKey(serviceType, order);
|
|
1172
|
+
const serviceType = stringify(order.metadata?.shop_service_data?.service_type).trim();
|
|
1173
|
+
const serviceTypeLabelKey = resolveServiceTypeLabelKey(serviceType);
|
|
1134
1174
|
if (!serviceTypeLabelKey) return [];
|
|
1135
1175
|
const items = [{
|
|
1136
1176
|
item: '',
|
|
@@ -1392,42 +1432,241 @@ function buildWallets(params) {
|
|
|
1392
1432
|
virtualCurrencyUnit: virtualCurrencySnapshot ? getVirtualCurrencySnapshotUnit(virtualCurrencySnapshot, params.locale) : undefined
|
|
1393
1433
|
});
|
|
1394
1434
|
});
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1435
|
+
const displayedWalletAssetIdentities = collectDisplayedWalletAssetIdentities(displayedWalletPayments);
|
|
1436
|
+
const voucherWallets = buildVoucherAssets({
|
|
1437
|
+
...params,
|
|
1438
|
+
displayedWalletAssetIdentities
|
|
1439
|
+
});
|
|
1440
|
+
const productDiscountWallets = buildProductDiscountAssets({
|
|
1441
|
+
...params,
|
|
1442
|
+
displayedWalletAssetIdentities
|
|
1443
|
+
});
|
|
1444
|
+
return [...paymentWallets, ...voucherWallets, ...productDiscountWallets, ...buildPointCardSnapshotAssets({
|
|
1397
1445
|
order: params.order,
|
|
1398
1446
|
locale: params.locale,
|
|
1399
|
-
|
|
1447
|
+
displayedWalletAssetIdentities
|
|
1400
1448
|
}), ...buildVirtualCurrencySnapshotAssets({
|
|
1401
1449
|
snapshots: virtualCurrencySnapshots.items,
|
|
1402
1450
|
order: params.order,
|
|
1403
1451
|
locale: params.locale,
|
|
1404
|
-
|
|
1452
|
+
displayedWalletAssetIdentities
|
|
1405
1453
|
})];
|
|
1406
1454
|
}
|
|
1407
|
-
function
|
|
1408
|
-
const
|
|
1455
|
+
function collectDisplayedWalletAssetIdentities(payments) {
|
|
1456
|
+
const identities = [];
|
|
1409
1457
|
payments.forEach(payment => {
|
|
1410
1458
|
const fundRecord = getFundRecord(payment);
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1459
|
+
const ids = Array.from(new Set([fundRecord?.voucher_id, payment.voucher_id].map(value => normalizeWalletPassId(value)).filter(value => !!value)));
|
|
1460
|
+
const codes = normalizeWalletAssetCodes(fundRecord?.code, fundRecord?.encoded);
|
|
1461
|
+
if (!ids.length) {
|
|
1462
|
+
registerWalletAssetIdentity(identities, {
|
|
1463
|
+
id: null,
|
|
1464
|
+
codes
|
|
1465
|
+
});
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
ids.forEach(id => {
|
|
1469
|
+
registerWalletAssetIdentity(identities, {
|
|
1470
|
+
id,
|
|
1471
|
+
codes
|
|
1472
|
+
});
|
|
1414
1473
|
});
|
|
1415
1474
|
});
|
|
1416
|
-
return
|
|
1475
|
+
return identities;
|
|
1476
|
+
}
|
|
1477
|
+
const PRODUCT_WALLET_DISCOUNT_TYPES = new Set(['good_pass', 'discount_card', 'product_discount_card', 'entitlement_pass']);
|
|
1478
|
+
function buildProductDiscountAssets(params) {
|
|
1479
|
+
const fallbackAssetTime = firstPresentValue(params.order.updated_at, params.order.created_at);
|
|
1480
|
+
return collectProductWalletDiscountAssets(params.order).flatMap(asset => {
|
|
1481
|
+
if (!claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
|
|
1482
|
+
id: asset.id,
|
|
1483
|
+
codes: asset.codes
|
|
1484
|
+
})) return [];
|
|
1485
|
+
const name = getProductWalletDiscountName(asset, params.locale);
|
|
1486
|
+
const assetTime = getProductWalletDiscountTime(asset) ?? fallbackAssetTime;
|
|
1487
|
+
const timeRow = isPresentId(assetTime) ? {
|
|
1488
|
+
item: formatDateTime(assetTime, params.locale),
|
|
1489
|
+
value: ''
|
|
1490
|
+
} : null;
|
|
1491
|
+
if (asset.type === 'entitlement_pass') {
|
|
1492
|
+
const remaining = getProductEntitlementBalance(asset);
|
|
1493
|
+
return [[{
|
|
1494
|
+
item: name,
|
|
1495
|
+
value: ''
|
|
1496
|
+
}, ...(remaining ? [{
|
|
1497
|
+
item: label(params.locale, 'entitlementRemaining'),
|
|
1498
|
+
value: formatEntitlementUses(remaining, params.locale)
|
|
1499
|
+
}] : []), ...(timeRow ? [timeRow] : [])]];
|
|
1500
|
+
}
|
|
1501
|
+
const percent = getProductWalletDiscountPercent(asset);
|
|
1502
|
+
if (percent) {
|
|
1503
|
+
return [[{
|
|
1504
|
+
item: appendPercentToVoucherName(name, percent),
|
|
1505
|
+
value: formatVoucherDiscount(percent, params.locale)
|
|
1506
|
+
}, ...(timeRow ? [timeRow] : [])]];
|
|
1507
|
+
}
|
|
1508
|
+
const balance = getProductWalletMoneyBalance(asset);
|
|
1509
|
+
return [[{
|
|
1510
|
+
item: name,
|
|
1511
|
+
value: ''
|
|
1512
|
+
}, ...(balance ? [{
|
|
1513
|
+
item: label(params.locale, 'balance'),
|
|
1514
|
+
value: formatMoney(balance, params.currencySymbol)
|
|
1515
|
+
}] : []), ...(timeRow ? [timeRow] : [])]];
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
function collectProductWalletDiscountAssets(order) {
|
|
1519
|
+
const assets = [];
|
|
1520
|
+
const assetsById = new Map();
|
|
1521
|
+
normalizeArray(order.products).forEach(rawProduct => {
|
|
1522
|
+
if (!rawProduct || typeof rawProduct !== 'object') return;
|
|
1523
|
+
visitProductWalletDiscounts(restoreReceiptDiscountHierarchy(rawProduct), assets, assetsById);
|
|
1524
|
+
});
|
|
1525
|
+
return assets;
|
|
1526
|
+
}
|
|
1527
|
+
function visitProductWalletDiscounts(product, assets, assetsById) {
|
|
1528
|
+
normalizeArray(product.discount_list).forEach(record => {
|
|
1529
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)) return;
|
|
1530
|
+
const type = getProductWalletDiscountType(record);
|
|
1531
|
+
if (!type) return;
|
|
1532
|
+
const id = getProductWalletDiscountAssetId(record);
|
|
1533
|
+
if (!id) return;
|
|
1534
|
+
const codes = getProductWalletDiscountCodes(record);
|
|
1535
|
+
const existing = assetsById.get(id);
|
|
1536
|
+
if (existing) {
|
|
1537
|
+
existing.records.push(record);
|
|
1538
|
+
existing.codes = Array.from(new Set([...existing.codes, ...codes]));
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
const asset = {
|
|
1542
|
+
id,
|
|
1543
|
+
type,
|
|
1544
|
+
codes,
|
|
1545
|
+
records: [record]
|
|
1546
|
+
};
|
|
1547
|
+
assetsById.set(id, asset);
|
|
1548
|
+
assets.push(asset);
|
|
1549
|
+
});
|
|
1550
|
+
for (const childKey of ['combinations', 'product_bundle', 'bundle']) {
|
|
1551
|
+
normalizeArray(product[childKey]).forEach(child => {
|
|
1552
|
+
if (!child || typeof child !== 'object' || Array.isArray(child)) return;
|
|
1553
|
+
visitProductWalletDiscounts(child, assets, assetsById);
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
function getProductWalletDiscountType(record) {
|
|
1558
|
+
for (const value of [record.tag, record.type, record.discount?.tag, record.discount?.type]) {
|
|
1559
|
+
const type = stringify(value).trim().toLowerCase();
|
|
1560
|
+
if (PRODUCT_WALLET_DISCOUNT_TYPES.has(type)) return type;
|
|
1561
|
+
}
|
|
1562
|
+
return null;
|
|
1563
|
+
}
|
|
1564
|
+
function getProductWalletDiscountAssetId(record) {
|
|
1565
|
+
for (const value of [record.discount?.resource_id, record.resource_id, record.id, record.discount_id]) {
|
|
1566
|
+
const id = normalizeWalletPassId(value);
|
|
1567
|
+
if (id && id !== '0') return id;
|
|
1568
|
+
}
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
function getProductWalletDiscountCodes(record) {
|
|
1572
|
+
return normalizeWalletAssetCodes(record.code, record.encoded, record.discount?.code, record.discount?.encoded);
|
|
1573
|
+
}
|
|
1574
|
+
function getProductWalletDiscountName(asset, locale) {
|
|
1575
|
+
for (const record of asset.records) {
|
|
1576
|
+
for (const value of [record.discount?.title, record.discount?.name, record.discount?.message, record.product_name, record.format_title, record.title, record.name, record.message]) {
|
|
1577
|
+
const name = getLocalizedValue(value, locale).trim();
|
|
1578
|
+
if (name) return name;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
return asset.codes[0] || label(locale, 'giftCard');
|
|
1582
|
+
}
|
|
1583
|
+
function getProductWalletDiscountTime(asset) {
|
|
1584
|
+
for (const field of ['updated_at', 'created_at', 'collection_time']) {
|
|
1585
|
+
for (const record of asset.records) {
|
|
1586
|
+
const value = firstPresentValue(record[field], record.discount?.[field]);
|
|
1587
|
+
if (isPresentId(value)) return value;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return undefined;
|
|
1591
|
+
}
|
|
1592
|
+
function getProductEntitlementBalance(asset) {
|
|
1593
|
+
for (const record of asset.records) {
|
|
1594
|
+
const balance = getEntitlementBalance(record.balance, record.discount?.balance);
|
|
1595
|
+
if (balance) return balance;
|
|
1596
|
+
}
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
function getEntitlementBalance(...values) {
|
|
1600
|
+
for (const value of values) {
|
|
1601
|
+
if (!isNumericAmount(value)) continue;
|
|
1602
|
+
const balance = new _decimal.default(value);
|
|
1603
|
+
if (balance.isFinite() && balance.isInteger() && balance.gte(0)) {
|
|
1604
|
+
return balance;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
function formatEntitlementUses(value, locale) {
|
|
1610
|
+
const count = value.toFixed(0);
|
|
1611
|
+
switch (normalizeLocaleKey(locale)) {
|
|
1612
|
+
case 'zh_CN':
|
|
1613
|
+
case 'zh_HK':
|
|
1614
|
+
return `${count}次`;
|
|
1615
|
+
case 'ja':
|
|
1616
|
+
return `${count}回`;
|
|
1617
|
+
case 'pt':
|
|
1618
|
+
return `${count} ${value.eq(1) ? 'utilização' : 'utilizações'}`;
|
|
1619
|
+
default:
|
|
1620
|
+
return `${count} ${value.eq(1) ? 'use' : 'uses'}`;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
function getProductWalletDiscountPercent(asset) {
|
|
1624
|
+
if (asset.type !== 'discount_card' && asset.type !== 'product_discount_card') return null;
|
|
1625
|
+
for (const record of asset.records) {
|
|
1626
|
+
const discountType = stringify(firstPresentValue(record.discount_card_type, record.metadata?.discount_card_type, record.discount?.discount_card_type, record.discount?.metadata?.discount_card_type)).trim().toLowerCase();
|
|
1627
|
+
if (discountType && discountType !== 'percent' && discountType !== 'percentage') continue;
|
|
1628
|
+
const candidates = [record.percent, record.discount?.percent];
|
|
1629
|
+
if (discountType === 'percent' || discountType === 'percentage') {
|
|
1630
|
+
candidates.push(record.par_value, record.discount?.par_value);
|
|
1631
|
+
}
|
|
1632
|
+
for (const value of candidates) {
|
|
1633
|
+
if (!isNumericAmount(value)) continue;
|
|
1634
|
+
const percent = new _decimal.default(value);
|
|
1635
|
+
if (percent.isFinite() && percent.gt(0) && percent.lte(100)) {
|
|
1636
|
+
return percent;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
return null;
|
|
1641
|
+
}
|
|
1642
|
+
function getProductWalletMoneyBalance(asset) {
|
|
1643
|
+
for (const record of asset.records) {
|
|
1644
|
+
for (const value of [record.balance, record.discount?.balance]) {
|
|
1645
|
+
if (!isNumericAmount(value)) continue;
|
|
1646
|
+
return _decimal.default.max(new _decimal.default(value), 0);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
for (const record of asset.records) {
|
|
1650
|
+
const parValue = firstPresentValue(record.par_value, record.discount?.par_value);
|
|
1651
|
+
const usedParValue = firstPresentValue(record.used_par_value, record.discount?.used_par_value);
|
|
1652
|
+
if (!isNumericAmount(parValue) || !isNumericAmount(usedParValue)) continue;
|
|
1653
|
+
return _decimal.default.max(new _decimal.default(parValue).minus(new _decimal.default(usedParValue)), 0);
|
|
1654
|
+
}
|
|
1655
|
+
return null;
|
|
1417
1656
|
}
|
|
1418
1657
|
function buildPointCardSnapshotAssets(params) {
|
|
1419
1658
|
const snapshots = params.order.order_meta_list?.point_cards_snapshot;
|
|
1420
1659
|
if (!Array.isArray(snapshots)) return [];
|
|
1421
1660
|
const snapshotTime = firstPresentValue(params.order.updated_at, params.order.created_at);
|
|
1422
|
-
const seenSnapshotIds = new Set();
|
|
1423
1661
|
return snapshots.flatMap(snapshot => {
|
|
1424
1662
|
if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return [];
|
|
1425
1663
|
const pointCard = snapshot;
|
|
1426
1664
|
if (stringify(pointCard.tag).trim().toLowerCase() !== 'point_card') return [];
|
|
1427
|
-
const
|
|
1428
|
-
if (!
|
|
1429
|
-
|
|
1430
|
-
|
|
1665
|
+
const assetId = normalizeWalletPassId(pointCard.id);
|
|
1666
|
+
if (!assetId || !claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
|
|
1667
|
+
id: assetId,
|
|
1668
|
+
codes: []
|
|
1669
|
+
})) return [];
|
|
1431
1670
|
const rows = [{
|
|
1432
1671
|
item: stringify(pointCard.product_name).trim() || label(params.locale, 'pointCard'),
|
|
1433
1672
|
value: ''
|
|
@@ -1483,8 +1722,11 @@ function findVirtualCurrencySnapshotForPayment(payment, snapshotsById) {
|
|
|
1483
1722
|
function buildVirtualCurrencySnapshotAssets(params) {
|
|
1484
1723
|
const snapshotTime = firstPresentValue(params.order.updated_at, params.order.created_at);
|
|
1485
1724
|
return params.snapshots.flatMap(virtualCurrency => {
|
|
1486
|
-
const
|
|
1487
|
-
if (!
|
|
1725
|
+
const assetId = normalizeWalletPassId(virtualCurrency.id);
|
|
1726
|
+
if (!assetId || !claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
|
|
1727
|
+
id: assetId,
|
|
1728
|
+
codes: []
|
|
1729
|
+
})) return [];
|
|
1488
1730
|
const rows = [{
|
|
1489
1731
|
item: stringify(virtualCurrency.product_name).trim(),
|
|
1490
1732
|
value: ''
|
|
@@ -1535,6 +1777,49 @@ function normalizeWalletPassId(value) {
|
|
|
1535
1777
|
if (typeof value !== 'string') return null;
|
|
1536
1778
|
return value.trim() || null;
|
|
1537
1779
|
}
|
|
1780
|
+
function firstNormalizedWalletAssetId(...values) {
|
|
1781
|
+
for (const value of values) {
|
|
1782
|
+
const id = normalizeWalletPassId(value);
|
|
1783
|
+
if (id) return id;
|
|
1784
|
+
}
|
|
1785
|
+
return null;
|
|
1786
|
+
}
|
|
1787
|
+
function normalizeWalletAssetCodes(...values) {
|
|
1788
|
+
return Array.from(new Set(values.map(value => normalizeWalletPassId(value)).filter(value => !!value)));
|
|
1789
|
+
}
|
|
1790
|
+
function registerWalletAssetIdentity(identities, candidate) {
|
|
1791
|
+
if (!candidate.id && !candidate.codes.length) return;
|
|
1792
|
+
const existing = identities.find(identity => isSameWalletAssetIdentity(identity, candidate));
|
|
1793
|
+
if (existing) {
|
|
1794
|
+
mergeWalletAssetIdentity(existing, candidate);
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
identities.push({
|
|
1798
|
+
id: candidate.id,
|
|
1799
|
+
codes: [...candidate.codes]
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
function claimWalletAssetIdentity(identities, candidate) {
|
|
1803
|
+
if (!candidate.id && !candidate.codes.length) return true;
|
|
1804
|
+
const existing = identities.find(identity => isSameWalletAssetIdentity(identity, candidate));
|
|
1805
|
+
if (existing) {
|
|
1806
|
+
mergeWalletAssetIdentity(existing, candidate);
|
|
1807
|
+
return false;
|
|
1808
|
+
}
|
|
1809
|
+
identities.push({
|
|
1810
|
+
id: candidate.id,
|
|
1811
|
+
codes: [...candidate.codes]
|
|
1812
|
+
});
|
|
1813
|
+
return true;
|
|
1814
|
+
}
|
|
1815
|
+
function isSameWalletAssetIdentity(left, right) {
|
|
1816
|
+
if (left.id && right.id) return left.id === right.id;
|
|
1817
|
+
return left.codes.some(code => right.codes.includes(code));
|
|
1818
|
+
}
|
|
1819
|
+
function mergeWalletAssetIdentity(target, source) {
|
|
1820
|
+
if (!target.id && source.id) target.id = source.id;
|
|
1821
|
+
target.codes = Array.from(new Set([...target.codes, ...source.codes]));
|
|
1822
|
+
}
|
|
1538
1823
|
function getPointCardSnapshotRemainingPoints(snapshot) {
|
|
1539
1824
|
if (!isNumericAmount(snapshot.par_value) || !isNumericAmount(snapshot.used_par_value)) {
|
|
1540
1825
|
return null;
|
|
@@ -1542,19 +1827,26 @@ function getPointCardSnapshotRemainingPoints(snapshot) {
|
|
|
1542
1827
|
return _decimal.default.max(new _decimal.default(snapshot.par_value).minus(new _decimal.default(snapshot.used_par_value)), 0);
|
|
1543
1828
|
}
|
|
1544
1829
|
function buildVoucherAssets(params) {
|
|
1545
|
-
const seenVoucherKeys = new Set();
|
|
1546
1830
|
const fallbackAssetTime = firstPresentValue(params.order.updated_at, params.order.created_at);
|
|
1547
|
-
return normalizeArray(params.order.vouchers).flatMap(
|
|
1831
|
+
return normalizeArray(params.order.vouchers).flatMap(voucher => {
|
|
1548
1832
|
if (!voucher || typeof voucher !== 'object' || Array.isArray(voucher)) return [];
|
|
1549
|
-
|
|
1550
|
-
if (seenVoucherKeys.has(voucherKey)) return [];
|
|
1551
|
-
seenVoucherKeys.add(voucherKey);
|
|
1833
|
+
if (!claimWalletAssetIdentity(params.displayedWalletAssetIdentities, getVoucherAssetIdentity(voucher))) return [];
|
|
1552
1834
|
const name = getVoucherAssetName(voucher, params.locale);
|
|
1553
1835
|
const assetTime = firstPresentValue(voucher.updated_at, voucher.created_at, voucher.collection_time, fallbackAssetTime);
|
|
1554
1836
|
const timeRow = isPresentId(assetTime) ? {
|
|
1555
1837
|
item: formatDateTime(assetTime, params.locale),
|
|
1556
1838
|
value: ''
|
|
1557
1839
|
} : null;
|
|
1840
|
+
if (isEntitlementVoucher(voucher)) {
|
|
1841
|
+
const remaining = getEntitlementBalance(voucher.balance, voucher.metadata?.balance);
|
|
1842
|
+
return [[{
|
|
1843
|
+
item: name,
|
|
1844
|
+
value: ''
|
|
1845
|
+
}, ...(remaining ? [{
|
|
1846
|
+
item: label(params.locale, 'entitlementRemaining'),
|
|
1847
|
+
value: formatEntitlementUses(remaining, params.locale)
|
|
1848
|
+
}] : []), ...(timeRow ? [timeRow] : [])]];
|
|
1849
|
+
}
|
|
1558
1850
|
if (isTicketVoucher(voucher)) {
|
|
1559
1851
|
const validity = getVoucherValidity(voucher, params.locale);
|
|
1560
1852
|
return [[{
|
|
@@ -1583,6 +1875,9 @@ function buildVoucherAssets(params) {
|
|
|
1583
1875
|
});
|
|
1584
1876
|
}
|
|
1585
1877
|
const TICKET_VOUCHER_TAGS = new Set(['ticket', 'product_package_ticket', 'appointment_ticket', 'session_ticket']);
|
|
1878
|
+
function isEntitlementVoucher(voucher) {
|
|
1879
|
+
return [voucher.tag, voucher.type].some(value => stringify(value).trim().toLowerCase() === 'entitlement_pass');
|
|
1880
|
+
}
|
|
1586
1881
|
function isTicketVoucher(voucher) {
|
|
1587
1882
|
return TICKET_VOUCHER_TAGS.has(stringify(voucher.tag).trim().toLowerCase());
|
|
1588
1883
|
}
|
|
@@ -1657,9 +1952,11 @@ function formatVoucherValidityDate(value, locale) {
|
|
|
1657
1952
|
text: time ? `${time} ${date}` : date
|
|
1658
1953
|
};
|
|
1659
1954
|
}
|
|
1660
|
-
function
|
|
1661
|
-
|
|
1662
|
-
|
|
1955
|
+
function getVoucherAssetIdentity(voucher) {
|
|
1956
|
+
return {
|
|
1957
|
+
id: firstNormalizedWalletAssetId(voucher.voucher_id, voucher.id),
|
|
1958
|
+
codes: normalizeWalletAssetCodes(voucher.code, voucher.encoded)
|
|
1959
|
+
};
|
|
1663
1960
|
}
|
|
1664
1961
|
function getVoucherAssetName(voucher, locale) {
|
|
1665
1962
|
return getLocalizedValue(voucher.product_name || voucher.name || voucher.title, locale) || stringify(voucher.encoded || voucher.code || label(locale, 'giftCard'));
|
|
@@ -1896,25 +2193,8 @@ function getLocalizedValue(value, locale) {
|
|
|
1896
2193
|
const underscoredLocale = locale.replace('-', '_');
|
|
1897
2194
|
return stringify(value[locale] ?? value[dashedLocale] ?? value[underscoredLocale] ?? value.original ?? value.auto ?? value.default ?? value.en ?? '');
|
|
1898
2195
|
}
|
|
1899
|
-
function resolveServiceTypeLabelKey(serviceType
|
|
1900
|
-
|
|
1901
|
-
if (['', 'nil', 'none', 'unknown'].includes(normalized)) return null;
|
|
1902
|
-
if (['pickup', 'pick_up', 'self_pickup'].includes(normalized)) return 'pickUp';
|
|
1903
|
-
if (['delivery', 'shipping', 'local_delivery'].includes(normalized)) return 'delivery';
|
|
1904
|
-
if (['takeaway', 'take_away'].includes(normalized)) return 'takeAway';
|
|
1905
|
-
if (['dine_in', 'dinein'].includes(normalized)) return 'dineIn';
|
|
1906
|
-
if (['shop_service', 'shop_server'].includes(normalized)) {
|
|
1907
|
-
return resolveShopServiceLabelKey(order);
|
|
1908
|
-
}
|
|
1909
|
-
return null;
|
|
1910
|
-
}
|
|
1911
|
-
function resolveShopServiceLabelKey(order) {
|
|
1912
|
-
const rawShopServiceType = firstPresentValue(order.metadata?.shop_service_type?.server_type, order.shop_service_type?.server_type, typeof order.shop_service_type === 'string' ? order.shop_service_type : undefined);
|
|
1913
|
-
if (!isPresentId(rawShopServiceType)) return 'dineIn';
|
|
1914
|
-
const normalized = stringify(rawShopServiceType).trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
1915
|
-
if (['takeaway', 'take_away'].includes(normalized)) return 'takeAway';
|
|
1916
|
-
if (['dine_in', 'dinein'].includes(normalized)) return 'dineIn';
|
|
1917
|
-
return null;
|
|
2196
|
+
function resolveServiceTypeLabelKey(serviceType) {
|
|
2197
|
+
return SERVICE_TYPE_LABEL_KEYS[serviceType] || null;
|
|
1918
2198
|
}
|
|
1919
2199
|
function normalizeBooleanFlag(value) {
|
|
1920
2200
|
if (value === true || value === 1 || stringify(value).trim() === '1') return 1;
|