@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.
Files changed (87) hide show
  1. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  2. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  3. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  4. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  5. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  6. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  7. package/dist/modules/Order/index.d.ts +41 -9
  8. package/dist/modules/Order/index.js +1438 -878
  9. package/dist/modules/Order/salesNotes.d.ts +31 -0
  10. package/dist/modules/Order/salesNotes.js +492 -0
  11. package/dist/modules/Order/types.d.ts +105 -8
  12. package/dist/modules/Order/types.js +6 -1
  13. package/dist/modules/Order/utils.d.ts +3 -1
  14. package/dist/modules/Order/utils.js +191 -71
  15. package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  16. package/dist/modules/Payment/cashRecommendationAlgorithm.js +17 -367
  17. package/dist/modules/ProductList/index.d.ts +2 -1
  18. package/dist/modules/ProductList/index.js +100 -20
  19. package/dist/modules/ProductList/types.d.ts +10 -0
  20. package/dist/server/index.d.ts +7 -0
  21. package/dist/server/index.js +45 -3
  22. package/dist/server/modules/order/index.js +6 -0
  23. package/dist/server/modules/order/types.d.ts +9 -0
  24. package/dist/server/utils/small-ticket.d.ts +1 -0
  25. package/dist/server/utils/small-ticket.js +142 -14
  26. package/dist/solution/BaseSales/index.d.ts +15 -1
  27. package/dist/solution/BaseSales/index.js +1240 -877
  28. package/dist/solution/BookingByStep/index.d.ts +1 -1
  29. package/dist/solution/BookingTicket/index.d.ts +1 -0
  30. package/dist/solution/BookingTicket/index.js +37 -16
  31. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  32. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  33. package/dist/solution/RegisterAndLogin/config.js +95 -40
  34. package/dist/solution/RegisterAndLogin/index.js +4 -1
  35. package/dist/solution/ScanOrder/index.d.ts +1 -0
  36. package/dist/solution/ScanOrder/index.js +31 -27
  37. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  38. package/dist/solution/ScanOrder/utils.js +2 -0
  39. package/dist/solution/UnifiedBookingSales/index.d.ts +15 -2
  40. package/dist/solution/UnifiedBookingSales/index.js +777 -510
  41. package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
  42. package/dist/solution/VenueBooking/index.d.ts +1 -0
  43. package/dist/solution/VenueBooking/index.js +8 -4
  44. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  45. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  46. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  47. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  48. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  49. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  50. package/lib/modules/Order/index.d.ts +41 -9
  51. package/lib/modules/Order/index.js +434 -61
  52. package/lib/modules/Order/salesNotes.d.ts +31 -0
  53. package/lib/modules/Order/salesNotes.js +382 -0
  54. package/lib/modules/Order/types.d.ts +105 -8
  55. package/lib/modules/Order/types.js +5 -1
  56. package/lib/modules/Order/utils.d.ts +3 -1
  57. package/lib/modules/Order/utils.js +114 -1
  58. package/lib/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  59. package/lib/modules/Payment/cashRecommendationAlgorithm.js +9 -354
  60. package/lib/modules/ProductList/index.d.ts +2 -1
  61. package/lib/modules/ProductList/index.js +47 -2
  62. package/lib/modules/ProductList/types.d.ts +10 -0
  63. package/lib/server/index.d.ts +7 -0
  64. package/lib/server/index.js +39 -3
  65. package/lib/server/modules/order/index.js +6 -0
  66. package/lib/server/modules/order/types.d.ts +9 -0
  67. package/lib/server/utils/small-ticket.d.ts +1 -0
  68. package/lib/server/utils/small-ticket.js +136 -12
  69. package/lib/solution/BaseSales/index.d.ts +15 -1
  70. package/lib/solution/BaseSales/index.js +192 -22
  71. package/lib/solution/BookingByStep/index.d.ts +1 -1
  72. package/lib/solution/BookingTicket/index.d.ts +1 -0
  73. package/lib/solution/BookingTicket/index.js +23 -5
  74. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  75. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  76. package/lib/solution/RegisterAndLogin/config.js +49 -8
  77. package/lib/solution/RegisterAndLogin/index.js +4 -1
  78. package/lib/solution/ScanOrder/index.d.ts +1 -0
  79. package/lib/solution/ScanOrder/index.js +5 -1
  80. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  81. package/lib/solution/ScanOrder/utils.js +1 -0
  82. package/lib/solution/UnifiedBookingSales/index.d.ts +15 -2
  83. package/lib/solution/UnifiedBookingSales/index.js +125 -1
  84. package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
  85. package/lib/solution/VenueBooking/index.d.ts +1 -0
  86. package/lib/solution/VenueBooking/index.js +5 -1
  87. package/package.json +1 -1
@@ -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;
@@ -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) return next;
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
  * 金额汇总(仅输出)。
@@ -45,6 +45,7 @@ export interface SmallTicketProduct {
45
45
  product_uid?: string | number;
46
46
  booking_uid?: string | number;
47
47
  product_note?: string;
48
+ allergy?: string;
48
49
  options?: Array<{
49
50
  name: string;
50
51
  num?: number;
@@ -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 => buildPaymentItems({
1363
- payment,
1364
- locale: params.locale,
1365
- currencySymbol: params.currencySymbol,
1366
- includeFundRecordBalance: true,
1367
- includeFundRecordUsage: false,
1368
- includePaymentAmount: false
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() === 'ticket';
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';