From 2c2652d07e3495c76faaa1ca49bbe0fa28212b9d Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 29 Apr 2025 13:10:18 -0400 Subject: [PATCH] feature/IO-3205-Paint-Scale-Integrations: Pre Change Checkpoint --- .env.imex | 4 +- .env.local | 4 +- .env.rome | 4 +- src/main/ipc/ipcMainConfig.ts | 322 ++++++++++++++-------------------- 4 files changed, 143 insertions(+), 191 deletions(-) diff --git a/.env.imex b/.env.imex index 1d6ab25..c18cc44 100644 --- a/.env.imex +++ b/.env.imex @@ -4,4 +4,6 @@ VITE_FIREBASE_CONFIG_TEST={ "apiKey":"AIzaSyBw7_GTy7GtQyfkIRPVrWHEGKfcqeyXw0c" VITE_GRAPHQL_ENDPOINT_TEST=https://db.test.bodyshop.app/v1/graphql VITE_COMPANY=IMEX VITE_FE_URL=https://imex.online -VITE_FE_URL_TEST=https://test.imex.online \ No newline at end of file +VITE_FE_URL_TEST=https://test.imex.online +VITE_API_URL="http://localhost:4000" +VITE_API_TEST_URL="http://api.test.imex.online" \ No newline at end of file diff --git a/.env.local b/.env.local index 5ca67ff..b364357 100644 --- a/.env.local +++ b/.env.local @@ -4,4 +4,6 @@ VITE_FIREBASE_CONFIG_TEST={ "apiKey":"AIzaSyBw7_GTy7GtQyfkIRPVrWHEGKfcqeyXw0c" VITE_GRAPHQL_ENDPOINT_TEST=https://db.test.bodyshop.app/v1/graphql VITE_COMPANY=IMEX VITE_FE_URL=https://imex.online -VITE_FE_URL_TEST=https://test.imex.online \ No newline at end of file +VITE_FE_URL_TEST=https://test.imex.online +VITE_API_URL="http://localhost:4000" +VITE_API_TEST_URL="http://api.test.imex.online" \ No newline at end of file diff --git a/.env.rome b/.env.rome index 4180038..749efc9 100644 --- a/.env.rome +++ b/.env.rome @@ -4,4 +4,6 @@ VITE_FIREBASE_CONFIG_TEST={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE" VITE_GRAPHQL_ENDPOINT_TEST=https://db.test.romeonline.io/v1/graphql VITE_COMPANY=ROME VITE_FE_URL=https://romeonline.io -VITE_FE_URL_TEST=https://test.romeonline.io \ No newline at end of file +VITE_FE_URL_TEST=https://test.romeonline.io +VITE_API_URL="http://localhost:4000" +VITE_API_TEST_URL="http://api.test.romeonline.io" \ No newline at end of file diff --git a/src/main/ipc/ipcMainConfig.ts b/src/main/ipc/ipcMainConfig.ts index 239fee8..1a28b93 100644 --- a/src/main/ipc/ipcMainConfig.ts +++ b/src/main/ipc/ipcMainConfig.ts @@ -119,7 +119,6 @@ const initializeCronTasks = async () => { } }; - // Log all IPC messages and their payloads const logIpcMessages = (): void => { Object.keys(ipcTypes.toMain).forEach((key) => { @@ -180,6 +179,7 @@ const inputTypeHandlers: Record< // Upload file to API const formData = new FormData(); + formData.append( "file", new Blob([await fs.readFile(filePath)]), @@ -190,17 +190,20 @@ const inputTypeHandlers: Record< (store.get("app.bodyshop") as BodyShop)?.shopname || "", ); - // TODO Clear up how to fetch API URL - const response = await axios.post( - "https://your-api-base-url/mixdata/upload", - formData, - { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "multipart/form-data", - }, + const baseURL = store.get("app.isTest") + ? import.meta.env.VITE_API_TEST_URL + : import.meta.env.VITE_API_URL; + + const finalUrl = `${baseURL}/mixdata/upload`; + + log.debug(`Uploading file to ${finalUrl}`); + + const response = await axios.post(finalUrl, formData, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", }, - ); + }); if (response.status === 200) { log.info(`Successful upload of ${filePath}`); @@ -234,69 +237,69 @@ const outputTypeHandlers: Record< // GraphQL query for jobs const query = ` - query PpgData($today: date!, $todayplus5: date!, $shopid: uuid!) { - bodyshops_by_pk(id: $shopid) { - imexshopid - shopname + query PpgData($today: date!, $todayplus5: date!, $shopid: uuid!) { + bodyshops_by_pk(id: $shopid) { + imexshopid + shopname + } + jobs(where: { + _and: [ + { shop_id: { _eq: $shopid } }, + { _or: [ + { status: { _eq: "Active" } }, + { scheduled_date: { _gte: $today, _lte: $todayplus5 } } + ] } + ] + }) { + ro_number + ownr_ln + ownr_fn + plate_no + v_vin + v_model_yr + v_make_desc + v_model_desc + vehicle { + v_paint_codes { + paint_cd1 + } } - jobs(where: { - _and: [ - { shop_id: { _eq: $shopid } }, - { _or: [ - { status: { _eq: "Active" } }, - { scheduled_date: { _gte: $today, _lte: $todayplus5 } } - ] } - ] - }) { - ro_number - ownr_ln - ownr_fn - plate_no - v_vin - v_model_yr - v_make_desc - v_model_desc - vehicle { - v_paint_codes { - paint_cd1 + larhrs_aggregate: estimate_lines_aggregate(where: { line_type: { _eq: "Paint" } }) { + aggregate { + sum { + mod_lb_hrs } } - larhrs_aggregate: estimate_lines_aggregate(where: { line_type: { _eq: "Paint" } }) { - aggregate { - sum { - mod_lb_hrs - } - } - } - ins_co_nm - est_ct_ln - est_ct_fn - job_totals { - rates { - mapa { - total { - amount - } - } - } - totals { - subtotal { + } + ins_co_nm + est_ct_ln + est_ct_fn + job_totals { + rates { + mapa { + total { amount } } } - rate_mapa - labhrs_aggregate: estimate_lines_aggregate(where: { line_type: { _eq: "Body" } }) { - aggregate { - sum { - mod_lb_hrs - } + totals { + subtotal { + amount } } - rate_lab } + rate_mapa + labhrs_aggregate: estimate_lines_aggregate(where: { line_type: { _eq: "Body" } }) { + aggregate { + sum { + mod_lb_hrs + } + } + } + rate_lab } - `; + } + `; const variables = { today: new Date().toISOString().split("T")[0], @@ -311,137 +314,80 @@ const outputTypeHandlers: Record< variables, )) as GraphQLResponse; - // Generate XML - const doc = create({ version: "1.0" }) - .ele("PPG") - .ele("Header") - .ele("Protocol") - .ele("Message") - .txt("PaintShopInterface") - .up() - .ele("Name") - .txt("PPG") - .up() - .ele("Version") - .txt("1.5.0") - .up() - .up() - .ele("Transaction") - .ele("TransactionID") - .txt("") - .up() - .ele("TransactionDate") - .txt(new Date().toISOString().replace("T", " ").substring(0, 19)) - .up() - .up() - .ele("Product") - .ele("Name") - .txt("ImEX Online") - .up() - .ele("Version") - .txt("") - .up() - .up() - .up() - .ele("DataInterface") - .ele("ROData") - .ele("ShopInfo") - .ele("ShopID") - .txt(response.bodyshops_by_pk?.imexshopid || "") - .up() - .ele("ShopName") - .txt(response.bodyshops_by_pk?.shopname || "") - .up() - .up() - .ele("RepairOrders") - .ele("ROCount") - .txt((response.jobs?.length || 0).toString()) - .up() - .up() - .up() - .up(); + // Build JSON structure + const jsonData = { + PPG: { + Header: { + Protocol: { + Message: "PaintShopInterface", + Name: "PPG", + Version: "1.5.0", + }, + Transaction: { + TransactionID: "", + TransactionDate: new Date() + .toISOString() + .replace("T", " ") + .substring(0, 19), + }, + Product: { + Name: "ImEX Online", + Version: "", + }, + }, + DataInterface: { + ROData: { + ShopInfo: { + ShopID: response.bodyshops_by_pk?.imexshopid || "", + ShopName: response.bodyshops_by_pk?.shopname || "", + }, + RepairOrders: { + ROCount: (response.jobs?.length || 0).toString(), + RO: + response.jobs?.map((job) => ({ + RONumber: job.ro_number || "", + ROStatus: "Open", + Customer: `${job.ownr_ln || ""}, ${job.ownr_fn || ""}`, + ROPainterNotes: "", + LicensePlateNum: job.plate_no || "", + VIN: job.v_vin || "", + ModelYear: job.v_model_yr || "", + MakeDesc: job.v_make_desc || "", + ModelName: job.v_model_desc || "", + OEMColorCode: job.vehicle?.v_paint_codes?.paint_cd1 || "", + RefinishLaborHours: + job.larhrs_aggregate?.aggregate?.sum?.mod_lb_hrs || 0, + InsuranceCompanyName: job.ins_co_nm || "", + EstimatorName: `${job.est_ct_ln || ""}, ${job.est_ct_fn || ""}`, + PaintMaterialsRevenue: ( + (job.job_totals?.rates?.mapa?.total?.amount || 0) / 100 + ).toFixed(2), + PaintMaterialsRate: job.rate_mapa || 0, + BodyHours: + job.labhrs_aggregate?.aggregate?.sum?.mod_lb_hrs || 0, + BodyLaborRate: job.rate_lab || 0, + TotalCostOfRepairs: ( + (job.job_totals?.totals?.subtotal?.amount || 0) / 100 + ).toFixed(2), + })) || [], + }, + }, + }, + }, + }; - const repairOrders = (doc.root() as any).findOne("RepairOrders"); - (response as GraphQLResponse).jobs?.forEach((job: any) => { - repairOrders - .ele("RO") - .ele("RONumber") - .txt(job.ro_number || "") - .up() - .ele("ROStatus") - .txt("Open") - .up() - .ele("Customer") - .txt(`${job.ownr_ln || ""}, ${job.ownr_fn || ""}`) - .up() - .ele("ROPainterNotes") - .txt("") - .up() - .ele("LicensePlateNum") - .txt(job.plate_no || "") - .up() - .ele("VIN") - .txt(job.v_vin || "") - .up() - .ele("ModelYear") - .txt(job.v_model_yr || "") - .up() - .ele("MakeDesc") - .txt(job.v_make_desc || "") - .up() - .ele("ModelName") - .txt(job.v_model_desc || "") - .up() - .ele("OEMColorCode") - .txt(job.vehicle?.v_paint_codes?.paint_cd1 || "") - .up() - .ele("RefinishLaborHours") - .txt(job.larhrs_aggregate?.aggregate?.sum?.mod_lb_hrs || 0) - .up() - .ele("InsuranceCompanyName") - .txt(job.ins_co_nm || "") - .up() - .ele("EstimatorName") - .txt(`${job.est_ct_ln || ""}, ${job.est_ct_fn || ""}`) - .up() - .ele("PaintMaterialsRevenue") - .txt( - ((job.job_totals?.rates?.mapa?.total?.amount || 0) / 100).toFixed( - 2, - ), - ) - .up() - .ele("PaintMaterialsRate") - .txt(job.rate_mapa || 0) - .up() - .ele("BodyHours") - .txt(job.labhrs_aggregate?.aggregate?.sum?.mod_lb_hrs || 0) - .up() - .ele("BodyLaborRate") - .txt(job.rate_lab || 0) - .up() - .ele("TotalCostOfRepairs") - .txt( - ((job.job_totals?.totals?.subtotal?.amount || 0) / 100).toFixed(2), - ) - .up(); - }); + // Convert JSON to XML + const doc = create({ version: "1.0" }, jsonData); + const xmlString = doc.end({ prettyPrint: true }); // Save XML to file - const xmlString = doc.end({ prettyPrint: true }); - const timestamp = new Date() - .toISOString() - .replace(/[-:]/g, "") - .replace("T", "") - .substring(0, 14); - const outputPath = path.join(config.path!, `PPGPaint_${timestamp}.xml`); + const outputPath = path.join(config.path!, `PPGPaint.xml`); await fs.writeFile(outputPath, xmlString); log.info(`Saved PPG output XML to ${outputPath}`); } catch (error) { log.error(`Error generating PPG output for config ${config.id}:`, error); } - }, - // Add other output type handlers as needed + }, // Add other output type handlers as needed }; // Default handler for unsupported types @@ -469,7 +415,7 @@ const handlePaintScaleInputCron = async (configs: PaintScaleConfig[]) => { await handler(config); }); log.info( - `Started input cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}s`, + `Started input cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`, ); }); }; @@ -492,7 +438,7 @@ const handlePaintScaleOutputCron = async (configs: PaintScaleConfig[]) => { await handler(config); }); log.info( - `Started output cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}s`, + `Started output cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`, ); }); };