import { DBFFile } from "dbffile"; import log from "electron-log/main"; import _ from "lodash"; import deepLowerCaseKeys from "../../util/deepLowercaseKeys"; import { DecodedVeh, VehicleRecordInterface } from "./decode-veh.interface"; import errorTypeCheck from "../../util/errorTypeCheck"; import store from "../store/store"; import typeCaster from "../../util/typeCaster"; import { platform } from "@electron-toolkit/utils"; import { findFileCaseInsensitive } from "./decoder-utils"; const DecodeVeh = async ( extensionlessFilePath: string, ): Promise => { let dbf: DBFFile | null = null; if (platform.isWindows) { try { dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`); } catch (error) { log.error("Error opening VEH File.", errorTypeCheck(error)); dbf = await DBFFile.open(`${extensionlessFilePath}.VEH`); log.log("Found VEH file using regular CIECA Id."); } if (!dbf) { log.error(`Could not find any VEH files at ${extensionlessFilePath}`); throw new Error( `Could not find any VEH files at ${extensionlessFilePath}`, ); } } else { const possibleExtensions: string[] = ["v.veh", ".veh"]; const filePath = await findFileCaseInsensitive( extensionlessFilePath, possibleExtensions, ); try { if (!filePath) { log.error(`Could not find any VEH files at ${extensionlessFilePath}`); throw new Error( `Could not find any VEH files at ${extensionlessFilePath}`, ); } dbf = await DBFFile.open(filePath, { readMode: "loose" }); } catch (error) { log.error("Error opening VEH File.", errorTypeCheck(error)); throw error; } } const rawDBFRecord = await dbf.readRecords(1); //AD2 will always have only 1 row. //Commented lines have been cross referenced with existing partner fields. //typeCaster is required as the previous partner sent some of these values toString, and the database was made accordingly rather than keeping their original type. //Alternative is to change the database schema to match the original type. const rawVehData: VehicleRecordInterface = typeCaster( deepLowerCaseKeys( _.pick(rawDBFRecord[0], [ //TODO: Add typings for EMS File Formats. "IMPACT_1", "IMPACT_2", "DB_V_CODE", "PLATE_NO", "PLATE_ST", "V_VIN", "V_COND", "V_PROD_DT", "V_MODEL_YR", "V_MAKECODE", "V_MAKEDESC", "V_MODEL", "V_TYPE", "V_BSTYLE", "V_TRIMCODE", "TRIM_COLOR", "V_MLDGCODE", "V_ENGINE", "V_MILEAGE", "V_COLOR", "V_TONE", "V_STAGE", "PAINT_CD1", "PAINT_CD2", "PAINT_CD3", ]), ), { v_tone: "string", v_stage: "string", }, ); //Apply business logic transfomrations. //An old error where the column had an extra underscore. rawVehData.v_make_desc = rawVehData.v_makedesc || rawVehData.v_makecode; //Fallback for US. delete rawVehData.v_makedesc; //An old error where the column had an extra underscore. rawVehData.v_model_desc = rawVehData.v_model; delete rawVehData.v_model; //Consolidate Area of Damage. const area_of_damage = { impact1: rawVehData.impact_1 ?? "", impact2: rawVehData.impact_2 ?? "", }; delete rawVehData.impact_1; delete rawVehData.impact_2; const kmin = rawVehData.v_mileage ?? 0; delete rawVehData.v_mileage; //Consolidate Paint Code information. rawVehData.v_paint_codes = { paint_cd1: rawVehData.paint_cd1 ?? "", paint_cd2: rawVehData.paint_cd2 ?? "", paint_cd3: rawVehData.paint_cd3 ?? "", }; delete rawVehData.paint_cd1; delete rawVehData.paint_cd2; delete rawVehData.paint_cd3; rawVehData.shopid = store.get("app.bodyshop.id"); //Aggregate the vehicle data to be stamped onto the job record. const jobVehicleData: DecodedVeh = { plate_no: rawVehData.plate_no, plate_st: rawVehData.plate_st, v_vin: rawVehData.v_vin, v_model_yr: rawVehData.v_model_yr, v_make_desc: rawVehData.v_make_desc, v_model_desc: rawVehData.v_model_desc, v_color: rawVehData.v_color, kmin: kmin, area_of_damage: area_of_damage, vehicle: { data: rawVehData, }, }; return jobVehicleData; }; export default DecodeVeh;