From 4d5d370ccf7e7550ba0af32a4721c7a28759f78a Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Mon, 19 Oct 2020 07:38:26 -0700 Subject: [PATCH] Added graphs, fixed rps total calculation --- electron/decoder/decoder.js | 37 +++- electron/electron-store.js | 2 +- electron/file-watcher/file-watcher.js | 5 +- electron/ipc-main-handler.js | 6 + .../down.yaml | 5 + .../up.yaml | 6 + .../down.yaml | 26 +++ .../up.yaml | 27 +++ hasura/migrations/metadata.yaml | 1 + package-lock.json | 186 ++++++++++++++++++ package.json | 1 + .../jobs-parts-graph.atom.jsx | 79 ++++++++ .../jobs-lines-table.molecule.jsx | 2 +- .../jobs-targets-stats.molecule.jsx | 28 ++- .../jobs-detail/jobs-detail.organism.jsx | 20 +- .../jobs-list/jobs-list.organism.jsx | 2 +- src/graphql/bodyshop.queries.js | 1 + src/graphql/jobs.queries.js | 3 +- src/ipc.types.js | 5 + src/redux/user/user.sagas.js | 5 +- 20 files changed, 416 insertions(+), 31 deletions(-) create mode 100644 hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/down.yaml create mode 100644 hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/up.yaml create mode 100644 hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/down.yaml create mode 100644 hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/up.yaml create mode 100644 src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx diff --git a/electron/decoder/decoder.js b/electron/decoder/decoder.js index 448ac7b..c4f053a 100644 --- a/electron/decoder/decoder.js +++ b/electron/decoder/decoder.js @@ -2,6 +2,7 @@ const { DBFFile } = require("dbffile"); const path = require("path"); const _ = require("lodash"); const log = require("electron-log"); +const { store } = require("../electron-store"); async function DecodeEstimate(filePath) { const parsedFilePath = path.parse(filePath); @@ -9,18 +10,34 @@ async function DecodeEstimate(filePath) { parsedFilePath.dir, parsedFilePath.name ); - const ret = { + const job = { ...(await DecodeAd1File(extensionlessFilePath)), ...(await DecodeVehFile(extensionlessFilePath)), ...(await DecodeTtlFile(extensionlessFilePath)), ...(await DecodeLinFile(extensionlessFilePath)), }; - if (ret.V_MILEAGE > 20000) - return _.transform(ret, function (result, val, key) { + const ad2 = await DecodeAd2File(extensionlessFilePath); + + if (job.OWNR_FN === "") job.OWNR_FN = ad2.CLMT_FN; + if (job.OWNR_LN === "") job.OWNR_LN = ad2.CLMT_LN; + + 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)) { + returnValue = { + ERROR: `Insurance Company Name is not valid for RPS. (${job.INS_CO_NM})`, + }; + } else { + returnValue = _.transform(job, function (result, val, key) { result[key.toLowerCase()] = val; }); - return null; + } + + return returnValue; } async function DecodeAd1File(extensionlessFilePath) { @@ -144,6 +161,13 @@ async function DecodeAd1File(extensionlessFilePath) { // "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"]); +} + async function DecodeVehFile(extensionlessFilePath) { let dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`); let records = await dbf.readRecords(1); @@ -299,6 +323,11 @@ async function DecodeLinFile(extensionlessFilePath) { (jobline) => jobline.part_type && !jobline.db_ref.startsWith("900") && + !jobline.db_ref.toLowerCase().startsWith("urethane") && + !jobline.db_ref.toLowerCase().startsWith("wheel") && + !jobline.db_ref.toLowerCase().startsWith("hazardous") && + !jobline.db_ref.toLowerCase().startsWith("detail") && + !jobline.db_ref.toLowerCase().startsWith("clean") && jobline.part_type.toUpperCase() !== "PAG" && jobline.part_type.toUpperCase() !== "PAS" && jobline.part_type.toUpperCase() !== "PASL" && diff --git a/electron/electron-store.js b/electron/electron-store.js index 4e62a8a..9d59c9c 100644 --- a/electron/electron-store.js +++ b/electron/electron-store.js @@ -1,5 +1,5 @@ const Store = require("electron-store"); -const store = new Store({ defaults: { filePaths: [] } }); +const store = new Store({ defaults: { filePaths: [], accepted_ins_co: [] } }); exports.store = store; diff --git a/electron/file-watcher/file-watcher.js b/electron/file-watcher/file-watcher.js index edde955..edb58d6 100644 --- a/electron/file-watcher/file-watcher.js +++ b/electron/file-watcher/file-watcher.js @@ -106,7 +106,7 @@ async function HandleNewFile(path) { b.webContents.send(ipcTypes.default.estimate.toRenderer.estimateDecodeStart); const newJob = await DecodeEstimate(path); - if (newJob && newJob) { + if (newJob && !newJob.ERROR) { b.webContents.send( ipcTypes.default.estimate.toRenderer.estimateDecodeSuccess, newJob @@ -119,8 +119,7 @@ async function HandleNewFile(path) { } else { NewNotification({ title: "Job Ignored", - body: - "The job was not uploaded because it does not meet RPS requirements.", + body: newJob.ERROR, }).show(); } } diff --git a/electron/ipc-main-handler.js b/electron/ipc-main-handler.js index e1783fd..6c69626 100644 --- a/electron/ipc-main-handler.js +++ b/electron/ipc-main-handler.js @@ -1,4 +1,6 @@ const { ipcMain } = require("electron"); +const { default: ipcTypes } = require("../src/ipc.types"); +const { store } = require("./electron-store"); const { mainWindow } = require("./main"); //Import Ipc Handlers require("./file-watcher/file-watcher-ipc"); @@ -11,3 +13,7 @@ ipcMain.on("test", async (event, object) => { console.log(mainWindow); event.reply("test-toRenderer", { status: 0, message: null }); }); + +ipcMain.on(ipcTypes.app.toMain.setAcceptableInsCoNm, (event, insCos) => { + store.set("accepted_ins_co", insCos); +}); diff --git a/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/down.yaml b/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/down.yaml new file mode 100644 index 0000000..05743ac --- /dev/null +++ b/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "accepted_ins_co"; + type: run_sql diff --git a/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/up.yaml b/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/up.yaml new file mode 100644 index 0000000..4453703 --- /dev/null +++ b/hasura/migrations/1602889815353_alter_table_public_bodyshops_add_column_accepted_ins_co/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "accepted_ins_co" jsonb NULL + DEFAULT jsonb_build_array(); + type: run_sql diff --git a/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/down.yaml new file mode 100644 index 0000000..a777f71 --- /dev/null +++ b/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/down.yaml @@ -0,0 +1,26 @@ +- args: + role: user + table: + name: bodyshops + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - created_at + - id + - shopname + - targets + - updated_at + computed_fields: [] + filter: + associations: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: bodyshops + schema: public + type: create_select_permission diff --git a/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/up.yaml new file mode 100644 index 0000000..c82a190 --- /dev/null +++ b/hasura/migrations/1602889830378_update_permission_user_public_table_bodyshops/up.yaml @@ -0,0 +1,27 @@ +- args: + role: user + table: + name: bodyshops + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - accepted_ins_co + - created_at + - id + - shopname + - targets + - updated_at + computed_fields: [] + filter: + associations: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: bodyshops + schema: public + type: create_select_permission diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index eb3f498..35df80b 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -42,6 +42,7 @@ tables: - role: user permission: columns: + - accepted_ins_co - created_at - id - shopname diff --git a/package-lock.json b/package-lock.json index 2b5b10e..a264126 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6313,6 +6313,73 @@ "type": "^1.0.1" } }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "requires": { + "d3-time": "1" + } + }, "damerau-levenshtein": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", @@ -6394,6 +6461,11 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -6726,6 +6798,14 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -12204,6 +12284,11 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, "lodash.escape": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", @@ -12248,6 +12333,11 @@ "lodash._reinterpolate": "^3.0.0" } }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -12372,6 +12462,11 @@ "escape-string-regexp": "^4.0.0" } }, + "math-expression-evaluator": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz", + "integrity": "sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -16115,6 +16210,17 @@ "react-is": "^16.9.0" } }, + "react-resize-detector": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz", + "integrity": "sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==", + "requires": { + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.6.0", + "resize-observer-polyfill": "^1.5.0" + } + }, "react-router": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", @@ -16249,6 +16355,17 @@ } } }, + "react-smooth": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-1.0.5.tgz", + "integrity": "sha512-eW057HT0lFgCKh8ilr0y2JaH2YbNcuEdFpxyg7Gf/qDKk9hqGMyXryZJ8iMGJEuKH0+wxS0ccSsBBB3W8yCn8w==", + "requires": { + "lodash": "~4.17.4", + "prop-types": "^15.6.0", + "raf": "^3.4.0", + "react-transition-group": "^2.5.0" + } + }, "react-test-renderer": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.13.1.tgz", @@ -16261,6 +16378,17 @@ "scheduler": "^0.19.1" } }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, "read-config-file": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.0.0.tgz", @@ -16333,6 +16461,39 @@ "util.promisify": "^1.0.0" } }, + "recharts": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-1.8.5.tgz", + "integrity": "sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg==", + "requires": { + "classnames": "^2.2.5", + "core-js": "^2.6.10", + "d3-interpolate": "^1.3.0", + "d3-scale": "^2.1.0", + "d3-shape": "^1.2.0", + "lodash": "^4.17.5", + "prop-types": "^15.6.0", + "react-resize-detector": "^2.3.0", + "react-smooth": "^1.0.5", + "recharts-scale": "^0.4.2", + "reduce-css-calc": "^1.3.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + } + } + }, + "recharts-scale": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.3.tgz", + "integrity": "sha512-t8p5sccG9Blm7c1JQK/ak9O8o95WGhNXD7TXg/BW5bYbVlr6eCeRBNpgyigD4p6pSSMehC5nSvBUPj6F68rbFA==", + "requires": { + "decimal.js-light": "^2.4.1" + } + }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -16350,6 +16511,31 @@ "strip-indent": "^1.0.1" } }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "requires": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "requires": { + "balanced-match": "^1.0.0" + } + }, "redux": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", diff --git a/package.json b/package.json index d5d51a3..51924e9 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "react-redux": "^7.2.1", "react-router-dom": "^5.2.0", "react-scripts": "3.4.3", + "recharts": "^1.8.5", "redux": "^4.0.5", "redux-persist": "^6.0.0", "redux-saga": "^1.1.3", 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 new file mode 100644 index 0000000..0ee2684 --- /dev/null +++ b/src/components/atoms/jobs-parts-graph/jobs-parts-graph.atom.jsx @@ -0,0 +1,79 @@ +import { Skeleton, Typography } from "antd"; +import React, { useMemo } from "react"; +import { Cell, Pie, PieChart, ResponsiveContainer } from "recharts"; +import ErrorResultAtom from "../error-result/error-result.atom"; +import Dinero from "dinero.js"; +export default function JobPartsGraphAtom({ + job, + loading, + price = "act_price", +}) { + const data = useMemo(() => { + if (!job) return []; + + const sums = job.joblines.reduce((acc, val) => { + if (!acc[val.part_type]) { + acc[val.part_type] = Dinero(); + } + + acc[val.part_type] = acc[val.part_type].add( + Dinero({ amount: Math.round((val[price] || 0) * 100) }) + ); + + return acc; + }, {}); + + return Object.keys(sums).map((key) => { + return { + name: key, + value: sums[key].getAmount() / 100, + label: sums[key].toFormat(), + color: getColor(key), + }; + }); + }, [job, price]); + + if (loading) return ; + if (!job) return ; + + return ( +
+ + {price === "act_price" ? "Actual Price" : "Database Price"} + + + + `${entry.name} - ${entry.label}`} + labelLine + > + {data.map((entry, index) => ( + + ))} + + + +
+ ); +} + +const getColor = (key) => { + switch (key) { + case "PAA": + return "tomato"; + case "PAL": + return "dodgeblue"; + case "PAN": + return "seagreen"; + default: + return "slategray"; + } +}; 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 ddac46a..93bc08c 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 @@ -84,7 +84,7 @@ export default function JobLinesTableMolecule({ loading, job }) { dataSource={joblines} scroll={{ x: true, - //y: "40rem" + y: "20rem", }} /> 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 3946596..71e90d2 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 @@ -1,28 +1,15 @@ -import { Skeleton, Space, Statistic } from "antd"; +import { Skeleton, Statistic } from "antd"; +import Dinero from "dinero.js"; import React, { useMemo } from "react"; import ErrorResultAtom from "../../atoms/error-result/error-result.atom"; import TargetPriceDiffPcAtom from "../../atoms/target-price-diff/target-price-diff-pc.atom"; -import _ from "lodash"; -import Dinero from "dinero.js"; export default function JobsTargetsStatsMolecule({ loading, job }) { - const currentRpsPc = useMemo(() => { - if (!job) { - return 0; - } - return ( - (_.sum(job.joblines.map((jl) => jl.price_diff_pc)) / - job.joblines.length) * - 100 - ).toFixed(1); - }, [job]); - const currentRpsDollars = useMemo(() => { if (!job) { return 0; } return job.joblines.reduce((acc, val) => { - console.log("val.price_diff :>> ", val.price_diff); if (val.price_diff > 0) { return acc.add( Dinero({ amount: Math.round((val.price_diff || 0) * 100) }) @@ -33,6 +20,17 @@ export default function JobsTargetsStatsMolecule({ loading, job }) { }, Dinero()); }, [job]); + const currentRpsPc = useMemo(() => { + //TODO Redo this to do total of db price - act price / db price + if (!job) { + return 0; + } + const dbPriceSum = job.joblines.reduce((acc, val) => { + return acc + val.db_price; + }, 0); + return (currentRpsDollars.getAmount() / dbPriceSum).toFixed(1); + }, [job, currentRpsDollars]); + if (loading) return ; if (!job) return ; diff --git a/src/components/organisms/jobs-detail/jobs-detail.organism.jsx b/src/components/organisms/jobs-detail/jobs-detail.organism.jsx index 2bb2c0b..0711337 100644 --- a/src/components/organisms/jobs-detail/jobs-detail.organism.jsx +++ b/src/components/organisms/jobs-detail/jobs-detail.organism.jsx @@ -6,6 +6,7 @@ import { createStructuredSelector } from "reselect"; import { QUERY_JOB_BY_PK } from "../../../graphql/jobs.queries"; import { selectSelectedJobId } from "../../../redux/application/application.selectors"; import ErrorResultAtom from "../../atoms/error-result/error-result.atom"; +import JobsPartsGraphAtom from "../../atoms/jobs-parts-graph/jobs-parts-graph.atom"; import JobsDetailDescriptionMolecule from "../../molecules/jobs-detail-description/jobs-detail-description.molecule"; import JobsLinesTableMolecule from "../../molecules/jobs-lines-table/jobs-lines-table.molecule"; import JobsTargetsStatsMolecule from "../../molecules/jobs-targets-stats/jobs-targets-stats.molecule"; @@ -40,14 +41,25 @@ export function JobsDetailOrganism({ selectedJobId }) { loading={loading} job={data ? data.jobs_by_pk : null} /> - + +
+ + +
); } diff --git a/src/components/organisms/jobs-list/jobs-list.organism.jsx b/src/components/organisms/jobs-list/jobs-list.organism.jsx index 13e80f4..aaef63a 100644 --- a/src/components/organisms/jobs-list/jobs-list.organism.jsx +++ b/src/components/organisms/jobs-list/jobs-list.organism.jsx @@ -1,6 +1,6 @@ import { SyncOutlined } from "@ant-design/icons"; import { useQuery } from "@apollo/client"; -import { Button, Divider, List, Space, Spin } from "antd"; +import { Button, List, Spin } from "antd"; import React, { useState } from "react"; import InfiniteScroll from "react-infinite-scroller"; import { connect } from "react-redux"; diff --git a/src/graphql/bodyshop.queries.js b/src/graphql/bodyshop.queries.js index 45e3d8c..6e69a35 100644 --- a/src/graphql/bodyshop.queries.js +++ b/src/graphql/bodyshop.queries.js @@ -5,6 +5,7 @@ export const QUERY_BODYSHOP = gql` id shopname targets + accepted_ins_co } } `; diff --git a/src/graphql/jobs.queries.js b/src/graphql/jobs.queries.js index c2574d3..05e3c6b 100644 --- a/src/graphql/jobs.queries.js +++ b/src/graphql/jobs.queries.js @@ -70,7 +70,8 @@ export const QUERY_JOB_BY_PK = gql` updated_at group v_age - joblines(order_by: { unq_seq: asc }) { + loss_date + joblines(order_by: { line_no: asc }) { id act_price db_price diff --git a/src/ipc.types.js b/src/ipc.types.js index 50b067e..db36934 100644 --- a/src/ipc.types.js +++ b/src/ipc.types.js @@ -4,6 +4,11 @@ exports.default = { test: { start: "test-start", }, + app: { + toMain: { + setAcceptableInsCoNm: "setAcceptableInsCoNm", + }, + }, fileWatcher: { toMain: { filepathsGet: "filewatcher__filepathsget", diff --git a/src/redux/user/user.sagas.js b/src/redux/user/user.sagas.js index f0e602c..77b4075 100644 --- a/src/redux/user/user.sagas.js +++ b/src/redux/user/user.sagas.js @@ -113,7 +113,10 @@ export function* signInSuccessSaga({ payload }) { const shop = yield client.query({ query: QUERY_BODYSHOP }); yield put(setBodyshop(shop.data.bodyshops[0])); - + ipcRenderer.send( + ipcTypes.default.app.toMain.setAcceptableInsCoNm, + shop.data.bodyshops[0].accepted_ins_co + ); ipcRenderer.send(ipcTypes.default.fileWatcher.toMain.start); // LogRocket.identify(payload.email); // if (!payload.email.includes("@imex.")) yield put(setInstanceId(payload.uid));