@pisell/pisellos 2.3.104 → 2.3.105

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.
@@ -851,7 +851,7 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
851
851
  key: "getUserIdentificationCodeListAsync",
852
852
  value: function () {
853
853
  var _getUserIdentificationCodeListAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(params) {
854
- var _newParams$products, _newParams$prepare_pa, _this$walletParams4, newParams, platform, response, sortedData;
854
+ var _newParams$products, _newParams$prepare_pa, _this$walletParams4, newParams, response, sortedData;
855
855
  return _regeneratorRuntime().wrap(function _callee6$(_context6) {
856
856
  while (1) switch (_context6.prev = _context6.next) {
857
857
  case 0:
@@ -864,20 +864,19 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
864
864
  this.paymentModule.logInfo('[WalletPass] 商品列表为空,跳过获取用户识别码列表');
865
865
  return _context6.abrupt("return", []);
866
866
  case 5:
867
- platform = this.paymentModule.getPlatform();
868
- if (!(platform === 'pc' || platform === 'h5')) {
869
- _context6.next = 11;
870
- break;
871
- }
872
- this.userIdentificationCodes = [];
873
- this.emitEvent(WalletPassHooks.OnUserIdentificationCodesUpdated, {
874
- userIdentificationCodes: []
875
- });
876
- this.paymentModule.logInfo('[WalletPass] 用户端平台跳过获取用户识别码列表', {
877
- platform: platform
878
- });
879
- return _context6.abrupt("return", []);
880
- case 11:
867
+ // const platform = this.paymentModule.getPlatform();
868
+ // if (platform === 'pc' || platform === 'h5') {
869
+ // this.userIdentificationCodes = [];
870
+ // this.emitEvent(WalletPassHooks.OnUserIdentificationCodesUpdated, {
871
+ // userIdentificationCodes: [],
872
+ // } as OnUserIdentificationCodesUpdatedEventData);
873
+ // this.paymentModule.logInfo(
874
+ // '[WalletPass] 用户端平台跳过获取用户识别码列表',
875
+ // { platform },
876
+ // );
877
+ // return [];
878
+ // }
879
+
881
880
  if (typeof newParams.payment_order_id === 'string' && newParams.payment_order_id.startsWith('LOCAL_')) {
882
881
  newParams.payment_order_id = undefined;
883
882
  }
@@ -888,9 +887,9 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
888
887
  filter_prepare_wallet_pass: newParams.filter_prepare_wallet_pass,
889
888
  payment_order_id: (_this$walletParams4 = this.walletParams) === null || _this$walletParams4 === void 0 ? void 0 : _this$walletParams4.payment_order_id
890
889
  });
891
- _context6.next = 15;
890
+ _context6.next = 9;
892
891
  return this.paymentModule.request.post('/machinecode/prepare/deduction', newParams);
893
- case 15:
892
+ case 9:
894
893
  response = _context6.sent;
895
894
  // 对获取到的数据进行排序,将错误码为 500100、500200、500300 的项目排到最后
896
895
  sortedData = sortUserIdentificationCodeList((response === null || response === void 0 ? void 0 : response.data) || []);
@@ -911,19 +910,19 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
911
910
  })
912
911
  });
913
912
  return _context6.abrupt("return", this.userIdentificationCodes);
914
- case 23:
915
- _context6.prev = 23;
913
+ case 17:
914
+ _context6.prev = 17;
916
915
  _context6.t0 = _context6["catch"](0);
917
916
  this.paymentModule.logError('[WalletPass] 获取用户识别码列表失败', _context6.t0, {
918
917
  customer_id: params.customer_id,
919
918
  available: params.available
920
919
  });
921
920
  return _context6.abrupt("return", []);
922
- case 27:
921
+ case 21:
923
922
  case "end":
924
923
  return _context6.stop();
925
924
  }
926
- }, _callee6, this, [[0, 23]]);
925
+ }, _callee6, this, [[0, 17]]);
927
926
  }));
928
927
  function getUserIdentificationCodeListAsync(_x7) {
929
928
  return _getUserIdentificationCodeListAsync.apply(this, arguments);
@@ -62,13 +62,21 @@ function resolveRequestedDurationMinutes(product, request) {
62
62
  }
63
63
  function resolveRequestedDurationStartTimes(product, request) {
64
64
  var _request$durationStar;
65
- if (product.kind !== 'duration') return [];
65
+ var allowSessionCustomRanges = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
66
+ if (product.kind !== 'duration' && !(product.kind === 'session' && allowSessionCustomRanges)) return [];
66
67
  var values = (_request$durationStar = request.durationStartTimesByProductId) === null || _request$durationStar === void 0 ? void 0 : _request$durationStar[String(product.id)];
67
68
  if (!Array.isArray(values)) return [];
68
69
  return Array.from(new Set(values.filter(function (value) {
69
70
  return typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value);
70
71
  })));
71
72
  }
73
+ function resolveRequestedSessionDurationMinutes(product, request, allowSessionCustomRanges) {
74
+ var _request$durationMinu2;
75
+ if (product.kind !== 'session' || !allowSessionCustomRanges) return undefined;
76
+ var override = (_request$durationMinu2 = request.durationMinutesByProductId) === null || _request$durationMinu2 === void 0 ? void 0 : _request$durationMinu2[String(product.id)];
77
+ var normalized = Number(override);
78
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : undefined;
79
+ }
72
80
  function toDateTime(value, _timezoneName) {
73
81
  try {
74
82
  return localDateTimeToScalar(parseLocalDateTime(value));
@@ -212,7 +220,11 @@ function evaluateCandidateTimeGate(params) {
212
220
  };
213
221
  }
214
222
  if (policy.type === 'before_start') {
215
- if (now < candidateRange.start) return null;
223
+ // Flexible-duration candidates start at minute precision. Keep the current
224
+ // minute selectable instead of treating the freshly generated candidate as
225
+ // already started because the query clock still contains seconds.
226
+ var hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
227
+ if (hasNotReachedStart) return null;
216
228
  return {
217
229
  status: 'unavailable',
218
230
  reasonCodes: ['booking_cutoff_before_start'],
@@ -1025,12 +1037,23 @@ export function getProductTimeRanges(projection) {
1025
1037
  };
1026
1038
  }
1027
1039
  if (product.kind === 'session' || product.kind === 'venue_slot') {
1040
+ var fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
1041
+ var customRanges = [];
1042
+ var customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
1043
+ var _requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
1044
+ if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
1045
+ _requestedStartTimes.forEach(function (startTime) {
1046
+ var start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
1047
+ if (!Number.isFinite(start)) return;
1048
+ customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
1049
+ });
1050
+ }
1028
1051
  return {
1029
1052
  productId: product.id,
1030
1053
  title: product.title,
1031
1054
  kind: product.kind,
1032
1055
  slotStepMinutes: slotStepMinutes,
1033
- ranges: getSessionRangesForProduct(projection, product, dateRange)
1056
+ ranges: dedupeProductRanges([].concat(_toConsumableArray(fixedRanges), customRanges))
1034
1057
  };
1035
1058
  }
1036
1059
  var requiredGroups = (product.requirementGroups || []).filter(function (group) {
@@ -243,6 +243,13 @@ export interface GetProductTimeRangesRequest {
243
243
  }
244
244
  export interface GetProductTimeRangesRuntimeOptions {
245
245
  evaluatedAt?: string;
246
+ /**
247
+ * Internal POS capability: allow explicit duration/start overrides to append
248
+ * a custom duration candidate for Session products. Fixed Session ranges are
249
+ * still returned unchanged. Callers outside the POS facade must leave this
250
+ * disabled.
251
+ */
252
+ allowSessionCustomRanges?: boolean;
246
253
  }
247
254
  export interface QueryAvailabilityBaseRequest {
248
255
  productIds?: AvailabilityId[];
@@ -30,6 +30,8 @@ var LABELS = {
30
30
  pickUpTime: 'Pick-up time',
31
31
  asap: 'ASAP',
32
32
  cash: 'Cash',
33
+ cashReceived: 'Cash received',
34
+ changeDue: 'Change due',
33
35
  eftpos: 'Eftpos',
34
36
  wallet: 'Wallet',
35
37
  giftCard: 'Gift card',
@@ -57,6 +59,8 @@ var LABELS = {
57
59
  pickUpTime: '取餐时间',
58
60
  asap: '尽快',
59
61
  cash: '现金支付',
62
+ cashReceived: '收取现金',
63
+ changeDue: '找零',
60
64
  eftpos: '刷卡支付',
61
65
  wallet: '钱包支付',
62
66
  giftCard: '礼品卡',
@@ -84,6 +88,8 @@ var LABELS = {
84
88
  pickUpTime: '取餐時間',
85
89
  asap: '盡快',
86
90
  cash: '現金支付',
91
+ cashReceived: '收取現金',
92
+ changeDue: '找零',
87
93
  eftpos: '刷卡支付',
88
94
  wallet: '錢包支付',
89
95
  giftCard: '禮品卡',
@@ -98,6 +104,14 @@ var LABELS = {
98
104
  rounding: '抹零',
99
105
  gross: '重量',
100
106
  tare: '去皮'
107
+ },
108
+ ja: {
109
+ cashReceived: 'お預かり',
110
+ changeDue: 'お釣り'
111
+ },
112
+ pt: {
113
+ cashReceived: 'Dinheiro recebido',
114
+ changeDue: 'Troco'
101
115
  }
102
116
  };
103
117
  export function buildSmallTicketData(params) {
@@ -174,7 +188,7 @@ function buildBaseData(params) {
174
188
  order_number: orderNumber,
175
189
  shop_tax_number: stringify(shopInfo.tax_number || order.shop_tax_number),
176
190
  shop_phone: stringify(shopInfo.phone || order.shop_phone),
177
- shop_address: stringify(shopInfo.address || buildShopAddress(shopInfo) || order.shop_address),
191
+ shop_address: stringify(shopInfo.receipt_address || shopInfo.address || buildShopAddress(shopInfo) || order.shop_address),
178
192
  original_payment_status: stringify(order.payment_status),
179
193
  is_repeat: 0,
180
194
  buzzer: stringify(order.buzzer || order.pickup_number || ((_order$metadata = order.metadata) === null || _order$metadata === void 0 ? void 0 : _order$metadata.buzzer)),
@@ -839,6 +853,11 @@ function buildPaymentItems(params) {
839
853
  item: paymentMethodName(payment, locale),
840
854
  value: formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol)
841
855
  }];
856
+ items.push.apply(items, _toConsumableArray(buildCashChangePaymentItems({
857
+ payment: payment,
858
+ locale: locale,
859
+ currencySymbol: currencySymbol
860
+ })));
842
861
  if (serviceFee.gt(0)) {
843
862
  items.push({
844
863
  item: label(locale, 'surchargeIncluded'),
@@ -882,6 +901,35 @@ function resolveReceiptPaymentAmount(payment, serviceFee) {
882
901
  var originAmount = new Decimal(toMoneyNumber(payment.origin_amount));
883
902
  return amount.eq(originAmount) ? amount.plus(serviceFee) : amount;
884
903
  }
904
+ function buildCashChangePaymentItems(params) {
905
+ var payment = params.payment,
906
+ locale = params.locale,
907
+ currencySymbol = params.currencySymbol;
908
+ if (!shouldDisplayCashChange(payment)) return [];
909
+ return [{
910
+ item: label(locale, 'cashReceived'),
911
+ value: formatMoney(payment.metadata.actual_paid_amount, currencySymbol)
912
+ }, {
913
+ item: label(locale, 'changeDue'),
914
+ value: formatMoney(payment.metadata.change_given_amount, currencySymbol)
915
+ }];
916
+ }
917
+ function shouldDisplayCashChange(payment) {
918
+ var _payment$code, _payment$metadata2, _payment$metadata3;
919
+ if (stringify(payment.status).toLowerCase() !== 'paid') return false;
920
+ var paymentMethod = stringify((_payment$code = payment.code) !== null && _payment$code !== void 0 ? _payment$code : payment.payment_method).toUpperCase();
921
+ if (paymentMethod !== 'CASHMANUAL') return false;
922
+ var actualPaidAmount = (_payment$metadata2 = payment.metadata) === null || _payment$metadata2 === void 0 ? void 0 : _payment$metadata2.actual_paid_amount;
923
+ var changeGivenAmount = (_payment$metadata3 = payment.metadata) === null || _payment$metadata3 === void 0 ? void 0 : _payment$metadata3.change_given_amount;
924
+ if (!isNumericAmount(actualPaidAmount) || !isNumericAmount(changeGivenAmount)) return false;
925
+ return new Decimal(changeGivenAmount).toDecimalPlaces(2).gt(0);
926
+ }
927
+ function isNumericAmount(value) {
928
+ if (typeof value === 'number') return Number.isFinite(value);
929
+ if (typeof value !== 'string') return false;
930
+ var normalized = value.trim();
931
+ return normalized !== '' && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(normalized);
932
+ }
885
933
  function buildFundRecordPaymentItems(params) {
886
934
  var payment = params.payment,
887
935
  fundRecord = params.fundRecord,
@@ -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 | 3 | 4 | 5 | 6;
329
+ weekNum: 0 | 2 | 3 | 1 | 5 | 6 | 4;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -130,8 +130,8 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
130
130
  */
131
131
  clearSessionStorageOrderSnapshot(): void;
132
132
  /**
133
- * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
134
- * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
133
+ * H5/Kiosk 不能把已收款订单留在本地等待重试,必须直接等待云端 checkout。
134
+ * 其它平台保持 WebPOS/POS 的本地待同步任务;显式 true 仍可强制使用本地任务。
135
135
  */
136
136
  protected shouldUseCheckoutSyncTask(): boolean;
137
137
  /** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
@@ -43,7 +43,7 @@ import { UnifiedBookingSalesHooks } from "./types";
43
43
  import { AvailabilityRemoteOccupancyCache } from "./remoteOccupancyCache";
44
44
  import { BookingTicket } from "../BookingTicket";
45
45
  import { addLocalCalendarDays, captureRuntimeOffsetMinutes, formatLocalDate, formatLocalDateTime, formatLocalTime, localDateTimeToScalar, localDateToScalar, localDateToScalarStart, parseLocalDate, parseLocalDateTime } from "../../modules/ResourcePlanner/localClock";
46
- import { isCustomerUserPlatform } from "../../utils/platform";
46
+ import { isCustomerUserPlatform, normalizeRuntimePlatform } from "../../utils/platform";
47
47
  import { ItemRuleEvaluator } from "../../model/strategy/adapter/itemRule";
48
48
  export * from "./types";
49
49
  export { AvailabilityError } from "../../modules/ResourcePlanner";
@@ -1053,7 +1053,7 @@ function buildBookingFromAvailabilitySelection(params) {
1053
1053
  var timeSlotId = (_candidate$primarySch3 = (_candidate$primarySch4 = candidate.primaryScheduleRef) === null || _candidate$primarySch4 === void 0 ? void 0 : _candidate$primarySch4.timeSlotId) !== null && _candidate$primarySch3 !== void 0 ? _candidate$primarySch3 : (_assignments$find2 = assignments.find(function (assignment) {
1054
1054
  return assignment.timeSlotId != null;
1055
1055
  })) === null || _assignments$find2 === void 0 ? void 0 : _assignments$find2.timeSlotId;
1056
- if (product.kind === 'session' && scheduleId == null) {
1056
+ if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
1057
1057
  throw new AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
1058
1058
  productId: product.id,
1059
1059
  candidateKey: candidate.key,
@@ -1062,15 +1062,16 @@ function buildBookingFromAvailabilitySelection(params) {
1062
1062
  }
1063
1063
  var normalizedHolder = holder && _typeof(holder) === 'object' ? cloneDeep(holder) : undefined;
1064
1064
  var normalizedHolderIds = Array.isArray(holderIds) ? cloneDeep(holderIds) : holderIds;
1065
- return _objectSpread(_objectSpread({
1065
+ return _objectSpread(_objectSpread(_objectSpread({
1066
1066
  start_date: bookingStartAt.slice(0, 10),
1067
1067
  start_time: bookingStartAt.slice(11, 16),
1068
1068
  end_date: bookingEndAt.slice(0, 10),
1069
1069
  end_time: bookingEndAt.slice(11, 16),
1070
1070
  duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
1071
- like_status: 'common',
1071
+ like_status: 'common'
1072
+ }, product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
1072
1073
  schedule_id: scheduleId !== null && scheduleId !== void 0 ? scheduleId : 0
1073
- }, normalizedHolder ? {
1074
+ }), normalizedHolder ? {
1074
1075
  holder: normalizedHolder
1075
1076
  } : {}), {}, {
1076
1077
  resources: assignments.map(function (assignment) {
@@ -1867,15 +1868,17 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
1867
1868
  }
1868
1869
 
1869
1870
  /**
1870
- * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
1871
- * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
1871
+ * H5/Kiosk 不能把已收款订单留在本地等待重试,必须直接等待云端 checkout。
1872
+ * 其它平台保持 WebPOS/POS 的本地待同步任务;显式 true 仍可强制使用本地任务。
1872
1873
  */
1873
1874
  }, {
1874
1875
  key: "shouldUseCheckoutSyncTask",
1875
1876
  value: function shouldUseCheckoutSyncTask() {
1876
- var _this$otherParams15;
1877
+ var _this$otherParams15, _this$otherParams16;
1877
1878
  var configured = (_this$otherParams15 = this.otherParams) === null || _this$otherParams15 === void 0 ? void 0 : _this$otherParams15.checkoutSyncTaskEnabled;
1878
- return typeof configured === 'boolean' ? configured : false;
1879
+ if (configured === true) return true;
1880
+ var platform = normalizeRuntimePlatform((_this$otherParams16 = this.otherParams) === null || _this$otherParams16 === void 0 ? void 0 : _this$otherParams16.platform);
1881
+ return platform !== 'h5' && platform !== 'kiosk';
1879
1882
  }
1880
1883
 
1881
1884
  /** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
@@ -2029,8 +2032,8 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2029
2032
  }, {
2030
2033
  key: "isAuthenticatedCustomerUserPlatform",
2031
2034
  value: function isAuthenticatedCustomerUserPlatform() {
2032
- var _this$otherParams16;
2033
- return isCustomerUserPlatform((_this$otherParams16 = this.otherParams) === null || _this$otherParams16 === void 0 ? void 0 : _this$otherParams16.platform);
2035
+ var _this$otherParams17;
2036
+ return isCustomerUserPlatform((_this$otherParams17 = this.otherParams) === null || _this$otherParams17 === void 0 ? void 0 : _this$otherParams17.platform);
2034
2037
  }
2035
2038
  }, {
2036
2039
  key: "resolveDiscountOrderIdentity",
@@ -2208,13 +2211,13 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2208
2211
  key: "getOpenData",
2209
2212
  value: function () {
2210
2213
  var _getOpenData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee12() {
2211
- var _this$otherParams17, _this$otherParams18, _this$store$openData;
2214
+ var _this$otherParams18, _this$otherParams19, _this$store$openData;
2212
2215
  var businessCode, channel, target, cachedData;
2213
2216
  return _regeneratorRuntime().wrap(function _callee12$(_context12) {
2214
2217
  while (1) switch (_context12.prev = _context12.next) {
2215
2218
  case 0:
2216
- businessCode = String(((_this$otherParams17 = this.otherParams) === null || _this$otherParams17 === void 0 ? void 0 : _this$otherParams17.businessCode) || '').trim();
2217
- channel = String(((_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.channel) || '').trim();
2219
+ businessCode = String(((_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.businessCode) || '').trim();
2220
+ channel = String(((_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.channel) || '').trim();
2218
2221
  if (!(!businessCode || !channel)) {
2219
2222
  _context12.next = 4;
2220
2223
  break;
@@ -2381,7 +2384,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2381
2384
  key: "resolveProductAllergyRequirement",
2382
2385
  value: (function () {
2383
2386
  var _resolveProductAllergyRequirement = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16(params) {
2384
- var _this$otherParams19, _this$getOrderProduct, _runtimePax$total, _runtimePax$adult, _runtimePax$child, _ref35, _runtimeConfig$servic, _this$otherParams20, _ref36, _ref37, _params$channel, _this$otherParams21, _this$otherParams22, _runtimeConfig$submis;
2387
+ var _this$otherParams20, _this$getOrderProduct, _runtimePax$total, _runtimePax$adult, _runtimePax$child, _ref35, _runtimeConfig$servic, _this$otherParams21, _ref36, _ref37, _params$channel, _this$otherParams22, _this$otherParams23, _runtimeConfig$submis;
2385
2388
  var productId, strategyConfigs, productVariantId, runtimeConfig, runtimePax, cartItems;
2386
2389
  return _regeneratorRuntime().wrap(function _callee16$(_context16) {
2387
2390
  while (1) switch (_context16.prev = _context16.next) {
@@ -2404,7 +2407,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2404
2407
  return _context16.abrupt("return", null);
2405
2408
  case 8:
2406
2409
  productVariantId = normalizePositiveInteger(params.productVariantId);
2407
- runtimeConfig = ((_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.itemRule) || {};
2410
+ runtimeConfig = ((_this$otherParams20 = this.otherParams) === null || _this$otherParams20 === void 0 ? void 0 : _this$otherParams20.itemRule) || {};
2408
2411
  runtimePax = runtimeConfig.pax || {};
2409
2412
  cartItems = (((_this$getOrderProduct = this.getOrderProducts) === null || _this$getOrderProduct === void 0 ? void 0 : _this$getOrderProduct.call(this)) || []).map(function (item) {
2410
2413
  var _item$product_id, _item$product_variant, _ref34, _item$num;
@@ -2423,8 +2426,8 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2423
2426
  child: Number((_runtimePax$child = runtimePax.child) !== null && _runtimePax$child !== void 0 ? _runtimePax$child : 0) || 0
2424
2427
  },
2425
2428
  cartItems: cartItems,
2426
- serviceType: String((_ref35 = (_runtimeConfig$servic = runtimeConfig.serviceType) !== null && _runtimeConfig$servic !== void 0 ? _runtimeConfig$servic : (_this$otherParams20 = this.otherParams) === null || _this$otherParams20 === void 0 ? void 0 : _this$otherParams20.serviceType) !== null && _ref35 !== void 0 ? _ref35 : ''),
2427
- channel: String((_ref36 = (_ref37 = (_params$channel = params.channel) !== null && _params$channel !== void 0 ? _params$channel : (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.channel) !== null && _ref37 !== void 0 ? _ref37 : (_this$otherParams22 = this.otherParams) === null || _this$otherParams22 === void 0 ? void 0 : _this$otherParams22.platform) !== null && _ref36 !== void 0 ? _ref36 : ''),
2429
+ serviceType: String((_ref35 = (_runtimeConfig$servic = runtimeConfig.serviceType) !== null && _runtimeConfig$servic !== void 0 ? _runtimeConfig$servic : (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.serviceType) !== null && _ref35 !== void 0 ? _ref35 : ''),
2430
+ channel: String((_ref36 = (_ref37 = (_params$channel = params.channel) !== null && _params$channel !== void 0 ? _params$channel : (_this$otherParams22 = this.otherParams) === null || _this$otherParams22 === void 0 ? void 0 : _this$otherParams22.channel) !== null && _ref37 !== void 0 ? _ref37 : (_this$otherParams23 = this.otherParams) === null || _this$otherParams23 === void 0 ? void 0 : _this$otherParams23.platform) !== null && _ref36 !== void 0 ? _ref36 : ''),
2428
2431
  currentProduct: _objectSpread({
2429
2432
  product_id: productId
2430
2433
  }, productVariantId ? {
@@ -4466,13 +4469,14 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4466
4469
  value: (function () {
4467
4470
  var _getProductTimeRanges = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee40(contextId) {
4468
4471
  var _this$otherParams$pla,
4469
- _this$otherParams23,
4472
+ _this$otherParams24,
4470
4473
  _this10 = this;
4471
4474
  var request,
4472
4475
  _yield$this$ensureAva,
4473
4476
  context,
4474
4477
  projectionEntry,
4475
4478
  contextVersion,
4479
+ isPosAvailabilityRequest,
4476
4480
  allowOutsideOperatingHoursForRequestedStartTimes,
4477
4481
  _args40 = arguments;
4478
4482
  return _regeneratorRuntime().wrap(function _callee40$(_context40) {
@@ -4486,13 +4490,15 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4486
4490
  context = _yield$this$ensureAva.context;
4487
4491
  projectionEntry = _yield$this$ensureAva.projectionEntry;
4488
4492
  contextVersion = context.activeVersion;
4489
- allowOutsideOperatingHoursForRequestedStartTimes = String((_this$otherParams$pla = (_this$otherParams23 = this.otherParams) === null || _this$otherParams23 === void 0 ? void 0 : _this$otherParams23.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase() === 'pos' && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
4493
+ isPosAvailabilityRequest = String((_this$otherParams$pla = (_this$otherParams24 = this.otherParams) === null || _this$otherParams24 === void 0 ? void 0 : _this$otherParams24.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase() === 'pos';
4494
+ allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
4490
4495
  return Array.isArray(startTimes) && startTimes.length > 0;
4491
4496
  });
4492
4497
  return _context40.abrupt("return", getProjectionProductTimeRanges(projectionEntry.projection, _objectSpread(_objectSpread({}, request), allowOutsideOperatingHoursForRequestedStartTimes ? {
4493
4498
  allowOutsideOperatingHoursForRequestedStartTimes: true
4494
4499
  } : {}), {
4495
- evaluatedAt: this.getAvailabilityRuntimeDateTime()
4500
+ evaluatedAt: this.getAvailabilityRuntimeDateTime(),
4501
+ allowSessionCustomRanges: isPosAvailabilityRequest
4496
4502
  }).map(function (group) {
4497
4503
  return _objectSpread(_objectSpread({}, group), {}, {
4498
4504
  ranges: group.ranges.map(function (candidate) {
@@ -4500,7 +4506,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4500
4506
  })
4501
4507
  });
4502
4508
  }));
4503
- case 9:
4509
+ case 10:
4504
4510
  case "end":
4505
4511
  return _context40.stop();
4506
4512
  }
@@ -4636,7 +4642,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4636
4642
  key: "commitAvailabilitySelection",
4637
4643
  value: (function () {
4638
4644
  var _commitAvailabilitySelection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee42(contextId, params) {
4639
- var normalizedContextId, _params$bookingCount, _ref51, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$pla2, _this$otherParams24, _ref52, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref53, _ref54, _params$orderProduct$4, _params$orderProduct7, _params$orderProduct8, _existingBooking$meta2, _existingBooking$hold, bookingCount, orderProductQuantity, partySize, _yield$this$ensureAva3, context, projectionEntry, refreshed, boundEditingUids, orderProductId, editingLine, _editingLine$product_2, baseProjection, commitWriteGuard, prepareParams, fallbackResources, commitSnapshot, refreshedProjection, _baseProjection$meta$3, latestContext, candidateDurationMinutes, candidateStartTime, allowPosAvailabilityOverride, refreshedRanges, refreshedCandidateBase, product, validation, forced, capacityConflict, revalidationEntry, revalidatedContext, refreshedCandidate, existingBooking, existingBookingUid, booking, transformed, productLineUid, bookingUid, productLineUids, bookingUids, _transformed$product_, _transformed$product_2, _transformed$product_3, _ref55, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _params$salesNotes, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
4645
+ var normalizedContextId, _params$bookingCount, _ref51, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$pla2, _this$otherParams25, _ref52, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref53, _ref54, _params$orderProduct$4, _params$orderProduct7, _params$orderProduct8, _existingBooking$meta2, _existingBooking$hold, bookingCount, orderProductQuantity, partySize, _yield$this$ensureAva3, context, projectionEntry, refreshed, boundEditingUids, orderProductId, editingLine, _editingLine$product_2, baseProjection, commitWriteGuard, prepareParams, fallbackResources, commitSnapshot, refreshedProjection, _baseProjection$meta$3, latestContext, candidateDurationMinutes, candidateStartTime, allowPosAvailabilityOverride, refreshedRanges, refreshedCandidateBase, product, validation, forced, capacityConflict, revalidationEntry, revalidatedContext, refreshedCandidate, existingBooking, existingBookingUid, booking, transformed, productLineUid, bookingUid, productLineUids, bookingUids, _transformed$product_, _transformed$product_2, _transformed$product_3, _ref55, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _params$salesNotes, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
4640
4646
  return _regeneratorRuntime().wrap(function _callee42$(_context42) {
4641
4647
  while (1) switch (_context42.prev = _context42.next) {
4642
4648
  case 0:
@@ -4866,7 +4872,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4866
4872
  this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
4867
4873
  candidateDurationMinutes = getCandidateDurationMinutes(params.candidate);
4868
4874
  candidateStartTime = getCandidateStartTime(params.candidate);
4869
- allowPosAvailabilityOverride = String((_this$otherParams$pla2 = (_this$otherParams24 = this.otherParams) === null || _this$otherParams24 === void 0 ? void 0 : _this$otherParams24.platform) !== null && _this$otherParams$pla2 !== void 0 ? _this$otherParams$pla2 : '').trim().toLowerCase() === 'pos';
4875
+ allowPosAvailabilityOverride = String((_this$otherParams$pla2 = (_this$otherParams25 = this.otherParams) === null || _this$otherParams25 === void 0 ? void 0 : _this$otherParams25.platform) !== null && _this$otherParams$pla2 !== void 0 ? _this$otherParams$pla2 : '').trim().toLowerCase() === 'pos';
4870
4876
  refreshedRanges = getProjectionProductTimeRanges(refreshedProjection, _objectSpread({
4871
4877
  productIds: [params.candidate.productId],
4872
4878
  dateRange: {
@@ -4879,7 +4885,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4879
4885
  durationStartTimesByProductId: _defineProperty({}, String(params.candidate.productId), [candidateStartTime])
4880
4886
  }, allowPosAvailabilityOverride ? {
4881
4887
  allowOutsideOperatingHoursForRequestedStartTimes: true
4882
- } : {}) : {}) : {})).flatMap(function (group) {
4888
+ } : {}) : {}) : {}), {
4889
+ allowSessionCustomRanges: allowPosAvailabilityOverride
4890
+ }).flatMap(function (group) {
4883
4891
  return group.ranges;
4884
4892
  });
4885
4893
  refreshedCandidateBase = refreshedRanges.find(function (candidate) {
@@ -650,17 +650,20 @@ class WalletPassPaymentImpl {
650
650
  this.paymentModule.logInfo('[WalletPass] 商品列表为空,跳过获取用户识别码列表');
651
651
  return [];
652
652
  }
653
- const platform = this.paymentModule.getPlatform();
654
- if (platform === 'pc' || platform === 'h5') {
655
- this.userIdentificationCodes = [];
656
- this.emitEvent(_types.WalletPassHooks.OnUserIdentificationCodesUpdated, {
657
- userIdentificationCodes: []
658
- });
659
- this.paymentModule.logInfo('[WalletPass] 用户端平台跳过获取用户识别码列表', {
660
- platform
661
- });
662
- return [];
663
- }
653
+
654
+ // const platform = this.paymentModule.getPlatform();
655
+ // if (platform === 'pc' || platform === 'h5') {
656
+ // this.userIdentificationCodes = [];
657
+ // this.emitEvent(WalletPassHooks.OnUserIdentificationCodesUpdated, {
658
+ // userIdentificationCodes: [],
659
+ // } as OnUserIdentificationCodesUpdatedEventData);
660
+ // this.paymentModule.logInfo(
661
+ // '[WalletPass] 用户端平台跳过获取用户识别码列表',
662
+ // { platform },
663
+ // );
664
+ // return [];
665
+ // }
666
+
664
667
  if (typeof newParams.payment_order_id === 'string' && newParams.payment_order_id.startsWith('LOCAL_')) {
665
668
  newParams.payment_order_id = undefined;
666
669
  }
@@ -55,12 +55,18 @@ function resolveRequestedDurationMinutes(product, request) {
55
55
  const normalized = Number(override);
56
56
  return Number.isInteger(normalized) && normalized > 0 ? normalized : configured;
57
57
  }
58
- function resolveRequestedDurationStartTimes(product, request) {
59
- if (product.kind !== 'duration') return [];
58
+ function resolveRequestedDurationStartTimes(product, request, allowSessionCustomRanges = false) {
59
+ if (product.kind !== 'duration' && !(product.kind === 'session' && allowSessionCustomRanges)) return [];
60
60
  const values = request.durationStartTimesByProductId?.[String(product.id)];
61
61
  if (!Array.isArray(values)) return [];
62
62
  return Array.from(new Set(values.filter(value => typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value))));
63
63
  }
64
+ function resolveRequestedSessionDurationMinutes(product, request, allowSessionCustomRanges) {
65
+ if (product.kind !== 'session' || !allowSessionCustomRanges) return undefined;
66
+ const override = request.durationMinutesByProductId?.[String(product.id)];
67
+ const normalized = Number(override);
68
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : undefined;
69
+ }
64
70
  function toDateTime(value, _timezoneName) {
65
71
  try {
66
72
  return (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(value));
@@ -207,7 +213,11 @@ function evaluateCandidateTimeGate(params) {
207
213
  };
208
214
  }
209
215
  if (policy.type === 'before_start') {
210
- if (now < candidateRange.start) return null;
216
+ // Flexible-duration candidates start at minute precision. Keep the current
217
+ // minute selectable instead of treating the freshly generated candidate as
218
+ // already started because the query clock still contains seconds.
219
+ const hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
220
+ if (hasNotReachedStart) return null;
211
221
  return {
212
222
  status: 'unavailable',
213
223
  reasonCodes: ['booking_cutoff_before_start'],
@@ -919,12 +929,23 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
919
929
  };
920
930
  }
921
931
  if (product.kind === 'session' || product.kind === 'venue_slot') {
932
+ const fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
933
+ const customRanges = [];
934
+ const customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
935
+ const requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
936
+ if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
937
+ requestedStartTimes.forEach(startTime => {
938
+ const start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
939
+ if (!Number.isFinite(start)) return;
940
+ customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
941
+ });
942
+ }
922
943
  return {
923
944
  productId: product.id,
924
945
  title: product.title,
925
946
  kind: product.kind,
926
947
  slotStepMinutes,
927
- ranges: getSessionRangesForProduct(projection, product, dateRange)
948
+ ranges: dedupeProductRanges([...fixedRanges, ...customRanges])
928
949
  };
929
950
  }
930
951
  const requiredGroups = (product.requirementGroups || []).filter(group => group.required !== false);
@@ -243,6 +243,13 @@ export interface GetProductTimeRangesRequest {
243
243
  }
244
244
  export interface GetProductTimeRangesRuntimeOptions {
245
245
  evaluatedAt?: string;
246
+ /**
247
+ * Internal POS capability: allow explicit duration/start overrides to append
248
+ * a custom duration candidate for Session products. Fixed Session ranges are
249
+ * still returned unchanged. Callers outside the POS facade must leave this
250
+ * disabled.
251
+ */
252
+ allowSessionCustomRanges?: boolean;
246
253
  }
247
254
  export interface QueryAvailabilityBaseRequest {
248
255
  productIds?: AvailabilityId[];
@@ -22,6 +22,8 @@ const LABELS = {
22
22
  pickUpTime: 'Pick-up time',
23
23
  asap: 'ASAP',
24
24
  cash: 'Cash',
25
+ cashReceived: 'Cash received',
26
+ changeDue: 'Change due',
25
27
  eftpos: 'Eftpos',
26
28
  wallet: 'Wallet',
27
29
  giftCard: 'Gift card',
@@ -49,6 +51,8 @@ const LABELS = {
49
51
  pickUpTime: '取餐时间',
50
52
  asap: '尽快',
51
53
  cash: '现金支付',
54
+ cashReceived: '收取现金',
55
+ changeDue: '找零',
52
56
  eftpos: '刷卡支付',
53
57
  wallet: '钱包支付',
54
58
  giftCard: '礼品卡',
@@ -76,6 +80,8 @@ const LABELS = {
76
80
  pickUpTime: '取餐時間',
77
81
  asap: '盡快',
78
82
  cash: '現金支付',
83
+ cashReceived: '收取現金',
84
+ changeDue: '找零',
79
85
  eftpos: '刷卡支付',
80
86
  wallet: '錢包支付',
81
87
  giftCard: '禮品卡',
@@ -90,6 +96,14 @@ const LABELS = {
90
96
  rounding: '抹零',
91
97
  gross: '重量',
92
98
  tare: '去皮'
99
+ },
100
+ ja: {
101
+ cashReceived: 'お預かり',
102
+ changeDue: 'お釣り'
103
+ },
104
+ pt: {
105
+ cashReceived: 'Dinheiro recebido',
106
+ changeDue: 'Troco'
93
107
  }
94
108
  };
95
109
  function buildSmallTicketData(params) {
@@ -169,7 +183,7 @@ function buildBaseData(params) {
169
183
  order_number: orderNumber,
170
184
  shop_tax_number: stringify(shopInfo.tax_number || order.shop_tax_number),
171
185
  shop_phone: stringify(shopInfo.phone || order.shop_phone),
172
- shop_address: stringify(shopInfo.address || buildShopAddress(shopInfo) || order.shop_address),
186
+ shop_address: stringify(shopInfo.receipt_address || shopInfo.address || buildShopAddress(shopInfo) || order.shop_address),
173
187
  original_payment_status: stringify(order.payment_status),
174
188
  is_repeat: 0,
175
189
  buzzer: stringify(order.buzzer || order.pickup_number || order.metadata?.buzzer),
@@ -807,6 +821,11 @@ function buildPaymentItems(params) {
807
821
  item: paymentMethodName(payment, locale),
808
822
  value: formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol)
809
823
  }];
824
+ items.push(...buildCashChangePaymentItems({
825
+ payment,
826
+ locale,
827
+ currencySymbol
828
+ }));
810
829
  if (serviceFee.gt(0)) {
811
830
  items.push({
812
831
  item: label(locale, 'surchargeIncluded'),
@@ -848,6 +867,36 @@ function resolveReceiptPaymentAmount(payment, serviceFee) {
848
867
  const originAmount = new _decimal.default(toMoneyNumber(payment.origin_amount));
849
868
  return amount.eq(originAmount) ? amount.plus(serviceFee) : amount;
850
869
  }
870
+ function buildCashChangePaymentItems(params) {
871
+ const {
872
+ payment,
873
+ locale,
874
+ currencySymbol
875
+ } = params;
876
+ if (!shouldDisplayCashChange(payment)) return [];
877
+ return [{
878
+ item: label(locale, 'cashReceived'),
879
+ value: formatMoney(payment.metadata.actual_paid_amount, currencySymbol)
880
+ }, {
881
+ item: label(locale, 'changeDue'),
882
+ value: formatMoney(payment.metadata.change_given_amount, currencySymbol)
883
+ }];
884
+ }
885
+ function shouldDisplayCashChange(payment) {
886
+ if (stringify(payment.status).toLowerCase() !== 'paid') return false;
887
+ const paymentMethod = stringify(payment.code ?? payment.payment_method).toUpperCase();
888
+ if (paymentMethod !== 'CASHMANUAL') return false;
889
+ const actualPaidAmount = payment.metadata?.actual_paid_amount;
890
+ const changeGivenAmount = payment.metadata?.change_given_amount;
891
+ if (!isNumericAmount(actualPaidAmount) || !isNumericAmount(changeGivenAmount)) return false;
892
+ return new _decimal.default(changeGivenAmount).toDecimalPlaces(2).gt(0);
893
+ }
894
+ function isNumericAmount(value) {
895
+ if (typeof value === 'number') return Number.isFinite(value);
896
+ if (typeof value !== 'string') return false;
897
+ const normalized = value.trim();
898
+ return normalized !== '' && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(normalized);
899
+ }
851
900
  function buildFundRecordPaymentItems(params) {
852
901
  const {
853
902
  payment,
@@ -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 | 3 | 4 | 5 | 6;
329
+ weekNum: 0 | 2 | 3 | 1 | 5 | 6 | 4;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -130,8 +130,8 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
130
130
  */
131
131
  clearSessionStorageOrderSnapshot(): void;
132
132
  /**
133
- * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
134
- * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
133
+ * H5/Kiosk 不能把已收款订单留在本地等待重试,必须直接等待云端 checkout。
134
+ * 其它平台保持 WebPOS/POS 的本地待同步任务;显式 true 仍可强制使用本地任务。
135
135
  */
136
136
  protected shouldUseCheckoutSyncTask(): boolean;
137
137
  /** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
@@ -962,7 +962,7 @@ function buildBookingFromAvailabilitySelection(params) {
962
962
  const endScalar = (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(bookingEndAt));
963
963
  const scheduleId = candidate.primaryScheduleRef?.scheduleId ?? assignments.find(assignment => assignment.scheduleId != null)?.scheduleId;
964
964
  const timeSlotId = candidate.primaryScheduleRef?.timeSlotId ?? assignments.find(assignment => assignment.timeSlotId != null)?.timeSlotId;
965
- if (product.kind === 'session' && scheduleId == null) {
965
+ if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
966
966
  throw new _ResourcePlanner.AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
967
967
  productId: product.id,
968
968
  candidateKey: candidate.key,
@@ -978,7 +978,9 @@ function buildBookingFromAvailabilitySelection(params) {
978
978
  end_time: bookingEndAt.slice(11, 16),
979
979
  duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
980
980
  like_status: 'common',
981
- schedule_id: scheduleId ?? 0,
981
+ ...(product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
982
+ schedule_id: scheduleId ?? 0
983
+ }),
982
984
  ...(normalizedHolder ? {
983
985
  holder: normalizedHolder
984
986
  } : {}),
@@ -1548,12 +1550,14 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
1548
1550
  }
1549
1551
 
1550
1552
  /**
1551
- * Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
1552
- * 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
1553
+ * H5/Kiosk 不能把已收款订单留在本地等待重试,必须直接等待云端 checkout。
1554
+ * 其它平台保持 WebPOS/POS 的本地待同步任务;显式 true 仍可强制使用本地任务。
1553
1555
  */
1554
1556
  shouldUseCheckoutSyncTask() {
1555
1557
  const configured = this.otherParams?.checkoutSyncTaskEnabled;
1556
- return typeof configured === 'boolean' ? configured : false;
1558
+ if (configured === true) return true;
1559
+ const platform = (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform);
1560
+ return platform !== 'h5' && platform !== 'kiosk';
1557
1561
  }
1558
1562
 
1559
1563
  /** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
@@ -2929,14 +2933,16 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2929
2933
  projectionEntry
2930
2934
  } = await this.ensureAvailabilityContextProjection(contextId, 'get_product_time_ranges');
2931
2935
  const contextVersion = context.activeVersion;
2932
- const allowOutsideOperatingHoursForRequestedStartTimes = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos' && Object.values(request.durationStartTimesByProductId || {}).some(startTimes => Array.isArray(startTimes) && startTimes.length > 0);
2936
+ const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
2937
+ const allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(startTimes => Array.isArray(startTimes) && startTimes.length > 0);
2933
2938
  return (0, _ResourcePlanner.getProductTimeRanges)(projectionEntry.projection, {
2934
2939
  ...request,
2935
2940
  ...(allowOutsideOperatingHoursForRequestedStartTimes ? {
2936
2941
  allowOutsideOperatingHoursForRequestedStartTimes: true
2937
2942
  } : {})
2938
2943
  }, {
2939
- evaluatedAt: this.getAvailabilityRuntimeDateTime()
2944
+ evaluatedAt: this.getAvailabilityRuntimeDateTime(),
2945
+ allowSessionCustomRanges: isPosAvailabilityRequest
2940
2946
  }).map(group => ({
2941
2947
  ...group,
2942
2948
  ranges: group.ranges.map(candidate => this.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate))
@@ -3207,6 +3213,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3207
3213
  } : {})
3208
3214
  } : {})
3209
3215
  } : {})
3216
+ }, {
3217
+ allowSessionCustomRanges: allowPosAvailabilityOverride
3210
3218
  }).flatMap(group => group.ranges);
3211
3219
  const refreshedCandidateBase = refreshedRanges.find(candidate => candidate.startAt === params.candidate.startAt && candidate.endAt === params.candidate.endAt && candidate.bookingStartAt === params.candidate.bookingStartAt && candidate.bookingEndAt === params.candidate.bookingEndAt);
3212
3220
  if (!refreshedCandidateBase) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.104",
4
+ "version": "2.3.105",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",