From 8ea7db64886bf7096d9564e71dc5af8cb7735405 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 19 Mar 2024 08:10:45 -0700 Subject: [PATCH] WIP RO Closer. --- bodyshop_translations.babel | 21 +++ .../job-close-ro-gaurd.labor.jsx | 57 +++++++++ .../job-close-ro-guard.bills.jsx | 38 ++++++ .../job-close-ro-guard.container.jsx | 51 ++++++++ .../job-close-ro-guard.profit.jsx | 80 ++++++++++++ .../job-close-ro-guard.totals.jsx | 26 ++++ .../job-close-ro-guard.tt-lifecycle.jsx | 25 ++++ .../job-costing-statistics.component.jsx | 121 +++++++++--------- .../pages/jobs-close/jobs-close.component.jsx | 3 +- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 12 files changed, 364 insertions(+), 61 deletions(-) create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-guard.totals.jsx create mode 100644 client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index bac95454e..2734144d1 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -33645,6 +33645,27 @@ + + profitbypassrequired + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + prt_dsmk_total 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 new file mode 100644 index 000000000..71954458a --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-gaurd.labor.jsx @@ -0,0 +1,57 @@ +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'; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardLabor); + +export function JobCloseRoGuardLabor({ job, jobRO, bodyshop, form }) { + const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, { + variables: { id: job.id }, + fetchPolicy: 'network-only', + nextFetchPolicy: 'network-only', + }); + const { + treatments: { Enhanced_Payroll }, + } = useSplitTreatments({ + attributes: {}, + names: ['Enhanced_Payroll'], + splitKey: bodyshop.imexshopid, + }); + + if (loading) return ; + if (error) return ; + + return Enhanced_Payroll.treatment === 'on' ? ( + + ) : ( + + ); +} 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 new file mode 100644 index 000000000..c8949d873 --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.bills.jsx @@ -0,0 +1,38 @@ +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'; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills); + +export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form }) { + const { loading, error, data } = useQuery(QUERY_BILLS_BY_JOBID, { + variables: { jobid: job.id }, + fetchPolicy: 'network-only', + nextFetchPolicy: 'network-only', + }); + + if (error) return ; + + 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 new file mode 100644 index 000000000..329e6a51e --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.container.jsx @@ -0,0 +1,51 @@ +import React from 'react'; + +import { Col, Row } from 'antd'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import { selectJobReadOnly } from '../../redux/application/application.selectors'; +import { selectBodyshop } from '../../redux/user/user.selectors'; +import JobCloseRoGuardBills from './job-close-ro-guard.bills'; +import JobCloseRoGuardTotals from './job-close-ro-guard.totals'; +import JobCloseRoGuardLabor from './job-close-ro-gaurd.labor'; +import JobCloseRoGuardTtLifecycle from './job-close-ro-guard.tt-lifecycle'; +import JobCloseRoGuardProfit from './job-close-ro-guard.profit'; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardContainer); + +const colSpans = { + md: 24, + lg: 12, + xl: 8, +}; +export function JobCloseRoGuardContainer({ job, jobRO, bodyshop, form }) { + return ( + + + + + + + + + + + AR Balance + + + + Sublet Manager + PPD Check + + + + + ); +} 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 new file mode 100644 index 000000000..52d78dd73 --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.profit.jsx @@ -0,0 +1,80 @@ +import React, { useEffect, useState } from 'react'; + +import axios from 'axios'; +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 { Card, Form, Input, Space } from 'antd'; +import { useTranslation } from 'react-i18next'; +import { LockOutlined } from '@ant-design/icons'; + +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardProfit); + +export function JobCloseRoGuardProfit({ job, jobRO, bodyshop, form }) { + const [costingData, setCostingData] = useState(null); + const [loading, setLoading] = useState(false); + const { t } = useTranslation(); + + useEffect(() => { + async function getData() { + try { + if (job.id) { + setLoading(true); + const { data } = await axios.post('/job/costing', { jobid: job.id }); + setCostingData(data); + } + } catch (error) {} + setLoading(false); + } + + getData(); + }, [job.id]); + + if (loading || !costingData) return ; + + const enforceProfitPassword = parseFloat(costingData?.summaryData.gppercent) < 90; + return ( + + + + {' '} + {enforceProfitPassword && ( + ({ + validator(_, value) { + if ( + parseFloat(costingData?.summaryData.gppercent) < + bodyshop.md_ro_guard.totalgppercent_minimum && + value !== bodyshop.md_ro_guard.profitbypasspassword + ) { + console.log('We shoudl enforce it.'); + return Promise.reject(t('jobs.labels.profitbypassrequired')); + } + return Promise.resolve(); + }, + }), + ]} + > + } type="password" placeholder="Password" /> + + )} + + ); +} diff --git a/client/src/components/job-close-ro-guard/job-close-ro-guard.totals.jsx b/client/src/components/job-close-ro-guard/job-close-ro-guard.totals.jsx new file mode 100644 index 000000000..e765c941c --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.totals.jsx @@ -0,0 +1,26 @@ +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 JobTotalsTableTotals from '../job-totals-table/job-totals.table.totals.component'; +import { Card } from 'antd'; +import { t } from 'i18next'; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRGuardTotals); + +export function JobCloseRGuardTotals({ job, jobRO, bodyshop, form }) { + return ( + + + + ); +} 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 new file mode 100644 index 000000000..b653d5ba8 --- /dev/null +++ b/client/src/components/job-close-ro-guard/job-close-ro-guard.tt-lifecycle.jsx @@ -0,0 +1,25 @@ +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'; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, + jobRO: selectJobReadOnly, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardTTLifeCycle); + +export function JobCloseRoGuardTTLifeCycle({ job, jobRO, bodyshop, form }) { + return ( +
+ Add Touch Time + +
+ ); +} diff --git a/client/src/components/job-costing-statistics/job-costing-statistics.component.jsx b/client/src/components/job-costing-statistics/job-costing-statistics.component.jsx index fc06e40eb..9f15a4850 100644 --- a/client/src/components/job-costing-statistics/job-costing-statistics.component.jsx +++ b/client/src/components/job-costing-statistics/job-costing-statistics.component.jsx @@ -1,63 +1,64 @@ -import {Statistic} from "antd"; -import React from "react"; -import {useTranslation} from "react-i18next"; -import Dinero from "dinero.js"; +import { Space, Statistic } from 'antd'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import Dinero from 'dinero.js'; -export default function JobCostingStatistics({summaryData}) { - const {t} = useTranslation(); +export default function JobCostingStatistics({ summaryData, onlyGP }) { + const { t } = useTranslation(); - return ( -
-
- - - - - - - - - - - - -
-
- ); + const gpTotals = ( + <> + + + + ); + if (onlyGP) return gpTotals; + + return ( + + + + + + + + + + + + + ); } diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index 44d9b5f86..c6d53c805 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -41,6 +41,7 @@ import {insertAuditTrail} from "../../redux/application/application.actions"; import {selectJobReadOnly} from "../../redux/application/application.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; +import JobCloseRoGuardContainer from '../../components/job-close-ro-guard/job-close-ro-guard.container'; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -193,7 +194,7 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) { } /> - + {!job.actual_in && job.scheduled_in && ( diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 334fdbc42..14bfe5670 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1973,6 +1973,7 @@ }, "ppc": "This line contains a part price change.", "profileadjustments": "Profile Disc./Mkup", + "profitbypassrequired": "Profit margin requirements not met. Bypass password required.", "prt_dsmk_total": "Line Item Adjustment", "rates": "Rates", "rates_subtotal": "All Rates Subtotal", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 3bdda9711..da6703881 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1973,6 +1973,7 @@ }, "ppc": "", "profileadjustments": "", + "profitbypassrequired": "", "prt_dsmk_total": "", "rates": "Tarifas", "rates_subtotal": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 8f180d52a..ae10b4070 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1973,6 +1973,7 @@ }, "ppc": "", "profileadjustments": "", + "profitbypassrequired": "", "prt_dsmk_total": "", "rates": "Les taux", "rates_subtotal": "",