From cab6df75fe690c6b184ba094a3169fe18322eab2 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 26 Oct 2020 15:24:03 -0700 Subject: [PATCH 01/10] Set package version/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f01042f..91a8d53 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "ImEX RPS", "author": "ImEX Systems Inc. ", "description": "ImEX RPS", - "version": "1.0.4", + "version": "1.0.5", "main": "electron/main.js", "homepage": "./", "dependencies": { From 41f0682fd51b3e3203ad63f4bb145f820686b7f0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 10:21:55 -0700 Subject: [PATCH 02/10] Added better auto-update handling. RPS-17 --- Xdev-app-update.yml | 3 + electron/main.js | 116 +++++++++------- package.json | 2 +- src/App/App.styles.scss | 10 ++ .../price-diff-pc-formatter.styles.scss | 9 -- .../update-manager.organism.jsx | 124 ++++++++++++++++++ src/components/pages/routes/routes.page.jsx | 3 + src/ipc.types.js | 7 + src/ipc/ipc-renderer-handler.js | 15 +++ src/redux/application/application.actions.js | 4 + src/redux/application/application.reducer.js | 3 + .../application/application.selectors.js | 4 + src/redux/application/application.types.js | 2 + src/redux/user/user.sagas.js | 1 + 14 files changed, 249 insertions(+), 54 deletions(-) create mode 100644 Xdev-app-update.yml create mode 100644 src/components/organisms/update-manager/update-manager.organism.jsx diff --git a/Xdev-app-update.yml b/Xdev-app-update.yml new file mode 100644 index 0000000..79b4862 --- /dev/null +++ b/Xdev-app-update.yml @@ -0,0 +1,3 @@ + provider: s3 + bucket: rps-updater + region: ca-central-1 \ No newline at end of file diff --git a/electron/main.js b/electron/main.js index 35ee665..5184e6a 100644 --- a/electron/main.js +++ b/electron/main.js @@ -19,6 +19,8 @@ const Nucleus = require("nucleus-nodejs"); require("./ipc-main-handler"); require("./analytics"); +autoUpdater.autoDownload = false; + autoUpdater.logger = log; autoUpdater.logger.transports.file.level = "info"; log.info("App starting...", app.getVersion()); @@ -70,10 +72,7 @@ var menu = Menu.buildFromTemplate([ { label: `Check for Updates (currently ${app.getVersion()})`, click() { - autoUpdater.checkForUpdatesAndNotify({ - title: "ImEX RPS Update Downloaded", - body: "Restart ImEX RPS to install.", - }); + checkForUpdates(); }, }, { @@ -168,7 +167,6 @@ function createWindow() { } mainWindow.maximize(); - autoUpdater.checkForUpdatesAndNotify(); globalShortcut.register("CommandOrControl+Shift+I", () => { mainWindow.webContents.toggleDevTools(); @@ -242,46 +240,22 @@ function createTray() { return appIcon; } -autoUpdater.on("checking-for-update", () => { - log.log("Checking for update..."); -}); -autoUpdater.on("update-available", (ev, info) => { - log.log("Update available."); -}); -autoUpdater.on("update-not-available", (ev, info) => { - log.log("Update not available."); -}); -autoUpdater.on("error", (ev, err) => { - log.log("Error in auto-updater."); -}); -autoUpdater.on("download-progress", (ev, progressObj) => { - log.log("Download progress..."); -}); -// autoUpdater.on("update-downloaded", (ev, info) => { -// console.log("Update downloaded; will install in 5 seconds"); +// autoUpdater.on("checking-for-update", () => { +// log.log("Checking for update..."); // }); -autoUpdater.on("update-downloaded", (ev, info) => { - Nucleus.track("UPDATE_DOWNLOADED", info); - if (process.env.NODE_ENV === "production") { - dialog.showMessageBox( - { - type: "info", - title: "Found Updates", - message: "Found updates, do you want update now?", - buttons: ["Sure", "No"], - }, - (buttonIndex) => { - if (buttonIndex === 0) { - const isSilent = true; - const isForceRunAfter = true; - autoUpdater.quitAndInstall(isSilent, isForceRunAfter); - } else { - logger.warn("Error"); - } - } - ); - } -}); +// autoUpdater.on("update-available", (ev, info) => { +// log.log("Update available."); +// }); +// autoUpdater.on("update-not-available", (ev, info) => { +// log.log("Update not available."); +// }); +// autoUpdater.on("error", (ev, err) => { +// log.log("Error in auto-updater."); +// }); + +// // autoUpdater.on("update-downloaded", (ev, info) => { +// // console.log("Update downloaded; will install in 5 seconds"); +// // }); function openNoticeWindow() { if (noticeWindow) { @@ -301,3 +275,57 @@ function openNoticeWindow() { noticeWindow = null; }); } + +ipcMain.on(ipcTypes.app.toMain.checkForUpdates, (event, args) => { + checkForUpdates(); +}); + +ipcMain.on(ipcTypes.app.toMain.downloadUpdates, (event, args) => { + autoUpdater.downloadUpdate(); +}); + +ipcMain.on(ipcTypes.app.toMain.installUpdates, (event, args) => { + const isSilent = true; + const isForceRunAfter = true; + autoUpdater.quitAndInstall(isSilent, isForceRunAfter); +}); + +autoUpdater.on("download-progress", (ev) => { + mainWindow.webContents.send(ipcTypes.app.toRenderer.downloadProgress, ev); +}); + +autoUpdater.on("update-downloaded", (ev, info) => { + Nucleus.track("UPDATE_DOWNLOADED", info); + // if (process.env.NODE_ENV === "production") { + + dialog.showMessageBox( + { + type: "info", + title: "ImeX RPS Update Manager", + message: `ImEX RPS is ready to update to Version ${ev.version}. It is highly recommended that you update immediately. Would you like to update now? RPS will automatically restart.`, + buttons: ["Yes", "No"], + }, + (buttonIndex) => { + if (buttonIndex === 0) { + const isSilent = true; + const isForceRunAfter = true; + autoUpdater.quitAndInstall(isSilent, isForceRunAfter); + } else { + logger.error("Error"); + } + } + ); +}); +async function checkForUpdates() { + try { + log.info("Checking for updates."); + const result = await autoUpdater.checkForUpdates(); + const { updateInfo } = result; + mainWindow.webContents.send( + ipcTypes.app.toRenderer.updateAvailable, + updateInfo + ); + } catch (error) { + log.error("Error while checking for update", error); + } +} diff --git a/package.json b/package.json index 91a8d53..739f6de 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "ImEX RPS", "author": "ImEX Systems Inc. ", "description": "ImEX RPS", - "version": "1.0.5", + "version": "1.0.3", "main": "electron/main.js", "homepage": "./", "dependencies": { diff --git a/src/App/App.styles.scss b/src/App/App.styles.scss index 4d1288d..dc2299e 100644 --- a/src/App/App.styles.scss +++ b/src/App/App.styles.scss @@ -78,3 +78,13 @@ body { .ant-tabs-content { height: 100%; } + +.blink_me { + animation: blinker 1s linear infinite; +} + +@keyframes blinker { + 50% { + opacity: 0; + } +} diff --git a/src/components/atoms/price-diff-pc-formatter/price-diff-pc-formatter.styles.scss b/src/components/atoms/price-diff-pc-formatter/price-diff-pc-formatter.styles.scss index bd4b9f5..e69de29 100644 --- a/src/components/atoms/price-diff-pc-formatter/price-diff-pc-formatter.styles.scss +++ b/src/components/atoms/price-diff-pc-formatter/price-diff-pc-formatter.styles.scss @@ -1,9 +0,0 @@ -.blink_me { - animation: blinker 1s linear infinite; -} - -@keyframes blinker { - 50% { - opacity: 0; - } -} diff --git a/src/components/organisms/update-manager/update-manager.organism.jsx b/src/components/organisms/update-manager/update-manager.organism.jsx new file mode 100644 index 0000000..a8c468c --- /dev/null +++ b/src/components/organisms/update-manager/update-manager.organism.jsx @@ -0,0 +1,124 @@ +import { AlertFilled } from "@ant-design/icons"; +import { Button, Layout, Progress } from "antd"; +import React from "react"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import ipcTypes from "../../../ipc.types"; +import { + selectUpdateAvailable, + selectUpdateProgress, +} from "../../../redux/application/application.selectors"; +const { ipcRenderer } = window; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + updateAvailable: selectUpdateAvailable, + updateProgress: selectUpdateProgress, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); + +export function UpdateManagerOrganism({ updateAvailable, updateProgress }) { + if (!updateAvailable) return null; + return ( + + {updateAvailable && !updateProgress && ( +
+
+ + {`An update to ImEX RPS is available. (Version ${updateAvailable.version})`} +
+ +
+ )} + {updateAvailable && updateProgress && ( +
+ + {updateProgress.percent === 100 ? ( +
+ {`Updated downloaded.`} + +
+ ) : ( + {`Downloading update at ${formatBytes( + updateProgress.bytesPerSecond + )})`} + )} +
+ )} +
+ ); +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(UpdateManagerOrganism); + +// download Info +// { +// // bytesPerSecond: 6633258; +// // delta: 2479242; +// // percent: 100; +// // total: 95651575; +// // transferred: 95651575; +// } + +function formatBytes(bytes) { + var marker = 1024; // Change to 1000 if required + var decimal = 1; // Change as required + var kiloBytes = marker; // One Kilobyte is 1024 bytes + var megaBytes = marker * marker; // One MB is 1024 KB + var gigaBytes = marker * marker * marker; // One GB is 1024 MB + //var teraBytes = marker * marker * marker * marker; // One TB is 1024 GB + + // return bytes if less than a KB + if (bytes < kiloBytes) return bytes + " Bytes/sec"; + // return KB if less than a MB + else if (bytes < megaBytes) + return (bytes / kiloBytes).toFixed(decimal) + " KB/sec"; + // return MB if less than a GB + else if (bytes < gigaBytes) + return (bytes / megaBytes).toFixed(decimal) + " MB/sec"; + // return GB if less than a TB + else return (bytes / gigaBytes).toFixed(decimal) + " GB/sec"; +} diff --git a/src/components/pages/routes/routes.page.jsx b/src/components/pages/routes/routes.page.jsx index 1e0b001..b9299bb 100644 --- a/src/components/pages/routes/routes.page.jsx +++ b/src/components/pages/routes/routes.page.jsx @@ -6,6 +6,7 @@ import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../../redux/user/user.selectors"; import ErrorResultAtom from "../../atoms/error-result/error-result.atom"; import SiderMenuOrganism from "../../organisms/sider-menu/sider-menu.organism"; +import UpdateManagerOrganism from "../../organisms/update-manager/update-manager.organism"; import JobsPage from "../jobs/jobs.page"; import ReportingPage from "../reporting/reporting.page"; import ScanPage from "../scan/scan.page"; @@ -39,6 +40,8 @@ export function RoutesPage({ bodyshop }) { + + ); diff --git a/src/ipc.types.js b/src/ipc.types.js index 794d547..fda1b6b 100644 --- a/src/ipc.types.js +++ b/src/ipc.types.js @@ -9,6 +9,13 @@ exports.default = { setAcceptableInsCoNm: "setAcceptableInsCoNm", setUserName: "setUserName", track: "analytics_track", + checkForUpdates: "app_checkForUpdates", + downloadUpdates: "app_downloadUpdates", + installUpdates: "app_installupdates", + }, + toRenderer: { + updateAvailable: "app_updateAvailable", + downloadProgress: "app_downloadProgress", }, }, store: { diff --git a/src/ipc/ipc-renderer-handler.js b/src/ipc/ipc-renderer-handler.js index b14dbdf..84100e6 100644 --- a/src/ipc/ipc-renderer-handler.js +++ b/src/ipc/ipc-renderer-handler.js @@ -1,6 +1,8 @@ import ipcTypes from "../ipc.types"; import { setSettings, + setUpdateAvailable, + setUpdateProgress, setWatchedPaths, setWatcherStatus, } from "../redux/application/application.actions"; @@ -65,3 +67,16 @@ ipcRenderer.on( store.dispatch(setScanEstimateList(listOfEstimates)); } ); + +ipcRenderer.on( + ipcTypes.default.app.toRenderer.updateAvailable, + async (event, updateInfo) => { + store.dispatch(setUpdateAvailable(updateInfo)); + } +); +ipcRenderer.on( + ipcTypes.default.app.toRenderer.downloadProgress, + async (event, progress) => { + store.dispatch(setUpdateProgress(progress)); + } +); diff --git a/src/redux/application/application.actions.js b/src/redux/application/application.actions.js index 060e812..71c4a0c 100644 --- a/src/redux/application/application.actions.js +++ b/src/redux/application/application.actions.js @@ -48,3 +48,7 @@ export const setUpdateAvailable = (available) => ({ type: ApplicationActionTypes.SET_UPDATE_AVAILABLE, payload: available, }); +export const setUpdateProgress = (progress) => ({ + type: ApplicationActionTypes.SET_UPDATE_PROGRESS, + payload: progress, +}); diff --git a/src/redux/application/application.reducer.js b/src/redux/application/application.reducer.js index d19df1a..c4896cc 100644 --- a/src/redux/application/application.reducer.js +++ b/src/redux/application/application.reducer.js @@ -8,6 +8,7 @@ const INITIAL_STATE = { selectedJobTargetPc: 0, settings: {}, updateAvailable: false, + updateProgress: null, }; const { ipcRenderer } = window; @@ -63,6 +64,8 @@ const applicationReducer = (state = INITIAL_STATE, action) => { return { ...state, settings: { ...state.settings, ...action.payload } }; case ApplicationActionTypes.SET_UPDATE_AVAILABLE: return { ...state, updateAvailable: action.payload }; + case ApplicationActionTypes.SET_UPDATE_PROGRESS: + return { ...state, updateProgress: action.payload }; default: return state; } diff --git a/src/redux/application/application.selectors.js b/src/redux/application/application.selectors.js index f474fbd..aad8463 100644 --- a/src/redux/application/application.selectors.js +++ b/src/redux/application/application.selectors.js @@ -36,3 +36,7 @@ export const selectUpdateAvailable = createSelector( [selectApplication], (application) => application.updateAvailable ); +export const selectUpdateProgress = createSelector( + [selectApplication], + (application) => application.updateProgress +); diff --git a/src/redux/application/application.types.js b/src/redux/application/application.types.js index 25f7ddf..3e24870 100644 --- a/src/redux/application/application.types.js +++ b/src/redux/application/application.types.js @@ -9,5 +9,7 @@ const ApplicationActionTypes = { SET_SELECTED_JOB_TARGET_PC_SUCCESS: "SET_SELECTED_JOB_TARGET_PC_SUCCESS", SET_SETTINGS: "SET_SETTINGS", SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE", + SET_UPDATE_PROGRESS: "SET_UPDATE_PROGRESS", + }; export default ApplicationActionTypes; diff --git a/src/redux/user/user.sagas.js b/src/redux/user/user.sagas.js index 57fdcfa..c298c2a 100644 --- a/src/redux/user/user.sagas.js +++ b/src/redux/user/user.sagas.js @@ -128,6 +128,7 @@ export function* signInSuccessSaga({ payload }) { LogRocket.identify(payload.email, { email: payload.email, }); + ipcRenderer.send(ipcTypes.default.app.toMain.checkForUpdates); ipcRenderer.send(ipcTypes.default.app.toMain.track, { event: "SIGN_IN_SUCCESS", From 0eb5d5dd47cca7ea5d3448c7916f353df614d97a Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 10:37:31 -0700 Subject: [PATCH 03/10] Resolved issue where EMS files were missed if they didnt have the expected suffix. RPS-20 --- electron/decoder/decoder.js | 327 +++++++++++++++++--------------- electron/file-scan/file-scan.js | 7 +- package.json | 2 +- 3 files changed, 184 insertions(+), 152 deletions(-) diff --git a/electron/decoder/decoder.js b/electron/decoder/decoder.js index e49e828..dd79602 100644 --- a/electron/decoder/decoder.js +++ b/electron/decoder/decoder.js @@ -80,163 +80,190 @@ async function DecodeEstimate(filePath, includeFilePathInReturnJob = false) { } async function DecodeAd1File(extensionlessFilePath) { - let dbf = await DBFFile.open(`${extensionlessFilePath}A.AD1`); - let records = await dbf.readRecords(1); - return _.pick(records[0], [ - // "INS_CO_ID", - "INS_CO_NM", - // "INS_ADDR1", - // "INS_ADDR2", - // "INS_CITY", - // "INS_ST", - // "INS_ZIP", - // "INS_CTRY", + let dbf; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}A.AD1`); + } catch (error) { + log.error("Error opening AD1 File.", error); + dbf = await DBFFile.open(`${extensionlessFilePath}.AD1`); + dbf && log.log("Found AD1 file using regular CIECA Id."); + } finally { + if (!dbf) return {}; + let records = await dbf.readRecords(1); + return _.pick(records[0], [ + // "INS_CO_ID", + "INS_CO_NM", + // "INS_ADDR1", + // "INS_ADDR2", + // "INS_CITY", + // "INS_ST", + // "INS_ZIP", + // "INS_CTRY", - // "INS_EA", - // "POLICY_NO", - // "DED_AMT", - // "DED_STATUS", - // "ASGN_NO", - //"ASGN_DATE", - // "ASGN_TYPE", - "CLM_NO", - // "CLM_OFC_ID", - // "CLM_OFC_NM", - // "CLM_ADDR1", - // "CLM_ADDR2", - // "CLM_CITY", - // "CLM_ST", - // "CLM_ZIP", - // "CLM_CTRY", - // "CLM_PH1", - // "CLM_PH1X", - // "CLM_PH2", - // "CLM_PH2X", - // "CLM_FAX", - // "CLM_FAXX", - // "CLM_CT_LN", - // "CLM_CT_FN", - // "CLM_TITLE", - // "CLM_CT_PH", - // "CLM_CT_PHX", - // "CLM_EA", - // "PAYEE_NMS", - // "PAY_TYPE", - // "PAY_DATE", - // "PAY_CHKNM", - // "PAY_AMT", - // "AGT_CO_ID", - // "AGT_CO_NM", - // "AGT_ADDR1", - // "AGT_ADDR2", - // "AGT_CITY", - // "AGT_ST", - // "AGT_ZIP", - // "AGT_CTRY", - // "AGT_PH1", - // "AGT_PH1X", - // "AGT_PH2", - // "AGT_PH2X", - // "AGT_FAX", - // "AGT_FAXX", - // "AGT_CT_LN", - // "AGT_CT_FN", - // "AGT_CT_PH", - // "AGT_CT_PHX", - // "AGT_EA", - // "AGT_LIC_NO", - "LOSS_DATE", - // "LOSS_TYPE", - // "LOSS_DESC", - // "THEFT_IND", - // "CAT_NO", - // "TLOS_IND", - // "CUST_PR", - // "INSD_LN", - // "INSD_FN", - // "INSD_TITLE", - // "INSD_CO_NM", - // "INSD_ADDR1", - // "INSD_ADDR2", - // "INSD_CITY", - // "INSD_ST", - // "INSD_ZIP", - // "INSD_CTRY", - // "INSD_PH1", - // "INSD_PH1X", - // "INSD_PH2", - // "INSD_PH2X", - // "INSD_FAX", - // "INSD_FAXX", - // "INSD_EA", - "OWNR_LN", - "OWNR_FN", - // "OWNR_TITLE", - // "OWNR_CO_NM", - // "OWNR_ADDR1", - // "OWNR_ADDR2", - // "OWNR_CITY", - // "OWNR_ST", - // "OWNR_ZIP", - // "OWNR_CTRY", - // "OWNR_PH1", - // "OWNR_PH1X", - // "OWNR_PH2", - // "OWNR_PH2X", - // "OWNR_FAX", - // "OWNR_FAXX", - // "OWNR_EA", - // "INS_PH1", - // "INS_PH1X", - // "INS_PH2", - // "INS_PH2X", - // "INS_FAX", - // "INS_FAXX", - // "INS_CT_LN", - // "INS_CT_FN", - // "INS_TITLE", - // "INS_CT_PH", - // "INS_CT_PHX", - // "LOSS_CAT", - ]); + // "INS_EA", + // "POLICY_NO", + // "DED_AMT", + // "DED_STATUS", + // "ASGN_NO", + //"ASGN_DATE", + // "ASGN_TYPE", + "CLM_NO", + // "CLM_OFC_ID", + // "CLM_OFC_NM", + // "CLM_ADDR1", + // "CLM_ADDR2", + // "CLM_CITY", + // "CLM_ST", + // "CLM_ZIP", + // "CLM_CTRY", + // "CLM_PH1", + // "CLM_PH1X", + // "CLM_PH2", + // "CLM_PH2X", + // "CLM_FAX", + // "CLM_FAXX", + // "CLM_CT_LN", + // "CLM_CT_FN", + // "CLM_TITLE", + // "CLM_CT_PH", + // "CLM_CT_PHX", + // "CLM_EA", + // "PAYEE_NMS", + // "PAY_TYPE", + // "PAY_DATE", + // "PAY_CHKNM", + // "PAY_AMT", + // "AGT_CO_ID", + // "AGT_CO_NM", + // "AGT_ADDR1", + // "AGT_ADDR2", + // "AGT_CITY", + // "AGT_ST", + // "AGT_ZIP", + // "AGT_CTRY", + // "AGT_PH1", + // "AGT_PH1X", + // "AGT_PH2", + // "AGT_PH2X", + // "AGT_FAX", + // "AGT_FAXX", + // "AGT_CT_LN", + // "AGT_CT_FN", + // "AGT_CT_PH", + // "AGT_CT_PHX", + // "AGT_EA", + // "AGT_LIC_NO", + "LOSS_DATE", + // "LOSS_TYPE", + // "LOSS_DESC", + // "THEFT_IND", + // "CAT_NO", + // "TLOS_IND", + // "CUST_PR", + // "INSD_LN", + // "INSD_FN", + // "INSD_TITLE", + // "INSD_CO_NM", + // "INSD_ADDR1", + // "INSD_ADDR2", + // "INSD_CITY", + // "INSD_ST", + // "INSD_ZIP", + // "INSD_CTRY", + // "INSD_PH1", + // "INSD_PH1X", + // "INSD_PH2", + // "INSD_PH2X", + // "INSD_FAX", + // "INSD_FAXX", + // "INSD_EA", + "OWNR_LN", + "OWNR_FN", + // "OWNR_TITLE", + // "OWNR_CO_NM", + // "OWNR_ADDR1", + // "OWNR_ADDR2", + // "OWNR_CITY", + // "OWNR_ST", + // "OWNR_ZIP", + // "OWNR_CTRY", + // "OWNR_PH1", + // "OWNR_PH1X", + // "OWNR_PH2", + // "OWNR_PH2X", + // "OWNR_FAX", + // "OWNR_FAXX", + // "OWNR_EA", + // "INS_PH1", + // "INS_PH1X", + // "INS_PH2", + // "INS_PH2X", + // "INS_FAX", + // "INS_FAXX", + // "INS_CT_LN", + // "INS_CT_FN", + // "INS_TITLE", + // "INS_CT_PH", + // "INS_CT_PHX", + // "LOSS_CAT", + ]); + } } async function DecodeAd2File(extensionlessFilePath) { - let dbf = await DBFFile.open(`${extensionlessFilePath}B.AD2`); - let records = await dbf.readRecords(1); - return _.pick(records[0], ["CLMT_LN", "CLMT_FN"]); + let dbf; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}B.AD2`); + } catch (error) { + log.error("Error opening AD2 File.", error); + dbf = await DBFFile.open(`${extensionlessFilePath}.AD2`); + dbf && log.log("Found AD2 file using regular CIECA Id."); + } finally { + if (!dbf) return {}; + let records = await dbf.readRecords(1); + return _.pick(records[0], ["CLMT_LN", "CLMT_FN"]); + } } async function DecodeVehFile(extensionlessFilePath) { - let dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`); - let records = await dbf.readRecords(1); - return _.pick(records[0], [ - // "IMPACT_1", - // "IMPACT_2", - // "DB_V_CODE", - // "PLATE_NO", - // "PLATE_ST", - "V_VIN", - // "V_COND", - // "V_PROD_DT", - "V_MODEL_YR", - // "V_MAKECODE", - "V_MAKEDESC", - "V_MODEL", - "V_TYPE", - "V_MILEAGE", - // "V_BSTYLE", - // "V_TRIMCODE", - // "TRIM_COLOR", - // "V_MLDGCODE", - // "V_ENGINE", - // "V_COLOR", - // "V_TONE", - // "V_STAGE", - // "PAINT_CD1", - // "PAINT_CD2", - // "PAINT_CD3", - ]); + let dbf; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`); + } catch (error) { + log.error("Error opening VEH File.", error); + dbf = await DBFFile.open(`${extensionlessFilePath}.VEH`); + dbf && log.log("Found VEH file using regular CIECA Id."); + } finally { + if (!dbf) return {}; + let records = await dbf.readRecords(1); + return _.pick(records[0], [ + // "IMPACT_1", + // "IMPACT_2", + // "DB_V_CODE", + // "PLATE_NO", + // "PLATE_ST", + "V_VIN", + // "V_COND", + // "V_PROD_DT", + "V_MODEL_YR", + // "V_MAKECODE", + "V_MAKEDESC", + "V_MODEL", + "V_TYPE", + "V_MILEAGE", + // "V_BSTYLE", + // "V_TRIMCODE", + // "TRIM_COLOR", + // "V_MLDGCODE", + // "V_ENGINE", + // "V_COLOR", + // "V_TONE", + // "V_STAGE", + // "PAINT_CD1", + // "PAINT_CD2", + // "PAINT_CD3", + ]); + } } async function DecodeTtlFile(extensionlessFilePath) { let dbf = await DBFFile.open(`${extensionlessFilePath}.TTL`); diff --git a/electron/file-scan/file-scan.js b/electron/file-scan/file-scan.js index 1b17158..c7328e5 100644 --- a/electron/file-scan/file-scan.js +++ b/electron/file-scan/file-scan.js @@ -16,6 +16,11 @@ async function GetListOfEstimates() { const FilteredListOfSummarizedEstimates = ListOfSummarizedEstimates.filter( (j) => !j.ERROR ); + + log.log( + "Number of estimates filtered on file scan due to error: ", + ListOfSummarizedEstimates.length - FilteredListOfSummarizedEstimates.length + ); return FilteredListOfSummarizedEstimates; } @@ -71,4 +76,4 @@ async function DeleteAllEms() { } exports.GetListOfEstimates = GetListOfEstimates; -exports.DeleteAllEms = DeleteAllEms \ No newline at end of file +exports.DeleteAllEms = DeleteAllEms; diff --git a/package.json b/package.json index 739f6de..91a8d53 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "ImEX RPS", "author": "ImEX Systems Inc. ", "description": "ImEX RPS", - "version": "1.0.3", + "version": "1.0.5", "main": "electron/main.js", "homepage": "./", "dependencies": { From 4852e325eedd1e0b15e844c6a1c190b90ce3ad48 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 10:43:11 -0700 Subject: [PATCH 04/10] Fixed typo in vehicle grouping change. RPS-22 --- src/components/molecules/job-group/job-group.molecule.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/job-group/job-group.molecule.jsx b/src/components/molecules/job-group/job-group.molecule.jsx index 53965bf..db1d277 100644 --- a/src/components/molecules/job-group/job-group.molecule.jsx +++ b/src/components/molecules/job-group/job-group.molecule.jsx @@ -35,7 +35,7 @@ export function JobGroupMolecule({ bodyshop, jobId, group, job }) { }); if (!result.errors) { - message.success("Close date updated."); + message.success("Vehicle group updated."); } else { message.error("Error updating job."); } From 08ae22eef474d448df4f70642ff54dfdd93e85d0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 10:50:53 -0700 Subject: [PATCH 05/10] Fixed deleting of jobs and added more detail to error result atoms. RPS-23 --- src/components/atoms/delete-job/delete-job.atom.jsx | 2 ++ .../atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx | 8 +++++++- .../jobs-detail-description.molecule.jsx | 8 +++++++- .../jobs-lines-table/jobs-lines-table.molecule.jsx | 9 +++++++++ .../jobs-targets-stats/jobs-targets-stats.molecule.jsx | 10 ++++++++-- .../organisms/jobs-detail/jobs-detail.organism.jsx | 6 +++--- 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/components/atoms/delete-job/delete-job.atom.jsx b/src/components/atoms/delete-job/delete-job.atom.jsx index 9648b41..e410b60 100644 --- a/src/components/atoms/delete-job/delete-job.atom.jsx +++ b/src/components/atoms/delete-job/delete-job.atom.jsx @@ -25,6 +25,8 @@ export function DeleteJobAtom({ setSelectedJobId, jobId }) { }); const result = await deleteJob({ variables: { jobId: jobId }, + refetchQueries: ["QUERY_ALL_JOBS_PAGINATED"], + awaitRefetchQueries: true, }); if (result.errors) { diff --git a/src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx b/src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx index 3085905..f4ad1b3 100644 --- a/src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx +++ b/src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx @@ -37,7 +37,13 @@ export default function JobPartsGraphAtom({ }, [job, price]); if (loading) return ; - if (!job) return ; + if (!job) + return ( + + ); return (
; - if (!job) return ; + if (!job) + return ( + + ); return (
diff --git a/src/components/molecules/jobs-lines-table/jobs-lines-table.molecule.jsx b/src/components/molecules/jobs-lines-table/jobs-lines-table.molecule.jsx index 6aabfe4..ef26d9a 100644 --- a/src/components/molecules/jobs-lines-table/jobs-lines-table.molecule.jsx +++ b/src/components/molecules/jobs-lines-table/jobs-lines-table.molecule.jsx @@ -4,6 +4,7 @@ import React, { useState } from "react"; import ipcTypes from "../../../ipc.types"; import { alphaSort } from "../../../util/sorters"; import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom"; +import ErrorResultAtom from "../../atoms/error-result/error-result.atom"; import IgnoreJobLine from "../../atoms/ignore-job-line/ignore-job-line.atom"; import partTypeConverterAtom from "../../atoms/part-type-converter/part-type-converter.atom"; import PriceDiffPcFormatterAtom from "../../atoms/price-diff-pc-formatter/price-diff-pc-formatter.atom"; @@ -13,6 +14,14 @@ export default function JobLinesTableMolecule({ loading, job }) { const [searchText, setSearchText] = useState(""); const [filters, setFilters] = useState({ ignore: ["false"] }); + if (!job) { + return ( + + ); + } const { joblines } = job; const columns = [ { diff --git a/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx b/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx index 1db0ff3..08e92bb 100644 --- a/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx +++ b/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx @@ -5,7 +5,7 @@ import { createStructuredSelector } from "reselect"; import { selectSelectedJobTargetPc } from "../../../redux/application/application.selectors"; import { CalculateJobRpsDollars, - CalculateJobRpsPc + CalculateJobRpsPc, } from "../../../util/CalculateJobRps"; import ErrorResultAtom from "../../atoms/error-result/error-result.atom"; @@ -38,7 +38,13 @@ export function JobsTargetsStatsMolecule({ ); if (loading) return ; - if (!job) return ; + if (!job) + return ( + + ); return (
{ - if (data) + if (data && data.jobs_by_pk) setSelectedJobTargetPc({ - group: data.jobs_by_pk.group, - v_age: data.jobs_by_pk.v_age, + group: data.jobs_by_pk && data.jobs_by_pk.group, + v_age: data.jobs_by_pk && data.jobs_by_pk.v_age, }); }, [data, setSelectedJobTargetPc]); From 7218dcd3ff441a27e4165d795a95fa40b895019f Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 10:53:18 -0700 Subject: [PATCH 06/10] Changed file scan default sort order and order of columns. RPS-24 --- .../scan-estimate-list.molecule.jsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/molecules/scan-estimate-list/scan-estimate-list.molecule.jsx b/src/components/molecules/scan-estimate-list/scan-estimate-list.molecule.jsx index 0a36b27..bc6462c 100644 --- a/src/components/molecules/scan-estimate-list/scan-estimate-list.molecule.jsx +++ b/src/components/molecules/scan-estimate-list/scan-estimate-list.molecule.jsx @@ -35,18 +35,20 @@ export function ScanEstimateListMolecule({ scanLoading, estimates }) { key: "ins_co_nm", sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm), }, + { + title: "Last Name", + dataIndex: "ownr_ln", + key: "ownr_ln", + defaultSortOrder: "ascend", + sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + }, { title: "First Name", dataIndex: "ownr_fn", key: "ownr_fn", sorter: (a, b) => alphaSort(a.ownr_fn, b.ownr_fn), }, - { - title: "Last Name", - dataIndex: "ownr_ln", - key: "ownr_ln", - sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), - }, + { title: "Vehicle", dataIndex: "vehicle", From 854ff7ea0a1011eefc1fff2b63fc42d36fb17510 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 11:04:24 -0700 Subject: [PATCH 07/10] Added visual indicators for jobs missing a close date. RPS-30 --- .../close-date-display.molecule.jsx | 10 +++++++++- .../jobs-list-item/jobs-list-item.molecule.jsx | 11 ++++++++++- src/graphql/jobs.queries.js | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/close-date-display/close-date-display.molecule.jsx b/src/components/molecules/close-date-display/close-date-display.molecule.jsx index a771319..7618087 100644 --- a/src/components/molecules/close-date-display/close-date-display.molecule.jsx +++ b/src/components/molecules/close-date-display/close-date-display.molecule.jsx @@ -1,3 +1,4 @@ +import { WarningOutlined } from "@ant-design/icons"; import { useMutation } from "@apollo/client"; import { DatePicker, message, Spin } from "antd"; import moment from "moment"; @@ -43,7 +44,14 @@ export default function CloseDateDisplayMolecule({ jobId, close_date }) { return (
setEditMode(true)}> - {value && value.isValid() ? value.format(DateFormat) : "No date set"} + {value && value.isValid() ? ( + value.format(DateFormat) + ) : ( +
+ No date set. + +
+ )}
); } diff --git a/src/components/molecules/jobs-list-item/jobs-list-item.molecule.jsx b/src/components/molecules/jobs-list-item/jobs-list-item.molecule.jsx index 8dfdbc9..6af24c8 100644 --- a/src/components/molecules/jobs-list-item/jobs-list-item.molecule.jsx +++ b/src/components/molecules/jobs-list-item/jobs-list-item.molecule.jsx @@ -6,6 +6,7 @@ import { setSelectedJobId } from "../../../redux/application/application.actions import { selectSelectedJobId } from "../../../redux/application/application.selectors"; import TimeAgoFormatter from "../../atoms/time-ago-formatter/time-ago-formatter.atom"; import "./jobs-list-item.styles.scss"; +import { WarningOutlined } from "@ant-design/icons"; const mapStateToProps = createStructuredSelector({ selectedJobId: selectSelectedJobId, @@ -41,7 +42,15 @@ export function JobsListItemMolecule({ justifyContent: "space-between", }} > - {item.clm_no || "No Claim Number"} + + {item.clm_no || "No Claim Number"} + {!item.close_date && ( + + )} + {item.updated_at} diff --git a/src/graphql/jobs.queries.js b/src/graphql/jobs.queries.js index 5175feb..03e7064 100644 --- a/src/graphql/jobs.queries.js +++ b/src/graphql/jobs.queries.js @@ -26,6 +26,7 @@ export const QUERY_ALL_JOBS_PAGINATED = gql` id ins_co_nm clm_no + close_date updated_at } jobs_aggregate { From bd072b4c0d9de320ca8aeb999d5fe34a03ff5e10 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 11:06:20 -0700 Subject: [PATCH 08/10] Added tire exclusions for joblines on import RPS-25 --- electron/decoder/decoder.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electron/decoder/decoder.js b/electron/decoder/decoder.js index dd79602..85a8485 100644 --- a/electron/decoder/decoder.js +++ b/electron/decoder/decoder.js @@ -383,7 +383,8 @@ async function DecodeLinFile(extensionlessFilePath) { !jobline.part_type || jobline.db_ref.startsWith("900") || jobline.line_desc.toLowerCase().startsWith("urethane") || - jobline.line_desc.toLowerCase().startsWith("wheel") || + jobline.line_desc.toLowerCase().includes("wheel") || + jobline.line_desc.toLowerCase().includes("tire") || jobline.line_desc.toLowerCase().startsWith("hazardous") || jobline.line_desc.toLowerCase().startsWith("detail") || jobline.line_desc.toLowerCase().startsWith("clean") || From 016a3ea6fee23b64fa9b22d410aaa73e3fad5060 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Oct 2020 11:32:33 -0700 Subject: [PATCH 09/10] Fixed wrong field used in target RPS $ calculation. RPS-27 --- electron/main.js | 6 ++++++ .../jobs-targets-stats/jobs-targets-stats.molecule.jsx | 2 +- src/ipc.types.js | 1 + src/ipc/ipc-renderer-handler.js | 9 +++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/electron/main.js b/electron/main.js index 5184e6a..d9da800 100644 --- a/electron/main.js +++ b/electron/main.js @@ -51,6 +51,12 @@ var menu = Menu.buildFromTemplate([ mainWindow.webContents.session.clearStorageData(); }, }, + { + label: "Sign Out", + click() { + mainWindow.webContents.send(ipcTypes.app.toRenderer.signOut); + }, + }, { label: "Exit", click() { diff --git a/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx b/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx index 08e92bb..9c2fb17 100644 --- a/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx +++ b/src/components/molecules/jobs-targets-stats/jobs-targets-stats.molecule.jsx @@ -77,7 +77,7 @@ export function JobsTargetsStatsMolecule({ { store.dispatch(setUpdateProgress(progress)); } ); + +ipcRenderer.on( + ipcTypes.default.app.toRenderer.signOut, + async (event, progress) => { + store.dispatch(signOutStart()); + } +); From 8e4cc5756c072ecf15fac5d8dbb51b65c82b20aa Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Wed, 28 Oct 2020 06:32:37 -0700 Subject: [PATCH 10/10] Updated format on reporting screen. RPS-26 --- .../reporting-jobs-list.molecule.jsx | 21 ++++++ .../reporting-totals-stats.molecule.jsx | 73 +++++++++++-------- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/components/molecules/reporting-jobs-list/reporting-jobs-list.molecule.jsx b/src/components/molecules/reporting-jobs-list/reporting-jobs-list.molecule.jsx index db64077..439c5f5 100644 --- a/src/components/molecules/reporting-jobs-list/reporting-jobs-list.molecule.jsx +++ b/src/components/molecules/reporting-jobs-list/reporting-jobs-list.molecule.jsx @@ -9,6 +9,7 @@ import { setSelectedJobId } from "../../../redux/application/application.actions import { selectReportData, selectReportLoading, + selectScorecard, } from "../../../redux/reporting/reporting.selectors"; const { ipcRenderer } = window; @@ -16,12 +17,14 @@ const { ipcRenderer } = window; const mapStateToProps = createStructuredSelector({ reportingLoading: selectReportLoading, reportData: selectReportData, + scoreCard: selectScorecard, }); const mapDispatchToProps = (dispatch) => ({ setSelectedJobId: (id) => dispatch(setSelectedJobId(id)), }); export function ReportingJobsListMolecule({ + scoreCard, reportingLoading, reportData, setSelectedJobId, @@ -147,6 +150,24 @@ export function ReportingJobsListMolecule({ scroll={{ x: true, }} + summary={() => ( + + + + + + + + {scoreCard && scoreCard.allJobsSumDbPrice.toFormat()} + + + {" "} + {scoreCard && scoreCard.allJobsSumActPrice.toFormat()} + + + + + )} />
); diff --git a/src/components/molecules/reporting-totals-stats/reporting-totals-stats.molecule.jsx b/src/components/molecules/reporting-totals-stats/reporting-totals-stats.molecule.jsx index 98e09f2..066fe24 100644 --- a/src/components/molecules/reporting-totals-stats/reporting-totals-stats.molecule.jsx +++ b/src/components/molecules/reporting-totals-stats/reporting-totals-stats.molecule.jsx @@ -35,38 +35,47 @@ export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard }) { marginBottom: "1rem", }} > - - - - - +
+ + +
+
+ + + +
); }