From 8bb86b9caa6388bb55b67690ab4c31ac1e1283b8 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 24 Mar 2025 09:59:41 -0700 Subject: [PATCH 1/2] IO-3178 Flat Rate ATS Signed-off-by: Allan Carr --- .../jobs-detail-rates.component.jsx | 44 +- .../shop-info.laborrates.component.jsx | 655 +++++++++--------- client/src/graphql/jobs.queries.js | 2 + client/src/translations/en_us/common.json | 5 +- client/src/translations/es/common.json | 3 + client/src/translations/fr/common.json | 3 + hasura/metadata/tables.yaml | 6 + .../down.sql | 4 + .../up.sql | 2 + .../down.sql | 4 + .../up.sql | 2 + server/graphql-client/queries.js | 2 + server/job/job-totals-USA.js | 182 +++-- server/job/job-totals.js | 126 ++-- 14 files changed, 593 insertions(+), 447 deletions(-) create mode 100644 hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/down.sql create mode 100644 hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/up.sql create mode 100644 hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/down.sql create mode 100644 hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/up.sql diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx index 98a76f7b5..300f45f5a 100644 --- a/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx +++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx @@ -5,6 +5,7 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; import CABCpvrtCalculator from "../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component"; @@ -14,9 +15,8 @@ import JobsDetailRatesLabor from "./jobs-detail-rates.labor.component"; import JobsDetailRatesMaterials from "./jobs-detail-rates.materials.component"; import JobsDetailRatesOther from "./jobs-detail-rates.other.component"; import JobsDetailRatesParts from "./jobs-detail-rates.parts.component"; -import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component"; import JobsDetailRatesProfileOVerride from "./jobs-detail-rates.profile-override.component"; -import InstanceRenderManager from "../../utils/instanceRenderMgr"; +import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component"; const mapStateToProps = createStructuredSelector({ jobRO: selectJobReadOnly, @@ -66,14 +66,48 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) { )} - + { + if (checked) { + form.setFieldsValue({ flat_rate_ats: false }); + form.setFieldsValue({ rate_ats: form.getFieldValue('rate_ats') || bodyshop.shoprates.rate_ats }); + } + }} + /> - prev.auto_add_ats !== cur.auto_add_ats}> {() => { if (form.getFieldValue("auto_add_ats")) return ( - + + + + ); + + return null; + }} + + + { + if (checked) { + form.setFieldsValue({ auto_add_ats: false }); + form.setFieldsValue({ rate_ats_flat: form.getFieldValue('rate_ats_flat') || bodyshop.shoprates.rate_ats_flat }); + + } + }} + /> + + prev.flat_rate_ats !== cur.flat_rate_ats}> + {() => { + if (form.getFieldValue("flat_rate_ats")) + return ( + ); diff --git a/client/src/components/shop-info/shop-info.laborrates.component.jsx b/client/src/components/shop-info/shop-info.laborrates.component.jsx index 0c7c9b556..af8df9b34 100644 --- a/client/src/components/shop-info/shop-info.laborrates.component.jsx +++ b/client/src/components/shop-info/shop-info.laborrates.component.jsx @@ -1,6 +1,5 @@ import { DeleteFilled } from "@ant-design/icons"; -import { Button, Form, Input } from "antd"; -import React from "react"; +import { Button, Form, Input, Space } from "antd"; import { useTranslation } from "react-i18next"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; @@ -10,326 +9,338 @@ export default function ShopInfoLaborRates({ form }) { const { t } = useTranslation(); return ( -
- - {(fields, { add, remove, move }) => { - return ( -
- {fields.map((field, index) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { - // - // - // - // - // - // - } - - - - - - - { - remove(field.name); - }} - /> - - + <> + + + + + + + + + + + {(fields, { add, remove, move }) => { + return ( +
+ {fields.map((field, index) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + // + // + // + // + // + // + } + + + + + + + + { + remove(field.name); + }} + /> + + + + + ))} + + - ))} - - - -
- ); - }} -
-
+
+ ); + }} + + + ); } diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index ddfd26a2f..a9f16c111 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -509,6 +509,7 @@ export const GET_JOB_BY_PK = gql` est_ct_ln est_ea est_ph1 + flat_rate_ats federal_tax_rate id inproduction @@ -649,6 +650,7 @@ export const GET_JOB_BY_PK = gql` policy_no production_vars rate_ats + rate_ats_flat rate_la1 rate_la2 rate_la3 diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 5e062169a..ccf90fc10 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -722,6 +722,7 @@ "scoreboardsetup": "Scoreboard Setup", "shop_enabled_features": "Shop Enabled Features", "shopinfo": "Shop Information", + "shoprates": "Shop Rates", "speedprint": "Speed Print Configuration", "ssbuckets": "Job Size Definitions", "systemsettings": "System Settings", @@ -1658,7 +1659,7 @@ "08": "Left Rear Side", "09": "Left Side" }, - "auto_add_ats": "Automatically Add/Update ATS", + "auto_add_ats": "Automatically Add/Update ATS?", "ca_bc_pvrt": "PVRT", "ca_customer_gst": "Customer Portion of GST", "ca_gst_registrant": "GST Registrant", @@ -1757,6 +1758,7 @@ "est_ct_ln": "Estimator Last Name", "est_ea": "Estimator Email", "est_ph1": "Estimator Phone #", + "flat_rate_ats": "Flat Rate ATS?", "federal_tax_payable": "Federal Tax Payable", "federal_tax_rate": "Federal Tax Rate", "ins_addr1": "Insurance Co. Address", @@ -1868,6 +1870,7 @@ }, "queued_for_parts": "Queued for Parts", "rate_ats": "ATS Rate", + "rate_ats_flat": "ATS Flat Rate", "rate_la1": "LA1", "rate_la2": "LA2", "rate_la3": "LA3", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 6aa64961a..2f9fa9a2b 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -722,6 +722,7 @@ "scoreboardsetup": "", "shop_enabled_features": "", "shopinfo": "", + "shoprates": "", "speedprint": "", "ssbuckets": "", "systemsettings": "", @@ -1757,6 +1758,7 @@ "est_ct_ln": "Apellido del tasador", "est_ea": "Correo electrónico del tasador", "est_ph1": "Número de teléfono del tasador", + "flat_rate_ats": "", "federal_tax_payable": "Impuesto federal por pagar", "federal_tax_rate": "", "ins_addr1": "Dirección de Insurance Co.", @@ -1868,6 +1870,7 @@ }, "queued_for_parts": "", "rate_ats": "", + "rate_ats_flat": "", "rate_la1": "Tarifa LA1", "rate_la2": "Tarifa LA2", "rate_la3": "Tarifa LA3", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 6e9713285..888162de9 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -722,6 +722,7 @@ "scoreboardsetup": "", "shop_enabled_features": "", "shopinfo": "", + "shoprates": "", "speedprint": "", "ssbuckets": "", "systemsettings": "", @@ -1757,6 +1758,7 @@ "est_ct_ln": "Nom de l'évaluateur", "est_ea": "Courriel de l'évaluateur", "est_ph1": "Numéro de téléphone de l'évaluateur", + "flat_rate_ats": "", "federal_tax_payable": "Impôt fédéral à payer", "federal_tax_rate": "", "ins_addr1": "Adresse Insurance Co.", @@ -1868,6 +1870,7 @@ }, "queued_for_parts": "", "rate_ats": "", + "rate_ats_flat": "", "rate_la1": "Taux LA1", "rate_la2": "Taux LA2", "rate_la3": "Taux LA3", diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 6cdb4c008..4d1f5192e 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -3695,6 +3695,7 @@ - est_st - est_zip - federal_tax_rate + - flat_rate_ats - g_bett_amt - id - inproduction @@ -3789,6 +3790,7 @@ - qb_multiple_payers - queued_for_parts - rate_ats + - rate_ats_flat - rate_la1 - rate_la2 - rate_la3 @@ -3965,6 +3967,7 @@ - est_st - est_zip - federal_tax_rate + - flat_rate_ats - g_bett_amt - id - inproduction @@ -4060,6 +4063,7 @@ - qb_multiple_payers - queued_for_parts - rate_ats + - rate_ats_flat - rate_la1 - rate_la2 - rate_la3 @@ -4247,6 +4251,7 @@ - est_st - est_zip - federal_tax_rate + - flat_rate_ats - g_bett_amt - id - inproduction @@ -4342,6 +4347,7 @@ - qb_multiple_payers - queued_for_parts - rate_ats + - rate_ats_flat - rate_la1 - rate_la2 - rate_la3 diff --git a/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/down.sql b/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/down.sql new file mode 100644 index 000000000..5478f998b --- /dev/null +++ b/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."jobs" add column "flat_rate_ats" boolean +-- null default 'false'; diff --git a/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/up.sql b/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/up.sql new file mode 100644 index 000000000..73fa874ae --- /dev/null +++ b/hasura/migrations/1742583400542_alter_table_public_jobs_add_column_flat_rate_ats/up.sql @@ -0,0 +1,2 @@ +alter table "public"."jobs" add column "flat_rate_ats" boolean + null default 'false'; diff --git a/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/down.sql b/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/down.sql new file mode 100644 index 000000000..3f82e9770 --- /dev/null +++ b/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."jobs" add column "rate_ats_flat" numeric +-- null; diff --git a/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/up.sql b/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/up.sql new file mode 100644 index 000000000..e0157edd2 --- /dev/null +++ b/hasura/migrations/1742583433746_alter_table_public_jobs_add_column_rate_ats_flat/up.sql @@ -0,0 +1,2 @@ +alter table "public"."jobs" add column "rate_ats_flat" numeric + null; diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index cc50b3115..3df3e810c 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -1485,6 +1485,8 @@ exports.GET_JOB_BY_PK = `query GET_JOB_BY_PK($id: uuid!) { materials auto_add_ats rate_ats + flat_rate_ats + rate_ats_flat joblines(where: { removed: { _eq: false } }){ id line_no diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index 4e889a658..6835dc7cb 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -1,7 +1,7 @@ const Dinero = require("dinero.js"); const queries = require("../graphql-client/queries"); -const adminClient = require("../graphql-client/graphql-client").client; -const _ = require("lodash"); +// const adminClient = require("../graphql-client/graphql-client").client; +// const _ = require("lodash"); const logger = require("../utils/logger"); const InstanceMgr = require("../utils/instanceMgr").default; @@ -45,7 +45,9 @@ exports.totalsSsu = async function (req, res) { } }); - res.status(200).send(); + if (result) { + res.status(200).send(); + } } catch (error) { logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, { jobid: id, @@ -59,7 +61,7 @@ exports.totalsSsu = async function (req, res) { //IMPORTANT*** These two functions MUST be mirrrored. async function TotalsServerSide(req, res) { const { job, client } = req.body; - await AutoAddAtsIfRequired({ job: job, client: client }); + await AtsAdjustmentsIfRequired({ job: job, client: client, user: req?.user }); try { let ret = { @@ -137,11 +139,12 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, { - jobid: job.id + logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, { + jobid: job.id, + id: id }); - await AutoAddAtsIfRequired({ job, client }); + await AtsAdjustmentsIfRequired({ job, client, user: req.user }); try { let ret = { @@ -162,40 +165,45 @@ async function Totals(req, res) { } } -async function AutoAddAtsIfRequired({ job, client }) { - //Check if ATS should be automatically added. - if (job.auto_add_ats) { - //Get the total sum of hours that should be the ATS amount. - //Check to see if an ATS line exists. +async function AtsAdjustmentsIfRequired({ job, client, user }) { + if (job.auto_add_ats || job.flat_rate_ats) { + let atsAmount = 0; let atsLineIndex = null; - const atsHours = job.joblines.reduce((acc, val, index) => { - if (val.line_desc && val.line_desc.toLowerCase() === "ats amount") { - atsLineIndex = index; - } - if ( - val.mod_lbr_ty !== "LA1" && - val.mod_lbr_ty !== "LA2" && - val.mod_lbr_ty !== "LA3" && - val.mod_lbr_ty !== "LA4" && - val.mod_lbr_ty !== "LAU" && - val.mod_lbr_ty !== "LAG" && - val.mod_lbr_ty !== "LAS" && - val.mod_lbr_ty !== "LAA" - ) { - acc = acc + val.mod_lb_hrs; - } + //Check if ATS should be automatically added. + if (job.auto_add_ats) { + const excludedLaborTypes = new Set(["LAA", "LAG", "LAS", "LAU", "LA1", "LA2", "LA3", "LA4"]); - return acc; - }, 0); + //Get the total sum of hours that should be the ATS amount. + //Check to see if an ATS line exists. + const atsHours = job.joblines.reduce((acc, val, index) => { + if (val.line_desc?.toLowerCase() === "ats amount") { + atsLineIndex = index; + } - const atsAmount = atsHours * (job.rate_ats || 0); - //If it does, update it in place, and make sure it is updated for local calculations. + if (!excludedLaborTypes.has(val.mod_lbr_ty)) { + acc = acc + val.mod_lb_hrs; + } + + return acc; + }, 0); + + atsAmount = atsHours * (job.rate_ats || 0); + } + + //Check if a Flat Rate ATS should be added. + if (job.flat_rate_ats) { + atsLineIndex = ((i) => (i === -1 ? null : i))( + job.joblines.findIndex((line) => line.line_desc?.toLowerCase() === "ats amount") + ); + atsAmount = job.rate_ats_flat || 0; + } + + //If it does not, create one for local calculations and insert it. if (atsLineIndex === null) { const newAtsLine = { jobid: job.id, alt_partm: null, - line_no: 35, unq_seq: 0, line_ind: "E", line_desc: "ATS Amount", @@ -220,19 +228,40 @@ async function AutoAddAtsIfRequired({ job, client }) { prt_dsmk_m: 0.0 }; - const result = await client.request(queries.INSERT_NEW_JOB_LINE, { - lineInput: [newAtsLine] - }); + try { + const result = await client.request(queries.INSERT_NEW_JOB_LINE, { + lineInput: [newAtsLine] + }); - job.joblines.push(newAtsLine); + if (result) { + job.joblines.push(newAtsLine); + } + } catch (error) { + logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + jobid: job.id, + error: error.message, + stack: error.stack + }); + } } - //If it does not, create one for local calculations and insert it. + //If it does, update it in place, and make sure it is updated for local calculations. else { - const result = await client.request(queries.UPDATE_JOB_LINE, { - line: { act_price: atsAmount }, - lineId: job.joblines[atsLineIndex].id - }); - job.joblines[atsLineIndex].act_price = atsAmount; + try { + const result = await client.request(queries.UPDATE_JOB_LINE, { + line: { act_price: atsAmount }, + lineId: job.joblines[atsLineIndex].id + }); + if (result) { + job.joblines[atsLineIndex].act_price = atsAmount; + } + } catch (error) { + logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + jobid: job.id, + atsLineIndex: atsLineIndex, + error: error.message, + stack: error.stack + }); + } } } } @@ -314,7 +343,7 @@ async function CalculateRatesTotals({ job, client }) { let hasMashLine = false; let hasMahwLine = false; let hasCustomMahwLine; - let mapaOpCodes = ParseCalopCode(job.materials["MAPA"]?.cal_opcode); + // let mapaOpCodes = ParseCalopCode(job.materials["MAPA"]?.cal_opcode); let mashOpCodes = ParseCalopCode(job.materials["MASH"]?.cal_opcode); jobLines.forEach((item) => { @@ -564,7 +593,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { } }; - default: + default: { if (!value.part_type && value.db_ref !== "900510" && value.db_ref !== "900511") return acc; const discountAmount = @@ -631,6 +660,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { ) } }; + } } }, { @@ -652,7 +682,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { let adjustments = {}; //Track all adjustments that need to be made. - const linesToAdjustForDiscount = []; + //const linesToAdjustForDiscount = []; Object.keys(parts_tax_rates).forEach((key) => { //Check if there's a discount or a mark up. let disc = Dinero(), @@ -1019,7 +1049,9 @@ function CalculateTaxesTotals(job, otherTotals) { } } catch (error) { logger.log("job-totals-USA Key with issue", "error", null, job.id, { - key + key: key, + error: error.message, + stack: error.stack }); } }); @@ -1158,6 +1190,8 @@ function CalculateTaxesTotals(job, otherTotals) { exports.default = Totals; function DiscountNotAlreadyCounted(jobline, joblines) { + void jobline; + void joblines; return false; } @@ -1172,27 +1206,35 @@ function IsTrueOrYes(value) { return value === true || value === "Y" || value === "y"; } -async function UpdateJobLines(joblinesToUpdate) { - if (joblinesToUpdate.length === 0) return; - const updateQueries = joblinesToUpdate.map((line, index) => - generateUpdateQuery(_.pick(line, ["id", "prt_dsmk_m", "prt_dsmk_p"]), index) - ); - const query = ` - mutation UPDATE_EST_LINES{ - ${updateQueries} - } - `; +// Function not in use from RO to IO Merger 02/05/2024 +// async function UpdateJobLines(joblinesToUpdate) { +// if (joblinesToUpdate.length === 0) return; +// const updateQueries = joblinesToUpdate.map((line, index) => +// generateUpdateQuery(_.pick(line, ["id", "prt_dsmk_m", "prt_dsmk_p"]), index) +// ); +// const query = ` +// mutation UPDATE_EST_LINES{ +// ${updateQueries} +// } +// `; +// try { +// const result = await adminClient.request(query); +// void result; +// } catch (error) { +// logger.log("update-job-lines", "error", null, null, { +// error: error.message, +// stack: error.stack +// }); +// } +// } - const result = await adminClient.request(query); -} - -const generateUpdateQuery = (lineToUpdate, index) => { - return ` - update_joblines${index}: update_joblines(where: { id: { _eq: "${ - lineToUpdate.id - }" } }, _set: ${JSON.stringify(lineToUpdate).replace(/"(\w+)"\s*:/g, "$1:")}) { - returning { - id - } - }`; -}; +// const generateUpdateQuery = (lineToUpdate, index) => { +// return ` +// update_joblines${index}: update_joblines(where: { id: { _eq: "${ +// lineToUpdate.id +// }" } }, _set: ${JSON.stringify(lineToUpdate).replace(/"(\w+)"\s*:/g, "$1:")}) { +// returning { +// id +// } +// }`; +// }; diff --git a/server/job/job-totals.js b/server/job/job-totals.js index 4cd45e13c..0a160426d 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -1,7 +1,5 @@ const Dinero = require("dinero.js"); const queries = require("../graphql-client/queries"); -const adminClient = require("../graphql-client/graphql-client").client; -const _ = require("lodash"); const logger = require("../utils/logger"); //****************************************************** */ @@ -44,11 +42,16 @@ exports.totalsSsu = async function (req, res) { } }); + if (!result) { + throw new Error("Failed to update job totals"); + } + res.status(200).send(); } catch (error) { logger.log("job-totals-ssu-error", "ERROR", req.user.email, id, { jobid: id, - error + error: error.message, + stack: error.stack }); res.status(503).send(); } @@ -57,7 +60,7 @@ exports.totalsSsu = async function (req, res) { //IMPORTANT*** These two functions MUST be mirrrored. async function TotalsServerSide(req, res) { const { job, client } = req.body; - await AutoAddAtsIfRequired({ job: job, client: client }); + await AtsAdjustmentsIfRequired({ job: job, client: client, user: req?.user }); try { let ret = { @@ -71,7 +74,8 @@ async function TotalsServerSide(req, res) { } catch (error) { logger.log("job-totals-ssu-error", "ERROR", req?.user?.email, job.id, { jobid: job.id, - error + error: error.message, + stack: error.stack }); res.status(400).send(JSON.stringify(error)); } @@ -83,13 +87,12 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals", "DEBUG", req.user.email, job.id, { - jobid: job.id + logger.log("job-totals-", "DEBUG", req.user.email, job.id, { + jobid: job.id, + id: id }); - logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null); - - await AutoAddAtsIfRequired({ job, client }); + await AtsAdjustmentsIfRequired({ job, client, user: req.user }); try { let ret = { @@ -103,46 +106,52 @@ async function Totals(req, res) { } catch (error) { logger.log("job-totals-error", "ERROR", req.user.email, job.id, { jobid: job.id, - error + error: error.message, + stack: error.stack }); res.status(400).send(JSON.stringify(error)); } } -async function AutoAddAtsIfRequired({ job, client }) { - //Check if ATS should be automatically added. - if (job.auto_add_ats) { - //Get the total sum of hours that should be the ATS amount. - //Check to see if an ATS line exists. +async function AtsAdjustmentsIfRequired({ job, client, user }) { + if (job.auto_add_ats || job.flat_rate_ats) { + let atsAmount = 0; let atsLineIndex = null; - const atsHours = job.joblines.reduce((acc, val, index) => { - if (val.line_desc && val.line_desc.toLowerCase() === "ats amount") { - atsLineIndex = index; - } - if ( - val.mod_lbr_ty !== "LA1" && - val.mod_lbr_ty !== "LA2" && - val.mod_lbr_ty !== "LA3" && - val.mod_lbr_ty !== "LA4" && - val.mod_lbr_ty !== "LAU" && - val.mod_lbr_ty !== "LAG" && - val.mod_lbr_ty !== "LAS" && - val.mod_lbr_ty !== "LAA" - ) { - acc = acc + val.mod_lb_hrs; - } + //Check if ATS should be automatically added. + if (job.auto_add_ats) { + const excludedLaborTypes = new Set(["LAA", "LAG", "LAS", "LAU", "LA1", "LA2", "LA3", "LA4"]); - return acc; - }, 0); + //Get the total sum of hours that should be the ATS amount. + //Check to see if an ATS line exists. + const atsHours = job.joblines.reduce((acc, val, index) => { + if (val.line_desc?.toLowerCase() === "ats amount") { + atsLineIndex = index; + } - const atsAmount = atsHours * (job.rate_ats || 0); - //If it does, update it in place, and make sure it is updated for local calculations. + if (!excludedLaborTypes.has(val.mod_lbr_ty)) { + acc = acc + val.mod_lb_hrs; + } + + return acc; + }, 0); + + atsAmount = atsHours * (job.rate_ats || 0); + } + + //Check if a Flat Rate ATS should be added. + if (job.flat_rate_ats) { + atsLineIndex = ((i) => (i === -1 ? null : i))( + job.joblines.findIndex((line) => line.line_desc?.toLowerCase() === "ats amount") + ); + atsAmount = job.rate_ats_flat || 0; + } + + //If it does not, create one for local calculations and insert it. if (atsLineIndex === null) { const newAtsLine = { jobid: job.id, alt_partm: null, - line_no: 35, unq_seq: 0, line_ind: "E", line_desc: "ATS Amount", @@ -167,22 +176,41 @@ async function AutoAddAtsIfRequired({ job, client }) { prt_dsmk_m: 0.0 }; - const result = await client.request(queries.INSERT_NEW_JOB_LINE, { - lineInput: [newAtsLine] - }); + try { + const result = await client.request(queries.INSERT_NEW_JOB_LINE, { + lineInput: [newAtsLine] + }); - job.joblines.push(newAtsLine); + if (result) { + job.joblines.push(newAtsLine); + } + } catch (error) { + logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + jobid: job.id, + error: error.message, + stack: error.stack + }); + } } - //If it does not, create one for local calculations and insert it. + //If it does, update it in place, and make sure it is updated for local calculations. else { - const result = await client.request(queries.UPDATE_JOB_LINE, { - line: { act_price: atsAmount }, - lineId: job.joblines[atsLineIndex].id - }); - job.joblines[atsLineIndex].act_price = atsAmount; + try { + const result = await client.request(queries.UPDATE_JOB_LINE, { + line: { act_price: atsAmount }, + lineId: job.joblines[atsLineIndex].id + }); + if (result) { + job.joblines[atsLineIndex].act_price = atsAmount; + } + } catch (error) { + logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + jobid: job.id, + atsLineIndex: atsLineIndex, + error: error.message, + stack: error.stack + }); + } } - - //console.log(job.jobLines); } } From f485951a4c4f39043d77d47a48fa894ad943d22d Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 24 Mar 2025 12:47:51 -0700 Subject: [PATCH 2/2] IO-3178 Requested Changes for Flat Rate ATS Signed-off-by: Allan Carr --- server/job/job-totals-USA.js | 9 +++++---- server/job/job-totals.js | 6 ++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index 6835dc7cb..dd850dc9b 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -139,7 +139,7 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, { jobid: job.id, id: id }); @@ -156,7 +156,7 @@ async function Totals(req, res) { res.status(200).json(ret); } catch (error) { - logger.log("job-totals-USA-error", "ERROR", req.user.email, job.id, { + logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -258,6 +258,8 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { jobid: job.id, atsLineIndex: atsLineIndex, + atsAmount: atsAmount, + jobline: job.joblines[atsLineIndex], error: error.message, stack: error.stack }); @@ -1189,9 +1191,8 @@ function CalculateTaxesTotals(job, otherTotals) { exports.default = Totals; +//eslint-disable-next-line no-unused-vars function DiscountNotAlreadyCounted(jobline, joblines) { - void jobline; - void joblines; return false; } diff --git a/server/job/job-totals.js b/server/job/job-totals.js index 0a160426d..6182f9ced 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -87,7 +87,7 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-ssu", "DEBUG", req.user.email, job.id, { jobid: job.id, id: id }); @@ -104,7 +104,7 @@ async function Totals(req, res) { res.status(200).json(ret); } catch (error) { - logger.log("job-totals-error", "ERROR", req.user.email, job.id, { + logger.log("job-totals-ssu-error", "ERROR", req.user.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -206,6 +206,8 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { jobid: job.id, atsLineIndex: atsLineIndex, + atsAmount: atsAmount, + jobline: job.joblines[atsLineIndex], error: error.message, stack: error.stack });