Files
bodyshop-desktop/src/main/decoder/decode-veh.ts
2025-04-25 09:20:19 -07:00

146 lines
4.3 KiB
TypeScript

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<DecodedVeh> => {
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;