onroute-policy-engine 1.8.4 → 2.0.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.
@@ -0,0 +1,21 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+
8
+ {
9
+ "type": "node",
10
+ "request": "launch",
11
+ "name": "Debug Jest Test",
12
+ "program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
13
+ "args": [
14
+ "--runInBand"
15
+ ],
16
+ "console": "integratedTerminal",
17
+ "internalConsoleOptions": "neverOpen",
18
+ "cwd": "${workspaceFolder}"
19
+ }
20
+ ]
21
+ }
@@ -3,7 +3,8 @@ export declare enum PolicyFacts {
3
3
  DaysInPermitYear = "daysInPermitYear",
4
4
  EndOfPermitQuarter = "endOfPermitQuarter",
5
5
  ValidationDate = "validationDate",
6
- ConfigurationIsValid = "configurationIsValid"
6
+ ConfigurationIsValid = "configurationIsValid",
7
+ DaysBetween = "daysBetween"
7
8
  }
8
9
  export declare enum CostFacts {
9
10
  ConditionalFixedCost = "conditionalFixedCost",
@@ -8,6 +8,7 @@ var PolicyFacts;
8
8
  PolicyFacts["EndOfPermitQuarter"] = "endOfPermitQuarter";
9
9
  PolicyFacts["ValidationDate"] = "validationDate";
10
10
  PolicyFacts["ConfigurationIsValid"] = "configurationIsValid";
11
+ PolicyFacts["DaysBetween"] = "daysBetween";
11
12
  })(PolicyFacts || (exports.PolicyFacts = PolicyFacts = {}));
12
13
  var CostFacts;
13
14
  (function (CostFacts) {
@@ -1,5 +1,5 @@
1
1
  import { BridgeCalculationResult, AxleConfiguration } from 'onroute-policy-engine/types';
2
- import { Policy } from '../policy-engine';
2
+ import { Policy } from 'onroute-policy-engine';
3
3
  /**
4
4
  * Runs the bridge formula against the supplied vehicle axle configuration.
5
5
  * Evaluates the weight against all possible axle group combinations and returns
@@ -1,5 +1,5 @@
1
- import { Policy } from '../policy-engine';
2
- import { ConditionForPermit } from '../types';
1
+ import { Policy } from 'onroute-policy-engine';
2
+ import { ConditionForPermit } from 'onroute-policy-engine/types';
3
3
  /**
4
4
  * Gets a list of conditions that are applicable for the supplied permit
5
5
  * application. The conditions may be driven by those applicable for the
@@ -1,6 +1,5 @@
1
- import { Policy } from '../policy-engine';
2
- import { AxleConfiguration, PowerUnitWeightDimension, SizeDimension, TrailerWeightDimension, VehicleRelatives, WeightDimension } from '../types';
3
- import { SingleAxleDimension } from '../types/weight-dimension';
1
+ import { Policy } from 'onroute-policy-engine';
2
+ import { AxleConfiguration, PowerUnitWeightDimension, SingleAxleDimension, SizeDimension, TrailerWeightDimension, VehicleRelatives, WeightDimension } from 'onroute-policy-engine/types';
4
3
  /**
5
4
  * Gets the maximum size dimensions for a given permit type, commodity,
6
5
  * and vehicle configuration. A vehicle configuration's size dimension is
@@ -79,8 +78,8 @@ export declare function selectCorrectWeightDimensionHelper(policy: Policy, weigh
79
78
  /**
80
79
  * Convenience method to get the vehicles in the configuration relative
81
80
  * to the axle unit at the indicated axleIndex, to be used when
82
- * evaluating weight modifiers.
83
- * @param policy The instantiated policy object with weight config
81
+ * evaluating dimension modifiers.
82
+ * @param policy The instantiated policy object with dimension config
84
83
  * @param configuration Full vehicle configuration
85
84
  * @param axleIndex Index of the axle unit for which relatives are
86
85
  * to be returned.
@@ -6,7 +6,7 @@ exports.getDefaultPowerUnitWeightHelper = getDefaultPowerUnitWeightHelper;
6
6
  exports.getDefaultTrailerWeightHelper = getDefaultTrailerWeightHelper;
7
7
  exports.selectCorrectWeightDimensionHelper = selectCorrectWeightDimensionHelper;
8
8
  exports.getVehicleRelatives = getVehicleRelatives;
9
- const enum_1 = require("../enum");
9
+ const enum_1 = require("onroute-policy-engine/enum");
10
10
  /**
11
11
  * Gets the maximum size dimensions for a given permit type, commodity,
12
12
  * and vehicle configuration. A vehicle configuration's size dimension is
@@ -24,14 +24,14 @@ const enum_1 = require("../enum");
24
24
  * @returns SizeDimension for the given permit type, commodity, and configuration
25
25
  */
26
26
  function getSizeDimensionHelper(policy, permitTypeId, commodityId, configuration, regions) {
27
- var _a, _b, _c;
27
+ var _a;
28
28
  // Initialize the sizeDimension with global defaults
29
29
  let sizeDimension = null;
30
30
  // Validate that the configuration is permittable
31
31
  if (policy.isConfigurationValid(permitTypeId, commodityId, configuration)) {
32
32
  // Get the power unit that has the size configuration
33
33
  const commodity = policy.getCommodityDefinition(commodityId);
34
- 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]);
34
+ const powerUnit = commodity === null || commodity === void 0 ? void 0 : commodity.powerUnits.find((pu) => pu.type == configuration[0]);
35
35
  if (!powerUnit) {
36
36
  throw new Error(`Configuration error: could not find power unit '${configuration[0]}'`);
37
37
  }
@@ -45,16 +45,13 @@ function getSizeDimensionHelper(policy, permitTypeId, commodityId, configuration
45
45
  });
46
46
  if (sizeTrailer) {
47
47
  // Get the trailer size dimension array for the commodity
48
- const trailer = (_c = powerUnit.trailers) === null || _c === void 0 ? void 0 : _c.find((t) => t.type == sizeTrailer);
49
- let sizeDimensions;
48
+ const trailer = (_a = powerUnit.trailers) === null || _a === void 0 ? void 0 : _a.find((t) => t.type == sizeTrailer);
49
+ let sizeDimensions = [];
50
50
  if (trailer &&
51
51
  trailer.sizeDimensions &&
52
52
  trailer.sizeDimensions.length > 0) {
53
53
  sizeDimensions = trailer.sizeDimensions;
54
54
  }
55
- else {
56
- sizeDimensions = new Array();
57
- }
58
55
  const sizeDimensionConfigured = selectCorrectSizeDimension(sizeDimensions, configuration, sizeTrailer);
59
56
  if (sizeDimensionConfigured) {
60
57
  // Adjust the size dimensions for the regions travelled, if needed
@@ -427,8 +424,8 @@ function selectCorrectWeightDimensionHelper(policy, weightDimensions, configurat
427
424
  /**
428
425
  * Convenience method to get the vehicles in the configuration relative
429
426
  * to the axle unit at the indicated axleIndex, to be used when
430
- * evaluating weight modifiers.
431
- * @param policy The instantiated policy object with weight config
427
+ * evaluating dimension modifiers.
428
+ * @param policy The instantiated policy object with dimension config
432
429
  * @param configuration Full vehicle configuration
433
430
  * @param axleIndex Index of the axle unit for which relatives are
434
431
  * to be returned.
@@ -436,10 +433,13 @@ function selectCorrectWeightDimensionHelper(policy, weightDimensions, configurat
436
433
  */
437
434
  function getVehicleRelatives(policy, configuration, axleIndex) {
438
435
  var _a, _b;
436
+ if (!configuration || configuration.length === 0) {
437
+ throw new Error('Cannot get relatives with an empty configuration');
438
+ }
439
439
  const firstType = configuration[0];
440
- const lastType = configuration[configuration.length - 1];
441
440
  const firstVehicle = policy.getVehicleDefinition(firstType);
442
- const lastVehicle = policy.getVehicleDefinition(lastType);
441
+ const lastVehicle = walk(policy, configuration, configuration.length - 1, -1);
442
+ const lastType = lastVehicle === null || lastVehicle === void 0 ? void 0 : lastVehicle.id;
443
443
  // Get relevant nearby vehicle types for the target axle
444
444
  const vehicleRelatives = {
445
445
  firstType: firstType,
@@ -455,8 +455,11 @@ function getVehicleRelatives(policy, configuration, axleIndex) {
455
455
  }
456
456
  else {
457
457
  // Subtract 2 from the configuration index to account for
458
- // the fact that the power unit has two axles.
459
- vehicleRelatives.prevType = configuration[axleIndex - 2];
458
+ // the fact that the power unit has two axles. We walk the
459
+ // configuration here to jump over any pseudo vehicles like
460
+ // additional axle units.
461
+ const prevVehicleType = walk(policy, configuration, axleIndex - 2, -1);
462
+ vehicleRelatives.prevType = prevVehicleType === null || prevVehicleType === void 0 ? void 0 : prevVehicleType.id;
460
463
  vehicleRelatives.prevCategory = (_a = policy.getVehicleDefinition(vehicleRelatives.prevType)) === null || _a === void 0 ? void 0 : _a.category;
461
464
  }
462
465
  if (configuration.length === 1 || axleIndex === configuration.length) {
@@ -466,8 +469,40 @@ function getVehicleRelatives(policy, configuration, axleIndex) {
466
469
  vehicleRelatives.nextCategory = null;
467
470
  }
468
471
  else {
469
- vehicleRelatives.nextType = configuration[axleIndex];
472
+ // Walk the configuration towards the rear, to jump over any
473
+ // pseudo vehicle in the line.
474
+ const nextVehicleType = walk(policy, configuration, axleIndex, 1);
475
+ vehicleRelatives.nextType = nextVehicleType === null || nextVehicleType === void 0 ? void 0 : nextVehicleType.id;
470
476
  vehicleRelatives.nextCategory = (_b = policy.getVehicleDefinition(vehicleRelatives.nextType)) === null || _b === void 0 ? void 0 : _b.category;
471
477
  }
472
478
  return vehicleRelatives;
473
479
  }
480
+ /**
481
+ * Walks along the vehicle configuration from the start index
482
+ * in the direction indicated by increment, which will typically
483
+ * be either 1 (towards the rear of the vehicle) or -1 (towards
484
+ * the front of the vehicle), and returns the first non-pseudo
485
+ * vehicle encountered. If no non-pseudo vehicles are encountered,
486
+ * returns null.
487
+ * @param policy The instantiated policy object with dimension config
488
+ * @param configuration Full vehicle configuration
489
+ * @param startIndex Index at which to begin search (will return
490
+ * the vehicle at startIndex if that vehicle is non-pseudo)
491
+ * @param increment Direction of travel, either 1 (towards the rear
492
+ * of the vehicle) or -1 (towards the front of the vehicle)
493
+ * @returns First non-pseudo vehicle encountered in the direction
494
+ * of travel
495
+ */
496
+ function walk(policy, configuration, startIndex, increment) {
497
+ let i = startIndex;
498
+ let vehicleType = null;
499
+ while (i >= 0 && i < configuration.length) {
500
+ const nextType = policy.getVehicleDefinition(configuration[i]);
501
+ if (nextType && nextType.category !== enum_1.VehicleCategory.Pseudo) {
502
+ vehicleType = nextType;
503
+ break;
504
+ }
505
+ i = i + increment;
506
+ }
507
+ return vehicleType;
508
+ }
@@ -1,5 +1,5 @@
1
1
  import { Engine } from 'json-rules-engine';
2
- import { Policy } from '../policy-engine';
2
+ import { Policy } from 'onroute-policy-engine';
3
3
  /**
4
4
  * Adds runtime facts for the validation. For example, adds the
5
5
  * validation date for comparison against startDate of the permit.
@@ -83,6 +83,20 @@ function addRuntimeFacts(engine, policy) {
83
83
  }
84
84
  return allowedVehicles;
85
85
  });
86
+ /**
87
+ * Add runtime fact to calculate the number of days between a from
88
+ * and to date supplied in parameters. Will be positive for a dateTo
89
+ * in the future with respect to dateFrom, negative otherwise.
90
+ */
91
+ engine.addFact(enum_1.PolicyFacts.DaysBetween.toString(), async function (params, almanac) {
92
+ const dateFromStr = await almanac.factValue(params.dateFrom.fact, {}, params.dateFrom.path);
93
+ const dateToStr = await almanac.factValue(params.dateTo.fact, {}, params.dateTo.path);
94
+ const dateFrom = (0, dayjs_1.default)(dateFromStr, enum_1.PermitAppInfo.PermitDateFormat);
95
+ const dateTo = (0, dayjs_1.default)(dateToStr, enum_1.PermitAppInfo.PermitDateFormat);
96
+ const daysBetween = dateTo.diff(dateFrom, 'day');
97
+ console.log(`Calculated daysBetween '${dateFromStr}' and '${dateToStr}' as '${daysBetween}'`);
98
+ return daysBetween;
99
+ });
86
100
  /**
87
101
  * Add runtime fact for a fixed permit cost, the cost supplied
88
102
  * as a parameter.
@@ -1,4 +1,4 @@
1
- import { VehicleTypes } from '../types';
1
+ import { VehicleTypes } from 'onroute-policy-engine/types';
2
2
  /**
3
3
  * Filters out all LCV vehicles from a supplied list of vehicle IDs.
4
4
  * @param vehicleList List of vehicle IDs to filter
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.filterOutLcv = filterOutLcv;
4
4
  exports.filterVehiclesByType = filterVehiclesByType;
5
- const enum_1 = require("../enum");
5
+ const enum_1 = require("onroute-policy-engine/enum");
6
6
  /**
7
7
  * Filters out all LCV vehicles from a supplied list of vehicle IDs.
8
8
  * @param vehicleList List of vehicle IDs to filter
@@ -1,4 +1,4 @@
1
- import { PolicyDefinition, PermitType, Commodity, VehicleType, SizeDimension, AxleConfiguration, BridgeCalculationResult, ConditionForPermit, TrailerType, PowerUnitType, TrailerWeightDimension, PowerUnitWeightDimension, WeightDimension, SingleAxleDimension, StandardTireSize } from 'onroute-policy-engine/types';
1
+ import { PolicyDefinition, PermitType, Commodity, VehicleType, SizeDimension, AxleConfiguration, BridgeCalculationResult, ConditionForPermit, TrailerType, PowerUnitType, TrailerWeightDimension, PowerUnitWeightDimension, WeightDimension, SingleAxleDimension, StandardTireSize, TrailerDimensions } from 'onroute-policy-engine/types';
2
2
  import { Engine } from 'json-rules-engine';
3
3
  import { ValidationResults } from './validation-results';
4
4
  import { SpecialAuthorizations } from './types/special-authorizations';
@@ -77,6 +77,17 @@ export declare class Policy {
77
77
  * vehicle, and a string common name for the vehicle.
78
78
  */
79
79
  getPermittableVehicleTypes(permitTypeId: string, commodityId?: string | null): Map<string, Map<string, string>>;
80
+ /**
81
+ * Given a trailer dimensions object from the commodities
82
+ * configuration and a permit type, return whether or not the
83
+ * trailer is permittable - this will depend on whether the trailer
84
+ * is size and/or weight permittable, and whether the permit
85
+ * type requires size and/or weight dimensions.
86
+ * @param permitType The permit type object
87
+ * @param trailer The trailer dimensions object for a specific commodity
88
+ * @returns true if the trailer is permittable, false otherwise
89
+ */
90
+ isTrailerPermittable(permitType: PermitType, trailer: TrailerDimensions): boolean | undefined;
80
91
  /**
81
92
  * Gets a list of all allowable power unit types for the given permit type
82
93
  * and commodity.
@@ -150,29 +150,15 @@ class Policy {
150
150
  return new Map();
151
151
  }
152
152
  else {
153
- // Commodities for oversize permits are those which have at least one
154
- // power unit defined in the size dimension object of the commodity.
155
153
  const commoditiesForOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities.filter((c) => {
156
- if (c.size) {
157
- if (c.size.powerUnits) {
158
- if (c.size.powerUnits.length > 0) {
159
- return true;
160
- }
161
- }
162
- }
163
- return false;
154
+ // Return true if any of the power units has any size
155
+ // permittable trailers
156
+ return c.powerUnits.some((p) => p.trailers.some((t) => t.sizePermittable));
164
157
  }));
165
- // Commodities for overweight permits are those which have at least one
166
- // power unit defined in the weight dimension object of the commodity.
167
158
  const commoditiesForOW = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities.filter((c) => {
168
- if (c.weight) {
169
- if (c.weight.powerUnits) {
170
- if (c.weight.powerUnits.length > 0) {
171
- return true;
172
- }
173
- }
174
- }
175
- return false;
159
+ // Return true if any of the power units has any size
160
+ // permittable trailers
161
+ return c.powerUnits.some((p) => p.trailers.some((t) => t.weightPermittable));
176
162
  }));
177
163
  if (permitType.sizeDimensionRequired &&
178
164
  permitType.weightDimensionRequired) {
@@ -203,7 +189,7 @@ class Policy {
203
189
  * vehicle, and a string common name for the vehicle.
204
190
  */
205
191
  getPermittableVehicleTypes(permitTypeId, commodityId) {
206
- var _a, _b, _c, _d, _e;
192
+ var _a;
207
193
  if (!permitTypeId) {
208
194
  throw new Error('Missing permitTypeId');
209
195
  }
@@ -233,62 +219,67 @@ class Policy {
233
219
  if (!commodity) {
234
220
  throw new Error(`Commodity id '${commodityId}' is not correctly configured in the policy definition`);
235
221
  }
236
- let puTypeIdsOS = (_b = (_a = commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.map((p) => p.type);
237
- let trTypeIdsOS = [];
238
- (_d = (_c = commodity.size) === null || _c === void 0 ? void 0 : _c.powerUnits) === null || _d === void 0 ? void 0 : _d.forEach((pu) => {
239
- const trForPu = pu.trailers.map((t) => t.type);
240
- if (trForPu)
241
- trTypeIdsOS === null || trTypeIdsOS === void 0 ? void 0 : trTypeIdsOS.concat(trForPu);
222
+ // Extract the permittable power unit and trailer IDs. If the permit
223
+ // type requires both size and weight dimension, only extract the
224
+ // power units that have at least one trailer that is both size and
225
+ // weight permittable.
226
+ const permittablePowerUnits = commodity.powerUnits.filter((p) => {
227
+ return p.trailers.some((t) => {
228
+ return this.isTrailerPermittable(permitType, t);
229
+ });
230
+ });
231
+ let puTypeIds = permittablePowerUnits.map((p) => p.type);
232
+ let trTypeIds = [];
233
+ permittablePowerUnits.forEach((pu) => {
234
+ trTypeIds = trTypeIds.concat(pu.trailers
235
+ .filter((t) => {
236
+ return this.isTrailerPermittable(permitType, t);
237
+ })
238
+ .map((t) => t.type));
242
239
  });
243
- // TODO: implement along with overweight permits. Stub for now.
244
- let puTypeIdsOW = [];
245
- let trTypeIdsOW = [];
240
+ // Remove duplicate trailer IDs
241
+ trTypeIds = [...new Set(trTypeIds)];
246
242
  // Remove long combination vehicles if needed
247
- if (!((_e = this.specialAuthorizations) === null || _e === void 0 ? void 0 : _e.isLcvAllowed)) {
248
- if (puTypeIdsOS) {
249
- puTypeIdsOS = this.filterOutLongCombinationVehicles(puTypeIdsOS);
250
- }
251
- if (trTypeIdsOS) {
252
- trTypeIdsOS = this.filterOutLongCombinationVehicles(trTypeIdsOS);
253
- }
254
- if (puTypeIdsOW) {
255
- puTypeIdsOW = this.filterOutLongCombinationVehicles(puTypeIdsOW);
256
- }
257
- if (trTypeIdsOW) {
258
- trTypeIdsOW = this.filterOutLongCombinationVehicles(trTypeIdsOW);
259
- }
260
- }
261
- const puTypesOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIdsOS);
262
- const trTypesOS = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIdsOS);
263
- const puTypesOW = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIdsOW);
264
- const trTypesOW = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIdsOW);
265
- if (permitType.sizeDimensionRequired &&
266
- permitType.weightDimensionRequired) {
267
- puTypes = (0, lists_helper_1.intersectIdMaps)(puTypesOS, puTypesOW);
268
- trTypes = (0, lists_helper_1.intersectIdMaps)(trTypesOS, trTypesOW);
243
+ if (!((_a = this.specialAuthorizations) === null || _a === void 0 ? void 0 : _a.isLcvAllowed)) {
244
+ puTypeIds = this.filterOutLongCombinationVehicles(puTypeIds);
245
+ trTypeIds = this.filterOutLongCombinationVehicles(trTypeIds);
269
246
  }
270
- else if (permitType.sizeDimensionRequired) {
271
- puTypes = puTypesOS;
272
- trTypes = trTypesOS;
273
- }
274
- else if (permitType.weightDimensionRequired) {
275
- puTypes = puTypesOW;
276
- trTypes = trTypesOW;
277
- }
278
- else {
247
+ if (!(permitType.sizeDimensionRequired || permitType.weightDimensionRequired)) {
279
248
  // This permit type requires commodity selection, but does not
280
249
  // require size or weight dimensions. For these permit types, the
281
250
  // allowedVehicles must be configured in policy. Return all power
282
251
  // units and trailers from this list.
283
- puTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, permitType.allowedVehicles);
284
- trTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, permitType.allowedVehicles);
252
+ puTypeIds = permitType.allowedVehicles || [];
253
+ trTypeIds = permitType.allowedVehicles || [];
285
254
  }
255
+ puTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIds);
256
+ trTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIds);
286
257
  }
287
258
  const vehicleTypes = new Map();
288
259
  vehicleTypes.set(enum_1.VehicleTypes.PowerUnits, puTypes);
289
260
  vehicleTypes.set(enum_1.VehicleTypes.Trailers, trTypes);
290
261
  return vehicleTypes;
291
262
  }
263
+ /**
264
+ * Given a trailer dimensions object from the commodities
265
+ * configuration and a permit type, return whether or not the
266
+ * trailer is permittable - this will depend on whether the trailer
267
+ * is size and/or weight permittable, and whether the permit
268
+ * type requires size and/or weight dimensions.
269
+ * @param permitType The permit type object
270
+ * @param trailer The trailer dimensions object for a specific commodity
271
+ * @returns true if the trailer is permittable, false otherwise
272
+ */
273
+ isTrailerPermittable(permitType, trailer) {
274
+ if (permitType.sizeDimensionRequired &&
275
+ permitType.weightDimensionRequired) {
276
+ return trailer.sizePermittable && trailer.weightPermittable;
277
+ }
278
+ else {
279
+ return ((trailer.sizePermittable && permitType.sizeDimensionRequired) ||
280
+ (trailer.weightPermittable && permitType.weightDimensionRequired));
281
+ }
282
+ }
292
283
  /**
293
284
  * Gets a list of all allowable power unit types for the given permit type
294
285
  * and commodity.
@@ -315,7 +306,7 @@ class Policy {
315
306
  * trailers in a single return value (if applicable).
316
307
  */
317
308
  getNextPermittableVehicles(permitTypeId, commodityId, currentConfiguration) {
318
- var _a, _b, _c, _d, _e;
309
+ var _a;
319
310
  if (!permitTypeId || !commodityId || !currentConfiguration) {
320
311
  throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
321
312
  }
@@ -342,10 +333,10 @@ class Policy {
342
333
  if (currentConfiguration.length == 0) {
343
334
  // The current configuration is empty, so return only the
344
335
  // allowable power units.
345
- vehicleTypeIds = (_b = (_a = commodity.size) === null || _a === void 0 ? void 0 : _a.powerUnits) === null || _b === void 0 ? void 0 : _b.map((p) => p.type);
336
+ vehicleTypeIds = Array.from(this.getPermittablePowerUnitTypes(permitTypeId, commodityId).keys());
346
337
  }
347
338
  else {
348
- 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]);
339
+ const powerUnit = commodity.powerUnits.find((p) => p.type == currentConfiguration[0]);
349
340
  let validTrailers;
350
341
  // ORV2-3953
351
342
  // If a jeep has been added, only add trailers that
@@ -356,9 +347,16 @@ class Policy {
356
347
  else {
357
348
  validTrailers = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers;
358
349
  }
350
+ // Filter trailer list down to those permittable for the permit
351
+ // type (size and/or weight dimensions required)
352
+ validTrailers = validTrailers === null || validTrailers === void 0 ? void 0 : validTrailers.filter((t) => this.isTrailerPermittable(permitType, t));
359
353
  const trailerIds = validTrailers === null || validTrailers === void 0 ? void 0 : validTrailers.map((t) => t.type);
360
- if (currentConfiguration.length == 1) {
361
- // Just a power unit, return the list of trailerIds for the
354
+ const lastVehicleId = currentConfiguration[currentConfiguration.length - 1];
355
+ const powerUnitType = this.getPowerUnitDefinition(powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.type);
356
+ if (currentConfiguration.length == 1 ||
357
+ lastVehicleId === (powerUnitType === null || powerUnitType === void 0 ? void 0 : powerUnitType.additionalAxleSubType)) {
358
+ // Just a power unit, optionally with one or more additional
359
+ // axles. Return the list of trailerIds for the
362
360
  // power unit, plus jeep if any of the trailer Ids allow
363
361
  // a jeep.
364
362
  if ((powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers) &&
@@ -368,7 +366,6 @@ class Policy {
368
366
  vehicleTypeIds = trailerIds;
369
367
  }
370
368
  else {
371
- const lastVehicleId = currentConfiguration[currentConfiguration.length - 1];
372
369
  switch (lastVehicleId) {
373
370
  case enum_1.AccessoryVehicleType.Jeep:
374
371
  // If there is one jeep, there can be more
@@ -381,11 +378,31 @@ class Policy {
381
378
  break;
382
379
  default:
383
380
  {
384
- const trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == lastVehicleId);
381
+ // The last vehicle is either a trailer, or an
382
+ // additional axle on the trailer. We need to
383
+ // identify the actual trailer type to determine
384
+ // if a booster is allowed.
385
+ let trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == lastVehicleId);
386
+ if (!trailer) {
387
+ // The last vehicle is not a trailer or a booster,
388
+ // so must be an additional axle of the trailer since
389
+ // we know this is a valid configuration at this point.
390
+ // Work our way backwards through the configuration
391
+ // to find the trailer.
392
+ let i = currentConfiguration.length - 1;
393
+ while (!trailer && i > 0) {
394
+ const prevVehicleId = currentConfiguration[--i];
395
+ trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == prevVehicleId);
396
+ }
397
+ }
385
398
  if (trailer && trailer.booster) {
386
399
  vehicleTypeIds = [enum_1.AccessoryVehicleType.Booster];
387
400
  }
388
401
  else {
402
+ // Either the trailer does not permit a booster, or
403
+ // we did not find the trailer which would be
404
+ // unexpected. Either way, no more vehicles are
405
+ // permittable.
389
406
  vehicleTypeIds = new Array();
390
407
  }
391
408
  }
@@ -394,7 +411,7 @@ class Policy {
394
411
  }
395
412
  }
396
413
  // Remove long combination vehicles if required
397
- if (!((_e = this.specialAuthorizations) === null || _e === void 0 ? void 0 : _e.isLcvAllowed)) {
414
+ if (!((_a = this.specialAuthorizations) === null || _a === void 0 ? void 0 : _a.isLcvAllowed)) {
398
415
  if (vehicleTypeIds) {
399
416
  vehicleTypeIds = this.filterOutLongCombinationVehicles(vehicleTypeIds);
400
417
  }
@@ -417,7 +434,6 @@ class Policy {
417
434
  * allowable for the permit type.
418
435
  */
419
436
  isConfigurationValid(permitTypeId, commodityId, currentConfiguration, validatePartial = false) {
420
- var _a, _b;
421
437
  if (!permitTypeId || !commodityId || !currentConfiguration) {
422
438
  throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
423
439
  }
@@ -449,15 +465,18 @@ class Policy {
449
465
  return false;
450
466
  }
451
467
  }
452
- 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]);
453
- if (!powerUnit) {
454
- // The power unit is not allowed for the commodity
468
+ const permittablePowerUnits = this.getPermittablePowerUnitTypes(permitTypeId, commodityId);
469
+ if (!permittablePowerUnits.has(currentConfiguration[0])) {
470
+ // The power unit is not permitted
455
471
  return false;
456
472
  }
457
- let trailerIds = powerUnit.trailers.map((t) => t.type);
473
+ const powerUnit = commodity.powerUnits.find((p) => p.type === currentConfiguration[0]);
474
+ let trailerIds = (powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.filter((t) => this.isTrailerPermittable(permitType, t)).map((t) => t.type)) || [];
458
475
  let jeepAllowed = true;
459
476
  let trailerAllowed = true;
460
477
  let boosterAllowed = false;
478
+ const powerUnitType = this.getPowerUnitDefinition(powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.type);
479
+ let additionalAxleType = (powerUnitType === null || powerUnitType === void 0 ? void 0 : powerUnitType.additionalAxleSubType) || '';
461
480
  for (let i = 1; i < currentConfiguration.length; i++) {
462
481
  switch (currentConfiguration[i]) {
463
482
  case enum_1.AccessoryVehicleType.Jeep:
@@ -465,28 +484,47 @@ class Policy {
465
484
  return false;
466
485
  }
467
486
  // Filter allowed trailers to only those that allow jeeps
468
- trailerIds = powerUnit.trailers
469
- .filter((t) => t.jeep)
470
- .map((t) => t.type);
487
+ trailerIds =
488
+ (powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.filter((t) => this.isTrailerPermittable(permitType, t)).filter((t) => t.jeep).map((t) => t.type)) || [];
489
+ if (trailerIds.length === 0) {
490
+ // The configuration has a jeep, but no trailers allow jeeps
491
+ // for this power unit and commodity. Return false.
492
+ return false;
493
+ }
494
+ additionalAxleType = '';
471
495
  break;
472
496
  case enum_1.AccessoryVehicleType.Booster:
473
497
  if (!boosterAllowed) {
474
498
  return false;
475
499
  }
500
+ additionalAxleType = '';
476
501
  break;
477
502
  default:
503
+ // This is a trailer (not a booster or jeep).
504
+ // Check to see if it is an additional axle pseudo trailer
505
+ // which is valid for the previous vehicle and let it
506
+ // pass if so.
507
+ if (currentConfiguration[i] === additionalAxleType) {
508
+ break;
509
+ }
478
510
  if (!trailerAllowed) {
479
511
  return false;
480
512
  }
513
+ if (!trailerIds.includes(currentConfiguration[i])) {
514
+ // Trailer not in our list of permittable trailers
515
+ return false;
516
+ }
517
+ jeepAllowed = false;
518
+ trailerAllowed = false;
481
519
  {
482
- const trailer = powerUnit.trailers.find((t) => t.type == currentConfiguration[i]);
483
- if (!trailer || !trailerIds.includes(currentConfiguration[i])) {
484
- // This trailer is not permitted for this power unit
485
- return false;
486
- }
487
- jeepAllowed = false;
488
- trailerAllowed = false;
489
- boosterAllowed = trailer.booster;
520
+ const trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type === currentConfiguration[i]);
521
+ // This is a trailer, set the additional axle type so it can be
522
+ // checked on the next vehicle in the configuration
523
+ const trailerType = this.getTrailerDefinition(trailer === null || trailer === void 0 ? void 0 : trailer.type);
524
+ additionalAxleType = (trailerType === null || trailerType === void 0 ? void 0 : trailerType.additionalAxleSubType) || '';
525
+ // Set the boosterAllowed flag based on whether the trailer allows
526
+ // a booster for the commodity in the configuration
527
+ boosterAllowed = (trailer === null || trailer === void 0 ? void 0 : trailer.booster) || false;
490
528
  }
491
529
  break;
492
530
  }
@@ -1,11 +1,4 @@
1
- import { IdentifiedObject, VehicleSizeConfiguration, VehicleWeightConfiguration } from 'onroute-policy-engine/types';
1
+ import { IdentifiedObject, VehicleDimensions } from 'onroute-policy-engine/types';
2
2
  export type Commodity = IdentifiedObject & {
3
- size?: CommoditySize;
4
- weight?: CommodityWeight;
5
- };
6
- export type CommoditySize = {
7
- powerUnits?: Array<VehicleSizeConfiguration>;
8
- };
9
- export type CommodityWeight = {
10
- powerUnits?: Array<VehicleWeightConfiguration>;
3
+ powerUnits: Array<VehicleDimensions>;
11
4
  };
@@ -9,7 +9,7 @@ export type DimensionModifier = SelfIssuable & {
9
9
  };
10
10
  export type VehicleRelatives = {
11
11
  firstType: string;
12
- lastType: string;
12
+ lastType?: string;
13
13
  nextType?: string | null;
14
14
  prevType?: string | null;
15
15
  firstCategory?: string | null;
@@ -1,7 +1,7 @@
1
1
  export { AxleConfiguration } from './axle-configuration';
2
2
  export { BridgeCalculationConstants } from './bridge-calculation-constants';
3
3
  export { BridgeCalculationResult } from './bridge-calculation-result';
4
- export { Commodity, CommoditySize, CommodityWeight } from './commodity';
4
+ export { Commodity } from './commodity';
5
5
  export { CostRule } from './cost-rule';
6
6
  export { DimensionModifier, VehicleRelatives } from './dimension-modifier';
7
7
  export { PermitFacts } from './facts';
@@ -19,5 +19,5 @@ export { SpecialAuthorizations } from './special-authorizations';
19
19
  export { StandardTireSize } from './standard-tire-size';
20
20
  export { VehicleCategory, PowerUnitCategory, TrailerCategory, VehicleCategories, } from './vehicle-category';
21
21
  export { VehicleType, PowerUnitType, TrailerType, VehicleTypes, } from './vehicle-type';
22
- export { Vehicle, VehicleSizeConfiguration, VehicleWeightConfiguration, TrailerSize, TrailerWeight, } from './vehicle';
22
+ export { TrailerDimensions, Vehicle, VehicleDimensions } from './vehicle';
23
23
  export { WeightDimension, PowerUnitWeightDimension, TrailerWeightDimension, DefaultWeightDimensions, SingleAxleDimension, } from './weight-dimension';
@@ -1,6 +1,5 @@
1
1
  import { RuleProperties } from 'json-rules-engine';
2
- import { CostRule, IdentifiedObject } from 'onroute-policy-engine/types';
3
- import { ConditionRequirement } from './permit-condition';
2
+ import { CostRule, IdentifiedObject, ConditionRequirement } from 'onroute-policy-engine/types';
4
3
  export type PermitType = IdentifiedObject & {
5
4
  routingRequired: boolean;
6
5
  weightDimensionRequired: boolean;
@@ -1,11 +1,11 @@
1
- import { IdentifiedObject, SizeDimension, PowerUnitWeightDimension, TrailerWeightDimension } from 'onroute-policy-engine/types';
2
- import { ConditionRequirement } from './permit-condition';
1
+ import { ConditionRequirement, IdentifiedObject, SizeDimension, PowerUnitWeightDimension, TrailerWeightDimension } from 'onroute-policy-engine/types';
3
2
  export type VehicleType = IdentifiedObject & {
4
3
  category: string;
5
4
  defaultSizeDimensions?: SizeDimension;
6
5
  ignoreForSizeDimensions?: boolean;
7
6
  isLcv?: boolean;
8
7
  conditions?: Array<ConditionRequirement>;
8
+ additionalAxleSubType?: string;
9
9
  };
10
10
  export type PowerUnitType = VehicleType & {
11
11
  defaultWeightDimensions?: Array<PowerUnitWeightDimension>;
@@ -2,22 +2,15 @@ import { SelfIssuable, SizeDimension, PowerUnitWeightDimension, TrailerWeightDim
2
2
  export type Vehicle = SelfIssuable & {
3
3
  type: string;
4
4
  };
5
- export type VehicleSizeConfiguration = Vehicle & {
6
- trailers: Array<TrailerSize>;
7
- };
8
- export type VehicleWeightConfiguration = Vehicle & {
5
+ export type VehicleDimensions = Vehicle & {
6
+ trailers: Array<TrailerDimensions>;
9
7
  weightDimensions?: Array<PowerUnitWeightDimension>;
10
- additionalAxleSubType?: string;
11
- trailers: Array<TrailerWeight>;
12
8
  };
13
- export type TrailerSize = Vehicle & {
14
- sizeDimensions?: Array<SizeDimension>;
15
- jeep: boolean;
9
+ export type TrailerDimensions = Vehicle & {
16
10
  booster: boolean;
17
- };
18
- export type TrailerWeight = Vehicle & {
19
- weightDimensions?: Array<TrailerWeightDimension>;
20
- additionalAxleSubType?: string;
21
11
  jeep: boolean;
22
- booster: boolean;
12
+ sizeDimensions?: Array<SizeDimension>;
13
+ sizePermittable?: boolean;
14
+ weightDimensions?: Array<TrailerWeightDimension>;
15
+ weightPermittable?: boolean;
23
16
  };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "v1.8.4";
1
+ export declare const version = "v2.0.0";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // Generated by genversion.
5
- exports.version = 'v1.8.4';
5
+ exports.version = 'v2.0.0';
package/package.json CHANGED
@@ -58,6 +58,7 @@
58
58
  "semver": "^7.6.3"
59
59
  },
60
60
  "jest": {
61
+ "verbose": true,
61
62
  "moduleFileExtensions": [
62
63
  "js",
63
64
  "json",
@@ -89,5 +90,5 @@
89
90
  ],
90
91
  "testEnvironment": "node"
91
92
  },
92
- "version": "v1.8.4"
93
+ "version": "v2.0.0"
93
94
  }