Auditing refinements.
This commit is contained in:
@@ -28,7 +28,7 @@ ipcMain.on(ipcTypes.default.audit.toMain.browseForFile, async (event, { sheetNam
|
||||
} else if (foundHeaderRow && !foundTotalRow && line[0] && line[0] !== "Grand Total") {
|
||||
//Add it to the array
|
||||
const row = {
|
||||
clm_no: line[0],
|
||||
clm_no: line[0].startsWith("00") ? line[0].slice(2) : line[0],
|
||||
close_date: line[1],
|
||||
v_model_yr: line[3],
|
||||
v_makedesc: line[4],
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
const path = require("path");
|
||||
const {
|
||||
app,
|
||||
BrowserWindow,
|
||||
Tray,
|
||||
Menu,
|
||||
ipcMain,
|
||||
dialog,
|
||||
shell,
|
||||
globalShortcut,
|
||||
} = require("electron");
|
||||
const { app, BrowserWindow, Tray, Menu, ipcMain, dialog, shell, globalShortcut } = require("electron");
|
||||
const isDev = require("electron-is-dev");
|
||||
const { default: ipcTypes } = require("../src/ipc.types.commonjs");
|
||||
const { store } = require("./electron-store");
|
||||
@@ -26,8 +17,8 @@ Sentry.init({
|
||||
ignoreErrors: [
|
||||
"SimpleURLLoaderWrapper",
|
||||
"Cannot read properties of null (reading 'webContents')",
|
||||
"EBUSY: resource busy or locked",
|
||||
],
|
||||
"EBUSY: resource busy or locked"
|
||||
]
|
||||
});
|
||||
autoUpdater.autoDownload = true;
|
||||
|
||||
@@ -52,28 +43,28 @@ var menu = Menu.buildFromTemplate([
|
||||
click() {
|
||||
app.exit();
|
||||
app.relaunch();
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Clear Settings",
|
||||
click() {
|
||||
store.reset("filePaths");
|
||||
mainWindow.webContents.session.clearStorageData();
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Sign Out",
|
||||
click() {
|
||||
mainWindow.webContents.send(ipcTypes.app.toRenderer.signOut);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Exit",
|
||||
click() {
|
||||
app.quit();
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
]
|
||||
// Other code removed for brevity
|
||||
},
|
||||
{
|
||||
@@ -83,13 +74,13 @@ var menu = Menu.buildFromTemplate([
|
||||
label: "Rescue",
|
||||
click() {
|
||||
shell.openExternal("http://imexrescue.com");
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: `Check for Updates (currently ${app.getVersion()})`,
|
||||
click() {
|
||||
checkForUpdates();
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: `Show Release Notes`,
|
||||
@@ -98,28 +89,28 @@ var menu = Menu.buildFromTemplate([
|
||||
ipcTypes.app.toRenderer.setReleaseNotes,
|
||||
require("./changelog.json")[app.getVersion()]
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Open Config File",
|
||||
click() {
|
||||
shell.openPath(store.path);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Open Log File",
|
||||
click() {
|
||||
shell.openPath(path.join(app.getPath("appData"), "ImeX RPS\\logs"));
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Third Party Notices",
|
||||
click() {
|
||||
openNoticeWindow();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
let mainWindow;
|
||||
@@ -142,8 +133,8 @@ function createWindow() {
|
||||
webSecurity: true,
|
||||
worldSafeExecuteJavaScript: true,
|
||||
contextIsolation: true,
|
||||
preload: path.join(__dirname, "preload.js"), // use a preload script
|
||||
},
|
||||
preload: path.join(__dirname, "preload.js") // use a preload script
|
||||
}
|
||||
});
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
@@ -162,11 +153,7 @@ function createWindow() {
|
||||
|
||||
// and load the index.html of the app.
|
||||
// win.loadFile("index.html");
|
||||
mainWindow.loadURL(
|
||||
isDev
|
||||
? "http://localhost:3000"
|
||||
: `file://${path.join(__dirname, "/../build/index.html")}`
|
||||
);
|
||||
mainWindow.loadURL(isDev ? "http://localhost:3000" : `file://${path.join(__dirname, "/../build/index.html")}`);
|
||||
|
||||
// mainWindow.on("close", function (event) {
|
||||
// event.preventDefault();
|
||||
@@ -256,15 +243,15 @@ function createTray() {
|
||||
label: "Show",
|
||||
click: function () {
|
||||
mainWindow.show();
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Exit",
|
||||
click: function () {
|
||||
app.isQuiting = true;
|
||||
app.quit();
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
appIcon.on("double-click", function (event) {
|
||||
@@ -297,7 +284,7 @@ function openNoticeWindow() {
|
||||
noticeWindow = new BrowserWindow({
|
||||
height: 600,
|
||||
width: 800,
|
||||
title: "ImEX RPS - Third Party Notices",
|
||||
title: "ImEX RPS - Third Party Notices"
|
||||
});
|
||||
|
||||
noticeWindow.loadURL("file://" + __dirname + "/licenses.txt");
|
||||
@@ -333,7 +320,7 @@ autoUpdater.on("update-downloaded", (ev, info) => {
|
||||
// if (process.env.NODE_ENV === "production") {
|
||||
mainWindow.webContents.send(ipcTypes.app.toRenderer.downloadProgress, {
|
||||
...ev,
|
||||
percent: 100,
|
||||
percent: 100
|
||||
});
|
||||
|
||||
dialog
|
||||
@@ -341,7 +328,7 @@ autoUpdater.on("update-downloaded", (ev, info) => {
|
||||
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"],
|
||||
buttons: ["Yes", "No"]
|
||||
})
|
||||
.then(({ response }) => {
|
||||
if (response === 0) {
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -42,6 +42,7 @@
|
||||
"react-infinite-scroller": "^1.2.6",
|
||||
"react-redux": "^9.1.1",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-to-print": "^2.15.1",
|
||||
"recharts": "^2.12.5",
|
||||
"redux": "^5.0.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
@@ -13473,6 +13474,15 @@
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-to-print": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.15.1.tgz",
|
||||
"integrity": "sha512-1foogIFbCpzAVxydkhBiDfMiFYhIMphiagDOfcG4X/EcQ+fBPqJ0rby9Wv/emzY1YLkIQy/rEgOrWQT+rBKhjw==",
|
||||
"peerDependencies": {
|
||||
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"react-infinite-scroller": "^1.2.6",
|
||||
"react-redux": "^9.1.1",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-to-print": "^2.15.1",
|
||||
"recharts": "^2.12.5",
|
||||
"redux": "^5.0.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
|
||||
@@ -93,3 +93,17 @@ body {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
height: unset;
|
||||
page-break-before: always;
|
||||
}
|
||||
@page {
|
||||
// size: landscape;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,71 @@
|
||||
import { Card, Col, Divider, Space, Table, Tooltip } from "antd";
|
||||
import Dinero from "dinero.js";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { setSelectedJobTargetPc } from "../../../redux/application/application.actions";
|
||||
import { selectAuditData } from "../../../redux/reporting/reporting.selectors";
|
||||
import { setSelectedJobId, setSelectedJobTargetPc } from "../../../redux/application/application.actions";
|
||||
import { selectAuditData, selectAuditLoading } from "../../../redux/reporting/reporting.selectors";
|
||||
import { DateFormat } from "../../../util/constants";
|
||||
import dayjs from "../../../util/day";
|
||||
import Dinero from "dinero.js";
|
||||
import { alphaSort, dateSort } from "../../../util/sorters";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectAuditData: selectAuditData
|
||||
selectAuditData: selectAuditData,
|
||||
auditLoading: selectAuditLoading
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
setSelectedJobId: (id) => dispatch(setSelectedJobId(id)),
|
||||
setSelectedJobTargetPc: (job) => dispatch(setSelectedJobTargetPc(job))
|
||||
});
|
||||
|
||||
export function AuditResultsOrganism({ selectAuditData }) {
|
||||
export function AuditResultsOrganism({ auditLoading, setSelectedJobId, selectAuditData }) {
|
||||
const missingColumns = [
|
||||
{
|
||||
key: "clm_no",
|
||||
width: "20%",
|
||||
width: "12%",
|
||||
title: "Claim No.",
|
||||
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||
dataIndex: "clm_no"
|
||||
dataIndex: "clm_no",
|
||||
render: (text, record) => (
|
||||
<Link onClick={() => setSelectedJobId(record.id)} to={"/"}>
|
||||
<Space>{text}</Space>
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "close_date",
|
||||
width: "20%",
|
||||
width: "12%",
|
||||
title: "[RPS] R4P",
|
||||
dataIndex: "close_date",
|
||||
defaultSortOrder: "ascend",
|
||||
sorter: (a, b) => dateSort(a.close_date, b.close_date),
|
||||
render: (text, record) => dayjs(record.close_date).format(DateFormat)
|
||||
},
|
||||
{ key: "v_model_yr", width: "20%", title: "Model Year", dataIndex: "v_model_yr" },
|
||||
{ key: "v_model_yr", width: "12%", title: "Model Year", dataIndex: "v_model_yr" },
|
||||
{ key: "v_makedesc", width: "20%", title: "Make", dataIndex: "v_makedesc" },
|
||||
{ key: "v_model", width: "20%", title: "Model", dataIndex: "v_model" }
|
||||
{ key: "v_model", width: "20%", title: "Model", dataIndex: "v_model" },
|
||||
{
|
||||
key: "expected_rps",
|
||||
width: "12%",
|
||||
title: "Expected RPS ",
|
||||
dataIndex: ["audit", "expectedRpsDollars"],
|
||||
render: (text, record) =>
|
||||
record.expectedRpsDollars
|
||||
? record?.expectedRpsDollars?.toFormat()
|
||||
: Dinero({ amount: Math.round((record?.expected_rps_dollars || 0) * 100) }).toFormat()
|
||||
},
|
||||
{
|
||||
key: "actual_rps",
|
||||
width: "12%",
|
||||
title: " Actual RPS ",
|
||||
dataIndex: ["audit", "jobRpsDollars"],
|
||||
render: (text, record) =>
|
||||
record?.jobRpsDollars
|
||||
? record?.jobRpsDollars.toFormat()
|
||||
: Dinero({ amount: Math.round((record?.actual_rps_dollars || 0) * 100) }).toFormat()
|
||||
}
|
||||
];
|
||||
|
||||
const mismatchColumns = [
|
||||
@@ -71,7 +99,7 @@ export function AuditResultsOrganism({ selectAuditData }) {
|
||||
{
|
||||
key: "expected_rps",
|
||||
width: "12%",
|
||||
title: "Expected RPS",
|
||||
title: "Expected RPS (RPS/Audit)",
|
||||
dataIndex: ["audit", "expectedRpsDollars"],
|
||||
render: (text, record) => (
|
||||
<Space split={<Divider type="vertical" />}>
|
||||
@@ -85,7 +113,7 @@ export function AuditResultsOrganism({ selectAuditData }) {
|
||||
{
|
||||
key: "actual_rps",
|
||||
width: "12%",
|
||||
title: " Actual RPS",
|
||||
title: " Actual RPS (RPS/Audit)",
|
||||
dataIndex: ["audit", "jobRpsDollars"],
|
||||
render: (text, record) => (
|
||||
<Space split={<Divider type="vertical" />}>
|
||||
@@ -101,22 +129,46 @@ export function AuditResultsOrganism({ selectAuditData }) {
|
||||
<>
|
||||
<Col span={24}>
|
||||
<Card title="Jobs in RPS, not found in MPI Audit">
|
||||
<Table columns={missingColumns} dataSource={selectAuditData?.missingFromRps} rowKey="clm_no" />
|
||||
<Table
|
||||
loading={auditLoading}
|
||||
columns={missingColumns}
|
||||
pagination={false}
|
||||
dataSource={selectAuditData?.missingFromRps}
|
||||
rowKey="clm_no"
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title="Jobs in MPI Audit, not in RPS">
|
||||
<Table columns={missingColumns} dataSource={selectAuditData?.missingFromAudit} rowKey="clm_no" />
|
||||
<Table
|
||||
loading={auditLoading}
|
||||
columns={missingColumns}
|
||||
pagination={false}
|
||||
dataSource={selectAuditData?.missingFromAudit}
|
||||
rowKey="clm_no"
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title="Mismatch - Expected Savings">
|
||||
<Table columns={mismatchColumns} dataSource={selectAuditData?.expectedMismatch} rowKey="clm_no" />
|
||||
<Table
|
||||
loading={auditLoading}
|
||||
columns={mismatchColumns}
|
||||
pagination={false}
|
||||
dataSource={selectAuditData?.expectedMismatch}
|
||||
rowKey="clm_no"
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title="Mismatch - Actual Savings">
|
||||
<Table columns={mismatchColumns} dataSource={selectAuditData?.actualMismatch} rowKey="clm_no" />
|
||||
<Table
|
||||
loading={auditLoading}
|
||||
columns={mismatchColumns}
|
||||
pagination={false}
|
||||
dataSource={selectAuditData?.actualMismatch}
|
||||
rowKey="clm_no"
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Alert, Button, Card, Col, DatePicker, Form, Input, Row } from "antd";
|
||||
import React from "react";
|
||||
import { PrinterFilled } from "@ant-design/icons";
|
||||
import { Alert, Button, Card, Col, DatePicker, Form, Input, Row, Space } from "antd";
|
||||
import React, { useRef } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { useReactToPrint } from "react-to-print";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { queryReportingData } from "../../../redux/reporting/reporting.actions";
|
||||
@@ -29,17 +31,25 @@ export function AuditPage({ auditError, queryReportingData }) {
|
||||
});
|
||||
ipcRenderer.send(ipcTypes.audit.toMain.browseForFile, { sheetName });
|
||||
};
|
||||
const componentRef = useRef();
|
||||
const handlePrint = useReactToPrint({
|
||||
content: () => componentRef.current,
|
||||
bodyClass: "audit-container-print"
|
||||
});
|
||||
|
||||
window.ref = componentRef.current;
|
||||
if (auditError) console.log("Error when opening audit file.", auditError);
|
||||
return (
|
||||
<FeatureWrapper featureName="audit">
|
||||
<div className="audit-container">
|
||||
<Row gutter={[16, 16]}>
|
||||
<div className="audit-container" id="audit-results-container">
|
||||
<Row gutter={[16, 16]} ref={componentRef}>
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<Form onFinish={handleBrowseForFile}>
|
||||
<Form.Item
|
||||
label="Ready for Payment Date Between"
|
||||
label="1. Ready for Payment Date Between"
|
||||
name="dateRange"
|
||||
tooltip="Select the time period that you would like to audit. This is typically a whole month or quarter."
|
||||
rules={[
|
||||
{ type: "array", required: true },
|
||||
{
|
||||
@@ -80,15 +90,24 @@ export function AuditPage({ auditError, queryReportingData }) {
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Sheet Name"
|
||||
tooltip="The name of the sheet which contains detailed RPS claim data."
|
||||
name="sheetName"
|
||||
initialValue="Shop RPS Claim Detail"
|
||||
>
|
||||
<Input width="200px" />
|
||||
</Form.Item>
|
||||
<Button htmlType="submit">Select MPI Audit XLS File</Button>
|
||||
|
||||
<Space align="middle" wrap>
|
||||
<Form.Item
|
||||
label="2. Sheet Name"
|
||||
tooltip="The name of the sheet which contains detailed RPS claim data."
|
||||
name="sheetName"
|
||||
initialValue="Shop RPS Claim Detail"
|
||||
required
|
||||
>
|
||||
<Input width="200px" />
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Select MPI Audit XLS File
|
||||
</Button>
|
||||
<Button onClick={handlePrint}>
|
||||
<PrinterFilled />
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
@@ -16,7 +16,7 @@ function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps
|
||||
noauth || (
|
||||
<Alert
|
||||
message={
|
||||
"You do not currently have access to this feature. Please reach out to support at support@thinkimex.com or 604-839-3431 to request access."
|
||||
"You do not currently have access to this feature. Please reach out to support at support@thinkimex.com or 604-839-3431 to subscribe."
|
||||
}
|
||||
type="warning"
|
||||
/>
|
||||
|
||||
@@ -5,6 +5,7 @@ const INITIAL_STATE = {
|
||||
scoreCard: null,
|
||||
error: null,
|
||||
loading: false,
|
||||
auditLoading: false,
|
||||
audit: {},
|
||||
auditError: null
|
||||
};
|
||||
@@ -30,10 +31,12 @@ const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
return { ...state, data: action.payload };
|
||||
case ReportingActionTypes.SET_SCORE_CARD:
|
||||
return { ...state, loading: false, scoreCard: action.payload };
|
||||
case ReportingActionTypes.CALCULATE_AUDIT:
|
||||
return { ...state, auditLoading: true };
|
||||
case ReportingActionTypes.SET_AUDIT_RESULTS:
|
||||
return { ...state, loading: false, auditError: null, audit: action.payload };
|
||||
return { ...state, loading: false, auditLoading: false, auditError: null, audit: action.payload };
|
||||
case ReportingActionTypes.SET_AUDIT_ERROR:
|
||||
return { ...state, auditError: action.payload };
|
||||
return { ...state, auditLoading: false, auditError: action.payload };
|
||||
case ReportingActionTypes.TOGGLE_GROUP_VERIFIED:
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -9,7 +9,7 @@ export const selectReportingError = createSelector([selectReporting], (reporting
|
||||
export const selectReportData = createSelector([selectReporting], (reporting) => reporting.data);
|
||||
export const selectAuditData = createSelector([selectReporting], (reporting) => reporting.audit);
|
||||
export const selectAuditError = createSelector([selectReporting], (reporting) => reporting.auditError);
|
||||
|
||||
export const selectAuditLoading = createSelector([selectReporting], (reporting) => reporting.auditLoading);
|
||||
// export const selectWatchedPaths = createSelector(
|
||||
// [selectReporting],
|
||||
// (application) => application.watchedPaths
|
||||
|
||||
Reference in New Issue
Block a user