Add several EMS file formats.

This commit is contained in:
Patrick Fic
2025-03-19 13:26:00 -07:00
parent 5ddfe4d86f
commit 3277af73f6
17 changed files with 745 additions and 7 deletions

View File

@@ -8,7 +8,7 @@ import { DecodedAd1, OwnerRecordInterface } from "./decode-ad1.interface";
const DecodeAD1 = async (
extensionlessFilePath: string
): Promise<DecodedAd1> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}A.AD1`);
} catch (error) {

View File

@@ -8,7 +8,7 @@ import errorTypeCheck from "../../util/errorTypeCheck";
const DecodeAD2 = async (
extensionlessFilePath: string
): Promise<DecodedAD2> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}B.AD2`);
} catch (error) {

View File

@@ -8,7 +8,7 @@ import errorTypeCheck from "../../util/errorTypeCheck";
const DecodeLin = async (
extensionlessFilePath: string
): Promise<DecodedLin[]> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.LIN`);
} catch (error) {

View File

@@ -8,7 +8,7 @@ import { DecodedPfh } from "./decode-pfh.interface";
const DecodePfh = async (
extensionlessFilePath: string
): Promise<DecodedPfh> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.PFH`);
} catch (error) {

View File

@@ -12,7 +12,7 @@ import {
const DecodePfl = async (
extensionlessFilePath: string
): Promise<DecodedPfl> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.PFL`);
} catch (error) {

View File

@@ -0,0 +1,46 @@
export interface DecodedPfmLine {
matl_type?: string;
cal_code?: number;
cal_desc?: string;
cal_maxdlr?: number;
cal_prip?: number;
cal_secp?: number;
mat_calp?: number;
cal_prethr?: number;
cal_pstthr?: number;
cal_thramt?: number;
cal_lbrmin?: number;
cal_lbrrte?: number;
cal_opcode?: string;
tax_ind?: boolean;
mat_taxp?: number;
mat_adjp?: number;
mat_tx_ty1?: string;
mat_tx_in1?: boolean;
mat_tx_ty2?: string;
mat_tx_in2?: boolean;
mat_tx_ty3?: string;
mat_tx_in3?: boolean;
mat_tx_ty4?: string;
mat_tx_in4?: boolean;
mat_tx_ty5?: string;
mat_tx_in5?: boolean;
}
export interface JobMaterialRateFields {
rate_mapa: number;
tax_paint_mat_rt: number;
rate_mash: number;
tax_shop_mat_rt: number;
rate_mahw: number;
tax_levies_rt: number;
rate_ma2s: number;
rate_ma2t: number;
rate_ma3s: number;
rate_macs: number;
rate_mabl: number;
}
export interface DecodedPfm extends JobMaterialRateFields {
cieca_pfm: DecodedPfmLine[];
}

View File

@@ -0,0 +1,107 @@
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import {
DecodedPfm,
DecodedPfmLine,
JobMaterialRateFields,
} from "./decode-pfm.interface";
const DecodePfm = async (
extensionlessFilePath: string
): Promise<DecodedPfm> => {
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.PFM`);
} catch (error) {
//PFM File only has 1 location.
log.error("Error opening PFM File.", errorTypeCheck(error));
}
if (!dbf) {
log.error(`Could not find any PFM files at ${extensionlessFilePath}`);
throw new Error(`Could not find any PFM files at ${extensionlessFilePath}`);
}
const rawDBFRecord = await dbf.readRecords();
//AD2 will always have only 1 row.
//Commented lines have been cross referenced with existing partner fields.
const jobMaterialRates: JobMaterialRateFields = {
rate_mapa: 0,
tax_paint_mat_rt: 0,
rate_mash: 0,
tax_shop_mat_rt: 0,
rate_mahw: 0,
tax_levies_rt: 0,
rate_ma2s: 0,
rate_ma2t: 0,
rate_ma3s: 0,
rate_macs: 0,
rate_mabl: 0,
};
const rawPfmData: DecodedPfmLine[] = rawDBFRecord.map((record) => {
const singleLineData: DecodedPfmLine = deepLowerCaseKeys(
_.pick(record, [
//TODO: Add typings for EMS File Formats.
"MATL_TYPE",
"CAL_CODE",
"CAL_DESC",
"CAL_MAXDLR",
"CAL_PRIP",
"CAL_SECP",
"MAT_CALP",
"CAL_PRETHR", //Mitchell here
"CAL_PSTTHR",
"CAL_THRAMT",
"CAL_LBRMIN",
"CAL_LBRRTE", //Audatex puts it here
"CAL_OPCODE",
"TAX_IND",
"MAT_TAXP",
"MAT_ADJP",
"MAT_TX_TY1",
"MAT_TX_IN1",
"MAT_TX_TY2",
"MAT_TX_IN2",
"MAT_TX_TY3",
"MAT_TX_IN3",
"MAT_TX_TY4",
"MAT_TX_IN4",
"MAT_TX_TY5",
"MAT_TX_IN5",
])
);
//Also capture the whole object.
//This is segmented because the whole object was not previously captured for ImEX as it wasn't needed.
//Rome needs the whole object to accurately calculate the tax rates.
return singleLineData;
});
//Apply line by line adjustments.
const materialsLine: DecodedPfmLine | undefined = rawPfmData.find(
(line) => line.matl_type === "MAPA"
);
if (materialsLine) {
jobMaterialRates.rate_mapa =
materialsLine.cal_lbrrte || materialsLine.cal_prethr || 0;
}
//Apply business logic transfomrations.
//We don't have an inspection date, we instead have `date_estimated`
return { ...jobMaterialRates, cieca_pfm: rawPfmData };
};
export default DecodePfm;

View File

@@ -0,0 +1,28 @@
export interface DecodedPfo {
tx_tow_ty?: string;
tow_t_ty1?: string;
tow_t_in1?: boolean;
tow_t_ty2?: string;
tow_t_in2?: boolean;
tow_t_ty3?: string;
tow_t_in3?: boolean;
tow_t_ty4?: string;
tow_t_in4?: boolean;
tow_t_ty5?: string;
tow_t_in5?: boolean;
tow_t_ty6?: string;
tow_t_in6?: boolean;
tx_stor_ty?: string;
stor_t_ty1?: string;
stor_t_in1?: boolean;
stor_t_ty2?: string;
stor_t_in2?: boolean;
stor_t_ty3?: string;
stor_t_in3?: boolean;
stor_t_ty4?: string;
stor_t_in4?: boolean;
stor_t_ty5?: string;
stor_t_in5?: boolean;
stor_t_ty6?: string;
stor_t_in6?: boolean;
}

View File

@@ -0,0 +1,66 @@
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import { DecodedPfo } from "./decode-pfo.interface";
const DecodePfo = async (
extensionlessFilePath: string
): Promise<DecodedPfo> => {
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.PFO`);
} catch (error) {
log.error("Error opening PFO File.", errorTypeCheck(error));
dbf = await DBFFile.open(`${extensionlessFilePath}.PFO`);
log.log("Trying to find PFO file using regular CIECA Id.");
}
if (!dbf) {
log.error(`Could not find any PFO files at ${extensionlessFilePath}`);
throw new Error(`Could not find any PFO files at ${extensionlessFilePath}`);
}
const rawDBFRecord = await dbf.readRecords(1);
//PFO will always have only 1 row.
//Commented lines have been cross referenced with existing partner fields.
const rawPfoData: DecodedPfo = deepLowerCaseKeys(
_.pick(rawDBFRecord[0], [
//TODO: Add typings for EMS File Formats.
"TX_TOW_TY",
"TOW_T_TY1",
"TOW_T_IN1",
"TOW_T_TY2",
"TOW_T_IN2",
"TOW_T_TY3",
"TOW_T_IN3",
"TOW_T_TY4",
"TOW_T_IN4",
"TOW_T_TY5",
"TOW_T_IN5",
"TOW_T_TY6",
"TOW_T_IN6",
"TX_STOR_TY",
"STOR_T_TY1",
"STOR_T_IN1",
"STOR_T_TY2",
"STOR_T_IN2",
"STOR_T_TY3",
"STOR_T_IN3",
"STOR_T_TY4",
"STOR_T_IN4",
"STOR_T_TY5",
"STOR_T_IN5",
"STOR_T_TY6",
"STOR_T_IN6",
])
);
//Apply business logic transfomrations.
return rawPfoData;
};
export default DecodePfo;

View File

@@ -0,0 +1,143 @@
/**
* Interface representing decoded data from a PFT file
* Contains tax type information with up to 6 tax types and 5 tiers each
*/
export interface DecodedPft {
// Tax Type 1
tax_type1?: string;
ty1_tier1?: number;
ty1_thres1?: number;
ty1_rate1?: number;
ty1_sur1?: number;
ty1_tier2?: number;
ty1_thres2?: number;
ty1_rate2?: number;
ty1_sur2?: number;
ty1_tier3?: number;
ty1_thres3?: number;
ty1_rate3?: number;
ty1_sur3?: number;
ty1_tier4?: number;
ty1_thres4?: number;
ty1_rate4?: number;
ty1_sur4?: number;
ty1_tier5?: number;
ty1_thres5?: number;
ty1_rate5?: number;
ty1_sur5?: number;
// Tax Type 2
tax_type2?: string;
ty2_tier1?: number;
ty2_thres1?: number;
ty2_rate1?: number;
ty2_sur1?: number;
ty2_tier2?: number;
ty2_thres2?: number;
ty2_rate2?: number;
ty2_sur2?: number;
ty2_tier3?: number;
ty2_thres3?: number;
ty2_rate3?: number;
ty2_sur3?: number;
ty2_tier4?: number;
ty2_thres4?: number;
ty2_rate4?: number;
ty2_sur4?: number;
ty2_tier5?: number;
ty2_thres5?: number;
ty2_rate5?: number;
ty2_sur5?: number;
// Tax Type 3
tax_type3?: string;
ty3_tier1?: number;
ty3_thres1?: number;
ty3_rate1?: number;
ty3_sur1?: number;
ty3_tier2?: number;
ty3_thres2?: number;
ty3_rate2?: number;
ty3_sur2?: number;
ty3_tier3?: number;
ty3_thres3?: number;
ty3_rate3?: number;
ty3_sur3?: number;
ty3_tier4?: number;
ty3_thres4?: number;
ty3_rate4?: number;
ty3_sur4?: number;
ty3_tier5?: number;
ty3_thres5?: number;
ty3_rate5?: number;
ty3_sur5?: number;
// Tax Type 4
tax_type4?: string;
ty4_tier1?: number;
ty4_thres1?: number;
ty4_rate1?: number;
ty4_sur1?: number;
ty4_tier2?: number;
ty4_thres2?: number;
ty4_rate2?: number;
ty4_sur2?: number;
ty4_tier3?: number;
ty4_thres3?: number;
ty4_rate3?: number;
ty4_sur3?: number;
ty4_tier4?: number;
ty4_thres4?: number;
ty4_rate4?: number;
ty4_sur4?: number;
ty4_tier5?: number;
ty4_thres5?: number;
ty4_rate5?: number;
ty4_sur5?: number;
// Tax Type 5
tax_type5?: string;
ty5_tier1?: number;
ty5_thres1?: number;
ty5_rate1?: number;
ty5_sur1?: number;
ty5_tier2?: number;
ty5_thres2?: number;
ty5_rate2?: number;
ty5_sur2?: number;
ty5_tier3?: number;
ty5_thres3?: number;
ty5_rate3?: number;
ty5_sur3?: number;
ty5_tier4?: number;
ty5_thres4?: number;
ty5_rate4?: number;
ty5_sur4?: number;
ty5_tier5?: number;
ty5_thres5?: number;
ty5_rate5?: number;
ty5_sur5?: number;
// Tax Type 6
tax_type6?: string;
ty6_tier1?: number;
ty6_thres1?: number;
ty6_rate1?: number;
ty6_sur1?: number;
ty6_tier2?: number;
ty6_thres2?: number;
ty6_rate2?: number;
ty6_sur2?: number;
ty6_tier3?: number;
ty6_thres3?: number;
ty6_rate3?: number;
ty6_sur3?: number;
ty6_tier4?: number;
ty6_thres4?: number;
ty6_rate4?: number;
ty6_sur4?: number;
ty6_tier5?: number;
ty6_thres5?: number;
ty6_rate5?: number;
ty6_sur5?: number;
}

View File

@@ -0,0 +1,165 @@
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import { DecodedPft } from "./decode-pft.interface";
const DecodePft = async (
extensionlessFilePath: string
): Promise<DecodedPft> => {
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.PFT`);
} catch (error) {
log.error("Error opening PFH File.", errorTypeCheck(error));
}
if (!dbf) {
log.error(`Could not find any PFT files at ${extensionlessFilePath}`);
throw new Error(`Could not find any PFT files at ${extensionlessFilePath}`);
}
const rawDBFRecord = await dbf.readRecords(1);
//PFT will always have only 1 row.
//Commented lines have been cross referenced with existing partner fields.
const rawPftData: DecodedPft = deepLowerCaseKeys(
_.pick(rawDBFRecord[0], [
//TODO: Add typings for EMS File Formats.
"TAX_TYPE1", //The below is is taken from a CCC estimate. Will require validation to ensure it is also accurate for Audatex/Mitchell
"TY1_TIER1",
"TY1_THRES1",
"TY1_RATE1",
"TY1_SUR1",
"TY1_TIER2",
"TY1_THRES2",
"TY1_RATE2",
"TY1_SUR2",
"TY1_TIER3",
"TY1_THRES3",
"TY1_RATE3",
"TY1_SUR3",
"TY1_TIER4",
"TY1_THRES4",
"TY1_RATE4",
"TY1_SUR4",
"TY1_TIER5",
"TY1_THRES5",
"TY1_RATE5",
"TY1_SUR5",
"TAX_TYPE2",
"TY2_TIER1",
"TY2_THRES1",
"TY2_RATE1",
"TY2_SUR1",
"TY2_TIER2",
"TY2_THRES2",
"TY2_RATE2",
"TY2_SUR2",
"TY2_TIER3",
"TY2_THRES3",
"TY2_RATE3",
"TY2_SUR3",
"TY2_TIER4",
"TY2_THRES4",
"TY2_RATE4",
"TY2_SUR4",
"TY2_TIER5",
"TY2_THRES5",
"TY2_RATE5",
"TY2_SUR5",
"TAX_TYPE3",
"TY3_TIER1",
"TY3_THRES1",
"TY3_RATE1",
"TY3_SUR1",
"TY3_TIER2",
"TY3_THRES2",
"TY3_RATE2",
"TY3_SUR2",
"TY3_TIER3",
"TY3_THRES3",
"TY3_RATE3",
"TY3_SUR3",
"TY3_TIER4",
"TY3_THRES4",
"TY3_RATE4",
"TY3_SUR4",
"TY3_TIER5",
"TY3_THRES5",
"TY3_RATE5",
"TY3_SUR5",
"TAX_TYPE4",
"TY4_TIER1",
"TY4_THRES1",
"TY4_RATE1",
"TY4_SUR1",
"TY4_TIER2",
"TY4_THRES2",
"TY4_RATE2",
"TY4_SUR2",
"TY4_TIER3",
"TY4_THRES3",
"TY4_RATE3",
"TY4_SUR3",
"TY4_TIER4",
"TY4_THRES4",
"TY4_RATE4",
"TY4_SUR4",
"TY4_TIER5",
"TY4_THRES5",
"TY4_RATE5",
"TY4_SUR5",
"TAX_TYPE5",
"TY5_TIER1",
"TY5_THRES1",
"TY5_RATE1",
"TY5_SUR1",
"TY5_TIER2",
"TY5_THRES2",
"TY5_RATE2",
"TY5_SUR2",
"TY5_TIER3",
"TY5_THRES3",
"TY5_RATE3",
"TY5_SUR3",
"TY5_TIER4",
"TY5_THRES4",
"TY5_RATE4",
"TY5_SUR4",
"TY5_TIER5",
"TY5_THRES5",
"TY5_RATE5",
"TY5_SUR5",
"TAX_TYPE6",
"TY6_TIER1",
"TY6_THRES1",
"TY6_RATE1",
"TY6_SUR1",
"TY6_TIER2",
"TY6_THRES2",
"TY6_RATE2",
"TY6_SUR2",
"TY6_TIER3",
"TY6_THRES3",
"TY6_RATE3",
"TY6_SUR3",
"TY6_TIER4",
"TY6_THRES4",
"TY6_RATE4",
"TY6_SUR4",
"TY6_TIER5",
"TY6_THRES5",
"TY6_RATE5",
"TY6_SUR5",
])
);
//Apply business logic transfomrations.
//We don't have an inspection date, we instead have `date_estimated`
return rawPftData;
};
export default DecodePft;

View File

@@ -0,0 +1,20 @@
export interface DecodedStl {
ttl_type?: string;
ttl_typecd?: string;
t_amt?: number;
t_hrs?: number;
t_addlbr?: number;
t_discamt?: number;
t_mkupamt?: number;
t_gdiscamt?: number;
tax_amt?: number;
nt_amt?: number;
nt_hrs?: number;
nt_addlbr?: number;
nt_disc?: number;
nt_mkup?: number;
nt_gdis?: number;
ttl_typamt?: number;
ttl_hrs?: number;
ttl_amt?: number;
}

View File

@@ -0,0 +1,62 @@
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import { DecodedStl } from "./decode-stl.interface";
const DecodeStl = async (
extensionlessFilePath: string
): Promise<DecodedStl[]> => {
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.STL`);
} catch (error) {
log.error("Error opening STL File.", errorTypeCheck(error));
}
if (!dbf) {
log.error(`Could not find any STL files at ${extensionlessFilePath}`);
throw new Error(`Could not find any STL files at ${extensionlessFilePath}`);
}
const rawDBFRecord = await dbf.readRecords();
//AD2 will always have only 1 row.
//Commented lines have been cross referenced with existing partner fields.
const rawStlData: DecodedStl[] = rawDBFRecord.map((record) => {
const singleLineData: DecodedStl = deepLowerCaseKeys(
_.pick(record, [
//TODO: Add typings for EMS File Formats.
"TTL_TYPE",
"TTL_TYPECD",
"T_AMT",
"T_HRS",
"T_ADDLBR",
"T_DISCAMT",
"T_MKUPAMT",
"T_GDISCAMT",
"TAX_AMT",
"NT_AMT",
"NT_HRS",
"NT_ADDLBR",
"NT_DISC",
"NT_MKUP",
"NT_GDIS",
"TTL_TYPAMT",
"TTL_HRS",
"TTL_AMT",
])
);
//Apply line by line adjustments.
return singleLineData;
});
//Apply business logic transfomrations.
//We don't have an inspection date, we instead have `date_estimated`
return rawStlData;
};
export default DecodeStl;

View File

@@ -0,0 +1,22 @@
export interface DecodedTtl {
clm_total: number;
depreciation_taxes: number;
cieca_ttl: DecodedTtlLine;
}
export interface DecodedTtlLine {
g_ttl_amt?: number;
g_bett_amt?: number;
g_rpd_amt?: number;
g_ded_amt?: number;
g_cust_amt?: number;
g_aa_amt?: number;
n_ttl_amt?: number;
prev_net?: number;
supp_amt?: number;
n_supp_amt?: number;
g_upd_amt?: number;
g_ttl_disc?: number;
g_tax?: number;
gst_amt?: number;
}

View File

@@ -0,0 +1,52 @@
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import { DecodedTtl, DecodedTtlLine } from "./decode-ttl.interface";
const DecodeTtl = async (
extensionlessFilePath: string
): Promise<DecodedTtl> => {
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}.TTL`);
} catch (error) {
log.error("Error opening TTL File.", errorTypeCheck(error));
}
if (!dbf) {
log.error(`Could not find any TTL files at ${extensionlessFilePath}`);
throw new Error(`Could not find any TTL files at ${extensionlessFilePath}`);
}
const rawDBFRecord = await dbf.readRecords(1);
//PFT will always have only 1 row.
//Commented lines have been cross referenced with existing partner fields.
const rawTtlData: DecodedTtlLine = deepLowerCaseKeys(
_.pick(rawDBFRecord[0], [
//TODO: Add typings for EMS File Formats.
"G_TTL_AMT",
"G_BETT_AMT",
"G_RPD_AMT",
"G_DED_AMT",
"G_CUST_AMT",
"G_AA_AMT",
"N_TTL_AMT",
"PREV_NET",
"SUPP_AMT",
"N_SUPP_AMT", //Previously commented. Possible issue.
"G_UPD_AMT",
"G_TTL_DISC",
"G_TAX",
"GST_AMT",
])
);
//Apply business logic transfomrations.
return { clm_total: 0, depreciation_taxes: 0, cieca_ttl: rawTtlData };
};
export default DecodeTtl;

View File

@@ -8,7 +8,7 @@ import errorTypeCheck from "../../util/errorTypeCheck";
const DecodeVeh = async (
extensionlessFilePath: string
): Promise<DecodedVeh> => {
let dbf: DBFFile;
let dbf: DBFFile | null = null;
try {
dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`);
} catch (error) {

View File

@@ -11,6 +11,16 @@ import DecodePfh from "./decode-pfh";
import { DecodedPfh } from "./decode-pfh.interface";
import DecodePfl from "./decode-pfl";
import { DecodedPfl } from "./decode-pfl.interface";
import DecodePfm from "./decode-pfm";
import { DecodedPfm } from "./decode-pfm.interface";
import DecodePfo from "./decode-pfo";
import { DecodedPfo } from "./decode-pfo.interface";
import DecodePft from "./decode-pft";
import { DecodedPft } from "./decode-pft.interface";
import DecodeStl from "./decode-stl";
import { DecodedStl } from "./decode-stl.interface";
import DecodeTtl from "./decode-ttl";
import { DecodedTtl } from "./decode-ttl.interface";
import DecodeVeh from "./decode-veh";
import { DecodedVeh } from "./decode-veh.interface";
@@ -31,7 +41,24 @@ async function ImportJob(filepath: string): Promise<void> {
const lin: DecodedLin[] = await DecodeLin(extensionlessFilePath);
const pfh: DecodedPfh = await DecodePfh(extensionlessFilePath);
const pfl: DecodedPfl = await DecodePfl(extensionlessFilePath);
log.debug("EMS Object", { ad1, ad2, veh, lin, pfh, pfl });
const pft: DecodedPft = await DecodePft(extensionlessFilePath);
const pfm: DecodedPfm = await DecodePfm(extensionlessFilePath);
const pfo: DecodedPfo = await DecodePfo(extensionlessFilePath); // TODO: This will be the `cieca_pfo` object
const stl: DecodedStl[] = await DecodeStl(extensionlessFilePath); // TODO: This will be the `cieca_stl` object
const ttl: DecodedTtl = await DecodeTtl(extensionlessFilePath); //
log.debug("EMS Object", {
ad1,
ad2,
veh,
lin,
pfh,
pfl,
pft,
pfm,
pfo,
stl,
ttl,
});
} catch (error) {
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
}