Additional Changes for calculations of RPS %.
This commit is contained in:
@@ -184,76 +184,128 @@ async function DecodeTtlFile(extensionlessFilePath) {
|
||||
async function DecodeLinFile(extensionlessFilePath) {
|
||||
let dbf = await DBFFile.open(`${extensionlessFilePath}.LIN`);
|
||||
let records = await dbf.readRecords();
|
||||
let joblines = records.map((record) =>
|
||||
_.transform(
|
||||
_.pick(record, [
|
||||
"LINE_NO",
|
||||
"LINE_IND",
|
||||
// "LINE_REF",
|
||||
// "TRAN_CODE",
|
||||
"DB_REF",
|
||||
"UNQ_SEQ",
|
||||
// "WHO_PAYS",
|
||||
"LINE_DESC",
|
||||
"PART_TYPE",
|
||||
// "PART_DESCJ",
|
||||
"GLASS_FLAG",
|
||||
"OEM_PARTNO",
|
||||
// "PRICE_INC",
|
||||
// "ALT_PART_I",
|
||||
// "TAX_PART",
|
||||
"DB_PRICE",
|
||||
"ACT_PRICE",
|
||||
// "PRICE_J",
|
||||
// "CERT_PART",
|
||||
"PART_QTY",
|
||||
// "ALT_CO_ID",
|
||||
// "ALT_PARTNO",
|
||||
// "ALT_OVERRD",
|
||||
// "ALT_PARTM",
|
||||
// "PRT_DSMK_P",
|
||||
// "PRT_DSMK_M",
|
||||
// "MOD_LBR_TY",
|
||||
// "DB_HRS",
|
||||
// "MOD_LB_HRS",
|
||||
// "LBR_INC",
|
||||
// "LBR_OP",
|
||||
// "LBR_HRS_J",
|
||||
// "LBR_TYP_J",
|
||||
// "LBR_OP_J",
|
||||
// "PAINT_STG",
|
||||
// "PAINT_TONE",
|
||||
// "LBR_TAX",
|
||||
// "LBR_AMT",
|
||||
// "MISC_AMT",
|
||||
// "MISC_SUBLT",
|
||||
// "MISC_TAX",
|
||||
// "BETT_TYPE",
|
||||
// "BETT_PCTG",
|
||||
// "BETT_AMT",
|
||||
// "BETT_TAX",
|
||||
]),
|
||||
function (result, val, key) {
|
||||
//Required because unq_seq gets pulled as a numeric instaed of a string.
|
||||
console.log("key", key);
|
||||
if (key === "UNQ_SEQ") {
|
||||
return (result[key.toLowerCase()] = val.toString());
|
||||
}
|
||||
return (result[key.toLowerCase()] = val);
|
||||
}
|
||||
)
|
||||
);
|
||||
let joblines = records
|
||||
.map((record) => {
|
||||
console.log(
|
||||
"object",
|
||||
_.pick(record, [
|
||||
"LINE_NO",
|
||||
"LINE_IND",
|
||||
// "LINE_REF",
|
||||
// "TRAN_CODE",
|
||||
"DB_REF",
|
||||
"UNQ_SEQ",
|
||||
// "WHO_PAYS",
|
||||
"LINE_DESC",
|
||||
"PART_TYPE",
|
||||
// "PART_DESCJ",
|
||||
"GLASS_FLAG",
|
||||
"OEM_PARTNO",
|
||||
// "PRICE_INC",
|
||||
// "ALT_PART_I",
|
||||
// "TAX_PART",
|
||||
"DB_PRICE",
|
||||
"ACT_PRICE",
|
||||
// "PRICE_J",
|
||||
// "CERT_PART",
|
||||
"PART_QTY",
|
||||
// "ALT_CO_ID",
|
||||
// "ALT_PARTNO",
|
||||
// "ALT_OVERRD",
|
||||
// "ALT_PARTM",
|
||||
// "PRT_DSMK_P",
|
||||
// "PRT_DSMK_M",
|
||||
// "MOD_LBR_TY",
|
||||
// "DB_HRS",
|
||||
// "MOD_LB_HRS",
|
||||
// "LBR_INC",
|
||||
// "LBR_OP",
|
||||
// "LBR_HRS_J",
|
||||
// "LBR_TYP_J",
|
||||
// "LBR_OP_J",
|
||||
// "PAINT_STG",
|
||||
// "PAINT_TONE",
|
||||
// "LBR_TAX",
|
||||
// "LBR_AMT",
|
||||
// "MISC_AMT",
|
||||
// "MISC_SUBLT",
|
||||
// "MISC_TAX",
|
||||
// "BETT_TYPE",
|
||||
// "BETT_PCTG",
|
||||
// "BETT_AMT",
|
||||
// "BETT_TAX",
|
||||
])
|
||||
);
|
||||
return _.transform(
|
||||
_.pick(record, [
|
||||
"LINE_NO",
|
||||
"LINE_IND",
|
||||
// "LINE_REF",
|
||||
// "TRAN_CODE",
|
||||
"DB_REF",
|
||||
"UNQ_SEQ",
|
||||
// "WHO_PAYS",
|
||||
"LINE_DESC",
|
||||
"PART_TYPE",
|
||||
// "PART_DESCJ",
|
||||
|
||||
const m = joblines
|
||||
"OEM_PARTNO",
|
||||
// "PRICE_INC",
|
||||
// "ALT_PART_I",
|
||||
// "TAX_PART",
|
||||
"DB_PRICE",
|
||||
"ACT_PRICE",
|
||||
// "PRICE_J",
|
||||
// "CERT_PART",
|
||||
"PART_QTY",
|
||||
// "ALT_CO_ID",
|
||||
// "ALT_PARTNO",
|
||||
// "ALT_OVERRD",
|
||||
// "ALT_PARTM",
|
||||
// "PRT_DSMK_P",
|
||||
// "PRT_DSMK_M",
|
||||
// "MOD_LBR_TY",
|
||||
// "DB_HRS",
|
||||
// "MOD_LB_HRS",
|
||||
// "LBR_INC",
|
||||
// "LBR_OP",
|
||||
// "LBR_HRS_J",
|
||||
// "LBR_TYP_J",
|
||||
// "LBR_OP_J",
|
||||
// "PAINT_STG",
|
||||
// "PAINT_TONE",
|
||||
// "LBR_TAX",
|
||||
// "LBR_AMT",
|
||||
// "MISC_AMT",
|
||||
// "MISC_SUBLT",
|
||||
// "MISC_TAX",
|
||||
// "BETT_TYPE",
|
||||
// "BETT_PCTG",
|
||||
// "BETT_AMT",
|
||||
// "BETT_TAX",
|
||||
"GLASS_FLAG",
|
||||
]),
|
||||
function (result, val, key) {
|
||||
//Required because unq_seq gets pulled as a numeric instaed of a string.
|
||||
console.log("key", key);
|
||||
if (key === "UNQ_SEQ") {
|
||||
return (result[key.toLowerCase()] = val.toString());
|
||||
}
|
||||
return (result[key.toLowerCase()] = val);
|
||||
}
|
||||
);
|
||||
})
|
||||
.filter(
|
||||
(jobline) =>
|
||||
jobline.PART_TYPE &&
|
||||
jobline.part_type &&
|
||||
!jobline.db_ref.startsWith("900") &&
|
||||
(jobline.part_type && jobline.part_type.toUpperCase()) !== "PAG" &&
|
||||
jobline.part_type.toUpperCase() !== "PAG" &&
|
||||
jobline.part_type.toUpperCase() !== "PAS" &&
|
||||
jobline.part_type.toUpperCase() !== "PASL" &&
|
||||
jobline.part_type.toUpperCase() !== "PAE" &&
|
||||
jobline.glass_flag === false
|
||||
)
|
||||
.map((jobline) => {
|
||||
console.log("Massagejobline", jobline);
|
||||
if (
|
||||
(jobline.db_price === null || jobline.db_price === 0) &&
|
||||
!!jobline.act_price &&
|
||||
@@ -285,7 +337,6 @@ async function DecodeLinFile(extensionlessFilePath) {
|
||||
}
|
||||
|
||||
delete jobline.glass_flag;
|
||||
console.log(jobline);
|
||||
return jobline;
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ const ipcTypes = require("../../src/ipc.types");
|
||||
const path = require("path");
|
||||
const { DecodeEstimate } = require("../decoder/decoder");
|
||||
const { BrowserWindow } = require("electron");
|
||||
const _ = require("lodash");
|
||||
const { store } = require("../electron-store");
|
||||
const {
|
||||
NewNotification,
|
||||
@@ -26,7 +25,7 @@ async function StartWatcher() {
|
||||
|
||||
if (watcher) {
|
||||
try {
|
||||
console.log("Trying to close watcher - it already existed.111");
|
||||
console.log("Trying to close watcher - it already existed.");
|
||||
await watcher.close();
|
||||
|
||||
console.log("Watcher closed successfully!");
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."targets";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,23 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
type: run_sql
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE TABLE \"public\".\"targets\"(\"id\" uuid NOT NULL DEFAULT gen_random_uuid(),
|
||||
\"updated_at\" timestamptz NOT NULL DEFAULT now(), \"created_at\" timestamptz
|
||||
NOT NULL DEFAULT now(), \"label\" text NOT NULL, \"config\" jsonb NOT NULL DEFAULT
|
||||
jsonb_build_object(), \"start_date\" date NOT NULL, \"end_date\" date, PRIMARY
|
||||
KEY (\"id\") );\nCREATE OR REPLACE FUNCTION \"public\".\"set_current_timestamp_updated_at\"()\nRETURNS
|
||||
TRIGGER AS $$\nDECLARE\n _new record;\nBEGIN\n _new := NEW;\n _new.\"updated_at\"
|
||||
= NOW();\n RETURN _new;\nEND;\n$$ LANGUAGE plpgsql;\nCREATE TRIGGER \"set_public_targets_updated_at\"\nBEFORE
|
||||
UPDATE ON \"public\".\"targets\"\nFOR EACH ROW\nEXECUTE PROCEDURE \"public\".\"set_current_timestamp_updated_at\"();\nCOMMENT
|
||||
ON TRIGGER \"set_public_targets_updated_at\" ON \"public\".\"targets\" \nIS
|
||||
'trigger to set value of column \"updated_at\" to current timestamp on row update';"
|
||||
type: run_sql
|
||||
- args:
|
||||
name: targets
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: targets
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,20 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- id
|
||||
- updated_at
|
||||
- created_at
|
||||
- label
|
||||
- config
|
||||
- start_date
|
||||
- end_date
|
||||
computed_fields: []
|
||||
filter: {}
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: targets
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."targets";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "targets";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "targets" jsonb NULL DEFAULT
|
||||
jsonb_build_object();
|
||||
type: run_sql
|
||||
@@ -0,0 +1,25 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- shopname
|
||||
computed_fields: []
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
@@ -0,0 +1,16 @@
|
||||
- args:
|
||||
permission:
|
||||
backend_only: false
|
||||
columns:
|
||||
- targets
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -42,15 +42,27 @@ tables:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- shopname
|
||||
- targets
|
||||
- updated_at
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- targets
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
- table:
|
||||
schema: public
|
||||
name: joblines
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
import "./price-diff-pc-formatter.styles.scss";
|
||||
import { AlertFilled } from "@ant-design/icons";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function PriceDiffPcFormatterAtom({
|
||||
bodyshop,
|
||||
price_diff_pc,
|
||||
group,
|
||||
v_age,
|
||||
}) {
|
||||
const metTarget = useMemo(() => {
|
||||
const targetsForGroup = bodyshop.targets[group];
|
||||
if (!targetsForGroup) return 0;
|
||||
const targetPc = targetsForGroup.filter(
|
||||
(t) => t.ageGte <= v_age && (t.ageLt ? t.ageLt > v_age : true)
|
||||
);
|
||||
if (targetPc.length === 0) return false;
|
||||
else if (targetPc.length === 1) return price_diff_pc >= targetPc[0].target;
|
||||
else {
|
||||
alert("Multiple targets match.");
|
||||
return false;
|
||||
}
|
||||
}, [bodyshop, group, price_diff_pc, v_age]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
color: metTarget ? "green" : "red",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{(price_diff_pc * 100).toFixed(1)}%
|
||||
{price_diff_pc === 1 ? (
|
||||
<AlertFilled style={{ color: "tomato" }} className="blink_me" />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PriceDiffPcFormatterAtom);
|
||||
@@ -0,0 +1,9 @@
|
||||
.blink_me {
|
||||
animation: blinker 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Statistic } from "antd";
|
||||
import React, { useMemo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function PriceDiffPcFormatterAtom({ bodyshop, group, v_age }) {
|
||||
const metTarget = useMemo(() => {
|
||||
const targetsForGroup = bodyshop.targets[group];
|
||||
if (!targetsForGroup) return 0;
|
||||
const targetPc = targetsForGroup.filter(
|
||||
(t) => t.ageGte <= v_age && (t.ageLt ? t.ageLt > v_age : true)
|
||||
);
|
||||
if (targetPc.length === 0) return 0;
|
||||
else if (targetPc.length === 1) return targetPc[0].target;
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}, [bodyshop, group, v_age]);
|
||||
|
||||
return (
|
||||
<Statistic
|
||||
title="Target RPS %"
|
||||
value={(metTarget * 100).toFixed(1)}
|
||||
suffix="%"
|
||||
/>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PriceDiffPcFormatterAtom);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Descriptions, Skeleton } from "antd";
|
||||
import { Descriptions, PageHeader, Skeleton } from "antd";
|
||||
import React from "react";
|
||||
import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
@@ -10,24 +10,17 @@ export default function JobsDetailDescriptionMolecule({ loading, job }) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Descriptions
|
||||
title={`${job.clm_no}${job.ins_co_nm ? ` | ${job.ins_co_nm}` : ""}`}
|
||||
bordered
|
||||
layout="vertical"
|
||||
column={{ xxl: 5, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }}
|
||||
>
|
||||
<Descriptions.Item label="Claim No.">{job.clm_no}</Descriptions.Item>
|
||||
<Descriptions.Item label="Ins Co. Nm.">
|
||||
{job.ins_co_nm}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Owner">{`${job.ownr_fn} ${job.ownr_ln}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Vehicle">{`${job.v_model_yr} ${job.v_makedesc} ${job.v_model}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Claim Total">
|
||||
<CurrencyFormatterAtom>{job.clm_total}</CurrencyFormatterAtom>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Group">{job.group}</Descriptions.Item>
|
||||
<Descriptions.Item label="Age">{job.v_age}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<PageHeader ghost={false} title={job.clm_no} subTitle={job.ins_co_nm}>
|
||||
<Descriptions column={{ xxl: 5, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }}>
|
||||
<Descriptions.Item label="Owner">{`${job.ownr_fn} ${job.ownr_ln}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Vehicle">{`${job.v_model_yr} ${job.v_makedesc} ${job.v_model}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Claim Total">
|
||||
<CurrencyFormatterAtom>{job.clm_total}</CurrencyFormatterAtom>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Group">{job.group}</Descriptions.Item>
|
||||
<Descriptions.Item label="Age">{job.v_age}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Table } from "antd";
|
||||
import React from "react";
|
||||
import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom";
|
||||
import PriceDiffPcFormatterAtom from "../../atoms/price-diff-pc-formatter/price-diff-pc-formatter.atom";
|
||||
|
||||
export default function JobLinesTableMolecule({ loading, jobLines }) {
|
||||
export default function JobLinesTableMolecule({ loading, job }) {
|
||||
const { joblines } = job;
|
||||
const columns = [
|
||||
{
|
||||
title: "#",
|
||||
@@ -48,9 +50,26 @@ export default function JobLinesTableMolecule({ loading, jobLines }) {
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Qty.",
|
||||
dataIndex: "part_qty",
|
||||
key: "part_qty",
|
||||
title: "Price Diff.",
|
||||
dataIndex: "price_diff",
|
||||
key: "price_diff",
|
||||
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatterAtom>{record.price_diff}</CurrencyFormatterAtom>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Price Diff. %",
|
||||
dataIndex: "price_diff_pc",
|
||||
key: "price_diff_pc",
|
||||
|
||||
render: (text, record) => (
|
||||
<PriceDiffPcFormatterAtom
|
||||
price_diff_pc={record.price_diff_pc}
|
||||
v_age={job.v_age}
|
||||
group={job.group}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -62,7 +81,7 @@ export default function JobLinesTableMolecule({ loading, jobLines }) {
|
||||
loading={loading}
|
||||
size="small"
|
||||
pagination={false}
|
||||
dataSource={jobLines}
|
||||
dataSource={joblines}
|
||||
scroll={{
|
||||
x: true,
|
||||
//y: "40rem"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Skeleton, Space, Statistic } from "antd";
|
||||
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) })
|
||||
);
|
||||
} else {
|
||||
return acc;
|
||||
}
|
||||
}, Dinero());
|
||||
}, [job]);
|
||||
|
||||
if (loading) return <Skeleton active />;
|
||||
if (!job) return <ErrorResultAtom title="Error displaying job data." />;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
<TargetPriceDiffPcAtom v_age={job.v_age} group={job.group} />
|
||||
<Statistic title="Current RPS %" value={currentRpsPc} suffix="%" />
|
||||
<Statistic title="Current RPS $" value={currentRpsDollars.toFormat()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { selectSelectedJobId } from "../../../redux/application/application.sele
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.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";
|
||||
import "./jobs-detail.organism.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -32,17 +33,21 @@ export function JobsDetailOrganism({ selectedJobId }) {
|
||||
errorMessage={JSON.stringify(error)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="jobs-detail-container">
|
||||
<JobsDetailDescriptionMolecule
|
||||
loading={loading}
|
||||
job={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobsTargetsStatsMolecule
|
||||
loading={loading}
|
||||
job={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobsLinesTableMolecule
|
||||
loading={loading}
|
||||
jobLines={data ? data.jobs_by_pk.joblines : []}
|
||||
job={data ? data.jobs_by_pk : {}}
|
||||
/>
|
||||
{selectedJobId}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, List, Space, Spin, Typography } from "antd";
|
||||
import { Button, Divider, List, Space, Spin } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import InfiniteScroll from "react-infinite-scroller";
|
||||
import { connect } from "react-redux";
|
||||
@@ -87,6 +87,7 @@ export function JobsTableOrganism({ selectedJobId, setSelectedJobId }) {
|
||||
useWindow={false}
|
||||
>
|
||||
<List
|
||||
bordered
|
||||
dataSource={data ? data.jobs : []}
|
||||
renderItem={(item) => (
|
||||
<List.Item
|
||||
@@ -101,22 +102,24 @@ export function JobsTableOrganism({ selectedJobId, setSelectedJobId }) {
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Typography.Title level={4} style={{ flex: 1 }}>
|
||||
{`${item.clm_no}${
|
||||
item.ins_co_nm ? ` | ${item.ins_co_nm}` : ""
|
||||
}`}
|
||||
</Typography.Title>
|
||||
<span className="job-list-last-updated-time">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<strong>{item.clm_no || "No Claim Number"}</strong>
|
||||
<span style={{ fontStyle: "italic" }}>
|
||||
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
|
||||
</span>
|
||||
</div>
|
||||
<Space>
|
||||
<span>{`${item.ownr_fn} ${item.ownr_ln}`}</span>
|
||||
<span>
|
||||
{`${item.v_model_yr} ${item.v_makedesc} ${item.v_model} ${item.v_vin}`}
|
||||
</span>
|
||||
</Space>
|
||||
|
||||
<div>{item.ins_co_nm || "No Insurance Co."}</div>
|
||||
<div>{`${item.ownr_fn} ${item.ownr_ln}`}</div>
|
||||
<div>
|
||||
{`${item.v_model_yr} ${item.v_makedesc} ${item.v_model} ${item.v_vin}`}
|
||||
</div>
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Col, Row } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import JobsListOrganism from "../../organisms/jobs-list/jobs-list.organism";
|
||||
import JobsDetailOrganism from "../../organisms/jobs-detail/jobs-detail.organism";
|
||||
import JobsListOrganism from "../../organisms/jobs-list/jobs-list.organism";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
@@ -12,11 +12,10 @@ export function JobsPage() {
|
||||
return (
|
||||
<div style={{ height: "100%" }}>
|
||||
<Row gutter={[16, 16]} style={{ height: "100%" }}>
|
||||
<Col span={10} style={{ height: "100%" }}>
|
||||
<Col span={6} style={{ height: "100%" }}>
|
||||
<JobsListOrganism />
|
||||
</Col>
|
||||
|
||||
<Col span={14} style={{ height: "100%" }}>
|
||||
<Col span={18} style={{ height: "100%" }}>
|
||||
<JobsDetailOrganism />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -4,6 +4,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
bodyshops {
|
||||
id
|
||||
shopname
|
||||
targets
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import gql from "graphql-tag";
|
||||
|
||||
export const QUERY_GROUPS_BY_MAKE_TYPE = gql`
|
||||
query QUERY_GROUPS_BY_MAKE_TYPE($make: String!, $type: String) {
|
||||
query QUERY_GROUPS_BY_MAKE_TYPE(
|
||||
$make: String!
|
||||
$type: String
|
||||
$isNull: Boolean
|
||||
) {
|
||||
veh_groups(
|
||||
where: { _and: { make: { _eq: $make } }, type: { _eq: $type } }
|
||||
where: {
|
||||
_and: { make: { _eq: $make } }
|
||||
type: { _eq: $type, _is_null: $isNull }
|
||||
}
|
||||
) {
|
||||
id
|
||||
group
|
||||
|
||||
@@ -166,7 +166,11 @@ const DetermineVehicleGroup = async (job) => {
|
||||
query: QUERY_GROUPS_BY_MAKE_TYPE,
|
||||
variables: {
|
||||
make: job.v_makedesc.toUpperCase(),
|
||||
type: job.v_type ? job.v_type.toUpperCase() : null,
|
||||
type:
|
||||
job.v_type && job.v_type.toUpperCase() !== "PC"
|
||||
? job.v_type.toUpperCase()
|
||||
: null,
|
||||
isNull: job.v_type && job.v_type.toUpperCase() !== "PC" ? false : true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user