diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 7b07e622e..15e3f0071 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -16878,6 +16878,27 @@ + + prt_dsmk_m + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + prt_dsmk_p false @@ -25960,6 +25981,27 @@ + + savebeforeconversion + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + scheduledinchange false diff --git a/client/package.json b/client/package.json index 8f86c402f..e262f3a62 100644 --- a/client/package.json +++ b/client/package.json @@ -12,29 +12,29 @@ "@openreplay/tracker-assist": "^3.4.3", "@openreplay/tracker-graphql": "^3.0.0", "@openreplay/tracker-redux": "^3.0.0", - "@sentry/react": "^6.13.2", - "@sentry/tracing": "^6.13.2", - "@stripe/react-stripe-js": "^1.5.0", + "@sentry/react": "^6.13.3", + "@sentry/tracing": "^6.13.3", + "@stripe/react-stripe-js": "^1.6.0", "@stripe/stripe-js": "^1.19.1", - "@tanem/react-nprogress": "^3.0.79", + "@tanem/react-nprogress": "^3.0.80", "antd": "^4.16.13", "apollo-link-logger": "^2.0.0", - "axios": "^0.22.0", + "axios": "^0.23.0", "craco-less": "^1.20.0", - "dinero.js": "^1.9.0", + "dinero.js": "^1.9.1", "dotenv": "^10.0.0", "enquire-js": "^0.2.1", "env-cmd": "^10.1.0", "exifr": "^7.1.3", - "firebase": "^9.1.1", - "graphql": "^15.6.0", - "i18next": "^21.2.4", + "firebase": "^9.1.2", + "graphql": "^15.6.1", + "i18next": "^21.3.0", "i18next-browser-languagedetector": "^6.1.2", "jsoneditor": "^9.5.6", "jsreport-browser-client-dist": "^1.3.0", - "libphonenumber-js": "^1.9.36", - "logrocket": "^2.0.0", - "markerjs2": "^2.13.0", + "libphonenumber-js": "^1.9.37", + "logrocket": "^2.1.0", + "markerjs2": "^2.14.0", "moment-business-days": "^1.2.0", "phone": "^3.1.8", "preval.macro": "^5.0.0", @@ -69,7 +69,7 @@ "socket.io-client": "^4.2.0", "styled-components": "^5.3.1", "subscriptions-transport-ws": "^0.9.18", - "web-vitals": "^2.1.0", + "web-vitals": "^2.1.2", "workbox-background-sync": "^6.3.0", "workbox-broadcast-update": "^6.3.0", "workbox-cacheable-response": "^6.3.0", @@ -114,7 +114,7 @@ ] }, "devDependencies": { - "@sentry/webpack-plugin": "^1.17.2", + "@sentry/webpack-plugin": "^1.18.0", "patch-package": "^6.4.7", "redux-logger": "^3.0.6", "source-map-explorer": "^2.5.2" diff --git a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx index 2edc4a0a4..53a51bdae 100644 --- a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx +++ b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx @@ -8,8 +8,26 @@ import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter"; import { alphaSort, dateSort } from "../../utils/sorters"; import PaymentExportButton from "../payment-export-button/payment-export-button.component"; import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component"; +import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors"; -export default function AccountingPayablesTableComponent({ +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); + +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(AccountingPayablesTableComponent); + +export function AccountingPayablesTableComponent({ + bodyshop, loading, payments, }) { @@ -163,6 +181,9 @@ export default function AccountingPayablesTableComponent({ loadingCallback={setTransInProgress} completedCallback={setSelectedPayments} /> + {bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && ( + + )} ); diff --git a/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx b/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx index d3b7d6028..73dd0675b 100644 --- a/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx +++ b/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx @@ -31,6 +31,7 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) { {t("joblines.fields.line_desc")} {t("joblines.fields.part_type")} {t("joblines.fields.act_price")} + {t("joblines.fields.prt_dsmk_m")} {t("joblines.fields.op_code_desc")} {t("joblines.fields.mod_lbr_ty")} {t("joblines.fields.mod_lb_hrs")} @@ -70,6 +71,16 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) { + + + + + { + if (parentFormIsFieldsTouched()) { + alert(t("jobs.labels.savebeforeconversion")); + return; + } setLoading(true); const res = await mutationConvertJob({ variables: { jobId: job.id, ...values }, diff --git a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx index 1670ddf22..5c5709558 100644 --- a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx +++ b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx @@ -197,7 +197,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) { - + - + diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx index 76b02aa52..6afef83ad 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx @@ -21,47 +21,61 @@ export function JobsDetailHeaderActionexportCustomerData({ const handleExportCustData = async (e) => { logImEXEvent("job_export_cust_data"); - let QbXmlResponse; - try { - QbXmlResponse = await axios.post( - "/accounting/qbxml/receivables", - { jobIds: [job.id], custDataOnly: true }, - { - headers: { - Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, - }, - } - ); - console.log("handle -> XML", QbXmlResponse); - } catch (error) { - console.log("Error getting QBXML from Server.", error); - notification["error"]({ - message: t("jobs.errors.exporting", { - error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), - }), - }); - - return; - } - let PartnerResponse; - try { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { PartnerResponse = await axios.post( - "http://localhost:1337/qb/", - QbXmlResponse.data, + `/qbo/receivables`, { - headers: { - Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, - }, - } + jobIds: [job.id], + custDataOnly: true, + }, + { withCredentials: true } ); - } catch (error) { - console.log("Error connecting to quickbooks or partner.", error); - notification["error"]({ - message: t("jobs.errors.exporting-partner"), - }); + } else { + //Default is QBD - return; + let QbXmlResponse; + try { + QbXmlResponse = await axios.post( + "/accounting/qbxml/receivables", + { jobIds: [job.id], custDataOnly: true }, + { + headers: { + Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, + }, + } + ); + console.log("handle -> XML", QbXmlResponse); + } catch (error) { + console.log("Error getting QBXML from Server.", error); + notification["error"]({ + message: t("jobs.errors.exporting", { + error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), + }), + }); + + return; + } + + //let PartnerResponse; + try { + PartnerResponse = await axios.post( + "http://localhost:1337/qb/", + QbXmlResponse.data, + { + headers: { + Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, + }, + } + ); + } catch (error) { + console.log("Error connecting to quickbooks or partner.", error); + notification["error"]({ + message: t("jobs.errors.exporting-partner"), + }); + + return; + } } //Check to see if any of them failed. If they didn't don't execute the update. const failedTransactions = PartnerResponse.data.filter((r) => !r.success); diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx index 69b15dcfc..8862bceeb 100644 --- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx +++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx @@ -13,6 +13,7 @@ import { selectBodyshop, selectCurrentUser, } from "../../redux/user/user.selectors"; +import { useCookies } from "react-cookie"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -30,6 +31,7 @@ export function JobsExportAllButton({ const { t } = useTranslation(); const [updateJob] = useMutation(UPDATE_JOBS); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); + const [cookies] = useCookies(); const [loading, setLoading] = useState(false); const handleQbxml = async () => { @@ -37,10 +39,13 @@ export function JobsExportAllButton({ let PartnerResponse; setLoading(true); if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { - PartnerResponse = await axios.post(`/qbo/receivables`, { - withCredentials: true, - jobIds: jobIds, - }); + PartnerResponse = await axios.post( + `/qbo/receivables`, + { + jobIds: jobIds, + }, + { withCredentials: true } + ); } else { let QbXmlResponse; try { @@ -173,8 +178,12 @@ export function JobsExportAllButton({ diff --git a/client/src/components/owner-find-modal/owner-find-modal.component.jsx b/client/src/components/owner-find-modal/owner-find-modal.component.jsx index 896995497..eb2a6e068 100644 --- a/client/src/components/owner-find-modal/owner-find-modal.component.jsx +++ b/client/src/components/owner-find-modal/owner-find-modal.component.jsx @@ -74,7 +74,6 @@ export default function OwnerFindModalComponent({ return (
t("owners.labels.existing_owners")} pagination={{ position: "bottom" }} columns={columns} rowKey="id" diff --git a/client/src/components/owner-find-modal/owner-find-modal.container.jsx b/client/src/components/owner-find-modal/owner-find-modal.container.jsx index 284c42adf..7e59b1f85 100644 --- a/client/src/components/owner-find-modal/owner-find-modal.container.jsx +++ b/client/src/components/owner-find-modal/owner-find-modal.container.jsx @@ -1,6 +1,6 @@ -import { Modal } from "antd"; -import React from "react"; -import { useQuery } from "@apollo/client"; +import { useLazyQuery } from "@apollo/client"; +import { Input, Modal } from "antd"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries"; import AlertComponent from "../alert/alert.component"; @@ -17,14 +17,27 @@ export default function OwnerFindModalContainer({ }) { //use owner object to run query and find what possible owners there are. const { t } = useTranslation(); + const [searchText, setSearchText] = useState(null); - const ownersList = useQuery(QUERY_SEARCH_OWNER_BY_IDX, { - variables: { - search: owner ? `${owner.ownr_fn || ""} ${owner.ownr_ln || ""}` : null, - }, - skip: !owner, - fetchPolicy: "network-only", - }); + const [callSearchowners, ownersList] = useLazyQuery( + QUERY_SEARCH_OWNER_BY_IDX, + { + variables: { + search: searchText, + }, + } + ); + + useEffect(() => { + if (modalProps.visible && owner) { + const s = `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${ + owner.ownr_co_nm || "" + }`; + + setSearchText(s.trim()); + callSearchowners({ variables: { search: s.trim() } }); + } + }, [callSearchowners, modalProps.visible, owner]); return ( : null} {error ? : null} {owner ? ( - + <> + setSearchText(e.target.value)} + onSearch={(val) => + callSearchowners({ variables: { search: val.trim() } }) + } + /> + + ) : null} ); diff --git a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx index 5845fbb73..95fd184b2 100644 --- a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx +++ b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx @@ -14,6 +14,7 @@ import { import { logImEXEvent } from "../../firebase/firebase.utils"; import _ from "lodash"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; +import { useCookies } from "react-cookie"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -32,6 +33,7 @@ export function PayableExportAll({ const [updateBill] = useMutation(UPDATE_BILLS); const [loading, setLoading] = useState(false); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); + const [cookies] = useCookies(); const handleQbxml = async () => { logImEXEvent("accounting_payables_export_all"); @@ -40,10 +42,13 @@ export function PayableExportAll({ setLoading(true); if (!!loadingCallback) loadingCallback(true); if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { - PartnerResponse = await axios.post(`/qbo/receivables`, { - withCredentials: true, - bills: billids, - }); + PartnerResponse = await axios.post( + `/qbo/receivables`, + { + bills: billids, + }, + { withCredentials: true } + ); } else { let QbXmlResponse; try { @@ -172,8 +177,12 @@ export function PayableExportAll({ diff --git a/client/src/components/payable-export-button/payable-export-button.component.jsx b/client/src/components/payable-export-button/payable-export-button.component.jsx index 6a9fd2494..70b115175 100644 --- a/client/src/components/payable-export-button/payable-export-button.component.jsx +++ b/client/src/components/payable-export-button/payable-export-button.component.jsx @@ -13,6 +13,7 @@ import { } from "../../redux/user/user.selectors"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; +import { useCookies } from "react-cookie"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -31,6 +32,7 @@ export function PayableExportButton({ const [updateBill] = useMutation(UPDATE_BILLS); const [loading, setLoading] = useState(false); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); + const [cookies] = useCookies(); const handleQbxml = async () => { logImEXEvent("accounting_export_payable"); @@ -41,10 +43,13 @@ export function PayableExportButton({ //Check if it's a QBO Setup. let PartnerResponse; if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { - PartnerResponse = await axios.post(`/qbo/payables`, { - withCredentials: true, - bills: [billId], - }); + PartnerResponse = await axios.post( + `/qbo/payables`, + { + bills: [billId], + }, + { withCredentials: true } + ); } else { //Default is QBD @@ -174,8 +179,12 @@ export function PayableExportButton({ diff --git a/client/src/components/payment-export-button/payment-export-button.component.jsx b/client/src/components/payment-export-button/payment-export-button.component.jsx index e6fbacb1e..0d3a124ac 100644 --- a/client/src/components/payment-export-button/payment-export-button.component.jsx +++ b/client/src/components/payment-export-button/payment-export-button.component.jsx @@ -8,6 +8,8 @@ import { createStructuredSelector } from "reselect"; import { auth, logImEXEvent } from "../../firebase/firebase.utils"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { UPDATE_PAYMENTS } from "../../graphql/payments.queries"; +import { useCookies } from "react-cookie"; + import { selectBodyshop, selectCurrentUser, @@ -30,58 +32,71 @@ export function PaymentExportButton({ const [updatePayment] = useMutation(UPDATE_PAYMENTS); const [loading, setLoading] = useState(false); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); + const [cookies] = useCookies(); const handleQbxml = async () => { logImEXEvent("accounting_payment_export"); - setLoading(true); - if (!!loadingCallback) loadingCallback(true); - - let QbXmlResponse; - try { - QbXmlResponse = await axios.post( - "/accounting/qbxml/payments", - { payments: [paymentId] }, - { - headers: { - Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, - }, - } - ); - console.log("handle -> XML", QbXmlResponse); - } catch (error) { - console.log("Error getting QBXML from Server.", error); - notification["error"]({ - message: t("payments.errors.exporting", { - error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), - }), - }); - if (loadingCallback) loadingCallback(false); - setLoading(false); - return; - } - + //Check if it's a QBO Setup. let PartnerResponse; - - try { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { PartnerResponse = await axios.post( - "http://localhost:1337/qb/", - //"http://609feaeae986.ngrok.io/qb/", - QbXmlResponse.data + `/qbo/payments`, + { + payments: [paymentId], + }, + { withCredentials: true } ); - } catch (error) { - console.log("Error connecting to quickbooks or partner.", error); - notification["error"]({ - message: t("payments.errors.exporting-partner"), - }); - if (!!loadingCallback) loadingCallback(false); - setLoading(false); - return; + } else { + //Default is QBD + + if (!!loadingCallback) loadingCallback(true); + + let QbXmlResponse; + try { + QbXmlResponse = await axios.post( + "/accounting/qbxml/payments", + { payments: [paymentId] }, + { + headers: { + Authorization: `Bearer ${await auth.currentUser.getIdToken()}`, + }, + } + ); + console.log("handle -> XML", QbXmlResponse); + } catch (error) { + console.log("Error getting QBXML from Server.", error); + notification["error"]({ + message: t("payments.errors.exporting", { + error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), + }), + }); + if (loadingCallback) loadingCallback(false); + setLoading(false); + return; + } + + try { + PartnerResponse = await axios.post( + "http://localhost:1337/qb/", + QbXmlResponse.data + ); + } catch (error) { + console.log("Error connecting to quickbooks or partner.", error); + notification["error"]({ + message: t("payments.errors.exporting-partner"), + }); + if (!!loadingCallback) loadingCallback(false); + setLoading(false); + return; + } } console.log("handleQbxml -> PartnerResponse", PartnerResponse); const failedTransactions = PartnerResponse.data.filter((r) => !r.success); - + const successfulTransactions = PartnerResponse.data.filter( + (r) => r.success + ); if (failedTransactions.length > 0) { //Uh oh. At least one was no good. failedTransactions.map((ft) => @@ -123,7 +138,14 @@ export function PaymentExportButton({ const paymentUpdateResponse = await updatePayment({ variables: { - paymentIdList: [paymentId], + paymentIdList: successfulTransactions.map( + (st) => + st[ + bodyshop.accountingconfig && bodyshop.accountingconfig.qbo + ? "paymentid" + : "id" + ] + ), payment: { exportedat: new Date(), }, @@ -158,8 +180,12 @@ export function PaymentExportButton({ diff --git a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx index 693a14339..35c58552a 100644 --- a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx +++ b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx @@ -8,6 +8,8 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { UPDATE_PAYMENTS } from "../../graphql/payments.queries"; +import { useCookies } from "react-cookie"; + import { selectBodyshop, selectCurrentUser, @@ -29,46 +31,58 @@ export function PaymentsExportAllButton({ const [updatePayments] = useMutation(UPDATE_PAYMENTS); const [loading, setLoading] = useState(false); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); + const [cookies] = useCookies(); const handleQbxml = async () => { setLoading(true); if (!!loadingCallback) loadingCallback(true); - - let QbXmlResponse; - try { - QbXmlResponse = await axios.post("/accounting/qbxml/payments", { - payments: paymentIds, - }); - } catch (error) { - console.log("Error getting QBXML from Server.", error); - notification["error"]({ - message: t("payments.errors.exporting", { - error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), - }), - }); - if (loadingCallback) loadingCallback(false); - setLoading(false); - return; - } - let PartnerResponse; - - try { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { PartnerResponse = await axios.post( - "http://localhost:1337/qb/", - QbXmlResponse.data + `/qbo/payments`, + { + payments: paymentIds, + }, + { withCredentials: true } ); - } catch (error) { - console.log("Error connecting to quickbooks or partner.", error); - notification["error"]({ - message: t("payments.errors.exporting-partner"), - }); - if (!!loadingCallback) loadingCallback(false); - setLoading(false); - return; + } else { + let QbXmlResponse; + try { + QbXmlResponse = await axios.post("/accounting/qbxml/payments", { + payments: paymentIds, + }); + } catch (error) { + console.log("Error getting QBXML from Server.", error); + notification["error"]({ + message: t("payments.errors.exporting", { + error: "Unable to retrieve QBXML. " + JSON.stringify(error.message), + }), + }); + if (loadingCallback) loadingCallback(false); + setLoading(false); + return; + } + + try { + PartnerResponse = await axios.post( + "http://localhost:1337/qb/", + QbXmlResponse.data + ); + } catch (error) { + console.log("Error connecting to quickbooks or partner.", error); + notification["error"]({ + message: t("payments.errors.exporting-partner"), + }); + if (!!loadingCallback) loadingCallback(false); + setLoading(false); + return; + } } - const groupedData = _.groupBy(PartnerResponse.data, "id"); + const groupedData = _.groupBy( + PartnerResponse.data, + bodyshop.accountingconfig.qbo ? "paymentid" : "id" + ); const proms = []; Object.keys(groupedData).forEach((key) => { proms.push( @@ -147,8 +161,12 @@ export function PaymentsExportAllButton({ diff --git a/client/src/components/production-list-columns/production-list-columns.add.component.jsx b/client/src/components/production-list-columns/production-list-columns.add.component.jsx index 0742235b5..8b671c54c 100644 --- a/client/src/components/production-list-columns/production-list-columns.add.component.jsx +++ b/client/src/components/production-list-columns/production-list-columns.add.component.jsx @@ -6,9 +6,11 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectTechnician } from "../../redux/tech/tech.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser technician: selectTechnician, + bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) @@ -21,6 +23,7 @@ export default connect( export function ProductionColumnsComponent({ columnState, technician, + bodyshop, tableState, }) { const [columns, setColumns] = columnState; @@ -29,9 +32,11 @@ export function ProductionColumnsComponent({ const handleAdd = (e) => { setColumns([ ...columns, - ...dataSource({ technician, state: tableState }).filter( - (i) => i.key === e.key - ), + ...dataSource({ + technician, + state: tableState, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }).filter((i) => i.key === e.key), ]); }; @@ -39,7 +44,11 @@ export function ProductionColumnsComponent({ const menu = ( - {dataSource({ technician, state: tableState }) + {dataSource({ + technician, + state: tableState, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }) .filter((i) => !columnKeys.includes(i.key)) .map((item) => ( {item.title} 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 027cfcc32..3dfae0c47 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 @@ -3,7 +3,7 @@ import React from "react"; import { Link } from "react-router-dom"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter"; -import { alphaSort, dateSort } from "../../utils/sorters"; +import { alphaSort, dateSort, statusSort } from "../../utils/sorters"; import JobAltTransportChange from "../job-at-change/job-at-change.component"; import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component"; import ProductionListColumnAlert from "./production-list-columns.alert.component"; @@ -17,7 +17,7 @@ import ProductionListColumnStatus from "./production-list-columns.status.compone import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component"; import ProductionListLastContacted from "./production-list-columns.lastcontacted.component"; -const r = ({ technician, state }) => { +const r = ({ technician, state, activeStatuses }) => { return [ { title: i18n.t("jobs.actions.viewdetail"), @@ -210,7 +210,7 @@ const r = ({ technician, state }) => { dataIndex: "status", key: "status", ellipsis: true, - sorter: (a, b) => alphaSort(a.status, b.status), + sorter: (a, b) => statusSort(a.status, b.status, activeStatuses), sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order, render: (text, record) => , diff --git a/client/src/components/production-list-table/production-list-table-view-select.component.jsx b/client/src/components/production-list-table/production-list-table-view-select.component.jsx index fb617f869..767f4602f 100644 --- a/client/src/components/production-list-table/production-list-table-view-select.component.jsx +++ b/client/src/components/production-list-table/production-list-table-view-select.component.jsx @@ -37,9 +37,11 @@ export function ProductionListTable({ .filter((pc) => pc.name === value)[0] .columns.columnKeys.map((k) => { return { - ...ProductionListColumns({ technician, state }).find( - (e) => e.key === k.key - ), + ...ProductionListColumns({ + technician, + state, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }).find((e) => e.key === k.key), width: k.width, }; }) @@ -88,9 +90,11 @@ export function ProductionListTable({ setColumns( bodyshop.production_config[0].columns.columnKeys.map((k) => { return { - ...ProductionListColumns({ technician, state }).find( - (e) => e.key === k.key - ), + ...ProductionListColumns({ + technician, + state, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }).find((e) => e.key === k.key), width: k.width, }; }) 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 158d07c9f..d69741496 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 @@ -1,4 +1,12 @@ -import { Dropdown, Input, Menu, PageHeader, Space, Table } from "antd"; +import { + Dropdown, + Input, + Menu, + PageHeader, + Space, + Statistic, + Table, +} from "antd"; import React, { useMemo, useState } from "react"; import ReactDragListView from "react-drag-listview"; import { useTranslation } from "react-i18next"; @@ -59,9 +67,11 @@ export function ProductionListTable({ matchingColumnConfig && matchingColumnConfig.columns.columnKeys.map((k) => { return { - ...ProductionListColumns({ technician, state }).find( - (e) => e.key === k.key - ), + ...ProductionListColumns({ + technician, + state, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }).find((e) => e.key === k.key), width: k.width, }; })) || @@ -155,10 +165,26 @@ export function ProductionListTable({ // }; if (!!!columns) return
No columns found.
; + console.log(data); + const totalHrs = data + .reduce( + (acc, val) => + acc + + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) + + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), + 0 + ) + .toFixed(1); return (
+ } extra={ {t("jobs.actions.printCenter")} - +