Skip to content

Commit

Permalink
feat: Updates to CSV import and export for size dimension set into po…
Browse files Browse the repository at this point in the history
…licy engine (#1639)
  • Loading branch information
john-fletcher-aot authored Oct 17, 2024
1 parent c43068a commit ab0fb51
Show file tree
Hide file tree
Showing 9 changed files with 5,136 additions and 4,617 deletions.
14 changes: 12 additions & 2 deletions policy-engine/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions policy-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"license": "Apache-2.0",
"homepage": "https://github.com/bcgov/onroutebc#readme",
"devDependencies": {
"@iwsio/json-csv-core": "^1.1.7",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^7.5.0",
"csv": "^6.3.10",
Expand Down
214 changes: 214 additions & 0 deletions policy-engine/src/_examples/Single Trip Oversize Dimension Set.csv

Large diffs are not rendered by default.

211 changes: 0 additions & 211 deletions policy-engine/src/_examples/os-dimensions-simplified-nodefault.csv

This file was deleted.

212 changes: 0 additions & 212 deletions policy-engine/src/_examples/os-dimensions-simplified.csv

This file was deleted.

213 changes: 213 additions & 0 deletions policy-engine/src/_examples/os-dimensions.csv

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions policy-engine/src/_examples/output-os-as-csv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { completePolicyConfig } from '../_test/policy-config/complete-in-progress.sample';
import { Policy } from '../policy-engine';
import { TrailerSize } from '../types';
import { toCsv } from '@iwsio/json-csv-core';

// json-csv-core options object
const options = {
fields: [
{ name: 'noSelfIssue', label: 'No Self Issue', transform: (v: boolean) => v ? 'X' : '' },
{ name: 'commodity', label: 'Commodity' },
{ name: 'powerUnit', label: 'Power Unit' },
{ name: 'trailer', label: 'Trailer' },
{ name: 'jeep', label: 'Allow Jeep', transform: (v: boolean) => v ? 'X' : '' },
{ name: 'booster', label: 'Allow Booster', transform: (v: boolean) => v ? 'X' : '' },
{ name: 'lmn.width', label: 'LMN - Width' },
{ name: 'lmn.height', label: 'LMN - Height' },
{ name: 'lmn.length', label: 'LMN - Length' },
{ name: 'ktn.width', label: 'KTN - Width' },
{ name: 'ktn.height', label: 'KTN - Height' },
{ name: 'ktn.length', label: 'KTN - Length' },
{ name: 'pce.width', label: 'PCE - Width' },
{ name: 'pce.height', label: 'PCE - Height' },
{ name: 'pce.length', label: 'PCE - Length' },
{ name: 'bcd.width', label: 'BCD - Width' },
{ name: 'bcd.height', label: 'BCD - Height' },
{ name: 'bcd.length', label: 'BCD - Length' },
{ name: 'fp', label: 'ORBC FP' },
{ name: 'rp', label: 'ORBC RP' },
],
};

/**
* Converts the size dimensions stored in the complete policy json to csv
* format matching the format used by business SMEs to verify the size
* dimensions match official policy.
* @param pol Policy with the size dimension set to convert
* @returns CSV string matching input size dimension set format
*/
function sizeDimensionSestToCsv(
pol: Policy,
): string | null {
const sizeDimensionSet: Array<any> = [];

pol.policyDefinition.commodities.forEach((commodity) => {
const commodityName = commodity.name;
commodity.size?.powerUnits?.forEach((powerUnit) => {
const powerUnitName = pol.getPowerUnitTypes().get(powerUnit.type);
powerUnit.trailers.forEach((trailer) => {
const trailerName = pol.getTrailerTypes().get(trailer.type);

let bcDefaultDimensions;
if (trailer.sizeDimensions && trailer.sizeDimensions.length > 0) {
const dim = trailer.sizeDimensions[0];
bcDefaultDimensions = {
bcd: {
width: dim.w,
height: dim.h,
length: dim.l,
},
fp: dim.fp,
rp: dim.rp,
}
}

let dimensionSetEntry = {
noSelfIssue: !trailer.selfIssue,
commodity: commodityName,
powerUnit: powerUnitName,
trailer: trailerName,
jeep: trailer.jeep,
booster: trailer.booster,
lmn: getDimensionsForRegion(trailer, 'LMN'),
ktn: getDimensionsForRegion(trailer, 'KTN'),
pce: getDimensionsForRegion(trailer, 'PCE'),
...bcDefaultDimensions,
};

sizeDimensionSet.push(dimensionSetEntry);
});
});
});

const csvString = toCsv(sizeDimensionSet, options);
return csvString;
}

/**
* Extracts the dimensions for the trailer as it applies to the supplied
* region, supplying BC Default values if no region configuration is available.
* @param trailer Trailer size dimensions for the region
* @param dimRegion Region the size dimensions are for - must match a region
* id as stored in the policy configuration JSON
* @returns object with width, height, and length for policy specific to the
* region. Defaults to width, height, and length for bc default if no specific
* region values are configured for the trailer.
*/
function getDimensionsForRegion(trailer: TrailerSize, dimRegion: string): any {
if (trailer.sizeDimensions && trailer.sizeDimensions.length > 0) {
const dim = trailer.sizeDimensions[0];
if (dim.regions && dim.regions.length > 0) {
const region = dim.regions.find((r) => r.region == dimRegion);
if (region) {
return {
width: region.w ?? dim.w,
height: region.h ?? dim.h,
length: region.l ?? dim.l,
}
}
}

// Use BC Default if region not configured
return {
width: dim.w,
height: dim.h,
length: dim.l,
}
}

// No dimensions in the input, return nothing
return null;
}

const policy = new Policy(completePolicyConfig);
const csv = sizeDimensionSestToCsv(policy);

console.log(csv);
54 changes: 36 additions & 18 deletions policy-engine/src/_examples/update-os-from-csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,34 @@ type DimensionEntry = {
trailer: TrailerSize;
};

enum ColumnNumbers {
NoSelfIssue = 0,
Commodity = 1,
PowerUnit = 2,
Trailer = 3,
AllowJeep = 4,
AllowBooster = 5,
FirstWidth = 6,
DefaultWidth = 15,
FrontProjection = 18,
RearProjection = 19,
}

function csvRowToObject(
row: Array<string>,
pol: Policy,
): DimensionEntry | null {
const commodityId = getIdFromName(pol.policyDefinition.commodities, row[1]);
const commodityId = getIdFromName(
pol.policyDefinition.commodities,
row[ColumnNumbers.Commodity],
);
const puId = getIdFromName(
pol.policyDefinition.vehicleTypes.powerUnitTypes,
row[2].trim(),
row[ColumnNumbers.PowerUnit].trim(),
);
const trId = getIdFromName(
pol.policyDefinition.vehicleTypes.trailerTypes,
row[4].trim(),
row[ColumnNumbers.Trailer].trim(),
);
let entryObject: DimensionEntry | null = null;
if (commodityId && puId && trId) {
Expand All @@ -31,16 +47,16 @@ function csvRowToObject(
powerUnit: puId,
trailer: {
type: trId,
jeep: row[5] == 'X',
booster: row[6] == 'X',
selfIssue: row[0] != 'X',
jeep: row[ColumnNumbers.AllowJeep] == 'X' || row[ColumnNumbers.AllowJeep] == 'x',
booster: row[ColumnNumbers.AllowBooster] == 'X' || row[ColumnNumbers.AllowBooster] == 'x',
selfIssue: row[ColumnNumbers.NoSelfIssue] != 'X' && row[ColumnNumbers.NoSelfIssue] != 'x',
},
};

const sizeDimension: SizeDimension = {};

const fp = parseFloat(row[19]);
const rp = parseFloat(row[20]);
const fp = parseFloat(row[ColumnNumbers.FrontProjection]);
const rp = parseFloat(row[ColumnNumbers.RearProjection]);
if (!isNaN(fp)) {
sizeDimension.fp = fp;
}
Expand All @@ -49,19 +65,19 @@ function csvRowToObject(
}

// Populate the BC Default dimensions
const bcWidth = parseFloat(row[16]);
const bcHeight = parseFloat(row[17]);
const bcLength = parseFloat(row[18]);
const bcWidth = parseFloat(row[ColumnNumbers.DefaultWidth]);
const bcHeight = parseFloat(row[ColumnNumbers.DefaultWidth + 1]);
const bcLength = parseFloat(row[ColumnNumbers.DefaultWidth + 2]);
if (!isNaN(bcWidth)) sizeDimension.w = bcWidth;
if (!isNaN(bcHeight)) sizeDimension.h = bcHeight;
if (!isNaN(bcLength)) sizeDimension.l = bcLength;

const regionIds: Array<string> = ['LMN', 'KTN', 'PCE'];
// Populate the 3 region dimensions
for (let i = 0; i < regionIds.length; i++) {
const w = parseFloat(row[7 + i * 3]);
const h = parseFloat(row[8 + i * 3]);
const l = parseFloat(row[9 + i * 3]);
const w = parseFloat(row[ColumnNumbers.FirstWidth + i * 3]);
const h = parseFloat(row[ColumnNumbers.FirstWidth + 1 + i * 3]);
const l = parseFloat(row[ColumnNumbers.FirstWidth + 2 + i * 3]);
if (
(isNaN(w) || w == sizeDimension.w) &&
(isNaN(h) || h == sizeDimension.h) &&
Expand Down Expand Up @@ -90,7 +106,7 @@ function csvRowToObject(
return entryObject;
} else {
console.log(
`No entry in policy config for commodity '${row[1]}' and/or power unit '${row[2]}' and/or trailer '${row[4]}'`,
`No entry in policy config for commodity '${row[ColumnNumbers.Commodity]}' and/or power unit '${row[ColumnNumbers.PowerUnit]}' and/or trailer '${row[ColumnNumbers.Trailer]}'`,
);
return null;
}
Expand Down Expand Up @@ -142,12 +158,14 @@ function processCsvRow(row: any) {
}
}

fs.createReadStream('./os-dimensions-simplified-nodefault.csv')
.pipe(parse({ delimiter: ',', from_line: 1 }))
fs.createReadStream('./Single Trip Oversize Dimension Set.csv')
.pipe(parse({ delimiter: ',', from_line: 3 }))
.on('data', function (row) {
processCsvRow(row);
})
.on('end', function () {
console.log(JSON.stringify(policy.policyDefinition, null, ' '));
console.log(
JSON.stringify(policy.policyDefinition.commodities, null, ' '),
);
//console.log(JSON.stringify(policy.policyDefinition));
});
Loading

0 comments on commit ab0fb51

Please sign in to comment.