onroute-policy-engine 0.1.0 → 0.2.0
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/README.md +5 -4
- package/dist/enum/accessory-vehicle-type.d.ts +4 -0
- package/dist/enum/accessory-vehicle-type.js +8 -0
- package/dist/enum/facts.d.ts +5 -1
- package/dist/enum/facts.js +4 -0
- package/dist/enum/index.d.ts +2 -0
- package/dist/enum/index.js +5 -1
- package/dist/enum/permit-app-info.d.ts +8 -2
- package/dist/enum/permit-app-info.js +8 -2
- package/dist/enum/validation-result-code.d.ts +2 -1
- package/dist/enum/validation-result-code.js +1 -0
- package/dist/enum/validation-result-type.d.ts +2 -1
- package/dist/enum/validation-result-type.js +1 -0
- package/dist/enum/vehicle-types.d.ts +4 -0
- package/dist/enum/vehicle-types.js +8 -0
- package/dist/helper/facts.helper.d.ts +2 -9
- package/dist/helper/facts.helper.js +63 -26
- package/dist/helper/lists.helper.d.ts +13 -0
- package/dist/helper/lists.helper.js +32 -1
- package/dist/helper/rules-engine.helper.js +32 -2
- package/dist/policy-engine.d.ts +82 -2
- package/dist/policy-engine.js +516 -6
- package/dist/rule-operator/custom-operators.js +5 -1
- package/dist/types/commodity.d.ts +10 -3
- package/dist/types/cost-rule.d.ts +4 -0
- package/dist/types/cost-rule.js +2 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/permit-type.d.ts +2 -1
- package/dist/types/policy-definition.d.ts +2 -1
- package/dist/types/range-matrix.d.ts +9 -0
- package/dist/types/range-matrix.js +2 -0
- package/dist/types/region-size-override.d.ts +3 -3
- package/dist/types/self-issuable.d.ts +1 -1
- package/dist/types/size-dimension.d.ts +7 -7
- package/dist/types/vehicle-type.d.ts +1 -0
- package/dist/types/vehicle.d.ts +11 -5
- package/dist/validation-result.d.ts +1 -0
- package/dist/validation-results.d.ts +5 -0
- package/dist/validation-results.js +10 -1
- package/package.json +3 -3
package/dist/policy-engine.js
CHANGED
|
@@ -35,10 +35,9 @@ class Policy {
|
|
|
35
35
|
else {
|
|
36
36
|
// Add facts specific to this run of the validation (e.g. validation
|
|
37
37
|
// date for comparison against start date of the permit).
|
|
38
|
-
(0, facts_helper_1.addRuntimeFacts)(engine);
|
|
39
|
-
const permitFacts = (0, facts_helper_1.transformPermitFacts)(permit);
|
|
38
|
+
(0, facts_helper_1.addRuntimeFacts)(engine, this);
|
|
40
39
|
// Run the json-rules-engine against the permit facts
|
|
41
|
-
const engineResult = await engine.run(
|
|
40
|
+
const engineResult = await engine.run(permit);
|
|
42
41
|
// Wrap the json-rules-engine result in a ValidationResult object
|
|
43
42
|
return new validation_results_1.ValidationResults(engineResult);
|
|
44
43
|
}
|
|
@@ -63,13 +62,507 @@ class Policy {
|
|
|
63
62
|
* Gets a list of all configured commodities in the policy definition.
|
|
64
63
|
* @param permitTypeId Return only commodities valid for this permit type.
|
|
65
64
|
* If not supplied, return all commodities configured in policy. If permit
|
|
66
|
-
* type does not require commodity (e.g. 'TROS'), return
|
|
65
|
+
* type does not require commodity (e.g. 'TROS'), return empty map.
|
|
67
66
|
* @returns Map of commodity IDs to commodity names.
|
|
68
67
|
*/
|
|
69
68
|
getCommodities(permitTypeId) {
|
|
70
69
|
const permitType = this.getPermitTypeDefinition(permitTypeId);
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if (!permitTypeId) {
|
|
71
|
+
// Permit type not supplied, return all commodities
|
|
72
|
+
return (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities);
|
|
73
|
+
}
|
|
74
|
+
else if (!permitType) {
|
|
75
|
+
// Permit type invalid, throw error
|
|
76
|
+
throw new Error(`Invalid permit type supplied: '${permitTypeId}'`);
|
|
77
|
+
}
|
|
78
|
+
else if (!permitType.commodityRequired) {
|
|
79
|
+
return new Map();
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Commodities for oversize permits are those which have at least one
|
|
83
|
+
// power unit defined in the size dimension object of the commodity.
|
|
84
|
+
const commoditiesForOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities.filter((c) => {
|
|
85
|
+
if (c.size) {
|
|
86
|
+
if (c.size.powerUnits) {
|
|
87
|
+
if (c.size.powerUnits.length > 0) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}), permitType.allowedCommodities);
|
|
94
|
+
// TODO when implementing overweight. Stub for now.
|
|
95
|
+
const commoditiesForOW = new Map();
|
|
96
|
+
if (permitType.sizeDimensionRequired &&
|
|
97
|
+
permitType.weightDimensionRequired) {
|
|
98
|
+
return (0, lists_helper_1.intersectIdMaps)(commoditiesForOS, commoditiesForOW);
|
|
99
|
+
}
|
|
100
|
+
else if (permitType.sizeDimensionRequired) {
|
|
101
|
+
return commoditiesForOS;
|
|
102
|
+
}
|
|
103
|
+
else if (permitType.weightDimensionRequired) {
|
|
104
|
+
return commoditiesForOW;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// This permit type requires commodity selection, but does not
|
|
108
|
+
// require size or weight dimensions. For these permit types, the
|
|
109
|
+
// allowedCommodities must be configured in policy. Return these.
|
|
110
|
+
const commodities = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities, permitType.allowedCommodities);
|
|
111
|
+
return commodities;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Gets a list of all allowable vehicle types for the given permit type
|
|
117
|
+
* and commodity. Includes all power units and trailers.
|
|
118
|
+
* @param permitTypeId ID of the permit type to get vehicles for
|
|
119
|
+
* @param commodityId ID of the commodity to get vehicles for
|
|
120
|
+
* @returns Map of two separate maps, one keyed on 'powerUnits' and the
|
|
121
|
+
* other keyed on 'trailers'. Each map consists of a string id for the
|
|
122
|
+
* vehicle, and a string common name for the vehicle.
|
|
123
|
+
*/
|
|
124
|
+
getPermittableVehicleTypes(permitTypeId, commodityId) {
|
|
125
|
+
var _a, _b, _c, _d;
|
|
126
|
+
if (!permitTypeId || !commodityId) {
|
|
127
|
+
throw new Error('Missing permitTypeId and/or commodityId');
|
|
128
|
+
}
|
|
129
|
+
const permitType = this.getPermitTypeDefinition(permitTypeId);
|
|
130
|
+
if (!permitType) {
|
|
131
|
+
throw new Error(`Invalid permit type: '${permitTypeId}'`);
|
|
132
|
+
}
|
|
133
|
+
if (!permitType.commodityRequired) {
|
|
134
|
+
// If commodity is not required, this method cannot calculate the
|
|
135
|
+
// permittable vehicle types since they will not be configured.
|
|
136
|
+
throw new Error(`Permit type '${permitTypeId}' does not require a commodity`);
|
|
137
|
+
}
|
|
138
|
+
let puTypes;
|
|
139
|
+
let trTypes;
|
|
140
|
+
const allowableCommodities = this.getCommodities(permitTypeId);
|
|
141
|
+
if (!allowableCommodities.has(commodityId)) {
|
|
142
|
+
// If the commodity is not allowed for the permit type, no power
|
|
143
|
+
// units or trailers are allowed.
|
|
144
|
+
puTypes = new Map();
|
|
145
|
+
trTypes = new Map();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const commodity = this.getCommodityDefinition(commodityId);
|
|
149
|
+
if (!commodity) {
|
|
150
|
+
throw new Error(`Commodity id '${commodityId}' is not correctly configured in the policy definition`);
|
|
151
|
+
}
|
|
152
|
+
const puTypeIdsOS = (_b = (_a = commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.map((p) => p.type);
|
|
153
|
+
const trTypeIdsOS = [];
|
|
154
|
+
(_d = (_c = commodity.size) === null || _c === void 0 ? void 0 : _c.powerUnits) === null || _d === void 0 ? void 0 : _d.forEach((pu) => {
|
|
155
|
+
const trForPu = pu.trailers.map((t) => t.type);
|
|
156
|
+
if (trForPu)
|
|
157
|
+
trTypeIdsOS.concat(trForPu);
|
|
158
|
+
});
|
|
159
|
+
// TODO: implement along with overweight permits. Stub for now.
|
|
160
|
+
const puTypeIdsOW = [];
|
|
161
|
+
const trTypeIdsOW = [];
|
|
162
|
+
const puTypesOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIdsOS);
|
|
163
|
+
const trTypesOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIdsOS);
|
|
164
|
+
const puTypesOW = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIdsOW);
|
|
165
|
+
const trTypesOW = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIdsOW);
|
|
166
|
+
if (permitType.sizeDimensionRequired &&
|
|
167
|
+
permitType.weightDimensionRequired) {
|
|
168
|
+
puTypes = (0, lists_helper_1.intersectIdMaps)(puTypesOS, puTypesOW);
|
|
169
|
+
trTypes = (0, lists_helper_1.intersectIdMaps)(trTypesOS, trTypesOW);
|
|
170
|
+
}
|
|
171
|
+
else if (permitType.sizeDimensionRequired) {
|
|
172
|
+
puTypes = puTypesOS;
|
|
173
|
+
trTypes = trTypesOS;
|
|
174
|
+
}
|
|
175
|
+
else if (permitType.weightDimensionRequired) {
|
|
176
|
+
puTypes = puTypesOW;
|
|
177
|
+
trTypes = trTypesOW;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// This permit type requires commodity selection, but does not
|
|
181
|
+
// require size or weight dimensions. For these permit types, the
|
|
182
|
+
// allowedVehicles must be configured in policy. Return all power
|
|
183
|
+
// units and trailers from this list.
|
|
184
|
+
puTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, permitType.allowedVehicles);
|
|
185
|
+
trTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, permitType.allowedVehicles);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const vehicleTypes = new Map();
|
|
189
|
+
vehicleTypes.set(enum_1.VehicleTypes.PowerUnits, puTypes);
|
|
190
|
+
vehicleTypes.set(enum_1.VehicleTypes.Trailers, trTypes);
|
|
191
|
+
return vehicleTypes;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Gets a list of all allowable power unit types for the given permit type
|
|
195
|
+
* and commodity.
|
|
196
|
+
* @param permitTypeId ID of the permit type to get power units for
|
|
197
|
+
* @param commodityId ID of the commodity to get power units for
|
|
198
|
+
* @returns Map of power unit IDs to power unit names.
|
|
199
|
+
*/
|
|
200
|
+
getPermittablePowerUnitTypes(permitTypeId, commodityId) {
|
|
201
|
+
const vehicleTypes = this.getPermittableVehicleTypes(permitTypeId, commodityId);
|
|
202
|
+
const puTypes = vehicleTypes.get(enum_1.VehicleTypes.PowerUnits);
|
|
203
|
+
return puTypes !== null && puTypes !== void 0 ? puTypes : new Map();
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Gets the next permittable vehicles based on the supplied permit type,
|
|
207
|
+
* commodity, and current configuration.
|
|
208
|
+
* If the permit type does not require commodity or if the commodity
|
|
209
|
+
* is not valid for the permit type, this will return an empty map
|
|
210
|
+
* (meaning no vehicles are permittable).
|
|
211
|
+
* @param permitTypeId ID of the permit type to get vehicles for
|
|
212
|
+
* @param commodityId ID of the commodity to get vehicles for
|
|
213
|
+
* @param currentConfiguration Current vehicle configuration to which will be
|
|
214
|
+
* added the next permittable vehicle
|
|
215
|
+
* @returns Map of vehicle ID to vehicle name. Includes both power units and
|
|
216
|
+
* trailers in a single return value (if applicable).
|
|
217
|
+
*/
|
|
218
|
+
getNextPermittableVehicles(permitTypeId, commodityId, currentConfiguration) {
|
|
219
|
+
var _a, _b, _c, _d;
|
|
220
|
+
if (!permitTypeId || !commodityId || !currentConfiguration) {
|
|
221
|
+
throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
|
|
222
|
+
}
|
|
223
|
+
const permitType = this.getPermitTypeDefinition(permitTypeId);
|
|
224
|
+
if (!permitType) {
|
|
225
|
+
throw new Error(`Invalid permit type: '${permitTypeId}'`);
|
|
226
|
+
}
|
|
227
|
+
if (!permitType.commodityRequired) {
|
|
228
|
+
// If commodity is not required, this method cannot calculate the
|
|
229
|
+
// permittable vehicle types since they will not be configured.
|
|
230
|
+
throw new Error(`Permit type '${permitTypeId}' does not require a commodity`);
|
|
231
|
+
}
|
|
232
|
+
const commodity = this.getCommodityDefinition(commodityId);
|
|
233
|
+
if (!commodity) {
|
|
234
|
+
throw new Error(`Invalid commodity type: '${commodityId}'`);
|
|
235
|
+
}
|
|
236
|
+
if (!this.isConfigurationValid(permitTypeId, commodityId, currentConfiguration, true)) {
|
|
237
|
+
// Invalid configuration, no vehicles permitted
|
|
238
|
+
return new Map();
|
|
239
|
+
}
|
|
240
|
+
let vehicleTypes = new Map();
|
|
241
|
+
let vehicleTypeIds;
|
|
242
|
+
const allVehicles = this.policyDefinition.vehicleTypes.powerUnitTypes.concat(this.policyDefinition.vehicleTypes.trailerTypes);
|
|
243
|
+
if (currentConfiguration.length == 0) {
|
|
244
|
+
// The current configuration is empty, so return only the
|
|
245
|
+
// allowable power units.
|
|
246
|
+
vehicleTypeIds = (_b = (_a = commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.map((p) => p.type);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
const powerUnit = (_d = (_c = commodity.size) === null || _c === void 0 ? void 0 : _c.powerUnits) === null || _d === void 0 ? void 0 : _d.find((p) => p.type == currentConfiguration[0]);
|
|
250
|
+
const trailerIds = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.map((t) => t.type);
|
|
251
|
+
if (currentConfiguration.length == 1) {
|
|
252
|
+
// Just a power unit, return the list of trailerIds for the
|
|
253
|
+
// power unit, plus jeep if any of the trailer Ids allow
|
|
254
|
+
// a jeep.
|
|
255
|
+
if ((powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers) &&
|
|
256
|
+
(powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.filter((t) => t.jeep).length) > 0) {
|
|
257
|
+
trailerIds === null || trailerIds === void 0 ? void 0 : trailerIds.push(enum_1.AccessoryVehicleType.Jeep);
|
|
258
|
+
}
|
|
259
|
+
vehicleTypeIds = trailerIds;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const lastVehicleId = currentConfiguration[currentConfiguration.length - 1];
|
|
263
|
+
switch (lastVehicleId) {
|
|
264
|
+
case enum_1.AccessoryVehicleType.Jeep:
|
|
265
|
+
// If there is one jeep, there can be more
|
|
266
|
+
trailerIds === null || trailerIds === void 0 ? void 0 : trailerIds.push(enum_1.AccessoryVehicleType.Jeep);
|
|
267
|
+
vehicleTypeIds = trailerIds;
|
|
268
|
+
break;
|
|
269
|
+
case enum_1.AccessoryVehicleType.Booster:
|
|
270
|
+
// If there is one booster, there can be more
|
|
271
|
+
vehicleTypeIds = [enum_1.AccessoryVehicleType.Booster];
|
|
272
|
+
break;
|
|
273
|
+
default:
|
|
274
|
+
{
|
|
275
|
+
const trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == lastVehicleId);
|
|
276
|
+
if (trailer && trailer.booster) {
|
|
277
|
+
vehicleTypeIds = [enum_1.AccessoryVehicleType.Booster];
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
vehicleTypeIds = new Array();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
vehicleTypes = (0, lists_helper_1.extractIdentifiedObjects)(allVehicles, vehicleTypeIds);
|
|
288
|
+
return vehicleTypes;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Returns whether the supplied configuration is valid for the given permit type
|
|
292
|
+
* and commodity. If the permit type does not require a commodity, this method
|
|
293
|
+
* will return false. This will not validate incomplete configurations - if the
|
|
294
|
+
* current configuration has only a power unit this will return false even if the
|
|
295
|
+
* power unit is acceptable because there is no trailer which is mandatory.
|
|
296
|
+
* If this is called for a permit type that does not require commodity, or with
|
|
297
|
+
* a commodity not permitted for the permit type, it will return false.
|
|
298
|
+
* @param permitTypeId ID of the permit type to validate the configuration against
|
|
299
|
+
* @param commodityId ID of the commodity used for the configuration
|
|
300
|
+
* @param currentConfiguration Current vehicle configuration to validate
|
|
301
|
+
* @param validatePartial Whether to validate a partial configuration (e.g. one
|
|
302
|
+
* that does not include a trailer). This will just return whether or not there
|
|
303
|
+
* are any invalid vehicles in the configuration. If true, an empty current
|
|
304
|
+
* configuration will return true from this method.
|
|
305
|
+
*/
|
|
306
|
+
isConfigurationValid(permitTypeId, commodityId, currentConfiguration, validatePartial = false) {
|
|
307
|
+
var _a, _b;
|
|
308
|
+
if (!permitTypeId || !commodityId || !currentConfiguration) {
|
|
309
|
+
throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
|
|
310
|
+
}
|
|
311
|
+
const permitType = this.getPermitTypeDefinition(permitTypeId);
|
|
312
|
+
if (!permitType) {
|
|
313
|
+
throw new Error(`Invalid permit type: '${permitTypeId}'`);
|
|
314
|
+
}
|
|
315
|
+
if (!permitType.commodityRequired) {
|
|
316
|
+
// If commodity is not required, this method cannot calculate the
|
|
317
|
+
// permittable vehicle types since they will not be configured.
|
|
318
|
+
throw new Error(`Permit type '${permitTypeId}' does not require a commodity`);
|
|
319
|
+
}
|
|
320
|
+
const commodity = this.getCommodityDefinition(commodityId);
|
|
321
|
+
if (!commodity) {
|
|
322
|
+
throw new Error(`Invalid commodity type: '${commodityId}'`);
|
|
323
|
+
}
|
|
324
|
+
if (currentConfiguration.length == 0) {
|
|
325
|
+
// The current configuration is empty. Fine for partial, but
|
|
326
|
+
// invalid as a complete configuration.
|
|
327
|
+
return validatePartial;
|
|
328
|
+
}
|
|
329
|
+
const powerUnit = (_b = (_a = commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.find((p) => p.type == currentConfiguration[0]);
|
|
330
|
+
if (!powerUnit) {
|
|
331
|
+
// The power unit is not allowed for the commodity
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
let trailerIds = powerUnit.trailers.map((t) => t.type);
|
|
335
|
+
let jeepAllowed = true;
|
|
336
|
+
let trailerAllowed = true;
|
|
337
|
+
let boosterAllowed = false;
|
|
338
|
+
for (let i = 1; i < currentConfiguration.length; i++) {
|
|
339
|
+
switch (currentConfiguration[i]) {
|
|
340
|
+
case enum_1.AccessoryVehicleType.Jeep:
|
|
341
|
+
if (!jeepAllowed) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
// Filter allowed trailers to only those that allow jeeps
|
|
345
|
+
trailerIds = powerUnit.trailers
|
|
346
|
+
.filter((t) => t.jeep)
|
|
347
|
+
.map((t) => t.type);
|
|
348
|
+
break;
|
|
349
|
+
case enum_1.AccessoryVehicleType.Booster:
|
|
350
|
+
if (!boosterAllowed) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
default:
|
|
355
|
+
if (!trailerAllowed) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
{
|
|
359
|
+
const trailer = powerUnit.trailers.find((t) => t.type == currentConfiguration[i]);
|
|
360
|
+
if (!trailer || !trailerIds.includes(currentConfiguration[i])) {
|
|
361
|
+
// This trailer is not permitted for this power unit
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
jeepAllowed = false;
|
|
365
|
+
trailerAllowed = false;
|
|
366
|
+
boosterAllowed = trailer.booster;
|
|
367
|
+
}
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// We are still here, so configuration is valid. If there is a trailer
|
|
372
|
+
// it is a valid final configuration, otherwise it is a valid partial
|
|
373
|
+
// configuration.
|
|
374
|
+
return !trailerAllowed || validatePartial;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Gets the maximum size dimensions for a given permit type, commodity,
|
|
378
|
+
* and vehicle configuration. A vehicle configuration's size dimension is
|
|
379
|
+
* dictated by the configuration on the trailer. For configurations that
|
|
380
|
+
* are just a power unit, a pseudo trailer type 'NONE' is used and the
|
|
381
|
+
* size dimension is configured on that. Accessory category trailers
|
|
382
|
+
* (e.g. jeeps and boosters) are not used for configuration since they
|
|
383
|
+
* do not impact the size dimension in policy.
|
|
384
|
+
* @param permitTypeId ID of the permit type to get size dimension for
|
|
385
|
+
* @param commodityId ID of the commodity to get size dimension for
|
|
386
|
+
* @param currentConfiguration Current vehicle configuration to get size dimension for
|
|
387
|
+
* @param regions List of regions the vehicle will be traveling in. If not
|
|
388
|
+
* supplied this defaults to the most restrictive size dimension (if multiple
|
|
389
|
+
* are configured).
|
|
390
|
+
* @returns SizeDimension for the given permit type, commodity, and configuration
|
|
391
|
+
*/
|
|
392
|
+
getSizeDimension(permitTypeId, commodityId, configuration, regions) {
|
|
393
|
+
var _a, _b, _c;
|
|
394
|
+
// Initialize the sizeDimension with global defaults
|
|
395
|
+
let sizeDimension = null;
|
|
396
|
+
// Validate that the configuration is permittable
|
|
397
|
+
if (this.isConfigurationValid(permitTypeId, commodityId, configuration)) {
|
|
398
|
+
// Get the power unit that has the size configuration
|
|
399
|
+
const commodity = this.getCommodityDefinition(commodityId);
|
|
400
|
+
const powerUnit = (_b = (_a = commodity === null || commodity === void 0 ? void 0 : commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.find((pu) => pu.type == configuration[0]);
|
|
401
|
+
if (!powerUnit) {
|
|
402
|
+
throw new Error(`Configuration error: could not find power unit '${configuration[0]}'`);
|
|
403
|
+
}
|
|
404
|
+
// Get the last trailer in the configuration that can be used for size calculations
|
|
405
|
+
const sizeTrailer = Array.from(configuration)
|
|
406
|
+
.reverse()
|
|
407
|
+
.find((vehicleId) => {
|
|
408
|
+
var _a;
|
|
409
|
+
const trailerType = (_a = this.policyDefinition.vehicleTypes.trailerTypes) === null || _a === void 0 ? void 0 : _a.find((v) => v.id == vehicleId);
|
|
410
|
+
return !(trailerType === null || trailerType === void 0 ? void 0 : trailerType.ignoreForSizeDimensions);
|
|
411
|
+
});
|
|
412
|
+
if (sizeTrailer) {
|
|
413
|
+
// Get the trailer size dimension array for the commodity
|
|
414
|
+
const trailer = (_c = powerUnit.trailers) === null || _c === void 0 ? void 0 : _c.find((t) => t.type == sizeTrailer);
|
|
415
|
+
let sizeDimensions;
|
|
416
|
+
if (trailer &&
|
|
417
|
+
trailer.sizeDimensions &&
|
|
418
|
+
trailer.sizeDimensions.length > 0) {
|
|
419
|
+
sizeDimensions = trailer.sizeDimensions;
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
sizeDimensions = new Array();
|
|
423
|
+
}
|
|
424
|
+
const sizeDimensionConfigured = this.selectCorrectSizeDimension(sizeDimensions, configuration, sizeTrailer);
|
|
425
|
+
if (sizeDimensionConfigured) {
|
|
426
|
+
// Adjust the size dimensions for the regions travelled, if needed
|
|
427
|
+
if (!regions) {
|
|
428
|
+
// If we are not provided a list of regions, assume we are
|
|
429
|
+
// traveling through all regions (will take the most restrictive
|
|
430
|
+
// of all dimensions in all cases).
|
|
431
|
+
console.log('Assuming all regions for size dimension lookup');
|
|
432
|
+
regions = this.policyDefinition.geographicRegions.map((g) => g.id);
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
console.log(`Using '${regions}' as regions for size lookup`);
|
|
436
|
+
}
|
|
437
|
+
const valueOverrides = [];
|
|
438
|
+
regions === null || regions === void 0 ? void 0 : regions.forEach((r) => {
|
|
439
|
+
var _a, _b, _c, _d;
|
|
440
|
+
let valueOverride;
|
|
441
|
+
// Check to see if this region has specific size dimensions
|
|
442
|
+
const regionOverride = (_a = sizeDimensionConfigured.regions) === null || _a === void 0 ? void 0 : _a.find((cr) => cr.region == r);
|
|
443
|
+
if (!regionOverride) {
|
|
444
|
+
// The region travelled does not have an override, so it assumes
|
|
445
|
+
// the dimensions of the bc default.
|
|
446
|
+
valueOverride = {
|
|
447
|
+
region: r,
|
|
448
|
+
h: sizeDimensionConfigured.h,
|
|
449
|
+
w: sizeDimensionConfigured.w,
|
|
450
|
+
l: sizeDimensionConfigured.l,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
// There is a region override with one or more dimensions. Use this
|
|
455
|
+
// value preferentially, using default dimension if not supplied
|
|
456
|
+
valueOverride = {
|
|
457
|
+
region: r,
|
|
458
|
+
h: (_b = regionOverride.h) !== null && _b !== void 0 ? _b : sizeDimensionConfigured.h,
|
|
459
|
+
w: (_c = regionOverride.w) !== null && _c !== void 0 ? _c : sizeDimensionConfigured.w,
|
|
460
|
+
l: (_d = regionOverride.l) !== null && _d !== void 0 ? _d : sizeDimensionConfigured.l,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
valueOverrides.push(valueOverride);
|
|
464
|
+
});
|
|
465
|
+
// At this point we have a complete set of size dimensions for each of
|
|
466
|
+
// the regions that will be traversed. Take the minimum value of each
|
|
467
|
+
// dimension for the final value.
|
|
468
|
+
const minimumOverrides = valueOverrides.reduce((accumulator, currentValue) => {
|
|
469
|
+
if (typeof currentValue.h !== 'undefined') {
|
|
470
|
+
if (typeof accumulator.h === 'undefined') {
|
|
471
|
+
accumulator.h = currentValue.h;
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
accumulator.h = Math.min(accumulator.h, currentValue.h);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (typeof currentValue.w !== 'undefined') {
|
|
478
|
+
if (typeof accumulator.w === 'undefined') {
|
|
479
|
+
accumulator.w = currentValue.w;
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
accumulator.w = Math.min(accumulator.w, currentValue.w);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (typeof currentValue.l !== 'undefined') {
|
|
486
|
+
if (typeof accumulator.l === 'undefined') {
|
|
487
|
+
accumulator.l = currentValue.l;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
accumulator.l = Math.min(accumulator.l, currentValue.l);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return accumulator;
|
|
494
|
+
}, { region: '' });
|
|
495
|
+
sizeDimension = {
|
|
496
|
+
rp: sizeDimensionConfigured.rp,
|
|
497
|
+
fp: sizeDimensionConfigured.fp,
|
|
498
|
+
h: minimumOverrides.h,
|
|
499
|
+
w: minimumOverrides.w,
|
|
500
|
+
l: minimumOverrides.l,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
console.log('Size dimension not configured for trailer');
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
console.log('Could not locate trailer to use for size dimension');
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
console.log('Configuration is invalid, returning null size dimension');
|
|
513
|
+
}
|
|
514
|
+
return sizeDimension;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Selects the correct size dimension from a list of potential candidates, based
|
|
518
|
+
* on the modifier of each dimension. If none of the modifiers match, returns
|
|
519
|
+
* null.
|
|
520
|
+
* @param sizeDimensions Size dimension options to choose from
|
|
521
|
+
* @param currentConfiguration The full vehicle configuration
|
|
522
|
+
*/
|
|
523
|
+
selectCorrectSizeDimension(sizeDimensions, configuration, sizeTrailer) {
|
|
524
|
+
var _a;
|
|
525
|
+
let matchingDimension = null;
|
|
526
|
+
if ((sizeDimensions === null || sizeDimensions === void 0 ? void 0 : sizeDimensions.length) > 0 && (configuration === null || configuration === void 0 ? void 0 : configuration.length) > 0) {
|
|
527
|
+
for (const sizeDimension of sizeDimensions) {
|
|
528
|
+
if (!sizeDimension.modifiers) {
|
|
529
|
+
// This dimension has no modifiers, so it is the default if none of
|
|
530
|
+
// the other specific modifiers match.
|
|
531
|
+
matchingDimension = sizeDimension;
|
|
532
|
+
console.log('Using default size dimension, no modifiers specified');
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
const sizeTrailerIndex = configuration.findIndex((c) => sizeTrailer == c);
|
|
536
|
+
const isMatch = (_a = sizeDimension.modifiers) === null || _a === void 0 ? void 0 : _a.every((m) => {
|
|
537
|
+
if (!m.type) {
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
switch (m.position) {
|
|
541
|
+
case enum_1.RelativePosition.First.toString():
|
|
542
|
+
return configuration[0] == m.type;
|
|
543
|
+
case enum_1.RelativePosition.Last.toString():
|
|
544
|
+
return configuration[configuration.length - 1] == m.type;
|
|
545
|
+
case enum_1.RelativePosition.Before.toString():
|
|
546
|
+
return configuration[sizeTrailerIndex - 1] == m.type;
|
|
547
|
+
case enum_1.RelativePosition.After.toString():
|
|
548
|
+
return configuration[sizeTrailerIndex + 1] == m.type;
|
|
549
|
+
default:
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
// As soon as we find a dimension with matching modifiers,
|
|
554
|
+
// set it and return it.
|
|
555
|
+
if (isMatch) {
|
|
556
|
+
matchingDimension = sizeDimension;
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
console.log('Either size dimensions or configuration array is null, no matching dimension returned');
|
|
564
|
+
}
|
|
565
|
+
return matchingDimension;
|
|
73
566
|
}
|
|
74
567
|
/**
|
|
75
568
|
* Gets a list of all configured power unit types in the policy definition.
|
|
@@ -104,5 +597,22 @@ class Policy {
|
|
|
104
597
|
return null;
|
|
105
598
|
}
|
|
106
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Gets a full Commodity definition by ID
|
|
602
|
+
* @param type Type ID of the commodity to return.
|
|
603
|
+
* @returns Commodity definition for the supplied ID.
|
|
604
|
+
*/
|
|
605
|
+
getCommodityDefinition(type) {
|
|
606
|
+
let commodity;
|
|
607
|
+
if (this.policyDefinition.commodities) {
|
|
608
|
+
commodity = this.policyDefinition.commodities.find((c) => c.id === type);
|
|
609
|
+
}
|
|
610
|
+
if (commodity) {
|
|
611
|
+
return commodity;
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
107
617
|
}
|
|
108
618
|
exports.Policy = Policy;
|
|
@@ -16,7 +16,11 @@ function dateStringValidator(a) {
|
|
|
16
16
|
}
|
|
17
17
|
const CustomOperators = [];
|
|
18
18
|
exports.CustomOperators = CustomOperators;
|
|
19
|
-
CustomOperators.push(new json_rules_engine_1.Operator('stringMinimumLength', (a, b) =>
|
|
19
|
+
CustomOperators.push(new json_rules_engine_1.Operator('stringMinimumLength', (a, b) => {
|
|
20
|
+
if (!a)
|
|
21
|
+
return false;
|
|
22
|
+
return a.trim().length >= b;
|
|
23
|
+
}, stringValidator));
|
|
20
24
|
CustomOperators.push(new json_rules_engine_1.Operator('dateLessThan', (a, b) => {
|
|
21
25
|
const firstDate = (0, dayjs_1.default)(a, enum_1.PermitAppInfo.PermitDateFormat.toString());
|
|
22
26
|
const secondDate = (0, dayjs_1.default)(b, enum_1.PermitAppInfo.PermitDateFormat.toString());
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { IdentifiedObject,
|
|
1
|
+
import { IdentifiedObject, VehicleSizeConfiguration, PowerUnitWeight, TrailerWeight } from 'onroute-policy-engine/types';
|
|
2
2
|
export type Commodity = IdentifiedObject & {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
size?: CommoditySize;
|
|
4
|
+
weight?: CommodityWeight;
|
|
5
|
+
};
|
|
6
|
+
export type CommoditySize = {
|
|
7
|
+
powerUnits?: Array<VehicleSizeConfiguration>;
|
|
8
|
+
};
|
|
9
|
+
export type CommodityWeight = {
|
|
10
|
+
powerUnits?: Array<PowerUnitWeight>;
|
|
11
|
+
trailers?: Array<TrailerWeight>;
|
|
5
12
|
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
export { Commodity } from './commodity';
|
|
1
|
+
export { Commodity, CommoditySize, CommodityWeight } from './commodity';
|
|
2
|
+
export { CostRule } from './cost-rule';
|
|
2
3
|
export { DimensionModifier } from './dimension-modifier';
|
|
3
4
|
export { PermitFacts } from './facts';
|
|
4
5
|
export { GeographicRegion } from './geographic-region';
|
|
5
6
|
export { IdentifiedObject } from './identified-object';
|
|
6
7
|
export { PermitType } from './permit-type';
|
|
7
8
|
export { PolicyDefinition } from './policy-definition';
|
|
9
|
+
export { Matrix, RangeMatrix } from './range-matrix';
|
|
8
10
|
export { RegionSizeOverride } from './region-size-override';
|
|
9
11
|
export { SelfIssuable } from './self-issuable';
|
|
10
12
|
export { SizeDimension } from './size-dimension';
|
|
11
13
|
export { VehicleCategory, PowerUnitCategory, TrailerCategory, VehicleCategories, } from './vehicle-category';
|
|
12
14
|
export { VehicleType, PowerUnitType, TrailerType, VehicleTypes, } from './vehicle-type';
|
|
13
|
-
export { Vehicle,
|
|
15
|
+
export { Vehicle, VehicleSizeConfiguration, TrailerSize, PowerUnitWeight, TrailerWeight, } from './vehicle';
|
|
14
16
|
export { WeightDimension, PowerUnitWeightDimension, TrailerWeightDimension, DefaultWeightDimensions, } from './weight-dimension';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RuleProperties } from 'json-rules-engine';
|
|
2
|
-
import { IdentifiedObject } from 'onroute-policy-engine/types';
|
|
2
|
+
import { CostRule, IdentifiedObject } from 'onroute-policy-engine/types';
|
|
3
3
|
export type PermitType = IdentifiedObject & {
|
|
4
4
|
routingRequired: boolean;
|
|
5
5
|
weightDimensionRequired: boolean;
|
|
@@ -8,4 +8,5 @@ export type PermitType = IdentifiedObject & {
|
|
|
8
8
|
allowedVehicles: Array<string>;
|
|
9
9
|
allowedCommodities?: Array<string>;
|
|
10
10
|
rules?: Array<RuleProperties>;
|
|
11
|
+
costRules?: Array<CostRule>;
|
|
11
12
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GeographicRegion, PermitType, DefaultWeightDimensions, VehicleTypes, Commodity, SizeDimension, VehicleCategories } from 'onroute-policy-engine/types';
|
|
1
|
+
import { GeographicRegion, PermitType, DefaultWeightDimensions, VehicleTypes, Commodity, SizeDimension, VehicleCategories, RangeMatrix } from 'onroute-policy-engine/types';
|
|
2
2
|
import { RuleProperties } from 'json-rules-engine';
|
|
3
3
|
export type PolicyDefinition = {
|
|
4
4
|
version: string;
|
|
@@ -10,4 +10,5 @@ export type PolicyDefinition = {
|
|
|
10
10
|
vehicleCategories: VehicleCategories;
|
|
11
11
|
vehicleTypes: VehicleTypes;
|
|
12
12
|
commodities: Array<Commodity>;
|
|
13
|
+
rangeMatrices?: Array<RangeMatrix>;
|
|
13
14
|
};
|