From 61766017ea55ec2ccacd8f5cdc14bec69fd4988e Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 8 Apr 2024 14:28:58 -0700 Subject: [PATCH 01/10] Resolve supplement import for CCC. --- .../jobs-available-table/jobs-available-table.container.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index bb2b2f7f4..a8784fda8 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -237,7 +237,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail executeFunction: true, rome: ResolveCCCLineIssues, promanager: ResolveCCCLineIssues, - args: [(supp, bodyshop)] + args: [supp, bodyshop] }); await InstanceRenderManager({ From 07bf84ed6948a20843d98cd76ee2d8cb8fc770bb Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 9 Apr 2024 11:55:20 -0700 Subject: [PATCH 02/10] IO-2609 Body & Refinish Times included in Calendar View Signed-off-by: Allan Carr --- .../schedule-calendar-header.component.js | 83 +++++++++++-------- .../redux/application/application.sagas.js | 35 +++++++- 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js index 732bcc2c2..96ef73a56 100644 --- a/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js +++ b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js @@ -1,5 +1,5 @@ import Icon from "@ant-design/icons"; -import { Popover } from "antd"; +import { Popover, Space } from "antd"; import _ from "lodash"; import moment from "moment"; import React, { useMemo } from "react"; @@ -69,19 +69,22 @@ export function ScheduleCalendarHeaderComponent({ {loadData && loadData.allJobsOut ? ( loadData.allJobsOut.map((j) => ( - - {j.ro_number} + + {j.ro_number} ( + {j.status}) - + - - {`(${( + + {`(${j.labhrs.aggregate.sum.mod_lb_hrs.toFixed( + 1 + )}/${j.larhrs.aggregate.sum.mod_lb_hrs.toFixed(1)}/${( j.labhrs.aggregate.sum.mod_lb_hrs + j.larhrs.aggregate.sum.mod_lb_hrs ).toFixed(1)} ${t("general.labels.hours")})`} - + {j.scheduled_completion} @@ -90,7 +93,9 @@ export function ScheduleCalendarHeaderComponent({ )) ) : ( - {t("appointments.labels.nocompletingjobs")} + + {t("appointments.labels.nocompletingjobs")} + )} @@ -105,27 +110,30 @@ export function ScheduleCalendarHeaderComponent({ {loadData && loadData.allJobsIn ? ( loadData.allJobsIn.map((j) => ( - + {j.ro_number} - {j.status} - + - - {`(${( + + {`(${j.labhrs.aggregate.sum.mod_lb_hrs.toFixed( + 1 + )}/${j.larhrs.aggregate.sum.mod_lb_hrs.toFixed(1)}/${( j.labhrs.aggregate.sum.mod_lb_hrs + j.larhrs.aggregate.sum.mod_lb_hrs ).toFixed(1)} ${t("general.labels.hours")})`} - + {j.scheduled_in} )) ) : ( - {t("appointments.labels.noarrivingjobs")} + + {t("appointments.labels.noarrivingjobs")} + )} @@ -136,25 +144,32 @@ export function ScheduleCalendarHeaderComponent({ const LoadComponent = loadData ? (
- - - {(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(2)} - - - - {(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(2)} - - + + + + {(loadData.allHoursInBody || 0) && + loadData.allHoursInBody.toFixed(1)} + / + {(loadData.allHoursInRefinish || 0) && + loadData.allHoursInRefinish.toFixed(1)} + /{(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(1)} + + + + {(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(1)} + + +
    diff --git a/client/src/redux/application/application.sagas.js b/client/src/redux/application/application.sagas.js index dc907da74..ff6cb91b0 100644 --- a/client/src/redux/application/application.sagas.js +++ b/client/src/redux/application/application.sagas.js @@ -131,7 +131,12 @@ export function* calculateScheduleLoad({ payload: end }) { (load[itemDate].allHoursIn || 0) + item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs; - + load[itemDate].allHoursInBody = + (load[itemDate].allHoursInBody || 0) + + item.labhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].allHoursInRefinish = + (load[itemDate].allHoursInRefinish || 0) + + item.larhrs.aggregate.sum.mod_lb_hrs; //If the job hasn't already arrived, add it to the jobs in list. // Make sure it also hasn't already been completed, or isn't an in and out job. //This prevents the duplicate counting. @@ -142,6 +147,12 @@ export function* calculateScheduleLoad({ payload: end }) { (load[itemDate].hoursIn || 0) + item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].hoursInBoyd = + (load[itemDate].hoursInBody || 0) + + item.labhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].hoursInRefinish = + (load[itemDate].hoursInRefinish || 0) + + item.larhrs.aggregate.sum.mod_lb_hrs; } } else { load[itemDate] = { @@ -152,10 +163,18 @@ export function* calculateScheduleLoad({ payload: end }) { allHoursIn: item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs, + allHoursInBody: item.labhrs.aggregate.sum.mod_lb_hrs, + allHoursInRefinish: item.larhrs.aggregate.sum.mod_lb_hrs, hoursIn: AddJobForSchedulingCalc ? item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs : 0, + hoursInBody: AddJobForSchedulingCalc + ? item.labhrs.aggregate.sum.mod_lb_hrs + : 0, + hoursInRefinish: AddJobForSchedulingCalc + ? item.larhrs.aggregate.sum.mod_lb_hrs + : 0, }; } }); @@ -179,6 +198,12 @@ export function* calculateScheduleLoad({ payload: end }) { (load[itemDate].allHoursOut || 0) + item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].allHoursOutBody = + (load[itemDate].allHoursOutBody || 0) + + item.labhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].allHoursOutRefinish = + (load[itemDate].allHoursOutRefinish || 0) + + item.larhrs.aggregate.sum.mod_lb_hrs; //Add only the jobs that are still in production to get rid of. //If it's not in production, we'd subtract unnecessarily. load[itemDate].allJobsOut.push(item); @@ -189,6 +214,12 @@ export function* calculateScheduleLoad({ payload: end }) { (load[itemDate].hoursOut || 0) + item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].hoursOutBody = + (load[itemDate].hoursOutBody || 0) + + item.labhrs.aggregate.sum.mod_lb_hrs; + load[itemDate].hoursOutRefinish = + (load[itemDate].hoursOutRefinish || 0) + + item.larhrs.aggregate.sum.mod_lb_hrs; } } else { load[itemDate] = { @@ -201,6 +232,8 @@ export function* calculateScheduleLoad({ payload: end }) { allHoursOut: item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs, + allHoursOutBody: item.labhrs.aggregate.sum.mod_lb_hrs, + allHoursOutRefinish: item.larhrs.aggregate.sum.mod_lb_hrs, }; } }); From 719fa6a67d5e96225b1c13ccb68dad765d598696 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 11 Apr 2024 09:23:20 -0700 Subject: [PATCH 03/10] ProMan totals changes. --- .../jobs-available-table.container.jsx | 54 ++++++++++--------- server/job/job-totals-USA.js | 3 +- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index a8784fda8..5e7681853 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -592,32 +592,34 @@ function ResolveCCCLineIssues(estData, bodyshop) { //Group by line no // For everything but the first one, strip out the price number in - // InstanceRenderManager({executeFunction:true, args:[], promanager: () => { - // const groupedByLineRef = _.groupBy(estData.joblines.data, "line_ref"); - // Object.keys(groupedByLineRef).forEach((lineRef) => { - // let index0ActPrice; - // groupedByLineRef[lineRef].forEach((line, index) => { - // //Let the first one keep it - // if (index === 0){ - // index0ActPrice = line.act_price; - // return;} - // //Web Est seems to have additional costs with UNQ_SEQ 0. Keep them all? - // if (line.unq_seq === 0) return; - // if(index0ActPrice !== line.act_price){ - // line.notes += ` | Price override.`; - // return; - // } - // const indexInEstData = estData.joblines.data.findIndex( - // (l) => l.unq_seq === line.unq_seq - // ); - // estData.joblines.data[ - // indexInEstData - // ].notes += ` | Scrubbed due to the line_ref issue. (prev act price = ${estData.joblines.data[indexInEstData].act_price})`; - // estData.joblines.data[indexInEstData].act_price = 0; - // estData.joblines.data[indexInEstData].db_price = 0; - // }); - // }) - // }}) + InstanceRenderManager({ + executeFunction: true, + args: [], + promanager: () => { + const groupedByLineRef = _.groupBy(estData.joblines.data, "line_ref"); + Object.keys(groupedByLineRef).forEach((lineRef) => { + let index0ActPrice; + groupedByLineRef[lineRef].forEach((line, index) => { + //Let the first one keep it + if (index === 0) { + index0ActPrice = line.act_price; + return; + } + //Web Est seems to have additional costs with UNQ_SEQ 0. Keep them all? + if (line.unq_seq === 0) return; + if (index0ActPrice !== line.act_price) { + // line.notes += ` | Price override.`; + return; + } + const indexInEstData = estData.joblines.data.findIndex((l) => l.unq_seq === line.unq_seq); + //estData.joblines.data[indexInEstData].notes += + // ` | Act Price delete. (prev act price = ${estData.joblines.data[indexInEstData].act_price})`; + estData.joblines.data[indexInEstData].act_price = 0; + estData.joblines.data[indexInEstData].db_price = 0; + }); + }); + } + }); InstanceRenderManager({ executeFunction: true, diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index 700ea451d..7617099ff 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -924,9 +924,8 @@ function CalculateTaxesTotals(job, otherTotals) { if ( thresholdAmount === 9999.99 || InstanceMgr({ - debug: true, imex: false, - rome: false, + rome: thresholdAmount === 0 && parseInt(tyCounter) === 1, promanager: thresholdAmount === 0 && parseInt(tyCounter) === 1 }) ) { From 453236cf3ae812bb39555e2637e8883bdbd7aae1 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 11 Apr 2024 09:49:00 -0700 Subject: [PATCH 04/10] Bug fixes and formatting for RO guard. --- bodyshop_translations.babel | 21 +++++ .../job-close-ro-gaurd.labor.jsx | 38 ++++----- .../job-close-ro-guard.ar.jsx | 38 ++++----- .../job-close-ro-guard.bills.jsx | 24 +++--- .../job-close-ro-guard.container.jsx | 23 ++++-- .../job-close-ro-guard.profit.jsx | 34 ++++---- .../job-close-ro-guard.sublet.jsx | 81 ++++++++----------- .../job-close-ro-guard.tt-lifecycle.jsx | 14 ++-- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 11 files changed, 146 insertions(+), 130 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8683bea4c..b8ca6e6f1 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -34201,6 +34201,27 @@ + + profitbypassrequired + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + profits false diff --git a/client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx b/client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx index 8a874d5b7..82721ccbc 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx @@ -1,20 +1,20 @@ -import React from 'react'; +import React from "react"; -import { useQuery } from '@apollo/client'; -import { useSplitTreatments } from '@splitsoftware/splitio-react'; -import { connect } from 'react-redux'; -import { createStructuredSelector } from 'reselect'; -import { GET_LINE_TICKET_BY_PK } from '../../graphql/jobs-lines.queries'; -import { selectJobReadOnly } from '../../redux/application/application.selectors'; -import { selectBodyshop } from '../../redux/user/user.selectors'; -import AlertComponent from '../alert/alert.component'; -import LaborAllocationsTableComponent from '../labor-allocations-table/labor-allocations-table.component'; -import PayrollLaborAllocationsTable from '../labor-allocations-table/labor-allocations-table.payroll.component'; -import LoadingSkeleton from '../loading-skeleton/loading-skeleton.component'; +import { useQuery } from "@apollo/client"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries"; +import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import AlertComponent from "../alert/alert.component"; +import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component"; +import PayrollLaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.payroll.component"; +import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, - jobRO: selectJobReadOnly, + jobRO: selectJobReadOnly }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -24,21 +24,21 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardLabor export function JobCloseRoGuardLabor({ job, jobRO, bodyshop, form, warningCallback }) { const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { variables: { id: job.id }, - fetchPolicy: 'network-only', - nextFetchPolicy: 'network-only', + fetchPolicy: "network-only", + nextFetchPolicy: "network-only" }); const { - treatments: { Enhanced_Payroll }, + treatments: { Enhanced_Payroll } } = useSplitTreatments({ attributes: {}, - names: ['Enhanced_Payroll'], - splitKey: bodyshop.imexshopid, + names: ["Enhanced_Payroll"], + splitKey: bodyshop.imexshopid }); if (loading) return ; if (error) return ; - return Enhanced_Payroll.treatment === 'on' ? ( + return Enhanced_Payroll.treatment === "on" ? ( ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -41,25 +41,21 @@ export function JobCloseRoGuardProfit({ job, jobRO, bodyshop, form, warningCallb useEffect(() => { if (balance.getAmount() !== 0) { - warningCallback({ key: 'ar', warning: t('jobs.labels.outstanding_ar') }); + warningCallback({ key: "ar", warning: t("jobs.labels.outstanding_ar") }); } }, [balance, t, warningCallback]); return ( - - {total.toFormat()} + + {total.toFormat()} {balance.toFormat()} {balance.getAmount() !== 0 && ( - + )} ); diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx index 23a0fe478..4bf03ea46 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx @@ -1,17 +1,17 @@ -import React from 'react'; +import React from "react"; -import { useQuery } from '@apollo/client'; -import { connect } from 'react-redux'; -import { createStructuredSelector } from 'reselect'; -import { QUERY_BILLS_BY_JOBID } from '../../graphql/bills.queries'; -import { selectJobReadOnly } from '../../redux/application/application.selectors'; -import { selectBodyshop } from '../../redux/user/user.selectors'; -import AlertComponent from '../alert/alert.component'; -import JobBillsTotalComponent from '../job-bills-total/job-bills-total.component'; +import { useQuery } from "@apollo/client"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries"; +import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import AlertComponent from "../alert/alert.component"; +import JobBillsTotalComponent from "../job-bills-total/job-bills-total.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, - jobRO: selectJobReadOnly, + jobRO: selectJobReadOnly }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -21,8 +21,8 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) { const { loading, error, data } = useQuery(QUERY_BILLS_BY_JOBID, { variables: { jobid: job.id }, - fetchPolicy: 'network-only', - nextFetchPolicy: 'network-only', + fetchPolicy: "network-only", + nextFetchPolicy: "network-only" }); if (error) return ; diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx index 04a07bd98..8dfdb1574 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx @@ -76,20 +76,27 @@ export function JobCloseRoGuardContainer({ job, jobRO, bodyshop, form }) { - + - - - {InstanceRenderManager({ rome: })} - + {InstanceRenderManager({ + imex: ( + + {/* */} + + + ), + rome: ( + + {/* */} + + + ) + })} diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx index 4cbbca357..2add7848d 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx @@ -1,20 +1,19 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState } from "react"; -import { LockOutlined } from '@ant-design/icons'; -import { Card, Form, Input } from 'antd'; -import axios from 'axios'; -import { useTranslation } from 'react-i18next'; -import { connect } from 'react-redux'; -import { createStructuredSelector } from 'reselect'; -import { selectJobReadOnly } from '../../redux/application/application.selectors'; -import { selectBodyshop } from '../../redux/user/user.selectors'; -import JobCostingStatistics from '../job-costing-statistics/job-costing-statistics.component'; -import LoadingSkeleton from '../loading-skeleton/loading-skeleton.component'; +import { Alert, Card } from "antd"; +import axios from "axios"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import JobCostingStatistics from "../job-costing-statistics/job-costing-statistics.component"; +import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, - jobRO: selectJobReadOnly, + jobRO: selectJobReadOnly }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -31,7 +30,7 @@ export function JobCloseRoGuardProfit({ job, jobRO, bodyshop, form, warningCallb try { if (job.id) { setLoading(true); - const { data } = await axios.post('/job/costing', { jobid: job.id }); + const { data } = await axios.post("/job/costing", { jobid: job.id }); setCostingData(data); } } catch (error) {} @@ -45,16 +44,19 @@ export function JobCloseRoGuardProfit({ job, jobRO, bodyshop, form, warningCallb parseFloat(costingData?.summaryData.gppercent) < bodyshop?.md_ro_guard?.totalgppercent_minimum; useEffect(() => { - if (enforceProfitPassword && typeof warningCallback === 'function') { - warningCallback({ key: 'profit', warning: t('jobs.labels.profitbypassrequired') }); + if (enforceProfitPassword && typeof warningCallback === "function") { + warningCallback({ key: "profit", warning: t("jobs.labels.profitbypassrequired") }); } }, [enforceProfitPassword, t, warningCallback]); if (loading || !costingData) return ; return ( - + + {enforceProfitPassword && ( + + )} ); } diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.sublet.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.sublet.jsx index e44e58adf..c6468c012 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-guard.sublet.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.sublet.jsx @@ -1,17 +1,17 @@ -import React, { useEffect } from 'react'; +import React, { useEffect } from "react"; -import { Alert, Card, Table } from 'antd'; -import { t } from 'i18next'; -import { connect } from 'react-redux'; -import { createStructuredSelector } from 'reselect'; -import { selectJobReadOnly } from '../../redux/application/application.selectors'; -import { selectBodyshop } from '../../redux/user/user.selectors'; -import CurrencyFormatter from '../../utils/CurrencyFormatter'; -import { alphaSort } from '../../utils/sorters'; +import { Alert, Card, Table } from "antd"; +import { t } from "i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import CurrencyFormatter from "../../utils/CurrencyFormatter"; +import { alphaSort } from "../../utils/sorters"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, - jobRO: selectJobReadOnly, + jobRO: selectJobReadOnly }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -20,69 +20,56 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRGuardSublet export function JobCloseRGuardSublet({ job, jobRO, bodyshop, form, warningCallback }) { const subletsNotDone = job?.joblines.filter( - (j) => - (j.part_type === 'PAS' || j.part_type === 'PASL') && - (!j.sublet_completed || !j.sublet_ignored) + (j) => (j.part_type === "PAS" || j.part_type === "PASL") && (!j.sublet_completed || !j.sublet_ignored) ); const columns = [ { - title: t('joblines.fields.line_desc'), - dataIndex: 'line_desc', - fixed: 'left', - key: 'line_desc', + title: t("joblines.fields.line_desc"), + dataIndex: "line_desc", + fixed: "left", + key: "line_desc", sorter: (a, b) => alphaSort(a.line_desc, b.line_desc), onCell: (record) => ({ - className: record.manual_line && 'job-line-manual', + className: record.manual_line && "job-line-manual", style: { - ...(record.critical ? { boxShadow: ' -.5em 0 0 #FFC107' } : {}), - }, + ...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {}) + } }), - ellipsis: true, + ellipsis: true }, { - title: t('joblines.fields.act_price'), - dataIndex: 'act_price', - key: 'act_price', + title: t("joblines.fields.act_price"), + dataIndex: "act_price", + key: "act_price", sorter: (a, b) => a.act_price - b.act_price, ellipsis: true, - render: (text, record) => {record.act_price}, + render: (text, record) => {record.act_price} }, { - title: t('joblines.fields.part_qty'), - dataIndex: 'part_qty', - key: 'part_qty', + title: t("joblines.fields.part_qty"), + dataIndex: "part_qty", + key: "part_qty" }, { - title: t('joblines.fields.notes'), - dataIndex: 'notes', - key: 'notes', - }, + title: t("joblines.fields.notes"), + dataIndex: "notes", + key: "notes" + } ]; useEffect(() => { if (subletsNotDone.length > 0) { - warningCallback({ key: 'sublet', warning: t('jobs.labels.outstanding_sublets') }); + warningCallback({ key: "sublet", warning: t("jobs.labels.outstanding_sublets") }); } }, [subletsNotDone.length, warningCallback]); return ( - - + +
    {subletsNotDone.length > 0 && ( - + )} ); diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx index 1b0f60514..2fe16e07d 100644 --- a/client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx @@ -1,14 +1,14 @@ -import React from 'react'; +import React from "react"; -import { connect } from 'react-redux'; -import { createStructuredSelector } from 'reselect'; -import { selectJobReadOnly } from '../../redux/application/application.selectors'; -import { selectBodyshop } from '../../redux/user/user.selectors'; -import JobLifecycleComponent from '../job-lifecycle/job-lifecycle.component'; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import JobLifecycleComponent from "../job-lifecycle/job-lifecycle.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, - jobRO: selectJobReadOnly, + jobRO: selectJobReadOnly }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 7f62004ec..9c398c1ec 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2003,6 +2003,7 @@ "ppc": "This line contains a part price change.", "ppdnotexported": "PPDs not Exported", "profileadjustments": "Profile Disc./Mkup", + "profitbypassrequired": "Minimum gross profit requirements have not been met.", "profits": "Job Profits", "prt_dsmk_total": "Line Item Adjustment", "rates": "Rates", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 1a710dc95..72c5de71b 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2003,6 +2003,7 @@ "ppc": "", "ppdnotexported": "", "profileadjustments": "", + "profitbypassrequired": "", "profits": "", "prt_dsmk_total": "", "rates": "Tarifas", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 25d9e4dde..4bc52d79f 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2003,6 +2003,7 @@ "ppc": "", "ppdnotexported": "", "profileadjustments": "", + "profitbypassrequired": "", "profits": "", "prt_dsmk_total": "", "rates": "Les taux", From 63f7106d2bc63b5f24e1a6f3829dbd8a2e7536aa Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 11 Apr 2024 11:55:55 -0700 Subject: [PATCH 05/10] IO-2752 BO ETA Jobline Expander Signed-off-by: Allan Carr --- .../job-lines-expander.component.jsx | 34 +++++++++++++------ client/src/graphql/jobs.queries.js | 2 ++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/client/src/components/job-detail-lines/job-lines-expander.component.jsx b/client/src/components/job-detail-lines/job-lines-expander.component.jsx index 06e00c729..6dab1eb8c 100644 --- a/client/src/components/job-detail-lines/job-lines-expander.component.jsx +++ b/client/src/components/job-detail-lines/job-lines-expander.component.jsx @@ -1,5 +1,5 @@ import { useQuery } from "@apollo/client"; -import { Col, Divider, Row, Skeleton, Space, Timeline, Typography } from "antd"; +import { Col, Row, Skeleton, Timeline, Typography } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; @@ -31,15 +31,27 @@ export default function JobLinesExpander({ jobline, jobid }) { {data.parts_order_lines.length > 0 ? ( data.parts_order_lines.map((line) => ( - } wrap> - - {line.parts_order.order_number} - - {line.parts_order.order_date} - {line.parts_order.vendor.name} - + + + + {line.parts_order.order_number} + + + + {line.parts_order.order_date} + + {line.parts_order.vendor.name} + {line.backordered_eta ? ( + + + {`${t("parts_orders.fields.backordered_eta")}: `} + {line.backordered_eta} + + + ) : null} + )) ) : ( @@ -71,7 +83,7 @@ export default function JobLinesExpander({ jobline, jobid }) { - {`${t("billlines.fields.actual_cost")}: `} + {`${t("billlines.fields.actual_cost")}: `} {line.actual_cost} diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 31f9be07c..0cd49d52b 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -2205,6 +2205,8 @@ export const GET_JOB_LINE_ORDERS = gql` parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) { id act_price + backordered_eta + backordered_on parts_order { id order_date From ce2086a480f45849065bf620ee5aeda7baa3667d Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 11 Apr 2024 12:43:14 -0700 Subject: [PATCH 06/10] IO-2753 Parts Order/Return Quantity restrict to above 0 Signed-off-by: Allan Carr --- .../parts-order-modal.component.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/components/parts-order-modal/parts-order-modal.component.jsx b/client/src/components/parts-order-modal/parts-order-modal.component.jsx index 7ce456280..8fcbe4007 100644 --- a/client/src/components/parts-order-modal/parts-order-modal.component.jsx +++ b/client/src/components/parts-order-modal/parts-order-modal.component.jsx @@ -1,17 +1,17 @@ -import { DeleteFilled, WarningFilled, DownOutlined } from "@ant-design/icons"; +import { DeleteFilled, DownOutlined, WarningFilled } from "@ant-design/icons"; import { useTreatments } from "@splitsoftware/splitio-react"; import { + Checkbox, Divider, + Dropdown, Form, Input, InputNumber, + Menu, Radio, + Select, Space, Tag, - Select, - Menu, - Dropdown, - Checkbox, } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -255,7 +255,7 @@ export function PartsOrderModalComponent({ }, ]} > - + Date: Thu, 11 Apr 2024 13:07:43 -0700 Subject: [PATCH 07/10] Minor bug fixes. --- bodyshop_translations.babel | 2 +- .../job-bills-total.component.jsx | 102 ++++++++---------- .../job-close-ro-guard.container.jsx | 6 -- client/src/translations/en_us/common.json | 2 +- 4 files changed, 49 insertions(+), 63 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index b8ca6e6f1..3d2e3dca2 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1,4 +1,4 @@ - +