diff --git a/src/main/ems-parts-order/ems-parts-order-generate-env.ts b/src/main/ems-parts-order/ems-parts-order-generate-env.ts new file mode 100644 index 0000000..3d725cd --- /dev/null +++ b/src/main/ems-parts-order/ems-parts-order-generate-env.ts @@ -0,0 +1,38 @@ +import { DBFFile } from "dbffile"; +import { envFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/env-field-descriptor"; +import { deleteEmsFileIfExists, generatePpcFilePath } from "../util/ems-util"; +import { EmsPartsOrder } from "./ems-parts-order-interfaces"; + +const EmsPartsOrderGenerateEnvFile = async ( + partsOrder: EmsPartsOrder, +): Promise => { + const records = [ + { + EST_SYSTEM: "C", + RO_ID: partsOrder.job.ro_number, + ESTFILE_ID: partsOrder.job.ciecaid, + STATUS: false, + INCL_ADMIN: true, + INCL_VEH: true, + INCL_EST: true, + INCL_PROFL: true, + INCL_TOTAL: true, + INCL_VENDR: false, + }, + ]; + + await deleteEmsFileIfExists( + generatePpcFilePath(`${partsOrder.job.ciecaid}.ENV`), + ); + + const dbf = await DBFFile.create( + generatePpcFilePath(`${partsOrder.job.ciecaid}.ENV`), + envFieldLineDescriptors, + ); + + await dbf.appendRecords(records); + console.log(`${records.length} LIN file records added.`); + return true; +}; + +export default EmsPartsOrderGenerateEnvFile; diff --git a/src/main/ems-parts-order/ems-parts-order-handler.ts b/src/main/ems-parts-order/ems-parts-order-handler.ts new file mode 100644 index 0000000..fcbb5ab --- /dev/null +++ b/src/main/ems-parts-order/ems-parts-order-handler.ts @@ -0,0 +1,53 @@ +import log from "electron-log/main"; +import express from "express"; +import _ from "lodash"; +import errorTypeCheck from "../../util/errorTypeCheck"; +import store from "../store/store"; +import createdDirectoryIfNotExist from "../util/createDirectoryIfNotExist"; +import EmsPartsOrderGenerateEnvFile from "./ems-parts-order-generate-env"; +import { EmsPartsOrder } from "./ems-parts-order-interfaces"; + +const handleEMSPartsOrder = async ( + req: express.Request, + res: express.Response, +): Promise => { + //Route handler here only. + + const partsOrderBody = req.body as EmsPartsOrder; + try { + await generateEMSPartsOrder(partsOrderBody); + res.status(200).json({ success: true }); + } catch (error) { + log.error("Error generating parts price change", errorTypeCheck(error)); + res.status(500).json({ + success: false, + error: "Error generating parts price change.", + ...errorTypeCheck(error), + }); + } + return; +}; + +const generateEMSPartsOrder = async ( + partsOrder: EmsPartsOrder, +): Promise => { + log.debug(" Generating parts price change"); + //Check to make sure that the EMS Output file path exists. If it doesn't, create it. If it's not set, abandon ship. + + const emsOutFilePath: string | null = store.get("settings.emsOutFilePath"); + if (_.isEmpty(emsOutFilePath) || emsOutFilePath === null) { + log.error("EMS Out file path is not set"); + throw new Error("EMS Out file path is not set"); + } + try { + createdDirectoryIfNotExist(emsOutFilePath); + + //Generate all required files: ad1, ad2, veh, lin, pfh, pfl, pfm,pfo, pfp, pft, stl, ttl + await EmsPartsOrderGenerateEnvFile(partsOrder); + } catch (error) { + log.error("Error generating parts price change", errorTypeCheck(error)); + throw error; + } +}; + +export { handleEMSPartsOrder }; diff --git a/src/main/ems-parts-order/ems-parts-order-interfaces.ts b/src/main/ems-parts-order/ems-parts-order-interfaces.ts new file mode 100644 index 0000000..7021ae4 --- /dev/null +++ b/src/main/ems-parts-order/ems-parts-order-interfaces.ts @@ -0,0 +1,308 @@ +export interface TaxRate { + prt_type: string; + prt_discp: number; + prt_mktyp: boolean; + prt_mkupp: number; + prt_tax_in: boolean; + prt_tax_rt: number; +} + +export interface BillTaxRates { + local_tax_rate: number; + state_tax_rate: number; + federal_tax_rate: number; +} + +export interface PaintCodes { + paint_cd1: string | null; + paint_cd2: string | null; + paint_cd3: string | null; +} + +export interface AreaOfDamage { + impact1: string; + impact2: string | null; +} + +// Jobline export interface +export interface Jobline { + tran_code: string; + act_price: number; + db_ref: string; + db_price: number; + db_hrs: number; + glass_flag: boolean; + id: string; + lbr_amt: number; + lbr_hrs_j: boolean; + lbr_inc: boolean; + lbr_op: string; + lbr_op_j: boolean; + lbr_tax: boolean; + lbr_typ_j: boolean; + line_desc: string; + line_ind: string; + line_no: number; + line_ref: number; + location: string | null; + misc_amt: number; + misc_sublt: boolean; + misc_tax: boolean; + mod_lb_hrs: number; + mod_lbr_ty: string; + oem_partno: string; + op_code_desc: string; + paint_stg: number; + paint_tone: number; + part_qty: number; + part_type: string; + price_inc: boolean; + price_j: boolean; + prt_dsmk_m: number; + prt_dsmk_p: number; + tax_part: boolean; + unq_seq: number; + alt_co_id: string | null; + alt_overrd: boolean; + alt_part_i: boolean; + alt_partm: string | null; + alt_partno: string | null; + bett_amt: number; + bett_pctg: number; + bett_tax: boolean; + bett_type: string | null; + cert_part: boolean; + est_seq: string | null; +} + +// Parts Order Line export interface +export interface PartsOrderLine { + jobline: Jobline; + act_price: number; + id: string; + db_price: number; + line_desc: string; + quantity: number; + part_type: string; +} + +// Vehicle export interface +export interface Vehicle { + v_bstyle: string; + v_type: string; + v_trimcode: string | null; + v_tone: string; + v_stage: string; + v_prod_dt: string | null; + v_options: string | null; + v_paint_codes: PaintCodes; + v_model_yr: string; + v_model_desc: string; + v_mldgcode: string | null; + v_makecode: string; + v_make_desc: string; + v_engine: string; + v_cond: string; + v_color: string | null; + trim_color: string | null; + shopid: string; + plate_no: string; + plate_st: string; + db_v_code: string; + v_vin: string; +} + +// Bodyshop export interface +export interface Bodyshop { + shopname: string; + bill_tax_rates: BillTaxRates; +} + +// Job export interface +export interface Job { + bodyshop: Bodyshop; + ro_number: string; + clm_no: string; + asgn_no: string; + asgn_date: string; + state_tax_rate: number | null; + area_of_damage: AreaOfDamage; + asgn_type: string | null; + ciecaid: string; + clm_addr1: string | null; + clm_city: string | null; + clm_addr2: string | null; + clm_ct_fn: string | null; + clm_ct_ln: string | null; + clm_ct_ph: string | null; + clm_ct_phx: string | null; + clm_ctry: string | null; + clm_ea: string | null; + clm_fax: string | null; + clm_faxx: string | null; + clm_ofc_id: string | null; + clm_ofc_nm: string | null; + clm_ph1: string | null; + clm_ph1x: string | null; + clm_ph2: string | null; + clm_ph2x: string | null; + clm_st: string | null; + clm_title: string | null; + clm_total: number; + clm_zip: string | null; + ded_amt: number; + est_addr1: string | null; + est_addr2: string | null; + est_city: string | null; + est_co_nm: string | null; + est_ct_fn: string; + est_ctry: string | null; + est_ct_ln: string; + est_ea: string; + est_ph1: string | null; + est_st: string | null; + est_zip: string | null; + g_bett_amt: number; + id: string; + ins_addr1: string | null; + ins_city: string | null; + ins_addr2: string | null; + ins_co_id: string | null; + ins_co_nm: string; + ins_ct_fn: string | null; + ins_ct_ln: string | null; + ins_ct_ph: string | null; + ins_ct_phx: string | null; + ins_ctry: string | null; + ins_ea: string | null; + ins_fax: string | null; + ins_faxx: string | null; + ins_memo: string | null; + ins_ph1: string | null; + ins_ph1x: string | null; + ins_ph2: string | null; + ins_ph2x: string | null; + ins_st: string | null; + ins_title: string | null; + ins_zip: string | null; + insd_addr1: string; + insd_addr2: string | null; + insd_city: string; + insd_co_nm: string | null; + insd_ctry: string | null; + insd_ea: string | null; + insd_fax: string | null; + insd_faxx: string | null; + insd_fn: string; + insd_ln: string; + insd_ph1: string; + insd_ph1x: string | null; + insd_ph2: string; + insd_ph2x: string | null; + insd_st: string; + insd_title: string | null; + insd_zip: string; + loss_cat: string; + loss_date: string; + loss_desc: string; + loss_of_use: string | null; + loss_type: string; + ownr_addr1: string; + ownr_addr2: string | null; + ownr_city: string; + ownr_co_nm: string | null; + ownr_ctry: string | null; + ownr_ea: string | null; + ownr_fax: string | null; + ownr_faxx: string | null; + ownr_ph1: string; + ownr_fn: string; + ownr_ln: string; + ownr_ph1x: string | null; + ownr_ph2: string; + ownr_ph2x: string | null; + ownr_st: string; + ownr_title: string | null; + ownr_zip: string; + parts_tax_rates: Record; + pay_amt: number; + pay_date: string | null; + pay_type: string | null; + pay_chknm: string; + payee_nms: string | null; + plate_no: string; + plate_st: string; + po_number: string | null; + policy_no: string; + tax_lbr_rt: number; + tax_levies_rt: number; + tax_paint_mat_rt: number; + tax_predis: number; + tax_prethr: number; + tax_pstthr: number; + tax_registration_number: string | null; + tax_str_rt: number; + tax_shop_mat_rt: number; + tax_sub_rt: number; + tax_thramt: number; + tax_tow_rt: number; + theft_ind: boolean; + tlos_ind: boolean; + towin: boolean; + v_color: string | null; + v_make_desc: string; + v_model_desc: string; + v_model_yr: string; + v_vin: string; + vehicle: Vehicle; + agt_zip: string | null; + agt_st: string | null; + agt_ph2x: string | null; + agt_ph2: string | null; + agt_ph1x: string | null; + agt_ph1: string | null; + agt_lic_no: string | null; + agt_faxx: string | null; + agt_fax: string | null; + agt_ea: string | null; + agt_ctry: string | null; + agt_ct_phx: string | null; + agt_ct_ph: string | null; + agt_ct_ln: string | null; + agt_ct_fn: string | null; + agt_co_nm: string | null; + agt_co_id: string | null; + agt_city: string | null; + agt_addr1: string | null; + agt_addr2: string | null; + adj_g_disc: number; + rate_matd: number | null; + rate_mash: number; + rate_mapa: number; + rate_mahw: number; + rate_macs: number; + rate_mabl: number | null; + rate_ma3s: number; + rate_ma2t: number; + rate_ma2s: number; + rate_lau: number; + rate_las: number; + rate_lar: number; + rate_lam: number; + rate_lag: number; + rate_laf: number; + rate_lae: number | null; + rate_lad: number | null; + rate_lab: number; + rate_laa: number; + rate_la4: number; + rate_la3: number; + rate_la2: number; + rate_la1: number; +} + +// Main Parts Order export interface +export interface EmsPartsOrder { + parts_order_lines: PartsOrderLine[]; + job: Job; +} diff --git a/src/main/http-server/http-server.ts b/src/main/http-server/http-server.ts index bd7f358..8223246 100644 --- a/src/main/http-server/http-server.ts +++ b/src/main/http-server/http-server.ts @@ -8,6 +8,7 @@ import ImportJob from "../decoder/decoder"; import folderScan from "../decoder/folder-scan"; import { handlePartsPariceChangeRequest } from "../ppc/ppc-handler"; import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop"; +import { handleEMSPartsOrder } from "../ems-parts-order/ems-parts-order-handler"; export default class LocalServer { private app: express.Application; @@ -119,6 +120,7 @@ export default class LocalServer { return; }); this.app.post("/ppc", handlePartsPariceChangeRequest); + this.app.post("/oec", handleEMSPartsOrder); this.app.post( "/import", async (req: express.Request, res: express.Response) => { diff --git a/src/main/ipc/ipcMainConfig.ts b/src/main/ipc/ipcMainConfig.ts index 482fa6a..93235cc 100644 --- a/src/main/ipc/ipcMainConfig.ts +++ b/src/main/ipc/ipcMainConfig.ts @@ -14,6 +14,8 @@ import { SettingsWatchedFilePathsRemove, SettingsWatcherPollingGet, SettingsWatcherPollingSet, + SettingEmsOutFilPathSet, + SettingEmsOutFilPathGet, } from "./ipcMainHandler.settings"; import { ipcMainHandleAuthStateChanged, @@ -98,6 +100,14 @@ ipcMain.handle( ipcMain.handle(ipcTypes.toMain.settings.getPpcFilePath, SettingsPpcFilPathGet); ipcMain.handle(ipcTypes.toMain.settings.setPpcFilePath, SettingsPpcFilPathSet); +ipcMain.handle( + ipcTypes.toMain.settings.getEmsOutFilePath, + SettingEmsOutFilPathGet, +); +ipcMain.handle( + ipcTypes.toMain.settings.setEmsOutFilePath, + SettingEmsOutFilPathSet, +); ipcMain.handle(ipcTypes.toMain.user.getActiveShop, () => { return store.get("app.bodyshop.shopname"); diff --git a/src/main/ipc/ipcMainHandler.settings.ts b/src/main/ipc/ipcMainHandler.settings.ts index 6e6c120..cc6eccf 100644 --- a/src/main/ipc/ipcMainHandler.settings.ts +++ b/src/main/ipc/ipcMainHandler.settings.ts @@ -96,6 +96,27 @@ const SettingsPpcFilPathSet = async (): Promise => { return (Store.get("settings.ppcFilePath") as string) || ""; }; +const SettingEmsOutFilPathGet = async (): Promise => { + const emsOutFilePath: string = Store.get("settings.emsOutFilePath"); + return emsOutFilePath; +}; +const SettingEmsOutFilPathSet = async (): Promise => { + const mainWindow = getMainWindow(); + if (!mainWindow) { + log.error("No main window found when trying to open dialog"); + return ""; + } + const result = await dialog.showOpenDialog(mainWindow, { + properties: ["openDirectory"], + }); + + if (!result.canceled) { + Store.set("settings.emsOutFilePath", result.filePaths[0]); //There should only ever be on directory that was selected. + } + + return (Store.get("settings.emsOutFilePath") as string) || ""; +}; + export { SettingsPpcFilPathGet, SettingsPpcFilPathSet, @@ -104,4 +125,6 @@ export { SettingsWatchedFilePathsRemove, SettingsWatcherPollingGet, SettingsWatcherPollingSet, + SettingEmsOutFilPathGet, + SettingEmsOutFilPathSet, }; diff --git a/src/main/ppc/ppc-generate-env.ts b/src/main/ppc/ppc-generate-env.ts index 7963be7..94f8c7a 100644 --- a/src/main/ppc/ppc-generate-env.ts +++ b/src/main/ppc/ppc-generate-env.ts @@ -1,8 +1,6 @@ -import { DBFFile, FieldDescriptor } from "dbffile"; -import { - deleteEmsFileIfExists, - generatePpcFilePath, -} from "./ppc-generate-file"; +import { DBFFile } from "dbffile"; +import { envFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/env-field-descriptor"; +import { deleteEmsFileIfExists, generatePpcFilePath } from "../util/ems-util"; import { PpcJob } from "./ppc-handler"; const GenerateEnvFile = async (job: PpcJob): Promise => { @@ -20,7 +18,6 @@ const GenerateEnvFile = async (job: PpcJob): Promise => { INCL_VENDR: false, }, ]; - //Check if it already exists, delete it if so. await deleteEmsFileIfExists(generatePpcFilePath(`${job.ciecaid}.ENV`)); @@ -35,157 +32,3 @@ const GenerateEnvFile = async (job: PpcJob): Promise => { }; export default GenerateEnvFile; - -//Taken from a set of CCC ems files. -const envFieldLineDescriptors: FieldDescriptor[] = [ - { - name: "EST_SYSTEM", - type: "C", - size: 1, - decimalPlaces: 0, - }, - { - name: "SW_VERSION", - type: "C", - size: 10, - decimalPlaces: 0, - }, - { - name: "DB_VERSION", - type: "C", - size: 12, - decimalPlaces: 0, - }, - { - name: "DB_DATE", - type: "D", - size: 8, - decimalPlaces: 0, - }, - { - name: "UNQFILE_ID", - type: "C", - size: 8, - decimalPlaces: 0, - }, - { - name: "RO_ID", - type: "C", - size: 8, - decimalPlaces: 0, - }, - { - name: "ESTFILE_ID", - type: "C", - size: 38, - decimalPlaces: 0, - }, - { - name: "SUPP_NO", - type: "C", - size: 3, - decimalPlaces: 0, - }, - { - name: "EST_CTRY", - type: "C", - size: 3, - decimalPlaces: 0, - }, - { - name: "TOP_SECRET", - type: "C", - size: 80, - decimalPlaces: 0, - }, - { - name: "H_TRANS_ID", - type: "C", - size: 9, - decimalPlaces: 0, - }, - { - name: "H_CTRL_NO", - type: "C", - size: 9, - decimalPlaces: 0, - }, - { - name: "TRANS_TYPE", - type: "C", - size: 1, - decimalPlaces: 0, - }, - { - name: "STATUS", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "CREATE_DT", - type: "D", - size: 8, - decimalPlaces: 0, - }, - { - name: "CREATE_TM", - type: "C", - size: 6, - decimalPlaces: 0, - }, - { - name: "TRANSMT_DT", - type: "D", - size: 8, - decimalPlaces: 0, - }, - { - name: "TRANSMT_TM", - type: "C", - size: 6, - decimalPlaces: 0, - }, - { - name: "INCL_ADMIN", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "INCL_VEH", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "INCL_EST", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "INCL_PROFL", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "INCL_TOTAL", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "INCL_VENDR", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "EMS_VER", - type: "C", - size: 5, - decimalPlaces: 0, - }, -]; diff --git a/src/main/ppc/ppc-generate-lin.ts b/src/main/ppc/ppc-generate-lin.ts index bac68ed..4e65d93 100644 --- a/src/main/ppc/ppc-generate-lin.ts +++ b/src/main/ppc/ppc-generate-lin.ts @@ -1,8 +1,6 @@ -import { DBFFile, FieldDescriptor } from "dbffile"; -import { - deleteEmsFileIfExists, - generatePpcFilePath, -} from "./ppc-generate-file"; +import { DBFFile } from "dbffile"; +import { linFieldDescriptors } from "../util/ems-interface/fielddescriptors/lin-field-descriptor"; +import { deleteEmsFileIfExists, generatePpcFilePath } from "../util/ems-util"; import { PpcJob } from "./ppc-handler"; const GenerateLinFile = async (job: PpcJob): Promise => { @@ -14,7 +12,6 @@ const GenerateLinFile = async (job: PpcJob): Promise => { ACT_PRICE: line.act_price, }; }); - //Check if it already exists, delete it if so. await deleteEmsFileIfExists(generatePpcFilePath(`${job.ciecaid}.LIN`)); @@ -29,277 +26,3 @@ const GenerateLinFile = async (job: PpcJob): Promise => { }; export default GenerateLinFile; - -//Taken from a set of CCC ems files. -const linFieldDescriptors: FieldDescriptor[] = [ - { - name: "LINE_NO", - type: "N", - size: 3, - decimalPlaces: 0, - }, - { - name: "LINE_IND", - type: "C", - size: 3, - decimalPlaces: 0, - }, - { - name: "LINE_REF", - type: "N", - size: 3, - decimalPlaces: 0, - }, - { - name: "TRAN_CODE", - type: "C", - size: 1, - decimalPlaces: 0, - }, - { - name: "DB_REF", - type: "C", - size: 7, - decimalPlaces: 0, - }, - { - name: "UNQ_SEQ", - type: "N", - size: 4, - decimalPlaces: 0, - }, - { - name: "WHO_PAYS", - type: "C", - size: 2, - decimalPlaces: 0, - }, - { - name: "LINE_DESC", - type: "C", - size: 40, - decimalPlaces: 0, - }, - { - name: "PART_TYPE", - type: "C", - size: 4, - decimalPlaces: 0, - }, - { - name: "PART_DES_J", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "GLASS_FLAG", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "OEM_PARTNO", - type: "C", - size: 25, - decimalPlaces: 0, - }, - { - name: "PRICE_INC", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "ALT_PART_I", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "TAX_PART", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "DB_PRICE", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "ACT_PRICE", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "PRICE_J", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "CERT_PART", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "PART_QTY", - type: "N", - size: 2, - decimalPlaces: 0, - }, - { - name: "ALT_CO_ID", - type: "C", - size: 20, - decimalPlaces: 0, - }, - { - name: "ALT_PARTNO", - type: "C", - size: 25, - decimalPlaces: 0, - }, - { - name: "ALT_OVERRD", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "ALT_PARTM", - type: "C", - size: 45, - decimalPlaces: 0, - }, - { - name: "PRT_DSMK_P", - type: "N", - size: 7, - decimalPlaces: 2, - }, - { - name: "PRT_DSMK_M", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "MOD_LBR_TY", - type: "C", - size: 4, - decimalPlaces: 0, - }, - { - name: "DB_HRS", - type: "N", - size: 5, - decimalPlaces: 1, - }, - { - name: "MOD_LB_HRS", - type: "N", - size: 5, - decimalPlaces: 1, - }, - { - name: "LBR_INC", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "LBR_OP", - type: "C", - size: 4, - decimalPlaces: 0, - }, - { - name: "LBR_HRS_J", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "LBR_TYP_J", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "LBR_OP_J", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "PAINT_STG", - type: "N", - size: 1, - decimalPlaces: 0, - }, - { - name: "PAINT_TONE", - type: "N", - size: 1, - decimalPlaces: 0, - }, - { - name: "LBR_TAX", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "LBR_AMT", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "MISC_AMT", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "MISC_SUBLT", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "MISC_TAX", - type: "L", - size: 1, - decimalPlaces: 0, - }, - { - name: "BETT_TYPE", - type: "C", - size: 4, - decimalPlaces: 0, - }, - { - name: "BETT_PCTG", - type: "N", - size: 8, - decimalPlaces: 4, - }, - { - name: "BETT_AMT", - type: "N", - size: 9, - decimalPlaces: 2, - }, - { - name: "BETT_TAX", - type: "L", - size: 1, - decimalPlaces: 0, - }, -]; diff --git a/src/main/ppc/ppc-handler.ts b/src/main/ppc/ppc-handler.ts index 8db6d31..c1687c2 100644 --- a/src/main/ppc/ppc-handler.ts +++ b/src/main/ppc/ppc-handler.ts @@ -1,13 +1,12 @@ import { UUID } from "crypto"; import log from "electron-log/main"; import express from "express"; -import fs from "fs"; import _ from "lodash"; -import path from "path"; import errorTypeCheck from "../../util/errorTypeCheck"; import store from "../store/store"; -import GenerateLinFile from "./ppc-generate-lin"; +import createdDirectoryIfNotExist from "../util/createDirectoryIfNotExist"; import GenerateEnvFile from "./ppc-generate-env"; +import GenerateLinFile from "./ppc-generate-lin"; const handlePartsPariceChangeRequest = async ( req: express.Request, @@ -40,12 +39,8 @@ const generatePartsPriceChange = async (job: PpcJob): Promise => { throw new Error("PPC file path is not set"); } try { - //If the directory doesn't exist, create it. - const directoryPath = path.dirname(ppcOutFilePath); - if (!fs.existsSync(directoryPath)) { - log.info(`Directory does not exist. Creating: ${directoryPath}`); - fs.mkdirSync(directoryPath, { recursive: true }); - } + createdDirectoryIfNotExist(ppcOutFilePath); + await GenerateLinFile(job); await GenerateEnvFile(job); } catch (error) { diff --git a/src/main/store/store.ts b/src/main/store/store.ts index 7874192..18f78c5 100644 --- a/src/main/store/store.ts +++ b/src/main/store/store.ts @@ -6,6 +6,7 @@ const store = new Store({ runOnStartup: true, filepaths: [], ppcFilePath: null, + emsOutFilePath: null, qbFilePath: "", runWatcherOnStartup: true, polling: { diff --git a/src/main/util/createDirectoryIfNotExist.ts b/src/main/util/createDirectoryIfNotExist.ts new file mode 100644 index 0000000..07e4626 --- /dev/null +++ b/src/main/util/createDirectoryIfNotExist.ts @@ -0,0 +1,21 @@ +import log from "electron-log/main"; +import fs from "fs"; +import path from "path"; +import errorTypeCheck from "../../util/errorTypeCheck"; + +const createdDirectoryIfNotExist = async (dirpath: string) => { + try { + const directoryPath = path.dirname(dirpath); + if (!fs.existsSync(directoryPath)) { + log.info(`Directory does not exist. Creating: ${directoryPath}`); + fs.mkdirSync(directoryPath, { recursive: true }); + } + } catch (error) { + log.error("Error creating directory as needed", errorTypeCheck(error)); + throw new Error( + "Error creating directory: " + errorTypeCheck(error).message, + ); + } +}; + +export default createdDirectoryIfNotExist; diff --git a/src/main/util/ems-interface/fielddescriptors/env-field-descriptor.ts b/src/main/util/ems-interface/fielddescriptors/env-field-descriptor.ts new file mode 100644 index 0000000..ec84c52 --- /dev/null +++ b/src/main/util/ems-interface/fielddescriptors/env-field-descriptor.ts @@ -0,0 +1,154 @@ +import { FieldDescriptor } from "dbffile"; + +export const envFieldLineDescriptors: FieldDescriptor[] = [ + { + name: "EST_SYSTEM", + type: "C", + size: 1, + decimalPlaces: 0, + }, + { + name: "SW_VERSION", + type: "C", + size: 10, + decimalPlaces: 0, + }, + { + name: "DB_VERSION", + type: "C", + size: 12, + decimalPlaces: 0, + }, + { + name: "DB_DATE", + type: "D", + size: 8, + decimalPlaces: 0, + }, + { + name: "UNQFILE_ID", + type: "C", + size: 8, + decimalPlaces: 0, + }, + { + name: "RO_ID", + type: "C", + size: 8, + decimalPlaces: 0, + }, + { + name: "ESTFILE_ID", + type: "C", + size: 38, + decimalPlaces: 0, + }, + { + name: "SUPP_NO", + type: "C", + size: 3, + decimalPlaces: 0, + }, + { + name: "EST_CTRY", + type: "C", + size: 3, + decimalPlaces: 0, + }, + { + name: "TOP_SECRET", + type: "C", + size: 80, + decimalPlaces: 0, + }, + { + name: "H_TRANS_ID", + type: "C", + size: 9, + decimalPlaces: 0, + }, + { + name: "H_CTRL_NO", + type: "C", + size: 9, + decimalPlaces: 0, + }, + { + name: "TRANS_TYPE", + type: "C", + size: 1, + decimalPlaces: 0, + }, + { + name: "STATUS", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "CREATE_DT", + type: "D", + size: 8, + decimalPlaces: 0, + }, + { + name: "CREATE_TM", + type: "C", + size: 6, + decimalPlaces: 0, + }, + { + name: "TRANSMT_DT", + type: "D", + size: 8, + decimalPlaces: 0, + }, + { + name: "TRANSMT_TM", + type: "C", + size: 6, + decimalPlaces: 0, + }, + { + name: "INCL_ADMIN", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "INCL_VEH", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "INCL_EST", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "INCL_PROFL", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "INCL_TOTAL", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "INCL_VENDR", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "EMS_VER", + type: "C", + size: 5, + decimalPlaces: 0, + }, +]; diff --git a/src/main/util/ems-interface/fielddescriptors/lin-field-descriptor.ts b/src/main/util/ems-interface/fielddescriptors/lin-field-descriptor.ts new file mode 100644 index 0000000..968d78b --- /dev/null +++ b/src/main/util/ems-interface/fielddescriptors/lin-field-descriptor.ts @@ -0,0 +1,274 @@ +import { FieldDescriptor } from "dbffile"; + +export const linFieldDescriptors: FieldDescriptor[] = [ + { + name: "LINE_NO", + type: "N", + size: 3, + decimalPlaces: 0, + }, + { + name: "LINE_IND", + type: "C", + size: 3, + decimalPlaces: 0, + }, + { + name: "LINE_REF", + type: "N", + size: 3, + decimalPlaces: 0, + }, + { + name: "TRAN_CODE", + type: "C", + size: 1, + decimalPlaces: 0, + }, + { + name: "DB_REF", + type: "C", + size: 7, + decimalPlaces: 0, + }, + { + name: "UNQ_SEQ", + type: "N", + size: 4, + decimalPlaces: 0, + }, + { + name: "WHO_PAYS", + type: "C", + size: 2, + decimalPlaces: 0, + }, + { + name: "LINE_DESC", + type: "C", + size: 40, + decimalPlaces: 0, + }, + { + name: "PART_TYPE", + type: "C", + size: 4, + decimalPlaces: 0, + }, + { + name: "PART_DES_J", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "GLASS_FLAG", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "OEM_PARTNO", + type: "C", + size: 25, + decimalPlaces: 0, + }, + { + name: "PRICE_INC", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "ALT_PART_I", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "TAX_PART", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "DB_PRICE", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "ACT_PRICE", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "PRICE_J", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "CERT_PART", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "PART_QTY", + type: "N", + size: 2, + decimalPlaces: 0, + }, + { + name: "ALT_CO_ID", + type: "C", + size: 20, + decimalPlaces: 0, + }, + { + name: "ALT_PARTNO", + type: "C", + size: 25, + decimalPlaces: 0, + }, + { + name: "ALT_OVERRD", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "ALT_PARTM", + type: "C", + size: 45, + decimalPlaces: 0, + }, + { + name: "PRT_DSMK_P", + type: "N", + size: 7, + decimalPlaces: 2, + }, + { + name: "PRT_DSMK_M", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "MOD_LBR_TY", + type: "C", + size: 4, + decimalPlaces: 0, + }, + { + name: "DB_HRS", + type: "N", + size: 5, + decimalPlaces: 1, + }, + { + name: "MOD_LB_HRS", + type: "N", + size: 5, + decimalPlaces: 1, + }, + { + name: "LBR_INC", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "LBR_OP", + type: "C", + size: 4, + decimalPlaces: 0, + }, + { + name: "LBR_HRS_J", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "LBR_TYP_J", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "LBR_OP_J", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "PAINT_STG", + type: "N", + size: 1, + decimalPlaces: 0, + }, + { + name: "PAINT_TONE", + type: "N", + size: 1, + decimalPlaces: 0, + }, + { + name: "LBR_TAX", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "LBR_AMT", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "MISC_AMT", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "MISC_SUBLT", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "MISC_TAX", + type: "L", + size: 1, + decimalPlaces: 0, + }, + { + name: "BETT_TYPE", + type: "C", + size: 4, + decimalPlaces: 0, + }, + { + name: "BETT_PCTG", + type: "N", + size: 8, + decimalPlaces: 4, + }, + { + name: "BETT_AMT", + type: "N", + size: 9, + decimalPlaces: 2, + }, + { + name: "BETT_TAX", + type: "L", + size: 1, + decimalPlaces: 0, + }, +]; diff --git a/src/main/ppc/ppc-generate-file.ts b/src/main/util/ems-util.ts similarity index 66% rename from src/main/ppc/ppc-generate-file.ts rename to src/main/util/ems-util.ts index e4412b7..a1c449e 100644 --- a/src/main/ppc/ppc-generate-file.ts +++ b/src/main/util/ems-util.ts @@ -1,6 +1,7 @@ import path from "path"; import store from "../store/store"; import fs from "fs"; + const generatePpcFilePath = (filename: string): string => { const ppcOutFilePath: string | null = store.get("settings.ppcFilePath"); if (!ppcOutFilePath) { @@ -9,6 +10,14 @@ const generatePpcFilePath = (filename: string): string => { return path.resolve(ppcOutFilePath, filename); }; +const generateEmsOutFilePath = (filename: string): string => { + const emsOutFilePath: string | null = store.get("settings.emsOutFilePath"); + if (!emsOutFilePath) { + throw new Error("EMS Out file path is not set"); + } + return path.resolve(emsOutFilePath, filename); +}; + const deleteEmsFileIfExists = async (filename: string): Promise => { // Check if the file exists and delete it if it does try { @@ -16,7 +25,7 @@ const deleteEmsFileIfExists = async (filename: string): Promise => { await fs.promises.unlink(filename); // Delete the file console.log(`Existing file at ${filename} deleted.`); } catch (err) { - if (err.code !== "ENOENT") { + if ((err as NodeJS.ErrnoException).code !== "ENOENT") { // If the error is not "file not found", rethrow it throw err; } @@ -24,4 +33,4 @@ const deleteEmsFileIfExists = async (filename: string): Promise => { } }; -export { generatePpcFilePath, deleteEmsFileIfExists }; +export { generatePpcFilePath, generateEmsOutFilePath, deleteEmsFileIfExists }; diff --git a/src/renderer/src/components/Settings/Settings.EmsOutFilePath.tsx b/src/renderer/src/components/Settings/Settings.EmsOutFilePath.tsx new file mode 100644 index 0000000..aff8ee6 --- /dev/null +++ b/src/renderer/src/components/Settings/Settings.EmsOutFilePath.tsx @@ -0,0 +1,46 @@ +import { FolderOpenFilled } from "@ant-design/icons"; +import { Button, Card, Input, Space } from "antd"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import ipcTypes from "../../../../util/ipcTypes.json"; + +const SettingsEmsOutFilePath: React.FC = () => { + const { t } = useTranslation(); + + const [emsFilePath, setEmsFilePath] = useState(null); + + const getPollingStateFromStore = (): void => { + window.electron.ipcRenderer + .invoke(ipcTypes.toMain.settings.getEmsOutFilePath) + .then((filePath: string | null) => { + setEmsFilePath(filePath); + }); + }; + + //Get state first time it renders. + useEffect(() => { + getPollingStateFromStore(); + }, []); + + const handlePathChange = (): void => { + window.electron.ipcRenderer + .invoke(ipcTypes.toMain.settings.setEmsOutFilePath) + .then((filePath: string | null) => { + setEmsFilePath(filePath); + }); + }; + + return ( + + + +