@pisell/pisellos 0.0.569 → 0.10.2
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/core/index.js +10 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -3
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +7 -5
- package/dist/model/strategy/adapter/walletPass/example.js +26 -3
- package/dist/model/strategy/adapter/walletPass/index.js +5 -5
- package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +17 -92
- package/dist/model/strategy/strategy-example.js +19 -5
- package/dist/modules/BaseModule.d.ts +1 -1
- package/dist/modules/BaseModule.js +8 -10
- package/dist/modules/Cart/index.js +3 -0
- package/dist/modules/Cart/utils/cartProduct.js +1 -0
- package/dist/modules/Cart/utils/cartResource.js +0 -2
- package/dist/modules/Cart/utils/changePrice.js +9 -16
- package/dist/modules/Date/index.js +5 -1
- package/dist/modules/Discount/index.d.ts +0 -1
- package/dist/modules/Discount/index.js +7 -22
- package/dist/modules/Discount/types.d.ts +0 -1
- package/dist/modules/OpenData/index.js +2 -0
- package/dist/modules/Order/index.js +70 -40
- package/dist/modules/Payment/index.js +162 -97
- package/dist/modules/Payment/types.d.ts +4 -8
- package/dist/modules/Payment/walletpass.d.ts +0 -2
- package/dist/modules/Payment/walletpass.js +5 -4
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +3 -12
- package/dist/modules/ProductList/types.d.ts +0 -1
- package/dist/modules/Rules/index.js +126 -427
- package/dist/modules/SalesSummary/utils.js +1 -2
- package/dist/modules/Schedule/getDateIsInSchedule.js +0 -5
- package/dist/modules/Schedule/index.js +1 -0
- package/dist/modules/Schedule/utils.js +1 -0
- package/dist/modules/Step/index.js +1 -0
- package/dist/modules/Summary/utils.js +22 -43
- package/dist/plugins/request.js +4 -1
- package/dist/plugins/window.js +6 -2
- package/dist/server/index.js +129 -97
- package/dist/server/modules/menu/index.js +41 -32
- package/dist/server/modules/order/index.js +4 -2
- package/dist/server/modules/products/index.js +42 -24
- package/dist/server/modules/quotation/index.js +38 -29
- package/dist/server/modules/resource/index.js +4 -3
- package/dist/server/modules/schedule/index.js +35 -27
- package/dist/server/utils/product.js +1 -0
- package/dist/solution/BaseSales/index.js +41 -38
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +60 -11
- package/dist/solution/BookingByStep/utils/capacity.js +11 -1
- package/dist/solution/BookingByStep/utils/resources.js +3 -1
- package/dist/solution/BookingByStep/utils/timeslots.js +43 -2
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +2 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +7 -6
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +31 -25
- package/dist/solution/BookingTicket/utils/scan/index.js +10 -6
- package/dist/solution/BuyTickets/index.js +12 -9
- package/dist/solution/Checkout/index.js +252 -177
- package/dist/solution/Checkout/utils/index.js +16 -4
- package/dist/solution/RegisterAndLogin/index.js +76 -30
- package/dist/solution/ScanOrder/index.js +60 -50
- package/dist/solution/ShopDiscount/index.js +14 -15
- package/dist/solution/ShopDiscount/types.d.ts +4 -5
- package/dist/solution/ShopDiscount/utils.d.ts +0 -9
- package/dist/solution/ShopDiscount/utils.js +0 -9
- package/dist/solution/VenueBooking/index.d.ts +3 -31
- package/dist/solution/VenueBooking/index.js +496 -651
- package/dist/solution/VenueBooking/types.d.ts +1 -3
- package/dist/solution/VenueBooking/types.js +0 -1
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/task.js +18 -15
- package/dist/utils/watch.js +1 -0
- package/lib/apis/picoding.js +0 -2
- package/lib/core/index.js +132 -130
- package/lib/effects/index.js +57 -46
- package/lib/index.d.ts +0 -1
- package/lib/index.js +50 -92
- package/lib/model/index.js +21 -14
- package/lib/model/strategy/adapter/dataVariant/adapter.js +50 -38
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +236 -162
- package/lib/model/strategy/adapter/dataVariant/examples.js +237 -229
- package/lib/model/strategy/adapter/dataVariant/index.js +34 -39
- package/lib/model/strategy/adapter/dataVariant/type.js +28 -57
- package/lib/model/strategy/adapter/index.js +64 -100
- package/lib/model/strategy/adapter/itemRule/adapter.js +144 -156
- package/lib/model/strategy/adapter/itemRule/evaluator.js +48 -36
- package/lib/model/strategy/adapter/itemRule/examples.js +225 -295
- package/lib/model/strategy/adapter/itemRule/index.js +57 -83
- package/lib/model/strategy/adapter/itemRule/type.js +36 -97
- package/lib/model/strategy/adapter/promotion/adapter.js +63 -84
- package/lib/model/strategy/adapter/promotion/evaluator.js +231 -381
- package/lib/model/strategy/adapter/promotion/examples.js +159 -139
- package/lib/model/strategy/adapter/promotion/index.js +49 -1
- package/lib/model/strategy/adapter/promotion/type.js +35 -199
- package/lib/model/strategy/adapter/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/evaluator.js +152 -180
- package/lib/model/strategy/adapter/walletPass/example.js +190 -217
- package/lib/model/strategy/adapter/walletPass/index.js +51 -75
- package/lib/model/strategy/adapter/walletPass/locales.js +58 -36
- package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/lib/model/strategy/adapter/walletPass/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/lib/model/strategy/adapter/walletPass/utils.js +383 -678
- package/lib/model/strategy/engine.js +168 -270
- package/lib/model/strategy/index.js +34 -49
- package/lib/model/strategy/strategy-example.js +239 -243
- package/lib/model/strategy/type.js +40 -100
- package/lib/modules/Account/index.js +53 -39
- package/lib/modules/Account/types.js +33 -20
- package/lib/modules/AccountList/index.js +154 -116
- package/lib/modules/AccountList/types.js +31 -30
- package/lib/modules/AccountList/utils.js +30 -18
- package/lib/modules/BaseModule.d.ts +1 -1
- package/lib/modules/BaseModule.js +46 -25
- package/lib/modules/BookingContext/index.js +136 -158
- package/lib/modules/BookingContext/types.js +32 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +143 -131
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +82 -75
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +150 -170
- package/lib/modules/BookingContext/utils/flexible.js +55 -38
- package/lib/modules/BookingContext/utils/formatResourceList.js +34 -19
- package/lib/modules/BookingContext/utils/index.js +41 -124
- package/lib/modules/BookingContext/utils/noResource.js +70 -58
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +41 -14
- package/lib/modules/BookingContext/utils/productExtend.js +155 -202
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +41 -19
- package/lib/modules/BookingContext/utils/resources.js +167 -209
- package/lib/modules/BookingContext/utils/serviceTimes.js +116 -115
- package/lib/modules/BookingContext/utils/timeSlices.js +80 -70
- package/lib/modules/Cart/index.js +124 -170
- package/lib/modules/Cart/types.js +51 -46
- package/lib/modules/Cart/utils/cartAccount.js +39 -40
- package/lib/modules/Cart/utils/cartDate.js +61 -56
- package/lib/modules/Cart/utils/cartDiscount.js +33 -28
- package/lib/modules/Cart/utils/cartNote.js +32 -27
- package/lib/modules/Cart/utils/cartProduct.js +251 -321
- package/lib/modules/Cart/utils/cartRelationForms.js +35 -29
- package/lib/modules/Cart/utils/cartResource.js +78 -72
- package/lib/modules/Cart/utils/changePrice.js +50 -28
- package/lib/modules/Cart/utils/index.js +48 -106
- package/lib/modules/Customer/constants.js +34 -13
- package/lib/modules/Customer/index.js +169 -232
- package/lib/modules/Customer/types.js +35 -38
- package/lib/modules/Date/index.js +115 -116
- package/lib/modules/Date/types.js +28 -16
- package/lib/modules/Date/utils.js +123 -174
- package/lib/modules/Discount/index.d.ts +0 -1
- package/lib/modules/Discount/index.js +128 -130
- package/lib/modules/Discount/types.d.ts +0 -1
- package/lib/modules/Discount/types.js +31 -9
- package/lib/modules/Guests/index.js +56 -30
- package/lib/modules/Guests/types.js +33 -23
- package/lib/modules/Holder/index.js +189 -209
- package/lib/modules/Holder/types.js +16 -4
- package/lib/modules/Holder/utils.js +49 -20
- package/lib/modules/OpenData/index.js +76 -69
- package/lib/modules/OpenData/types.js +16 -4
- package/lib/modules/OpenData/utils.js +78 -44
- package/lib/modules/Order/index.js +1909 -1572
- package/lib/modules/Order/types.js +35 -78
- package/lib/modules/Order/utils/bundleDiscountHydration.js +74 -41
- package/lib/modules/Order/utils/manualProductDiscount.js +123 -124
- package/lib/modules/Order/utils/orderCollectionIdentity.js +210 -148
- package/lib/modules/Order/utils.js +634 -799
- package/lib/modules/Payment/cash.js +33 -20
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +76 -145
- package/lib/modules/Payment/eftpos.js +30 -16
- package/lib/modules/Payment/index.js +378 -518
- package/lib/modules/Payment/mx51.js +0 -1
- package/lib/modules/Payment/types.d.ts +4 -8
- package/lib/modules/Payment/types.js +107 -216
- package/lib/modules/Payment/utils.js +48 -51
- package/lib/modules/Payment/walletpass.d.ts +0 -2
- package/lib/modules/Payment/walletpass.js +211 -226
- package/lib/modules/Product/index.js +46 -51
- package/lib/modules/Product/types.js +16 -4
- package/lib/modules/Product/utils.js +33 -32
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +117 -117
- package/lib/modules/ProductList/types.d.ts +0 -1
- package/lib/modules/ProductList/types.js +31 -9
- package/lib/modules/Quotation/index.js +100 -66
- package/lib/modules/Quotation/types.js +16 -4
- package/lib/modules/Resource/index.js +59 -27
- package/lib/modules/Resource/types.js +32 -22
- package/lib/modules/Resource/utils.js +38 -30
- package/lib/modules/ResourcePlanner/index.js +61 -60
- package/lib/modules/ResourcePlanner/planner.js +384 -346
- package/lib/modules/ResourcePlanner/types.js +16 -4
- package/lib/modules/Rules/index.js +903 -1475
- package/lib/modules/Rules/types.js +40 -17
- package/lib/modules/SalesSummary/index.js +90 -85
- package/lib/modules/SalesSummary/types.js +16 -4
- package/lib/modules/SalesSummary/utils.js +427 -351
- package/lib/modules/ScanOrderLogger/index.js +79 -59
- package/lib/modules/ScanOrderLogger/providers/feishu.js +78 -54
- package/lib/modules/ScanOrderLogger/providers/grafana.js +36 -13
- package/lib/modules/ScanOrderLogger/types.js +16 -4
- package/lib/modules/Schedule/getDateIsInSchedule.js +163 -339
- package/lib/modules/Schedule/index.js +114 -100
- package/lib/modules/Schedule/type.js +16 -4
- package/lib/modules/Schedule/types.js +16 -4
- package/lib/modules/Schedule/utils.js +291 -433
- package/lib/modules/Step/index.js +52 -40
- package/lib/modules/Step/tyeps.js +16 -4
- package/lib/modules/Summary/index.js +71 -66
- package/lib/modules/Summary/types.js +16 -4
- package/lib/modules/Summary/utils.js +418 -791
- package/lib/modules/SurchargeList/index.js +60 -46
- package/lib/modules/SurchargeList/types.js +16 -4
- package/lib/modules/index.js +63 -245
- package/lib/plugins/app.js +16 -4
- package/lib/plugins/index.js +25 -36
- package/lib/plugins/request.js +126 -137
- package/lib/plugins/shopStore.js +16 -4
- package/lib/plugins/user.js +16 -4
- package/lib/plugins/window.js +179 -171
- package/lib/server/index.js +2337 -2675
- package/lib/server/modules/floor-plan/index.js +123 -102
- package/lib/server/modules/floor-plan/types.js +30 -15
- package/lib/server/modules/index.js +68 -106
- package/lib/server/modules/menu/index.js +122 -146
- package/lib/server/modules/menu/types.js +31 -18
- package/lib/server/modules/order/index.js +642 -567
- package/lib/server/modules/order/types.js +32 -117
- package/lib/server/modules/order/utils/filterBookings.js +194 -219
- package/lib/server/modules/order/utils/filterOrders.js +92 -118
- package/lib/server/modules/payment/index.js +83 -59
- package/lib/server/modules/payment/types.js +16 -4
- package/lib/server/modules/products/index.js +459 -575
- package/lib/server/modules/products/types.js +34 -44
- package/lib/server/modules/quotation/index.js +172 -137
- package/lib/server/modules/quotation/types.js +31 -21
- package/lib/server/modules/resource/index.js +184 -213
- package/lib/server/modules/resource/types.js +33 -42
- package/lib/server/modules/schedule/index.js +123 -135
- package/lib/server/modules/schedule/types.js +21 -14
- package/lib/server/modules/schedule/utils.js +163 -334
- package/lib/server/types.js +16 -4
- package/lib/server/utils/index.js +23 -25
- package/lib/server/utils/product.js +139 -196
- package/lib/server/utils/schedule.js +41 -34
- package/lib/server/utils/small-ticket.js +456 -478
- package/lib/server/utils/time.js +49 -40
- package/lib/solution/BaseSales/index.js +1016 -850
- package/lib/solution/BaseSales/types.js +37 -41
- package/lib/solution/BaseSales/utils/cartPromotion.js +460 -611
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +105 -85
- package/lib/solution/BaseSales/utils/quotationPrice.js +114 -56
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +143 -102
- package/lib/solution/BaseSales/utils.js +140 -155
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1340 -1530
- package/lib/solution/BookingByStep/types.js +99 -40
- package/lib/solution/BookingByStep/utils/capacity.js +160 -192
- package/lib/solution/BookingByStep/utils/products.js +52 -42
- package/lib/solution/BookingByStep/utils/resources.js +330 -527
- package/lib/solution/BookingByStep/utils/stock.js +44 -65
- package/lib/solution/BookingByStep/utils/timeslots.js +131 -129
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +459 -543
- package/lib/solution/BookingTicket/types.js +77 -99
- package/lib/solution/BookingTicket/utils/addProductDecision.js +184 -219
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +89 -58
- package/lib/solution/BookingTicket/utils/bookingStatus.js +78 -107
- package/lib/solution/BookingTicket/utils/cartView.js +94 -110
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -185
- package/lib/solution/BookingTicket/utils/orderCustomer.js +41 -18
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +86 -219
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +93 -144
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +91 -79
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +41 -54
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -84
- package/lib/solution/BookingTicket/utils/scan/index.js +104 -98
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +64 -52
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +58 -56
- package/lib/solution/BuyTickets/index.js +70 -67
- package/lib/solution/BuyTickets/types.js +38 -22
- package/lib/solution/Checkout/index.js +1158 -1451
- package/lib/solution/Checkout/types.js +61 -91
- package/lib/solution/Checkout/utils/index.js +156 -228
- package/lib/solution/PlaceOrder/index.js +0 -55
- package/lib/solution/RegisterAndLogin/config.js +460 -493
- package/lib/solution/RegisterAndLogin/index.js +630 -633
- package/lib/solution/RegisterAndLogin/types.js +76 -189
- package/lib/solution/RegisterAndLogin/utils.js +125 -183
- package/lib/solution/Sales/index.js +320 -317
- package/lib/solution/Sales/types.js +33 -27
- package/lib/solution/ScanOrder/index.js +862 -831
- package/lib/solution/ScanOrder/types.js +34 -33
- package/lib/solution/ScanOrder/utils.js +371 -406
- package/lib/solution/ShopDiscount/index.js +233 -235
- package/lib/solution/ShopDiscount/types.d.ts +4 -5
- package/lib/solution/ShopDiscount/types.js +37 -15
- package/lib/solution/ShopDiscount/utils.d.ts +0 -9
- package/lib/solution/ShopDiscount/utils.js +172 -309
- package/lib/solution/UnifiedBookingSales/index.js +405 -379
- package/lib/solution/UnifiedBookingSales/types.js +31 -12
- package/lib/solution/VenueBooking/index.d.ts +3 -31
- package/lib/solution/VenueBooking/index.js +916 -967
- package/lib/solution/VenueBooking/types.d.ts +1 -3
- package/lib/solution/VenueBooking/types.js +39 -20
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/lib/solution/VenueBooking/utils/dateSummary.js +62 -25
- package/lib/solution/VenueBooking/utils/resource.js +54 -31
- package/lib/solution/VenueBooking/utils/slotMerge.js +107 -94
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -138
- package/lib/solution/VenueBooking/utils.js +67 -130
- package/lib/solution/index.js +41 -124
- package/lib/store/createStore.js +29 -32
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +16 -4
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +47 -81
- package/package.json +2 -4
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
|
@@ -1,27 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
28
|
|
|
3
|
-
|
|
4
|
-
|
|
29
|
+
// src/modules/ResourcePlanner/planner.ts
|
|
30
|
+
var planner_exports = {};
|
|
31
|
+
__export(planner_exports, {
|
|
32
|
+
DEFAULT_RESOURCE_PLANNER_CONTEXT: () => DEFAULT_RESOURCE_PLANNER_CONTEXT,
|
|
33
|
+
DEFAULT_RESOURCE_PLANNER_SELECTION: () => DEFAULT_RESOURCE_PLANNER_SELECTION,
|
|
34
|
+
autoAssignResources: () => autoAssignResources,
|
|
35
|
+
buildDemandIntervals: () => buildDemandIntervals,
|
|
36
|
+
evaluateResourceForInterval: () => evaluateResourceForInterval,
|
|
37
|
+
normalizePlannerContext: () => normalizePlannerContext,
|
|
38
|
+
queryPlannerAvailability: () => queryPlannerAvailability,
|
|
39
|
+
resolveAssignableSlots: () => resolveAssignableSlots,
|
|
40
|
+
validateAssignments: () => validateAssignments
|
|
5
41
|
});
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
exports.evaluateResourceForInterval = evaluateResourceForInterval;
|
|
10
|
-
exports.normalizePlannerContext = normalizePlannerContext;
|
|
11
|
-
exports.queryPlannerAvailability = queryPlannerAvailability;
|
|
12
|
-
exports.resolveAssignableSlots = resolveAssignableSlots;
|
|
13
|
-
exports.validateAssignments = validateAssignments;
|
|
14
|
-
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
15
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
-
const DEFAULT_RESOURCE_PLANNER_CONTEXT = exports.DEFAULT_RESOURCE_PLANNER_CONTEXT = {
|
|
42
|
+
module.exports = __toCommonJS(planner_exports);
|
|
43
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
44
|
+
var DEFAULT_RESOURCE_PLANNER_CONTEXT = {
|
|
17
45
|
products: [],
|
|
18
46
|
resources: [],
|
|
19
47
|
externalEvents: [],
|
|
20
48
|
slotDurationMinutes: 30,
|
|
21
|
-
businessStartTime:
|
|
22
|
-
businessEndTime:
|
|
49
|
+
businessStartTime: "09:00",
|
|
50
|
+
businessEndTime: "18:00"
|
|
23
51
|
};
|
|
24
|
-
|
|
52
|
+
var DEFAULT_RESOURCE_PLANNER_SELECTION = {
|
|
25
53
|
productIds: [],
|
|
26
54
|
resourceIds: [],
|
|
27
55
|
assignments: []
|
|
@@ -40,14 +68,15 @@ function sameId(left, right) {
|
|
|
40
68
|
return String(left) === String(right);
|
|
41
69
|
}
|
|
42
70
|
function dateOf(value) {
|
|
43
|
-
return (0,
|
|
71
|
+
return (0, import_dayjs.default)(value).format("YYYY-MM-DD");
|
|
44
72
|
}
|
|
45
73
|
function timeOf(value) {
|
|
46
|
-
return (0,
|
|
74
|
+
return (0, import_dayjs.default)(value).format("HH:mm");
|
|
47
75
|
}
|
|
48
76
|
function toDateTime(date, time) {
|
|
49
|
-
if (/^\d{4}-\d{2}-\d{2}/.test(time))
|
|
50
|
-
|
|
77
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(time))
|
|
78
|
+
return (0, import_dayjs.default)(time);
|
|
79
|
+
return (0, import_dayjs.default)(`${date} ${time.length === 5 ? `${time}:00` : time}`);
|
|
51
80
|
}
|
|
52
81
|
function overlaps(startA, endA, startB, endB) {
|
|
53
82
|
return startA.isBefore(endB) && endA.isAfter(startB);
|
|
@@ -63,36 +92,44 @@ function minDayjs(left, right) {
|
|
|
63
92
|
}
|
|
64
93
|
function addDays(start, end) {
|
|
65
94
|
const result = [];
|
|
66
|
-
let cursor = (0,
|
|
67
|
-
const finalDay = (0,
|
|
68
|
-
while (!cursor.isAfter(finalDay,
|
|
69
|
-
result.push(cursor.format(
|
|
70
|
-
cursor = cursor.add(1,
|
|
95
|
+
let cursor = (0, import_dayjs.default)(start);
|
|
96
|
+
const finalDay = (0, import_dayjs.default)(end);
|
|
97
|
+
while (!cursor.isAfter(finalDay, "day")) {
|
|
98
|
+
result.push(cursor.format("YYYY-MM-DD"));
|
|
99
|
+
cursor = cursor.add(1, "day");
|
|
71
100
|
}
|
|
72
101
|
return result;
|
|
73
102
|
}
|
|
74
103
|
function getQueryProducts(products, query) {
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
var _a;
|
|
105
|
+
if (!((_a = query.productIds) == null ? void 0 : _a.length))
|
|
106
|
+
return products;
|
|
107
|
+
return products.filter((product) => query.productIds.some((id) => sameId(id, product.id)));
|
|
77
108
|
}
|
|
78
109
|
function getQueryResources(resources, query) {
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
var _a;
|
|
111
|
+
if (!((_a = query.resourceIds) == null ? void 0 : _a.length))
|
|
112
|
+
return resources;
|
|
113
|
+
return resources.filter((resource) => query.resourceIds.some((id) => sameId(id, resource.id)));
|
|
81
114
|
}
|
|
82
115
|
function matchesResourceRequirement(resource, requirement) {
|
|
116
|
+
var _a;
|
|
83
117
|
const isFormlessCandidate = resource.formId == null;
|
|
84
118
|
const formMatches = requirement.formId == null || isFormlessCandidate || sameId(requirement.formId, resource.formId);
|
|
85
|
-
const resourceMatches = !requirement.resourceIds
|
|
119
|
+
const resourceMatches = !((_a = requirement.resourceIds) == null ? void 0 : _a.length) || isFormlessCandidate || requirement.resourceIds.some((id) => sameId(id, resource.id));
|
|
86
120
|
return formMatches && resourceMatches;
|
|
87
121
|
}
|
|
88
122
|
function resolveProductTitle(product) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (typeof
|
|
92
|
-
|
|
123
|
+
var _a, _b, _c;
|
|
124
|
+
const rawTitle = ((_a = product.raw) == null ? void 0 : _a.title) || ((_b = product.raw) == null ? void 0 : _b.name) || ((_c = product.raw) == null ? void 0 : _c.product_title);
|
|
125
|
+
if (typeof product.title === "string")
|
|
126
|
+
return product.title;
|
|
127
|
+
if (typeof rawTitle === "string")
|
|
128
|
+
return rawTitle;
|
|
129
|
+
if (rawTitle && typeof rawTitle === "object") {
|
|
93
130
|
return rawTitle.en || rawTitle.zh || rawTitle.default || Object.values(rawTitle)[0];
|
|
94
131
|
}
|
|
95
|
-
return
|
|
132
|
+
return void 0;
|
|
96
133
|
}
|
|
97
134
|
function buildDemandIntervals(products, query, context) {
|
|
98
135
|
const dates = query.date ? [query.date] : query.dateRange ? addDays(query.dateRange.start, query.dateRange.end) : [];
|
|
@@ -102,13 +139,14 @@ function buildDemandIntervals(products, query, context) {
|
|
|
102
139
|
const quantity = Math.max(1, Number(product.quantity || 1));
|
|
103
140
|
const capacityRequired = Math.max(1, Number(query.pax || product.capacityRequired || 1));
|
|
104
141
|
const requirements = product.resourceRequirements || [];
|
|
105
|
-
if (product.kind ===
|
|
142
|
+
if (product.kind === "session" || product.kind === "venue_slot") {
|
|
106
143
|
const schedules = product.schedule || [];
|
|
107
144
|
for (const schedule of schedules) {
|
|
108
145
|
const scheduleDate = dateOf(schedule.start_at);
|
|
109
|
-
if (dates.length > 0 && !dates.includes(scheduleDate))
|
|
110
|
-
|
|
111
|
-
const
|
|
146
|
+
if (dates.length > 0 && !dates.includes(scheduleDate))
|
|
147
|
+
continue;
|
|
148
|
+
const start = (0, import_dayjs.default)(schedule.start_at);
|
|
149
|
+
const end = (0, import_dayjs.default)(schedule.end_at);
|
|
112
150
|
intervals.push({
|
|
113
151
|
id: `${product.id}:${start.toISOString()}:${end.toISOString()}`,
|
|
114
152
|
productId: product.id,
|
|
@@ -116,7 +154,7 @@ function buildDemandIntervals(products, query, context) {
|
|
|
116
154
|
date: dateOf(schedule.start_at),
|
|
117
155
|
start_at: start.toISOString(),
|
|
118
156
|
end_at: end.toISOString(),
|
|
119
|
-
durationMinutes: Math.max(1, end.diff(start,
|
|
157
|
+
durationMinutes: Math.max(1, end.diff(start, "minute")),
|
|
120
158
|
quantity,
|
|
121
159
|
capacityRequired,
|
|
122
160
|
resourceRequirements: requirements
|
|
@@ -124,16 +162,17 @@ function buildDemandIntervals(products, query, context) {
|
|
|
124
162
|
}
|
|
125
163
|
continue;
|
|
126
164
|
}
|
|
127
|
-
if (product.kind ===
|
|
165
|
+
if (product.kind === "duration") {
|
|
128
166
|
const duration = Math.max(1, Number(product.durationMinutes || 30));
|
|
129
167
|
for (const currentDate of dates) {
|
|
130
|
-
const start = query.startTime ? toDateTime(currentDate, query.startTime) : toDateTime(currentDate, context
|
|
131
|
-
let end = query.startTime && query.endTime ? toDateTime(currentDate, query.endTime) : query.startTime ? start.add(duration,
|
|
132
|
-
if (!end.isAfter(start))
|
|
168
|
+
const start = query.startTime ? toDateTime(currentDate, query.startTime) : toDateTime(currentDate, (context == null ? void 0 : context.businessStartTime) || DEFAULT_RESOURCE_PLANNER_CONTEXT.businessStartTime);
|
|
169
|
+
let end = query.startTime && query.endTime ? toDateTime(currentDate, query.endTime) : query.startTime ? start.add(duration, "minute") : toDateTime(currentDate, (context == null ? void 0 : context.businessEndTime) || DEFAULT_RESOURCE_PLANNER_CONTEXT.businessEndTime);
|
|
170
|
+
if (!end.isAfter(start))
|
|
171
|
+
end = end.add(1, "day");
|
|
133
172
|
intervals.push({
|
|
134
|
-
id: `${product.id}:${currentDate}:${query.startTime ||
|
|
173
|
+
id: `${product.id}:${currentDate}:${query.startTime || "range"}`,
|
|
135
174
|
productId: product.id,
|
|
136
|
-
source:
|
|
175
|
+
source: "duration",
|
|
137
176
|
date: currentDate,
|
|
138
177
|
start_at: start.toISOString(),
|
|
139
178
|
end_at: end.toISOString(),
|
|
@@ -148,83 +187,75 @@ function buildDemandIntervals(products, query, context) {
|
|
|
148
187
|
return intervals;
|
|
149
188
|
}
|
|
150
189
|
function getEventsForResource(resource, contextEvents) {
|
|
151
|
-
const embeddedEvents = resource.times.flatMap(time => time.event_list || []);
|
|
152
|
-
return [
|
|
190
|
+
const embeddedEvents = resource.times.flatMap((time) => time.event_list || []);
|
|
191
|
+
return [
|
|
192
|
+
...embeddedEvents,
|
|
193
|
+
...contextEvents.filter((event) => sameId(event.resourceId ?? event.resource_id, resource.id))
|
|
194
|
+
].filter(Boolean);
|
|
153
195
|
}
|
|
154
196
|
function collectEventsByResource(resources, contextEvents) {
|
|
155
|
-
const eventsByResource = new Map();
|
|
156
|
-
resources.forEach(resource => {
|
|
197
|
+
const eventsByResource = /* @__PURE__ */ new Map();
|
|
198
|
+
resources.forEach((resource) => {
|
|
157
199
|
eventsByResource.set(String(resource.id), getEventsForResource(resource, contextEvents));
|
|
158
200
|
});
|
|
159
201
|
return eventsByResource;
|
|
160
202
|
}
|
|
161
203
|
function getWorkingSegmentsForInterval(resource, interval) {
|
|
162
|
-
const intervalStart = (0,
|
|
163
|
-
const intervalEnd = (0,
|
|
164
|
-
return resource.times.map(time => {
|
|
165
|
-
const start = maxDayjs((0,
|
|
166
|
-
const end = minDayjs((0,
|
|
167
|
-
return {
|
|
168
|
-
|
|
169
|
-
end
|
|
170
|
-
};
|
|
171
|
-
}).filter(segment => segment.end.isAfter(segment.start));
|
|
204
|
+
const intervalStart = (0, import_dayjs.default)(interval.start_at);
|
|
205
|
+
const intervalEnd = (0, import_dayjs.default)(interval.end_at);
|
|
206
|
+
return resource.times.map((time) => {
|
|
207
|
+
const start = maxDayjs((0, import_dayjs.default)(time.start_at), intervalStart);
|
|
208
|
+
const end = minDayjs((0, import_dayjs.default)(time.end_at), intervalEnd);
|
|
209
|
+
return { start, end };
|
|
210
|
+
}).filter((segment) => segment.end.isAfter(segment.start));
|
|
172
211
|
}
|
|
173
212
|
function mergeBusySegments(segments) {
|
|
174
|
-
const sorted = [...segments].filter(segment => segment.end.isAfter(segment.start)).sort((left, right) => left.start.valueOf() - right.start.valueOf());
|
|
213
|
+
const sorted = [...segments].filter((segment) => segment.end.isAfter(segment.start)).sort((left, right) => left.start.valueOf() - right.start.valueOf());
|
|
175
214
|
const merged = [];
|
|
176
|
-
sorted.forEach(segment => {
|
|
215
|
+
sorted.forEach((segment) => {
|
|
177
216
|
const previous = merged[merged.length - 1];
|
|
178
217
|
if (previous && !segment.start.isAfter(previous.end)) {
|
|
179
218
|
previous.end = maxDayjs(previous.end, segment.end);
|
|
180
219
|
} else {
|
|
181
|
-
merged.push({
|
|
182
|
-
...segment
|
|
183
|
-
});
|
|
220
|
+
merged.push({ ...segment });
|
|
184
221
|
}
|
|
185
222
|
});
|
|
186
223
|
return merged;
|
|
187
224
|
}
|
|
188
225
|
function subtractBusyIntervals(workingSegments, events) {
|
|
189
226
|
const available = [];
|
|
190
|
-
workingSegments.forEach(working => {
|
|
191
|
-
const busySegments = mergeBusySegments(events.filter(event => overlaps(working.start, working.end, (0,
|
|
192
|
-
start: maxDayjs((0,
|
|
193
|
-
end: minDayjs((0,
|
|
227
|
+
workingSegments.forEach((working) => {
|
|
228
|
+
const busySegments = mergeBusySegments(events.filter((event) => overlaps(working.start, working.end, (0, import_dayjs.default)(event.start_at), (0, import_dayjs.default)(event.end_at))).map((event) => ({
|
|
229
|
+
start: maxDayjs((0, import_dayjs.default)(event.start_at), working.start),
|
|
230
|
+
end: minDayjs((0, import_dayjs.default)(event.end_at), working.end)
|
|
194
231
|
})));
|
|
195
232
|
let cursor = working.start;
|
|
196
|
-
busySegments.forEach(busy => {
|
|
233
|
+
busySegments.forEach((busy) => {
|
|
197
234
|
if (busy.start.isAfter(cursor)) {
|
|
198
|
-
available.push({
|
|
199
|
-
start: cursor,
|
|
200
|
-
end: busy.start
|
|
201
|
-
});
|
|
235
|
+
available.push({ start: cursor, end: busy.start });
|
|
202
236
|
}
|
|
203
|
-
if (busy.end.isAfter(cursor))
|
|
237
|
+
if (busy.end.isAfter(cursor))
|
|
238
|
+
cursor = busy.end;
|
|
204
239
|
});
|
|
205
240
|
if (working.end.isAfter(cursor)) {
|
|
206
|
-
available.push({
|
|
207
|
-
start: cursor,
|
|
208
|
-
end: working.end
|
|
209
|
-
});
|
|
241
|
+
available.push({ start: cursor, end: working.end });
|
|
210
242
|
}
|
|
211
243
|
});
|
|
212
244
|
return available;
|
|
213
245
|
}
|
|
214
246
|
function buildCapacityRanges(params) {
|
|
215
|
-
const {
|
|
216
|
-
workingSegments,
|
|
217
|
-
events,
|
|
218
|
-
maxCapacity,
|
|
219
|
-
requiredCapacity
|
|
220
|
-
} = params;
|
|
247
|
+
const { workingSegments, events, maxCapacity, requiredCapacity } = params;
|
|
221
248
|
const ranges = [];
|
|
222
|
-
workingSegments.forEach(working => {
|
|
223
|
-
const boundaries = new Map([
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
249
|
+
workingSegments.forEach((working) => {
|
|
250
|
+
const boundaries = /* @__PURE__ */ new Map([
|
|
251
|
+
[working.start.valueOf(), working.start],
|
|
252
|
+
[working.end.valueOf(), working.end]
|
|
253
|
+
]);
|
|
254
|
+
events.forEach((event) => {
|
|
255
|
+
const eventStart = (0, import_dayjs.default)(event.start_at);
|
|
256
|
+
const eventEnd = (0, import_dayjs.default)(event.end_at);
|
|
257
|
+
if (!overlaps(working.start, working.end, eventStart, eventEnd))
|
|
258
|
+
return;
|
|
228
259
|
const clippedStart = maxDayjs(eventStart, working.start);
|
|
229
260
|
const clippedEnd = minDayjs(eventEnd, working.end);
|
|
230
261
|
boundaries.set(clippedStart.valueOf(), clippedStart);
|
|
@@ -234,11 +265,13 @@ function buildCapacityRanges(params) {
|
|
|
234
265
|
for (let index = 0; index < points.length - 1; index += 1) {
|
|
235
266
|
const start = points[index];
|
|
236
267
|
const end = points[index + 1];
|
|
237
|
-
if (!end.isAfter(start))
|
|
238
|
-
|
|
268
|
+
if (!end.isAfter(start))
|
|
269
|
+
continue;
|
|
270
|
+
const usedCapacity = events.filter((event) => overlaps(start, end, (0, import_dayjs.default)(event.start_at), (0, import_dayjs.default)(event.end_at))).reduce((sum, event) => sum + Math.max(1, Number(event.pax || 1)), 0);
|
|
239
271
|
const remainingCapacity = Math.max(0, maxCapacity - usedCapacity);
|
|
240
|
-
if (remainingCapacity < requiredCapacity)
|
|
241
|
-
|
|
272
|
+
if (remainingCapacity < requiredCapacity)
|
|
273
|
+
continue;
|
|
274
|
+
const status = remainingCapacity < maxCapacity ? "limited" : "available";
|
|
242
275
|
const previous = ranges[ranges.length - 1];
|
|
243
276
|
if (previous && previous.end.isSame(start) && previous.remainingCapacity === remainingCapacity && previous.maxCapacity === maxCapacity && previous.status === status) {
|
|
244
277
|
previous.end = end;
|
|
@@ -256,17 +289,13 @@ function buildCapacityRanges(params) {
|
|
|
256
289
|
return ranges;
|
|
257
290
|
}
|
|
258
291
|
function rangeFitsDuration(segment, durationMinutes) {
|
|
259
|
-
return segment.end.diff(segment.start,
|
|
292
|
+
return segment.end.diff(segment.start, "minute") >= durationMinutes;
|
|
260
293
|
}
|
|
261
294
|
function makeAvailabilityRangeCell(params) {
|
|
262
|
-
const {
|
|
263
|
-
interval,
|
|
264
|
-
resource,
|
|
265
|
-
segment
|
|
266
|
-
} = params;
|
|
295
|
+
const { interval, resource, segment } = params;
|
|
267
296
|
const maxCapacity = Math.max(1, Number(segment.maxCapacity || resource.capacity || 1));
|
|
268
|
-
const remainingCapacity = resource.resourceType ===
|
|
269
|
-
const status = resource.resourceType ===
|
|
297
|
+
const remainingCapacity = resource.resourceType === "single" ? 1 : Math.max(0, Number(segment.remainingCapacity ?? maxCapacity));
|
|
298
|
+
const status = resource.resourceType === "single" ? "available" : segment.status || (remainingCapacity < maxCapacity ? "limited" : "available");
|
|
270
299
|
return {
|
|
271
300
|
key: `${interval.productId}:${resource.id}:${segment.start.toISOString()}:${segment.end.toISOString()}`,
|
|
272
301
|
productId: interval.productId,
|
|
@@ -274,10 +303,10 @@ function makeAvailabilityRangeCell(params) {
|
|
|
274
303
|
date: interval.date,
|
|
275
304
|
start_at: segment.start.toISOString(),
|
|
276
305
|
end_at: segment.end.toISOString(),
|
|
277
|
-
startTime: segment.start.format(
|
|
278
|
-
endTime: segment.end.format(
|
|
306
|
+
startTime: segment.start.format("HH:mm"),
|
|
307
|
+
endTime: segment.end.format("HH:mm"),
|
|
279
308
|
durationMinutes: interval.durationMinutes,
|
|
280
|
-
cellType:
|
|
309
|
+
cellType: "availability_range",
|
|
281
310
|
status,
|
|
282
311
|
remainingCapacity,
|
|
283
312
|
maxCapacity,
|
|
@@ -286,98 +315,94 @@ function makeAvailabilityRangeCell(params) {
|
|
|
286
315
|
};
|
|
287
316
|
}
|
|
288
317
|
function buildAvailabilityCellsForResource(params) {
|
|
289
|
-
const {
|
|
290
|
-
resource,
|
|
291
|
-
interval,
|
|
292
|
-
events
|
|
293
|
-
} = params;
|
|
318
|
+
const { resource, interval, events } = params;
|
|
294
319
|
const requiredCapacity = Math.max(1, Number(interval.capacityRequired || 1));
|
|
295
320
|
const durationMinutes = Math.max(1, Number(interval.durationMinutes || 1));
|
|
296
321
|
const maxCapacity = Math.max(1, Number(resource.capacity || 1));
|
|
297
322
|
let workingSegments = getWorkingSegmentsForInterval(resource, interval);
|
|
298
|
-
const now = (0,
|
|
299
|
-
workingSegments = workingSegments.map(segment => ({
|
|
323
|
+
const now = (0, import_dayjs.default)();
|
|
324
|
+
workingSegments = workingSegments.map((segment) => ({
|
|
300
325
|
start: segment.end.isAfter(now) ? maxDayjs(segment.start, now) : segment.start,
|
|
301
326
|
end: segment.end
|
|
302
|
-
})).filter(segment => segment.end.isAfter(segment.start));
|
|
303
|
-
const availableSegments = resource.resourceType ===
|
|
327
|
+
})).filter((segment) => segment.end.isAfter(segment.start));
|
|
328
|
+
const availableSegments = resource.resourceType === "single" ? subtractBusyIntervals(workingSegments, events).map((segment) => ({
|
|
304
329
|
...segment,
|
|
305
330
|
remainingCapacity: 1,
|
|
306
331
|
maxCapacity: 1,
|
|
307
|
-
status:
|
|
332
|
+
status: "available"
|
|
308
333
|
})) : buildCapacityRanges({
|
|
309
334
|
workingSegments,
|
|
310
335
|
events,
|
|
311
336
|
maxCapacity,
|
|
312
337
|
requiredCapacity
|
|
313
338
|
});
|
|
314
|
-
return availableSegments.filter(segment => rangeFitsDuration(segment, durationMinutes)).map(segment => makeAvailabilityRangeCell({
|
|
339
|
+
return availableSegments.filter((segment) => rangeFitsDuration(segment, durationMinutes)).map((segment) => makeAvailabilityRangeCell({
|
|
315
340
|
interval,
|
|
316
341
|
resource,
|
|
317
342
|
segment
|
|
318
343
|
}));
|
|
319
344
|
}
|
|
320
345
|
function evaluateResourceForInterval(params) {
|
|
321
|
-
const {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
context
|
|
325
|
-
} = params;
|
|
326
|
-
const start = (0, _dayjs.default)(interval.start_at);
|
|
327
|
-
const end = (0, _dayjs.default)(interval.end_at);
|
|
346
|
+
const { resource, interval, context } = params;
|
|
347
|
+
const start = (0, import_dayjs.default)(interval.start_at);
|
|
348
|
+
const end = (0, import_dayjs.default)(interval.end_at);
|
|
328
349
|
const conflicts = [];
|
|
329
350
|
const reasonCodes = [];
|
|
330
351
|
const maxCapacity = Math.max(1, Number(resource.capacity || 1));
|
|
331
352
|
const requiredCapacity = Math.max(1, Number(interval.capacityRequired || 1));
|
|
332
|
-
if (start.isBefore((0,
|
|
333
|
-
reasonCodes.push(
|
|
353
|
+
if (start.isBefore((0, import_dayjs.default)())) {
|
|
354
|
+
reasonCodes.push("past");
|
|
334
355
|
conflicts.push({
|
|
335
|
-
type:
|
|
336
|
-
message:
|
|
356
|
+
type: "past",
|
|
357
|
+
message: "时间已过期",
|
|
337
358
|
resourceId: resource.id,
|
|
338
359
|
productId: interval.productId
|
|
339
360
|
});
|
|
340
361
|
}
|
|
341
|
-
const insideResourceTime = resource.times.some(time => {
|
|
342
|
-
return containsRange((0,
|
|
362
|
+
const insideResourceTime = resource.times.some((time) => {
|
|
363
|
+
return containsRange((0, import_dayjs.default)(time.start_at), (0, import_dayjs.default)(time.end_at), start, end);
|
|
343
364
|
});
|
|
344
365
|
if (!insideResourceTime) {
|
|
345
|
-
reasonCodes.push(
|
|
366
|
+
reasonCodes.push("outside_resource_time");
|
|
346
367
|
conflicts.push({
|
|
347
|
-
type:
|
|
348
|
-
message:
|
|
368
|
+
type: "outside_resource_time",
|
|
369
|
+
message: "所选时间不在资源可用时间内",
|
|
349
370
|
resourceId: resource.id,
|
|
350
371
|
productId: interval.productId
|
|
351
372
|
});
|
|
352
373
|
}
|
|
353
374
|
const events = getEventsForResource(resource, context.externalEvents);
|
|
354
|
-
const overlapping = events.filter(event => overlaps(start, end, (0,
|
|
355
|
-
const usedCapacity = resource.resourceType ===
|
|
356
|
-
const remainingCapacity = resource.resourceType ===
|
|
357
|
-
if (overlapping.length > 0 && resource.resourceType ===
|
|
358
|
-
reasonCodes.push(
|
|
359
|
-
conflicts.push(...overlapping.map(event => ({
|
|
360
|
-
type:
|
|
361
|
-
message:
|
|
375
|
+
const overlapping = events.filter((event) => overlaps(start, end, (0, import_dayjs.default)(event.start_at), (0, import_dayjs.default)(event.end_at)));
|
|
376
|
+
const usedCapacity = resource.resourceType === "single" ? overlapping.length : overlapping.reduce((sum, event) => sum + Math.max(1, Number(event.pax || 1)), 0);
|
|
377
|
+
const remainingCapacity = resource.resourceType === "single" ? overlapping.length > 0 ? 0 : 1 : Math.max(0, maxCapacity - usedCapacity);
|
|
378
|
+
if (overlapping.length > 0 && resource.resourceType === "single") {
|
|
379
|
+
reasonCodes.push("remote_event_overlap");
|
|
380
|
+
conflicts.push(...overlapping.map((event) => ({
|
|
381
|
+
type: "remote_event_overlap",
|
|
382
|
+
message: "资源时间被已有预约占用",
|
|
362
383
|
event,
|
|
363
384
|
resourceId: resource.id,
|
|
364
385
|
productId: interval.productId
|
|
365
386
|
})));
|
|
366
387
|
}
|
|
367
|
-
if (resource.resourceType !==
|
|
368
|
-
reasonCodes.push(
|
|
388
|
+
if (resource.resourceType !== "single" && remainingCapacity < requiredCapacity) {
|
|
389
|
+
reasonCodes.push("capacity_full");
|
|
369
390
|
conflicts.push({
|
|
370
|
-
type:
|
|
371
|
-
message:
|
|
391
|
+
type: "capacity_full",
|
|
392
|
+
message: "资源剩余容量不足",
|
|
372
393
|
resourceId: resource.id,
|
|
373
394
|
productId: interval.productId
|
|
374
395
|
});
|
|
375
396
|
}
|
|
376
|
-
let status =
|
|
377
|
-
if (reasonCodes.includes(
|
|
378
|
-
status =
|
|
397
|
+
let status = "available";
|
|
398
|
+
if (reasonCodes.includes("past"))
|
|
399
|
+
status = "past";
|
|
400
|
+
else if (reasonCodes.includes("outside_resource_time"))
|
|
401
|
+
status = "unavailable";
|
|
402
|
+
else if (reasonCodes.includes("remote_event_overlap") || reasonCodes.includes("capacity_full")) {
|
|
403
|
+
status = "full";
|
|
379
404
|
} else if (remainingCapacity < maxCapacity) {
|
|
380
|
-
status =
|
|
405
|
+
status = "limited";
|
|
381
406
|
}
|
|
382
407
|
return {
|
|
383
408
|
key: `${interval.productId}:${resource.id}:${interval.start_at}:${interval.end_at}`,
|
|
@@ -389,7 +414,7 @@ function evaluateResourceForInterval(params) {
|
|
|
389
414
|
startTime: timeOf(interval.start_at),
|
|
390
415
|
endTime: timeOf(interval.end_at),
|
|
391
416
|
durationMinutes: interval.durationMinutes,
|
|
392
|
-
cellType: status ===
|
|
417
|
+
cellType: status === "available" || status === "limited" ? "fixed_interval" : "unavailable",
|
|
393
418
|
status,
|
|
394
419
|
remainingCapacity,
|
|
395
420
|
maxCapacity,
|
|
@@ -398,22 +423,28 @@ function evaluateResourceForInterval(params) {
|
|
|
398
423
|
};
|
|
399
424
|
}
|
|
400
425
|
function aggregateStatus(cells) {
|
|
401
|
-
if (!cells.length)
|
|
402
|
-
|
|
403
|
-
if (cells.some(cell => cell.status ===
|
|
404
|
-
|
|
405
|
-
if (cells.some(cell => cell.status ===
|
|
406
|
-
|
|
407
|
-
|
|
426
|
+
if (!cells.length)
|
|
427
|
+
return "unavailable";
|
|
428
|
+
if (cells.some((cell) => cell.status === "available"))
|
|
429
|
+
return "available";
|
|
430
|
+
if (cells.some((cell) => cell.status === "limited"))
|
|
431
|
+
return "limited";
|
|
432
|
+
if (cells.some((cell) => cell.status === "past"))
|
|
433
|
+
return "past";
|
|
434
|
+
if (cells.some((cell) => cell.status === "full"))
|
|
435
|
+
return "full";
|
|
436
|
+
if (cells.some((cell) => cell.status === "conflict"))
|
|
437
|
+
return "conflict";
|
|
438
|
+
return "unavailable";
|
|
408
439
|
}
|
|
409
440
|
function uniqueReasonCodes(cells) {
|
|
410
|
-
return Array.from(new Set(cells.flatMap(cell => cell.reasonCodes || [])));
|
|
441
|
+
return Array.from(new Set(cells.flatMap((cell) => cell.reasonCodes || [])));
|
|
411
442
|
}
|
|
412
443
|
function buildProductOptions(products, cells, query) {
|
|
413
444
|
const queryProducts = getQueryProducts(products, query);
|
|
414
|
-
return queryProducts.map(product => {
|
|
415
|
-
const productCells = cells.filter(cell => sameId(cell.productId, product.id));
|
|
416
|
-
const status = product.kind ===
|
|
445
|
+
return queryProducts.map((product) => {
|
|
446
|
+
const productCells = cells.filter((cell) => sameId(cell.productId, product.id));
|
|
447
|
+
const status = product.kind === "normal" ? "available" : aggregateStatus(productCells);
|
|
417
448
|
return {
|
|
418
449
|
productId: product.id,
|
|
419
450
|
title: resolveProductTitle(product),
|
|
@@ -424,55 +455,57 @@ function buildProductOptions(products, cells, query) {
|
|
|
424
455
|
}
|
|
425
456
|
function buildResourceOptions(resources, cells, query) {
|
|
426
457
|
const queryResources = getQueryResources(resources, query);
|
|
427
|
-
return queryResources.map(resource => {
|
|
428
|
-
const resourceCells = cells.filter(cell => cell.resourceId !==
|
|
429
|
-
const bestCell = resourceCells.find(cell => cell.status ===
|
|
458
|
+
return queryResources.map((resource) => {
|
|
459
|
+
const resourceCells = cells.filter((cell) => cell.resourceId !== void 0 && sameId(cell.resourceId, resource.id));
|
|
460
|
+
const bestCell = resourceCells.find((cell) => cell.status === "available") || resourceCells.find((cell) => cell.status === "limited") || resourceCells[0];
|
|
430
461
|
return {
|
|
431
462
|
resourceId: resource.id,
|
|
432
463
|
resourceName: resource.name,
|
|
433
464
|
resourceFormId: resource.formId,
|
|
434
465
|
resourceType: resource.resourceType,
|
|
435
|
-
status: resourceCells.length ? aggregateStatus(resourceCells) :
|
|
436
|
-
remainingCapacity: bestCell
|
|
437
|
-
maxCapacity: bestCell
|
|
466
|
+
status: resourceCells.length ? aggregateStatus(resourceCells) : "unavailable",
|
|
467
|
+
remainingCapacity: bestCell == null ? void 0 : bestCell.remainingCapacity,
|
|
468
|
+
maxCapacity: (bestCell == null ? void 0 : bestCell.maxCapacity) || resource.capacity,
|
|
438
469
|
reasonCodes: uniqueReasonCodes(resourceCells)
|
|
439
470
|
};
|
|
440
471
|
});
|
|
441
472
|
}
|
|
442
473
|
function buildDateSummary(cells, query) {
|
|
443
|
-
const dates = query.date ? [query.date] : query.dateRange ? addDays(query.dateRange.start, query.dateRange.end) : Array.from(new Set(cells.map(cell => cell.date).filter(Boolean)));
|
|
444
|
-
return dates.map(date => {
|
|
445
|
-
const dateCells = cells.filter(cell => cell.date === date);
|
|
446
|
-
const availableCount = dateCells.filter(cell => cell.status ===
|
|
474
|
+
const dates = query.date ? [query.date] : query.dateRange ? addDays(query.dateRange.start, query.dateRange.end) : Array.from(new Set(cells.map((cell) => cell.date).filter(Boolean)));
|
|
475
|
+
return dates.map((date) => {
|
|
476
|
+
const dateCells = cells.filter((cell) => cell.date === date);
|
|
477
|
+
const availableCount = dateCells.filter((cell) => cell.status === "available" || cell.status === "limited").length;
|
|
447
478
|
return {
|
|
448
479
|
date,
|
|
449
|
-
status: dateCells.length ? aggregateStatus(dateCells) :
|
|
480
|
+
status: dateCells.length ? aggregateStatus(dateCells) : "unavailable",
|
|
450
481
|
availableCount,
|
|
451
482
|
totalCount: dateCells.length
|
|
452
483
|
};
|
|
453
484
|
});
|
|
454
485
|
}
|
|
455
486
|
function buildTimeLabels(date, context, query) {
|
|
456
|
-
if (!date)
|
|
487
|
+
if (!date)
|
|
488
|
+
return [];
|
|
457
489
|
const slotMinutes = query.slotDurationMinutes || context.slotDurationMinutes;
|
|
458
490
|
const labels = [];
|
|
459
491
|
let cursor = toDateTime(date, context.businessStartTime);
|
|
460
492
|
let end = toDateTime(date, context.businessEndTime);
|
|
461
|
-
if (!end.isAfter(cursor))
|
|
493
|
+
if (!end.isAfter(cursor))
|
|
494
|
+
end = end.add(1, "day");
|
|
462
495
|
while (cursor.isBefore(end)) {
|
|
463
|
-
labels.push(cursor.format(
|
|
464
|
-
cursor = cursor.add(slotMinutes,
|
|
496
|
+
labels.push(cursor.format("HH:mm"));
|
|
497
|
+
cursor = cursor.add(slotMinutes, "minute");
|
|
465
498
|
}
|
|
466
499
|
return labels;
|
|
467
500
|
}
|
|
468
501
|
function buildGridSlotInterval(product, date, label, context, query) {
|
|
469
|
-
const slotMinutes = product.kind ===
|
|
502
|
+
const slotMinutes = product.kind === "duration" ? Math.max(1, Number(product.durationMinutes || query.slotDurationMinutes || context.slotDurationMinutes)) : query.slotDurationMinutes || context.slotDurationMinutes;
|
|
470
503
|
const start = toDateTime(date, label);
|
|
471
|
-
const end = start.add(slotMinutes,
|
|
504
|
+
const end = start.add(slotMinutes, "minute");
|
|
472
505
|
return {
|
|
473
506
|
id: `${product.id}:${date}:${label}`,
|
|
474
507
|
productId: product.id,
|
|
475
|
-
source: product.kind ===
|
|
508
|
+
source: product.kind === "session" ? "session" : product.kind === "venue_slot" ? "venue_slot" : "duration",
|
|
476
509
|
date,
|
|
477
510
|
start_at: start.toISOString(),
|
|
478
511
|
end_at: end.toISOString(),
|
|
@@ -483,33 +516,30 @@ function buildGridSlotInterval(product, date, label, context, query) {
|
|
|
483
516
|
};
|
|
484
517
|
}
|
|
485
518
|
function buildTimeGrid(context, query, cells) {
|
|
486
|
-
|
|
487
|
-
const
|
|
519
|
+
var _a;
|
|
520
|
+
const date = query.date || ((_a = query.dateRange) == null ? void 0 : _a.start);
|
|
521
|
+
const products = getQueryProducts(context.products, query).filter((product) => product.kind !== "normal");
|
|
488
522
|
const resources = getQueryResources(context.resources, query);
|
|
489
523
|
const timeLabels = buildTimeLabels(date, context, query);
|
|
490
524
|
if (!date || !products.length || !resources.length) {
|
|
491
|
-
return {
|
|
492
|
-
date,
|
|
493
|
-
timeLabels,
|
|
494
|
-
resources: []
|
|
495
|
-
};
|
|
525
|
+
return { date, timeLabels, resources: [] };
|
|
496
526
|
}
|
|
497
|
-
const rows = resources.map(resource => {
|
|
498
|
-
const slots = timeLabels.map(label => {
|
|
527
|
+
const rows = resources.map((resource) => {
|
|
528
|
+
const slots = timeLabels.map((label) => {
|
|
499
529
|
const product = products[0];
|
|
500
530
|
const interval = buildGridSlotInterval(product, date, label, context, query);
|
|
501
|
-
const start = (0,
|
|
502
|
-
const end = (0,
|
|
503
|
-
const cell = cells.find(item => sameId(item.productId, product.id) && sameId(item.resourceId, resource.id) && item.date === date && (item.status ===
|
|
531
|
+
const start = (0, import_dayjs.default)(interval.start_at);
|
|
532
|
+
const end = (0, import_dayjs.default)(interval.end_at);
|
|
533
|
+
const cell = cells.find((item) => sameId(item.productId, product.id) && sameId(item.resourceId, resource.id) && item.date === date && (item.status === "available" || item.status === "limited") && containsRange((0, import_dayjs.default)(item.start_at), (0, import_dayjs.default)(item.end_at), start, end));
|
|
504
534
|
return {
|
|
505
535
|
startTime: label,
|
|
506
|
-
endTime: (0,
|
|
507
|
-
status: cell
|
|
536
|
+
endTime: (0, import_dayjs.default)(interval.end_at).format("HH:mm"),
|
|
537
|
+
status: (cell == null ? void 0 : cell.status) || "unavailable",
|
|
508
538
|
resourceId: resource.id,
|
|
509
539
|
productId: product.id,
|
|
510
|
-
remainingCapacity: cell
|
|
511
|
-
maxCapacity: cell
|
|
512
|
-
reasonCodes: cell
|
|
540
|
+
remainingCapacity: cell == null ? void 0 : cell.remainingCapacity,
|
|
541
|
+
maxCapacity: (cell == null ? void 0 : cell.maxCapacity) || resource.capacity,
|
|
542
|
+
reasonCodes: (cell == null ? void 0 : cell.reasonCodes) || ["outside_available_range"]
|
|
513
543
|
};
|
|
514
544
|
});
|
|
515
545
|
return {
|
|
@@ -519,11 +549,7 @@ function buildTimeGrid(context, query, cells) {
|
|
|
519
549
|
slots
|
|
520
550
|
};
|
|
521
551
|
});
|
|
522
|
-
return {
|
|
523
|
-
date,
|
|
524
|
-
timeLabels,
|
|
525
|
-
resources: rows
|
|
526
|
-
};
|
|
552
|
+
return { date, timeLabels, resources: rows };
|
|
527
553
|
}
|
|
528
554
|
function queryPlannerAvailability(contextInput, query = {}) {
|
|
529
555
|
const context = normalizePlannerContext(contextInput);
|
|
@@ -532,10 +558,11 @@ function queryPlannerAvailability(contextInput, query = {}) {
|
|
|
532
558
|
const eventsByResource = collectEventsByResource(resources, context.externalEvents);
|
|
533
559
|
const cells = [];
|
|
534
560
|
for (const interval of intervals) {
|
|
535
|
-
const candidateResources = resources.filter(resource => {
|
|
561
|
+
const candidateResources = resources.filter((resource) => {
|
|
536
562
|
const requirements = interval.resourceRequirements || [];
|
|
537
|
-
if (!requirements.length)
|
|
538
|
-
|
|
563
|
+
if (!requirements.length)
|
|
564
|
+
return true;
|
|
565
|
+
return requirements.some((requirement) => matchesResourceRequirement(resource, requirement));
|
|
539
566
|
});
|
|
540
567
|
if (!candidateResources.length) {
|
|
541
568
|
cells.push({
|
|
@@ -547,19 +574,19 @@ function queryPlannerAvailability(contextInput, query = {}) {
|
|
|
547
574
|
startTime: timeOf(interval.start_at),
|
|
548
575
|
endTime: timeOf(interval.end_at),
|
|
549
576
|
durationMinutes: interval.durationMinutes,
|
|
550
|
-
cellType:
|
|
551
|
-
status:
|
|
552
|
-
reasonCodes: [
|
|
577
|
+
cellType: "unavailable",
|
|
578
|
+
status: "unavailable",
|
|
579
|
+
reasonCodes: ["missing_resource"],
|
|
553
580
|
conflicts: [{
|
|
554
|
-
type:
|
|
555
|
-
message:
|
|
581
|
+
type: "missing_resource",
|
|
582
|
+
message: "没有匹配商品需求的资源",
|
|
556
583
|
productId: interval.productId
|
|
557
584
|
}]
|
|
558
585
|
});
|
|
559
586
|
continue;
|
|
560
587
|
}
|
|
561
|
-
candidateResources.forEach(resource => {
|
|
562
|
-
if (interval.source ===
|
|
588
|
+
candidateResources.forEach((resource) => {
|
|
589
|
+
if (interval.source === "duration" && !query.startTime) {
|
|
563
590
|
cells.push(...buildAvailabilityCellsForResource({
|
|
564
591
|
resource,
|
|
565
592
|
interval,
|
|
@@ -567,11 +594,7 @@ function queryPlannerAvailability(contextInput, query = {}) {
|
|
|
567
594
|
}));
|
|
568
595
|
return;
|
|
569
596
|
}
|
|
570
|
-
cells.push(evaluateResourceForInterval({
|
|
571
|
-
resource,
|
|
572
|
-
interval,
|
|
573
|
-
context
|
|
574
|
-
}));
|
|
597
|
+
cells.push(evaluateResourceForInterval({ resource, interval, context }));
|
|
575
598
|
});
|
|
576
599
|
}
|
|
577
600
|
return {
|
|
@@ -591,84 +614,86 @@ function getIntervalRequirements(interval) {
|
|
|
591
614
|
}];
|
|
592
615
|
}
|
|
593
616
|
function buildAssignableCandidateGroups(params) {
|
|
594
|
-
const {
|
|
595
|
-
interval,
|
|
596
|
-
cells,
|
|
597
|
-
resources
|
|
598
|
-
} = params;
|
|
617
|
+
const { interval, cells, resources } = params;
|
|
599
618
|
const conflicts = [];
|
|
600
|
-
const groups = getIntervalRequirements(interval).map(requirement => {
|
|
601
|
-
const candidateCells = cells.filter(cell => {
|
|
602
|
-
if (!sameId(cell.productId, interval.productId))
|
|
603
|
-
|
|
604
|
-
if (cell.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
619
|
+
const groups = getIntervalRequirements(interval).map((requirement) => {
|
|
620
|
+
const candidateCells = cells.filter((cell) => {
|
|
621
|
+
if (!sameId(cell.productId, interval.productId))
|
|
622
|
+
return false;
|
|
623
|
+
if (cell.date !== interval.date)
|
|
624
|
+
return false;
|
|
625
|
+
if (cell.resourceId === void 0)
|
|
626
|
+
return false;
|
|
627
|
+
if (cell.status !== "available" && cell.status !== "limited")
|
|
628
|
+
return false;
|
|
629
|
+
const cellStart = (0, import_dayjs.default)(cell.start_at);
|
|
630
|
+
const cellEnd = (0, import_dayjs.default)(cell.end_at);
|
|
631
|
+
const intervalStart = (0, import_dayjs.default)(interval.start_at);
|
|
632
|
+
const intervalEnd = (0, import_dayjs.default)(interval.end_at);
|
|
633
|
+
return containsRange(cellStart, cellEnd, intervalStart, intervalEnd) || interval.source === "duration";
|
|
611
634
|
});
|
|
612
|
-
return candidateCells.flatMap(cell => {
|
|
613
|
-
const resource = resources.find(item => sameId(item.id, cell.resourceId));
|
|
614
|
-
if (!resource || !matchesResourceRequirement(resource, requirement))
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
resource,
|
|
618
|
-
cell
|
|
619
|
-
}];
|
|
635
|
+
return candidateCells.flatMap((cell) => {
|
|
636
|
+
const resource = resources.find((item) => sameId(item.id, cell.resourceId));
|
|
637
|
+
if (!resource || !matchesResourceRequirement(resource, requirement))
|
|
638
|
+
return [];
|
|
639
|
+
return [{ requirement, resource, cell }];
|
|
620
640
|
});
|
|
621
641
|
});
|
|
622
642
|
groups.forEach((group, index) => {
|
|
623
|
-
|
|
643
|
+
var _a, _b;
|
|
644
|
+
if (group.length)
|
|
645
|
+
return;
|
|
624
646
|
conflicts.push({
|
|
625
|
-
type:
|
|
626
|
-
message:
|
|
647
|
+
type: "missing_resource",
|
|
648
|
+
message: "没有匹配商品需求的可用资源",
|
|
627
649
|
productId: interval.productId,
|
|
628
|
-
resourceId: interval.resourceRequirements[index]
|
|
650
|
+
resourceId: (_b = (_a = interval.resourceRequirements[index]) == null ? void 0 : _a.resourceIds) == null ? void 0 : _b[0]
|
|
629
651
|
});
|
|
630
652
|
});
|
|
631
|
-
return {
|
|
632
|
-
groups,
|
|
633
|
-
conflicts
|
|
634
|
-
};
|
|
653
|
+
return { groups, conflicts };
|
|
635
654
|
}
|
|
636
655
|
function combineCandidateGroups(groups) {
|
|
637
|
-
if (!groups.length || groups.some(group => group.length === 0))
|
|
638
|
-
|
|
656
|
+
if (!groups.length || groups.some((group) => group.length === 0))
|
|
657
|
+
return [];
|
|
658
|
+
return groups.reduce((combinations, group) => combinations.flatMap((combination) => group.map((candidate) => [...combination, candidate])), [[]]);
|
|
639
659
|
}
|
|
640
660
|
function buildSlotFromCandidates(params) {
|
|
641
|
-
const {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
} = params;
|
|
647
|
-
if (!end.isAfter(start)) return null;
|
|
648
|
-
const status = candidates.some(candidate => candidate.cell.status === 'limited') ? 'limited' : 'available';
|
|
649
|
-
const assignments = candidates.map(candidate => ({
|
|
661
|
+
const { interval, candidates, start, end } = params;
|
|
662
|
+
if (!end.isAfter(start))
|
|
663
|
+
return null;
|
|
664
|
+
const status = candidates.some((candidate) => candidate.cell.status === "limited") ? "limited" : "available";
|
|
665
|
+
const assignments = candidates.map((candidate) => ({
|
|
650
666
|
productId: interval.productId,
|
|
651
667
|
resourceId: candidate.resource.id,
|
|
652
668
|
start_at: start.toISOString(),
|
|
653
669
|
end_at: end.toISOString(),
|
|
654
|
-
capacityRequired: Math.max(1, Number(
|
|
670
|
+
capacityRequired: Math.max(1, Number(
|
|
671
|
+
candidate.requirement.capacityRequired || interval.capacityRequired || 1
|
|
672
|
+
))
|
|
655
673
|
}));
|
|
656
674
|
return {
|
|
657
|
-
key: [
|
|
675
|
+
key: [
|
|
676
|
+
interval.productId,
|
|
677
|
+
start.toISOString(),
|
|
678
|
+
end.toISOString(),
|
|
679
|
+
...candidates.map((candidate) => candidate.resource.id)
|
|
680
|
+
].join(":"),
|
|
658
681
|
productId: interval.productId,
|
|
659
682
|
date: interval.date,
|
|
660
683
|
start_at: start.toISOString(),
|
|
661
684
|
end_at: end.toISOString(),
|
|
662
|
-
startTime: start.format(
|
|
663
|
-
endTime: end.format(
|
|
664
|
-
durationMinutes: Math.max(1, end.diff(start,
|
|
685
|
+
startTime: start.format("HH:mm"),
|
|
686
|
+
endTime: end.format("HH:mm"),
|
|
687
|
+
durationMinutes: Math.max(1, end.diff(start, "minute")),
|
|
665
688
|
status,
|
|
666
|
-
resources: candidates.map(candidate => ({
|
|
689
|
+
resources: candidates.map((candidate) => ({
|
|
667
690
|
resourceId: candidate.resource.id,
|
|
668
691
|
resourceName: candidate.resource.name,
|
|
669
692
|
resourceFormId: candidate.resource.formId,
|
|
670
693
|
resourceType: candidate.resource.resourceType,
|
|
671
|
-
capacityRequired: Math.max(1, Number(
|
|
694
|
+
capacityRequired: Math.max(1, Number(
|
|
695
|
+
candidate.requirement.capacityRequired || interval.capacityRequired || 1
|
|
696
|
+
)),
|
|
672
697
|
remainingCapacity: candidate.cell.remainingCapacity,
|
|
673
698
|
maxCapacity: candidate.cell.maxCapacity
|
|
674
699
|
})),
|
|
@@ -677,19 +702,20 @@ function buildSlotFromCandidates(params) {
|
|
|
677
702
|
};
|
|
678
703
|
}
|
|
679
704
|
function buildSlotsForInterval(params) {
|
|
680
|
-
const {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
705
|
+
const { interval, candidates, query, context } = params;
|
|
706
|
+
const start = candidates.reduce(
|
|
707
|
+
(current, candidate) => maxDayjs(current, (0, import_dayjs.default)(candidate.cell.start_at)),
|
|
708
|
+
(0, import_dayjs.default)(interval.start_at)
|
|
709
|
+
);
|
|
710
|
+
const end = candidates.reduce(
|
|
711
|
+
(current, candidate) => minDayjs(current, (0, import_dayjs.default)(candidate.cell.end_at)),
|
|
712
|
+
(0, import_dayjs.default)(interval.end_at)
|
|
713
|
+
);
|
|
688
714
|
const durationMinutes = Math.max(1, Number(interval.durationMinutes || 1));
|
|
689
|
-
if (interval.source !==
|
|
690
|
-
const fixedStart = (0,
|
|
691
|
-
const fixedEnd = (0,
|
|
692
|
-
if (containsRange(start, end, fixedStart, fixedEnd) || candidates.every(candidate => candidate.cell.cellType ===
|
|
715
|
+
if (interval.source !== "duration" || query.startTime) {
|
|
716
|
+
const fixedStart = (0, import_dayjs.default)(interval.start_at);
|
|
717
|
+
const fixedEnd = (0, import_dayjs.default)(interval.end_at);
|
|
718
|
+
if (containsRange(start, end, fixedStart, fixedEnd) || candidates.every((candidate) => candidate.cell.cellType === "fixed_interval")) {
|
|
693
719
|
const slot = buildSlotFromCandidates({
|
|
694
720
|
interval,
|
|
695
721
|
candidates,
|
|
@@ -703,16 +729,17 @@ function buildSlotsForInterval(params) {
|
|
|
703
729
|
const stepMinutes = Math.max(1, Number(query.slotDurationMinutes || context.slotDurationMinutes || 30));
|
|
704
730
|
const slots = [];
|
|
705
731
|
let cursor = start;
|
|
706
|
-
while (!cursor.add(durationMinutes,
|
|
707
|
-
const slotEnd = cursor.add(durationMinutes,
|
|
732
|
+
while (!cursor.add(durationMinutes, "minute").isAfter(end)) {
|
|
733
|
+
const slotEnd = cursor.add(durationMinutes, "minute");
|
|
708
734
|
const slot = buildSlotFromCandidates({
|
|
709
735
|
interval,
|
|
710
736
|
candidates,
|
|
711
737
|
start: cursor,
|
|
712
738
|
end: slotEnd
|
|
713
739
|
});
|
|
714
|
-
if (slot)
|
|
715
|
-
|
|
740
|
+
if (slot)
|
|
741
|
+
slots.push(slot);
|
|
742
|
+
cursor = cursor.add(stepMinutes, "minute");
|
|
716
743
|
}
|
|
717
744
|
return slots;
|
|
718
745
|
}
|
|
@@ -720,26 +747,24 @@ function resolveAssignableSlots(contextInput, query = {}) {
|
|
|
720
747
|
const context = normalizePlannerContext(contextInput);
|
|
721
748
|
const projection = queryPlannerAvailability(context, query);
|
|
722
749
|
const resources = getQueryResources(context.resources, query);
|
|
723
|
-
const slotsByKey = new Map();
|
|
750
|
+
const slotsByKey = /* @__PURE__ */ new Map();
|
|
724
751
|
const conflicts = [];
|
|
725
|
-
projection.demandIntervals.forEach(interval => {
|
|
726
|
-
const {
|
|
727
|
-
groups,
|
|
728
|
-
conflicts: groupConflicts
|
|
729
|
-
} = buildAssignableCandidateGroups({
|
|
752
|
+
projection.demandIntervals.forEach((interval) => {
|
|
753
|
+
const { groups, conflicts: groupConflicts } = buildAssignableCandidateGroups({
|
|
730
754
|
interval,
|
|
731
755
|
cells: projection.cells,
|
|
732
756
|
resources
|
|
733
757
|
});
|
|
734
758
|
conflicts.push(...groupConflicts);
|
|
735
|
-
combineCandidateGroups(groups).forEach(candidates => {
|
|
759
|
+
combineCandidateGroups(groups).forEach((candidates) => {
|
|
736
760
|
buildSlotsForInterval({
|
|
737
761
|
interval,
|
|
738
762
|
candidates,
|
|
739
763
|
query,
|
|
740
764
|
context
|
|
741
|
-
}).forEach(slot => {
|
|
742
|
-
if (!slotsByKey.has(slot.key))
|
|
765
|
+
}).forEach((slot) => {
|
|
766
|
+
if (!slotsByKey.has(slot.key))
|
|
767
|
+
slotsByKey.set(slot.key, slot);
|
|
743
768
|
});
|
|
744
769
|
});
|
|
745
770
|
});
|
|
@@ -754,35 +779,36 @@ function autoAssignResources(contextInput, query = {}) {
|
|
|
754
779
|
const projection = queryPlannerAvailability(baseContext, query);
|
|
755
780
|
const assignments = [];
|
|
756
781
|
const conflicts = [];
|
|
757
|
-
const missingTimeProductIds = new Set();
|
|
782
|
+
const missingTimeProductIds = /* @__PURE__ */ new Set();
|
|
758
783
|
for (const interval of projection.demandIntervals) {
|
|
759
|
-
if (interval.source ===
|
|
784
|
+
if (interval.source === "duration" && !query.startTime) {
|
|
760
785
|
const productKey = String(interval.productId);
|
|
761
786
|
if (!missingTimeProductIds.has(productKey)) {
|
|
762
787
|
missingTimeProductIds.add(productKey);
|
|
763
788
|
conflicts.push({
|
|
764
|
-
type:
|
|
765
|
-
message:
|
|
789
|
+
type: "missing_time",
|
|
790
|
+
message: "duration 商品需要先确定开始时间后才能自动分配资源",
|
|
766
791
|
productId: interval.productId
|
|
767
792
|
});
|
|
768
793
|
}
|
|
769
794
|
continue;
|
|
770
795
|
}
|
|
771
796
|
const contextWithAssignments = withAssignmentEvents(baseContext, assignments);
|
|
772
|
-
const candidateResources = getQueryResources(contextWithAssignments.resources, query).filter(resource => {
|
|
797
|
+
const candidateResources = getQueryResources(contextWithAssignments.resources, query).filter((resource) => {
|
|
773
798
|
const requirements = interval.resourceRequirements || [];
|
|
774
|
-
if (!requirements.length)
|
|
775
|
-
|
|
799
|
+
if (!requirements.length)
|
|
800
|
+
return true;
|
|
801
|
+
return requirements.some((requirement) => matchesResourceRequirement(resource, requirement));
|
|
776
802
|
});
|
|
777
|
-
const availableCell = candidateResources.map(resource => evaluateResourceForInterval({
|
|
803
|
+
const availableCell = candidateResources.map((resource) => evaluateResourceForInterval({
|
|
778
804
|
resource,
|
|
779
805
|
interval,
|
|
780
806
|
context: contextWithAssignments
|
|
781
|
-
})).find(cell => cell.status ===
|
|
782
|
-
if (!availableCell
|
|
807
|
+
})).find((cell) => cell.status === "available" || cell.status === "limited");
|
|
808
|
+
if (!(availableCell == null ? void 0 : availableCell.resourceId)) {
|
|
783
809
|
conflicts.push({
|
|
784
|
-
type:
|
|
785
|
-
message:
|
|
810
|
+
type: "missing_resource",
|
|
811
|
+
message: "无法为商品自动分配可用资源",
|
|
786
812
|
productId: interval.productId
|
|
787
813
|
});
|
|
788
814
|
continue;
|
|
@@ -795,88 +821,88 @@ function autoAssignResources(contextInput, query = {}) {
|
|
|
795
821
|
capacityRequired: interval.capacityRequired
|
|
796
822
|
});
|
|
797
823
|
}
|
|
798
|
-
return {
|
|
799
|
-
assignments,
|
|
800
|
-
conflicts
|
|
801
|
-
};
|
|
824
|
+
return { assignments, conflicts };
|
|
802
825
|
}
|
|
803
826
|
function withAssignmentEvents(context, assignments) {
|
|
804
|
-
if (!assignments.length)
|
|
827
|
+
if (!assignments.length)
|
|
828
|
+
return context;
|
|
805
829
|
return {
|
|
806
830
|
...context,
|
|
807
|
-
externalEvents: [
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
831
|
+
externalEvents: [
|
|
832
|
+
...context.externalEvents,
|
|
833
|
+
...assignments.map((assignment) => ({
|
|
834
|
+
resourceId: assignment.resourceId,
|
|
835
|
+
start_at: assignment.start_at,
|
|
836
|
+
end_at: assignment.end_at,
|
|
837
|
+
pax: assignment.capacityRequired || 1,
|
|
838
|
+
source: "selection"
|
|
839
|
+
}))
|
|
840
|
+
]
|
|
814
841
|
};
|
|
815
842
|
}
|
|
816
843
|
function validateAssignments(contextInput, selection) {
|
|
817
844
|
if (selection.assignments.length > 0) {
|
|
818
845
|
const context = normalizePlannerContext(contextInput);
|
|
819
|
-
const
|
|
846
|
+
const conflicts2 = [];
|
|
820
847
|
for (let index = 0; index < selection.assignments.length; index += 1) {
|
|
821
848
|
const assignment = selection.assignments[index];
|
|
822
|
-
const product = context.products.find(item => sameId(item.id, assignment.productId));
|
|
823
|
-
const resource = context.resources.find(item => sameId(item.id, assignment.resourceId));
|
|
849
|
+
const product = context.products.find((item) => sameId(item.id, assignment.productId));
|
|
850
|
+
const resource = context.resources.find((item) => sameId(item.id, assignment.resourceId));
|
|
824
851
|
if (!product) {
|
|
825
|
-
|
|
826
|
-
type:
|
|
827
|
-
message:
|
|
852
|
+
conflicts2.push({
|
|
853
|
+
type: "missing_resource",
|
|
854
|
+
message: "assignment 对应的商品不存在",
|
|
828
855
|
productId: assignment.productId
|
|
829
856
|
});
|
|
830
857
|
continue;
|
|
831
858
|
}
|
|
832
859
|
if (!resource) {
|
|
833
|
-
|
|
834
|
-
type:
|
|
835
|
-
message:
|
|
860
|
+
conflicts2.push({
|
|
861
|
+
type: "missing_resource",
|
|
862
|
+
message: "assignment 对应的资源不存在",
|
|
836
863
|
productId: assignment.productId,
|
|
837
864
|
resourceId: assignment.resourceId
|
|
838
865
|
});
|
|
839
866
|
continue;
|
|
840
867
|
}
|
|
841
|
-
const start = (0,
|
|
842
|
-
const end = (0,
|
|
868
|
+
const start = (0, import_dayjs.default)(assignment.start_at);
|
|
869
|
+
const end = (0, import_dayjs.default)(assignment.end_at);
|
|
843
870
|
const interval = {
|
|
844
871
|
id: `${assignment.productId}:${assignment.resourceId}:${assignment.start_at}:${assignment.end_at}`,
|
|
845
872
|
productId: assignment.productId,
|
|
846
|
-
source: product.kind ===
|
|
847
|
-
date: start.format(
|
|
873
|
+
source: product.kind === "session" ? "session" : product.kind === "venue_slot" ? "venue_slot" : "duration",
|
|
874
|
+
date: start.format("YYYY-MM-DD"),
|
|
848
875
|
start_at: assignment.start_at,
|
|
849
876
|
end_at: assignment.end_at,
|
|
850
|
-
durationMinutes: Math.max(1, end.diff(start,
|
|
877
|
+
durationMinutes: Math.max(1, end.diff(start, "minute")),
|
|
851
878
|
quantity: Math.max(1, Number(product.quantity || 1)),
|
|
852
879
|
capacityRequired: Math.max(1, Number(assignment.capacityRequired || product.capacityRequired || 1)),
|
|
853
880
|
resourceRequirements: product.resourceRequirements || []
|
|
854
881
|
};
|
|
855
|
-
const cell = evaluateResourceForInterval({
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
context
|
|
859
|
-
});
|
|
860
|
-
if (cell.status !== 'available' && cell.status !== 'limited') {
|
|
861
|
-
conflicts.push(...cell.conflicts);
|
|
882
|
+
const cell = evaluateResourceForInterval({ resource, interval, context });
|
|
883
|
+
if (cell.status !== "available" && cell.status !== "limited") {
|
|
884
|
+
conflicts2.push(...cell.conflicts);
|
|
862
885
|
}
|
|
863
|
-
const priorContext = withAssignmentEvents(
|
|
886
|
+
const priorContext = withAssignmentEvents(
|
|
887
|
+
context,
|
|
888
|
+
selection.assignments.slice(0, index)
|
|
889
|
+
);
|
|
864
890
|
const selfConflictCell = evaluateResourceForInterval({
|
|
865
891
|
resource,
|
|
866
892
|
interval,
|
|
867
893
|
context: priorContext
|
|
868
894
|
});
|
|
869
|
-
if (selfConflictCell.status !==
|
|
870
|
-
|
|
895
|
+
if (selfConflictCell.status !== "available" && selfConflictCell.status !== "limited") {
|
|
896
|
+
conflicts2.push(...selfConflictCell.conflicts.map((conflict) => ({
|
|
871
897
|
...conflict,
|
|
872
|
-
type:
|
|
873
|
-
message:
|
|
898
|
+
type: "cart_overlap",
|
|
899
|
+
message: "本次选择中存在资源时间冲突"
|
|
874
900
|
})));
|
|
875
901
|
}
|
|
876
902
|
}
|
|
877
903
|
return {
|
|
878
|
-
ok:
|
|
879
|
-
conflicts
|
|
904
|
+
ok: conflicts2.length === 0,
|
|
905
|
+
conflicts: conflicts2
|
|
880
906
|
};
|
|
881
907
|
}
|
|
882
908
|
const projection = queryPlannerAvailability(contextInput, {
|
|
@@ -887,9 +913,21 @@ function validateAssignments(contextInput, selection) {
|
|
|
887
913
|
resourceIds: selection.resourceIds,
|
|
888
914
|
mode: selection.mode
|
|
889
915
|
});
|
|
890
|
-
const conflicts = projection.cells.filter(cell => cell.status !==
|
|
916
|
+
const conflicts = projection.cells.filter((cell) => cell.status !== "available" && cell.status !== "limited").flatMap((cell) => cell.conflicts);
|
|
891
917
|
return {
|
|
892
918
|
ok: conflicts.length === 0,
|
|
893
919
|
conflicts
|
|
894
920
|
};
|
|
895
|
-
}
|
|
921
|
+
}
|
|
922
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
923
|
+
0 && (module.exports = {
|
|
924
|
+
DEFAULT_RESOURCE_PLANNER_CONTEXT,
|
|
925
|
+
DEFAULT_RESOURCE_PLANNER_SELECTION,
|
|
926
|
+
autoAssignResources,
|
|
927
|
+
buildDemandIntervals,
|
|
928
|
+
evaluateResourceForInterval,
|
|
929
|
+
normalizePlannerContext,
|
|
930
|
+
queryPlannerAvailability,
|
|
931
|
+
resolveAssignableSlots,
|
|
932
|
+
validateAssignments
|
|
933
|
+
});
|