diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 6c5575efc..8c6af0eb4 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -26589,6 +26589,27 @@ + + parts_received + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + parts_tax_rates false @@ -31189,6 +31210,37 @@ + + owner + + + labels + + + noownerinfo + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + owners diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index 0e1ddc327..a1463ba40 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -63,10 +63,11 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim(); - console.log( - "🚀 ~ file: jobs-detail-header.component.jsx ~ line 64 ~ vehicleTitle", - vehicleTitle.length - ); + + const ownerTitle = `${job.ownr_fn || ""} ${job.ownr_ln || ""} ${ + job.ownr_co_nm || "" + }`.trim(); + return ( @@ -159,9 +160,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { style={{ height: "100%" }} title={ - {`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${ - job.ownr_co_nm || "" - }`} + {ownerTitle.length > 0 + ? ownerTitle + : t("owner.labels.noownerinfo")} } > diff --git a/client/src/components/production-list-columns/production-list-columns.data.js b/client/src/components/production-list-columns/production-list-columns.data.js index cda6fd57a..5a73e2629 100644 --- a/client/src/components/production-list-columns/production-list-columns.data.js +++ b/client/src/components/production-list-columns/production-list-columns.data.js @@ -21,6 +21,7 @@ import ProductionListColumnStatus from "./production-list-columns.status.compone import ProductionListColumnCategory from "./production-list-columns.status.category"; import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component"; import ProductionListColumnComment from "./production-list-columns.comment.component"; +import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component"; const r = ({ technician, state, activeStatuses, bodyshop }) => { return [ @@ -96,7 +97,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => { sortOrder: state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order, render: (text, record) => ( - + ), }, { @@ -477,6 +478,14 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => { /> ), }, + { + title: i18n.t("jobs.labels.parts_received"), + dataIndex: "parts_received", + key: "parts_received", + render: (text, record) => ( + + ), + }, ]; }; export default r; diff --git a/client/src/components/production-list-columns/production-list-columns.partsreceived.component.jsx b/client/src/components/production-list-columns/production-list-columns.partsreceived.component.jsx new file mode 100644 index 000000000..e1948ff94 --- /dev/null +++ b/client/src/components/production-list-columns/production-list-columns.partsreceived.component.jsx @@ -0,0 +1,41 @@ +import { 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 default connect( + mapStateToProps, + mapDispatchToProps +)(ProductionListColumnPartsReceived); + +export function ProductionListColumnPartsReceived({ bodyshop, record }) { + const amount = useMemo(() => { + const amount = record.joblines_status.reduce( + (acc, val) => { + acc.total += val.count; + acc.received = + val.status === bodyshop.md_order_statuses.default_received + ? acc.received + val.count + : acc.received; + return acc; + }, + { total: 0, received: 0 } + ); + + return { + ...amount, + percent: + amount.total !== 0 + ? ((amount.received / amount.total) * 100).toFixed(0) + "%" + : "N/A", + }; + }, [record, bodyshop.md_order_statuses]); + + return `${amount.percent} (${amount.received}/${amount.total})`; +} diff --git a/client/src/components/production-list-table/production-list-table.component.jsx b/client/src/components/production-list-table/production-list-table.component.jsx index d0a620819..a42ed413d 100644 --- a/client/src/components/production-list-table/production-list-table.component.jsx +++ b/client/src/components/production-list-table/production-list-table.component.jsx @@ -88,12 +88,6 @@ export function ProductionListTable({ ); const handleTableChange = (pagination, filters, sorter) => { - console.log( - "🚀 ~ file: production-list-table.component.jsx ~ line 91 ~ pagination, filters, sorter", - pagination, - filters, - sorter - ); setState({ ...state, filteredInfo: filters, diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 9f4c1664c..aabb3670a 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -146,6 +146,11 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql` employee_refinish employee_prep employee_csr + joblines_status{ + part_type + status + count + } labhrs: joblines_aggregate( where: { _and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }] @@ -219,6 +224,11 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql` employee_refinish employee_prep employee_csr + joblines_status{ + part_type + status + count + } labhrs: joblines_aggregate( where: { _and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }] @@ -294,6 +304,11 @@ export const QUERY_JOBS_IN_PRODUCTION = gql` employee_prep employee_csr suspended + joblines_status{ + part_type + status + count + } labhrs: joblines_aggregate( where: { _and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }] diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index e66d3d3e4..8ed44e230 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1563,6 +1563,7 @@ "override_header": "Override estimate header on import?", "ownerassociation": "Owner Association", "parts": "Parts", + "parts_received": "Parts Rec.", "parts_tax_rates": "Parts Tax rates", "partsfilter": "Parts Only", "partssubletstotal": "Parts & Sublets Total", @@ -1842,6 +1843,11 @@ "updated": "Note updated successfully." } }, + "owner": { + "labels": { + "noownerinfo": "No owner information." + } + }, "owners": { "actions": { "update": "Update Selected Records" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 50f393073..d99f0b7c7 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1563,6 +1563,7 @@ "override_header": "¿Anular encabezado estimado al importar?", "ownerassociation": "", "parts": "Partes", + "parts_received": "", "parts_tax_rates": "", "partsfilter": "", "partssubletstotal": "", @@ -1842,6 +1843,11 @@ "updated": "Nota actualizada con éxito." } }, + "owner": { + "labels": { + "noownerinfo": "" + } + }, "owners": { "actions": { "update": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 8a9be8021..b32145edc 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1563,6 +1563,7 @@ "override_header": "Remplacer l'en-tête d'estimation à l'importation?", "ownerassociation": "", "parts": "les pièces", + "parts_received": "", "parts_tax_rates": "", "partsfilter": "", "partssubletstotal": "", @@ -1842,6 +1843,11 @@ "updated": "Remarque mise à jour avec succès." } }, + "owner": { + "labels": { + "noownerinfo": "" + } + }, "owners": { "actions": { "update": ""