@pisell/pisellos 0.10.56 → 0.10.57

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 (111) hide show
  1. package/dist/modules/OpenData/index.js +2 -1
  2. package/dist/modules/Order/index.d.ts +2 -1
  3. package/dist/modules/Order/index.js +118 -59
  4. package/dist/modules/Order/utils/weighedProduct.d.ts +12 -0
  5. package/dist/modules/Order/utils/weighedProduct.js +94 -0
  6. package/dist/modules/Order/utils.d.ts +1 -1
  7. package/dist/modules/Order/utils.js +9 -6
  8. package/dist/modules/Payment/index.d.ts +0 -5
  9. package/dist/modules/Payment/index.js +35 -85
  10. package/dist/modules/ProductList/index.js +18 -5
  11. package/dist/modules/ResourcePlanner/planner.js +10 -8
  12. package/dist/modules/Rules/index.js +16 -14
  13. package/dist/modules/Rules/types.d.ts +2 -0
  14. package/dist/server/index.js +122 -69
  15. package/dist/server/modules/floor-plan/index.js +34 -3
  16. package/dist/server/modules/payment/index.d.ts +25 -6
  17. package/dist/server/modules/payment/index.js +660 -133
  18. package/dist/server/test.json +1 -1
  19. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  20. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  21. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +5 -0
  22. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +46 -4
  23. package/dist/shared/receipt/small-ticket.d.ts +11 -0
  24. package/dist/shared/receipt/small-ticket.js +430 -255
  25. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  26. package/dist/shared/receipt/templateVisibility.js +64 -0
  27. package/dist/solution/BaseSales/index.d.ts +4 -2
  28. package/dist/solution/BaseSales/index.js +1328 -1214
  29. package/dist/solution/BaseSales/types.d.ts +5 -1
  30. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +40 -25
  31. package/dist/solution/BaseSales/utils.js +3 -2
  32. package/dist/solution/BookingByStep/index.d.ts +1 -1
  33. package/dist/solution/BookingTicket/index.d.ts +4 -1
  34. package/dist/solution/BookingTicket/index.js +120 -80
  35. package/dist/solution/OrderInvoicePreview/index.d.ts +10 -0
  36. package/dist/solution/OrderInvoicePreview/index.js +85 -14
  37. package/dist/solution/RegisterAndLogin/config.js +54 -11
  38. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  39. package/dist/solution/RegisterAndLogin/index.js +1 -1
  40. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  41. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  42. package/dist/solution/Sales/index.d.ts +2 -0
  43. package/dist/solution/Sales/index.js +15 -1
  44. package/dist/solution/ScanOrder/utils.js +3 -2
  45. package/dist/solution/UnifiedBookingSales/index.js +12 -13
  46. package/dist/solution/VenueBooking/index.d.ts +15 -2
  47. package/dist/solution/VenueBooking/index.js +1062 -785
  48. package/dist/solution/VenueBooking/types.d.ts +2 -1
  49. package/dist/solution/VenueBooking/types.js +1 -0
  50. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  51. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  52. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  53. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  54. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  55. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  56. package/lib/modules/OpenData/index.js +2 -1
  57. package/lib/modules/Order/index.d.ts +2 -1
  58. package/lib/modules/Order/index.js +71 -11
  59. package/lib/modules/Order/utils/weighedProduct.d.ts +12 -0
  60. package/lib/modules/Order/utils/weighedProduct.js +89 -0
  61. package/lib/modules/Order/utils.d.ts +1 -1
  62. package/lib/modules/Order/utils.js +5 -3
  63. package/lib/modules/Payment/index.d.ts +0 -5
  64. package/lib/modules/Payment/index.js +3 -28
  65. package/lib/modules/ProductList/index.js +14 -1
  66. package/lib/modules/ResourcePlanner/planner.js +10 -8
  67. package/lib/modules/Rules/index.js +16 -14
  68. package/lib/modules/Rules/types.d.ts +2 -0
  69. package/lib/server/index.js +72 -28
  70. package/lib/server/modules/floor-plan/index.js +29 -1
  71. package/lib/server/modules/payment/index.d.ts +25 -6
  72. package/lib/server/modules/payment/index.js +350 -78
  73. package/lib/server/test.json +1 -1
  74. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  75. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  76. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +5 -0
  77. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +42 -4
  78. package/lib/shared/receipt/small-ticket.d.ts +11 -0
  79. package/lib/shared/receipt/small-ticket.js +234 -30
  80. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  81. package/lib/shared/receipt/templateVisibility.js +63 -0
  82. package/lib/solution/BaseSales/index.d.ts +4 -2
  83. package/lib/solution/BaseSales/index.js +79 -18
  84. package/lib/solution/BaseSales/types.d.ts +5 -1
  85. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +24 -9
  86. package/lib/solution/BaseSales/utils.js +2 -1
  87. package/lib/solution/BookingByStep/index.d.ts +1 -1
  88. package/lib/solution/BookingTicket/index.d.ts +4 -1
  89. package/lib/solution/BookingTicket/index.js +14 -2
  90. package/lib/solution/OrderInvoicePreview/index.d.ts +10 -0
  91. package/lib/solution/OrderInvoicePreview/index.js +61 -7
  92. package/lib/solution/RegisterAndLogin/config.js +57 -11
  93. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  94. package/lib/solution/RegisterAndLogin/index.js +9 -1
  95. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  96. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  97. package/lib/solution/Sales/index.d.ts +2 -0
  98. package/lib/solution/Sales/index.js +10 -1
  99. package/lib/solution/ScanOrder/utils.js +2 -1
  100. package/lib/solution/UnifiedBookingSales/index.js +5 -6
  101. package/lib/solution/VenueBooking/index.d.ts +15 -2
  102. package/lib/solution/VenueBooking/index.js +243 -96
  103. package/lib/solution/VenueBooking/types.d.ts +2 -1
  104. package/lib/solution/VenueBooking/types.js +1 -0
  105. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  106. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  107. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  108. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  109. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  110. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  111. package/package.json +1 -1
@@ -0,0 +1,23 @@
1
+ /** Template children are direct module members; legacy missing values stay visible. */
2
+ export interface InvoiceDataVisibility {
3
+ handover: {
4
+ show: boolean;
5
+ method: boolean;
6
+ fulfillmentTime: boolean;
7
+ };
8
+ customer: {
9
+ show: boolean;
10
+ name: boolean;
11
+ email: boolean;
12
+ phone: boolean;
13
+ };
14
+ card: {
15
+ show: boolean;
16
+ passTypes: ReadonlySet<string> | null;
17
+ };
18
+ }
19
+ export declare function invoiceSettingIsVisible(value: unknown): boolean;
20
+ export declare function getInvoiceTemplateModules(settings: unknown): Record<string, any>[];
21
+ export declare function resolveInvoiceDataVisibility(settings: unknown): InvoiceDataVisibility;
22
+ /** Whether an old unfiltered snapshot is unsafe for this template. */
23
+ export declare function requiresInvoiceDataFiltering(settings: unknown): boolean;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getInvoiceTemplateModules = getInvoiceTemplateModules;
7
+ exports.invoiceSettingIsVisible = invoiceSettingIsVisible;
8
+ exports.requiresInvoiceDataFiltering = requiresInvoiceDataFiltering;
9
+ exports.resolveInvoiceDataVisibility = resolveInvoiceDataVisibility;
10
+ /** Template children are direct module members; legacy missing values stay visible. */
11
+
12
+ function invoiceSettingIsVisible(value) {
13
+ return value !== 0 && value !== false;
14
+ }
15
+ function getInvoiceTemplateModules(settings) {
16
+ if (Array.isArray(settings)) return settings.filter(isRecord);
17
+ if (!isRecord(settings)) return [];
18
+ if (isRecord(settings.template_settings)) {
19
+ return getInvoiceTemplateModules(settings.template_settings);
20
+ }
21
+ const modules = settings.modules ?? settings.module;
22
+ return Array.isArray(modules) ? modules.filter(isRecord) : [];
23
+ }
24
+ function isRecord(value) {
25
+ return !!value && typeof value === 'object' && !Array.isArray(value);
26
+ }
27
+ function resolveInvoiceDataVisibility(settings) {
28
+ const modules = getInvoiceTemplateModules(settings);
29
+ // Native templates use the first occurrence of each module.
30
+ const module = key => modules.find(item => item.key === key);
31
+ const handover = module('handover');
32
+ const customer = module('customer');
33
+ const card = module('card');
34
+ const field = (config, key) => invoiceSettingIsVisible(config?.[key]?.is_show);
35
+ const passTypes = Array.isArray(card?.pass_type) && card.pass_type.length > 0 ? new Set(card.pass_type.filter(tag => typeof tag === 'string' && tag.length > 0)) : null;
36
+ return {
37
+ handover: {
38
+ show: invoiceSettingIsVisible(handover?.is_show),
39
+ method: field(handover, 'method'),
40
+ fulfillmentTime: field(handover, 'fulfillment_time')
41
+ },
42
+ customer: {
43
+ show: invoiceSettingIsVisible(customer?.is_show),
44
+ name: field(customer, 'name'),
45
+ email: field(customer, 'email'),
46
+ phone: field(customer, 'phone')
47
+ },
48
+ card: {
49
+ show: invoiceSettingIsVisible(card?.is_show),
50
+ passTypes
51
+ }
52
+ };
53
+ }
54
+
55
+ /** Whether an old unfiltered snapshot is unsafe for this template. */
56
+ function requiresInvoiceDataFiltering(settings) {
57
+ const {
58
+ handover,
59
+ customer,
60
+ card
61
+ } = resolveInvoiceDataVisibility(settings);
62
+ return !handover.show || !handover.method || !handover.fulfillmentTime || !customer.show || !customer.name || !customer.email || !customer.phone || !card.show || card.passTypes !== null;
63
+ }
@@ -1,6 +1,6 @@
1
1
  import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
- import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesSubmitSalesOrderParams, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
3
+ import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesSubmitSalesOrderParams, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentOptions, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
4
4
  import { OrderModule } from '../../modules/Order';
5
5
  import { type PickupTimingBookingInput } from '../../modules/Order/pickupTiming';
6
6
  import type { PickupTimingAvailability, PickupTimingSelection, PickupTimingValidationResult } from '../../modules/FulfillmentTiming';
@@ -74,6 +74,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
74
74
  private walletAssetsRefreshSequence;
75
75
  private salesDetailHydrateQueue;
76
76
  private serverOrderChangeUnsubscribe;
77
+ private paymentMethodsChangedUnsubscribe;
77
78
  private serverOrderChangeHydrateInFlight;
78
79
  private queuedServerOrderChanges;
79
80
  private serverOrderChangeSyncEnabled;
@@ -105,6 +106,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
105
106
  private drainQueuedServerOrderChanges;
106
107
  private syncCurrentSalesDetailFromServerOrderChange;
107
108
  private registerServerOrderChangeSync;
109
+ private registerPaymentMethodsChangeSync;
108
110
  private hydrateLatestLoadedSalesDetail;
109
111
  private hydrateOrderPaymentNames;
110
112
  get payment(): PaymentModule | undefined;
@@ -462,7 +464,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
462
464
  private findCashPaymentMethod;
463
465
  private getPendingWalletPaymentAmount;
464
466
  /** 读取现金 action 所需的支付方式、待付金额和快捷金额。 */
465
- getCashPaymentConfig(): Promise<BaseSalesCashPaymentConfig>;
467
+ getCashPaymentConfig(options?: BaseSalesCashPaymentOptions): Promise<BaseSalesCashPaymentConfig>;
466
468
  /**
467
469
  * 确认足额覆盖订单的 pending Wallet 支付并提交订单。
468
470
  *
@@ -39,6 +39,7 @@ var _transformBaseProductToOrderProduct = require("./utils/transformBaseProductT
39
39
  var _quotationPrice = require("./utils/quotationPrice");
40
40
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
41
41
  const SERVER_ORDER_CHANGED_EVENT = 'order:onOrdersChanged';
42
+ const PAYMENT_METHODS_CHANGED_EVENT = 'payment:onPaymentMethodsChanged';
42
43
  const OS_FULFILLMENT_REF_MODE_FIELD = '_os_fulfillment_ref_mode';
43
44
  const OS_INVOICE_LAYOUT_CONFIG_FIELD = '_os_invoice_layout_config';
44
45
  const OS_INVOICE_TEMPLATE_SETTINGS_FIELD = '_os_invoice_template_settings';
@@ -496,6 +497,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
496
497
  walletAssetsRefreshSequence = 0;
497
498
  salesDetailHydrateQueue = Promise.resolve();
498
499
  serverOrderChangeUnsubscribe = null;
500
+ paymentMethodsChangedUnsubscribe = null;
499
501
  serverOrderChangeHydrateInFlight = null;
500
502
  queuedServerOrderChanges = [];
501
503
  serverOrderChangeSyncEnabled = false;
@@ -641,6 +643,15 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
641
643
  });
642
644
  });
643
645
  }
646
+ registerPaymentMethodsChangeSync() {
647
+ this.paymentMethodsChangedUnsubscribe?.();
648
+ const effects = this.core?.effects;
649
+ if (!effects || typeof effects.on !== 'function') return;
650
+ this.paymentMethodsChangedUnsubscribe = effects.on(PAYMENT_METHODS_CHANGED_EVENT, async payload => {
651
+ if (!Array.isArray(payload?.newMethods)) return;
652
+ await this.getPaymentMethodsAsync();
653
+ });
654
+ }
644
655
  async hydrateLatestLoadedSalesDetail(record, loadSequence, options) {
645
656
  let hydratedSales = null;
646
657
  let skippedBeforeHydrate = false;
@@ -1405,9 +1416,22 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1405
1416
  }
1406
1417
  syncAppDataToTempOrder(tempOrder) {
1407
1418
  const isPriceIncludeTax = this.getAppData('is_price_include_tax');
1408
- const taxCountryCode = this.getAppData('tax_country_code');
1409
- const currencyCode = this.getAppData('shop_currency_code');
1410
- const currencySymbol = this.getAppData('shop_symbol');
1419
+ const rawTaxCountryCode = this.getAppData('tax_country_code');
1420
+ const rawCurrencyCode = this.getAppData('shop_currency_code');
1421
+ const rawCurrencySymbol = this.getAppData('shop_symbol');
1422
+ const normalizeNonBlankValue = value => {
1423
+ if (value === undefined || value === null) return undefined;
1424
+ const normalizedValue = String(value).trim();
1425
+ return normalizedValue || undefined;
1426
+ };
1427
+ const taxCountryCode = normalizeNonBlankValue(rawTaxCountryCode);
1428
+ const currencyCode = normalizeNonBlankValue(rawCurrencyCode);
1429
+ const currencySymbol = normalizeNonBlankValue(rawCurrencySymbol);
1430
+ const before = {
1431
+ tax_country_code: tempOrder.tax_country_code,
1432
+ currency_code: tempOrder.currency_code,
1433
+ currency_symbol: tempOrder.currency_symbol
1434
+ };
1411
1435
  // 历史虚拟币订单不依赖交易开关;普通 POS 不从商品行残留快照推断订单币种。
1412
1436
  const isHistoricalVirtualSettlement = this.isHistoricalVirtualSettlementOrder(tempOrder);
1413
1437
  const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder) || isHistoricalVirtualSettlement;
@@ -1421,9 +1445,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1421
1445
  }
1422
1446
  }
1423
1447
  if (taxCountryCode !== undefined) {
1424
- const nextTaxCountryCode = String(taxCountryCode || '');
1425
- if (tempOrder.tax_country_code !== nextTaxCountryCode) {
1426
- tempOrder.tax_country_code = nextTaxCountryCode;
1448
+ if (tempOrder.tax_country_code !== taxCountryCode) {
1449
+ tempOrder.tax_country_code = taxCountryCode;
1427
1450
  isChanged = true;
1428
1451
  }
1429
1452
  }
@@ -1440,19 +1463,45 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1440
1463
  }
1441
1464
  }
1442
1465
  if (!isVirtualSettlement && currencyCode !== undefined) {
1443
- const nextCurrencyCode = String(currencyCode || '');
1444
- if (tempOrder.currency_code !== nextCurrencyCode) {
1445
- tempOrder.currency_code = nextCurrencyCode;
1466
+ if (tempOrder.currency_code !== currencyCode) {
1467
+ tempOrder.currency_code = currencyCode;
1446
1468
  isChanged = true;
1447
1469
  }
1448
1470
  }
1449
1471
  if (!isVirtualSettlement && currencySymbol !== undefined) {
1450
- const nextCurrencySymbol = String(currencySymbol || '');
1451
- if (tempOrder.currency_symbol !== nextCurrencySymbol) {
1452
- tempOrder.currency_symbol = nextCurrencySymbol;
1472
+ if (tempOrder.currency_symbol !== currencySymbol) {
1473
+ tempOrder.currency_symbol = currencySymbol;
1453
1474
  isChanged = true;
1454
1475
  }
1455
1476
  }
1477
+ try {
1478
+ const orderIdentity = this.store.order?.getOrderIdentity?.();
1479
+ this.logger?.addLog?.({
1480
+ type: 'info',
1481
+ title: 'syncAppDataToTempOrder',
1482
+ metadata: {
1483
+ moduleName: this.name,
1484
+ cacheId: this.cacheId,
1485
+ orderId: orderIdentity?.orderId ?? tempOrder.order_id,
1486
+ externalSaleNumber: orderIdentity?.externalSaleNumber ?? tempOrder.external_sale_number,
1487
+ shopOrderNumber: orderIdentity?.shopOrderNumber ?? tempOrder.shop_order_number,
1488
+ readValues: {
1489
+ tax_country_code: rawTaxCountryCode,
1490
+ shop_currency_code: rawCurrencyCode,
1491
+ shop_symbol: rawCurrencySymbol
1492
+ },
1493
+ before,
1494
+ after: {
1495
+ tax_country_code: tempOrder.tax_country_code,
1496
+ currency_code: tempOrder.currency_code,
1497
+ currency_symbol: tempOrder.currency_symbol
1498
+ },
1499
+ isChanged
1500
+ }
1501
+ });
1502
+ } catch {
1503
+ // 诊断日志不能影响订单字段同步。
1504
+ }
1456
1505
  return isChanged;
1457
1506
  }
1458
1507
  async initialize(core, options = {}) {
@@ -1504,6 +1553,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1504
1553
  this.store.order.setEnableTempOrderPersist(this.otherParams.enableTempOrderPersist);
1505
1554
  }
1506
1555
  await this.getPaymentMethodsAsync();
1556
+ this.registerPaymentMethodsChangeSync();
1507
1557
  this.registerServerOrderChangeSync();
1508
1558
  this.core.effects.emit(`${this.name}:onInited`, {});
1509
1559
  }
@@ -1511,6 +1561,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1511
1561
  this.resetPickupTimingCache();
1512
1562
  this.serverOrderChangeUnsubscribe?.();
1513
1563
  this.serverOrderChangeUnsubscribe = null;
1564
+ this.paymentMethodsChangedUnsubscribe?.();
1565
+ this.paymentMethodsChangedUnsubscribe = null;
1514
1566
  Object.keys(this.store).forEach(key => {
1515
1567
  if (this.reusedSharedSubModuleNames.has(key)) return;
1516
1568
  const sub = this.store[key];
@@ -3417,10 +3469,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3417
3469
  getPaymentMethods() {
3418
3470
  return [...this.paymentMethodsCache];
3419
3471
  }
3420
- findCashPaymentMethod(paymentMethods) {
3472
+ findCashPaymentMethod(paymentMethods, paymentMethodId) {
3421
3473
  return paymentMethods.find(method => {
3474
+ if (method?.enabled === false || method?.enable === false) return false;
3422
3475
  const identifiers = [method?.code, method?.type, method?.tag].map(value => String(value || '').toUpperCase());
3423
- return identifiers.includes('CASHMANUAL') && method?.enabled !== false && method?.enable !== false;
3476
+ const isDefaultCash = identifiers.includes('CASHMANUAL');
3477
+ if (paymentMethodId === undefined) return isDefaultCash;
3478
+ const isCustomCash = String(method?.type || '').trim().toLowerCase() === 'custom' && [method?.name, method?.nameEn].some(name => typeof name === 'string' && /现金|現金|cash/i.test(name));
3479
+ return String(method?.id) === String(paymentMethodId) && (isDefaultCash || isCustomCash);
3424
3480
  });
3425
3481
  }
3426
3482
  getPendingWalletPaymentAmount(payments = this.store.order?.getOrderPayments?.() || []) {
@@ -3437,13 +3493,16 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3437
3493
  }
3438
3494
 
3439
3495
  /** 读取现金 action 所需的支付方式、待付金额和快捷金额。 */
3440
- async getCashPaymentConfig() {
3496
+ async getCashPaymentConfig(options = {}) {
3441
3497
  if (!this.store.payment) throw new Error('payment 模块未初始化');
3442
3498
  let paymentMethods = this.getPaymentMethods();
3443
- let paymentMethod = this.findCashPaymentMethod(paymentMethods);
3499
+ let paymentMethod = this.findCashPaymentMethod(paymentMethods, options.paymentMethodId);
3444
3500
  if (!paymentMethod) {
3445
3501
  paymentMethods = await this.getPaymentMethodsAsync();
3446
- paymentMethod = this.findCashPaymentMethod(paymentMethods);
3502
+ paymentMethod = this.findCashPaymentMethod(paymentMethods, options.paymentMethodId);
3503
+ }
3504
+ if (!paymentMethod && options.paymentMethodId !== undefined) {
3505
+ throw new Error(`未找到可用的现金支付方式:${options.paymentMethodId}`);
3447
3506
  }
3448
3507
  const amountSnapshot = this.store.order?.getOrderAmountSnapshot?.();
3449
3508
  const pendingWalletAmount = this.getPendingWalletPaymentAmount();
@@ -3541,7 +3600,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3541
3600
  if (!Number.isFinite(amount) || amount <= 0) {
3542
3601
  throw new Error('现金支付金额必须大于 0');
3543
3602
  }
3544
- const config = await this.getCashPaymentConfig();
3603
+ const config = params.paymentMethodId === undefined ? await this.getCashPaymentConfig() : await this.getCashPaymentConfig({
3604
+ paymentMethodId: params.paymentMethodId
3605
+ });
3545
3606
  const paymentMethod = config.paymentMethod;
3546
3607
  if (!paymentMethod) throw new Error('未找到可用的 CASHMANUAL 支付方式');
3547
3608
  if (config.amountDue <= 0) throw new Error('当前订单没有待支付金额');
@@ -25,6 +25,10 @@ export type BaseSalesHookName = typeof BaseSalesHookNames[keyof typeof BaseSales
25
25
  export declare function createBaseSalesHook(moduleName: string, hookName: BaseSalesHookName): string;
26
26
  export type BaseSalesStatus = 'idle' | 'initializing' | 'ready' | 'error';
27
27
  export type BaseSalesPaymentStatus = 'paid' | 'partially_paid' | 'unpaid' | 'payment_processing' | string;
28
+ export interface BaseSalesCashPaymentOptions {
29
+ /** 指定现金支付方式;省略时使用默认 CASHMANUAL。 */
30
+ paymentMethodId?: number | string;
31
+ }
28
32
  export interface BaseSalesSubmitSalesOrderParams {
29
33
  payments?: OrderPaymentSource[];
30
34
  paymentStatus?: BaseSalesPaymentStatus;
@@ -40,7 +44,7 @@ export interface BaseSalesCashPaymentConfig {
40
44
  amountDue: number;
41
45
  recommendedAmounts: number[];
42
46
  }
43
- export interface BaseSalesPayCashParams {
47
+ export interface BaseSalesPayCashParams extends BaseSalesCashPaymentOptions {
44
48
  /** 实际计入订单的现金支付金额(部分支付时小于待付金额)。 */
45
49
  amount: number;
46
50
  /** 顾客实际交付现金;可大于 amount。 */
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.transformBaseProductToOrderProduct = transformBaseProductToOrderProduct;
7
+ var _weighedProduct = require("../../../modules/Order/utils/weighedProduct");
7
8
  var _utils = require("../../../modules/Order/utils");
8
9
  var _manualProductDiscount = require("../../../modules/Order/utils/manualProductDiscount");
9
10
  function toNumber(value, fallback = 0) {
@@ -65,11 +66,11 @@ function appendDataVariantIds(base, ...values) {
65
66
  }
66
67
  return Array.isArray(base) || result.length ? result : undefined;
67
68
  }
68
- function normalizeOptionItems(optionItems) {
69
+ function normalizeOptionItems(optionItems, useOriginalPrice = false) {
69
70
  if (!Array.isArray(optionItems)) return [];
70
71
  return optionItems.map(optionItem => {
71
72
  const optionGroupItemId = toNumber(optionItem?.option_group_item_id ?? optionItem?.id);
72
- const price = optionItem?.price ?? optionItem?.add_price ?? 0;
73
+ const price = (useOriginalPrice ? optionItem?.original_price : undefined) ?? optionItem?.price ?? optionItem?.add_price ?? 0;
73
74
  return {
74
75
  ...optionItem,
75
76
  option_group_item_id: optionGroupItemId,
@@ -80,10 +81,12 @@ function normalizeOptionItems(optionItems) {
80
81
  };
81
82
  });
82
83
  }
83
- function normalizeBundleItems(bundleItems, preferPriceField = false) {
84
+ function normalizeBundleItems(bundleItems, preferPriceField = false, preferBundleSellingPrice = false) {
84
85
  if (!Array.isArray(bundleItems)) return [];
85
86
  return bundleItems.map(bundleItem => {
86
- const unitSelling = preferPriceField ? bundleItem.price ?? bundleItem.bundle_selling_price ?? bundleItem.custom_price ?? bundleItem.product_price ?? '0' : bundleItem.bundle_selling_price ?? bundleItem.price ?? bundleItem.custom_price ?? bundleItem.product_price ?? '0';
87
+ // Weighed manual prices distribute the bundle base and nested options separately.
88
+ // Its explicit selling amount already includes those options.
89
+ const unitSelling = preferPriceField && !preferBundleSellingPrice ? bundleItem.price ?? bundleItem.bundle_selling_price ?? bundleItem.custom_price ?? bundleItem.product_price ?? '0' : bundleItem.bundle_selling_price ?? bundleItem.price ?? bundleItem.custom_price ?? bundleItem.product_price ?? '0';
87
90
  const unitStr = toPriceString(unitSelling, '0.00');
88
91
  const num = toSafePositiveInt(bundleItem?.num ?? bundleItem?.quantity, 1);
89
92
  const magnitudeSource = {
@@ -147,19 +150,25 @@ function transformBaseProductToOrderProduct(params) {
147
150
  const productionCode = normalizeProductionCode(Object.prototype.hasOwnProperty.call(payload, 'production_code') ? payload.production_code : productVariantId > 0 ? matchedVariant?.production_code : origin?.production_code ?? sourceProduct?.production_code);
148
151
  const hasPriceOverride = payload.price_override !== undefined && payload.price_override !== null && payload.price_override !== '';
149
152
  // 手动改价后 payload.price 是分摊后的主商品售价,不能再作为券前 source。
150
- // 此时优先从商品/variant 快照读取目录价;售价仍由 line_total - bundle 推导。
153
+ // 称重商品使用改价前净重金额;其它商品从商品/variant 快照读取目录价。
154
+ // 售价仍由 line_total - bundle 推导。
151
155
  const catalogSourcePrice = matchedVariant?.price ?? matchedVariant?.base_price ?? origin?.price ?? origin?.base_price ?? sourceProduct?.price ?? sourceProduct?.selling_price ?? sourceProduct?.base_price;
152
- const sourceProductPrice = toPriceString(hasPriceOverride ? catalogSourcePrice ?? payload.price ?? payload.selling_price : payload.price ?? payload.selling_price ?? catalogSourcePrice, '0.00');
156
+ const weighedSourcePrice = (0, _weighedProduct.resolveWeighedSourcePrice)(payload.product_sku ?? origin.product_sku, payload._extend?.weighing ?? origin._extend?.weighing);
157
+ const sourceProductPrice = toPriceString(weighedSourcePrice ?? (hasPriceOverride ? catalogSourcePrice ?? payload.price ?? payload.selling_price : payload.price ?? payload.selling_price ?? catalogSourcePrice), '0.00');
153
158
  const explicitLineTotal = payload.line_total ?? payload.total ?? payload._extend?.total;
154
159
  const hasExplicitLineTotal = Number.isFinite(Number(explicitLineTotal));
155
160
  const lineCompositeTotal = toPriceString(explicitLineTotal, sourceProductPrice);
156
- const productOptionItem = (0, _utils.normalizeProductSkuOptions)(normalizeOptionItems(payload.product_sku?.option ?? payload.option ?? payload.options ?? payload.product_option_item));
157
- const productBundle = normalizeBundleItems(payload.bundle ?? payload.product_bundle, hasPriceOverride);
161
+ const productOptionItem = (0, _utils.normalizeProductSkuOptions)(normalizeOptionItems(payload.product_sku?.option ?? payload.option ?? payload.options ?? payload.product_option_item, hasPriceOverride || weighedSourcePrice !== undefined));
162
+ const productBundle = normalizeBundleItems(payload.bundle ?? payload.product_bundle, hasPriceOverride, hasPriceOverride && weighedSourcePrice !== undefined);
158
163
  // `payload.unique` 是业务侧商品/票务标识,可能在连续加同一商品时重复;
159
164
  // 行级唯一值只接受显式协议字段,缺省交给 OrderModule 生成。
160
165
  const uniqueIdentificationNumber = payload.unique_identification_number;
161
166
  const resolvedQuantity = toSafePositiveInt(payload.quantity ?? payload.num, 1);
162
- const originTotal = (0, _manualProductDiscount.resolveManualDiscountOriginTotal)({
167
+ const originTotal = weighedSourcePrice !== undefined ? Number((0, _utils.composeLinePrice)({
168
+ mainPrice: Number(weighedSourcePrice) + (0, _utils.sumOptionUnitPrice)(productOptionItem).toNumber(),
169
+ bundle: hasPriceOverride ? (0, _weighedProduct.withOriginalBundleOptionPrices)(productBundle) : productBundle,
170
+ useOriginalBundle: true
171
+ })) : (0, _manualProductDiscount.resolveManualDiscountOriginTotal)({
163
172
  originTotal: payload.origin_total,
164
173
  extendOriginTotal: payload._extend?.origin_total,
165
174
  originExtendOriginTotal: origin?._extend?.origin_total,
@@ -260,6 +269,12 @@ function transformBaseProductToOrderProduct(params) {
260
269
  product_cover: firstNonBlank(matchedVariant?.cover, sourceProduct?.cover),
261
270
  _origin: {
262
271
  ...(sourceProduct || {}),
272
+ ...(weighedSourcePrice !== undefined && hasPriceOverride ? {
273
+ _extend: {
274
+ ...sourceProduct?._extend,
275
+ origin_total: originTotal
276
+ }
277
+ } : {}),
263
278
  callbackData: payload
264
279
  }
265
280
  };
@@ -8,6 +8,7 @@ exports.createEmptySummary = createEmptySummary;
8
8
  exports.getSafeProductNum = getSafeProductNum;
9
9
  exports.isSkuOnlyDeleteIdentity = isSkuOnlyDeleteIdentity;
10
10
  exports.normalizeOrderProduct = normalizeOrderProduct;
11
+ var _weighedProduct = require("../../modules/Order/utils/weighedProduct");
11
12
  var _decimal = _interopRequireDefault(require("decimal.js"));
12
13
  var _utils = require("../../modules/Order/utils");
13
14
  var _manualProductDiscount = require("../../modules/Order/utils/manualProductDiscount");
@@ -237,7 +238,7 @@ function normalizeOrderProduct(product) {
237
238
  });
238
239
  const composedOriginalPrice = (0, _utils.composeLinePrice)({
239
240
  mainPrice: mainOriginalStr,
240
- bundle: normalizedBundle,
241
+ bundle: Number(productSku.open_sold_weight) === 1 && (0, _manualProductDiscount.hasManualProductDiscountFlag)(metadata) ? (0, _weighedProduct.withOriginalBundleOptionPrices)(normalizedBundle) : normalizedBundle,
241
242
  useOriginalBundle: true
242
243
  });
243
244
  const finalOriginalPrice = (0, _utils.resolveManualOverrideLineOriginalPrice)({
@@ -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 | 2 | 1 | 6 | 4 | 5 | 3;
329
+ weekNum: 0 | 2 | 1 | 3 | 5 | 4 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -8,6 +8,7 @@ import { BaseSalesImpl } from '../BaseSales';
8
8
  import type { BaseSalesScanCodeResult } from '../BaseSales/types';
9
9
  import type { ISalesDetail } from '../BaseSales/utils/parseSalesResponse';
10
10
  import type { LoadSalesDetailParams } from '../../modules/Order/types';
11
+ import type { GlobalScanSearchType } from './utils/scan/formatGlobalScan';
11
12
  import type { AddAddTimeProductToBookingInput, AddAddTimeProductsToBookingInput, GlobalScanHandleResult, GlobalScanHostBridge } from './types';
12
13
  import { AddProductDecideContext, AddProductRequiresDetailPayload } from './utils/addProductDecision';
13
14
  import { type BuildCacheItemFromOrderLineInput } from '../../modules/BookingContext/utils/buildCacheItemFromOrderLine';
@@ -31,10 +32,10 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
31
32
  private orderCustomerDiscountRefreshCustomerId;
32
33
  private orderCustomerDiscountRefreshTarget;
33
34
  private orderCustomerPromotionRefreshInFlight;
35
+ private readonly customerResolveRequests;
34
36
  protected loadOpenDataInFlight: Promise<OpenDataConfig> | null;
35
37
  protected loadOpenDataInFlightTarget: string | null;
36
38
  protected openDataTarget: string | null;
37
- private readonly customerResolveRequests;
38
39
  /**
39
40
  * 在 BaseSales 默认模块清单(products/order/salesSummary/schedule)基础上追加 customer + bookingContext。
40
41
  * bookingContext 是 SalesSdk 加车下沉所需的「预约 UI 上下文」(bookingConfig / resourcesOrigin / date)。
@@ -537,6 +538,8 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
537
538
  * ```
538
539
  */
539
540
  handleGlobalScanCode(code: string, bridge?: GlobalScanHostBridge): Promise<GlobalScanHandleResult>;
541
+ /** 查询码类型;复用原有识别和缓存,不写订单、不打开选择 UI。 */
542
+ getGlobalScanCodeType(code: string): Promise<GlobalScanSearchType | null>;
540
543
  resolveBestAddTimePlan(addTimeProducts: any[], targetMinutes: number): any;
541
544
  /**
542
545
  * 构造一条绑定到已有 booking 的加时商品行。
@@ -162,10 +162,10 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
162
162
  orderCustomerDiscountRefreshCustomerId = null;
163
163
  orderCustomerDiscountRefreshTarget = null;
164
164
  orderCustomerPromotionRefreshInFlight = null;
165
+ customerResolveRequests = new Map();
165
166
  loadOpenDataInFlight = null;
166
167
  loadOpenDataInFlightTarget = null;
167
168
  openDataTarget = null;
168
- customerResolveRequests = new Map();
169
169
 
170
170
  /**
171
171
  * 在 BaseSales 默认模块清单(products/order/salesSummary/schedule)基础上追加 customer + bookingContext。
@@ -1685,8 +1685,8 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
1685
1685
  confirmDetail: guardCallback(bridge.confirmDetail),
1686
1686
  confirmBookingEdit: guardCallback(bridge.confirmBookingEdit),
1687
1687
  applyPromotionCode: guardCallback(bridge.applyPromotionCode),
1688
- requestCustomerSwitch: guardCallback(bridge.requestCustomerSwitch),
1689
1688
  openOrder: guardCallback(bridge.openOrder),
1689
+ requestCustomerSwitch: guardCallback(bridge.requestCustomerSwitch),
1690
1690
  openProductDetail: bridge.openProductDetail ? payload => {
1691
1691
  beforeScanDialog();
1692
1692
  return bridge.openProductDetail(payload);
@@ -1743,6 +1743,18 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
1743
1743
  };
1744
1744
  }
1745
1745
  }
1746
+
1747
+ /** 查询码类型;复用原有识别和缓存,不写订单、不打开选择 UI。 */
1748
+ async getGlobalScanCodeType(code) {
1749
+ const trimmed = typeof code === 'string' ? code.trim() : '';
1750
+ if (!trimmed) return null;
1751
+ const scan = (0, _handleScan.handleGlobalScan)(this.request, value => this.store.products.findProductsByCodeOrBarcode(value), this.getSubmitOrderSalesChannel());
1752
+ const raw = await scan({
1753
+ type: 'nativeScanner',
1754
+ value: trimmed
1755
+ });
1756
+ return (0, _formatGlobalScan.formatGlobalScanResult)(raw, trimmed)?.searchType ?? null;
1757
+ }
1746
1758
  resolveBestAddTimePlan(addTimeProducts, targetMinutes) {
1747
1759
  return (0, _resolveBestAddTimePlan.resolveBestAddTimePlan)(addTimeProducts, targetMinutes);
1748
1760
  }
@@ -1,5 +1,7 @@
1
1
  import type { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
+ import { type CustomerInvoiceLanguageCode, type CustomerInvoiceLanguageOption } from '../../shared/receipt/customerInvoiceLanguages';
4
+ export type { CustomerInvoiceLanguageCode, CustomerInvoiceLanguageOption, } from '../../shared/receipt/customerInvoiceLanguages';
3
5
  import type { InvoiceLayoutConfig } from '../../modules/OpenData';
4
6
  import { type SmallTicketData } from '../../shared/receipt/small-ticket';
5
7
  export interface OrderInvoicePreviewInput {
@@ -19,6 +21,9 @@ export interface OrderInvoicePreviewResult {
19
21
  sourceRevision: string;
20
22
  generatedAt: string;
21
23
  locale: string;
24
+ secondaryLocale?: string;
25
+ languageOptions: CustomerInvoiceLanguageOption[];
26
+ selectedLanguage: CustomerInvoiceLanguageCode;
22
27
  orderId: string | number;
23
28
  source: Record<string, any>;
24
29
  shop: Record<string, any>;
@@ -40,6 +45,7 @@ export declare class OrderInvoicePreviewImpl extends BaseModule implements Modul
40
45
  private disposed;
41
46
  private input?;
42
47
  private activeKey;
48
+ private languageSelection?;
43
49
  private pending?;
44
50
  private snapshotCache;
45
51
  constructor(name?: string);
@@ -51,6 +57,10 @@ export declare class OrderInvoicePreviewImpl extends BaseModule implements Modul
51
57
  private loadContext;
52
58
  private loadSource;
53
59
  prepare(input: OrderInvoicePreviewInput): Promise<OrderInvoicePreviewResult>;
60
+ private getSelectionScope;
61
+ private documentIdentity;
62
+ /** Switch only the ready receipt projection; no fetching or rebuilding data. */
63
+ selectLanguage(code: string): OrderInvoicePreviewResult;
54
64
  retry(): Promise<OrderInvoicePreviewResult>;
55
65
  destroy(): void;
56
66
  }