Begin Audit Functionality testing.
This commit is contained in:
@@ -2,27 +2,35 @@ import ReportingActionTypes from "./reporting.types";
|
||||
|
||||
export const queryReportingData = ({ startDate, endDate }) => ({
|
||||
type: ReportingActionTypes.QUERY_REPORTING_DATA,
|
||||
payload: { startDate, endDate },
|
||||
payload: { startDate, endDate }
|
||||
});
|
||||
|
||||
export const setReportingData = (data) => ({
|
||||
type: ReportingActionTypes.SET_REPORTING_DATA,
|
||||
payload: data,
|
||||
payload: data
|
||||
});
|
||||
|
||||
export const calculateScorecard = (data) => ({
|
||||
type: ReportingActionTypes.CALCULATE_SCORE_CARD,
|
||||
payload: data,
|
||||
payload: data
|
||||
});
|
||||
export const setScoreCard = (data) => ({
|
||||
type: ReportingActionTypes.SET_SCORE_CARD,
|
||||
payload: data,
|
||||
payload: data
|
||||
});
|
||||
export const setReportingError = (data) => ({
|
||||
type: ReportingActionTypes.SET_REPORTING_ERROR,
|
||||
payload: data,
|
||||
payload: data
|
||||
});
|
||||
export const toggleGroupVerified = (jobId) => ({
|
||||
type: ReportingActionTypes.TOGGLE_GROUP_VERIFIED,
|
||||
payload: jobId,
|
||||
payload: jobId
|
||||
});
|
||||
export const calculateAudit = (claimsArrayFromAudit) => ({
|
||||
type: ReportingActionTypes.CALCULATE_AUDIT,
|
||||
payload: claimsArrayFromAudit
|
||||
});
|
||||
export const setAuditResults = (auditResults) => ({
|
||||
type: ReportingActionTypes.SET_AUDIT_RESULTS,
|
||||
payload: auditResults
|
||||
});
|
||||
|
||||
@@ -4,34 +4,23 @@ import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import client from "../../graphql/GraphQLClient";
|
||||
import { REPORTING_GET_JOBS } from "../../graphql/reporting.queries";
|
||||
import ipcTypes from "../../ipc.types";
|
||||
import {
|
||||
CalculateJobRpsDollars,
|
||||
CalculateJobRpsPc,
|
||||
} from "../../util/CalculateJobRps";
|
||||
import { CalculateJobRpsDollars, CalculateJobRpsPc } from "../../util/CalculateJobRps";
|
||||
import GetJobTarget from "../../util/GetJobTarget";
|
||||
import {
|
||||
calculateScorecard,
|
||||
setReportingData,
|
||||
setScoreCard,
|
||||
setReportingError,
|
||||
} from "./reporting.actions";
|
||||
import { calculateScorecard, setReportingData, setScoreCard, setReportingError } from "./reporting.actions";
|
||||
import ReportingApplicationTypes from "./reporting.types";
|
||||
|
||||
const { log, ipcRenderer } = window;
|
||||
|
||||
export function* onQueryReportData() {
|
||||
yield takeLatest(
|
||||
ReportingApplicationTypes.QUERY_REPORTING_DATA,
|
||||
queryReportingData
|
||||
);
|
||||
yield takeLatest(ReportingApplicationTypes.QUERY_REPORTING_DATA, queryReportingData);
|
||||
}
|
||||
export function* queryReportingData({ payload: { startDate, endDate } }) {
|
||||
const result = yield client.query({
|
||||
query: REPORTING_GET_JOBS,
|
||||
variables: {
|
||||
startDate: startDate.format("YYYY-MM-DD"),
|
||||
endDate: endDate.format("YYYY-MM-DD"),
|
||||
},
|
||||
endDate: endDate.format("YYYY-MM-DD")
|
||||
}
|
||||
});
|
||||
if (result.errors) {
|
||||
log.error("Error fetching report data.", result.errors);
|
||||
@@ -42,25 +31,66 @@ export function* queryReportingData({ payload: { startDate, endDate } }) {
|
||||
}
|
||||
|
||||
export function* onSetReportData() {
|
||||
yield takeLatest(
|
||||
ReportingApplicationTypes.SET_REPORTING_DATA,
|
||||
handleSetReportData
|
||||
);
|
||||
yield takeLatest(ReportingApplicationTypes.SET_REPORTING_DATA, handleSetReportData);
|
||||
}
|
||||
export function* handleSetReportData({ payload: jobs }) {
|
||||
// yield put(calculateScorecard(jobs));
|
||||
}
|
||||
export function* onCalculateAudit() {
|
||||
yield takeLatest(ReportingApplicationTypes.CALCULATE_AUDIT, handleCalculateAudit);
|
||||
}
|
||||
export function* handleCalculateAudit({ payload: claimsArrayFromAudit }) {
|
||||
const rpsJobs = yield select((state) => state.reporting.data);
|
||||
//Get List of Claims delta.
|
||||
const missingFromRps = rpsJobs.filter((job) => !claimsArrayFromAudit.find((c) => c.clm_no.includes(job.clm_no)));
|
||||
const missingFromAudit = claimsArrayFromAudit.filter((c) => !rpsJobs.find((job) => c.clm_no.includes(job.clm_no)));
|
||||
console.log("Missing From RPS/From Audit", missingFromRps.length, missingFromAudit.length);
|
||||
|
||||
//For the items in both spots, highlight the discrepancy.
|
||||
const claimsArrayHashObject = {};
|
||||
claimsArrayFromAudit.forEach((claim) => {
|
||||
const cleansedClaimNo = claim.clm_no.replace(/^0+/, "").trim();
|
||||
claimsArrayHashObject[cleansedClaimNo] = claim;
|
||||
});
|
||||
|
||||
const JobsThatDontMatch = [];
|
||||
|
||||
rpsJobs.forEach((rpsJob) => {
|
||||
const matchingAuditJob = claimsArrayHashObject[rpsJob.clm_no];
|
||||
|
||||
if (Math.abs(rpsJob.expectedRpsDollars.getAmount() / 100 - matchingAuditJob.expected_rps_dollars) > 0.01) {
|
||||
let styles =
|
||||
"font-weight: bold; font-size: 22px;color: yellow; 6px 6px 0 rgb(226,91,14) , 9px 9px 0 rgb(245,221,8) , 12px 12px 0 rgb(5,148,68) ";
|
||||
console.log(
|
||||
"%c %s",
|
||||
styles,
|
||||
`Expected Savings Mismatch for ${rpsJob.clm_no} || ${rpsJob.expectedRpsDollars.toFormat()} >> ${
|
||||
matchingAuditJob.expected_rps_dollars
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
if (Math.abs(rpsJob.jobRpsDollars.getAmount() / 100 - matchingAuditJob.actual_rps_dollars) > 0.01) {
|
||||
let styles =
|
||||
"font-weight: bold; font-size: 22px;color: red; 6px 6px 0 rgb(226,91,14) , 9px 9px 0 rgb(245,221,8) , 12px 12px 0 rgb(5,148,68) ";
|
||||
console.log(
|
||||
"%c %s",
|
||||
styles,
|
||||
`Actual Savings Mismatch for ${rpsJob.clm_no} || ${rpsJob.jobRpsDollars.toFormat()} >> ${
|
||||
matchingAuditJob.actual_rps_dollars
|
||||
}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function* onCalculateScoreCard() {
|
||||
yield takeLatest(
|
||||
ReportingApplicationTypes.CALCULATE_SCORE_CARD,
|
||||
handleCalculateScoreCard
|
||||
);
|
||||
yield takeLatest(ReportingApplicationTypes.CALCULATE_SCORE_CARD, handleCalculateScoreCard);
|
||||
}
|
||||
export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "CALCULATE_SCORECARD",
|
||||
event: "CALCULATE_SCORECARD"
|
||||
});
|
||||
|
||||
const targets = yield select((state) => state.user.bodyshop.targets);
|
||||
@@ -77,7 +107,7 @@ export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
yield put(
|
||||
setReportingError({
|
||||
message: "There is an issue with the following jobs.",
|
||||
jobs: [...jobsWithNoGroup],
|
||||
jobs: [...jobsWithNoGroup]
|
||||
})
|
||||
);
|
||||
return;
|
||||
@@ -92,44 +122,28 @@ export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
allJobsSumActPrice: Dinero(),
|
||||
currentRpsPc: 0,
|
||||
targetRpsPc: 0,
|
||||
scatterChart: _.sortBy(
|
||||
groups,
|
||||
[(group) => group.toLowerCase()],
|
||||
["desc"]
|
||||
).reduce((acc, val) => {
|
||||
scatterChart: _.sortBy(groups, [(group) => group.toLowerCase()], ["desc"]).reduce((acc, val) => {
|
||||
return { ...acc, [val]: [] };
|
||||
}, {}),
|
||||
}, {})
|
||||
};
|
||||
|
||||
//Get the RPS on a per job basis.
|
||||
jobs = jobs.map((job) => {
|
||||
const { actPriceSum, jobRpsDollars } = CalculateJobRpsDollars(job, true);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(
|
||||
job,
|
||||
jobRpsDollars,
|
||||
true
|
||||
);
|
||||
const jobTarget = GetJobTarget({group:job.group, v_age:job.v_age, targets,close_date: job.close_date});
|
||||
scoreCard.shopRpsTotalDollars = scoreCard.shopRpsTotalDollars.add(
|
||||
jobRpsDollars
|
||||
);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(job, jobRpsDollars, true);
|
||||
const jobTarget = GetJobTarget({ group: job.group, v_age: job.v_age, targets, close_date: job.close_date });
|
||||
scoreCard.shopRpsTotalDollars = scoreCard.shopRpsTotalDollars.add(jobRpsDollars);
|
||||
const expectedRpsDollars = dbPriceSum.percentage(jobTarget * 100);
|
||||
scoreCard.shopRpsExpectedDollars = scoreCard.shopRpsExpectedDollars.add(
|
||||
expectedRpsDollars
|
||||
);
|
||||
scoreCard.shopRpsExpectedDollars = scoreCard.shopRpsExpectedDollars.add(expectedRpsDollars);
|
||||
|
||||
scoreCard.allJobsSumDbPrice = scoreCard.allJobsSumDbPrice.add(dbPriceSum);
|
||||
scoreCard.allJobsSumActPrice = scoreCard.allJobsSumActPrice.add(
|
||||
actPriceSum
|
||||
);
|
||||
scoreCard.allJobsSumActPrice = scoreCard.allJobsSumActPrice.add(actPriceSum);
|
||||
|
||||
const deviationPc = Math.round((jobRpsPc - jobTarget) * 1000) / 10;
|
||||
|
||||
scoreCard.scatterChart[job.group].push({
|
||||
deviationPc: isNaN(deviationPc) ? -100 : deviationPc,
|
||||
deviationDollars: (
|
||||
jobRpsDollars.subtract(expectedRpsDollars).getAmount() / 100
|
||||
).toFixed(2),
|
||||
deviationDollars: (jobRpsDollars.subtract(expectedRpsDollars).getAmount() / 100).toFixed(2),
|
||||
age: job.v_age,
|
||||
dbPriceSum,
|
||||
dbPriceSumAmt: dbPriceSum.getAmount() / 100,
|
||||
@@ -138,7 +152,7 @@ export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
vehicle: `${job.v_model_yr} ${job.v_makedesc} ${job.v_model} (${job.v_type}) - ${job.group}`,
|
||||
clm_no: job.clm_no,
|
||||
jobRpsDollars,
|
||||
jobRpsPc: isNaN(jobRpsPc) ? -1 : jobRpsPc,
|
||||
jobRpsPc: isNaN(jobRpsPc) ? -1 : jobRpsPc
|
||||
});
|
||||
|
||||
//sum db price * percentage expected.
|
||||
@@ -149,20 +163,14 @@ export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
dbPriceSum,
|
||||
jobRpsPc,
|
||||
jobTarget,
|
||||
expectedRpsDollars,
|
||||
expectedRpsDollars
|
||||
};
|
||||
});
|
||||
|
||||
scoreCard.varianceDollars = scoreCard.shopRpsTotalDollars.subtract(
|
||||
scoreCard.shopRpsExpectedDollars
|
||||
);
|
||||
scoreCard.varianceDollars = scoreCard.shopRpsTotalDollars.subtract(scoreCard.shopRpsExpectedDollars);
|
||||
|
||||
scoreCard.currentRpsPc =
|
||||
scoreCard.shopRpsTotalDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
scoreCard.targetRpsPc =
|
||||
scoreCard.shopRpsExpectedDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
scoreCard.currentRpsPc = scoreCard.shopRpsTotalDollars.getAmount() / scoreCard.allJobsSumDbPrice.getAmount();
|
||||
scoreCard.targetRpsPc = scoreCard.shopRpsExpectedDollars.getAmount() / scoreCard.allJobsSumDbPrice.getAmount();
|
||||
|
||||
scoreCard.variancePc = scoreCard.currentRpsPc - scoreCard.targetRpsPc;
|
||||
//Set the data.
|
||||
@@ -171,16 +179,12 @@ export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
} catch (error) {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "CALCULATE_SCORE_CARD_ERROR",
|
||||
error: error,
|
||||
error: error
|
||||
});
|
||||
yield put(setReportingError({ message: error, jobs: [] }));
|
||||
}
|
||||
}
|
||||
|
||||
export function* reportingSagas() {
|
||||
yield all([
|
||||
call(onQueryReportData),
|
||||
call(onSetReportData),
|
||||
call(onCalculateScoreCard),
|
||||
]);
|
||||
yield all([call(onQueryReportData), call(onSetReportData), call(onCalculateScoreCard), call(onCalculateAudit)]);
|
||||
}
|
||||
|
||||
@@ -5,5 +5,7 @@ const ReportingActionTypes = {
|
||||
SET_SCORE_CARD: "SET_SCORE_CARD",
|
||||
SET_REPORTING_ERROR: "SET_REPORTING_ERROR",
|
||||
TOGGLE_GROUP_VERIFIED: "TOGGLE_GROUP_VERIFIED",
|
||||
CALCULATE_AUDIT: "CALCULATE_AUDIT",
|
||||
SET_AUDIT_RESULTS: "SET_AUDIT_RESULTS"
|
||||
};
|
||||
export default ReportingActionTypes;
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { message } from "antd";
|
||||
import dayjs from '../../util/day.js';
|
||||
import dayjs from "../../util/day.js";
|
||||
//import LogRocket from "logrocket";
|
||||
import * as Sentry from "@sentry/electron";
|
||||
import { sendPasswordResetEmail, signInWithEmailAndPassword, signOut } from "firebase/auth";
|
||||
import { all, call, delay, put, takeLatest } from "redux-saga/effects";
|
||||
import {
|
||||
auth,
|
||||
getCurrentUser,
|
||||
updateCurrentUser,
|
||||
} from "../../firebase/firebase.utils";
|
||||
import { auth, getCurrentUser, updateCurrentUser } from "../../firebase/firebase.utils";
|
||||
import client from "../../graphql/GraphQLClient";
|
||||
import {
|
||||
QUERY_BODYSHOP,
|
||||
QUERY_NOTIFICATIONS,
|
||||
} from "../../graphql/bodyshop.queries";
|
||||
import { UPSERT_USER } from "../../graphql/user.queries";
|
||||
import { QUERY_BODYSHOP, QUERY_NOTIFICATIONS } from "../../graphql/bodyshop.queries";
|
||||
import ipcTypes from "../../ipc.types";
|
||||
import {
|
||||
checkForNotification,
|
||||
@@ -27,7 +20,7 @@ import {
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
updateUserDetailsSuccess
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
@@ -40,31 +33,29 @@ export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "SIGN_IN_ATTEMPT",
|
||||
email: email,
|
||||
email: email
|
||||
});
|
||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||
const { user } = yield signInWithEmailAndPassword(auth, email, password);
|
||||
|
||||
const result = yield client.mutate({
|
||||
mutation: UPSERT_USER,
|
||||
variables: { authEmail: user.email, authToken: user.uid },
|
||||
});
|
||||
if (!result.errors) {
|
||||
// const result = yield client.mutate({
|
||||
// mutation: UPSERT_USER,
|
||||
// variables: { authEmail: user.email, authToken: user.uid },
|
||||
// });
|
||||
if (user) {
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
authorized: true
|
||||
})
|
||||
);
|
||||
} else {
|
||||
yield put(signInFailure(JSON.stringify(result.errors)));
|
||||
yield put(signInFailure());
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(
|
||||
signInFailure({ ...error, messagePretty: ErrorFormatter(error.code) })
|
||||
);
|
||||
yield put(signInFailure({ ...error, messagePretty: ErrorFormatter(error.code) }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +77,7 @@ export function* isUserAuthenticated() {
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
authorized: true
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -101,10 +92,10 @@ export function* onSignOutStart() {
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "SIGN_OUT",
|
||||
event: "SIGN_OUT"
|
||||
});
|
||||
ipcRenderer.send(ipcTypes.fileWatcher.toMain.stop);
|
||||
yield auth.signOut();
|
||||
yield signOut(auth);
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
} catch (error) {
|
||||
@@ -140,37 +131,26 @@ export function* signInSuccessSaga({ payload }) {
|
||||
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "SIGN_IN_SUCCESS",
|
||||
email: payload.email,
|
||||
email: payload.email
|
||||
});
|
||||
const shop = yield client.query({ query: QUERY_BODYSHOP });
|
||||
if (shop.data.bodyshops.length > 0) {
|
||||
yield put(setBodyshop(shop.data.bodyshops[0]));
|
||||
ipcRenderer.send(
|
||||
ipcTypes.app.toMain.setAcceptableInsCoNm,
|
||||
shop.data.bodyshops[0].accepted_ins_co
|
||||
);
|
||||
ipcRenderer.send(ipcTypes.app.toMain.setAcceptableInsCoNm, shop.data.bodyshops[0].accepted_ins_co);
|
||||
ipcRenderer.send(ipcTypes.fileWatcher.toMain.start, {
|
||||
startup: true,
|
||||
startup: true
|
||||
});
|
||||
yield put(checkForNotification());
|
||||
//Check for notifications, and continue to check.
|
||||
window.$crisp.push([
|
||||
"set",
|
||||
"user:company",
|
||||
[shop.data.bodyshops[0].shopname],
|
||||
]);
|
||||
window.$crisp.push([
|
||||
"set",
|
||||
"user:nickname",
|
||||
[payload.displayName || payload.email],
|
||||
]);
|
||||
window.$crisp.push(["set", "user:company", [shop.data.bodyshops[0].shopname]]);
|
||||
window.$crisp.push(["set", "user:nickname", [payload.displayName || payload.email]]);
|
||||
window.$crisp.push(["set", "user:email", [payload.email]]);
|
||||
window.$crisp.push(["set", "session:segments", [["rps-user"]]]);
|
||||
ipcRenderer.send(ipcTypes.app.toMain.getAppVersion);
|
||||
|
||||
Sentry.setUser({
|
||||
email: payload.email,
|
||||
username: payload.displayName || payload.email,
|
||||
username: payload.displayName || payload.email
|
||||
});
|
||||
} else {
|
||||
console.log("No bodyshop has been associated.");
|
||||
@@ -188,17 +168,14 @@ export function* signInSuccessSaga({ payload }) {
|
||||
}
|
||||
|
||||
export function* onCheckForNotification() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.CHECK_FOR_NOTIFICATION,
|
||||
checkForNotificationSaga
|
||||
);
|
||||
yield takeLatest(UserActionTypes.CHECK_FOR_NOTIFICATION, checkForNotificationSaga);
|
||||
}
|
||||
export function* checkForNotificationSaga() {
|
||||
const {
|
||||
data: { notifications },
|
||||
data: { notifications }
|
||||
} = yield client.query({
|
||||
query: QUERY_NOTIFICATIONS,
|
||||
variables: { now: dayjs() },
|
||||
variables: { now: dayjs() }
|
||||
});
|
||||
|
||||
if (notifications) {
|
||||
@@ -209,18 +186,15 @@ export function* checkForNotificationSaga() {
|
||||
}
|
||||
|
||||
export function* onSendPasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmail
|
||||
);
|
||||
yield takeLatest(UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START, sendPasswordResetEmailFunc);
|
||||
}
|
||||
export function* sendPasswordResetEmail({ payload }) {
|
||||
export function* sendPasswordResetEmailFunc({ payload }) {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "RESET_PASSWORD",
|
||||
email: payload,
|
||||
email: payload
|
||||
});
|
||||
yield auth.sendPasswordResetEmail(payload);
|
||||
yield sendPasswordResetEmail(auth, payload);
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
message.success("Password reset sent succesfully.");
|
||||
@@ -236,7 +210,7 @@ export function* userSagas() {
|
||||
call(onUpdateUserDetails),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onCheckForNotification),
|
||||
call(onCheckForNotification)
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user