IO-3001 Add UI adjustments.

This commit is contained in:
Patrick Fic
2024-11-01 19:54:49 -07:00
parent f8e65ada76
commit 1205e71ea6
6 changed files with 156 additions and 103 deletions

View File

@@ -22,6 +22,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
const data = useMemo(() => { const data = useMemo(() => {
return [ return [
...(job.job_totals?.totals?.ttl_adjustment
? [
{
key: `Subtotal Adj.`,
total: job.job_totals?.totals?.ttl_adjustment
}
]
: []),
{ {
key: t("jobs.labels.subtotal"), key: t("jobs.labels.subtotal"),
total: job.job_totals.totals.subtotal, total: job.job_totals.totals.subtotal,
@@ -116,7 +124,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
...(job.job_totals?.totals?.ttl_tax_adjustment ...(job.job_totals?.totals?.ttl_tax_adjustment
? [ ? [
{ {
key: `Adj.`, key: `Tax Adj.`,
total: job.job_totals?.totals?.ttl_tax_adjustment total: job.job_totals?.totals?.ttl_tax_adjustment
} }
] ]

View File

@@ -408,26 +408,23 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
updateSchComp={updateSchComp} updateSchComp={updateSchComp}
setSchComp={setSchComp} setSchComp={setSchComp}
/> />
{ {currentUser.email.includes("@rome.") || currentUser.email.includes("@imex.") ? (
currentUser.email.includes("@rome.") || <Button
currentUser.email.includes("@imex.") ? ( onClick={async () => {
<Button for (const record of data.available_jobs) {
onClick={async () => { //Query the data
for (const record of data.available_jobs) { console.log("Start Job", record.id);
//Query the data const { data } = await loadEstData({
console.log("Start Job", record.id); variables: { id: record.id }
const {data} = await loadEstData({ });
variables: {id: record.id}, console.log("Query has been awaited and is complete");
}); await onOwnerFindModalOk(data);
console.log("Query has been awaited and is complete"); }
await onOwnerFindModalOk(data); }}
} >
}} Add all jobs as new.
> </Button>
Add all jobs as new. ) : null}
</Button>
) : null
}
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col span={24}> <Col span={24}>
<JobsAvailableTableComponent <JobsAvailableTableComponent

View File

@@ -1,12 +1,12 @@
const path = require("path"); const path = require("path");
const fs = require("fs");
const Dinero = require("dinero.js"); const Dinero = require("dinero.js");
const { gql } = require("graphql-request"); const { gql } = require("graphql-request");
const AxiosLib = require("axios").default; const AxiosLib = require("axios").default;
const axios = AxiosLib.create(); const axios = AxiosLib.create();
const pLimit = require("p-limit");
const converter = require("json-2-csv");
// Dinero.defaultCurrency = "USD";
// Dinero.globalLocale = "en-CA";
Dinero.globalRoundingMode = "HALF_EVEN"; Dinero.globalRoundingMode = "HALF_EVEN";
const client = require("./server/graphql-client/graphql-client").client; const client = require("./server/graphql-client/graphql-client").client;
require("dotenv").config({ require("dotenv").config({
@@ -15,7 +15,7 @@ require("dotenv").config({
async function RunTheTest() { async function RunTheTest() {
const bodyshopids = ["71f8494c-89f0-43e0-8eb2-820b52d723bc"]; const bodyshopids = ["71f8494c-89f0-43e0-8eb2-820b52d723bc"];
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImU2YWMzNTcyNzY3ZGUyNjE0ZmM1MTA4NjMzMDg3YTQ5MjMzMDNkM2IiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUGF0cmljayBGaWMgKERFVikiLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImhOSjhBRHB0REhRQkRFcXNCOFFNWVRqaURuZjEifSwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL2ltZXgtZGV2IiwiYXVkIjoiaW1leC1kZXYiLCJhdXRoX3RpbWUiOjE3MzAxMzIwMjksInVzZXJfaWQiOiJoTko4QURwdERIUUJERXFzQjhRTVlUamlEbmYxIiwic3ViIjoiaE5KOEFEcHRESFFCREVxc0I4UU1ZVGppRG5mMSIsImlhdCI6MTczMDE1MjI5NiwiZXhwIjoxNzMwMTU1ODk2LCJlbWFpbCI6InBhdHJpY2tAaW1leC5kZXYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicGF0cmlja0BpbWV4LmRldiJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.Fgf_itlA2-CMd2sTYBNjD-g8Jt3wPLW_YWbDtMn8tm-doSPhU7-RHSHON7Vz6o1m6S3x88RODt2uxSifxfgjqXYC_yJiUVEnHp7xokI1X-7EIbv6S_jfD1gKq7gNehkKkm0QETvAX_wmL0hEZyZnBacxjkSZzDZgbfKfj8U2CAU1nY6O5vk90q0HdTrt98RL37Uiz62ftAdBZCLSpZ1AS1hGa1S3NDMhWbWvBVCMY59bhM8lreH-Q1znlSe9jNXbElvrKofSc3Jz2WeTIj3Ifq5Ev-p4rIOoILww8kE9ZKp4s28JXMdrpRnqFM7tufggjZaKx5g1_rwRnzl-dk50RQ`; const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImU2YWMzNTcyNzY3ZGUyNjE0ZmM1MTA4NjMzMDg3YTQ5MjMzMDNkM2IiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUGF0cmljayBGaWMgKERFVikiLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImhOSjhBRHB0REhRQkRFcXNCOFFNWVRqaURuZjEifSwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL2ltZXgtZGV2IiwiYXVkIjoiaW1leC1kZXYiLCJhdXRoX3RpbWUiOjE3MzAxMzIwMjksInVzZXJfaWQiOiJoTko4QURwdERIUUJERXFzQjhRTVlUamlEbmYxIiwic3ViIjoiaE5KOEFEcHRESFFCREVxc0I4UU1ZVGppRG5mMSIsImlhdCI6MTczMDQwNzg2MSwiZXhwIjoxNzMwNDExNDYxLCJlbWFpbCI6InBhdHJpY2tAaW1leC5kZXYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicGF0cmlja0BpbWV4LmRldiJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.Mxla5zqBNpdzXuAPqCswsLohrV5xm0SNi2Agr0lAU_crNJxVXJdTaKL8B4Av-LMCGjylHqume9WUbZ43fnMxrq4hlWGqeDzGpD7ev76h4omSn0jiMJ0qZmFeR1ejV40KZ6eLrvxEbDLiAebbU2rLp7tZonpspwPa1ruoRk4ixvtvv66ZNcbiEA5NP3VM9VDFnLzj8Vb160t3dQF58bxMUt8RoCc9cP_XPXWxnj-DsyDaYBO-shJrg3Co8T_jPg2ix-x2HkAVpPvTUjCCpAya-DhOx5aFZYiaNlmvosqCqcfZgVfjVuEogZb_rDkSF4wkR8DtfUt9IgGjWxF_rhos_Q`;
const { jobs } = await client.request( const { jobs } = await client.request(
gql` gql`
@@ -35,79 +35,94 @@ async function RunTheTest() {
const results = []; const results = [];
for (const [index, job] of jobs.entries()) { const limit = pLimit(5); // Set concurrency limit to 3
process.stdout.cursorTo(0);
process.stdout.write(
`Processing job ${index + 1} of ${jobs.length}. Failed jobs: ${results.filter((r) => r.result !== "PASS").length}`
);
try { const tasks = jobs.map((job, index) => {
await axios.post( return limit(async () => {
`http://localhost:4000/job/totalsssu`, process.stdout.cursorTo(0);
{ id: job.id }, process.stdout.write(
{ headers: { Authorization: bearerToken } } `Processing job ${index + 1} of ${jobs.length}. Failed jobs: ${results.filter((r) => r.overallTotalCorrect !== "PASS").length}. Correct jobs because of adjustment: ${results.filter((r) => r.correctJobsBecauseOfAdjustment).length}`
); );
const { jobs_by_pk: newjob } = await client.request(
gql` try {
query GET_JOBS($id: uuid!) { await axios.post(
jobs_by_pk(id: $id) { `http://localhost:4000/job/totalsssu`,
id { id: job.id },
ro_number { headers: { Authorization: bearerToken } }
cieca_ttl );
job_totals const { jobs_by_pk: newjob } = await client.request(
ownr_fn gql`
ownr_ln query GET_JOBS($id: uuid!) {
ownr_co_nm jobs_by_pk(id: $id) {
ins_co_nm id
comment ro_number
cieca_ttl
job_totals
ownr_fn
ownr_ln
ownr_co_nm
ins_co_nm
comment
}
} }
`,
{
id: job.id
} }
`, );
{
id: job.id const result = {
id: newjob.id,
owner: `${newjob.ownr_fn} ${newjob.ownr_ln} ${job.ownr_co_nm || ""}`,
ins_co: newjob.ins_co_nm,
comment: newjob.comment
};
const calcTotal = newjob.job_totals.totals.total_repairs.amount;
const ttlTotal = newjob.cieca_ttl.data.g_ttl_amt * 100;
result.difference = (calcTotal - ttlTotal) / 100;
if (Math.abs(calcTotal - ttlTotal) > 3) {
result.overallTotalCorrect = "***FAIL***";
} else {
result.overallTotalCorrect = "PASS";
} }
); result.ttl_adjustment = Dinero(newjob.job_totals.totals.ttl_adjustment).toFormat();
result.ttl_tax_adjustment = Dinero(newjob.job_totals.totals.ttl_tax_adjustment).toFormat();
const result = { const calcTax =
id: newjob.id, Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
owner: `${newjob.ownr_fn} ${newjob.ownr_ln} ${job.ownr_co_nm || ""}`, .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty2Tax))
ins_co: newjob.ins_co_nm, .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty3Tax))
comment: newjob.comment .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty4Tax))
}; .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty5Tax))
.add(Dinero(newjob.job_totals.totals.ttl_tax_adjustment))
.getAmount() / 100;
const calcTotal = newjob.job_totals.totals.total_repairs.amount; const emsTax = newjob.cieca_ttl.data.g_tax;
const ttlTotal = newjob.cieca_ttl.data.g_ttl_amt * 100; result.taxDifference = calcTax - emsTax;
result.difference = (calcTotal - ttlTotal) / 100;
if (Math.abs(calcTotal - ttlTotal) > 3) { if (Math.abs(calcTax - emsTax) > 3) {
//Diff is greater than 5 cents. Fail it. result.taxCorrect = "***FAIL***";
result.result = "***FAIL***"; } else {
} else { result.taxCorrect = "PASS";
result.result = "PASS"; }
results.push(result);
} catch (error) {
results.push({
ro_number: job.ro_number,
id: job.id,
result: "**503 FAILURE**"
});
} }
const subcalcTotal = newjob.job_totals.totals.subtotal.amount; });
const subttlTotal = newjob.cieca_ttl.data.n_ttl_amt * 100; });
result.subdifference = (subcalcTotal - subttlTotal) / 100;
if (Math.abs(subcalcTotal - subttlTotal) > 3) { await Promise.all(tasks);
//Diff is greater than 5 cents. Fail it.
result.subresult = "***FAIL***";
} else {
result.subresult = "PASS";
}
// console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `);
results.push(result); console.table(results.filter((r) => r.overallTotalCorrect !== "PASS"));
} catch (error) { console.log("=======================================");
results.push({
ro_number: job.ro_number,
id: job.id,
result: "**503 FAILURE**"
});
}
}
console.table(results.filter((r) => r.result !== "PASS"));
const summary = results.reduce( const summary = results.reduce(
(acc, val) => { (acc, val) => {
if (val.result === "PASS") { if (val.result === "PASS") {
@@ -119,18 +134,12 @@ async function RunTheTest() {
{ pass: 0, fail: 0 } { pass: 0, fail: 0 }
); );
console.log("Pass Rate: ", ((summary.pass / (summary.fail + summary.pass)) * 100).toFixed(1)); console.log("Pass Rate: ", ((summary.pass / (summary.fail + summary.pass)) * 100).toFixed(1));
const ret = converter.json2csv(results, { emptyFieldValue: "" });
fs.writeFile(`./logs/totalstest-${Date.now()}.csv`, ret, (error) => console.log(error));
} }
RunTheTest(); RunTheTest().catch((error) => {
console.log("Error in RunTheTest: ", error);
// mutation { });
// delete_jobs(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
// affected_rows
// }
// delete_owners(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
// affected_rows
// }
// delete_vehicles(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
// affected_rows
// }
// }

7
package-lock.json generated
View File

@@ -64,6 +64,7 @@
"devDependencies": { "devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"p-limit": "^3.1.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"source-map-explorer": "^2.5.2" "source-map-explorer": "^2.5.2"
}, },
@@ -6726,7 +6727,8 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"optional": true, "devOptional": true,
"license": "MIT",
"dependencies": { "dependencies": {
"yocto-queue": "^0.1.0" "yocto-queue": "^0.1.0"
}, },
@@ -8720,7 +8722,8 @@
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"optional": true, "devOptional": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },

View File

@@ -74,6 +74,7 @@
"devDependencies": { "devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"p-limit": "^3.1.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"source-map-explorer": "^2.5.2" "source-map-explorer": "^2.5.2"
} }

View File

@@ -476,7 +476,7 @@ function GenerateCostingData(job) {
if (!hasMapaLine) { if (!hasMapaLine) {
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]]) if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero(); jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[ jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MAPA"] defaultProfits["MAPA"]
].add( ].add(
@@ -809,6 +809,41 @@ function GenerateCostingData(job) {
gppercent: formatGpPercent(0) gppercent: formatGpPercent(0)
}); });
} }
//Push adjustments to bottom line.
if (job.job_totals.totals.ttl_adjustment) {
//Add to totals.
const Adjustment = Dinero(job.job_totals.totals.ttl_adjustment); //Need to invert, since this is being assigned as a cost.
summaryData.totalAdditionalSales = summaryData.totalAdditionalSales.add(Adjustment);
summaryData.totalSales = summaryData.totalSales.add(Adjustment);
//Add to lines.
costCenterData.push({
id: "Adj",
cost_center: "Adjustment",
sale_labor: Dinero().toFormat(),
sale_labor_dinero: Dinero(),
sale_parts: Dinero().toFormat(),
sale_parts_dinero: Dinero(),
sale_additional: Adjustment.toFormat(),
sale_additional_dinero: Adjustment,
sale_sublet: Dinero(),
sale_sublet_dinero: Dinero(),
sales: Adjustment.toFormat(),
sales_dinero: Adjustment,
cost_parts: Dinero().toFormat(),
cost_parts_dinero: Dinero(),
cost_labor: Dinero().toFormat(), //Adjustment.toFormat(),
cost_labor_dinero: Dinero(), // Adjustment,
cost_additional: Dinero(),
cost_additional_dinero: Dinero(),
cost_sublet: Dinero(),
cost_sublet_dinero: Dinero(),
costs: Dinero().toFormat(),
costs_dinero: Dinero(),
gpdollars_dinero: Dinero(),
gpdollars: Dinero().toFormat(),
gppercent: formatGpPercent(0)
});
}
//Final summary data massaging. //Final summary data massaging.