@pisell/pisellos 0.10.41 → 0.10.42

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 (50) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +58 -19
  3. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +24 -12
  4. package/dist/modules/Discount/entitlementPass.d.ts +34 -0
  5. package/dist/modules/Discount/entitlementPass.js +147 -0
  6. package/dist/modules/Discount/index.d.ts +2 -0
  7. package/dist/modules/Discount/index.js +39 -13
  8. package/dist/modules/Discount/types.d.ts +26 -5
  9. package/dist/modules/Order/index.d.ts +6 -1
  10. package/dist/modules/Order/index.js +283 -118
  11. package/dist/modules/Order/utils/orderCollectionIdentity.js +16 -12
  12. package/dist/modules/Order/utils.js +17 -1
  13. package/dist/modules/ResourcePlanner/planner.d.ts +2 -2
  14. package/dist/modules/ResourcePlanner/planner.js +163 -46
  15. package/dist/modules/ResourcePlanner/types.d.ts +17 -0
  16. package/dist/modules/Rules/index.js +310 -134
  17. package/dist/solution/BaseSales/index.d.ts +2 -0
  18. package/dist/solution/BaseSales/index.js +9 -1
  19. package/dist/solution/BaseSales/utils/cartPromotion.js +141 -126
  20. package/dist/solution/BookingByStep/index.d.ts +1 -1
  21. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +2 -0
  22. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  23. package/dist/solution/ShopDiscount/index.js +41 -21
  24. package/dist/solution/ShopDiscount/utils.js +3 -2
  25. package/dist/solution/UnifiedBookingSales/index.js +94 -21
  26. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +35 -6
  27. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +13 -6
  28. package/lib/modules/Discount/entitlementPass.d.ts +34 -0
  29. package/lib/modules/Discount/entitlementPass.js +141 -0
  30. package/lib/modules/Discount/index.d.ts +2 -0
  31. package/lib/modules/Discount/index.js +25 -9
  32. package/lib/modules/Discount/types.d.ts +26 -5
  33. package/lib/modules/Order/index.d.ts +6 -1
  34. package/lib/modules/Order/index.js +172 -28
  35. package/lib/modules/Order/utils/orderCollectionIdentity.js +14 -11
  36. package/lib/modules/Order/utils.js +19 -1
  37. package/lib/modules/ResourcePlanner/planner.d.ts +2 -2
  38. package/lib/modules/ResourcePlanner/planner.js +137 -35
  39. package/lib/modules/ResourcePlanner/types.d.ts +17 -0
  40. package/lib/modules/Rules/index.js +230 -96
  41. package/lib/solution/BaseSales/index.d.ts +2 -0
  42. package/lib/solution/BaseSales/index.js +7 -1
  43. package/lib/solution/BaseSales/utils/cartPromotion.js +12 -4
  44. package/lib/solution/BookingByStep/index.d.ts +1 -1
  45. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +2 -0
  46. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  47. package/lib/solution/ShopDiscount/index.js +26 -6
  48. package/lib/solution/ShopDiscount/utils.js +3 -2
  49. package/lib/solution/UnifiedBookingSales/index.js +86 -22
  50. package/package.json +1 -1
@@ -27,6 +27,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
27
27
  import { BaseModule } from "../../modules/BaseModule";
28
28
  import { DiscountModule } from "../../modules/Discount";
29
29
  import { RulesModule } from "../../modules/Rules";
30
+ import { isEntitlementPass } from "../../modules/Discount/entitlementPass";
30
31
  import { filterDiscountListByBookingTime as _filterDiscountListByBookingTime, isAllNormalProduct } from "./utils";
31
32
  import { UnavailableReason } from "../../modules/Rules/types";
32
33
  import Decimal from 'decimal.js';
@@ -203,7 +204,8 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
203
204
  customerId: customer.id,
204
205
  action: 'create',
205
206
  with_good_pass: 1,
206
- with_discount_card: 1
207
+ with_discount_card: 1,
208
+ with_entitlement_pass: 1
207
209
  });
208
210
  });
209
211
  }
@@ -622,7 +624,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
622
624
  var _this3$hooks;
623
625
  var product = (_this3$hooks = _this3.hooks) === null || _this3$hooks === void 0 ? void 0 : _this3$hooks.getProduct(item);
624
626
  (item.discount_list || []).forEach(function (discount) {
625
- if (discount.id && ['good_pass', 'discount_card'].includes(discount.type)) {
627
+ if (discount.id && ['entitlement_pass', 'good_pass', 'discount_card'].includes(discount.type)) {
626
628
  var index = editModeDiscountList.findIndex(function (n) {
627
629
  var _discount$discount;
628
630
  return n.id === (((_discount$discount = discount.discount) === null || _discount$discount === void 0 ? void 0 : _discount$discount.resource_id) || discount.id);
@@ -789,7 +791,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
789
791
  key: "loadPrepareConfig",
790
792
  value: function () {
791
793
  var _loadPrepareConfig = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(params) {
792
- var _this$getCustomer2, _this$store$discount8, _this$getDiscountList, _this$store$discount9, _this$store$productLi2, orderId, customerId, prepareConfigResult, goodPassList, scanDiscount, scanDiscountIds, newGoodPassList, newDiscountList, filteredDiscountList, _result3;
794
+ var _this$getCustomer2, _this$store$discount8, _this$getDiscountList, _this$store$discount9, _this$store$productLi2, orderId, customerId, prepareConfigResult, goodPassList, scanDiscount, scanDiscountById, refreshedScanEntitlementIds, newGoodPassList, retainedScanDiscounts, newDiscountList, filteredDiscountList, _result3;
793
795
  return _regeneratorRuntime().wrap(function _callee10$(_context10) {
794
796
  while (1) switch (_context10.prev = _context10.next) {
795
797
  case 0:
@@ -805,6 +807,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
805
807
  with_good_pass: 1,
806
808
  with_discount_card: 1,
807
809
  with_wallet_pass_holder: 1,
810
+ with_entitlement_pass: 1,
808
811
  request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
809
812
  }, orderId ? {
810
813
  order_id: orderId
@@ -814,44 +817,61 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
814
817
  goodPassList = (prepareConfigResult === null || prepareConfigResult === void 0 ? void 0 : prepareConfigResult.discountList) || [];
815
818
  scanDiscount = (_this$getDiscountList = this.getDiscountList()) === null || _this$getDiscountList === void 0 ? void 0 : _this$getDiscountList.filter(function (item) {
816
819
  return item.isScan;
817
- }); // goodPassList 里可能有 scanDiscount 重合的部分,goodPassList 需要剔除
818
- scanDiscountIds = scanDiscount.map(function (n) {
819
- return n.id;
820
+ }); // 扫码 Entitlement Pass 与客户列表重复时保留扫码选择状态,但刷新实时余额。
821
+ // 其他券继续沿用原来的“保留扫码结果、剔除列表重复项”行为。
822
+ scanDiscountById = new Map(scanDiscount.map(function (discount) {
823
+ return [String(discount.id), discount];
824
+ }));
825
+ refreshedScanEntitlementIds = new Set();
826
+ newGoodPassList = goodPassList.flatMap(function (discount) {
827
+ var key = String(discount.id);
828
+ var scannedDiscount = scanDiscountById.get(key);
829
+ if (!scannedDiscount) return [discount];
830
+ if (isEntitlementPass(scannedDiscount) && isEntitlementPass(discount)) {
831
+ var _scannedDiscount$isSe, _scannedDiscount$isMa;
832
+ refreshedScanEntitlementIds.add(key);
833
+ return [_objectSpread(_objectSpread({}, discount), {}, {
834
+ isScan: true,
835
+ isSelected: (_scannedDiscount$isSe = scannedDiscount.isSelected) !== null && _scannedDiscount$isSe !== void 0 ? _scannedDiscount$isSe : discount.isSelected,
836
+ isManualSelect: (_scannedDiscount$isMa = scannedDiscount.isManualSelect) !== null && _scannedDiscount$isMa !== void 0 ? _scannedDiscount$isMa : discount.isManualSelect
837
+ })];
838
+ }
839
+ return [];
820
840
  });
821
- newGoodPassList = goodPassList === null || goodPassList === void 0 ? void 0 : goodPassList.filter(function (n) {
822
- return !scanDiscountIds.includes(n.id);
841
+ retainedScanDiscounts = scanDiscount.filter(function (discount) {
842
+ return !refreshedScanEntitlementIds.has(String(discount.id));
823
843
  });
824
- newDiscountList = [].concat(_toConsumableArray(scanDiscount), _toConsumableArray(newGoodPassList || [])); // 存储原始优惠券列表
844
+ newDiscountList = [].concat(_toConsumableArray(retainedScanDiscounts), _toConsumableArray(newGoodPassList)); // 存储原始优惠券列表
825
845
  this.store.originalDiscountList = newDiscountList;
826
- _context10.next = 14;
846
+ _context10.next = 16;
827
847
  return (_this$store$discount9 = this.store.discount) === null || _this$store$discount9 === void 0 ? void 0 : _this$store$discount9.setOriginalDiscountList(newDiscountList);
828
- case 14:
848
+ case 16:
829
849
  // 根据当前预约时间过滤优惠券列表
830
850
  filteredDiscountList = this.filterDiscountListByBookingTime(newDiscountList, this.store.currentBookingTime);
831
851
  this.store.filteredDiscountList = filteredDiscountList;
832
852
  this.setDiscountList(filteredDiscountList || []);
833
853
  if (!((_this$store$productLi2 = this.store.productList) !== null && _this$store$productLi2 !== void 0 && _this$store$productLi2.length)) {
834
- _context10.next = 21;
854
+ _context10.next = 23;
835
855
  break;
836
856
  }
837
857
  _result3 = this.calcDiscount(this.store.productList);
838
- _context10.next = 21;
839
- return this.core.effects.emit("".concat(this.name, ":onLoadPrepareCalcResult"), _result3);
840
- case 21:
841
858
  _context10.next = 23;
842
- return this.core.effects.emit("".concat(this.name, ":onLoadDiscountList"), filteredDiscountList);
859
+ return this.core.effects.emit("".concat(this.name, ":onLoadPrepareCalcResult"), _result3);
843
860
  case 23:
844
- _context10.next = 28;
845
- break;
861
+ _context10.next = 25;
862
+ return this.core.effects.emit("".concat(this.name, ":onLoadDiscountList"), filteredDiscountList);
846
863
  case 25:
847
- _context10.prev = 25;
864
+ _context10.next = 30;
865
+ break;
866
+ case 27:
867
+ _context10.prev = 27;
848
868
  _context10.t0 = _context10["catch"](0);
849
869
  console.error('[ShopDiscount] 加载准备配置出错:', _context10.t0);
850
- case 28:
870
+ case 30:
851
871
  case "end":
852
872
  return _context10.stop();
853
873
  }
854
- }, _callee10, this, [[0, 25]]);
874
+ }, _callee10, this, [[0, 27]]);
855
875
  }));
856
876
  function loadPrepareConfig(_x10) {
857
877
  return _loadPrepareConfig.apply(this, arguments);
@@ -9,6 +9,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
9
9
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
10
10
  import Decimal from "decimal.js";
11
11
  import dayjs from "dayjs";
12
+ import { isFullCoveragePass } from "../../modules/Discount/entitlementPass";
12
13
  export var uniqueById = function uniqueById(arr) {
13
14
  var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'id';
14
15
  var seen = new Set();
@@ -41,8 +42,8 @@ export var isAllNormalProduct = function isAllNormalProduct(items) {
41
42
  */
42
43
  export var getDiscountAmount = function getDiscountAmount(discount, total, price) {
43
44
  var _discount$metadata;
44
- // 商品券
45
- if (discount.tag === 'good_pass') {
45
+ // 商品券和 Entitlement Pass 都是全额抵扣。
46
+ if (isFullCoveragePass(discount)) {
46
47
  return new Decimal(price).minus(new Decimal(price || 0)).toNumber();
47
48
  }
48
49
 
@@ -142,7 +142,7 @@ export function buildPlannerDiscountResult(params) {
142
142
  productDiscounts.forEach(function (discount) {
143
143
  var _product$product_id, _product$metadata;
144
144
  var type = discount.tag || discount.type;
145
- if (!['good_pass', 'discount_card', 'product_discount_card'].includes(type)) return;
145
+ if (!['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(type)) return;
146
146
  var discountId = resolvePlannerDiscountId(discount);
147
147
  applications.push({
148
148
  discountId: discountId,
@@ -194,7 +194,7 @@ function isLocalOrderId(orderId) {
194
194
  function isCustomerBoundDiscount(discount) {
195
195
  var _discount$type;
196
196
  var type = (_discount$type = discount === null || discount === void 0 ? void 0 : discount.type) !== null && _discount$type !== void 0 ? _discount$type : discount === null || discount === void 0 ? void 0 : discount.tag;
197
- return type === 'good_pass' || type === 'discount_card' || type === 'product_discount_card';
197
+ return type === 'entitlement_pass' || type === 'good_pass' || type === 'discount_card' || type === 'product_discount_card';
198
198
  }
199
199
  function filterCustomerBoundDiscounts(discountList) {
200
200
  if (!Array.isArray(discountList)) return [];
@@ -674,14 +674,9 @@ function normalizeResource(raw) {
674
674
  var id = (_ref5 = (_raw$resourceId = raw.resourceId) !== null && _raw$resourceId !== void 0 ? _raw$resourceId : raw.resource_id) !== null && _ref5 !== void 0 ? _ref5 : raw.id;
675
675
  if (id === undefined || id === null || id === '') return null;
676
676
  var rawWindows = raw.windows || raw.times || [];
677
- return {
678
- id: id,
679
- formId: (_ref6 = (_raw$formId = raw.formId) !== null && _raw$formId !== void 0 ? _raw$formId : raw.form_id) !== null && _ref6 !== void 0 ? _ref6 : raw.resource_form_id,
680
- name: raw.resourceName || raw.main_field || raw.name || raw.title,
681
- code: raw.code,
682
- resourceType: normalizeResourceType(raw.type || raw.resourceType),
683
- capacity: Math.max(1, Number(raw.capacity || raw.max_capacity || 1) || 1),
684
- windows: (Array.isArray(rawWindows) ? rawWindows : []).flatMap(function (window) {
677
+ var rawExcludedWindows = raw.excludedWindows || raw.excluded_windows || [];
678
+ var normalizeWindows = function normalizeWindows(windows) {
679
+ return (Array.isArray(windows) ? windows : []).flatMap(function (window) {
685
680
  var range = normalizeAvailabilityLocalDateTimeRange({
686
681
  startAt: window.startAt || window.start_at || window.start,
687
682
  endAt: window.endAt || window.end_at || window.end,
@@ -695,7 +690,17 @@ function normalizeResource(raw) {
695
690
  source: window.source,
696
691
  raw: window
697
692
  }];
698
- }),
693
+ });
694
+ };
695
+ return {
696
+ id: id,
697
+ formId: (_ref6 = (_raw$formId = raw.formId) !== null && _raw$formId !== void 0 ? _raw$formId : raw.form_id) !== null && _ref6 !== void 0 ? _ref6 : raw.resource_form_id,
698
+ name: raw.resourceName || raw.main_field || raw.name || raw.title,
699
+ code: raw.code,
700
+ resourceType: normalizeResourceType(raw.type || raw.resourceType),
701
+ capacity: Math.max(1, Number(raw.capacity || raw.max_capacity || 1) || 1),
702
+ windows: normalizeWindows(rawWindows),
703
+ excludedWindows: normalizeWindows(rawExcludedWindows),
699
704
  raw: raw
700
705
  };
701
706
  }
@@ -719,6 +724,16 @@ function dateRangeDays(dateRange) {
719
724
  }
720
725
  return dates;
721
726
  }
727
+ function getExcludedScheduleDateOverrideTimePoints(date, schedule) {
728
+ var _schedule$repeat_rule;
729
+ if (!((_schedule$repeat_rule = schedule.repeat_rule) !== null && _schedule$repeat_rule !== void 0 && (_schedule$repeat_rule = _schedule$repeat_rule.excluded_date) !== null && _schedule$repeat_rule !== void 0 && _schedule$repeat_rule.length)) return [];
730
+ if (getScheduleStartEndTimePoints(date, [schedule]).length > 0) return [];
731
+ return getScheduleStartEndTimePoints(date, [_objectSpread(_objectSpread({}, schedule), {}, {
732
+ repeat_rule: _objectSpread(_objectSpread({}, schedule.repeat_rule), {}, {
733
+ excluded_date: []
734
+ })
735
+ })]);
736
+ }
722
737
  function normalizeResourceOccupancy(rawEvent, resourceId) {
723
738
  var _ref9, _ref10, _rawEvent$start_at, _ref11, _ref12, _rawEvent$end_at, _ref13, _ref14, _rawEvent$pax, _rawEvent$schedule_ev, _ref15, _rawEvent$schedule_ev2, _ref16, _rawEvent$booking_uid, _rawEvent$metadata, _ref17, _rawEvent$product_uid, _rawEvent$metadata2;
724
739
  var source = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'remote';
@@ -825,7 +840,30 @@ export function buildAvailabilityResourcesFromV2(params) {
825
840
  });
826
841
  });
827
842
  });
843
+ var excludedWindows = dates.flatMap(function (date) {
844
+ return schedules.flatMap(function (schedule) {
845
+ return getExcludedScheduleDateOverrideTimePoints(date, schedule).flatMap(function (slot) {
846
+ var range = normalizeAvailabilityLocalDateTimeRange({
847
+ startAt: slot.start_at,
848
+ endAt: slot.end_at,
849
+ fixedOffsetMinutes: fixedOffsetMinutes,
850
+ rollOverEnd: true
851
+ });
852
+ if (!range) return [];
853
+ return [{
854
+ startAt: range.startAt,
855
+ endAt: range.endAt,
856
+ source: "resource_schedule_excluded:".concat(schedule.id),
857
+ raw: {
858
+ scheduleId: schedule.id,
859
+ excludedDate: date
860
+ }
861
+ }];
862
+ });
863
+ });
864
+ });
828
865
  resource.windows = materializedWindows.length > 0 ? materializedWindows : explicitWindows;
866
+ resource.excludedWindows = [].concat(_toConsumableArray(resource.excludedWindows || []), _toConsumableArray(excludedWindows));
829
867
  if (resource.windows.length === 0 && missingScheduleIds.length > 0) {
830
868
  resource.windows = buildResourceWindowFallbackTimes({
831
869
  raw: raw,
@@ -1093,7 +1131,7 @@ function buildBookingFromAvailabilitySelection(params) {
1093
1131
  } : {})
1094
1132
  });
1095
1133
  }
1096
- var POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES = new Set(['past', 'booking_cutoff', 'resource_full', 'resource_unavailable', 'resource_capacity_exceeded',
1134
+ var POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES = new Set(['past', 'booking_cutoff', 'schedule_excluded_date', 'resource_full', 'resource_unavailable', 'resource_capacity_exceeded',
1097
1135
  // A required group whose selected resource is outside its window is surfaced
1098
1136
  // as missing_resource at group level. Structural validation below still
1099
1137
  // rejects a genuinely missing selection.
@@ -3133,12 +3171,35 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
3133
3171
  }] : [];
3134
3172
  });
3135
3173
  });
3136
- return {
3174
+ var excludedWindows = dateRangeDays(params.dateRange).flatMap(function (date) {
3175
+ return schedules.flatMap(function (schedule) {
3176
+ return getExcludedScheduleDateOverrideTimePoints(date, schedule).flatMap(function (slot) {
3177
+ var range = normalizeAvailabilityLocalDateTimeRange({
3178
+ startAt: slot.start_at,
3179
+ endAt: slot.end_at,
3180
+ fixedOffsetMinutes: _this3.getAvailabilityRuntimeOffsetMinutes(),
3181
+ rollOverEnd: true
3182
+ });
3183
+ return range ? [{
3184
+ startAt: range.startAt,
3185
+ endAt: range.endAt,
3186
+ source: "operating_schedule_excluded:".concat(schedule.id),
3187
+ raw: {
3188
+ scheduleId: schedule.id,
3189
+ excludedDate: date
3190
+ }
3191
+ }] : [];
3192
+ });
3193
+ });
3194
+ });
3195
+ return _objectSpread({
3137
3196
  source: descriptor.source,
3138
3197
  scheduleIds: _toConsumableArray(descriptor.scheduleIds),
3139
3198
  missingScheduleIds: missingScheduleIds,
3140
3199
  windows: windows
3141
- };
3200
+ }, excludedWindows.length > 0 ? {
3201
+ excludedWindows: excludedWindows
3202
+ } : {});
3142
3203
  }
3143
3204
  }, {
3144
3205
  key: "loadAvailabilityProducts",
@@ -4312,7 +4373,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4312
4373
  allowOutsideOperatingHoursForRequestedStartTimes: true
4313
4374
  } : {}), {
4314
4375
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
4315
- allowSessionCustomRanges: isPosAvailabilityRequest
4376
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4377
+ allowSessionCustomRanges: isPosAvailabilityRequest,
4378
+ allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4316
4379
  }).map(function (group) {
4317
4380
  return _objectSpread(_objectSpread({}, group), {}, {
4318
4381
  ranges: group.ranges.map(function (candidate) {
@@ -4335,7 +4398,8 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4335
4398
  key: "queryBookingAvailability",
4336
4399
  value: (function () {
4337
4400
  var _queryBookingAvailability = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee38(contextId, request) {
4338
- var _yield$this$ensureAva2, context, projectionEntry, refreshed, result, contextVersion, contextualResult;
4401
+ var _this$otherParams$pla3, _this$otherParams21;
4402
+ var _yield$this$ensureAva2, context, projectionEntry, refreshed, isPosAvailabilityRequest, result, contextVersion, contextualResult;
4339
4403
  return _regeneratorRuntime().wrap(function _callee38$(_context38) {
4340
4404
  while (1) switch (_context38.prev = _context38.next) {
4341
4405
  case 0:
@@ -4347,7 +4411,11 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4347
4411
  projectionEntry = _yield$this$ensureAva2.projectionEntry;
4348
4412
  refreshed = _yield$this$ensureAva2.refreshed;
4349
4413
  this.assertContextualQueryFreshness(context, request);
4350
- result = queryAvailabilityProjection(projectionEntry.projection, request);
4414
+ isPosAvailabilityRequest = String((_this$otherParams$pla3 = (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.platform) !== null && _this$otherParams$pla3 !== void 0 ? _this$otherParams$pla3 : '').trim().toLowerCase() === 'pos';
4415
+ result = queryAvailabilityProjection(projectionEntry.projection, request, {
4416
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4417
+ allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4418
+ });
4351
4419
  contextVersion = context.activeVersion;
4352
4420
  contextualResult = result.target === 'time' ? _objectSpread(_objectSpread({}, result), {}, {
4353
4421
  data: result.data.map(function (group) {
@@ -4379,7 +4447,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4379
4447
  contextVersion: contextVersion,
4380
4448
  refreshed: refreshed
4381
4449
  }));
4382
- case 11:
4450
+ case 12:
4383
4451
  case "end":
4384
4452
  return _context38.stop();
4385
4453
  }
@@ -4456,7 +4524,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4456
4524
  key: "commitAvailabilitySelection",
4457
4525
  value: (function () {
4458
4526
  var _commitAvailabilitySelection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee39(contextId, params) {
4459
- var normalizedContextId, _params$bookingCount, _ref46, _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$pla3, _this$otherParams21, _ref47, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref48, _ref49, _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, _ref50, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
4527
+ var normalizedContextId, _params$bookingCount, _ref46, _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$pla4, _this$otherParams22, _ref47, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref48, _ref49, _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, _ref50, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
4460
4528
  return _regeneratorRuntime().wrap(function _callee39$(_context39) {
4461
4529
  while (1) switch (_context39.prev = _context39.next) {
4462
4530
  case 0:
@@ -4686,7 +4754,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4686
4754
  this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
4687
4755
  candidateDurationMinutes = getCandidateDurationMinutes(params.candidate);
4688
4756
  candidateStartTime = getCandidateStartTime(params.candidate);
4689
- allowPosAvailabilityOverride = String((_this$otherParams$pla3 = (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.platform) !== null && _this$otherParams$pla3 !== void 0 ? _this$otherParams$pla3 : '').trim().toLowerCase() === 'pos';
4757
+ allowPosAvailabilityOverride = String((_this$otherParams$pla4 = (_this$otherParams22 = this.otherParams) === null || _this$otherParams22 === void 0 ? void 0 : _this$otherParams22.platform) !== null && _this$otherParams$pla4 !== void 0 ? _this$otherParams$pla4 : '').trim().toLowerCase() === 'pos';
4690
4758
  refreshedRanges = getProjectionProductTimeRanges(refreshedProjection, _objectSpread({
4691
4759
  productIds: [params.candidate.productId],
4692
4760
  dateRange: {
@@ -4700,7 +4768,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4700
4768
  }, allowPosAvailabilityOverride ? {
4701
4769
  allowOutsideOperatingHoursForRequestedStartTimes: true
4702
4770
  } : {}) : {}) : {}), {
4703
- allowSessionCustomRanges: allowPosAvailabilityOverride
4771
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4772
+ allowSessionCustomRanges: allowPosAvailabilityOverride,
4773
+ allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4704
4774
  }).flatMap(function (group) {
4705
4775
  return group.ranges;
4706
4776
  });
@@ -4733,6 +4803,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4733
4803
  requirementSelections: params.requirementSelections,
4734
4804
  partySize: partySize,
4735
4805
  bookingCount: bookingCount
4806
+ }, {
4807
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4808
+ allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4736
4809
  });
4737
4810
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(function (conflict) {
4738
4811
  return POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES.has(conflict.code);
@@ -7,6 +7,7 @@ exports.buildCacheItemFromOrderLine = buildCacheItemFromOrderLine;
7
7
  var _dayjs = _interopRequireDefault(require("dayjs"));
8
8
  var _utils = require("../../Order/utils");
9
9
  var _manualProductDiscount = require("../../Order/utils/manualProductDiscount");
10
+ var _entitlementPass = require("../../Discount/entitlementPass");
10
11
  var _orderLineDisplay = require("./orderLineDisplay");
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13
  function safeFormat(value, fmt) {
@@ -116,11 +117,38 @@ function resolveProductTitle(product, booking, sourceProduct) {
116
117
  function resolveProductCover(product, booking, sourceProduct) {
117
118
  return sourceProduct?.cover ?? product.product_cover ?? '';
118
119
  }
119
- function resolveMainProductPrice(product, fallback) {
120
- const metadata = product.metadata || {};
121
- const value = metadata.main_product_original_price ?? metadata.source_product_price;
120
+ function toFinitePrice(value) {
121
+ if (value === undefined || value === null || value === '') return null;
122
122
  const parsed = Number(value);
123
- return Number.isFinite(parsed) ? parsed : fallback;
123
+ return Number.isFinite(parsed) ? parsed : null;
124
+ }
125
+ function hasEntitlementPassDiscount(product) {
126
+ const hasEntitlementDiscount = discountList => Array.isArray(discountList) && discountList.some(_entitlementPass.isEntitlementPass);
127
+ return hasEntitlementDiscount(product.discount_list) || Array.isArray(product.product_bundle) && product.product_bundle.some(bundle => hasEntitlementDiscount(bundle?.discount_list));
128
+ }
129
+ function resolveMainProductPrice(product, fallback, sourceProduct, restoreEntitlementPrice = false) {
130
+ const metadata = product.metadata || {};
131
+ if (!restoreEntitlementPrice) {
132
+ const value = metadata.main_product_original_price ?? metadata.source_product_price;
133
+ const parsed = Number(value);
134
+ return Number.isFinite(parsed) ? parsed : fallback;
135
+ }
136
+ const sourcePrice = toFinitePrice(metadata.source_product_price);
137
+ if (sourcePrice !== null) return sourcePrice;
138
+ const variantId = Number(product.product_variant_id || 0);
139
+ const variantList = sourceProduct?.variant ?? metadata.origin?.variant;
140
+ if (variantId > 0 && Array.isArray(variantList)) {
141
+ const matched = variantList.find(variant => Number(variant?.id) === variantId);
142
+ const variantPrice = toFinitePrice(matched?.price ?? matched?.base_price);
143
+ if (variantPrice !== null) return variantPrice;
144
+ }
145
+ const catalogPrice = toFinitePrice(sourceProduct?.price ?? sourceProduct?.base_price ?? metadata.origin?.price ?? metadata.origin?.base_price);
146
+ if (catalogPrice !== null) return catalogPrice;
147
+
148
+ // legacy 数据没有 source_product_price 时,main_product_original_price
149
+ // 仍比已被月卡改写为 0 的 selling_price 更可靠。
150
+ const legacyMainPrice = toFinitePrice(metadata.main_product_original_price);
151
+ return legacyMainPrice ?? fallback;
124
152
  }
125
153
  function mapOrderBundleToOtherBundle(bundle) {
126
154
  return bundle.map(item => {
@@ -185,7 +213,8 @@ function buildCacheItemFromOrderLine(input) {
185
213
  const resolvedId = product.product_id ?? sourceProduct?.id;
186
214
  const selling = Number(product.selling_price ?? 0);
187
215
  const original = Number(product.original_price ?? selling);
188
- const mainProductPrice = resolveMainProductPrice(product, selling);
216
+ const shouldRestoreEntitlementPrice = hasEntitlementPassDiscount(product);
217
+ const mainProductPrice = resolveMainProductPrice(product, selling, sourceProduct, shouldRestoreEntitlementPrice);
189
218
  const startDate = safeFormat(booking.start_date, 'YYYY-MM-DD');
190
219
  const endDate = safeFormat(booking.end_date, 'YYYY-MM-DD');
191
220
  const startTime = normalizeTimeString(booking.start_time);
@@ -240,7 +269,7 @@ function buildCacheItemFromOrderLine(input) {
240
269
  }
241
270
  }
242
271
  if (product.metadata?.price_override != null || manualDiscount) {
243
- extend.priceOverride = selling;
272
+ extend.priceOverride = shouldRestoreEntitlementPrice ? product.metadata?.price_override ?? selling : selling;
244
273
  }
245
274
  if (booking.holder !== undefined) {
246
275
  extend.holder = booking.holder;
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.buildNormalProductCacheItemFromOrderLine = buildNormalProductCacheItemFromOrderLine;
7
7
  var _utils = require("../../Order/utils");
8
+ var _entitlementPass = require("../../Discount/entitlementPass");
8
9
  var _orderLineDisplay = require("./orderLineDisplay");
9
10
  /**
10
11
  * 从已加车的普通商品 order line 反查 SkuDetailModal edit 所需的 cacheItem。
@@ -44,12 +45,16 @@ function resolveSourceProductPrice(product, sourceProduct) {
44
45
  }
45
46
  return Number(product.selling_price ?? 0);
46
47
  }
48
+ function hasEntitlementPassDiscount(product) {
49
+ const hasEntitlementDiscount = discountList => Array.isArray(discountList) && discountList.some(_entitlementPass.isEntitlementPass);
50
+ return hasEntitlementDiscount(product.discount_list) || Array.isArray(product.product_bundle) && product.product_bundle.some(bundle => hasEntitlementDiscount(bundle?.discount_list));
51
+ }
47
52
 
48
53
  /** 订单行 bundle → booking other.bundle(保留 original_price 供 setProductPrice 按比例分摊) */
49
- function mapOrderBundleToOtherBundle(bundle) {
54
+ function mapOrderBundleToOtherBundle(bundle, preferManualPrice = false) {
50
55
  return bundle.map(item => {
51
56
  const catalogOriginal = item.original_price ?? item.product_price ?? item.price ?? item.bundle_selling_price;
52
- const selling = item.bundle_selling_price ?? item.price ?? catalogOriginal;
57
+ const selling = preferManualPrice ? item.price ?? item.bundle_selling_price ?? catalogOriginal : item.bundle_selling_price ?? item.price ?? catalogOriginal;
53
58
  const {
54
59
  bundle_selling_price: _omitBundleSelling,
55
60
  ...rest
@@ -78,9 +83,11 @@ function buildNormalProductCacheItemFromOrderLine(input) {
78
83
  const selling = Number(product.selling_price ?? 0);
79
84
  const original = Number(product.original_price ?? selling);
80
85
  const uid = product.metadata?.unique_identification_number;
81
- const option = (0, _utils.getProductSkuOptions)(product);
82
- const bundle = mapOrderBundleToOtherBundle(Array.isArray(product.product_bundle) ? product.product_bundle : []);
83
86
  const originExtend = product.metadata?.origin?._extend;
87
+ const shouldPreserveEntitlementPriceOverride = hasEntitlementPassDiscount(product) && (originExtend?.priceOverride !== undefined || product.metadata?.price_override != null);
88
+ const hasPriceOverride = originExtend?.priceOverride !== undefined || shouldPreserveEntitlementPriceOverride;
89
+ const option = (0, _utils.getProductSkuOptions)(product);
90
+ const bundle = mapOrderBundleToOtherBundle(Array.isArray(product.product_bundle) ? product.product_bundle : [], shouldPreserveEntitlementPriceOverride);
84
91
  const productOptionString = (0, _orderLineDisplay.buildProductOptionStringFromOrderLine)(product);
85
92
  const discountList = product.discount_list || [];
86
93
  const other = {
@@ -114,8 +121,8 @@ function buildNormalProductCacheItemFromOrderLine(input) {
114
121
  ...(productOptionString ? {
115
122
  product_option_string: productOptionString
116
123
  } : {}),
117
- ...(originExtend?.priceOverride !== undefined ? {
118
- priceOverride: originExtend.priceOverride
124
+ ...(hasPriceOverride ? {
125
+ priceOverride: shouldPreserveEntitlementPriceOverride ? originExtend?.priceOverride ?? product.metadata?.price_override : originExtend?.priceOverride
119
126
  } : {}),
120
127
  ...(originExtend?.bundle_edit !== undefined ? {
121
128
  bundle_edit: originExtend.bundle_edit
@@ -0,0 +1,34 @@
1
+ export declare const ENTITLEMENT_PASS_TYPE = "entitlement_pass";
2
+ export declare const GOOD_PASS_TYPE = "good_pass";
3
+ type DiscountLike = {
4
+ id?: number | string | null;
5
+ tag?: unknown;
6
+ type?: unknown;
7
+ discount?: object | null;
8
+ metadata?: object | null;
9
+ extension_data?: unknown;
10
+ balance?: unknown;
11
+ expire_time?: unknown;
12
+ };
13
+ export type EntitlementQuota = {
14
+ type: 'limited';
15
+ value: number;
16
+ balance: number;
17
+ } | {
18
+ type: 'unlimited';
19
+ value: null;
20
+ balance: null;
21
+ };
22
+ export declare function isEntitlementPass(discount: DiscountLike | null | undefined): boolean;
23
+ export declare function isFullCoveragePass(discount: DiscountLike | null | undefined): boolean;
24
+ /**
25
+ * Resolve the authoritative total-use contract for an Entitlement Pass.
26
+ * Invalid or missing configuration fails closed. Legacy mode/total_uses fields
27
+ * are intentionally unsupported.
28
+ */
29
+ export declare function resolveEntitlementQuota(discount: DiscountLike | null | undefined): EntitlementQuota | null;
30
+ export declare function getRemainingEntitlementUses(discount: DiscountLike | null | undefined, usedCount: number, requestedCount: number): number;
31
+ export declare function hasAvailableEntitlementUses(discount: DiscountLike | null | undefined): boolean;
32
+ /** Sort Entitlement Passes by expiry, finite balance, then card instance id. */
33
+ export declare function compareEntitlementPassPriority(left: DiscountLike, right: DiscountLike): number;
34
+ export {};