@pisell/pisellos 2.3.67 → 2.3.69

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 (61) hide show
  1. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -1
  2. package/dist/model/strategy/adapter/walletPass/utils.js +0 -2
  3. package/dist/modules/BaseModule.d.ts +1 -0
  4. package/dist/modules/BaseModule.js +24 -28
  5. package/dist/modules/Customer/index.d.ts +4 -0
  6. package/dist/modules/Customer/index.js +91 -59
  7. package/dist/modules/Customer/types.d.ts +2 -0
  8. package/dist/modules/Order/index.d.ts +22 -2
  9. package/dist/modules/Order/index.js +313 -142
  10. package/dist/modules/Order/types.d.ts +13 -1
  11. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
  12. package/dist/modules/Order/utils/orderCollectionIdentity.js +75 -0
  13. package/dist/modules/Order/utils.js +0 -1
  14. package/dist/modules/Payment/index.d.ts +4 -0
  15. package/dist/modules/Payment/index.js +14 -4
  16. package/dist/modules/Payment/walletpass.js +52 -18
  17. package/dist/modules/Rules/index.js +46 -31
  18. package/dist/server/index.js +3 -6
  19. package/dist/server/modules/order/index.d.ts +1 -0
  20. package/dist/server/modules/order/index.js +252 -93
  21. package/dist/server/utils/small-ticket.js +2 -1
  22. package/dist/solution/BaseSales/index.d.ts +13 -1
  23. package/dist/solution/BaseSales/index.js +903 -831
  24. package/dist/solution/BaseSales/utils.js +31 -20
  25. package/dist/solution/BookingTicket/index.d.ts +7 -1
  26. package/dist/solution/BookingTicket/index.js +310 -224
  27. package/dist/solution/ScanOrder/utils.js +31 -20
  28. package/dist/solution/UnifiedBookingSales/index.d.ts +25 -0
  29. package/dist/solution/UnifiedBookingSales/index.js +640 -321
  30. package/dist/solution/UnifiedBookingSales/types.d.ts +7 -0
  31. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -1
  32. package/lib/model/strategy/adapter/walletPass/utils.js +0 -1
  33. package/lib/modules/BaseModule.d.ts +1 -0
  34. package/lib/modules/BaseModule.js +24 -37
  35. package/lib/modules/Customer/index.d.ts +4 -0
  36. package/lib/modules/Customer/index.js +11 -0
  37. package/lib/modules/Customer/types.d.ts +2 -0
  38. package/lib/modules/Order/index.d.ts +22 -2
  39. package/lib/modules/Order/index.js +212 -54
  40. package/lib/modules/Order/types.d.ts +13 -1
  41. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
  42. package/lib/modules/Order/utils/orderCollectionIdentity.js +70 -0
  43. package/lib/modules/Order/utils.js +0 -1
  44. package/lib/modules/Payment/index.d.ts +4 -0
  45. package/lib/modules/Payment/index.js +7 -0
  46. package/lib/modules/Payment/walletpass.js +27 -2
  47. package/lib/modules/Rules/index.js +17 -1
  48. package/lib/server/index.js +3 -6
  49. package/lib/server/modules/order/index.d.ts +1 -0
  50. package/lib/server/modules/order/index.js +66 -2
  51. package/lib/server/utils/small-ticket.js +1 -1
  52. package/lib/solution/BaseSales/index.d.ts +13 -1
  53. package/lib/solution/BaseSales/index.js +61 -18
  54. package/lib/solution/BaseSales/utils.js +29 -18
  55. package/lib/solution/BookingTicket/index.d.ts +7 -1
  56. package/lib/solution/BookingTicket/index.js +65 -14
  57. package/lib/solution/ScanOrder/utils.js +29 -18
  58. package/lib/solution/UnifiedBookingSales/index.d.ts +25 -0
  59. package/lib/solution/UnifiedBookingSales/index.js +188 -0
  60. package/lib/solution/UnifiedBookingSales/types.d.ts +7 -0
  61. package/package.json +1 -1
@@ -56,6 +56,7 @@ var import_utils = require("../../modules/Order/utils");
56
56
  __reExport(BookingTicket_exports, require("./types"), module.exports);
57
57
  var OPEN_DATA_SECTION_CODES = ["sale", "reservation", "fulfillment", "menu", "workflow"];
58
58
  var OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
59
+ var USER_PLATFORM = ["pc", "h5"];
59
60
  function resolveBookingUidForAddTime(booking) {
60
61
  var _a;
61
62
  const uid = (_a = booking == null ? void 0 : booking.metadata) == null ? void 0 : _a.unique_identification_number;
@@ -135,6 +136,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
135
136
  this.addTimeProductsCatalog = [];
136
137
  this.orderCustomerDiscountRefreshInFlight = null;
137
138
  this.orderCustomerDiscountRefreshCustomerId = null;
139
+ this.orderCustomerPromotionRefreshInFlight = null;
138
140
  this.loadOpenDataConfigInFlight = null;
139
141
  }
140
142
  /**
@@ -240,6 +242,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
240
242
  }
241
243
  async configureIdGeneratorFromOpenData() {
242
244
  this.setPaymentNumberDevicePrefix(null);
245
+ const idGenerator = this.getIdGeneratorPlugin();
246
+ if (!(idGenerator == null ? void 0 : idGenerator.configure)) {
247
+ console.warn("[BookingTicket] idGenerator 插件不可用,跳过配置");
248
+ return;
249
+ }
243
250
  let openDataConfig = null;
244
251
  try {
245
252
  openDataConfig = await this.loadOpenDataConfig();
@@ -247,11 +254,6 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
247
254
  console.warn("[BookingTicket] OpenData 配置加载失败,跳过 idGenerator 配置", error);
248
255
  return;
249
256
  }
250
- const idGenerator = this.getIdGeneratorPlugin();
251
- if (!(idGenerator == null ? void 0 : idGenerator.configure)) {
252
- console.warn("[BookingTicket] idGenerator 插件不可用,跳过配置");
253
- return;
254
- }
255
257
  const receiptSequenceLength = this.normalizePositiveInteger(
256
258
  openDataConfig == null ? void 0 : openDataConfig["sale.short_number_digits"],
257
259
  5
@@ -352,7 +354,8 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
352
354
  const scannedList = raw.scannedDiscountList || [];
353
355
  const extractedCustomerId = this.getDiscountCustomerId(scannedList);
354
356
  const hasOrderCustomer = Boolean(this.store.order.getOrderCustomer());
355
- if (!hasOrderCustomer && extractedCustomerId) {
357
+ const isUserPlatform = USER_PLATFORM.includes(this.otherParams.platform);
358
+ if (!hasOrderCustomer && extractedCustomerId && !isUserPlatform) {
356
359
  await this.hydrateOrderCustomerFromScanDiscounts(scannedList);
357
360
  }
358
361
  if (raw.isAvailable) {
@@ -396,7 +399,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
396
399
  }
397
400
  return null;
398
401
  }
399
- async resolveCustomerByDiscountCustomerId(customerId) {
402
+ async resolveCustomerById(customerId) {
400
403
  var _a;
401
404
  const localCustomers = this.store.customer.getCustomers();
402
405
  const localCustomer = this.findCustomerById(localCustomers, customerId);
@@ -410,7 +413,23 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
410
413
  num: 1
411
414
  });
412
415
  const remoteCustomer = this.findCustomerById((result == null ? void 0 : result.list) || [], customerId) || ((_a = result == null ? void 0 : result.list) == null ? void 0 : _a[0]) || null;
413
- return remoteCustomer ? this.normalizeCustomer(remoteCustomer) : null;
416
+ if (remoteCustomer) {
417
+ return this.normalizeCustomer(remoteCustomer);
418
+ }
419
+ try {
420
+ const detailCustomer = await this.store.customer.queryCustomerDetail(customerId);
421
+ return detailCustomer ? this.normalizeCustomer(detailCustomer) : null;
422
+ } catch (error) {
423
+ console.warn(
424
+ "[BookingTicket] resolveCustomerById detail request failed",
425
+ { customerId, error }
426
+ );
427
+ return null;
428
+ }
429
+ }
430
+ /** 兼容既有优惠码扫码逻辑。 */
431
+ resolveCustomerByDiscountCustomerId(customerId) {
432
+ return this.resolveCustomerById(customerId);
414
433
  }
415
434
  findCustomerById(customers = [], customerId) {
416
435
  return customers.find((customer) => {
@@ -899,9 +918,21 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
899
918
  const next = this.buildOrderCustomerPayload();
900
919
  this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next);
901
920
  this.refreshDiscountConfigAfterOrderCustomerChange(patch.customer_id);
902
- void this.store.order.applyPromotion().catch((error) => {
903
- console.error("[BookingTicket] applyPromotion after customer change failed", error);
904
- });
921
+ const promotionRefreshTask = this.store.order.applyPromotion().then(() => void 0);
922
+ this.orderCustomerPromotionRefreshInFlight = promotionRefreshTask;
923
+ void promotionRefreshTask.then(
924
+ () => {
925
+ if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask)
926
+ return;
927
+ this.orderCustomerPromotionRefreshInFlight = null;
928
+ },
929
+ (error) => {
930
+ console.error("[BookingTicket] applyPromotion after customer change failed", error);
931
+ if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask)
932
+ return;
933
+ this.orderCustomerPromotionRefreshInFlight = null;
934
+ }
935
+ );
905
936
  }
906
937
  /**
907
938
  * 读取 tempOrder 上的下单客户协议字段;customer_id 缺失时返回 null。
@@ -971,12 +1002,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
971
1002
  }
972
1003
  refreshDiscountConfigAfterOrderCustomerChange(customerId) {
973
1004
  if (!customerId || customerId === 1)
974
- return;
1005
+ return Promise.resolve();
975
1006
  if (this.orderCustomerDiscountRefreshInFlight && this.orderCustomerDiscountRefreshCustomerId === customerId) {
976
- return;
1007
+ return this.orderCustomerDiscountRefreshInFlight;
977
1008
  }
978
1009
  const previousRefresh = this.orderCustomerDiscountRefreshInFlight;
979
1010
  const refreshTask = (async () => {
1011
+ var _a, _b, _c, _d;
980
1012
  if (previousRefresh) {
981
1013
  await previousRefresh.catch(() => void 0);
982
1014
  }
@@ -984,7 +1016,10 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
984
1016
  if (!currentCustomer || Number(currentCustomer.customer_id) !== customerId) {
985
1017
  return;
986
1018
  }
987
- await this.loadDiscountConfig({ customerId });
1019
+ const tempOrder = (_b = (_a = this.store.order).getTempOrder) == null ? void 0 : _b.call(_a);
1020
+ const orderId = (tempOrder == null ? void 0 : tempOrder.order_id) || ((_d = (_c = this.getOrderIdentity) == null ? void 0 : _c.call(this)) == null ? void 0 : _d.orderId);
1021
+ const action = !orderId || String(orderId).startsWith("local_order") ? "create" : "edit";
1022
+ await this.loadDiscountConfig({ customerId, action });
988
1023
  })();
989
1024
  this.orderCustomerDiscountRefreshInFlight = refreshTask;
990
1025
  this.orderCustomerDiscountRefreshCustomerId = customerId;
@@ -996,6 +1031,22 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
996
1031
  this.orderCustomerDiscountRefreshInFlight = null;
997
1032
  this.orderCustomerDiscountRefreshCustomerId = null;
998
1033
  });
1034
+ return refreshTask;
1035
+ }
1036
+ waitForOrderCustomerPromotionRefresh() {
1037
+ return this.orderCustomerPromotionRefreshInFlight || Promise.resolve();
1038
+ }
1039
+ async prepareProductPriceQueryContext(customerId) {
1040
+ await Promise.resolve();
1041
+ const normalizedCustomerId = Number(customerId || 0);
1042
+ const refreshTask = this.orderCustomerDiscountRefreshInFlight;
1043
+ const shouldWait = normalizedCustomerId > 1 && this.orderCustomerDiscountRefreshCustomerId === normalizedCustomerId && Boolean(refreshTask);
1044
+ if (shouldWait && refreshTask) {
1045
+ await refreshTask;
1046
+ }
1047
+ }
1048
+ preferAuthoritativeProductQueryPrice() {
1049
+ return true;
999
1050
  }
1000
1051
  /**
1001
1052
  * 获取客户分页信息
@@ -357,33 +357,44 @@ function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
357
357
  return productList;
358
358
  }
359
359
  function buildProductLineFingerprint(productOptionItem, productBundle) {
360
- const optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
361
- const normalizedOpts = optArr.map((item) => ({
362
- option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
363
- option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
364
- num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
365
- price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
366
- })).sort((p, q) => {
367
- if (p.option_group_item_id !== q.option_group_item_id) {
368
- return p.option_group_item_id - q.option_group_item_id;
369
- }
370
- if (p.option_group_id !== q.option_group_id)
371
- return p.option_group_id - q.option_group_id;
372
- if (p.num !== q.num)
373
- return p.num - q.num;
374
- return p.price.localeCompare(q.price);
375
- });
360
+ const normalizeOptions = (options) => {
361
+ const optionArr = Array.isArray(options) ? options : [];
362
+ return optionArr.map((item) => ({
363
+ option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
364
+ option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
365
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
366
+ price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
367
+ })).sort((p, q) => {
368
+ if (p.option_group_item_id !== q.option_group_item_id) {
369
+ return p.option_group_item_id - q.option_group_item_id;
370
+ }
371
+ if (p.option_group_id !== q.option_group_id) {
372
+ return p.option_group_id - q.option_group_id;
373
+ }
374
+ if (p.num !== q.num)
375
+ return p.num - q.num;
376
+ return p.price.localeCompare(q.price);
377
+ });
378
+ };
379
+ const normalizedOpts = normalizeOptions(productOptionItem);
376
380
  const bundleArr = Array.isArray(productBundle) ? productBundle : [];
377
381
  const normalizedBundles = bundleArr.map((item) => ({
378
382
  bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
379
383
  product_id: Number(item == null ? void 0 : item.product_id) || 0,
380
- num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
384
+ product_variant_id: Number((item == null ? void 0 : item.bundle_variant_id) ?? (item == null ? void 0 : item.product_variant_id)) || 0,
385
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
386
+ option: normalizeOptions(item == null ? void 0 : item.option)
381
387
  })).sort((p, q) => {
382
388
  if (p.bundle_id !== q.bundle_id)
383
389
  return p.bundle_id - q.bundle_id;
384
390
  if (p.product_id !== q.product_id)
385
391
  return p.product_id - q.product_id;
386
- return p.num - q.num;
392
+ if (p.product_variant_id !== q.product_variant_id) {
393
+ return p.product_variant_id - q.product_variant_id;
394
+ }
395
+ if (p.num !== q.num)
396
+ return p.num - q.num;
397
+ return JSON.stringify(p.option).localeCompare(JSON.stringify(q.option));
387
398
  });
388
399
  return JSON.stringify([normalizedOpts, normalizedBundles]);
389
400
  }
@@ -63,6 +63,24 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
63
63
  private openDataTarget;
64
64
  private loadOpenDataInFlight;
65
65
  private loadOpenDataInFlightTarget;
66
+ protected getSubmitOrderSalesChannel(): string;
67
+ protected isSessionStoragePersistEnabled(): boolean;
68
+ protected shouldUseSessionStorageForSubModule(moduleName?: string): boolean;
69
+ /**
70
+ * 读取与当前 cacheId 同分桶的 Solution 会话状态。
71
+ * 该状态独立于 otherParams,适合页面皮肤保存短生命周期 UI 状态。
72
+ */
73
+ getSessionStateValue<T = unknown>(key: string): T | undefined;
74
+ /**
75
+ * 写入与当前 cacheId 同分桶的 Solution 会话状态。
76
+ * value 为 undefined 时删除该 key;存储失败不阻断业务流程。
77
+ */
78
+ setSessionStateValue(key: string, value: unknown): void;
79
+ /**
80
+ * 清除当前 cacheId 的可恢复订单快照,同时保留 Solution UI sessionState。
81
+ * 用于支付跳转等终态场景,避免浏览器返回时恢复已提交订单。
82
+ */
83
+ clearSessionStorageOrderSnapshot(): void;
66
84
  /**
67
85
  * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
68
86
  * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
@@ -72,6 +90,13 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
72
90
  protected getDefaultCheckoutSmallTicketDataFlag(): number;
73
91
  protected getRegisteredModuleNames(): readonly string[];
74
92
  protected createSubModule(moduleName: string): Module | null;
93
+ addNewOrder(): Promise<import("../../modules/Order/types").OrderTempOrder>;
94
+ syncAuthenticatedOrderCustomer(): Promise<boolean>;
95
+ private isAuthenticatedCustomerUserPlatform;
96
+ private resolveDiscountOrderIdentity;
97
+ private resolveDiscountAction;
98
+ private resetCachedCustomerDiscountState;
99
+ private refreshLegacySessionCustomerDiscounts;
75
100
  /**
76
101
  * Loads OpenData without borrowing BookingTicket. Cache ownership is tied to the exact
77
102
  * business/channel target so a reused solution instance cannot leak another entry's menus.
@@ -49,6 +49,9 @@ var import_BookingTicket = require("../BookingTicket");
49
49
  __reExport(UnifiedBookingSales_exports, require("./types"), module.exports);
50
50
  var OPEN_DATA_SECTION_CODES = ["sale", "reservation", "fulfillment", "menu", "workflow"];
51
51
  var OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
52
+ function isRecord(value) {
53
+ return !!value && typeof value === "object" && !Array.isArray(value);
54
+ }
52
55
  function pickLocalizedText(value) {
53
56
  if (!value)
54
57
  return void 0;
@@ -141,6 +144,28 @@ function toNumberId(value) {
141
144
  const parsed = Number(value);
142
145
  return Number.isFinite(parsed) ? parsed : String(value);
143
146
  }
147
+ function toCustomerId(value) {
148
+ const parsed = Number(value);
149
+ return Number.isFinite(parsed) && parsed > 1 ? parsed : null;
150
+ }
151
+ function resolveTempOrderCustomerId(tempOrder) {
152
+ var _a, _b, _c, _d, _e;
153
+ return toCustomerId(
154
+ (tempOrder == null ? void 0 : tempOrder.customer_id) || ((_a = tempOrder == null ? void 0 : tempOrder.customer) == null ? void 0 : _a.id) || ((_c = (_b = tempOrder == null ? void 0 : tempOrder._extend) == null ? void 0 : _b.customerSnapshot) == null ? void 0 : _c.id) || ((_e = (_d = tempOrder == null ? void 0 : tempOrder._extend) == null ? void 0 : _d.customerSnapshot) == null ? void 0 : _e.customer_id)
155
+ );
156
+ }
157
+ function isLocalOrderId(orderId) {
158
+ return typeof orderId === "string" && orderId.startsWith("local_order");
159
+ }
160
+ function isCustomerBoundDiscount(discount) {
161
+ const type = (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag);
162
+ return type === "good_pass" || type === "discount_card" || type === "product_discount_card";
163
+ }
164
+ function filterCustomerBoundDiscounts(discountList) {
165
+ if (!Array.isArray(discountList))
166
+ return [];
167
+ return discountList.filter((discount) => !isCustomerBoundDiscount(discount));
168
+ }
144
169
  function resolveProductKind(product) {
145
170
  var _a, _b, _c;
146
171
  if (product.duration)
@@ -447,6 +472,65 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
447
472
  this.loadOpenDataInFlight = null;
448
473
  this.loadOpenDataInFlightTarget = null;
449
474
  }
475
+ getSubmitOrderSalesChannel() {
476
+ var _a;
477
+ const channel = String(((_a = this.otherParams) == null ? void 0 : _a.channel) ?? "").trim();
478
+ return channel || super.getSubmitOrderSalesChannel();
479
+ }
480
+ isSessionStoragePersistEnabled() {
481
+ var _a;
482
+ return Boolean(
483
+ this.cacheId && ((_a = this.otherParams) == null ? void 0 : _a.enableSessionStoragePersist) === true
484
+ );
485
+ }
486
+ shouldUseSessionStorageForSubModule(moduleName) {
487
+ return this.isSessionStoragePersistEnabled() && moduleName === "order";
488
+ }
489
+ /**
490
+ * 读取与当前 cacheId 同分桶的 Solution 会话状态。
491
+ * 该状态独立于 otherParams,适合页面皮肤保存短生命周期 UI 状态。
492
+ */
493
+ getSessionStateValue(key) {
494
+ if (!key || !this.isSessionStoragePersistEnabled())
495
+ return void 0;
496
+ const cacheData = this.readSessionCacheData();
497
+ const solutionCache = cacheData == null ? void 0 : cacheData[this.name];
498
+ if (!isRecord(solutionCache) || !isRecord(solutionCache.sessionState)) {
499
+ return void 0;
500
+ }
501
+ return solutionCache.sessionState[key];
502
+ }
503
+ /**
504
+ * 写入与当前 cacheId 同分桶的 Solution 会话状态。
505
+ * value 为 undefined 时删除该 key;存储失败不阻断业务流程。
506
+ */
507
+ setSessionStateValue(key, value) {
508
+ if (!key || !this.isSessionStoragePersistEnabled())
509
+ return;
510
+ const cacheData = this.readSessionCacheData();
511
+ const solutionCache = cacheData == null ? void 0 : cacheData[this.name];
512
+ const currentSessionState = isRecord(solutionCache) && isRecord(solutionCache.sessionState) ? solutionCache.sessionState : {};
513
+ const nextSessionState = { ...currentSessionState };
514
+ if (value === void 0) {
515
+ delete nextSessionState[key];
516
+ } else {
517
+ nextSessionState[key] = value;
518
+ }
519
+ this.checkSaveCache({
520
+ cacheId: this.cacheId,
521
+ fatherModule: this.name,
522
+ store: { sessionState: nextSessionState },
523
+ cacheKey: ["sessionState"]
524
+ });
525
+ }
526
+ /**
527
+ * 清除当前 cacheId 的可恢复订单快照,同时保留 Solution UI sessionState。
528
+ * 用于支付跳转等终态场景,避免浏览器返回时恢复已提交订单。
529
+ */
530
+ clearSessionStorageOrderSnapshot() {
531
+ var _a, _b;
532
+ (_b = (_a = this.store.order) == null ? void 0 : _a.clearSessionStoragePersistedTempOrder) == null ? void 0 : _b.call(_a);
533
+ }
450
534
  /**
451
535
  * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
452
536
  * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
@@ -472,6 +556,110 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
472
556
  }
473
557
  return super.createSubModule(moduleName);
474
558
  }
559
+ async addNewOrder() {
560
+ var _a, _b, _c, _d;
561
+ const sessionRecord = this.isSessionStoragePersistEnabled() ? (_b = (_a = this.store.order) == null ? void 0 : _a.consumeSessionStorageRestore) == null ? void 0 : _b.call(_a) : null;
562
+ if (sessionRecord) {
563
+ await this.loadSalesDetail({
564
+ preloadedSalesDetail: sessionRecord,
565
+ hydrateSource: "sessionStorage"
566
+ });
567
+ }
568
+ const tempOrder = await super.addNewOrder();
569
+ if (sessionRecord) {
570
+ (_c = this.store.order) == null ? void 0 : _c.persistTempOrder();
571
+ }
572
+ if (this.isAuthenticatedCustomerUserPlatform()) {
573
+ try {
574
+ const didSyncAuthenticatedCustomer = await this.syncAuthenticatedOrderCustomer();
575
+ if (!didSyncAuthenticatedCustomer && sessionRecord) {
576
+ await this.refreshLegacySessionCustomerDiscounts(tempOrder);
577
+ }
578
+ } catch (error) {
579
+ console.warn(
580
+ "[UnifiedBookingSales] Failed to sync authenticated order customer after addNewOrder",
581
+ error
582
+ );
583
+ }
584
+ } else if (sessionRecord) {
585
+ try {
586
+ await this.refreshLegacySessionCustomerDiscounts(tempOrder);
587
+ } catch (error) {
588
+ console.warn(
589
+ "[UnifiedBookingSales] Failed to refresh cached customer discounts after addNewOrder",
590
+ error
591
+ );
592
+ }
593
+ }
594
+ return ((_d = this.store.order) == null ? void 0 : _d.getTempOrder()) || tempOrder;
595
+ }
596
+ async syncAuthenticatedOrderCustomer() {
597
+ var _a, _b, _c, _d, _e, _f;
598
+ if (!this.isAuthenticatedCustomerUserPlatform())
599
+ return false;
600
+ const authenticatedCustomer = (_d = (_c = (_b = (_a = this.core) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "user")) == null ? void 0 : _c.get) == null ? void 0 : _d.call(_c);
601
+ const authenticatedCustomerId = toCustomerId(authenticatedCustomer == null ? void 0 : authenticatedCustomer.id);
602
+ if (!authenticatedCustomerId)
603
+ return false;
604
+ const tempOrder = this.getTempOrder();
605
+ const cachedCustomerId = resolveTempOrderCustomerId(tempOrder);
606
+ if (cachedCustomerId !== null && cachedCustomerId !== authenticatedCustomerId) {
607
+ await this.resetCachedCustomerDiscountState();
608
+ }
609
+ (_f = (_e = this.store.customer) == null ? void 0 : _e.setSelectedCustomer) == null ? void 0 : _f.call(_e, authenticatedCustomer);
610
+ this.setOrderCustomer(authenticatedCustomer);
611
+ await Promise.all([
612
+ this.refreshDiscountConfigAfterOrderCustomerChange(authenticatedCustomerId),
613
+ this.waitForOrderCustomerPromotionRefresh()
614
+ ]);
615
+ return true;
616
+ }
617
+ isAuthenticatedCustomerUserPlatform() {
618
+ var _a;
619
+ const platform = String(((_a = this.otherParams) == null ? void 0 : _a.platform) || "").toLowerCase();
620
+ return platform === "pc" || platform === "h5";
621
+ }
622
+ resolveDiscountOrderIdentity(tempOrder) {
623
+ var _a, _b, _c;
624
+ return (tempOrder == null ? void 0 : tempOrder.order_id) || ((_c = (_b = (_a = this.store.order) == null ? void 0 : _a.getOrderIdentity) == null ? void 0 : _b.call(_a)) == null ? void 0 : _c.orderId) || null;
625
+ }
626
+ resolveDiscountAction(orderId) {
627
+ if (!orderId || isLocalOrderId(orderId))
628
+ return "create";
629
+ return "edit";
630
+ }
631
+ async resetCachedCustomerDiscountState() {
632
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
633
+ (_b = (_a = this.store.order) == null ? void 0 : _a.clearOrderCustomer) == null ? void 0 : _b.call(_a);
634
+ (_d = (_c = this.store.customer) == null ? void 0 : _c.setSelectedCustomer) == null ? void 0 : _d.call(_c, null);
635
+ this.discountConfigCacheKey = null;
636
+ this.hasManualDiscountSelection = false;
637
+ const orderStore = ((_e = this.store.order) == null ? void 0 : _e.store) || {};
638
+ const discountModule = orderStore.discount;
639
+ const filteredOriginalDiscounts = filterCustomerBoundDiscounts(
640
+ ((_f = discountModule == null ? void 0 : discountModule.getOriginalDiscountList) == null ? void 0 : _f.call(discountModule)) || []
641
+ );
642
+ const filteredCurrentDiscounts = filterCustomerBoundDiscounts(
643
+ ((_g = discountModule == null ? void 0 : discountModule.getDiscountList) == null ? void 0 : _g.call(discountModule)) || []
644
+ );
645
+ await ((_h = discountModule == null ? void 0 : discountModule.setOriginalDiscountList) == null ? void 0 : _h.call(discountModule, filteredOriginalDiscounts));
646
+ await ((_i = discountModule == null ? void 0 : discountModule.setDiscountList) == null ? void 0 : _i.call(discountModule, filteredCurrentDiscounts));
647
+ (_k = (_j = this.store.order) == null ? void 0 : _j.applyDiscount) == null ? void 0 : _k.call(_j);
648
+ await ((_m = (_l = this.store.order) == null ? void 0 : _l.recalculateSummary) == null ? void 0 : _m.call(_l, { createIfMissing: true }));
649
+ (_o = (_n = this.store.order) == null ? void 0 : _n.persistTempOrder) == null ? void 0 : _o.call(_n);
650
+ }
651
+ async refreshLegacySessionCustomerDiscounts(tempOrder) {
652
+ const customerId = resolveTempOrderCustomerId(tempOrder);
653
+ if (!customerId)
654
+ return void 0;
655
+ const loadDiscountConfig = super.loadDiscountConfig.bind(this);
656
+ return await loadDiscountConfig({
657
+ customerId,
658
+ action: this.resolveDiscountAction(
659
+ this.resolveDiscountOrderIdentity(tempOrder)
660
+ )
661
+ });
662
+ }
475
663
  /**
476
664
  * Loads OpenData without borrowing BookingTicket. Cache ownership is tied to the exact
477
665
  * business/channel target so a reused solution instance cannot leak another entry's menus.
@@ -11,6 +11,13 @@ export declare enum UnifiedBookingSalesHooks {
11
11
  export interface UnifiedBookingSalesState extends BookingTicketState {
12
12
  resourcePlanner: ResourcePlannerModule;
13
13
  }
14
+ export interface UnifiedBookingSalesOtherParams extends Record<string, any> {
15
+ /**
16
+ * Persist the active order workspace in sessionStorage, partitioned by cacheId.
17
+ * Disabled by default and ignored when cacheId is missing.
18
+ */
19
+ enableSessionStoragePersist?: boolean;
20
+ }
14
21
  /** Explicit OpenData target used by page-level UnifiedBookingSales skins. */
15
22
  export interface UnifiedBookingSalesLoadOpenDataParams {
16
23
  businessCode: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.67",
4
+ "version": "2.3.69",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",