diff --git a/electron-builder.yml b/electron-builder.yml index 21eeb04..4d54d6d 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -18,10 +18,6 @@ nsis: shortcutName: ${productName} uninstallDisplayName: ${productName} createDesktopShortcut: always - azureSignOptions: - endpoint: https://eus.codesigning.azure.net - certificateProfileName: ImEXRPS - codeSigningAccountName: ImEX mac: entitlementsInherit: build/entitlements.mac.plist category: public.app-category.business diff --git a/src/main/decoder/decode-ad1.ts b/src/main/decoder/decode-ad1.ts index 955cdf0..5aa8f1e 100644 --- a/src/main/decoder/decode-ad1.ts +++ b/src/main/decoder/decode-ad1.ts @@ -2,8 +2,8 @@ import { DBFFile } from "dbffile"; import log from "electron-log/main"; import _ from "lodash"; import deepLowerCaseKeys from "../../util/deepLowercaseKeys"; -import { OwnerRecordInterface, DecodedAd1 } from "./decode-ad1.interface"; import errorTypeCheck from "../../util/errorTypeCheck"; +import { DecodedAd1, OwnerRecordInterface } from "./decode-ad1.interface"; const DecodeAD1 = async ( extensionlessFilePath: string @@ -14,7 +14,7 @@ const DecodeAD1 = async ( } catch (error) { log.error("Error opening AD1 File.", errorTypeCheck(error)); dbf = await DBFFile.open(`${extensionlessFilePath}.AD1`); - log.log("Found AD1 file using regular CIECA Id."); + log.log("Trying to find AD1 file using regular CIECA Id."); } if (!dbf) { diff --git a/src/main/decoder/decode-ad2.interface.ts b/src/main/decoder/decode-ad2.interface.ts index 5feacee..8f803ed 100644 --- a/src/main/decoder/decode-ad2.interface.ts +++ b/src/main/decoder/decode-ad2.interface.ts @@ -25,5 +25,5 @@ export interface DecodedAD2 { est_ct_fn?: string; est_ea?: string; date_estimated?: Date; // This is transformed from insp_date - //insp_date?: string; // This exists initially but gets deleted + insp_date?: Date; // This exists initially but gets deleted } diff --git a/src/main/decoder/decode-ad2.ts b/src/main/decoder/decode-ad2.ts index 64fecf4..5ebbe2e 100644 --- a/src/main/decoder/decode-ad2.ts +++ b/src/main/decoder/decode-ad2.ts @@ -14,7 +14,7 @@ const DecodeAD2 = async ( } catch (error) { log.error("Error opening AD2 File.", errorTypeCheck(error)); dbf = await DBFFile.open(`${extensionlessFilePath}.AD2`); - log.log("Found AD2 file using regular CIECA Id."); + log.log("Trying to find AD2 file using regular CIECA Id."); } if (!dbf) { @@ -27,7 +27,7 @@ const DecodeAD2 = async ( //AD2 will always have only 1 row. //Commented lines have been cross referenced with existing partner fields. - const rawAd2Data = deepLowerCaseKeys( + const rawAd2Data: DecodedAD2 = deepLowerCaseKeys( _.pick(rawDBFRecord[0], [ //TODO: Add typings for EMS File Formats. "CLMT_LN", diff --git a/src/main/decoder/decode-pfh.interface.ts b/src/main/decoder/decode-pfh.interface.ts new file mode 100644 index 0000000..043c08f --- /dev/null +++ b/src/main/decoder/decode-pfh.interface.ts @@ -0,0 +1,15 @@ +export interface DecodedPfh { + tax_prethr: number; + tax_thr_amt?: number; + tax_pstthr?: number; + tax_tow_rt: number; + tax_str_rt: number; + tax_sub_rt: number; + tax_lbr_rt: number; + federal_tax_rate: number; + adj_g_disc?: number; + adj_towdis?: number; + adj_strdis?: number; + tax_predis?: number; + tax_gst_rt?: number; +} diff --git a/src/main/decoder/decode-pfh.ts b/src/main/decoder/decode-pfh.ts new file mode 100644 index 0000000..303905b --- /dev/null +++ b/src/main/decoder/decode-pfh.ts @@ -0,0 +1,71 @@ +import { DBFFile } from "dbffile"; +import log from "electron-log/main"; +import _ from "lodash"; +import deepLowerCaseKeys from "../../util/deepLowercaseKeys"; +import errorTypeCheck from "../../util/errorTypeCheck"; +import { DecodedPfh } from "./decode-pfh.interface"; + +const DecodePfh = async ( + extensionlessFilePath: string +): Promise => { + let dbf: DBFFile; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}.PFH`); + } catch (error) { + log.error("Error opening PFH File.", errorTypeCheck(error)); + dbf = await DBFFile.open(`${extensionlessFilePath}.PFH`); + log.log("Trying to find PFH file using regular CIECA Id."); + } + + if (!dbf) { + log.error(`Could not find any PFH files at ${extensionlessFilePath}`); + throw new Error(`Could not find any PFH files at ${extensionlessFilePath}`); + } + + const rawDBFRecord = await dbf.readRecords(1); + + //AD2 will always have only 1 row. + //Commented lines have been cross referenced with existing partner fields. + + const rawPfhData: DecodedPfh = deepLowerCaseKeys( + _.pick(rawDBFRecord[0], [ + //TODO: Add typings for EMS File Formats. + //TODO: Several of these fields will fail. Should extend schema to capture them. + "ID_PRO_NAM", //Remove + "TAX_PRETHR", + "TAX_THRAMT", //Remove + "TAX_PSTTHR", + "TAX_TOW_IN", //Remove + "TAX_TOW_RT", + "TAX_STR_IN", //Remove + "TAX_STR_RT", + "TAX_SUB_IN", //Remove + "TAX_SUB_RT", + "TAX_BTR_IN", //Remove + "TAX_LBR_RT", + "TAX_GST_RT", + "TAX_GST_IN", //Remove + "ADJ_G_DISC", + "ADJ_TOWDIS", + "ADJ_STRDIS", + "ADJ_BTR_IN", //Remove + "TAX_PREDIS", + ]) + ); + + //Apply business logic transfomrations. + + //Standardize some of the numbers and divide by 100. + + rawPfhData.tax_prethr = rawPfhData.tax_prethr ?? 0 / 100; + rawPfhData.tax_pstthr = rawPfhData.tax_pstthr ?? 0 / 100; + rawPfhData.tax_tow_rt = rawPfhData.tax_tow_rt ?? 0 / 100; + rawPfhData.tax_str_rt = rawPfhData.tax_str_rt ?? 0 / 100; + rawPfhData.tax_sub_rt = rawPfhData.tax_sub_rt ?? 0 / 100; + rawPfhData.tax_lbr_rt = rawPfhData.tax_lbr_rt ?? 0 / 100; + rawPfhData.federal_tax_rate = rawPfhData.tax_gst_rt ?? 0 / 100; + delete rawPfhData.tax_gst_rt; + + return rawPfhData; +}; +export default DecodePfh; diff --git a/src/main/decoder/decode-pfl.interface.ts b/src/main/decoder/decode-pfl.interface.ts new file mode 100644 index 0000000..38dd5a6 --- /dev/null +++ b/src/main/decoder/decode-pfl.interface.ts @@ -0,0 +1,41 @@ +//TODO: Clean up this interface. A bit messy as we store the data in very different ways. + +export interface DecodedPflLine { + lbr_type: string; + lbr_desc: string; + lbr_rate: number; + lbr_tax_in: boolean; + lbr_taxp: number; + lbr_adjP: number; + lbr_tx_ty1: string; + lbr_tx_in1: boolean; + lbr_tx_ty2: string; + lbr_tx_in2: boolean; + lbr_tx_ty3: string; + lbr_tx_in3: boolean; + lbr_tx_ty4: string; + lbr_tx_in4: boolean; + lbr_tx_ty5: string; + lbr_tx_in5: boolean; +} + +export interface JobLaborRateFields { + rate_laa: number; + rate_lab: number; + rate_lad: number; + rate_las: number; + rate_lar: number; + rate_lae: number; + rate_lag: number; + rate_laf: number; + rate_lam: number; + rate_lau: number; + rate_la1: number; + rate_la2: number; + rate_la3: number; + rate_la4: number; +} + +export interface DecodedPfl extends JobLaborRateFields { + cieca_pfl: DecodedPflLine[]; +} diff --git a/src/main/decoder/decode-pfl.ts b/src/main/decoder/decode-pfl.ts new file mode 100644 index 0000000..f29ce41 --- /dev/null +++ b/src/main/decoder/decode-pfl.ts @@ -0,0 +1,89 @@ +import { DBFFile } from "dbffile"; +import log from "electron-log/main"; +import _ from "lodash"; +import deepLowerCaseKeys from "../../util/deepLowercaseKeys"; +import errorTypeCheck from "../../util/errorTypeCheck"; +import { + DecodedPfl, + JobLaborRateFields, + DecodedPflLine, +} from "./decode-pfl.interface"; + +const DecodePfl = async ( + extensionlessFilePath: string +): Promise => { + let dbf: DBFFile; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}.PFL`); + } catch (error) { + //PFL File only has 1 location. + log.error("Error opening PFL File.", errorTypeCheck(error)); + } + + if (!dbf) { + log.error(`Could not find any PFL files at ${extensionlessFilePath}`); + throw new Error(`Could not find any PFL 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 jobLaborRates: JobLaborRateFields = { + rate_laa: 0, + rate_lab: 0, + rate_lad: 0, + rate_las: 0, + rate_lar: 0, + rate_lae: 0, + rate_lag: 0, + rate_laf: 0, + rate_lam: 0, + rate_lau: 0, + rate_la1: 0, + rate_la2: 0, + rate_la3: 0, + rate_la4: 0, + }; + + const rawPflData: DecodedPflLine[] = rawDBFRecord.map((record) => { + const singleLineData: DecodedPflLine = deepLowerCaseKeys( + _.pick(record, [ + //TODO: Add typings for EMS File Formats. + "LBR_TYPE", + "LBR_DESC", + "LBR_RATE", + "LBR_TAX_IN", + "LBR_TAXP", + "LBR_ADJP", + "LBR_TX_TY1", + "LBR_TX_IN1", + "LBR_TX_TY2", + "LBR_TX_IN2", + "LBR_TX_TY3", + "LBR_TX_IN3", + "LBR_TX_TY4", + "LBR_TX_IN4", + "LBR_TX_TY5", + "LBR_TX_IN5", + ]) + ); + //Apply line by line adjustments. + //Set the job.rate_ field based on the value. + jobLaborRates[`rate_${singleLineData.lbr_type.toLowerCase()}`] = + singleLineData.lbr_rate; + //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 business logic transfomrations. + //We don't have an inspection date, we instead have `date_estimated` + + return { ...jobLaborRates, cieca_pfl: rawPflData }; +}; + +export default DecodePfl; diff --git a/src/main/decoder/decoder.ts b/src/main/decoder/decoder.ts index 613bc4a..fb02516 100644 --- a/src/main/decoder/decoder.ts +++ b/src/main/decoder/decoder.ts @@ -7,6 +7,10 @@ import DecodeAD2 from "./decode-ad2"; import { DecodedAD2 } from "./decode-ad2.interface"; import DecodeLin from "./decode-lin"; import { DecodedLin } from "./decode-lin.interface"; +import DecodePfh from "./decode-pfh"; +import { DecodedPfh } from "./decode-pfh.interface"; +import DecodePfl from "./decode-pfl"; +import { DecodedPfl } from "./decode-pfl.interface"; import DecodeVeh from "./decode-veh"; import { DecodedVeh } from "./decode-veh.interface"; @@ -25,7 +29,9 @@ async function ImportJob(filepath: string): Promise { const ad2: DecodedAD2 = await DecodeAD2(extensionlessFilePath); const veh: DecodedVeh = await DecodeVeh(extensionlessFilePath); const lin: DecodedLin[] = await DecodeLin(extensionlessFilePath); - log.debug("EMS Object", { ad1, ad2, veh, lin }); + const pfh: DecodedPfh = await DecodePfh(extensionlessFilePath); + const pfl: DecodedPfl = await DecodePfl(extensionlessFilePath); + log.debug("EMS Object", { ad1, ad2, veh, lin, pfh, pfl }); } catch (error) { log.error("Error encountered while decoding job. ", errorTypeCheck(error)); }