@pisell/pisellos 0.10.31 → 0.10.33

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