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": ""