onroute-policy-engine 1.8.4 → 2.0.1

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.
@@ -26,18 +26,19 @@ class Policy {
26
26
  * @param definition Policy definition to validate permits against
27
27
  */
28
28
  constructor(definition, authorizations) {
29
+ const cleanVersion = (0, valid_1.default)(version_1.version);
29
30
  // Check compatibility of the policy engine with the policy config
30
- if (!(0, valid_1.default)(version_1.version)) {
31
+ if (!cleanVersion) {
31
32
  throw new Error(`Cannot determine the version of the policy engine for compatibility: invalid semver: ${version_1.version}`);
32
33
  }
33
34
  else if (!(0, valid_1.default)(definition.minPEVersion)) {
34
35
  throw new Error(`Cannot determine the minimum PE version for the configuration: invalid semver: ${definition.minPEVersion}`);
35
36
  }
36
- else if ((0, lt_1.default)(version_1.version, definition.minPEVersion)) {
37
- throw new Error(`Current policy engine version is less than minimum version required for policy config: ${version_1.version} > ${definition.minPEVersion}`);
37
+ else if ((0, lt_1.default)(cleanVersion, definition.minPEVersion)) {
38
+ throw new Error(`Current policy engine version is less than minimum version required for policy config: ${cleanVersion} > ${definition.minPEVersion}`);
38
39
  }
39
- else if ((0, major_1.default)(version_1.version) > (0, major_1.default)(definition.minPEVersion)) {
40
- throw new Error(`Current policy config minimum version is at least one major version behind policy engine: major(${definition.minPEVersion}) < major(${version_1.version}))`);
40
+ else if ((0, major_1.default)(cleanVersion) > (0, major_1.default)(definition.minPEVersion)) {
41
+ throw new Error(`Current policy config minimum version is at least one major version behind policy engine: major(${definition.minPEVersion}) < major(${cleanVersion}))`);
41
42
  }
42
43
  this.policyDefinition = definition;
43
44
  this.setSpecialAuthorizations(authorizations);
@@ -150,29 +151,15 @@ class Policy {
150
151
  return new Map();
151
152
  }
152
153
  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
154
  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;
155
+ // Return true if any of the power units has any size
156
+ // permittable trailers
157
+ return c.powerUnits.some((p) => p.trailers.some((t) => t.sizePermittable));
164
158
  }));
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
159
  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;
160
+ // Return true if any of the power units has any size
161
+ // permittable trailers
162
+ return c.powerUnits.some((p) => p.trailers.some((t) => t.weightPermittable));
176
163
  }));
177
164
  if (permitType.sizeDimensionRequired &&
178
165
  permitType.weightDimensionRequired) {
@@ -203,7 +190,7 @@ class Policy {
203
190
  * vehicle, and a string common name for the vehicle.
204
191
  */
205
192
  getPermittableVehicleTypes(permitTypeId, commodityId) {
206
- var _a, _b, _c, _d, _e;
193
+ var _a;
207
194
  if (!permitTypeId) {
208
195
  throw new Error('Missing permitTypeId');
209
196
  }
@@ -233,62 +220,67 @@ class Policy {
233
220
  if (!commodity) {
234
221
  throw new Error(`Commodity id '${commodityId}' is not correctly configured in the policy definition`);
235
222
  }
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);
223
+ // Extract the permittable power unit and trailer IDs. If the permit
224
+ // type requires both size and weight dimension, only extract the
225
+ // power units that have at least one trailer that is both size and
226
+ // weight permittable.
227
+ const permittablePowerUnits = commodity.powerUnits.filter((p) => {
228
+ return p.trailers.some((t) => {
229
+ return this.isTrailerPermittable(permitType, t);
230
+ });
231
+ });
232
+ let puTypeIds = permittablePowerUnits.map((p) => p.type);
233
+ let trTypeIds = [];
234
+ permittablePowerUnits.forEach((pu) => {
235
+ trTypeIds = trTypeIds.concat(pu.trailers
236
+ .filter((t) => {
237
+ return this.isTrailerPermittable(permitType, t);
238
+ })
239
+ .map((t) => t.type));
242
240
  });
243
- // TODO: implement along with overweight permits. Stub for now.
244
- let puTypeIdsOW = [];
245
- let trTypeIdsOW = [];
241
+ // Remove duplicate trailer IDs
242
+ trTypeIds = [...new Set(trTypeIds)];
246
243
  // 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);
244
+ if (!((_a = this.specialAuthorizations) === null || _a === void 0 ? void 0 : _a.isLcvAllowed)) {
245
+ puTypeIds = this.filterOutLongCombinationVehicles(puTypeIds);
246
+ trTypeIds = this.filterOutLongCombinationVehicles(trTypeIds);
269
247
  }
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 {
248
+ if (!(permitType.sizeDimensionRequired || permitType.weightDimensionRequired)) {
279
249
  // This permit type requires commodity selection, but does not
280
250
  // require size or weight dimensions. For these permit types, the
281
251
  // allowedVehicles must be configured in policy. Return all power
282
252
  // 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);
253
+ puTypeIds = permitType.allowedVehicles || [];
254
+ trTypeIds = permitType.allowedVehicles || [];
285
255
  }
256
+ puTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes, puTypeIds);
257
+ trTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes, trTypeIds);
286
258
  }
287
259
  const vehicleTypes = new Map();
288
260
  vehicleTypes.set(enum_1.VehicleTypes.PowerUnits, puTypes);
289
261
  vehicleTypes.set(enum_1.VehicleTypes.Trailers, trTypes);
290
262
  return vehicleTypes;
291
263
  }
264
+ /**
265
+ * Given a trailer dimensions object from the commodities
266
+ * configuration and a permit type, return whether or not the
267
+ * trailer is permittable - this will depend on whether the trailer
268
+ * is size and/or weight permittable, and whether the permit
269
+ * type requires size and/or weight dimensions.
270
+ * @param permitType The permit type object
271
+ * @param trailer The trailer dimensions object for a specific commodity
272
+ * @returns true if the trailer is permittable, false otherwise
273
+ */
274
+ isTrailerPermittable(permitType, trailer) {
275
+ if (permitType.sizeDimensionRequired &&
276
+ permitType.weightDimensionRequired) {
277
+ return trailer.sizePermittable && trailer.weightPermittable;
278
+ }
279
+ else {
280
+ return ((trailer.sizePermittable && permitType.sizeDimensionRequired) ||
281
+ (trailer.weightPermittable && permitType.weightDimensionRequired));
282
+ }
283
+ }
292
284
  /**
293
285
  * Gets a list of all allowable power unit types for the given permit type
294
286
  * and commodity.
@@ -315,7 +307,7 @@ class Policy {
315
307
  * trailers in a single return value (if applicable).
316
308
  */
317
309
  getNextPermittableVehicles(permitTypeId, commodityId, currentConfiguration) {
318
- var _a, _b, _c, _d, _e;
310
+ var _a;
319
311
  if (!permitTypeId || !commodityId || !currentConfiguration) {
320
312
  throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
321
313
  }
@@ -342,10 +334,10 @@ class Policy {
342
334
  if (currentConfiguration.length == 0) {
343
335
  // The current configuration is empty, so return only the
344
336
  // 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);
337
+ vehicleTypeIds = Array.from(this.getPermittablePowerUnitTypes(permitTypeId, commodityId).keys());
346
338
  }
347
339
  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]);
340
+ const powerUnit = commodity.powerUnits.find((p) => p.type == currentConfiguration[0]);
349
341
  let validTrailers;
350
342
  // ORV2-3953
351
343
  // If a jeep has been added, only add trailers that
@@ -356,9 +348,16 @@ class Policy {
356
348
  else {
357
349
  validTrailers = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers;
358
350
  }
351
+ // Filter trailer list down to those permittable for the permit
352
+ // type (size and/or weight dimensions required)
353
+ validTrailers = validTrailers === null || validTrailers === void 0 ? void 0 : validTrailers.filter((t) => this.isTrailerPermittable(permitType, t));
359
354
  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
355
+ const lastVehicleId = currentConfiguration[currentConfiguration.length - 1];
356
+ const powerUnitType = this.getPowerUnitDefinition(powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.type);
357
+ if (currentConfiguration.length == 1 ||
358
+ lastVehicleId === (powerUnitType === null || powerUnitType === void 0 ? void 0 : powerUnitType.additionalAxleSubType)) {
359
+ // Just a power unit, optionally with one or more additional
360
+ // axles. Return the list of trailerIds for the
362
361
  // power unit, plus jeep if any of the trailer Ids allow
363
362
  // a jeep.
364
363
  if ((powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers) &&
@@ -368,7 +367,6 @@ class Policy {
368
367
  vehicleTypeIds = trailerIds;
369
368
  }
370
369
  else {
371
- const lastVehicleId = currentConfiguration[currentConfiguration.length - 1];
372
370
  switch (lastVehicleId) {
373
371
  case enum_1.AccessoryVehicleType.Jeep:
374
372
  // If there is one jeep, there can be more
@@ -381,11 +379,31 @@ class Policy {
381
379
  break;
382
380
  default:
383
381
  {
384
- const trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == lastVehicleId);
382
+ // The last vehicle is either a trailer, or an
383
+ // additional axle on the trailer. We need to
384
+ // identify the actual trailer type to determine
385
+ // if a booster is allowed.
386
+ let trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == lastVehicleId);
387
+ if (!trailer) {
388
+ // The last vehicle is not a trailer or a booster,
389
+ // so must be an additional axle of the trailer since
390
+ // we know this is a valid configuration at this point.
391
+ // Work our way backwards through the configuration
392
+ // to find the trailer.
393
+ let i = currentConfiguration.length - 1;
394
+ while (!trailer && i > 0) {
395
+ const prevVehicleId = currentConfiguration[--i];
396
+ trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type == prevVehicleId);
397
+ }
398
+ }
385
399
  if (trailer && trailer.booster) {
386
400
  vehicleTypeIds = [enum_1.AccessoryVehicleType.Booster];
387
401
  }
388
402
  else {
403
+ // Either the trailer does not permit a booster, or
404
+ // we did not find the trailer which would be
405
+ // unexpected. Either way, no more vehicles are
406
+ // permittable.
389
407
  vehicleTypeIds = new Array();
390
408
  }
391
409
  }
@@ -394,7 +412,7 @@ class Policy {
394
412
  }
395
413
  }
396
414
  // Remove long combination vehicles if required
397
- if (!((_e = this.specialAuthorizations) === null || _e === void 0 ? void 0 : _e.isLcvAllowed)) {
415
+ if (!((_a = this.specialAuthorizations) === null || _a === void 0 ? void 0 : _a.isLcvAllowed)) {
398
416
  if (vehicleTypeIds) {
399
417
  vehicleTypeIds = this.filterOutLongCombinationVehicles(vehicleTypeIds);
400
418
  }
@@ -417,7 +435,6 @@ class Policy {
417
435
  * allowable for the permit type.
418
436
  */
419
437
  isConfigurationValid(permitTypeId, commodityId, currentConfiguration, validatePartial = false) {
420
- var _a, _b;
421
438
  if (!permitTypeId || !commodityId || !currentConfiguration) {
422
439
  throw new Error('Missing permitTypeId and/or commodityId and/or currentConfiguration');
423
440
  }
@@ -449,15 +466,18 @@ class Policy {
449
466
  return false;
450
467
  }
451
468
  }
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
469
+ const permittablePowerUnits = this.getPermittablePowerUnitTypes(permitTypeId, commodityId);
470
+ if (!permittablePowerUnits.has(currentConfiguration[0])) {
471
+ // The power unit is not permitted
455
472
  return false;
456
473
  }
457
- let trailerIds = powerUnit.trailers.map((t) => t.type);
474
+ const powerUnit = commodity.powerUnits.find((p) => p.type === currentConfiguration[0]);
475
+ let trailerIds = (powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.filter((t) => this.isTrailerPermittable(permitType, t)).map((t) => t.type)) || [];
458
476
  let jeepAllowed = true;
459
477
  let trailerAllowed = true;
460
478
  let boosterAllowed = false;
479
+ const powerUnitType = this.getPowerUnitDefinition(powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.type);
480
+ let additionalAxleType = (powerUnitType === null || powerUnitType === void 0 ? void 0 : powerUnitType.additionalAxleSubType) || '';
461
481
  for (let i = 1; i < currentConfiguration.length; i++) {
462
482
  switch (currentConfiguration[i]) {
463
483
  case enum_1.AccessoryVehicleType.Jeep:
@@ -465,28 +485,47 @@ class Policy {
465
485
  return false;
466
486
  }
467
487
  // Filter allowed trailers to only those that allow jeeps
468
- trailerIds = powerUnit.trailers
469
- .filter((t) => t.jeep)
470
- .map((t) => t.type);
488
+ trailerIds =
489
+ (powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.filter((t) => this.isTrailerPermittable(permitType, t)).filter((t) => t.jeep).map((t) => t.type)) || [];
490
+ if (trailerIds.length === 0) {
491
+ // The configuration has a jeep, but no trailers allow jeeps
492
+ // for this power unit and commodity. Return false.
493
+ return false;
494
+ }
495
+ additionalAxleType = '';
471
496
  break;
472
497
  case enum_1.AccessoryVehicleType.Booster:
473
498
  if (!boosterAllowed) {
474
499
  return false;
475
500
  }
501
+ additionalAxleType = '';
476
502
  break;
477
503
  default:
504
+ // This is a trailer (not a booster or jeep).
505
+ // Check to see if it is an additional axle pseudo trailer
506
+ // which is valid for the previous vehicle and let it
507
+ // pass if so.
508
+ if (currentConfiguration[i] === additionalAxleType) {
509
+ break;
510
+ }
478
511
  if (!trailerAllowed) {
479
512
  return false;
480
513
  }
514
+ if (!trailerIds.includes(currentConfiguration[i])) {
515
+ // Trailer not in our list of permittable trailers
516
+ return false;
517
+ }
518
+ jeepAllowed = false;
519
+ trailerAllowed = false;
481
520
  {
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;
521
+ const trailer = powerUnit === null || powerUnit === void 0 ? void 0 : powerUnit.trailers.find((t) => t.type === currentConfiguration[i]);
522
+ // This is a trailer, set the additional axle type so it can be
523
+ // checked on the next vehicle in the configuration
524
+ const trailerType = this.getTrailerDefinition(trailer === null || trailer === void 0 ? void 0 : trailer.type);
525
+ additionalAxleType = (trailerType === null || trailerType === void 0 ? void 0 : trailerType.additionalAxleSubType) || '';
526
+ // Set the boosterAllowed flag based on whether the trailer allows
527
+ // a booster for the commodity in the configuration
528
+ boosterAllowed = (trailer === null || trailer === void 0 ? void 0 : trailer.booster) || false;
490
529
  }
491
530
  break;
492
531
  }
@@ -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.1";
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.1';
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.1"
93
94
  }