@pisell/pisellos 2.3.143 → 2.3.145
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.
- package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/dist/modules/BookingContext/utils/productExtend.js +62 -18
- package/dist/modules/Order/index.d.ts +2 -1
- package/dist/modules/Order/index.js +380 -198
- package/dist/modules/Order/types.d.ts +9 -0
- package/dist/modules/Order/utils.d.ts +5 -3
- package/dist/modules/Order/utils.js +32 -11
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
- package/dist/modules/ResourcePlanner/planner.js +327 -22
- package/dist/modules/ResourcePlanner/types.d.ts +29 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/dist/solution/UnifiedBookingSales/index.d.ts +3 -0
- package/dist/solution/UnifiedBookingSales/index.js +432 -163
- package/dist/solution/UnifiedBookingSales/types.d.ts +14 -2
- package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/lib/modules/BookingContext/utils/productExtend.js +45 -2
- package/lib/modules/Order/index.d.ts +2 -1
- package/lib/modules/Order/index.js +92 -10
- package/lib/modules/Order/types.d.ts +9 -0
- package/lib/modules/Order/utils.d.ts +5 -3
- package/lib/modules/Order/utils.js +29 -10
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
- package/lib/modules/ResourcePlanner/planner.js +247 -7
- package/lib/modules/ResourcePlanner/types.d.ts +29 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/lib/solution/UnifiedBookingSales/index.d.ts +3 -0
- package/lib/solution/UnifiedBookingSales/index.js +220 -27
- package/lib/solution/UnifiedBookingSales/types.d.ts +14 -2
- package/package.json +1 -1
|
@@ -445,6 +445,15 @@ export interface AddProductToOrderOptions {
|
|
|
445
445
|
disableMerge?: boolean;
|
|
446
446
|
/** 商品行 UID 落定后,由 OrderModule 原子绑定到该行的 Sales Notes 草稿。 */
|
|
447
447
|
salesNotes?: SalesNoteDraftInput[];
|
|
448
|
+
/**
|
|
449
|
+
* 自动预约加购的同步提交门禁;抛错时不发布本次新增。
|
|
450
|
+
* 带门禁时先在私有草稿中准备全部商品/booking,异步等待后及原子发布前重新调用。
|
|
451
|
+
* 门禁须校验当前订单身份/版本和真实时间;发布前不会因本次拆行改变订单版本。
|
|
452
|
+
* 不传时保留原有人工加购行为。
|
|
453
|
+
*/
|
|
454
|
+
availabilityCommitGuard?: () => void;
|
|
455
|
+
/** 发布后的订单/业务归属检查;只用于阻止旧异步收尾写入新单,不再校验截止或 revision。 */
|
|
456
|
+
availabilityCommitTargetGuard?: () => boolean;
|
|
448
457
|
}
|
|
449
458
|
/**
|
|
450
459
|
* 删除商品后的可选位置保持策略。
|
|
@@ -121,8 +121,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
121
121
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
122
122
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
123
123
|
* 不含折扣。**权威源**。
|
|
124
|
-
* - `
|
|
125
|
-
* - `metadata.
|
|
124
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
125
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
126
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
126
127
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
127
128
|
*
|
|
128
129
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -131,8 +132,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
131
132
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
132
133
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
133
134
|
* total(source + option + bundle)对齐。
|
|
135
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
134
136
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
135
|
-
*
|
|
137
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
136
138
|
* 优先级:
|
|
137
139
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
138
140
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -588,8 +588,9 @@ export function getBundleSellingMagnitude(bundle) {
|
|
|
588
588
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
589
589
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
590
590
|
* 不含折扣。**权威源**。
|
|
591
|
-
* - `
|
|
592
|
-
* - `metadata.
|
|
591
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
592
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
593
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
593
594
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
594
595
|
*
|
|
595
596
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -598,8 +599,9 @@ export function getBundleSellingMagnitude(bundle) {
|
|
|
598
599
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
599
600
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
600
601
|
* total(source + option + bundle)对齐。
|
|
602
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
601
603
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
602
|
-
*
|
|
604
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
603
605
|
* 优先级:
|
|
604
606
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
605
607
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -822,6 +824,15 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
822
824
|
var effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
823
825
|
return new Decimal(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
824
826
|
};
|
|
827
|
+
|
|
828
|
+
// optionDiscountAmount 已是每件主商品内的单规格优惠合计,不再乘商品数量。
|
|
829
|
+
var getOptionDiscountAmount = function getOptionDiscountAmount(discountList) {
|
|
830
|
+
return (discountList || []).reduce(function (total, discount) {
|
|
831
|
+
var _discount$metadata, _discount$metadata2;
|
|
832
|
+
if (discount !== null && discount !== void 0 && (_discount$metadata = discount.metadata) !== null && _discount$metadata !== void 0 && _discount$metadata.custom_product_bundle_map_id) return total;
|
|
833
|
+
return total.plus(Number(discount === null || discount === void 0 || (_discount$metadata2 = discount.metadata) === null || _discount$metadata2 === void 0 ? void 0 : _discount$metadata2.optionDiscountAmount) || 0);
|
|
834
|
+
}, new Decimal(0));
|
|
835
|
+
};
|
|
825
836
|
var getBundleIdentity = function getBundleIdentity(bundle) {
|
|
826
837
|
var _ref21, _bundle$bundle_id, _ref22, _ref23, _bundle$bundle_produc, _ref24, _ref25, _bundle$bundle_varian, _ref26, _bundle$bundle_group_;
|
|
827
838
|
return [(_ref21 = (_bundle$bundle_id = bundle.bundle_id) !== null && _bundle$bundle_id !== void 0 ? _bundle$bundle_id : bundle.id) !== null && _ref21 !== void 0 ? _ref21 : '', (_ref22 = (_ref23 = (_bundle$bundle_produc = bundle.bundle_product_id) !== null && _bundle$bundle_produc !== void 0 ? _bundle$bundle_produc : bundle._bundle_product_id) !== null && _ref23 !== void 0 ? _ref23 : bundle.product_id) !== null && _ref22 !== void 0 ? _ref22 : '', (_ref24 = (_ref25 = (_bundle$bundle_varian = bundle.bundle_variant_id) !== null && _bundle$bundle_varian !== void 0 ? _bundle$bundle_varian : bundle.variant_id) !== null && _ref25 !== void 0 ? _ref25 : bundle.product_variant_id) !== null && _ref24 !== void 0 ? _ref24 : 0, (_ref26 = (_bundle$bundle_group_ = bundle.bundle_group_id) !== null && _bundle$bundle_group_ !== void 0 ? _bundle$bundle_group_ : bundle.group_id) !== null && _ref26 !== void 0 ? _ref26 : ''].join('|');
|
|
@@ -859,12 +870,14 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
859
870
|
var _product$metadata7, _product$metadata8, _product$metadata9, _metadataAny$_promoti;
|
|
860
871
|
// source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
|
|
861
872
|
var metadataAny = product.metadata || {};
|
|
862
|
-
var
|
|
873
|
+
var productOptions = getProductSkuOptions(product);
|
|
874
|
+
var optionSum = sumOptionUnitPrice(productOptions);
|
|
875
|
+
var optionSellingSum = optionSum.minus(getOptionDiscountAmount(product.discount_list));
|
|
863
876
|
var sourcePrice;
|
|
864
877
|
if (metadataAny.source_product_price !== undefined) {
|
|
865
878
|
sourcePrice = String(metadataAny.source_product_price);
|
|
866
879
|
} else if (metadataAny.main_product_selling_price !== undefined) {
|
|
867
|
-
sourcePrice = new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
880
|
+
sourcePrice = new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString();
|
|
868
881
|
} else {
|
|
869
882
|
var _product$selling_pric;
|
|
870
883
|
sourcePrice = String((_product$selling_pric = product.selling_price) !== null && _product$selling_pric !== void 0 ? _product$selling_pric : 0);
|
|
@@ -895,6 +908,12 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
895
908
|
num: product.num || 1,
|
|
896
909
|
discount_list: product.discount_list || [],
|
|
897
910
|
bundle: product.product_bundle || [],
|
|
911
|
+
// 仅在 Rules 入参中映射 price,避免折后价污染订单的 add_price。
|
|
912
|
+
options: productOptions.map(function (option) {
|
|
913
|
+
return _objectSpread(_objectSpread({}, option), {}, {
|
|
914
|
+
price: option.add_price
|
|
915
|
+
});
|
|
916
|
+
}),
|
|
898
917
|
booking_id: ((_product$metadata8 = product.metadata) === null || _product$metadata8 === void 0 ? void 0 : _product$metadata8.booking_id) || null,
|
|
899
918
|
isClient: false,
|
|
900
919
|
// 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
|
|
@@ -902,20 +921,22 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
902
921
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
903
922
|
holder_id: (_product$metadata9 = product.metadata) === null || _product$metadata9 === void 0 ? void 0 : _product$metadata9.holder_id,
|
|
904
923
|
startDate: getProductStartDate(product),
|
|
905
|
-
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
924
|
+
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString() : undefined,
|
|
906
925
|
inPromotion: ((_metadataAny$_promoti = metadataAny._promotion) === null || _metadataAny$_promoti === void 0 ? void 0 : _metadataAny$_promoti.inPromotion) === true,
|
|
907
926
|
_promotion: metadataAny._promotion
|
|
908
927
|
};
|
|
909
928
|
},
|
|
910
929
|
setProduct: function setProduct(product, values) {
|
|
911
|
-
var _ref32, _values$quantity, _ref33, _metadataAny$source_p,
|
|
930
|
+
var _ref32, _values$quantity, _ref33, _metadataAny$source_p, _values$discount_list, _product$product_sku, _values$quantity2;
|
|
912
931
|
var nextNum = Number((_ref32 = (_values$quantity = values.quantity) !== null && _values$quantity !== void 0 ? _values$quantity : product.num) !== null && _ref32 !== void 0 ? _ref32 : 1) || 1;
|
|
913
932
|
var metadataAny = product.metadata || {};
|
|
914
933
|
var existedSource = (_ref33 = (_metadataAny$source_p = metadataAny.source_product_price) !== null && _metadataAny$source_p !== void 0 ? _metadataAny$source_p : product.selling_price) !== null && _ref33 !== void 0 ? _ref33 : '0';
|
|
915
934
|
var nextOptions = getProductSkuOptions(product);
|
|
916
935
|
var optionSum = sumOptionUnitPrice(nextOptions);
|
|
936
|
+
var nextDiscountList = (_values$discount_list = values.discount_list) !== null && _values$discount_list !== void 0 ? _values$discount_list : product.discount_list;
|
|
937
|
+
var optionSellingSum = optionSum.minus(getOptionDiscountAmount(nextDiscountList));
|
|
917
938
|
|
|
918
|
-
// Rules 返回的 main_product_selling_price / price
|
|
939
|
+
// Rules 返回的 main_product_selling_price / price 为不含 option 的主商品价。
|
|
919
940
|
// 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
|
|
920
941
|
// total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
|
|
921
942
|
var nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
@@ -924,8 +945,8 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
924
945
|
// 缺省时保留现有 source(券前 = 当前 source)。
|
|
925
946
|
var nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
|
|
926
947
|
|
|
927
|
-
//
|
|
928
|
-
var nextMainSellingPrice = new Decimal(Number(nextSourceSellingPrice) || 0).plus(
|
|
948
|
+
// 成交价只加回 option 折后合计;原价仍使用订单中保存的 option 原价。
|
|
949
|
+
var nextMainSellingPrice = new Decimal(Number(nextSourceSellingPrice) || 0).plus(optionSellingSum).toDecimalPlaces(2).toFixed(2);
|
|
929
950
|
var nextMainOriginalPrice = new Decimal(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
930
951
|
var nextBundle = values.bundle !== undefined ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
|
|
931
952
|
var composedSellingPrice = composeLinePrice({
|
|
@@ -945,7 +966,7 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
945
966
|
return _objectSpread(_objectSpread({}, product), {}, {
|
|
946
967
|
selling_price: composedSellingPrice,
|
|
947
968
|
original_price: finalOriginalPrice,
|
|
948
|
-
discount_list:
|
|
969
|
+
discount_list: nextDiscountList,
|
|
949
970
|
num: (_values$quantity2 = values.quantity) !== null && _values$quantity2 !== void 0 ? _values$quantity2 : product.num,
|
|
950
971
|
product_bundle: nextBundle,
|
|
951
972
|
metadata: _objectSpread(_objectSpread({}, metadataAny), {}, {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
|
|
2
2
|
export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
|
|
3
|
+
/** Resolve the label without changing the real calendar timestamp. */
|
|
4
|
+
export declare function getDurationBusinessDate(projection: AvailabilityProjection, startAt: string): string;
|
|
3
5
|
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
|
|
4
6
|
export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilityQueryResult;
|
|
5
7
|
export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilitySelectionValidationResult;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
3
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
4
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
5
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
2
6
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
3
7
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
4
8
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
@@ -263,6 +267,18 @@ function evaluateCandidateTimeGate(params) {
|
|
|
263
267
|
};
|
|
264
268
|
}
|
|
265
269
|
var policy = product.cutOffPolicy;
|
|
270
|
+
// Current duration items can be shown outside business hours. Their real
|
|
271
|
+
// interval must remain unavailable, including products with no resource groups.
|
|
272
|
+
if (evaluationContext.useDurationTimeGrid && product.kind === 'duration' && !projection.meta.defaults.operatingHours.windows.some(function (window) {
|
|
273
|
+
var range = normalizeAbsoluteRange(window);
|
|
274
|
+
return range && contains(range, candidateRange);
|
|
275
|
+
})) {
|
|
276
|
+
return {
|
|
277
|
+
status: 'unavailable',
|
|
278
|
+
reasonCodes: ['outside_operating_hours'],
|
|
279
|
+
conflictCode: 'booking_cutoff'
|
|
280
|
+
};
|
|
281
|
+
}
|
|
266
282
|
if (!policy) return null;
|
|
267
283
|
if (resolveCutOffPolicyIssue(policy)) {
|
|
268
284
|
return {
|
|
@@ -299,8 +315,8 @@ function evaluateCandidateTimeGate(params) {
|
|
|
299
315
|
// otherwise a minute refresh turns it into 0 capacity and incorrectly
|
|
300
316
|
// advances a create flow to the next slot. The earlier `past` gate still
|
|
301
317
|
// rejects the anchor once its booking range has ended.
|
|
302
|
-
var isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
|
|
303
|
-
var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
|
|
318
|
+
var isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && !evaluationContext.enforceSaleCutoff && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
|
|
319
|
+
var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useDurationTimeGrid || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
|
|
304
320
|
var hasNotReachedStart = isActivePosDurationAnchor || (usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start);
|
|
305
321
|
if (hasNotReachedStart) return null;
|
|
306
322
|
return {
|
|
@@ -494,7 +510,7 @@ function normalizeResources(resources) {
|
|
|
494
510
|
});
|
|
495
511
|
}
|
|
496
512
|
function normalizeOperatingHours(params) {
|
|
497
|
-
var _params$input, _params$input2, _params$input3, _params$input4;
|
|
513
|
+
var _params$input, _params$input2, _params$input3, _params$input4, _params$input5, _params$input6;
|
|
498
514
|
var fallbackWindows = enumerateDates(params.dateRange.startDate, params.dateRange.endDate).map(function (date) {
|
|
499
515
|
var start = toDateTimeInDate(date, params.businessHours.startTime, params.timezoneName);
|
|
500
516
|
var end = toDateTimeInDate(date, params.businessHours.endTime, params.timezoneName);
|
|
@@ -530,11 +546,43 @@ function normalizeOperatingHours(params) {
|
|
|
530
546
|
};
|
|
531
547
|
var windows = normalizeWindows(sourceWindows);
|
|
532
548
|
var excludedWindows = normalizeWindows(((_params$input = params.input) === null || _params$input === void 0 ? void 0 : _params$input.excludedWindows) || []);
|
|
549
|
+
// Keep original dates and opening anchors separately: the availability
|
|
550
|
+
// windows below may be clipped at midnight or merged without segment identity.
|
|
551
|
+
var periodMap = new Map();
|
|
552
|
+
var originalPeriods = ((_params$input2 = params.input) === null || _params$input2 === void 0 ? void 0 : _params$input2.businessPeriods) || [].concat(_toConsumableArray(sourceWindows), _toConsumableArray(((_params$input3 = params.input) === null || _params$input3 === void 0 ? void 0 : _params$input3.excludedWindows) || [])).map(function (window) {
|
|
553
|
+
return {
|
|
554
|
+
businessDate: window.businessDate || window.startAt.slice(0, 10),
|
|
555
|
+
startAt: window.openingAnchorAt || window.startAt,
|
|
556
|
+
endAt: window.endAt
|
|
557
|
+
};
|
|
558
|
+
});
|
|
559
|
+
originalPeriods.forEach(function (period) {
|
|
560
|
+
var range = normalizeAbsoluteRange(period);
|
|
561
|
+
if (!range) return;
|
|
562
|
+
var previous = periodMap.get(period.businessDate);
|
|
563
|
+
periodMap.set(period.businessDate, {
|
|
564
|
+
start: previous ? Math.min(previous.start, range.start) : range.start,
|
|
565
|
+
end: previous ? Math.max(previous.end, range.end) : range.end
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
var businessPeriods = Array.from(periodMap, function (_ref) {
|
|
569
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
570
|
+
businessDate = _ref2[0],
|
|
571
|
+
range = _ref2[1];
|
|
572
|
+
return {
|
|
573
|
+
businessDate: businessDate,
|
|
574
|
+
startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
|
|
575
|
+
endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
|
|
576
|
+
};
|
|
577
|
+
}).sort(function (left, right) {
|
|
578
|
+
return left.startAt.localeCompare(right.startAt);
|
|
579
|
+
});
|
|
533
580
|
return _objectSpread({
|
|
534
|
-
source: ((_params$
|
|
535
|
-
scheduleIds: uniqById(((_params$
|
|
536
|
-
missingScheduleIds: uniqById(((_params$
|
|
537
|
-
windows: windows
|
|
581
|
+
source: ((_params$input4 = params.input) === null || _params$input4 === void 0 ? void 0 : _params$input4.source) || params.fallbackSource,
|
|
582
|
+
scheduleIds: uniqById(((_params$input5 = params.input) === null || _params$input5 === void 0 ? void 0 : _params$input5.scheduleIds) || []),
|
|
583
|
+
missingScheduleIds: uniqById(((_params$input6 = params.input) === null || _params$input6 === void 0 ? void 0 : _params$input6.missingScheduleIds) || []),
|
|
584
|
+
windows: windows,
|
|
585
|
+
businessPeriods: businessPeriods
|
|
538
586
|
}, excludedWindows.length > 0 ? {
|
|
539
587
|
excludedWindows: excludedWindows
|
|
540
588
|
} : {});
|
|
@@ -553,8 +601,8 @@ function matchesRequirementGroup(requirementGroup, resource, product) {
|
|
|
553
601
|
return resource.capacity >= resolveRequiredCapacity(requirementGroup, product, partySize);
|
|
554
602
|
}
|
|
555
603
|
function resolveRequiredCapacity(requirementGroup, product, partySize) {
|
|
556
|
-
var
|
|
557
|
-
return Math.max(1, Number((
|
|
604
|
+
var _ref3, _ref4;
|
|
605
|
+
return Math.max(1, Number((_ref3 = (_ref4 = partySize !== null && partySize !== void 0 ? partySize : requirementGroup.capacityRequired) !== null && _ref4 !== void 0 ? _ref4 : product.capacityRequired) !== null && _ref3 !== void 0 ? _ref3 : 1) || 1);
|
|
558
606
|
}
|
|
559
607
|
function buildCellKey(params) {
|
|
560
608
|
return [String(params.productId), params.groupId, String(params.resourceId), params.start, params.end].join(':');
|
|
@@ -608,8 +656,8 @@ function buildCells(projection) {
|
|
|
608
656
|
boundaries.add(window.start);
|
|
609
657
|
boundaries.add(window.end);
|
|
610
658
|
});
|
|
611
|
-
occupancies.forEach(function (
|
|
612
|
-
var range =
|
|
659
|
+
occupancies.forEach(function (_ref5) {
|
|
660
|
+
var range = _ref5.range;
|
|
613
661
|
boundaries.add(range.start);
|
|
614
662
|
boundaries.add(range.end);
|
|
615
663
|
});
|
|
@@ -627,11 +675,11 @@ function buildCells(projection) {
|
|
|
627
675
|
var isInsideWorkingWindow = windows.some(function (window) {
|
|
628
676
|
return contains(window, segment);
|
|
629
677
|
});
|
|
630
|
-
var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (
|
|
631
|
-
var range =
|
|
678
|
+
var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (_ref6) {
|
|
679
|
+
var range = _ref6.range;
|
|
632
680
|
return overlaps(range, segment);
|
|
633
|
-
}).map(function (
|
|
634
|
-
var occupancy =
|
|
681
|
+
}).map(function (_ref7) {
|
|
682
|
+
var occupancy = _ref7.occupancy;
|
|
635
683
|
return occupancy;
|
|
636
684
|
}) : [];
|
|
637
685
|
var usedCapacity = segmentOccupancies.reduce(function (sum, occupancy) {
|
|
@@ -1108,6 +1156,211 @@ function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection,
|
|
|
1108
1156
|
scheduleRefs: []
|
|
1109
1157
|
};
|
|
1110
1158
|
}
|
|
1159
|
+
|
|
1160
|
+
/** Resolve the label without changing the real calendar timestamp. */
|
|
1161
|
+
export function getDurationBusinessDate(projection, startAt) {
|
|
1162
|
+
var start = toDateTime(startAt);
|
|
1163
|
+
var periods = projection.meta.defaults.operatingHours.businessPeriods || [];
|
|
1164
|
+
var period = _toConsumableArray(periods).reverse().find(function (item) {
|
|
1165
|
+
var range = normalizeAbsoluteRange(item);
|
|
1166
|
+
return range && range.start <= start && start < range.end;
|
|
1167
|
+
});
|
|
1168
|
+
return (period === null || period === void 0 ? void 0 : period.businessDate) || startAt.slice(0, 10);
|
|
1169
|
+
}
|
|
1170
|
+
function getAlignedDurationRanges(params) {
|
|
1171
|
+
var _request$rememberedSt, _request$editingStart;
|
|
1172
|
+
var projection = params.projection,
|
|
1173
|
+
product = params.product,
|
|
1174
|
+
request = params.request,
|
|
1175
|
+
runtimeOptions = params.runtimeOptions,
|
|
1176
|
+
dateRange = params.dateRange,
|
|
1177
|
+
operatingRanges = params.operatingRanges,
|
|
1178
|
+
baseRanges = params.baseRanges,
|
|
1179
|
+
resourceWindowIndex = params.resourceWindowIndex,
|
|
1180
|
+
fixedOffsetMinutes = params.fixedOffsetMinutes;
|
|
1181
|
+
var step = projection.meta.defaults.slotStepMinutes;
|
|
1182
|
+
var now = floorToMinute(toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt));
|
|
1183
|
+
if (!Number.isFinite(now)) throw availabilityError('INVALID_TARGET_FILTER', 'evaluatedAt 必须是有效时间');
|
|
1184
|
+
var nowAt = formatDateTime(now, projection.meta.timezone, fixedOffsetMinutes);
|
|
1185
|
+
var currentBusinessDate = getDurationBusinessDate(projection, nowAt);
|
|
1186
|
+
var inRequestedDays = function inRequestedDays(date) {
|
|
1187
|
+
return date >= dateRange.startDate && date <= dateRange.endDate;
|
|
1188
|
+
};
|
|
1189
|
+
var periods = (projection.meta.defaults.operatingHours.businessPeriods || []).filter(function (period) {
|
|
1190
|
+
return inRequestedDays(period.businessDate);
|
|
1191
|
+
});
|
|
1192
|
+
// A prepared month includes tomorrow's windows too; the single-day UI must
|
|
1193
|
+
// receive the selected business cycle's end, not tomorrow's closing time.
|
|
1194
|
+
var operatingEndAt = dateRange.startDate === dateRange.endDate && periods.length ? periods.reduce(function (latest, period) {
|
|
1195
|
+
return period.endAt > latest ? period.endAt : latest;
|
|
1196
|
+
}, periods[0].endAt) : undefined;
|
|
1197
|
+
var ranges = [];
|
|
1198
|
+
var duration = resolveRequestedDurationMinutes(product, request);
|
|
1199
|
+
var addRange = function addRange(start, end, businessDate) {
|
|
1200
|
+
if (end <= start) return;
|
|
1201
|
+
var candidate = createDurationTimeRangeWithEnd(product, start, end, projection, fixedOffsetMinutes);
|
|
1202
|
+
candidate.businessDate = businessDate || getDurationBusinessDate(projection, candidate.startAt);
|
|
1203
|
+
if (inRequestedDays(candidate.businessDate)) ranges.push(candidate);
|
|
1204
|
+
};
|
|
1205
|
+
// A flexible end comes from resources that actually cover this exact start,
|
|
1206
|
+
// never from the next future window. Keep alternative real ends separate.
|
|
1207
|
+
var flexibleEnds = function flexibleEnds(start) {
|
|
1208
|
+
var _projection$meta$defa;
|
|
1209
|
+
var operating = operatingRanges.find(function (range) {
|
|
1210
|
+
return range.start <= start && start < range.end;
|
|
1211
|
+
});
|
|
1212
|
+
if (!operating) return [];
|
|
1213
|
+
var businessDate = getDurationBusinessDate(projection, formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes));
|
|
1214
|
+
var period = (_projection$meta$defa = projection.meta.defaults.operatingHours.businessPeriods) === null || _projection$meta$defa === void 0 ? void 0 : _projection$meta$defa.find(function (item) {
|
|
1215
|
+
return item.businessDate === businessDate;
|
|
1216
|
+
});
|
|
1217
|
+
var operatingEnd = Math.min(operating.end, period ? toDateTime(period.endAt) : operating.end);
|
|
1218
|
+
var requiredGroups = (product.requirementGroups || []).filter(function (group) {
|
|
1219
|
+
return group.required !== false;
|
|
1220
|
+
});
|
|
1221
|
+
var groups = requiredGroups.map(function (group) {
|
|
1222
|
+
return projection.resources.filter(function (resource) {
|
|
1223
|
+
return matchesRequirementGroup(group, resource, product, request.partySize);
|
|
1224
|
+
}).filter(function (resource) {
|
|
1225
|
+
var _request$resourceIds;
|
|
1226
|
+
return !((_request$resourceIds = request.resourceIds) !== null && _request$resourceIds !== void 0 && _request$resourceIds.length) || request.resourceIds.some(function (id) {
|
|
1227
|
+
return sameId(id, resource.id);
|
|
1228
|
+
});
|
|
1229
|
+
}).flatMap(function (resource) {
|
|
1230
|
+
return (resourceWindowIndex.get(String(resource.id)) || []).filter(function (range) {
|
|
1231
|
+
return range.start <= start && start < range.end;
|
|
1232
|
+
}).map(function (range) {
|
|
1233
|
+
return Math.min(range.end, operatingEnd);
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
if (groups.some(function (ends) {
|
|
1238
|
+
return ends.length === 0;
|
|
1239
|
+
})) return [];
|
|
1240
|
+
if (!groups.length) return [operatingEnd];
|
|
1241
|
+
return Array.from(new Set(groups.flat())).filter(function (end) {
|
|
1242
|
+
return groups.every(function (ends) {
|
|
1243
|
+
return ends.some(function (availableEnd) {
|
|
1244
|
+
return availableEnd >= end;
|
|
1245
|
+
});
|
|
1246
|
+
});
|
|
1247
|
+
}).sort(function (left, right) {
|
|
1248
|
+
return left - right;
|
|
1249
|
+
});
|
|
1250
|
+
};
|
|
1251
|
+
if (product.isFlexibleDuration) {
|
|
1252
|
+
// Preserve the existing continuous-window UI, with the business-day label.
|
|
1253
|
+
periods.forEach(function (period) {
|
|
1254
|
+
var periodRange = normalizeAbsoluteRange(period);
|
|
1255
|
+
baseRanges.forEach(function (range) {
|
|
1256
|
+
var start = Math.max(range.start, periodRange.start, now);
|
|
1257
|
+
var end = Math.min(range.end, periodRange.end);
|
|
1258
|
+
if (start < end) addRange(start, end, period.businessDate);
|
|
1259
|
+
});
|
|
1260
|
+
});
|
|
1261
|
+
} else {
|
|
1262
|
+
periods.forEach(function (period) {
|
|
1263
|
+
var periodRange = normalizeAbsoluteRange(period);
|
|
1264
|
+
var anchor = 60 % step === 0 ? toDateStart(period.businessDate) : periodRange.start;
|
|
1265
|
+
baseRanges.forEach(function (range) {
|
|
1266
|
+
var lower = Math.max(range.start, periodRange.start, now);
|
|
1267
|
+
var upper = Math.min(range.end, periodRange.end);
|
|
1268
|
+
var cursor = anchor + Math.ceil((lower - anchor) / (step * 60000)) * step * 60000;
|
|
1269
|
+
for (; cursor + duration * 60000 <= upper; cursor += step * 60000) {
|
|
1270
|
+
addRange(cursor, cursor + duration * 60000, period.businessDate);
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
var unavailableCurrentTime;
|
|
1276
|
+
if (inRequestedDays(currentBusinessDate)) {
|
|
1277
|
+
if (product.isFlexibleDuration) {
|
|
1278
|
+
var ends = flexibleEnds(now);
|
|
1279
|
+
ends.forEach(function (end) {
|
|
1280
|
+
return addRange(now, end, currentBusinessDate);
|
|
1281
|
+
});
|
|
1282
|
+
if (!ends.length) {
|
|
1283
|
+
unavailableCurrentTime = {
|
|
1284
|
+
productId: product.id,
|
|
1285
|
+
startAt: nowAt,
|
|
1286
|
+
date: formatDate(now),
|
|
1287
|
+
businessDate: currentBusinessDate,
|
|
1288
|
+
startTime: formatTime(now),
|
|
1289
|
+
status: 'unavailable',
|
|
1290
|
+
reasonCodes: [operatingRanges.some(function (range) {
|
|
1291
|
+
return range.start <= now && now < range.end;
|
|
1292
|
+
}) ? 'outside_resource_window' : 'outside_operating_hours']
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
} else {
|
|
1296
|
+
// Even outside a working window the fixed product has a real end. Query
|
|
1297
|
+
// reports unavailable; POS manual capabilities remain a separate policy.
|
|
1298
|
+
addRange(now, now + duration * 60000, currentBusinessDate);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
var rememberedAt = (_request$rememberedSt = request.rememberedStartAtByProductId) === null || _request$rememberedSt === void 0 ? void 0 : _request$rememberedSt[String(product.id)];
|
|
1302
|
+
if (rememberedAt !== undefined) {
|
|
1303
|
+
var start = toDateTime(rememberedAt);
|
|
1304
|
+
if (!Number.isFinite(start)) throw availabilityError('INVALID_TARGET_FILTER', '记忆开始时间必须是完整日期时间');
|
|
1305
|
+
if (product.isFlexibleDuration) {
|
|
1306
|
+
flexibleEnds(start).forEach(function (end) {
|
|
1307
|
+
return addRange(start, end);
|
|
1308
|
+
});
|
|
1309
|
+
} else {
|
|
1310
|
+
addRange(start, start + duration * 60000);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
var editingAt = (_request$editingStart = request.editingStartAtByProductId) === null || _request$editingStart === void 0 ? void 0 : _request$editingStart[String(product.id)];
|
|
1314
|
+
if (editingAt !== undefined) {
|
|
1315
|
+
var _request$durationMinu3;
|
|
1316
|
+
var _start = toDateTime(editingAt);
|
|
1317
|
+
var editingDuration = Number((_request$durationMinu3 = request.durationMinutesByProductId) === null || _request$durationMinu3 === void 0 ? void 0 : _request$durationMinu3[String(product.id)]);
|
|
1318
|
+
if (!Number.isFinite(_start) || !Number.isInteger(editingDuration) || editingDuration <= 0) {
|
|
1319
|
+
throw availabilityError('INVALID_TARGET_FILTER', '编辑时间必须包含完整开始日期时间和明确的正整数时长');
|
|
1320
|
+
}
|
|
1321
|
+
// Editing restores the original interval, including its actual overnight
|
|
1322
|
+
// date. It neither adopts the current grid nor recomputes a flexible end.
|
|
1323
|
+
if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
|
|
1324
|
+
return range.start <= _start && _start < range.end;
|
|
1325
|
+
})) {
|
|
1326
|
+
addRange(_start, addMinutesZoned(_start, editingDuration, projection.meta.timezone));
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// Explicit custom input keeps its existing start + requested duration
|
|
1331
|
+
// semantics. Remembered input above must never use this default-30 path.
|
|
1332
|
+
if (dateRange.startDate === dateRange.endDate) {
|
|
1333
|
+
resolveRequestedDurationStartTimes(product, request).forEach(function (startTime) {
|
|
1334
|
+
var sameDayStart = toDateTimeInDate(dateRange.startDate, startTime);
|
|
1335
|
+
var period = periods.find(function (item) {
|
|
1336
|
+
return item.businessDate === dateRange.startDate;
|
|
1337
|
+
});
|
|
1338
|
+
var periodRange = period ? normalizeAbsoluteRange(period) : null;
|
|
1339
|
+
var nextDayStart = addLocalCalendarDays(sameDayStart, 1);
|
|
1340
|
+
// HH:mm is entered within a selected business day, whose early hours
|
|
1341
|
+
// may belong to the next calendar day. Do not move other out-of-hours
|
|
1342
|
+
// manual input to tomorrow merely because the business closes overnight.
|
|
1343
|
+
var start = periodRange && !(periodRange.start <= sameDayStart && sameDayStart < periodRange.end) && periodRange.start <= nextDayStart && nextDayStart < periodRange.end ? nextDayStart : sameDayStart;
|
|
1344
|
+
if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
|
|
1345
|
+
return range.start <= start && start < range.end;
|
|
1346
|
+
})) {
|
|
1347
|
+
addRange(start, start + duration * 60000);
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
return _objectSpread(_objectSpread({
|
|
1352
|
+
productId: product.id,
|
|
1353
|
+
title: product.title,
|
|
1354
|
+
kind: product.kind,
|
|
1355
|
+
slotStepMinutes: step
|
|
1356
|
+
}, operatingEndAt ? {
|
|
1357
|
+
operatingEndAt: operatingEndAt
|
|
1358
|
+
} : {}), {}, {
|
|
1359
|
+
ranges: dedupeProductRanges(ranges)
|
|
1360
|
+
}, unavailableCurrentTime ? {
|
|
1361
|
+
unavailableCurrentTime: unavailableCurrentTime
|
|
1362
|
+
} : {});
|
|
1363
|
+
}
|
|
1111
1364
|
export function getProductTimeRanges(projection) {
|
|
1112
1365
|
var _extractFixedOffsetMi3, _request$productIds;
|
|
1113
1366
|
var request = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -1173,6 +1426,19 @@ export function getProductTimeRanges(projection) {
|
|
|
1173
1426
|
return current === null ? ranges : intersectRangeLists(current, ranges);
|
|
1174
1427
|
}, null) || [] : null;
|
|
1175
1428
|
var baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
1429
|
+
if (runtimeOptions.useDurationTimeGrid) {
|
|
1430
|
+
return getAlignedDurationRanges({
|
|
1431
|
+
projection: projection,
|
|
1432
|
+
product: product,
|
|
1433
|
+
request: request,
|
|
1434
|
+
runtimeOptions: runtimeOptions,
|
|
1435
|
+
dateRange: dateRange,
|
|
1436
|
+
operatingRanges: operatingRanges,
|
|
1437
|
+
baseRanges: baseRanges,
|
|
1438
|
+
resourceWindowIndex: resourceWindowIndex,
|
|
1439
|
+
fixedOffsetMinutes: fixedOffsetMinutes
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1176
1442
|
var durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
1177
1443
|
var flexibleStartAt = function () {
|
|
1178
1444
|
if (!product.isFlexibleDuration) return undefined;
|
|
@@ -1454,7 +1720,9 @@ function buildEvaluationContext(params) {
|
|
|
1454
1720
|
selectionsByGroupKey: selectionsByGroupKey,
|
|
1455
1721
|
useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
|
|
1456
1722
|
durationCandidateAnchorAtMs: Number.isFinite(durationCandidateAnchorAt) ? floorToMinute(durationCandidateAnchorAt) : null,
|
|
1457
|
-
allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
|
|
1723
|
+
allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true,
|
|
1724
|
+
useDurationTimeGrid: params.useDurationTimeGrid === true,
|
|
1725
|
+
enforceSaleCutoff: params.enforceSaleCutoff === true
|
|
1458
1726
|
};
|
|
1459
1727
|
}
|
|
1460
1728
|
function summarizeStatuses(statuses) {
|
|
@@ -1504,7 +1772,7 @@ function summarizeStatusAggregate(aggregate) {
|
|
|
1504
1772
|
return 'unavailable';
|
|
1505
1773
|
}
|
|
1506
1774
|
function evaluateMatchedResourceSummary(params) {
|
|
1507
|
-
var
|
|
1775
|
+
var _ref8, _params$matchedCell$m;
|
|
1508
1776
|
var isPast = params.candidateRange.endMs <= params.evaluationContext.evaluatedAtMs;
|
|
1509
1777
|
if (!params.matchedCell) {
|
|
1510
1778
|
return {
|
|
@@ -1516,7 +1784,7 @@ function evaluateMatchedResourceSummary(params) {
|
|
|
1516
1784
|
};
|
|
1517
1785
|
}
|
|
1518
1786
|
var remainingCapacity = Math.max(0, params.matchedCell.remainingCapacity || 0);
|
|
1519
|
-
var maxCapacity = Math.max(0, (
|
|
1787
|
+
var maxCapacity = Math.max(0, (_ref8 = (_params$matchedCell$m = params.matchedCell.maxCapacity) !== null && _params$matchedCell$m !== void 0 ? _params$matchedCell$m : params.resourceCapacity) !== null && _ref8 !== void 0 ? _ref8 : 0);
|
|
1520
1788
|
var maxPartySize = isPast ? 0 : remainingCapacity;
|
|
1521
1789
|
var status = function () {
|
|
1522
1790
|
if (isPast) return 'past';
|
|
@@ -1942,6 +2210,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
1942
2210
|
projection: projection,
|
|
1943
2211
|
evaluatedAt: evaluatedAt,
|
|
1944
2212
|
resourceIds: request.resourceIds,
|
|
2213
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2214
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
1945
2215
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
1946
2216
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
1947
2217
|
});
|
|
@@ -2032,6 +2302,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2032
2302
|
partySize: normalizedPartySize
|
|
2033
2303
|
}, {
|
|
2034
2304
|
evaluatedAt: evaluatedAt,
|
|
2305
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2306
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
2035
2307
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
2036
2308
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
2037
2309
|
});
|
|
@@ -2060,7 +2332,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2060
2332
|
candidateRangeCache: candidateRangeCache,
|
|
2061
2333
|
evaluationContext: evaluationContext
|
|
2062
2334
|
});
|
|
2063
|
-
var
|
|
2335
|
+
var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
|
|
2336
|
+
var aggregate = byDate.get(candidateDate) || {
|
|
2064
2337
|
availableCount: 0,
|
|
2065
2338
|
totalCount: 0,
|
|
2066
2339
|
maxPartySize: 0,
|
|
@@ -2080,8 +2353,26 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2080
2353
|
evaluated.reasonCodes.forEach(function (reasonCode) {
|
|
2081
2354
|
return aggregate.reasonCodeSet.add(reasonCode);
|
|
2082
2355
|
});
|
|
2083
|
-
byDate.set(
|
|
2356
|
+
byDate.set(candidateDate, aggregate);
|
|
2084
2357
|
});
|
|
2358
|
+
if (group.unavailableCurrentTime) {
|
|
2359
|
+
var current = group.unavailableCurrentTime;
|
|
2360
|
+
var aggregate = byDate.get(current.businessDate) || {
|
|
2361
|
+
availableCount: 0,
|
|
2362
|
+
totalCount: 0,
|
|
2363
|
+
maxPartySize: 0,
|
|
2364
|
+
remainingCapacity: 0,
|
|
2365
|
+
maxCapacity: 0,
|
|
2366
|
+
reasonCodeSet: new Set(),
|
|
2367
|
+
statusAggregate: createStatusAggregate()
|
|
2368
|
+
};
|
|
2369
|
+
aggregate.totalCount += 1;
|
|
2370
|
+
pushStatusAggregate(aggregate.statusAggregate, 'unavailable');
|
|
2371
|
+
current.reasonCodes.forEach(function (reason) {
|
|
2372
|
+
return aggregate.reasonCodeSet.add(reason);
|
|
2373
|
+
});
|
|
2374
|
+
byDate.set(current.businessDate, aggregate);
|
|
2375
|
+
}
|
|
2085
2376
|
var dates = enumerateDates(dateRange.startDate, dateRange.endDate).map(function (date) {
|
|
2086
2377
|
var aggregate = byDate.get(date);
|
|
2087
2378
|
return {
|
|
@@ -2143,10 +2434,22 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2143
2434
|
evaluated.reasonCodes.forEach(function (reasonCode) {
|
|
2144
2435
|
return productReasonCodeSet.add(reasonCode);
|
|
2145
2436
|
});
|
|
2146
|
-
var
|
|
2437
|
+
var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
|
|
2438
|
+
var dateAggregate = dateStatusMap.get(candidateDate) || createStatusAggregate();
|
|
2147
2439
|
pushStatusAggregate(dateAggregate, evaluated.status);
|
|
2148
|
-
dateStatusMap.set(
|
|
2440
|
+
dateStatusMap.set(candidateDate, dateAggregate);
|
|
2149
2441
|
});
|
|
2442
|
+
if (group.unavailableCurrentTime) {
|
|
2443
|
+
var current = group.unavailableCurrentTime;
|
|
2444
|
+
totalTimeCount += 1;
|
|
2445
|
+
pushStatusAggregate(productStatusAggregate, 'unavailable');
|
|
2446
|
+
current.reasonCodes.forEach(function (reason) {
|
|
2447
|
+
return productReasonCodeSet.add(reason);
|
|
2448
|
+
});
|
|
2449
|
+
var dateAggregate = dateStatusMap.get(current.businessDate) || createStatusAggregate();
|
|
2450
|
+
pushStatusAggregate(dateAggregate, 'unavailable');
|
|
2451
|
+
dateStatusMap.set(current.businessDate, dateAggregate);
|
|
2452
|
+
}
|
|
2150
2453
|
var availableDateCount = Array.from(dateStatusMap.values()).filter(function (aggregate) {
|
|
2151
2454
|
var status = summarizeStatusAggregate(aggregate);
|
|
2152
2455
|
return status === 'available' || status === 'limited';
|
|
@@ -2233,6 +2536,8 @@ export function validateAvailabilitySelection(projection, params) {
|
|
|
2233
2536
|
projection: projection,
|
|
2234
2537
|
evaluatedAt: evaluatedAt,
|
|
2235
2538
|
requirementSelections: params.requirementSelections,
|
|
2539
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2540
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
2236
2541
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
2237
2542
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
2238
2543
|
})
|