Strip out partner related functionality.
This commit is contained in:
@@ -1,158 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { ad1FieldLineDescriptors } from "../util/ems-interface/fielddescriptors/ad1-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateAd1File = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = [
|
||||
{
|
||||
INS_CO_ID: partsOrder.job.ins_co_nm,
|
||||
INS_CO_NM: partsOrder.job.ins_co_nm,
|
||||
INS_ADDR1: partsOrder.job.ins_addr1,
|
||||
INS_ADDR2: partsOrder.job.ins_addr2,
|
||||
INS_CITY: partsOrder.job.ins_city,
|
||||
INS_ST: partsOrder.job.ins_st,
|
||||
INS_ZIP: partsOrder.job.ins_zip,
|
||||
INS_CTRY: partsOrder.job.ins_ctry,
|
||||
INS_PH1: partsOrder.job.ins_ph1,
|
||||
INS_PH1X: partsOrder.job.ins_ph1x,
|
||||
INS_PH2: partsOrder.job.ins_ph2,
|
||||
INS_PH2X: partsOrder.job.ins_ph2x,
|
||||
INS_FAX: partsOrder.job.ins_fax,
|
||||
INS_FAXX: partsOrder.job.ins_faxx,
|
||||
INS_CT_LN: partsOrder.job.ins_ct_ln,
|
||||
INS_CT_FN: partsOrder.job.ins_ct_fn,
|
||||
INS_TITLE: partsOrder.job.ins_title,
|
||||
INS_CT_PH: partsOrder.job.ins_ct_ph,
|
||||
INS_CT_PHX: partsOrder.job.ins_ct_phx,
|
||||
INS_EA: partsOrder.job.ins_ea,
|
||||
INS_MEMO: partsOrder.job.ins_memo,
|
||||
POLICY_NO: partsOrder.job.policy_no,
|
||||
DED_AMT: partsOrder.job.ded_amt,
|
||||
DED_STATUS: partsOrder.job.ded_status,
|
||||
ASGN_NO: partsOrder.job.asgn_no,
|
||||
ASGN_DATE: partsOrder.job.asgn_date
|
||||
? new Date(partsOrder.job.asgn_date)
|
||||
: null,
|
||||
ASGN_TYPE: partsOrder.job.asgn_type,
|
||||
CLM_NO: partsOrder.job.clm_no,
|
||||
CLM_OFC_ID: partsOrder.job.clm_ofc_id,
|
||||
CLM_OFC_NM: partsOrder.job.clm_ofc_nm,
|
||||
CLM_ADDR1: partsOrder.job.clm_addr1,
|
||||
CLM_ADDR2: partsOrder.job.clm_addr2,
|
||||
CLM_CITY: partsOrder.job.clm_city,
|
||||
CLM_ST: partsOrder.job.clm_st,
|
||||
CLM_ZIP: partsOrder.job.clm_zip,
|
||||
CLM_CTRY: partsOrder.job.clm_ctry,
|
||||
CLM_PH1: partsOrder.job.clm_ph1,
|
||||
CLM_PH1X: partsOrder.job.clm_ph1x,
|
||||
CLM_PH2: partsOrder.job.clm_ph2,
|
||||
CLM_PH2X: partsOrder.job.clm_ph2x,
|
||||
CLM_FAX: partsOrder.job.clm_fax,
|
||||
CLM_FAXX: partsOrder.job.clm_faxx,
|
||||
CLM_CT_LN: partsOrder.job.clm_ct_ln,
|
||||
CLM_CT_FN: partsOrder.job.clm_ct_fn,
|
||||
CLM_TITLE: partsOrder.job.clm_title,
|
||||
CLM_CT_PH: partsOrder.job.clm_ct_ph,
|
||||
CLM_CT_PHX: partsOrder.job.clm_ct_phx,
|
||||
CLM_EA: partsOrder.job.clm_ea,
|
||||
PAYEE_NMS: partsOrder.job.payee_nms,
|
||||
PAY_TYPE: partsOrder.job.pay_type,
|
||||
PAY_DATE: partsOrder.job.pay_date,
|
||||
PAY_CHKNM: null, // Explicitly set to null as in original code
|
||||
PAY_AMT: null, // Explicitly set to null as in original code
|
||||
PAY_MEMO: partsOrder.job.pay_memo,
|
||||
AGT_CO_ID: partsOrder.job.agt_co_id,
|
||||
AGT_CO_NM: partsOrder.job.agt_co_nm,
|
||||
AGT_ADDR1: partsOrder.job.agt_addr1,
|
||||
AGT_ADDR2: partsOrder.job.agt_addr2,
|
||||
AGT_CITY: partsOrder.job.agt_city,
|
||||
AGT_ST: partsOrder.job.agt_st,
|
||||
AGT_ZIP: partsOrder.job.agt_zip,
|
||||
AGT_CTRY: partsOrder.job.agt_ctry,
|
||||
AGT_PH1: partsOrder.job.agt_ph1,
|
||||
AGT_PH1X: partsOrder.job.agt_ph1x,
|
||||
AGT_PH2: partsOrder.job.agt_ph2,
|
||||
AGT_PH2X: partsOrder.job.agt_ph2x,
|
||||
AGT_FAX: partsOrder.job.agt_fax,
|
||||
AGT_FAXX: partsOrder.job.agt_faxx,
|
||||
AGT_CT_LN: partsOrder.job.agt_ct_ln,
|
||||
AGT_CT_FN: partsOrder.job.agt_ct_fn,
|
||||
AGT_CT_PH: partsOrder.job.agt_ct_ph,
|
||||
AGT_CT_PHX: partsOrder.job.agt_ct_phx,
|
||||
AGT_EA: partsOrder.job.agt_ea,
|
||||
AGT_LIC_NO: partsOrder.job.agt_lic_no,
|
||||
LOSS_DATE: partsOrder.job.loss_date
|
||||
? new Date(partsOrder.job.loss_date)
|
||||
: null,
|
||||
LOSS_CAT: null, // Explicitly set to null as in original code
|
||||
LOSS_TYPE: null, // Explicitly set to null as in original code
|
||||
LOSS_DESC: partsOrder.job.loss_desc,
|
||||
THEFT_IND: null, // Explicitly set to null as in original code
|
||||
CAT_NO: partsOrder.job.cat_no,
|
||||
TLOS_IND: null, // Explicitly set to null as in original code
|
||||
LOSS_MEMO: partsOrder.job.loss_memo,
|
||||
CUST_PR: partsOrder.job.cust_pr,
|
||||
INSD_LN: partsOrder.job.insd_ln,
|
||||
INSD_FN: partsOrder.job.insd_fn,
|
||||
INSD_TITLE: partsOrder.job.insd_title,
|
||||
INSD_CO_NM: partsOrder.job.insd_co_nm,
|
||||
INSD_ADDR1: partsOrder.job.insd_addr1,
|
||||
INSD_ADDR2: partsOrder.job.insd_addr2,
|
||||
INSD_CITY: partsOrder.job.insd_city,
|
||||
INSD_ST: partsOrder.job.insd_st,
|
||||
INSD_ZIP: partsOrder.job.insd_zip,
|
||||
INSD_CTRY: partsOrder.job.insd_ctry,
|
||||
INSD_PH1: partsOrder.job.insd_ph1,
|
||||
INSD_PH1X: partsOrder.job.insd_ph1x,
|
||||
INSD_PH2: partsOrder.job.insd_ph2,
|
||||
INSD_PH2X: partsOrder.job.insd_ph2x,
|
||||
INSD_FAX: partsOrder.job.insd_fax,
|
||||
INSD_FAXX: partsOrder.job.insd_faxx,
|
||||
INSD_EA: partsOrder.job.insd_ea,
|
||||
OWNR_LN: partsOrder.job.ownr_ln,
|
||||
OWNR_FN: partsOrder.job.ownr_fn,
|
||||
OWNR_TITLE: partsOrder.job.ownr_title,
|
||||
OWNR_CO_NM: partsOrder.job.ownr_co_nm,
|
||||
OWNR_ADDR1: partsOrder.job.ownr_addr1,
|
||||
OWNR_ADDR2: partsOrder.job.ownr_addr2,
|
||||
OWNR_CITY: partsOrder.job.ownr_city,
|
||||
OWNR_ST: partsOrder.job.ownr_st,
|
||||
OWNR_ZIP: partsOrder.job.ownr_zip,
|
||||
OWNR_CTRY: partsOrder.job.ownr_ctry,
|
||||
OWNR_PH1: partsOrder.job.ownr_ph1,
|
||||
OWNR_PH1X: partsOrder.job.ownr_ph1x,
|
||||
OWNR_PH2: partsOrder.job.ownr_ph2,
|
||||
OWNR_PH2X: partsOrder.job.ownr_ph2x,
|
||||
OWNR_FAX: partsOrder.job.ownr_fax,
|
||||
OWNR_FAXX: partsOrder.job.ownr_faxx,
|
||||
OWNR_EA: partsOrder.job.ownr_ea,
|
||||
},
|
||||
];
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.AD1`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.AD1`),
|
||||
ad1FieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} AD1 file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating AD1 file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateAd1File;
|
||||
@@ -1,67 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { ad2FieldLineDescriptors } from "../util/ems-interface/fielddescriptors/ad2-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateAd2File = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = [
|
||||
{
|
||||
EST_CO_NM: partsOrder.job.est_co_nm,
|
||||
EST_ADDR1: partsOrder.job.est_addr1,
|
||||
EST_ADDR2: partsOrder.job.est_addr2,
|
||||
EST_CITY: partsOrder.job.est_city,
|
||||
EST_ST: partsOrder.job.est_st,
|
||||
EST_ZIP: partsOrder.job.est_zip,
|
||||
EST_CTRY: partsOrder.job.est_ctry,
|
||||
EST_PH1: partsOrder.job.est_ph1,
|
||||
EST_CT_LN: partsOrder.job.est_ct_ln,
|
||||
EST_CT_FN: partsOrder.job.est_ct_fn,
|
||||
EST_EA: partsOrder.job.est_ea,
|
||||
CLMT_ADDR1: partsOrder.job.clm_addr1,
|
||||
CLMT_ADDR2: partsOrder.job.clm_addr2,
|
||||
CLMT_CITY: partsOrder.job.clm_city,
|
||||
CLMT_ST: partsOrder.job.clm_st,
|
||||
CLMT_ZIP: partsOrder.job.clm_zip,
|
||||
CLMT_CTRY: partsOrder.job.clm_ctry,
|
||||
CLMT_PH1: partsOrder.job.clm_ph1,
|
||||
CLMT_PH1X: partsOrder.job.clm_ph1x,
|
||||
CLMT_PH2: partsOrder.job.clm_ph2,
|
||||
CLMT_PH2X: partsOrder.job.clm_ph2x,
|
||||
CLMT_FAX: partsOrder.job.clm_fax,
|
||||
CLMT_FAXX: partsOrder.job.clm_faxx,
|
||||
CLMT_LN: partsOrder.job.clm_ct_ln,
|
||||
CLMT_FN: partsOrder.job.clm_ct_fn,
|
||||
CLMT_TITLE: partsOrder.job.clm_title,
|
||||
CLMT_CT_PH: partsOrder.job.clm_ct_ph,
|
||||
CLMT_CT_PHX: partsOrder.job.clm_ct_phx,
|
||||
CLMT_EA: partsOrder.job.clm_ea,
|
||||
RF_CO_NM: partsOrder.job.bodyshop.shopname,
|
||||
},
|
||||
];
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.AD2`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.AD2`),
|
||||
ad2FieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} AD2 file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating AD2 file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateAd2File;
|
||||
@@ -1,80 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { envFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/env-field-descriptor";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateEnvFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const dateNow = new Date();
|
||||
const formatTime = (date: Date): string =>
|
||||
`${date.getHours().toString().padStart(2, "0")}${date.getMinutes().toString().padStart(2, "0")}${date.getSeconds().toString().padStart(2, "0")}`;
|
||||
|
||||
const {
|
||||
job: { ro_number, ciecaid },
|
||||
} = partsOrder;
|
||||
|
||||
// Find the highest line_ind value
|
||||
const lineInds = partsOrder.parts_order_lines.map(
|
||||
(line) => line.jobline.line_ind,
|
||||
);
|
||||
const getNumber = (str: string): number => {
|
||||
const match = str.match(/(\d+)$/);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
};
|
||||
const highestLineInd = lineInds.reduce(
|
||||
(max, current) => (getNumber(current) > getNumber(max) ? current : max),
|
||||
lineInds[0] || "",
|
||||
);
|
||||
|
||||
const records = [
|
||||
{
|
||||
EST_SYSTEM: "M",
|
||||
SW_VERSION: "25.3",
|
||||
DB_VERSION: "OCT_25_V",
|
||||
DB_DATE: dateNow,
|
||||
RO_ID: ro_number,
|
||||
ESTFILE_ID: ciecaid,
|
||||
SUPP_NO: highestLineInd ? getNumber(highestLineInd).toString() : "1",
|
||||
EST_CTRY: "CAN",
|
||||
TOP_SECRET: "00000000-0000-0000-0000-000000000000",
|
||||
TRANS_TYPE: highestLineInd ? highestLineInd.charAt(0) : "S",
|
||||
STATUS: false,
|
||||
CREATE_DT: dateNow,
|
||||
CREATE_TM: formatTime(dateNow),
|
||||
TRANSMT_DT: dateNow,
|
||||
TRANSMT_TM: formatTime(dateNow),
|
||||
INCL_ADMIN: true,
|
||||
INCL_VEH: true,
|
||||
INCL_EST: true,
|
||||
INCL_PROFL: false,
|
||||
INCL_TOTAL: false,
|
||||
INCL_VENDR: false,
|
||||
EMS_VER: "2.0",
|
||||
},
|
||||
];
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.ENV`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.ENV`),
|
||||
envFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} ENV file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating ENV file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateEnvFile;
|
||||
@@ -1,85 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
import { linFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/lin-field-descriptors";
|
||||
|
||||
const EmsPartsOrderGenerateLinFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = partsOrder.parts_order_lines.map((partsOrderLine) => ({
|
||||
LINE_NO: partsOrderLine.jobline?.line_no,
|
||||
LINE_IND: partsOrderLine.jobline?.line_ind,
|
||||
LINE_REF: partsOrderLine.jobline?.line_ref,
|
||||
TRAN_CODE: partsOrderLine.jobline?.tran_code ?? "1",
|
||||
DB_REF: partsOrderLine.jobline?.db_ref,
|
||||
UNQ_SEQ: partsOrderLine.jobline?.unq_seq,
|
||||
PART_DES_J: false,
|
||||
LINE_DESC: partsOrderLine.jobline?.line_desc,
|
||||
PART_TYPE:
|
||||
partsOrderLine.priceChange === true
|
||||
? partsOrderLine.part_type
|
||||
: partsOrderLine.jobline?.part_type,
|
||||
GLASS_FLAG: partsOrderLine.jobline?.glass_flag,
|
||||
OEM_PARTNO: partsOrderLine.jobline?.oem_partno,
|
||||
PRICE_INC: partsOrderLine.jobline?.price_inc,
|
||||
ALT_PART_I: partsOrderLine.jobline?.alt_part_i,
|
||||
TAX_PART: partsOrderLine.jobline?.tax_part,
|
||||
DB_PRICE: partsOrderLine.jobline?.db_price,
|
||||
ACT_PRICE:
|
||||
partsOrderLine.priceChange === true
|
||||
? partsOrderLine.act_price
|
||||
: partsOrderLine.jobline?.act_price,
|
||||
PRICE_J: partsOrderLine.jobline?.price_j,
|
||||
CERT_PART: partsOrderLine.jobline?.cert_part,
|
||||
PART_QTY: partsOrderLine.jobline?.part_qty,
|
||||
ALT_CO_ID: partsOrderLine.jobline?.alt_co_id,
|
||||
ALT_PARTNO: partsOrderLine.jobline?.alt_partno,
|
||||
ALT_OVERRD: partsOrderLine.jobline?.alt_overrd,
|
||||
ALT_PARTM: partsOrderLine.jobline?.alt_partm,
|
||||
PRT_DSMK_P: partsOrderLine.jobline?.prt_dsmk_p,
|
||||
PRT_DSMK_M: partsOrderLine.jobline?.prt_dsmk_m,
|
||||
MOD_LBR_TY: partsOrderLine.jobline?.mod_lbr_ty,
|
||||
DB_HRS: partsOrderLine.jobline?.db_hrs,
|
||||
MOD_LB_HRS: partsOrderLine.jobline?.mod_lb_hrs,
|
||||
LBR_INC: partsOrderLine.jobline?.lbr_inc,
|
||||
LBR_OP: partsOrderLine.jobline?.lbr_op,
|
||||
LBR_HRS_J: partsOrderLine.jobline?.lbr_hrs_j,
|
||||
LBR_TYP_J: partsOrderLine.jobline?.lbr_typ_j,
|
||||
LBR_OP_J: partsOrderLine.jobline?.lbr_op_j,
|
||||
PAINT_STG: partsOrderLine.jobline?.paint_stg,
|
||||
PAINT_TONE: partsOrderLine.jobline?.paint_tone,
|
||||
LBR_TAX: partsOrderLine.jobline?.lbr_tax,
|
||||
LBR_AMT: partsOrderLine.jobline?.lbr_amt,
|
||||
MISC_AMT: partsOrderLine.jobline?.misc_amt,
|
||||
MISC_SUBLT: partsOrderLine.jobline?.misc_sublt,
|
||||
MISC_TAX: partsOrderLine.jobline?.misc_tax,
|
||||
BETT_TYPE: partsOrderLine.jobline?.bett_type,
|
||||
BETT_PCTG: partsOrderLine.jobline?.bett_pctg,
|
||||
BETT_AMT: partsOrderLine.jobline?.bett_amt,
|
||||
BETT_TAX: partsOrderLine.jobline?.bett_tax,
|
||||
}));
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.LIN`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.LIN`),
|
||||
linFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} LIN file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating LIN file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateLinFile;
|
||||
@@ -1,59 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
import { pfhFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pfh-field-descriptors";
|
||||
|
||||
const EmsPartsOrderGeneratePfhFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = [
|
||||
{
|
||||
ID_PRO_NAM: "REPAIR FACILITY", // Job.id_pro_nam?.Value
|
||||
TAX_PRETHR: (partsOrder.job.tax_prethr || 0) * 100,
|
||||
TAX_THRAMT: (partsOrder.job.tax_thramt || 0) * 100,
|
||||
TAX_PSTTHR: (partsOrder.job.tax_pstthr || 0) * 100,
|
||||
TAX_TOW_IN: true, // Job.tax_tow_in?.Value
|
||||
TAX_TOW_RT: (partsOrder.job.tax_tow_rt || 0) * 100,
|
||||
TAX_STR_IN: true, // Job.tax_str_in?.Value
|
||||
TAX_STR_RT: (partsOrder.job.tax_str_rt || 0) * 100,
|
||||
TAX_SUB_IN: true, // Job.tax_sub_in?.Value
|
||||
TAX_SUB_RT: (partsOrder.job.tax_sub_rt || 0) * 100,
|
||||
TAX_BTR_IN: true, // Job.tax_btr_in?.Value
|
||||
TAX_LBR_RT:
|
||||
(partsOrder.job.bodyshop?.bill_tax_rates?.state_tax_rate || 0) * 100,
|
||||
TAX_GST_RT:
|
||||
(partsOrder.job.bodyshop?.bill_tax_rates?.federal_tax_rate || 0) *
|
||||
100,
|
||||
TAX_GST_IN: true, // Job.tax_gst_in?.Value
|
||||
ADJ_G_DISC: (partsOrder.job.adj_g_disc || 0) * 100,
|
||||
ADJ_TOWDIS: (partsOrder.job.adj_towdis || 0) * 100,
|
||||
ADJ_STRDIS: (partsOrder.job.adj_strdis || 0) * 100,
|
||||
ADJ_BTR_IN: null, // Job.adj_btr_in?.Value
|
||||
TAX_PREDIS: (partsOrder.job.tax_predis || 0) * 100,
|
||||
},
|
||||
];
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFH`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFH`),
|
||||
pfhFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFH file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFH file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePfhFile;
|
||||
@@ -1,302 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { DecodedPflLine } from "../decoder/decode-pfl.interface";
|
||||
import { pflFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pfl-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import uppercaseObjectKeys from "../util/uppercaseObjectKeys";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
import _ from "lodash";
|
||||
|
||||
const EmsPartsOrderGeneratePflFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
let records;
|
||||
|
||||
if (partsOrder.job.cieca_pfl && !_.isEmpty(partsOrder.job.cieca_pfl)) {
|
||||
records = Object.keys(partsOrder.job.cieca_pfl).map((key) => {
|
||||
const record: DecodedPflLine = partsOrder.job.cieca_pfl[key];
|
||||
return uppercaseObjectKeys(record);
|
||||
});
|
||||
} else {
|
||||
//We don't have the PFL data for an old job, so make it manually.
|
||||
|
||||
records = [
|
||||
{
|
||||
LBR_TYPE: "LAA",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_laa,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAB",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lab,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
|
||||
{
|
||||
LBR_TYPE: "LAD",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lad,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAE",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lae,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAF",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_laf,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAG",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lag,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAM",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lam,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAR",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lar,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAS",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_las,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LAU",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_lau,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LA1",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_la1,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LA2",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_la2,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LA3",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_la3,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
{
|
||||
LBR_TYPE: "LA4",
|
||||
LBR_DESC: "",
|
||||
LBR_RATE: partsOrder.job.rate_la4,
|
||||
LBR_TAX_IN: true,
|
||||
LBR_TAXP: null, // Job.bodyshop.bill_tax_rates.state_tax_rate?.Value ?? 0,
|
||||
LBR_ADJP: 0,
|
||||
LBR_TX_TY1: null, //partsOrder.job.lbr_tx_ty1,
|
||||
LBR_TX_IN1: null, //partsOrder.job.lbr_tx_in1,
|
||||
LBR_TX_TY2: null, //partsOrder.job.lbr_tx_ty2,
|
||||
LBR_TX_IN2: null, //partsOrder.job.lbr_tx_in2,
|
||||
LBR_TX_TY3: null, //partsOrder.job.lbr_tx_ty3,
|
||||
LBR_TX_IN3: null, //partsOrder.job.lbr_tx_in3,
|
||||
LBR_TX_TY4: null, //partsOrder.job.lbr_tx_ty4,
|
||||
LBR_TX_IN4: null, //partsOrder.job.lbr_tx_in4,
|
||||
LBR_TX_TY5: null, //partsOrder.job.lbr_tx_ty5,
|
||||
LBR_TX_IN5: null, //partsOrder.job.lbr_tx_in5,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFL`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFL`),
|
||||
pflFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFL file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFL file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePflFile;
|
||||
@@ -1,105 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import _ from "lodash";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { DecodedPfmLine } from "../decoder/decode-pfm.interface";
|
||||
import { pfmFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pfm-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import uppercaseObjectKeys from "../util/uppercaseObjectKeys";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGeneratePfmFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
let records;
|
||||
if (partsOrder.job.materials && !_.isEmpty(partsOrder.job.materials)) {
|
||||
records = Object.keys(partsOrder.job.materials).map((key) => {
|
||||
const record: DecodedPfmLine = partsOrder.job.materials[key];
|
||||
return uppercaseObjectKeys(record);
|
||||
});
|
||||
} else {
|
||||
//Older records may not have materials, especially for ImEX.
|
||||
records = [
|
||||
{
|
||||
MATL_TYPE: "MAPA",
|
||||
CAL_CODE: null,
|
||||
CAL_DESC: null,
|
||||
CAL_MAXDLR: 0,
|
||||
CAL_PRIP: 0,
|
||||
CAL_SECP: 0,
|
||||
MAT_CALP: 0,
|
||||
CAL_PRETHR: 0,
|
||||
CAL_PSTTHR: 0,
|
||||
CAL_THRAMT: 0,
|
||||
CAL_LBRMIN: 0,
|
||||
CAL_LBRMAX: 0,
|
||||
CAL_LBRRTE: partsOrder.job.rate_mapa,
|
||||
CAL_OPCODE: null,
|
||||
TAX_IND: true,
|
||||
MAT_TAXP: null,
|
||||
MAT_ADJP: null,
|
||||
MAT_TX_TY1: null,
|
||||
MAT_TX_IN1: null,
|
||||
MAT_TX_TY2: null,
|
||||
MAT_TX_IN2: null,
|
||||
MAT_TX_TY3: null,
|
||||
MAT_TX_IN3: null,
|
||||
MAT_TX_TY4: null,
|
||||
MAT_TX_IN4: null,
|
||||
MAT_TX_TY5: null,
|
||||
MAT_TX_IN5: null,
|
||||
},
|
||||
{
|
||||
MATL_TYPE: "MASH",
|
||||
CAL_CODE: null,
|
||||
CAL_DESC: null,
|
||||
CAL_MAXDLR: 0,
|
||||
CAL_PRIP: 0,
|
||||
CAL_SECP: 0,
|
||||
MAT_CALP: 0,
|
||||
CAL_PRETHR: 0,
|
||||
CAL_PSTTHR: 0,
|
||||
CAL_THRAMT: 0,
|
||||
CAL_LBRMIN: 0,
|
||||
CAL_LBRMAX: 0,
|
||||
CAL_LBRRTE: partsOrder.job.rate_mash,
|
||||
CAL_OPCODE: null,
|
||||
TAX_IND: true,
|
||||
MAT_TAXP: null,
|
||||
MAT_ADJP: null,
|
||||
MAT_TX_TY1: null,
|
||||
MAT_TX_IN1: null,
|
||||
MAT_TX_TY2: null,
|
||||
MAT_TX_IN2: null,
|
||||
MAT_TX_TY3: null,
|
||||
MAT_TX_IN3: null,
|
||||
MAT_TX_TY4: null,
|
||||
MAT_TX_IN4: null,
|
||||
MAT_TX_TY5: null,
|
||||
MAT_TX_IN5: null,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFM`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFM`),
|
||||
pfmFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFM file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFM file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePfmFile;
|
||||
@@ -1,34 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { pfoFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pfo-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGeneratePfoFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = []; //This was kept blank previously as well.
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFO`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFO`),
|
||||
pfoFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFO file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFO file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePfoFile;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { DecodedPfpLine } from "../decoder/decode-pfp.interface";
|
||||
import { pfpFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pfp-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import uppercaseObjectKeys from "../util/uppercaseObjectKeys";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGeneratePfpFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = Object.keys(partsOrder.job.parts_tax_rates).map((key) => {
|
||||
const record: DecodedPfpLine = partsOrder.job.parts_tax_rates[key];
|
||||
return uppercaseObjectKeys(record);
|
||||
});
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFP`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFP`),
|
||||
pfpFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFP file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFP file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePfpFile;
|
||||
@@ -1,34 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { pftFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/pft-field-descriptor";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGeneratePftFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = []; //Left blank intentionally as per previous code.
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFT`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.PFT`),
|
||||
pftFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} PFT file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PFT file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGeneratePftFile;
|
||||
@@ -1,40 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { DecodedStlLine } from "../decoder/decode-stl.interface";
|
||||
import { stlFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/stl-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import uppercaseObjectKeys from "../util/uppercaseObjectKeys";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateStlFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
//TODO: Add CIECA STL to parts order.
|
||||
const records = Object.keys(partsOrder.job.cieca_stl?.data).map((key) => {
|
||||
const record: DecodedStlLine = partsOrder.job.cieca_stl.data[key];
|
||||
return uppercaseObjectKeys(record);
|
||||
});
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.STL`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.STL`),
|
||||
stlFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} STL file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating STL file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateStlFile;
|
||||
@@ -1,36 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { ttlFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/ttl-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import uppercaseObjectKeys from "../util/uppercaseObjectKeys";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateTtlFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
//TODO: Add CIECA STL to parts order.
|
||||
const records = uppercaseObjectKeys(partsOrder.job.cieca_ttl?.data);
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.TTL`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.TTL`),
|
||||
ttlFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords([records]);
|
||||
console.log(`${records.length} TTL file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating TTL file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateTtlFile;
|
||||
@@ -1,65 +0,0 @@
|
||||
import { DBFFile } from "dbffile";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import { vehFieldLineDescriptors } from "../util/ems-interface/fielddescriptors/veh-field-descriptors";
|
||||
import {
|
||||
deleteEmsFileIfExists,
|
||||
generateEmsOutFilePath,
|
||||
} from "../util/ems-util";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const EmsPartsOrderGenerateVehFile = async (
|
||||
partsOrder: EmsPartsOrder,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const records = [
|
||||
{
|
||||
IMPACT_1: partsOrder.job.area_of_damage?.impact1 || null,
|
||||
IMPACT_2: partsOrder.job.area_of_damage?.impact2 || null,
|
||||
DMG_MEMO: null,
|
||||
DB_V_CODE: "",
|
||||
PLATE_NO: partsOrder.job.plate_no || null,
|
||||
PLATE_ST: partsOrder.job.plate_st || null,
|
||||
V_VIN: partsOrder.job.v_vin || null,
|
||||
V_COND: "",
|
||||
V_PROD_DT: "",
|
||||
V_MODEL_YR: partsOrder.job.v_model_yr || null,
|
||||
V_MAKECODE: "",
|
||||
V_MAKEDESC: partsOrder.job.v_make_desc || null,
|
||||
V_MODEL: partsOrder.job.v_model_desc || null,
|
||||
V_TYPE: partsOrder.job.vehicle?.v_type || null,
|
||||
V_BSTYLE: partsOrder.job.vehicle?.v_bstyle || null,
|
||||
V_TRIMCODE: partsOrder.job.vehicle?.v_trimcode || null,
|
||||
TRIM_COLOR: partsOrder.job.vehicle?.trim_color || null,
|
||||
V_MLDGCODE: partsOrder.job.vehicle?.v_mldgcode || null,
|
||||
V_ENGINE: partsOrder.job.vehicle?.v_engine || null,
|
||||
V_MILEAGE: partsOrder.job.vehicle?.v_mileage || null,
|
||||
V_OPTIONS: null,
|
||||
V_COLOR: partsOrder.job.vehicle?.v_color || null,
|
||||
V_TONE: Number(partsOrder.job.vehicle?.v_tone) || null,
|
||||
V_STAGE: null,
|
||||
PAINT_CD1: partsOrder.job.vehicle?.v_paint_codes?.paint_cd1 || "",
|
||||
PAINT_CD2: partsOrder.job.vehicle?.v_paint_codes?.paint_cd2 || "",
|
||||
PAINT_CD3: partsOrder.job.vehicle?.v_paint_codes?.paint_cd3 || "",
|
||||
V_MEMO: null,
|
||||
},
|
||||
];
|
||||
|
||||
await deleteEmsFileIfExists(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.VEH`),
|
||||
);
|
||||
|
||||
const dbf: DBFFile = await DBFFile.create(
|
||||
generateEmsOutFilePath(`${partsOrder.job.ciecaid}.VEH`),
|
||||
vehFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} VEH file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating VEH file:", errorTypeCheck(error));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default EmsPartsOrderGenerateVehFile;
|
||||
@@ -1,83 +0,0 @@
|
||||
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 EmsPartsOrderGenerateAd1File from "./ems-parts-order-generate-ad1";
|
||||
import EmsPartsOrderGenerateAd2File from "./ems-parts-order-generate-ad2";
|
||||
import EmsPartsOrderGenerateEnvFile from "./ems-parts-order-generate-env";
|
||||
import EmsPartsOrderGenerateLinFile from "./ems-parts-order-generate-lin";
|
||||
import EmsPartsOrderGeneratePfhFile from "./ems-parts-order-generate-pfh";
|
||||
import EmsPartsOrderGeneratePflFile from "./ems-parts-order-generate-pfl";
|
||||
import EmsPartsOrderGeneratePfmFile from "./ems-parts-order-generate-pfm";
|
||||
import EmsPartsOrderGeneratePfoFile from "./ems-parts-order-generate-pfo";
|
||||
import EmsPartsOrderGeneratePfpFile from "./ems-parts-order-generate-pfp";
|
||||
import EmsPartsOrderGeneratePftFile from "./ems-parts-order-generate-pft";
|
||||
import EmsPartsOrderGenerateStlFile from "./ems-parts-order-generate-stl";
|
||||
import EmsPartsOrderGenerateTtlFile from "./ems-parts-order-generate-ttl";
|
||||
import EmsPartsOrderGenerateVehFile from "./ems-parts-order-generate-veh";
|
||||
import { EmsPartsOrder } from "./ems-parts-order-interfaces";
|
||||
|
||||
const handleEMSPartsOrder = async (
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
): Promise<void> => {
|
||||
//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<void> => {
|
||||
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 EmsPartsOrderGenerateAd1File(partsOrder);
|
||||
await EmsPartsOrderGenerateAd2File(partsOrder);
|
||||
await EmsPartsOrderGenerateVehFile(partsOrder);
|
||||
await EmsPartsOrderGenerateLinFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePfhFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePflFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePfmFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePfoFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePfpFile(partsOrder);
|
||||
await EmsPartsOrderGeneratePftFile(partsOrder);
|
||||
await EmsPartsOrderGenerateStlFile(partsOrder);
|
||||
await EmsPartsOrderGenerateTtlFile(partsOrder);
|
||||
|
||||
await EmsPartsOrderGenerateEnvFile(partsOrder);
|
||||
|
||||
log.info(
|
||||
"EMS Parts Order files generated successfully for " +
|
||||
partsOrder.job.ciecaid,
|
||||
);
|
||||
} catch (error) {
|
||||
log.error("Error generating parts price change", errorTypeCheck(error));
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { handleEMSPartsOrder };
|
||||
@@ -1,322 +0,0 @@
|
||||
import { CiecaPfl } from "../decoder/decode-pfl.interface";
|
||||
import { DecodedPfmLine } from "../decoder/decode-pfm.interface";
|
||||
import { DecodedPfpLine } from "../decoder/decode-pfp.interface";
|
||||
import { DecodedStlLine } from "../decoder/decode-stl.interface";
|
||||
import { DecodedTtlLine } from "../decoder/decode-ttl.interface";
|
||||
|
||||
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;
|
||||
part_descj: boolean;
|
||||
}
|
||||
|
||||
// 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;
|
||||
priceChange: boolean;
|
||||
}
|
||||
|
||||
// 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;
|
||||
cieca_pfl: CiecaPfl;
|
||||
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<string, DecodedPfpLine>;
|
||||
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;
|
||||
materials: Record<string, DecodedPfmLine>;
|
||||
cieca_stl: {
|
||||
data: Array<DecodedStlLine>;
|
||||
};
|
||||
cieca_ttl: { data: DecodedTtlLine };
|
||||
}
|
||||
|
||||
// Main Parts Order export interface
|
||||
export interface EmsPartsOrder {
|
||||
parts_order_lines: PartsOrderLine[];
|
||||
job: Job;
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
import cors from "cors";
|
||||
import { app } from "electron";
|
||||
import log from "electron-log/main";
|
||||
import express from "express";
|
||||
import http from "http";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
import ImportJob from "../decoder/decoder";
|
||||
import folderScan from "../decoder/folder-scan";
|
||||
import { handleEMSPartsOrder } from "../ems-parts-order/ems-parts-order-handler";
|
||||
import { handleShopMetaDataFetch } from "../ipc/ipcMainHandler.user";
|
||||
import { handlePartsPriceChangeRequest } from "../ppc/ppc-handler";
|
||||
import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop";
|
||||
|
||||
export default class LocalServer {
|
||||
private readonly app: express.Application;
|
||||
private server: http.Server | null;
|
||||
private PORT = 1337;
|
||||
|
||||
constructor() {
|
||||
this.server = null;
|
||||
this.app = express();
|
||||
this.configureMiddleware();
|
||||
this.configureRoutes();
|
||||
}
|
||||
|
||||
private configureMiddleware(): void {
|
||||
const allowedOrigins = [
|
||||
"http://localhost",
|
||||
"https://localhost",
|
||||
"http://localhost:3000",
|
||||
"https://localhost:3000",
|
||||
"https://test.imex.online",
|
||||
"https://imex.online",
|
||||
"https://test.romeonline.io",
|
||||
"https://romeonline.io",
|
||||
"https://www.test.imex.online",
|
||||
"https://www.imex.online",
|
||||
"https://www.test.romeonline.io",
|
||||
"https://www.romeonline.io",
|
||||
];
|
||||
|
||||
this.app.use(
|
||||
cors({
|
||||
origin: (origin, callback) => {
|
||||
// Allow requests with no origin (like mobile apps, curl requests)
|
||||
if (!origin) return callback(null, true);
|
||||
|
||||
if (allowedOrigins.indexOf(origin) !== -1) {
|
||||
return callback(null, true);
|
||||
} else {
|
||||
return callback(null, false);
|
||||
}
|
||||
},
|
||||
credentials: true,
|
||||
}),
|
||||
);
|
||||
|
||||
// Parse JSON bodies
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded());
|
||||
|
||||
//Add logger Middleware
|
||||
this.app.use((req, res, next) => {
|
||||
const startTime = Date.now();
|
||||
const requestId = Math.random().toString(36).substring(2, 15);
|
||||
|
||||
// Log request details
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Request: ${req.method} ${req.url}`,
|
||||
);
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Headers: ${JSON.stringify(req.headers)}`,
|
||||
);
|
||||
|
||||
// Log request body if it exists
|
||||
if (req.body && Object.keys(req.body).length > 0) {
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Body: ${JSON.stringify(req.body)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Capture the original methods
|
||||
const originalSend = res.send;
|
||||
const originalJson = res.json;
|
||||
|
||||
// Override send method to log response
|
||||
res.send = function (body): express.Response {
|
||||
log.info(`[HTTP Server] [${requestId}] Response body: ${body}`);
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Response time: ${Date.now() - startTime}ms`,
|
||||
);
|
||||
return originalSend.call(this, body);
|
||||
};
|
||||
|
||||
// Override json method to log response
|
||||
res.json = function (body): express.Response {
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Response body: ${JSON.stringify(body)}`,
|
||||
);
|
||||
log.info(
|
||||
`[HTTP Server] [${requestId}] Response time: ${Date.now() - startTime}ms`,
|
||||
);
|
||||
return originalJson.call(this, body);
|
||||
};
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
private configureRoutes(): void {
|
||||
// Basic health check endpoint
|
||||
this.app.get("/health", (_req: express.Request, res: express.Response) => {
|
||||
res.status(200).json({ status: "ok" });
|
||||
});
|
||||
this.app.post("/ping", (_req, res) => {
|
||||
res.status(200).json({
|
||||
appVer: app.getVersion(),
|
||||
qbPath: app.getPath("userData"), //TODO: Resolve to actual QB file path.
|
||||
});
|
||||
});
|
||||
|
||||
this.app.post("/qb", handleQuickBookRequest);
|
||||
this.app.post("/scan", async (_req, res): Promise<void> => {
|
||||
log.debug("[HTTP Server] Scan request received");
|
||||
const files = await folderScan();
|
||||
res.status(200).json(files);
|
||||
return;
|
||||
});
|
||||
this.app.post("/ppc", handlePartsPriceChangeRequest);
|
||||
this.app.post("/oec", handleEMSPartsOrder);
|
||||
this.app.post(
|
||||
"/import",
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
log.debug("[HTTP Server] Import request received");
|
||||
const { filepath } = req.body;
|
||||
if (!filepath) {
|
||||
res.status(400).json({ error: "filepath is required" });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await ImportJob(filepath);
|
||||
res.status(200).json({ success: true });
|
||||
} catch (error) {
|
||||
log.error(
|
||||
"[HTTP Server] Error importing file",
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error importing file",
|
||||
...errorTypeCheck(error),
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
this.app.post(
|
||||
"/refresh",
|
||||
async (_req: express.Request, res: express.Response) => {
|
||||
log.debug("[HTTP Server] Refresh request received");
|
||||
try {
|
||||
await handleShopMetaDataFetch(true);
|
||||
res.status(200).json({ success: true });
|
||||
} catch (error) {
|
||||
log.error(
|
||||
"[HTTP Server] Error refreshing shop metadata",
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error importing file",
|
||||
...errorTypeCheck(error),
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Add more routes as needed
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
try {
|
||||
this.server = http.createServer(this.app);
|
||||
|
||||
this.server.on("error", (error: NodeJS.ErrnoException) => {
|
||||
if (error.code === "EADDRINUSE") {
|
||||
log.error(
|
||||
`[HTTP Server] Port ${this.PORT} is already in use. Please use a different port.`,
|
||||
);
|
||||
} else {
|
||||
log.error(`[HTTP Server] Server error: ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.server.listen(this.PORT, () => {
|
||||
log.info(
|
||||
`[HTTP Server] Local HTTP server running on port ${this.PORT}`,
|
||||
);
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
log.error("[HTTP Server] Error starting server", errorTypeCheck(error));
|
||||
}
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
log.info("[HTTP Server] Local HTTP server stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import log from "electron-log/main";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import path, { join } from "path";
|
||||
import imexAppIcon from "../../resources/icon.png?asset";
|
||||
import romeAppIcon from "../../resources/ro-icon.png?asset";
|
||||
|
||||
import {
|
||||
default as ErrorTypeCheck,
|
||||
@@ -22,11 +21,8 @@ import {
|
||||
} from "../util/errorTypeCheck";
|
||||
import ipcTypes from "../util/ipcTypes.json";
|
||||
import ImportJob from "./decoder/decoder";
|
||||
import LocalServer from "./http-server/http-server";
|
||||
import store from "./store/store";
|
||||
import { checkForAppUpdates } from "./util/checkForAppUpdates";
|
||||
import { getMainWindow } from "./util/toRenderer";
|
||||
import { GetAllEnvFiles } from "./watcher/watcher";
|
||||
|
||||
import { dumpMemoryStatsToFile } from "../util/memUsage";
|
||||
import {
|
||||
isKeepAliveAgentInstalled,
|
||||
setupKeepAliveAgent,
|
||||
@@ -35,11 +31,13 @@ import {
|
||||
isKeepAliveTaskInstalled,
|
||||
setupKeepAliveTask,
|
||||
} from "./setup-keep-alive-task";
|
||||
import store from "./store/store";
|
||||
import { checkForAppUpdates } from "./util/checkForAppUpdates";
|
||||
import ensureWindowOnScreen from "./util/ensureWindowOnScreen";
|
||||
import ongoingMemoryDump, { dumpMemoryStatsToFile } from "../util/memUsage";
|
||||
import { getMainWindow } from "./util/toRenderer";
|
||||
import { GetAllEnvFiles } from "./watcher/watcher";
|
||||
|
||||
const appIconToUse =
|
||||
import.meta.env.VITE_COMPANY === "IMEX" ? imexAppIcon : romeAppIcon;
|
||||
const appIconToUse = imexAppIcon;
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://ba41d22656999a8c1fd63bcb7df98650@o492140.ingest.us.sentry.io/4509074139447296",
|
||||
@@ -54,11 +52,10 @@ log.transports.console.format =
|
||||
"[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] [PID:{processId}] {text}";
|
||||
log.transports.file.maxSize = 50 * 1024 * 1024; // 50 MB
|
||||
const isMac: boolean = process.platform === "darwin";
|
||||
const protocol: string = "imexmedia";
|
||||
const protocol: string = "esdp";
|
||||
let isAppQuitting = false; //Needed on Mac as an override to allow us to fully quit the app.
|
||||
let isKeepAliveLaunch = false; // Track if launched via keep-alive
|
||||
// Initialize the server
|
||||
const localServer = new LocalServer();
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
if (!gotTheLock) {
|
||||
@@ -95,7 +92,7 @@ function createWindow(): void {
|
||||
icon: appIconToUse,
|
||||
}
|
||||
: {}),
|
||||
title: "Shop Partner",
|
||||
title: "EMS Uploader",
|
||||
webPreferences: {
|
||||
preload: join(__dirname, "../preload/index.js"),
|
||||
sandbox: false,
|
||||
@@ -425,13 +422,6 @@ function createWindow(): void {
|
||||
if (!isKeepAliveLaunch) {
|
||||
mainWindow.show(); // Show only if not a keep-alive launch
|
||||
}
|
||||
//Start the HTTP server.
|
||||
// Start the local HTTP server
|
||||
try {
|
||||
localServer.start();
|
||||
} catch (error) {
|
||||
log.error("Failed to start HTTP server:", errorTypeCheck(error));
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow.on("close", (event: Electron.Event) => {
|
||||
@@ -476,7 +466,7 @@ app.whenReady().then(async () => {
|
||||
log.debug("App is ready, initializing shortcuts and protocol handlers.");
|
||||
|
||||
if (platform.isWindows) {
|
||||
app.setAppUserModelId("Shop Partner");
|
||||
app.setAppUserModelId("esdp");
|
||||
}
|
||||
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
@@ -508,17 +498,8 @@ app.whenReady().then(async () => {
|
||||
|
||||
//Dynamically load ipcMain handlers once ready.
|
||||
try {
|
||||
const { initializeCronTasks } = await import("./ipc/ipcMainConfig");
|
||||
await import("./ipc/ipcMainConfig");
|
||||
log.debug("Successfully loaded ipcMainConfig");
|
||||
|
||||
try {
|
||||
await initializeCronTasks();
|
||||
log.info("Cron tasks initialized successfully");
|
||||
} catch (error) {
|
||||
log.warn("Non-fatal: Failed to initialize cron tasks", {
|
||||
...ErrorTypeCheck(error),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
log.error("Fatal: Failed to load ipcMainConfig", {
|
||||
...ErrorTypeCheck(error),
|
||||
@@ -599,7 +580,6 @@ app.whenReady().then(async () => {
|
||||
|
||||
//The update itself will run when the bodyshop record is queried to know what release channel to use.
|
||||
openMainWindow();
|
||||
ongoingMemoryDump();
|
||||
|
||||
app.on("activate", function () {
|
||||
openMainWindow();
|
||||
@@ -661,7 +641,6 @@ ipcMain.on(ipcTypes.toMain.updates.apply, () => {
|
||||
});
|
||||
|
||||
function preQuitMethods(): void {
|
||||
localServer.stop();
|
||||
const currentSetting = store.get("app.openOnStartup") as boolean;
|
||||
if (!import.meta.env.DEV) {
|
||||
app.setLoginItemSettings({
|
||||
|
||||
@@ -27,27 +27,6 @@ import {
|
||||
ipcMainHandleAuthStateChanged,
|
||||
ipMainHandleResetPassword,
|
||||
} from "./ipcMainHandler.user";
|
||||
import cron from "node-cron";
|
||||
import { PaintScaleConfig, PaintScaleType } from "../../util/types/paintScale";
|
||||
import { ppgInputHandler, ppgOutputHandler } from "./paintScaleHandlers/PPG";
|
||||
|
||||
const initializeCronTasks = async () => {
|
||||
try {
|
||||
// Fetch input and output configurations
|
||||
const inputConfigs = await SettingsPaintScaleInputConfigsGet();
|
||||
const outputConfigs = await SettingsPaintScaleOutputConfigsGet();
|
||||
|
||||
// Start input cron tasks
|
||||
await handlePaintScaleInputCron(inputConfigs);
|
||||
log.info("Initialized input cron tasks on app startup");
|
||||
|
||||
// Start output cron tasks
|
||||
await handlePaintScaleOutputCron(outputConfigs);
|
||||
log.info("Initialized output cron tasks on app startup");
|
||||
} catch (error) {
|
||||
log.error("Error initializing cron tasks on app startup:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Log all IPC messages and their payloads
|
||||
const logIpcMessages = (): void => {
|
||||
@@ -71,75 +50,6 @@ const logIpcMessages = (): void => {
|
||||
});
|
||||
};
|
||||
|
||||
// Input handler map
|
||||
const inputTypeHandlers: Partial<
|
||||
Record<PaintScaleType, (config: PaintScaleConfig) => Promise<void>>
|
||||
> = {
|
||||
[PaintScaleType.PPG]: ppgInputHandler,
|
||||
// Add other input type handlers as needed
|
||||
};
|
||||
|
||||
// Output handler map
|
||||
const outputTypeHandlers: Partial<
|
||||
Record<PaintScaleType, (config: PaintScaleConfig) => Promise<void>>
|
||||
> = {
|
||||
[PaintScaleType.PPG]: ppgOutputHandler,
|
||||
// Add other output type handlers as needed
|
||||
};
|
||||
|
||||
// Default handler for unsupported types
|
||||
const defaultHandler = async (config: PaintScaleConfig) => {
|
||||
log.debug(
|
||||
`No handler defined for type ${config.type} in config ${config.id}`,
|
||||
);
|
||||
};
|
||||
|
||||
// Input cron job management
|
||||
let inputCronTasks: { [id: string]: cron.ScheduledTask } = {};
|
||||
|
||||
const handlePaintScaleInputCron = async (configs: PaintScaleConfig[]) => {
|
||||
Object.values(inputCronTasks).forEach((task) => task.stop());
|
||||
inputCronTasks = {};
|
||||
|
||||
const validConfigs = configs.filter(
|
||||
(config) => config.path && config.path.trim() !== "",
|
||||
);
|
||||
|
||||
validConfigs.forEach((config) => {
|
||||
const cronExpression = `*/${config.pollingInterval} * * * *`;
|
||||
inputCronTasks[config.id] = cron.schedule(cronExpression, async () => {
|
||||
const handler = inputTypeHandlers[config.type] || defaultHandler;
|
||||
await handler(config);
|
||||
});
|
||||
log.info(
|
||||
`Started input cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// Output cron job management
|
||||
let outputCronTasks: { [id: string]: cron.ScheduledTask } = {};
|
||||
|
||||
const handlePaintScaleOutputCron = async (configs: PaintScaleConfig[]) => {
|
||||
Object.values(outputCronTasks).forEach((task) => task.stop());
|
||||
outputCronTasks = {};
|
||||
|
||||
const validConfigs = configs.filter(
|
||||
(config) => config.path && config.path.trim() !== "",
|
||||
);
|
||||
|
||||
validConfigs.forEach((config) => {
|
||||
const cronExpression = `*/${config.pollingInterval} * * * *`;
|
||||
outputCronTasks[config.id] = cron.schedule(cronExpression, async () => {
|
||||
const handler = outputTypeHandlers[config.type] || defaultHandler;
|
||||
await handler(config);
|
||||
});
|
||||
log.info(
|
||||
`Started output cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// Existing IPC handlers...
|
||||
|
||||
ipcMain.on(ipcTypes.toMain.test, () =>
|
||||
@@ -230,25 +140,6 @@ ipcMain.handle(
|
||||
SettingsPaintScaleOutputPathSet,
|
||||
);
|
||||
|
||||
// IPC handlers for updating paint scale cron
|
||||
ipcMain.on(
|
||||
ipcTypes.toMain.settings.paintScale.updateInputCron,
|
||||
(_event, configs: PaintScaleConfig[]) => {
|
||||
handlePaintScaleInputCron(configs).catch((error) => {
|
||||
log.error(`Error handling paint scale input cron for configs: ${error}`);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.on(
|
||||
ipcTypes.toMain.settings.paintScale.updateOutputCron,
|
||||
(_event, configs: PaintScaleConfig[]) => {
|
||||
handlePaintScaleOutputCron(configs).catch((error) => {
|
||||
log.error(`Error handling paint scale output cron for configs: ${error}`);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.handle(ipcTypes.toMain.user.getActiveShop, () => {
|
||||
return store.get("app.bodyshop.shopname");
|
||||
});
|
||||
@@ -273,6 +164,4 @@ ipcMain.on(ipcTypes.toMain.updates.download, () => {
|
||||
});
|
||||
});
|
||||
|
||||
export { initializeCronTasks };
|
||||
|
||||
logIpcMessages();
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
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<boolean> => {
|
||||
const records = [
|
||||
{
|
||||
EST_SYSTEM: "C",
|
||||
RO_ID: job.ro_number,
|
||||
ESTFILE_ID: 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(`${job.ciecaid}.ENV`));
|
||||
|
||||
const dbf = await DBFFile.create(
|
||||
generatePpcFilePath(`${job.ciecaid}.ENV`),
|
||||
envFieldLineDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} LIN file records added.`);
|
||||
return true;
|
||||
};
|
||||
|
||||
export default GenerateEnvFile;
|
||||
@@ -1,34 +0,0 @@
|
||||
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";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
|
||||
const GenerateLinFile = async (job: PpcJob): Promise<boolean> => {
|
||||
try {
|
||||
const records = job.joblines.map((line) => {
|
||||
return {
|
||||
//TODO: There are missing types here. May require server side updates, but we are missing things like LINE_NO, LINE_IND, etc.
|
||||
TRAN_CODE: "2",
|
||||
UNQ_SEQ: line.unq_seq,
|
||||
ACT_PRICE: line.act_price,
|
||||
};
|
||||
});
|
||||
|
||||
await deleteEmsFileIfExists(generatePpcFilePath(`${job.ciecaid}.LIN`));
|
||||
|
||||
const dbf = await DBFFile.create(
|
||||
generatePpcFilePath(`${job.ciecaid}.LIN`),
|
||||
linFieldDescriptors,
|
||||
);
|
||||
|
||||
await dbf.appendRecords(records);
|
||||
console.log(`${records.length} LIN file records added.`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error generating PPC LIN file", errorTypeCheck(error));
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export default GenerateLinFile;
|
||||
@@ -1,67 +0,0 @@
|
||||
import { UUID } from "crypto";
|
||||
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 GenerateEnvFile from "./ppc-generate-env";
|
||||
import GenerateLinFile from "./ppc-generate-lin";
|
||||
|
||||
const handlePartsPriceChangeRequest = async (
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
): Promise<void> => {
|
||||
//Route handler here only.
|
||||
|
||||
const job = req.body as PpcJob;
|
||||
try {
|
||||
await generatePartsPriceChange(job);
|
||||
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 generatePartsPriceChange = async (job: PpcJob): Promise<void> => {
|
||||
log.debug(" Generating parts price change");
|
||||
//Check to make sure that the PPC Output file path exists. If it doesn't, create it. If it's not set, abandon ship.
|
||||
|
||||
const ppcOutFilePath: string | null = store.get("settings.ppcFilePath");
|
||||
if (_.isEmpty(ppcOutFilePath) || ppcOutFilePath === null) {
|
||||
log.error("PPC file path is not set");
|
||||
throw new Error("PPC file path is not set");
|
||||
}
|
||||
try {
|
||||
createdDirectoryIfNotExist(ppcOutFilePath);
|
||||
|
||||
await GenerateLinFile(job);
|
||||
await GenerateEnvFile(job);
|
||||
} catch (error) {
|
||||
log.error("Error generating parts price change", errorTypeCheck(error));
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
export interface PpcJob {
|
||||
id: UUID;
|
||||
ciecaid: string;
|
||||
ro_number: string;
|
||||
joblines: {
|
||||
removed: boolean;
|
||||
act_price_before_ppc: number | null;
|
||||
id: string;
|
||||
act_price: number;
|
||||
unq_seq: string; //TODO: Might be a number.
|
||||
}[];
|
||||
bodyshop: {
|
||||
timezone: string;
|
||||
};
|
||||
}
|
||||
|
||||
export { handlePartsPriceChangeRequest };
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using Interop.QBFC16; // Ensure this matches your DLL version
|
||||
|
||||
public class QuickBooksConnector
|
||||
{
|
||||
public string ProcessQBXML(string qbxmlRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
QBSessionManager sessionManager = new QBSessionManager();
|
||||
sessionManager.OpenConnection("", "YourAppName");
|
||||
sessionManager.BeginSession("", ENOpenMode.omDontCare);
|
||||
|
||||
IMsgSetRequest requestMsgSet = sessionManager.CreateMsgSetRequest("US", 13, 0);
|
||||
requestMsgSet.AppendXML(qbxmlRequest);
|
||||
|
||||
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
|
||||
string qbxmlResponse = responseMsgSet.ToXMLString();
|
||||
|
||||
sessionManager.EndSession();
|
||||
sessionManager.CloseConnection();
|
||||
|
||||
return qbxmlResponse;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"Error: {ex.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
import log from "electron-log/main";
|
||||
|
||||
import { UUID } from "crypto";
|
||||
import { Request, Response } from "express";
|
||||
import _ from "lodash";
|
||||
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let Winax: any; // Declare Winax as any to avoid TypeScript errors on non-Windows platforms
|
||||
|
||||
if (process.platform === "win32") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
Winax = require("winax");
|
||||
}
|
||||
|
||||
export async function handleQuickBookRequest(
|
||||
req: Request,
|
||||
res: Response,
|
||||
): Promise<void> {
|
||||
if (process.platform !== "win32") {
|
||||
res.status(500).json({
|
||||
error: "QuickBooks Desktop integration is only available on Windows",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const QbFilePath: string = `C:\\Users\\PatrickFic\\Development\\FRODO COLLISION.QBW`;
|
||||
// ||
|
||||
// (store.get("settings.qbFilePath") as string) F
|
||||
|
||||
if (_.isEmpty(QbFilePath)) {
|
||||
res.status(400).json({ error: "Quickbooks file path not set" });
|
||||
return;
|
||||
}
|
||||
|
||||
const qbxmlRequestList = req.body as Array<{
|
||||
id: UUID;
|
||||
okStatusCodes: Array<string>;
|
||||
qbxml: string;
|
||||
}>;
|
||||
|
||||
const returnResponse: Array<{
|
||||
Id: UUID;
|
||||
Success: boolean;
|
||||
ErrorMessage: string;
|
||||
}> = [];
|
||||
|
||||
//Connect to the QuickBooks File
|
||||
let requestProcessor;
|
||||
try {
|
||||
requestProcessor = new Winax.Object("QBXMLRP2.RequestProcessor.2");
|
||||
requestProcessor.OpenConnection(QbFilePath, "ShopPartnerActualRequest");
|
||||
} catch (error) {
|
||||
log.error(
|
||||
"Error instnatiating QuickBooks Request Processor",
|
||||
QbFilePath,
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
res.status(500).json({ error: "Error connecting to QuickBooks" });
|
||||
return;
|
||||
}
|
||||
|
||||
const ticket = requestProcessor.BeginSession(QbFilePath, 2); //2 indicated qbFileOpenModeDoNotCare
|
||||
log.info("Quickbooks Ticket", ticket);
|
||||
for (const qbxmlRequest of qbxmlRequestList) {
|
||||
try {
|
||||
//TODO: Refactor to not create a new connection every time.
|
||||
const QuickBooksResponse = requestProcessor.ProcessRequest(
|
||||
ticket,
|
||||
qbxmlRequest.qbxml,
|
||||
);
|
||||
log.info("QuickBooks Raw Response: ", QuickBooksResponse);
|
||||
returnResponse.push({
|
||||
Id: qbxmlRequest.id,
|
||||
Success:
|
||||
QuickBooksResponse.StatusCode === "0" ||
|
||||
qbxmlRequest.okStatusCodes.includes(QuickBooksResponse.StatusCode),
|
||||
ErrorMessage: QuickBooksResponse,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(
|
||||
"Error running transaction",
|
||||
ticket,
|
||||
qbxmlRequest,
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
requestProcessor.EndSession(ticket);
|
||||
requestProcessor.CloseConnection();
|
||||
res.json(qbxmlRequestList);
|
||||
}
|
||||
|
||||
//This set of functions works.
|
||||
export function TestQB(): void {
|
||||
if (process.platform !== "win32") {
|
||||
log.warn("TestQB is only available on Windows");
|
||||
return;
|
||||
}
|
||||
let requestProcessor, ticket;
|
||||
try {
|
||||
requestProcessor = new Winax.Object("QBXMLRP.RequestProcessor.1");
|
||||
requestProcessor.OpenConnection("", "ShopPartnerOneoFf");
|
||||
|
||||
ticket = requestProcessor.BeginSession("", 2); //2 indicated qbFileOOpenModeDoNotCare
|
||||
|
||||
requestProcessor.ProcessRequest(
|
||||
ticket,
|
||||
`<?qbxml version="16.0"?>
|
||||
<QBXML>
|
||||
<QBXMLMsgsRq onError="stopOnError">
|
||||
<AccountQueryRq requestID="1"> </AccountQueryRq>
|
||||
</QBXMLMsgsRq>
|
||||
</QBXML>`,
|
||||
);
|
||||
} catch (error) {
|
||||
log.error(
|
||||
"Error instnatiating QuickBooks Request Processor",
|
||||
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
log.log("Ticket", ticket);
|
||||
requestProcessor.EndSession(ticket);
|
||||
requestProcessor.CloseConnection();
|
||||
return;
|
||||
}
|
||||
@@ -5,11 +5,7 @@ const store = new Store({
|
||||
settings: {
|
||||
runOnStartup: true,
|
||||
filepaths: [],
|
||||
ppcFilePath: null,
|
||||
emsOutFilePath: null,
|
||||
qbFilePath: "",
|
||||
runWatcherOnStartup: true,
|
||||
enableMemDebug: false,
|
||||
polling: {
|
||||
enabled: false,
|
||||
interval: 30000,
|
||||
@@ -25,9 +21,6 @@ const store = new Store({
|
||||
user: null,
|
||||
isTest: false,
|
||||
bodyshop: {},
|
||||
masterdata: {
|
||||
opcodes: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user