diff --git a/README.md b/README.md index 89b278a..3a21f6d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +Creating Release Notes Tools: +https://onlinestringtools.com/json-stringify-string + This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). ## Available Scripts diff --git a/WIP Changelog.txt b/WIP Changelog.txt new file mode 100644 index 0000000..0f25504 --- /dev/null +++ b/WIP Changelog.txt @@ -0,0 +1,13 @@ +New Features: +- Vehicles with mileage under 20,000kms will now be included in Watcher filtering criteria. +- Savings on OEM parts will always default to the user enter price and override the estimating system price. +- Wheel related lines will no longer be automatically ignored. +- Glass related lines will no longer be automatically ignored. +- Added 'Variance %' statistic to reporting totals. +- Automatically ignore any lines which have invalid prices from estimating system. +- Force line inclusion/exclusion - Using “ /rps-exclude” or “/rps” in the Part Number field to force inclusion or exclusion of lines for RPS calculation. +- Added automatic update checks every 30 minutes. + +Bug Fixes: +- Resolved an issue where the updater would not show update progress to some users. +- Fixed a UI bug during job search that would cause the 'no close date' alert to be incorrectly shown. \ No newline at end of file diff --git a/changelog.json b/changelog.json new file mode 100644 index 0000000..c935fca --- /dev/null +++ b/changelog.json @@ -0,0 +1,7 @@ +{ + "1.0.9": { + "title": "Release Notes for 1.0.9", + "date": "11/16/2020", + "notes": "New Features: \n- Vehicles with mileage under 20,000kms will now be included in Watcher filtering criteria.\n- Savings on OEM parts will always default to the user enter price and override the estimating system price.\n- Wheel related lines will no longer be automatically ignored.\n- Glass related lines will no longer be automatically ignored.\n- Added 'Variance %' statistic to reporting totals.\n- Automatically ignore any lines which have invalid prices from estimating system.\n- Force line inclusion/exclusion - Using “ /rps-exclude” or “/rps” in the Part Number field to force inclusion or exclusion of lines for RPS calculation.\n- Added automatic update checks every 30 minutes.\n\nBug Fixes: \n- Resolved an issue where the updater would not show update progress to some users.\n- Fixed a UI bug during job search that would cause the 'no close date' alert to be incorrectly shown." + } +} diff --git a/electron/analytics.js b/electron/analytics.js index 5d8b23b..f7f22eb 100644 --- a/electron/analytics.js +++ b/electron/analytics.js @@ -7,6 +7,7 @@ const { default: ipcTypes } = require("../src/ipc.types"); Nucleus.init("5f91b569b95bac34eefdb63a", { disableInDev: true, debug: false, + version: app.getVersion(), }); Nucleus.setProps({ diff --git a/electron/decoder/decoder.js b/electron/decoder/decoder.js index 85a8485..1dca8d5 100644 --- a/electron/decoder/decoder.js +++ b/electron/decoder/decoder.js @@ -57,9 +57,12 @@ async function DecodeEstimate(filePath, includeFilePathInReturnJob = false) { const accepted_ins_co = store.get("accepted_ins_co"); let returnValue; - if (job.V_MILEAGE <= 20000) { - returnValue = { ERROR: "Vehicle mileage is less than 20,000kms." }; - } else if (!accepted_ins_co.includes(job.INS_CO_NM)) { + //Removed as a part of RPS-40. + // if (job.V_MILEAGE <= 20000) { + // returnValue = { ERROR: "Vehicle mileage is less than 20,000kms." }; + // } else + + if (!accepted_ins_co.includes(job.INS_CO_NM)) { returnValue = { ERROR: `Insurance Company Name is not valid for RPS. (${ job.INS_CO_NM || "No name set" @@ -351,51 +354,68 @@ async function DecodeLinFile(extensionlessFilePath) { // jobline.glass_flag === false // ) .map((jobline) => { + //Removed as a result of conversation with Norm. + // Appears you are calculating based on ‘N.A.’ part values in the Mitchell database. + // Reminder – if Mitchell DB has $0.00 price updates can be tracked, if it has N.A. it cannot calculate RPS value. + + // if ( + // (jobline.db_price === null || jobline.db_price === 0) && + // !!jobline.act_price && + // jobline.act_price > 0 + // ) { + // // log.info( + // // "DB Price null/lower than act price", + // // jobline.line_desc, + // // jobline.db_price, + // // jobline.act_price + // // ); + // jobline.db_price = jobline.act_price; + // } + + //RPS-39 - OEM ON OEM SAVINGS if ( - (jobline.db_price === null || jobline.db_price === 0) && - !!jobline.act_price && - jobline.act_price > 0 + jobline.part_type === "PAN" && + jobline.db_price !== jobline.act_price ) { - // log.info( - // "DB Price null/lower than act price", - // jobline.line_desc, - // jobline.db_price, - // jobline.act_price - // ); jobline.db_price = jobline.act_price; } if ( - jobline.db_price && - jobline.act_price && + !!jobline.db_price && + jobline.db_price > 0 && + !!jobline.act_price && jobline.act_price > jobline.db_price ) { - // log.info( - // "Act price higher than existing db price", - // jobline.line_desc, - // jobline.db_price, - // jobline.act_price - // ); + //Actual price should never be higher than the DB Price. jobline.db_price = jobline.act_price; } + //Logic Based Exclusions. if ( !jobline.part_type || jobline.db_ref.startsWith("900") || jobline.line_desc.toLowerCase().startsWith("urethane") || - jobline.line_desc.toLowerCase().includes("wheel") || + //jobline.line_desc.toLowerCase().includes("wheel") || Removed as a part of RPS-41 jobline.line_desc.toLowerCase().includes("tire") || jobline.line_desc.toLowerCase().startsWith("hazardous") || jobline.line_desc.toLowerCase().startsWith("detail") || jobline.line_desc.toLowerCase().startsWith("clean") || - jobline.part_type.toUpperCase() === "PAG" || + // jobline.part_type.toUpperCase() === "PAG" ||Removed for RPS-43. jobline.part_type.toUpperCase() === "PAS" || jobline.part_type.toUpperCase() === "PASL" || jobline.part_type.toUpperCase() === "PAE" || - jobline.glass_flag === true + //jobline.glass_flag === true //Removed for RPS-43. + jobline.db_price === 0 //Added as a part of RPS-46. ) jobline.ignore = true; + //RPS-42 Dynamic Inclusion or Exclusion of Lines based on RPS-EXCLUDE or RPS. + if (jobline.oem_partno.toLowerCase().includes("/rps-exclude")) { + jobline.ignore = true; + } else if (jobline.oem_partno.toLowerCase().includes("/rps")) { + jobline.ignore = false; + } + delete jobline.glass_flag; return jobline; }); diff --git a/electron/electron-store.js b/electron/electron-store.js index b444ac8..488fe8d 100644 --- a/electron/electron-store.js +++ b/electron/electron-store.js @@ -2,13 +2,14 @@ const Store = require("electron-store"); const store = new Store({ defaults: { + showChangeLog: true, enableNotifications: true, filePaths: [], accepted_ins_co: [], runWatcherOnStartup: true, polling: { enabled: false, - pollingInterval: 1000, + pollingInterval: 30000, }, }, }); diff --git a/electron/ipc-main-handler.js b/electron/ipc-main-handler.js index 54f9858..2d28b1a 100644 --- a/electron/ipc-main-handler.js +++ b/electron/ipc-main-handler.js @@ -1,4 +1,5 @@ -const { ipcMain } = require("electron"); +const { ipcMain, app: electronApp } = require("electron"); +const { app } = require("firebase"); const { default: ipcTypes } = require("../src/ipc.types"); const { store } = require("./electron-store"); //Import Ipc Handlers @@ -32,3 +33,13 @@ ipcMain.on(ipcTypes.store.getAll, (event, obj) => { const val = store.get(); event.sender.send(ipcTypes.store.response, val); }); + +ipcMain.on(ipcTypes.app.toMain.getReleaseNotes, (event, obj) => { + const showNotes = store.get("showChangeLog"); + if (showNotes) { + const rn = require("../changelog.json")[electronApp.getVersion()]; + event.sender.send(ipcTypes.app.toRenderer.setReleaseNotes, rn); + } else { + event.sender.send(ipcTypes.app.toRenderer.setReleaseNotes, null); + } +}); diff --git a/electron/main.js b/electron/main.js index f8f6d25..6c71781 100644 --- a/electron/main.js +++ b/electron/main.js @@ -81,6 +81,15 @@ var menu = Menu.buildFromTemplate([ checkForUpdates(); }, }, + { + label: `Show Release Notes`, + click() { + mainWindow.webContents.send( + ipcTypes.app.toRenderer.setReleaseNotes, + require("../changelog.json")[app.getVersion()] + ); + }, + }, { label: "Open Config File", click() { @@ -195,6 +204,10 @@ app.whenReady().then(() => { .catch((error) => console.log(`An error occurred: , ${error}`)); } + setInterval(() => { + checkForUpdates(); + }, 1000 * 60 * 30); //Added auto update check for RPS-38 + // ipcMain.on(ipcTypes.default.webcontent, (event, ...obj) => { // console.log("event", event); // mainWindow.webContents.send(event, obj); @@ -246,9 +259,6 @@ function createTray() { return appIcon; } -// autoUpdater.on("checking-for-update", () => { -// log.log("Checking for update..."); -// }); autoUpdater.on("update-available", (ev) => { log.log("Update available.", ev); mainWindow.webContents.send(ipcTypes.app.toRenderer.updateAvailable, ev); @@ -261,10 +271,6 @@ autoUpdater.on("error", (ev, err) => { log.log("Error in auto-updater.", ev, err); }); -// // autoUpdater.on("update-downloaded", (ev, info) => { -// // console.log("Update downloaded; will install in 5 seconds"); -// // }); - function openNoticeWindow() { if (noticeWindow) { noticeWindow.focus(); @@ -318,6 +324,7 @@ autoUpdater.on("update-downloaded", (ev, info) => { if (buttonIndex === 0) { const isSilent = true; const isForceRunAfter = true; + store.set("showChangeLog", true); autoUpdater.quitAndInstall(isSilent, isForceRunAfter); } else { logger.error("Error"); diff --git a/hasura/config.yaml b/hasura/config.yaml index 5909335..3b809c2 100644 --- a/hasura/config.yaml +++ b/hasura/config.yaml @@ -1,2 +1 @@ -#endpoint: https://rps.bodyshop.app -endpoint: https://db.rps.imex.online +endpoint: https://rps.bodyshop.app diff --git a/hasura/migrations/1605053078816_modify_primarykey_public_associations/down.yaml b/hasura/migrations/1605053078816_modify_primarykey_public_associations/down.yaml new file mode 100644 index 0000000..27ddc0a --- /dev/null +++ b/hasura/migrations/1605053078816_modify_primarykey_public_associations/down.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: "alter table \"public\".\"associations\"\n add constraint \"associations_pkey\" + \n primary key ( \"bodyshopid\", \"email\" );" + type: run_sql diff --git a/hasura/migrations/1605053078816_modify_primarykey_public_associations/up.yaml b/hasura/migrations/1605053078816_modify_primarykey_public_associations/up.yaml new file mode 100644 index 0000000..772aa8e --- /dev/null +++ b/hasura/migrations/1605053078816_modify_primarykey_public_associations/up.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: alter table "public"."associations" drop constraint "associations_pkey"; + type: run_sql diff --git a/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/down.yaml b/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/down.yaml new file mode 100644 index 0000000..5d8e8a8 --- /dev/null +++ b/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."associations" DROP COLUMN "id"; + type: run_sql diff --git a/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/up.yaml b/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/up.yaml new file mode 100644 index 0000000..9b56fce --- /dev/null +++ b/hasura/migrations/1605053124904_alter_table_public_associations_add_column_id/up.yaml @@ -0,0 +1,11 @@ +- args: + cascade: false + read_only: false + sql: CREATE EXTENSION IF NOT EXISTS pgcrypto; + type: run_sql +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."associations" ADD COLUMN "id" uuid NULL UNIQUE DEFAULT + gen_random_uuid(); + type: run_sql diff --git a/hasura/migrations/1605053131947_modify_primarykey_public_associations/down.yaml b/hasura/migrations/1605053131947_modify_primarykey_public_associations/down.yaml new file mode 100644 index 0000000..772aa8e --- /dev/null +++ b/hasura/migrations/1605053131947_modify_primarykey_public_associations/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: alter table "public"."associations" drop constraint "associations_pkey"; + type: run_sql diff --git a/hasura/migrations/1605053131947_modify_primarykey_public_associations/up.yaml b/hasura/migrations/1605053131947_modify_primarykey_public_associations/up.yaml new file mode 100644 index 0000000..a0bf100 --- /dev/null +++ b/hasura/migrations/1605053131947_modify_primarykey_public_associations/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: "alter table \"public\".\"associations\"\n add constraint \"associations_pkey\" + \n primary key ( \"id\" );" + type: run_sql diff --git a/hasura/migrations/1605053139986_update_permission_user_public_table_associations/down.yaml b/hasura/migrations/1605053139986_update_permission_user_public_table_associations/down.yaml new file mode 100644 index 0000000..a078ae4 --- /dev/null +++ b/hasura/migrations/1605053139986_update_permission_user_public_table_associations/down.yaml @@ -0,0 +1,22 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - email + - bodyshopid + computed_fields: [] + filter: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: associations + schema: public + type: create_select_permission diff --git a/hasura/migrations/1605053139986_update_permission_user_public_table_associations/up.yaml b/hasura/migrations/1605053139986_update_permission_user_public_table_associations/up.yaml new file mode 100644 index 0000000..7bfbc75 --- /dev/null +++ b/hasura/migrations/1605053139986_update_permission_user_public_table_associations/up.yaml @@ -0,0 +1,23 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - bodyshopid + - email + - id + computed_fields: [] + filter: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: associations + schema: public + type: create_select_permission diff --git a/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/down.yaml b/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/down.yaml new file mode 100644 index 0000000..032a708 --- /dev/null +++ b/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."users" DROP COLUMN "id"; + type: run_sql diff --git a/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/up.yaml b/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/up.yaml new file mode 100644 index 0000000..2a4b2b5 --- /dev/null +++ b/hasura/migrations/1605053333239_alter_table_public_users_add_column_id/up.yaml @@ -0,0 +1,10 @@ +- args: + cascade: false + read_only: false + sql: CREATE EXTENSION IF NOT EXISTS pgcrypto; + type: run_sql +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."users" ADD COLUMN "id" uuid NULL UNIQUE DEFAULT gen_random_uuid(); + type: run_sql diff --git a/hasura/migrations/1605053392992_update_permission_user_public_table_users/down.yaml b/hasura/migrations/1605053392992_update_permission_user_public_table_users/down.yaml new file mode 100644 index 0000000..6613a78 --- /dev/null +++ b/hasura/migrations/1605053392992_update_permission_user_public_table_users/down.yaml @@ -0,0 +1,23 @@ +- args: + role: user + table: + name: users + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - authid + - email + - created_at + - updated_at + computed_fields: [] + filter: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: users + schema: public + type: create_select_permission diff --git a/hasura/migrations/1605053392992_update_permission_user_public_table_users/up.yaml b/hasura/migrations/1605053392992_update_permission_user_public_table_users/up.yaml new file mode 100644 index 0000000..a055b70 --- /dev/null +++ b/hasura/migrations/1605053392992_update_permission_user_public_table_users/up.yaml @@ -0,0 +1,24 @@ +- args: + role: user + table: + name: users + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - authid + - created_at + - email + - id + - updated_at + computed_fields: [] + filter: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: users + schema: public + type: create_select_permission diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index 171c7b2..97056b2 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -14,8 +14,9 @@ tables: - role: user permission: columns: - - email - bodyshopid + - email + - id filter: user: authid: @@ -316,8 +317,9 @@ tables: permission: columns: - authid - - email - created_at + - email + - id - updated_at filter: authid: diff --git a/package.json b/package.json index f2a446f..3d30c8f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "ImEX RPS", "author": "ImEX Systems Inc. ", "description": "ImEX RPS", - "version": "1.0.8", + "version": "1.0.9", "main": "electron/main.js", "homepage": "./", "dependencies": { diff --git a/src/components/molecules/release-notes/release-notes.molecule.jsx b/src/components/molecules/release-notes/release-notes.molecule.jsx new file mode 100644 index 0000000..6f118fc --- /dev/null +++ b/src/components/molecules/release-notes/release-notes.molecule.jsx @@ -0,0 +1,44 @@ +import { Modal } from "antd"; +import React, { useEffect } from "react"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import ipcTypes from "../../../ipc.types"; +import { setReleaseNotes } from "../../../redux/application/application.actions"; +import { selectReleaseNotes } from "../../../redux/application/application.selectors"; +const mapStateToProps = createStructuredSelector({ + releaseNotes: selectReleaseNotes, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) + setReleaseNotes: (notes) => dispatch(setReleaseNotes(notes)), +}); +const { ipcRenderer } = window; + +export function ReleaseNotes({ releaseNotes, setReleaseNotes }) { + console.log("ReleaseNotes -> releaseNotes", releaseNotes); + + useEffect(() => { + ipcRenderer.send(ipcTypes.default.app.toMain.getReleaseNotes); + }, []); + + const handleOk = () => { + ipcRenderer.send(ipcTypes.default.store.set, { showChangeLog: false }); + setReleaseNotes(null); + }; + + return ( + +
{releaseNotes && releaseNotes.date}
+
+ {releaseNotes && releaseNotes.notes} +
+
+ ); +} +export default connect(mapStateToProps, mapDispatchToProps)(ReleaseNotes); diff --git a/src/components/molecules/reporting-scatterchart/reporting-scatterchart.molecule.jsx b/src/components/molecules/reporting-scatterchart/reporting-scatterchart.molecule.jsx index c1fd722..5ecf75b 100644 --- a/src/components/molecules/reporting-scatterchart/reporting-scatterchart.molecule.jsx +++ b/src/components/molecules/reporting-scatterchart/reporting-scatterchart.molecule.jsx @@ -1,5 +1,11 @@ -import { Card, Skeleton, Typography, Tooltip as AntdToolTip } from "antd"; -import React from "react"; +import { + Card, + Radio, + Skeleton, + Tooltip as AntdToolTip, + Typography, +} from "antd"; +import React, { useState } from "react"; import { connect } from "react-redux"; import { CartesianGrid, @@ -24,19 +30,23 @@ const mapStateToProps = createStructuredSelector({ reportingLoading: selectReportLoading, scoreCard: selectScorecard, }); -const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) -}); +const mapDispatchToProps = (dispatch) => ({}); export default connect( mapStateToProps, mapDispatchToProps )(ReportingScatterChartMolecule); export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) { + const [type, setType] = useState("percent"); + if (reportingLoading) return ; if (!scoreCard) return ; + const handleTypeChange = (e) => { + setType(e.target.value); + }; + return (
- - % Variance from Target - +
+ {type === "percent" && ( + + + % Variance from Target + + + )} + {type === "dollars" && ( + + + $ Variance from Target + + + )} + + + % - Percent + $ - Dollars + +
- + {type === "percent" && ( + + )} + {type === "dollars" && ( + + )} + -
-
{item.owner} {item.vehicle} @@ -88,6 +132,12 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) { {item.dbPriceSum.toFormat()} + + {`${item.deviationPc}%`} + + + ${item.deviationDollars} + ); }} 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 066fe24..a7f69e8 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 @@ -54,6 +54,15 @@ export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard }) { value={((scoreCard.currentRpsPc || 0) * 100).toFixed(1)} suffix="%" /> +
- + diff --git a/src/graphql/jobs.queries.js b/src/graphql/jobs.queries.js index 03e7064..1077399 100644 --- a/src/graphql/jobs.queries.js +++ b/src/graphql/jobs.queries.js @@ -60,6 +60,7 @@ export const SEARCH_JOBS_PAGINATED = gql` ins_co_nm clm_no updated_at + close_date } search_jobs_aggregate( args: { enddate: $endDate, search: $search, startdate: $startDate } diff --git a/src/ipc.types.js b/src/ipc.types.js index c4ebd88..95bdd3f 100644 --- a/src/ipc.types.js +++ b/src/ipc.types.js @@ -12,11 +12,13 @@ exports.default = { checkForUpdates: "app_checkForUpdates", downloadUpdates: "app_downloadUpdates", installUpdates: "app_installupdates", + getReleaseNotes: "app_getReleaseNotes", }, toRenderer: { updateAvailable: "app_updateAvailable", downloadProgress: "app_downloadProgress", signOut: "app_signOut", + setReleaseNotes: "app_setReleaseNotes", }, }, store: { diff --git a/src/ipc/ipc-renderer-handler.js b/src/ipc/ipc-renderer-handler.js index 87faa92..1d47322 100644 --- a/src/ipc/ipc-renderer-handler.js +++ b/src/ipc/ipc-renderer-handler.js @@ -1,5 +1,6 @@ import ipcTypes from "../ipc.types"; import { + setReleaseNotes, setSettings, setUpdateAvailable, setUpdateProgress, @@ -89,3 +90,10 @@ ipcRenderer.on( store.dispatch(signOutStart()); } ); + +ipcRenderer.on( + ipcTypes.default.app.toRenderer.setReleaseNotes, + async (event, releaseNotes) => { + store.dispatch(setReleaseNotes(releaseNotes)); + } +); diff --git a/src/redux/application/application.actions.js b/src/redux/application/application.actions.js index 71c4a0c..e38f2b8 100644 --- a/src/redux/application/application.actions.js +++ b/src/redux/application/application.actions.js @@ -52,3 +52,8 @@ export const setUpdateProgress = (progress) => ({ type: ApplicationActionTypes.SET_UPDATE_PROGRESS, payload: progress, }); + +export const setReleaseNotes = (releaseNotes) => ({ + type: ApplicationActionTypes.SET_RELEASE_NOTES, + payload: releaseNotes, +}); diff --git a/src/redux/application/application.reducer.js b/src/redux/application/application.reducer.js index c4896cc..549bbcc 100644 --- a/src/redux/application/application.reducer.js +++ b/src/redux/application/application.reducer.js @@ -9,6 +9,7 @@ const INITIAL_STATE = { settings: {}, updateAvailable: false, updateProgress: null, + releaseNotes: null, }; const { ipcRenderer } = window; @@ -66,6 +67,8 @@ const applicationReducer = (state = INITIAL_STATE, action) => { return { ...state, updateAvailable: action.payload }; case ApplicationActionTypes.SET_UPDATE_PROGRESS: return { ...state, updateProgress: action.payload }; + case ApplicationActionTypes.SET_RELEASE_NOTES: + return { ...state, releaseNotes: action.payload }; default: return state; } diff --git a/src/redux/application/application.selectors.js b/src/redux/application/application.selectors.js index aad8463..729e391 100644 --- a/src/redux/application/application.selectors.js +++ b/src/redux/application/application.selectors.js @@ -36,7 +36,13 @@ export const selectUpdateAvailable = createSelector( [selectApplication], (application) => application.updateAvailable ); + export const selectUpdateProgress = createSelector( [selectApplication], (application) => application.updateProgress ); + +export const selectReleaseNotes = createSelector( + [selectApplication], + (application) => application.releaseNotes +); diff --git a/src/redux/application/application.types.js b/src/redux/application/application.types.js index 3e24870..bdb4e27 100644 --- a/src/redux/application/application.types.js +++ b/src/redux/application/application.types.js @@ -10,6 +10,6 @@ const ApplicationActionTypes = { SET_SETTINGS: "SET_SETTINGS", SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE", SET_UPDATE_PROGRESS: "SET_UPDATE_PROGRESS", - + SET_RELEASE_NOTES: "SET_RELEASE_NOTES", }; export default ApplicationActionTypes; diff --git a/src/redux/reporting/reporting.sagas.js b/src/redux/reporting/reporting.sagas.js index 7af6c47..f22c7f9 100644 --- a/src/redux/reporting/reporting.sagas.js +++ b/src/redux/reporting/reporting.sagas.js @@ -102,8 +102,13 @@ export function* handleCalculateScoreCard({ payload: jobs }) { actPriceSum ); + const deviationPc = Math.round((jobRpsPc - jobTarget) * 1000) / 10; + scoreCard.scatterChart[job.group].push({ - deviation: Math.round((jobRpsPc - jobTarget) * 1000) / 10, + deviationPc: isNaN(deviationPc) ? -100 : deviationPc, + deviationDollars: ( + jobRpsDollars.subtract(expectedRpsDollars).getAmount() / 100 + ).toFixed(2), age: job.v_age, dbPriceSum, dbPriceSumAmt: dbPriceSum.getAmount() / 100, @@ -112,7 +117,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, + jobRpsPc: isNaN(jobRpsPc) ? -1 : jobRpsPc, }); //sum db price * percentage expected. @@ -131,16 +136,14 @@ export function* handleCalculateScoreCard({ payload: jobs }) { scoreCard.shopRpsExpectedDollars ); - scoreCard.variancePc = - scoreCard.varianceDollars.getAmount() / - scoreCard.shopRpsExpectedDollars.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. yield put(setScoreCard(scoreCard)); yield put(setReportingData(jobs));