Add PFL and PFH files.
This commit is contained in:
@@ -18,10 +18,6 @@ nsis:
|
|||||||
shortcutName: ${productName}
|
shortcutName: ${productName}
|
||||||
uninstallDisplayName: ${productName}
|
uninstallDisplayName: ${productName}
|
||||||
createDesktopShortcut: always
|
createDesktopShortcut: always
|
||||||
azureSignOptions:
|
|
||||||
endpoint: https://eus.codesigning.azure.net
|
|
||||||
certificateProfileName: ImEXRPS
|
|
||||||
codeSigningAccountName: ImEX
|
|
||||||
mac:
|
mac:
|
||||||
entitlementsInherit: build/entitlements.mac.plist
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
category: public.app-category.business
|
category: public.app-category.business
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { DBFFile } from "dbffile";
|
|||||||
import log from "electron-log/main";
|
import log from "electron-log/main";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
|
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
|
||||||
import { OwnerRecordInterface, DecodedAd1 } from "./decode-ad1.interface";
|
|
||||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||||
|
import { DecodedAd1, OwnerRecordInterface } from "./decode-ad1.interface";
|
||||||
|
|
||||||
const DecodeAD1 = async (
|
const DecodeAD1 = async (
|
||||||
extensionlessFilePath: string
|
extensionlessFilePath: string
|
||||||
@@ -14,7 +14,7 @@ const DecodeAD1 = async (
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Error opening AD1 File.", errorTypeCheck(error));
|
log.error("Error opening AD1 File.", errorTypeCheck(error));
|
||||||
dbf = await DBFFile.open(`${extensionlessFilePath}.AD1`);
|
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) {
|
if (!dbf) {
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ export interface DecodedAD2 {
|
|||||||
est_ct_fn?: string;
|
est_ct_fn?: string;
|
||||||
est_ea?: string;
|
est_ea?: string;
|
||||||
date_estimated?: Date; // This is transformed from insp_date
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const DecodeAD2 = async (
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Error opening AD2 File.", errorTypeCheck(error));
|
log.error("Error opening AD2 File.", errorTypeCheck(error));
|
||||||
dbf = await DBFFile.open(`${extensionlessFilePath}.AD2`);
|
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) {
|
if (!dbf) {
|
||||||
@@ -27,7 +27,7 @@ const DecodeAD2 = async (
|
|||||||
//AD2 will always have only 1 row.
|
//AD2 will always have only 1 row.
|
||||||
//Commented lines have been cross referenced with existing partner fields.
|
//Commented lines have been cross referenced with existing partner fields.
|
||||||
|
|
||||||
const rawAd2Data = deepLowerCaseKeys(
|
const rawAd2Data: DecodedAD2 = deepLowerCaseKeys(
|
||||||
_.pick(rawDBFRecord[0], [
|
_.pick(rawDBFRecord[0], [
|
||||||
//TODO: Add typings for EMS File Formats.
|
//TODO: Add typings for EMS File Formats.
|
||||||
"CLMT_LN",
|
"CLMT_LN",
|
||||||
|
|||||||
15
src/main/decoder/decode-pfh.interface.ts
Normal file
15
src/main/decoder/decode-pfh.interface.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
71
src/main/decoder/decode-pfh.ts
Normal file
71
src/main/decoder/decode-pfh.ts
Normal file
@@ -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<DecodedPfh> => {
|
||||||
|
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;
|
||||||
41
src/main/decoder/decode-pfl.interface.ts
Normal file
41
src/main/decoder/decode-pfl.interface.ts
Normal file
@@ -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[];
|
||||||
|
}
|
||||||
89
src/main/decoder/decode-pfl.ts
Normal file
89
src/main/decoder/decode-pfl.ts
Normal file
@@ -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<DecodedPfl> => {
|
||||||
|
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_<CIECA_TYPE> 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;
|
||||||
@@ -7,6 +7,10 @@ import DecodeAD2 from "./decode-ad2";
|
|||||||
import { DecodedAD2 } from "./decode-ad2.interface";
|
import { DecodedAD2 } from "./decode-ad2.interface";
|
||||||
import DecodeLin from "./decode-lin";
|
import DecodeLin from "./decode-lin";
|
||||||
import { DecodedLin } from "./decode-lin.interface";
|
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 DecodeVeh from "./decode-veh";
|
||||||
import { DecodedVeh } from "./decode-veh.interface";
|
import { DecodedVeh } from "./decode-veh.interface";
|
||||||
|
|
||||||
@@ -25,7 +29,9 @@ async function ImportJob(filepath: string): Promise<void> {
|
|||||||
const ad2: DecodedAD2 = await DecodeAD2(extensionlessFilePath);
|
const ad2: DecodedAD2 = await DecodeAD2(extensionlessFilePath);
|
||||||
const veh: DecodedVeh = await DecodeVeh(extensionlessFilePath);
|
const veh: DecodedVeh = await DecodeVeh(extensionlessFilePath);
|
||||||
const lin: DecodedLin[] = await DecodeLin(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) {
|
} catch (error) {
|
||||||
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
|
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user