@pisell/pisellos 2.3.141 → 2.3.143

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 (39) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  2. package/dist/modules/BookingContext/utils/resources.js +1 -1
  3. package/dist/modules/Cart/index.js +4 -3
  4. package/dist/modules/Cart/types.d.ts +2 -0
  5. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  6. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  7. package/dist/modules/Order/index.d.ts +1 -1
  8. package/dist/modules/Order/types.d.ts +1 -0
  9. package/dist/modules/Order/utils.js +8 -0
  10. package/dist/modules/Product/types.d.ts +11 -0
  11. package/dist/server/index.js +118 -69
  12. package/dist/server/modules/order/types.d.ts +1 -0
  13. package/dist/shared/receipt/small-ticket.d.ts +2 -0
  14. package/dist/shared/receipt/small-ticket.js +188 -73
  15. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  16. package/dist/shared/receipt/templateVisibility.js +64 -0
  17. package/dist/solution/BookingByStep/index.d.ts +4 -2
  18. package/dist/solution/BookingByStep/index.js +8 -3
  19. package/dist/solution/OrderInvoicePreview/index.js +2 -1
  20. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  21. package/lib/modules/BookingContext/utils/resources.js +1 -1
  22. package/lib/modules/Cart/index.js +4 -2
  23. package/lib/modules/Cart/types.d.ts +2 -0
  24. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  25. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  26. package/lib/modules/Order/index.d.ts +1 -1
  27. package/lib/modules/Order/types.d.ts +1 -0
  28. package/lib/modules/Order/utils.js +8 -0
  29. package/lib/modules/Product/types.d.ts +11 -0
  30. package/lib/server/index.js +68 -28
  31. package/lib/server/modules/order/types.d.ts +1 -0
  32. package/lib/shared/receipt/small-ticket.d.ts +2 -0
  33. package/lib/shared/receipt/small-ticket.js +113 -22
  34. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  35. package/lib/shared/receipt/templateVisibility.js +63 -0
  36. package/lib/solution/BookingByStep/index.d.ts +4 -2
  37. package/lib/solution/BookingByStep/index.js +7 -3
  38. package/lib/solution/OrderInvoicePreview/index.js +2 -1
  39. package/package.json +1 -1
@@ -210,6 +210,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
210
210
  * product: ProductData;
211
211
  * date?: { startTime: string; endTime: string } | null;
212
212
  * account?: Account | null;
213
+ * isLegacyOrder?: boolean;
213
214
  * })} {
214
215
  * product,
215
216
  * date,
@@ -218,13 +219,14 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
218
219
  * @return {*}
219
220
  * @memberof BookingByStepImpl
220
221
  */
221
- addProductToCart({ product, date, account, }: {
222
+ addProductToCart({ product, date, account, isLegacyOrder, }: {
222
223
  product: ProductData;
223
224
  date?: {
224
225
  startTime: string;
225
226
  endTime: string;
226
227
  } | null;
227
228
  account?: Account | null;
229
+ isLegacyOrder?: boolean;
228
230
  }): {
229
231
  success: boolean;
230
232
  errorCode?: string;
@@ -326,7 +328,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
328
  date: string;
327
329
  status: string;
328
330
  week: string;
329
- weekNum: 0 | 2 | 1 | 6 | 4 | 5 | 3;
331
+ weekNum: 0 | 1 | 2 | 5 | 4 | 3 | 6;
330
332
  }[]>;
331
333
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
334
  private getScheduleDataByIds;
@@ -1189,7 +1189,8 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
1189
1189
  // 直接调用 addProductToCart,不传递 date 参数以避免日期检查逻辑
1190
1190
  return this.addProductToCart({
1191
1191
  product: productData,
1192
- account: activeAccount
1192
+ account: activeAccount,
1193
+ isLegacyOrder: true
1193
1194
  });
1194
1195
  }
1195
1196
 
@@ -1200,6 +1201,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
1200
1201
  * product: ProductData;
1201
1202
  * date?: { startTime: string; endTime: string } | null;
1202
1203
  * account?: Account | null;
1204
+ * isLegacyOrder?: boolean;
1203
1205
  * })} {
1204
1206
  * product,
1205
1207
  * date,
@@ -1213,7 +1215,9 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
1213
1215
  value: function addProductToCart(_ref6) {
1214
1216
  var product = _ref6.product,
1215
1217
  date = _ref6.date,
1216
- account = _ref6.account;
1218
+ account = _ref6.account,
1219
+ _ref6$isLegacyOrder = _ref6.isLegacyOrder,
1220
+ isLegacyOrder = _ref6$isLegacyOrder === void 0 ? false : _ref6$isLegacyOrder;
1217
1221
  var _ref7 = product || {},
1218
1222
  bundle = _ref7.bundle,
1219
1223
  options = _ref7.options,
@@ -1278,7 +1282,8 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
1278
1282
  product: productData,
1279
1283
  bundle: bundle,
1280
1284
  options: options,
1281
- quantity: quantity
1285
+ quantity: quantity,
1286
+ isLegacyOrder: isLegacyOrder
1282
1287
  };
1283
1288
  if (date) {
1284
1289
  addItemParams.date = date;
@@ -244,7 +244,8 @@ export var OrderInvoicePreviewImpl = /*#__PURE__*/function (_BaseModule) {
244
244
  locales: _toConsumableArray(new Set(languageOptions.flatMap(function (option) {
245
245
  return option.locales;
246
246
  }))),
247
- includeReceiptKeys: true
247
+ includeReceiptKeys: true,
248
+ templateSettings: template.layout
248
249
  })
249
250
  });
250
251
  _this3.publish({
@@ -1 +1,46 @@
1
- "use strict";
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _examples.BUY_X_GET_Y_FREE_STRATEGY;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _examples.ITEM_REWARD_STRATEGY;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "PromotionAdapter", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _adapter.PromotionAdapter;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "PromotionEvaluator", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _evaluator.PromotionEvaluator;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "default", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _adapter.default;
40
+ }
41
+ });
42
+ var _evaluator = require("./evaluator");
43
+ var _adapter = _interopRequireWildcard(require("./adapter"));
44
+ var _examples = require("./examples");
45
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
46
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -241,7 +241,7 @@ function getResourceMaxFreeTime(resource, isAutoAllocationOn) {
241
241
  if (!isAutoAllocationOn(form_id)) return [];
242
242
  const usableList = (renderList || []).filter(d => d.usable && d.id !== 0);
243
243
  let defaultResource = [];
244
- let maxFreeTime = 0;
244
+ let maxFreeTime = -1;
245
245
  usableList.forEach(d => {
246
246
  const {
247
247
  times = []
@@ -89,7 +89,8 @@ class CartModule extends _BaseModule.BaseModule {
89
89
  bundle,
90
90
  options,
91
91
  date,
92
- quantity = 1
92
+ quantity = 1,
93
+ isLegacyOrder
93
94
  } = params;
94
95
  // 生成一个唯一的 ID
95
96
  let cartItem = {
@@ -108,7 +109,8 @@ class CartModule extends _BaseModule.BaseModule {
108
109
  bundle,
109
110
  options,
110
111
  product_variant_id: newProduct.product_variant_id,
111
- quantity
112
+ quantity,
113
+ isLegacyOrder
112
114
  });
113
115
  }
114
116
  if (account) {
@@ -180,6 +180,8 @@ export interface IAddItemParams {
180
180
  };
181
181
  /** 商品组合规格ID */
182
182
  product_variant_id?: number;
183
+ /** 是否由旧版下单流程加入购物车 */
184
+ isLegacyOrder?: boolean;
183
185
  }
184
186
  /**
185
187
  * 更新购物车信息参数
@@ -21,6 +21,7 @@ export declare const formatProductToCartItem: (params: {
21
21
  product_variant_id?: number;
22
22
  quantity?: number;
23
23
  discounts?: any[];
24
+ isLegacyOrder?: boolean;
24
25
  }) => CartItem;
25
26
  export declare const formatProductToCartItemOrigin: (params: {
26
27
  cartItem: CartItem;
@@ -29,6 +30,7 @@ export declare const formatProductToCartItemOrigin: (params: {
29
30
  options?: any;
30
31
  product_variant_id?: number;
31
32
  quantity?: number;
33
+ isLegacyOrder?: boolean;
32
34
  }) => any;
33
35
  /**
34
36
  * 获取商品总价
@@ -61,7 +63,7 @@ export declare const getProductOriginTotalPrice: (params: {
61
63
  * @param options 套餐规格信息
62
64
  * @returns 格式化后的套餐规格信息
63
65
  */
64
- export declare const formatOptions: (options: any) => any;
66
+ export declare const formatOptions: (options: any, product?: ProductData) => any;
65
67
  export declare const formatOptionsToOrigin: (options: any) => any;
66
68
  /**
67
69
  * 格式化商品套餐信息
@@ -106,7 +106,7 @@ const formatProductToCartItem = params => {
106
106
  cartItem.bundle = formatBundle(bundle);
107
107
  }
108
108
  if (options?.length) {
109
- cartItem.options = formatOptions(options);
109
+ cartItem.options = formatOptions(options, product);
110
110
  }
111
111
  // 拼装出 product_option_string
112
112
  if (product_variant_id) {
@@ -148,22 +148,32 @@ const formatProductToCartItemOrigin = params => {
148
148
  bundle,
149
149
  options,
150
150
  product_variant_id,
151
- quantity = 1
151
+ quantity = 1,
152
+ isLegacyOrder = false
152
153
  } = params;
153
154
  let origin = cartItem._origin;
154
155
  const product_discount_difference = (origin.product?.discount_list || []).filter(item => !item?.metadata?.custom_product_bundle_map_id).reduce((pre, cur) => {
155
156
  return pre + (cur?.metadata?.product_discount_difference || 0);
156
157
  }, 0);
157
158
  if (product) {
159
+ const {
160
+ option: _option,
161
+ ...legacyProductSku
162
+ } = origin.product?.product_sku || {};
158
163
  origin.product = {
159
164
  ...(origin.product || {}),
160
165
  num: quantity,
161
166
  product_id: product.id,
162
167
  product_variant_id: product_variant_id || 0,
163
168
  product_bundle: origin.product?.product_bundle || [],
164
- product_sku: origin.product?.product_sku || {
165
- option: []
166
- },
169
+ ...(isLegacyOrder ? {
170
+ product_sku: legacyProductSku,
171
+ product_option_item: origin.product?.product_option_item || []
172
+ } : {
173
+ product_sku: origin.product?.product_sku || {
174
+ option: []
175
+ }
176
+ }),
167
177
  metadata: {
168
178
  product_discount_difference
169
179
  }
@@ -176,17 +186,22 @@ const formatProductToCartItemOrigin = params => {
176
186
  origin.product.product_bundle = formatBundleToOrigin(bundle);
177
187
  }
178
188
  if (options?.length) {
179
- origin.product.product_sku = {
180
- ...(origin.product.product_sku || {}),
181
- option: formatOptionsToOrigin(options).map(option => {
182
- const next = {
183
- ...option,
184
- add_price: option.add_price ?? option.price
185
- };
186
- delete next.price;
187
- return next;
188
- })
189
- };
189
+ const formattedOptions = formatOptionsToOrigin(options);
190
+ if (isLegacyOrder) {
191
+ origin.product.product_option_item = formattedOptions;
192
+ } else {
193
+ origin.product.product_sku = {
194
+ ...(origin.product.product_sku || {}),
195
+ option: formattedOptions.map(option => {
196
+ const next = {
197
+ ...option,
198
+ add_price: option.add_price ?? option.price
199
+ };
200
+ delete next.price;
201
+ return next;
202
+ })
203
+ };
204
+ }
190
205
  }
191
206
  }
192
207
  return origin;
@@ -299,12 +314,16 @@ const getProductOriginTotalPrice = params => {
299
314
  * @returns 格式化后的套餐规格信息
300
315
  */
301
316
  exports.getProductOriginTotalPrice = getProductOriginTotalPrice;
302
- const formatOptions = options => {
317
+ const formatOptions = (options, product) => {
303
318
  if (!options?.length) return [];
304
319
  return options.map(item => {
320
+ const optionGroupId = item?.option_group_id;
321
+ const optionItemId = item?.id ?? item?.option_group_item_id ?? item?.product_option_item_id;
322
+ const optionGroup = product?.option_group?.find(group => String(group?.id) === String(optionGroupId));
323
+ const optionItem = optionGroup?.option_item?.find(candidate => String(candidate?.id) === String(optionItemId));
305
324
  return {
306
- id: item?.id,
307
- name: item?.name,
325
+ id: optionItemId,
326
+ name: item?.name ?? item?.title ?? optionItem?.name ?? optionItem?.title,
308
327
  num: item?.num,
309
328
  price: item?.price,
310
329
  total: item?.price,
@@ -320,7 +339,7 @@ const formatOptionsToOrigin = options => {
320
339
  return options.map(d => {
321
340
  return {
322
341
  num: d.num,
323
- option_group_item_id: d.option_group_item_id,
342
+ option_group_item_id: d?.option_group_item_id || d?.product_option_item_id,
324
343
  option_group_id: d.option_group_id
325
344
  };
326
345
  });
@@ -592,7 +592,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
592
592
  generateIdempotencyToken(): string;
593
593
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
594
594
  createOrder(params: CommitOrderParams['query']): {
595
- type: "appointment_booking" | "virtual";
595
+ type: "virtual" | "appointment_booking";
596
596
  platform: string;
597
597
  sales_channel: string;
598
598
  order_sales_channel: string;
@@ -213,6 +213,7 @@ export interface VirtualCurrencySnapshotItem {
213
213
  id: number | string;
214
214
  tag: 'virtual_currency';
215
215
  product_id?: number | string;
216
+ code?: string;
216
217
  product_name: string;
217
218
  par_value: string;
218
219
  used_par_value: string;
@@ -284,6 +284,10 @@ function normalizeVirtualCurrencySnapshotItem(value) {
284
284
  if (productId !== undefined) {
285
285
  snapshot.product_id = productId;
286
286
  }
287
+ const code = normalizeSnapshotScalar(value.code);
288
+ if (code !== undefined) {
289
+ snapshot.code = String(code).trim();
290
+ }
287
291
  return snapshot;
288
292
  }
289
293
  function normalizeVirtualCurrencySnapshotList(value) {
@@ -314,6 +318,10 @@ function buildVirtualCurrencySnapshotFromList(value) {
314
318
  if (productId !== undefined) {
315
319
  snapshot.product_id = productId;
316
320
  }
321
+ const code = normalizeSnapshotScalar(item.code);
322
+ if (code !== undefined) {
323
+ snapshot.code = String(code).trim();
324
+ }
317
325
  result.push(snapshot);
318
326
  return result;
319
327
  }, []);
@@ -218,6 +218,17 @@ export interface ProductData {
218
218
  bundle?: any[];
219
219
  /** 商品选项组成 */
220
220
  options?: any[];
221
+ /** 单规格组;用于由已选 option 反查规格项名称、价格等商品快照字段。 */
222
+ option_group?: Array<{
223
+ id: number | string;
224
+ option_item?: Array<{
225
+ id: number | string;
226
+ name?: string | Record<string, any>;
227
+ title?: string | Record<string, any>;
228
+ [key: string]: any;
229
+ }>;
230
+ [key: string]: any;
231
+ }>;
221
232
  /** 商品原信息 */
222
233
  origin?: any;
223
234
  /** 容量 */
@@ -25,6 +25,7 @@ var _types3 = require("./modules/order/types");
25
25
  var _filterOrders = require("./modules/order/utils/filterOrders");
26
26
  var _filterBookings = require("./modules/order/utils/filterBookings");
27
27
  var _smallTicket = require("./utils/small-ticket");
28
+ var _templateVisibility = require("../shared/receipt/templateVisibility");
28
29
  var _BaseSales = require("../solution/BaseSales");
29
30
  var _paymentUtils = require("../modules/Order/payment-utils");
30
31
  var _salesNotes = require("../modules/Order/salesNotes");
@@ -3851,7 +3852,8 @@ class Server {
3851
3852
  }
3852
3853
  const printableOrder = await this.withLocalSmallTicketData(params.order, {
3853
3854
  requireFullyPaid: params.requireFullyPaid,
3854
- invoiceTemplateSettings: params.invoiceTemplateSettings
3855
+ invoiceTemplateSettings: params.invoiceTemplateSettings,
3856
+ applyTemplateVisibility: true
3855
3857
  });
3856
3858
  if (!(0, _smallTicket.hasSmallTicketData)(printableOrder.payment_info?.small_ticket_data)) {
3857
3859
  return {
@@ -3873,9 +3875,11 @@ class Server {
3873
3875
  invoiceLayoutConfig: params.invoiceLayoutConfig,
3874
3876
  invoiceTemplateSettings: params.invoiceTemplateSettings
3875
3877
  });
3878
+ // Receipt visibility belongs to this output only. Do not return a filtered
3879
+ // snapshot to callers that may retain the order for later sync or reprints.
3876
3880
  return {
3877
3881
  printed: true,
3878
- order: printableOrder
3882
+ order: (0, _templateVisibility.requiresInvoiceDataFiltering)(params.invoiceTemplateSettings) ? params.order : printableOrder
3879
3883
  };
3880
3884
  }
3881
3885
  shouldLookupLocalPrintOrder(input) {
@@ -4084,7 +4088,10 @@ class Server {
4084
4088
  small_ticket_data_flag: 1,
4085
4089
  payment_info: paymentInfo
4086
4090
  }, {
4087
- locales: this.normalizeRequestedReceiptLocales(input.locales)
4091
+ locales: this.normalizeRequestedReceiptLocales(input.locales),
4092
+ invoiceTemplateSettings: input.template_settings === undefined ? undefined : this.normalizePrintInvoiceTemplateSettings(input.template_settings),
4093
+ applyTemplateVisibility: true,
4094
+ includeReceiptKeys: input.template_settings !== undefined
4088
4095
  });
4089
4096
  const smallTicketData = rebuiltOrder.payment_info?.small_ticket_data;
4090
4097
  if (!(0, _smallTicket.hasSmallTicketData)(smallTicketData)) {
@@ -4102,7 +4109,17 @@ class Server {
4102
4109
  status: true,
4103
4110
  message: '',
4104
4111
  data: {
4105
- small_ticket_data: smallTicketData
4112
+ small_ticket_data: smallTicketData,
4113
+ template_visibility_applied: true,
4114
+ // These products and currency settings are the exact source used for
4115
+ // this receipt, not the potentially newer active tempOrder.
4116
+ source: {
4117
+ ...rebuiltOrder,
4118
+ payment_info: {
4119
+ ...(rebuiltOrder.payment_info || {}),
4120
+ small_ticket_data: undefined
4121
+ }
4122
+ }
4106
4123
  }
4107
4124
  };
4108
4125
  } catch (error) {
@@ -4343,15 +4360,24 @@ class Server {
4343
4360
  });
4344
4361
  if (pendingResult?.status === true) {
4345
4362
  const pendingOrder = pendingResult.data;
4346
- if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
4347
- await this.dispatchLocalReceiptPrint({
4348
- checkoutData,
4349
- order: pendingOrder,
4350
- response: pendingResult,
4351
- requireFullyPaid: true,
4352
- invoiceLayoutConfig,
4353
- invoiceTemplateSettings
4354
- });
4363
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData, invoiceTemplateSettings) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
4364
+ try {
4365
+ await this.dispatchLocalReceiptPrint({
4366
+ checkoutData,
4367
+ order: pendingOrder,
4368
+ response: pendingResult,
4369
+ requireFullyPaid: true,
4370
+ invoiceLayoutConfig,
4371
+ invoiceTemplateSettings
4372
+ });
4373
+ } catch (error) {
4374
+ // The sale is already persisted. A failed receipt must not cancel its
4375
+ // sync task or send an unfiltered fallback to the printer.
4376
+ pendingResult.receipt_print_error = this.getUnknownErrorMessage(error);
4377
+ this.logError(`${title}: 小票生成失败,订单仍继续同步`, {
4378
+ error: pendingResult.receipt_print_error
4379
+ });
4380
+ }
4355
4381
  }
4356
4382
  await this.dispatchCheckoutSyncTask({
4357
4383
  backendPath,
@@ -4409,16 +4435,24 @@ class Server {
4409
4435
  }
4410
4436
  const response = this.withSyncedOrderIdInCheckoutResponse(syncResult.normalizedResponse, syncResult.syncedOrder);
4411
4437
  const syncedOrder = syncResult.syncedOrder;
4412
- if (syncedOrder && this.shouldBuildSmallTicketData(syncResult.checkoutData) && this.isSalesOrderFullyPaid(syncedOrder)) {
4413
- await this.dispatchLocalReceiptPrint({
4414
- checkoutData: syncResult.checkoutData,
4415
- order: syncedOrder,
4416
- response: syncResult.normalizedResponse,
4417
- requireFullyPaid: true,
4418
- invoiceLayoutConfig,
4419
- invoiceTemplateSettings
4420
- // print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
4421
- });
4438
+ if (syncedOrder && this.shouldBuildSmallTicketData(syncResult.checkoutData, invoiceTemplateSettings) && this.isSalesOrderFullyPaid(syncedOrder)) {
4439
+ try {
4440
+ await this.dispatchLocalReceiptPrint({
4441
+ checkoutData: syncResult.checkoutData,
4442
+ order: syncedOrder,
4443
+ response: syncResult.normalizedResponse,
4444
+ requireFullyPaid: true,
4445
+ invoiceLayoutConfig,
4446
+ invoiceTemplateSettings
4447
+ });
4448
+ } catch (error) {
4449
+ // Checkout already succeeded remotely; report the receipt failure
4450
+ // separately instead of implying that payment/order creation failed.
4451
+ response.receipt_print_error = this.getUnknownErrorMessage(error);
4452
+ this.logError(`${title}: 小票生成失败,订单已同步`, {
4453
+ error: response.receipt_print_error
4454
+ });
4455
+ }
4422
4456
  }
4423
4457
  return response;
4424
4458
  } catch (error) {
@@ -4627,10 +4661,12 @@ class Server {
4627
4661
  if (this.core.context?.getPlatform?.() !== 'android') return true;
4628
4662
  return this.app?.storage?.getStorage?.(AUTO_PRINT_STORAGE_KEY) !== 'false';
4629
4663
  }
4630
- shouldBuildSmallTicketData(order) {
4664
+ shouldBuildSmallTicketData(order, invoiceTemplateSettings) {
4631
4665
  if (!order || typeof order !== 'object') return false;
4632
- // if (hasSmallTicketData(order.payment_info?.small_ticket_data)) return false;
4633
- return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
4666
+ const flag = order.small_ticket_data_flag ?? order.smallTicketDataFlag;
4667
+ // A synced order can omit the generation flag; required display filtering
4668
+ // still rebuilds its output. An explicit 0 retains the no-auto-print intent.
4669
+ return Number(flag ?? 0) === 1 || flag == null && (0, _templateVisibility.requiresInvoiceDataFiltering)(invoiceTemplateSettings);
4634
4670
  }
4635
4671
  shouldPrintSyncedOrder(params) {
4636
4672
  if (this.hasPaymentStatus(params.syncedOrder)) {
@@ -4934,7 +4970,8 @@ class Server {
4934
4970
  }
4935
4971
  }
4936
4972
  async withLocalSmallTicketData(order, options) {
4937
- if (!this.shouldBuildSmallTicketData(order)) return order;
4973
+ const mustApplyVisibility = options?.applyTemplateVisibility === true && (0, _templateVisibility.requiresInvoiceDataFiltering)(options.invoiceTemplateSettings);
4974
+ if (!this.shouldBuildSmallTicketData(order) && !mustApplyVisibility) return order;
4938
4975
  if (options?.requireFullyPaid && !this.isSalesOrderFullyPaid(order)) return order;
4939
4976
  try {
4940
4977
  const normalizedCollections = (0, _orderCollectionIdentity.normalizeOrderCollections)(order, {
@@ -4958,7 +4995,9 @@ class Server {
4958
4995
  order: enrichedOrder,
4959
4996
  shopInfo: this.getSmallTicketShopInfo(),
4960
4997
  locales: [...(0, _OpenData.resolveInvoiceReceiptLocales)(options?.invoiceTemplateSettings), ...(options?.locales || [])],
4961
- productMap
4998
+ productMap,
4999
+ includeReceiptKeys: options?.includeReceiptKeys,
5000
+ templateSettings: options?.applyTemplateVisibility ? options.invoiceTemplateSettings : undefined
4962
5001
  });
4963
5002
  return {
4964
5003
  ...enrichedOrder,
@@ -4971,6 +5010,7 @@ class Server {
4971
5010
  this.logError('withLocalSmallTicketData: 生成本地小票数据失败', {
4972
5011
  error: error instanceof Error ? error.message : String(error)
4973
5012
  });
5013
+ if (mustApplyVisibility) throw error;
4974
5014
  return order;
4975
5015
  }
4976
5016
  }
@@ -463,6 +463,7 @@ export interface OrderData {
463
463
  id: number | string;
464
464
  tag: 'virtual_currency';
465
465
  product_id?: number | string;
466
+ code?: string;
466
467
  product_name: string;
467
468
  par_value: string;
468
469
  used_par_value: string;
@@ -22,6 +22,8 @@ export interface BuildSmallTicketDataParams {
22
22
  shopInfo?: SmallTicketShopInfo | null;
23
23
  locales?: string[];
24
24
  productMap?: Record<string | number, Record<string, any>>;
25
+ /** Resolved template settings or layout; omitted settings preserve native compatibility. */
26
+ templateSettings?: unknown;
25
27
  /** Customer preview only: stable source identities for bilingual rows. */
26
28
  includeReceiptKeys?: boolean;
27
29
  }