Add feature wrapper to Audit.

This commit is contained in:
Patrick Fic
2024-04-24 08:59:23 -07:00
parent b1d8c036e7
commit 09b5fca3b3
10 changed files with 161 additions and 85 deletions

View File

@@ -31,7 +31,7 @@ ipcMain.on(ipcTypes.default.audit.toMain.browseForFile, async (event, { sheetNam
clm_no: line[0],
close_date: line[1],
v_model_yr: line[3],
v_make_desc: line[4],
v_makedesc: line[4],
v_model: line[5],
under20kmiles: line[6],
pan_total: line[7],

View File

@@ -29,6 +29,7 @@ select_permissions:
columns:
- accepted_ins_co
- created_at
- features
- groups
- id
- ppd_diff_alert

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "features" jsonb
-- null default jsonb_build_object();

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "features" jsonb
null default jsonb_build_object();

View File

@@ -7,6 +7,7 @@ import { selectAuditData } 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";
const mapStateToProps = createStructuredSelector({
selectAuditData: selectAuditData
@@ -18,25 +19,41 @@ const mapDispatchToProps = (dispatch) => ({
export function AuditResultsOrganism({ selectAuditData }) {
const missingColumns = [
{ key: "clm_no", width: "20%", title: "Claim No.", dataIndex: "clm_no" },
{
key: "clm_no",
width: "20%",
title: "Claim No.",
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
dataIndex: "clm_no"
},
{
key: "close_date",
width: "20%",
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_make_desc", width: "20%", title: "Make", dataIndex: "v_make_desc" },
{ key: "v_makedesc", width: "20%", title: "Make", dataIndex: "v_makedesc" },
{ key: "v_model", width: "20%", title: "Model", dataIndex: "v_model" }
];
const mismatchColumns = [
{ key: "clm_no", width: "12%", title: "Claim No.", dataIndex: ["rps", "clm_no"] },
{
key: "clm_no",
width: "12%",
title: "Claim No.",
sorter: (a, b) => alphaSort(a.rps.clm_no, b.rps.clm_no),
dataIndex: ["rps", "clm_no"]
},
{
key: "close_date",
title: "[RPS] R4P",
dataIndex: "close_date",
defaultSortOrder: "ascend",
sorter: (a, b) => dateSort(a.rps.close_date, b.rps.close_date),
render: (text, record) => dayjs(record.rps.close_date).format(DateFormat)
},
{
@@ -44,10 +61,12 @@ export function AuditResultsOrganism({ selectAuditData }) {
width: "12%",
title: "[Audit] R4P",
dataIndex: "close_date_audit",
sorter: (a, b) => dateSort(a.audit.close_date, b.audit.close_date),
render: (text, record) => dayjs(record.audit.close_date).format(DateFormat)
},
{ key: "v_model_yr", width: "12%", title: "Model Year", dataIndex: ["audit", "v_model_yr"] },
{ key: "v_make_desc", width: "12%", title: "Make", dataIndex: ["audit", "v_make_desc"] },
{ key: "v_makedesc", width: "12%", title: "Make", dataIndex: ["audit", "v_makedesc"] },
{ key: "v_model", width: "12%", title: "Model", dataIndex: ["audit", "v_model"] },
{
key: "expected_rps",

View File

@@ -1,13 +1,14 @@
import { Alert, Button, Card, Col, DatePicker, Form, Input, Row } from "antd";
import React from "react";
import ipcTypes from "../../../ipc.types";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import ipcTypes from "../../../ipc.types";
import { queryReportingData } from "../../../redux/reporting/reporting.actions";
import { selectAuditError } from "../../../redux/reporting/reporting.selectors";
import dayjs from "../../../util/day";
import AuditResultsOrganism from "../../organisms/audit-results/audit-results.organism";
import FeatureWrapper from "../../templates/feature-wrapper";
import "./audit.page.styles.scss";
import { selectAuditError } from "../../../redux/reporting/reporting.selectors";
const { ipcRenderer } = window;
@@ -28,70 +29,81 @@ export function AuditPage({ auditError, queryReportingData }) {
});
ipcRenderer.send(ipcTypes.audit.toMain.browseForFile, { sheetName });
};
if (auditError) console.log("Error when opening audit file.", auditError);
return (
<div className="audit-container">
<Row gutter={[16, 16]}>
<Col span={24}>
<Card>
<Form onFinish={handleBrowseForFile}>
<Form.Item
label="Ready for Payment Date Between"
name="dateRange"
rules={[
{ type: "array", required: true },
{
validator(rule, value) {
if (!value || !value.length === 2) {
return Promise.resolve();
}
// if (dayjs(value[1]).diff(dayjs(value[0]), "month", true) > 1) {
// return Promise.reject("Time period exceeds 1 month. Please select a shorter date range.");
// } else {
return Promise.resolve();
// }
}
}
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={{
"2 Months ago": [
dayjs().startOf("month").subtract(2, "month"),
dayjs().startOf("month").subtract(2, "month").endOf("month")
],
"Last Month": [
dayjs().startOf("month").subtract(1, "month"),
dayjs().startOf("month").subtract(1, "month").endOf("month")
],
"This Month": [dayjs().startOf("month"), dayjs().endOf("month")],
"Last Quarter": [
dayjs().startOf("quarter").subtract(1, "quarter"),
dayjs().startOf("quarter").subtract(1, "day")
],
"Last 3 Months": [
dayjs().startOf("month").subtract(3, "month"),
dayjs().startOf("month").subtract(1, "month").endOf("month")
]
}}
/>
</Form.Item>
<Form.Item label="Sheet Name" tooltip="" name="sheetName" initialValue="Shop RPS Claim Detail">
<Input />
</Form.Item>
<Button htmlType="submit">Select Audit XLS</Button>
</Form>
</Card>
</Col>
{auditError && (
<FeatureWrapper featureName="audit">
<div className="audit-container">
<Row gutter={[16, 16]}>
<Col span={24}>
<Alert type="error" banner message={auditError} />
<Card>
<Form onFinish={handleBrowseForFile}>
<Form.Item
label="Ready for Payment Date Between"
name="dateRange"
rules={[
{ type: "array", required: true },
{
validator(rule, value) {
if (!value || !value.length === 2) {
return Promise.resolve();
}
// if (dayjs(value[1]).diff(dayjs(value[0]), "month", true) > 1) {
// return Promise.reject("Time period exceeds 1 month. Please select a shorter date range.");
// } else {
return Promise.resolve();
// }
}
}
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={{
"2 Months ago": [
dayjs().startOf("month").subtract(2, "month"),
dayjs().startOf("month").subtract(2, "month").endOf("month")
],
"Last Month": [
dayjs().startOf("month").subtract(1, "month"),
dayjs().startOf("month").subtract(1, "month").endOf("month")
],
"This Month": [dayjs().startOf("month"), dayjs().endOf("month")],
"Last Quarter": [
dayjs().startOf("quarter").subtract(1, "quarter"),
dayjs().startOf("quarter").subtract(1, "day")
],
"Last 3 Months": [
dayjs().startOf("month").subtract(3, "month"),
dayjs().startOf("month").subtract(1, "month").endOf("month")
]
}}
/>
</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>
</Form>
</Card>
</Col>
)}
<AuditResultsOrganism />
</Row>
</div>
{auditError && (
<Col span={24}>
<Alert
type="error"
banner
message="Error encountered when opening the audit file. Please ensure it is not open in any other programs, and the sheet name is correct."
/>
</Col>
)}
<AuditResultsOrganism />
</Row>
</div>
</FeatureWrapper>
);
}

View File

@@ -4,10 +4,7 @@ import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { setSelectedJobId } from "../../../redux/application/application.actions";
import {
selectDates,
selectReportingError,
} from "../../../redux/reporting/reporting.selectors";
import { selectDates, selectReportingError } from "../../../redux/reporting/reporting.selectors";
import ReportingTitleAtom from "../../atoms/reporting-title/reporting-title.atom";
import ReportingDatesMolecule from "../../molecules/reporting-dates/reporting-dates.molecule";
import ReportingJobsListMolecule from "../../molecules/reporting-jobs-list/reporting-jobs-list.molecule";
@@ -17,10 +14,10 @@ import "./reporting.page.styles.scss";
const mapStateToProps = createStructuredSelector({
dates: selectDates,
error: selectReportingError,
error: selectReportingError
});
const mapDispatchToProps = (dispatch) => ({
setSelectedJobId: (id) => dispatch(setSelectedJobId(id)),
setSelectedJobId: (id) => dispatch(setSelectedJobId(id))
});
export function ReportingPage({ dates, error, setSelectedJobId }) {

View File

@@ -0,0 +1,40 @@
import dayjs from "../../util/day";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { Alert } from "antd";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps }) {
if (HasFeatureAccess({ featureName, bodyshop })) return children;
return (
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."
}
type="warning"
/>
)
);
}
export function HasFeatureAccess({ featureName, bodyshop }) {
return bodyshop?.features?.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
}
export default connect(mapStateToProps, null)(FeatureWrapper);
/*
dashboard
production-board
scoreboard
csi
tech-console
mobile-imaging
*/

View File

@@ -8,6 +8,7 @@ export const QUERY_BODYSHOP = gql`
accepted_ins_co
groups
ppd_diff_alert
features
}
targets {
id
@@ -33,6 +34,7 @@ export const UPDATE_SHOP = gql`
accepted_ins_co
groups
ppd_diff_alert
features
}
}
}

View File

@@ -1,12 +1,11 @@
export function alphaSort(a, b) {
let A;
let B;
A = a ? a.toLowerCase() : "";
B = b ? b.toLowerCase() : "";
if (A < B)
//sort string ascending
return -1;
if (A > B) return 1;
return 0; //default return value (no sorting)
return (a ? a.toLowerCase() : "").localeCompare(b ? b.toLowerCase() : "");
}
export function dateSort(a, b) {
return new Date(a) - new Date(b);
}
export function statusSort(a, b, statusList) {
return statusList.findIndex((x) => x === a) - statusList.findIndex((x) => x === b);
}