From 93c92e89767e221ef46ee8ee58f0e29c73b0365d Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 22 Jul 2024 13:30:08 -0700 Subject: [PATCH 1/8] IO-2564 Row Expander Links Signed-off-by: Allan Carr --- .../job-close-ro-guard.bills.jsx | 4 +-- .../job-lines-expander.component.jsx | 24 ++++++++--------- .../jobs-detail-pli.container.jsx | 10 +------ client/src/graphql/bills.queries.js | 2 +- .../jobs-detail.page.component.jsx | 26 ++++++++++++------- 5 files changed, 33 insertions(+), 33 deletions(-) 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 4bf03ea46..a6dcf7b35 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 @@ -3,7 +3,7 @@ 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 { QUERY_PARTS_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"; @@ -19,7 +19,7 @@ const mapDispatchToProps = (dispatch) => ({ export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills); export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) { - const { loading, error, data } = useQuery(QUERY_BILLS_BY_JOBID, { + const { loading, error, data } = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { variables: { jobid: job.id }, fetchPolicy: "network-only", nextFetchPolicy: "network-only" 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 22f0f8616..64e3f023f 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 @@ -2,17 +2,17 @@ import { useQuery } from "@apollo/client"; import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; import { Link } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries"; +import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js"; +import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; import AlertComponent from "../alert/alert.component"; -import { connect } from "react-redux"; -import { createStructuredSelector } from "reselect"; -import { selectBodyshop } from "../../redux/user/user.selectors"; -import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js"; -import TaskListContainer from "../task-list/task-list.container.jsx"; import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx"; +import TaskListContainer from "../task-list/task-list.container.jsx"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop @@ -84,17 +84,17 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) { key: line.id, children: ( - - {line.parts_dispatch.number} - + {line.parts_dispatch.number} {bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name} - - {t("parts_dispatch_lines.fields.accepted_at")} - {line.accepted_at} - + {line.accepted_at ? ( + + {t("parts_dispatch_lines.fields.accepted_at")} + {line.accepted_at} + + ) : null} ) diff --git a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx index f968b1da7..25b8081d0 100644 --- a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx +++ b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx @@ -1,17 +1,9 @@ -import { useQuery } from "@apollo/client"; import queryString from "query-string"; import React from "react"; import { useLocation, useNavigate } from "react-router-dom"; -import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import JobsDetailPliComponent from "./jobs-detail-pli.component"; -export default function JobsDetailPliContainer({ job }) { - const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, { - variables: { jobid: job.id }, - fetchPolicy: "network-only", - nextFetchPolicy: "network-only" - }); - +export default function JobsDetailPliContainer({ job, billsQuery }) { const search = queryString.parse(useLocation().search); const history = useNavigate(); diff --git a/client/src/graphql/bills.queries.js b/client/src/graphql/bills.queries.js index 3a38031ba..7a7fd2d8a 100644 --- a/client/src/graphql/bills.queries.js +++ b/client/src/graphql/bills.queries.js @@ -50,7 +50,7 @@ export const QUERY_ALL_BILLS_PAGINATED = gql` } `; -export const QUERY_BILLS_BY_JOBID = gql` +export const QUERY_PARTS_BILLS_BY_JOBID = gql` query QUERY_PARTS_BILLS_BY_JOBID($jobid: uuid!) { parts_orders(where: { jobid: { _eq: $jobid } }, order_by: { order_date: desc }) { id diff --git a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx index 79ce401bc..e2f251b79 100644 --- a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx +++ b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx @@ -8,11 +8,12 @@ import Icon, { SyncOutlined, ToolFilled } from "@ant-design/icons"; -import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd"; import { PageHeader } from "@ant-design/pro-layout"; +import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd"; +import { useQuery } from "@apollo/client"; import Axios from "axios"; -import dayjs from "../../utils/day"; +import _ from "lodash"; import queryString from "query-string"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -20,11 +21,13 @@ import { FaHardHat, FaRegStickyNote, FaShieldAlt, FaTasks } from "react-icons/fa import { connect } from "react-redux"; import { useLocation, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; +import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component"; import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component"; import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component"; import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container"; import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component"; import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container"; +import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component"; import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container"; import JobSyncButton from "../../components/job-sync-button/job-sync-button.component"; import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component"; @@ -42,19 +45,18 @@ import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gal import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container"; import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container"; import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container"; +import TaskListContainer from "../../components/task-list/task-list.container.jsx"; +import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries.js"; +import { QUERY_JOB_TASKS_PAGINATED } from "../../graphql/tasks.queries.js"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; -import UndefinedToNull from "../../utils/undefinedtonull"; -import _ from "lodash"; -import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component"; import { DateTimeFormat } from "../../utils/DateFormatter"; +import dayjs from "../../utils/day"; import InstanceRenderManager from "../../utils/instanceRenderMgr"; -import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component"; -import TaskListContainer from "../../components/task-list/task-list.container.jsx"; -import { QUERY_JOB_TASKS_PAGINATED } from "../../graphql/tasks.queries.js"; +import UndefinedToNull from "../../utils/undefinedtonull"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -96,6 +98,12 @@ export function JobsDetailPage({ layout: "vertical" }; + const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { + variables: { jobid: job.id }, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only" + }); + useEffect(() => { //form.setFieldsValue(transormJobToForm(job)); form.resetFields(); @@ -326,7 +334,7 @@ export function JobsDetailPage({ label: HasFeatureAccess({ featureName: "bills", bodyshop }) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"), - children: + children: }, ...(InstanceRenderManager({ imex: true, From 4a16df36ddfdfe6fe5c49beadb8545b2fc288aff Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 22 Jul 2024 17:35:05 -0700 Subject: [PATCH 2/8] IO-2848 UPDATE_JOB query Signed-off-by: Allan Carr --- client/src/graphql/jobs.queries.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 377552b72..7b4a0cac8 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -1149,6 +1149,7 @@ export const UPDATE_JOB = gql` suspended queued_for_parts scheduled_completion + scheduled_delivery actual_in date_repairstarted date_void From 6cc1cfd1b0ff82ceb48725bd862060a4c8f1711c Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 25 Jul 2024 08:36:08 -0700 Subject: [PATCH 3/8] IO-2851 Manual Job Creation Taxes Signed-off-by: Allan Carr --- .../jobs-create/jobs-create.container.jsx | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx index d919bcb46..2347f8f9a 100644 --- a/client/src/pages/jobs-create/jobs-create.container.jsx +++ b/client/src/pages/jobs-create/jobs-create.container.jsx @@ -10,9 +10,9 @@ import { INSERT_NEW_JOB } from "../../graphql/jobs.queries"; import { QUERY_OWNER_FOR_JOB_CREATION } from "../../graphql/owners.queries"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; import JobsCreateComponent from "./jobs-create.component"; import JobCreateContext from "./jobs-create.context"; -import InstanceRenderManager from "../../utils/instanceRenderMgr"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop @@ -159,13 +159,6 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { layout="vertical" autoComplete={"off"} initialValues={{ - tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, - tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100, state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100, local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100, @@ -261,19 +254,34 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100 } }, - rome: { - cieca_pft: { - ...bodyshop.md_responsibility_centers.taxes.tax_ty1, - ...bodyshop.md_responsibility_centers.taxes.tax_ty2, - ...bodyshop.md_responsibility_centers.taxes.tax_ty3, - ...bodyshop.md_responsibility_centers.taxes.tax_ty4, - ...bodyshop.md_responsibility_centers.taxes.tax_ty5 - }, - materials: bodyshop.md_responsibility_centers.cieca_pfm, - cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl, - parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates - } - } + tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, + tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100 + }, + rome: { + cieca_pft: { + ...bodyshop.md_responsibility_centers.taxes.tax_ty1, + ...bodyshop.md_responsibility_centers.taxes.tax_ty2, + ...bodyshop.md_responsibility_centers.taxes.tax_ty3, + ...bodyshop.md_responsibility_centers.taxes.tax_ty4, + ...bodyshop.md_responsibility_centers.taxes.tax_ty5 + }, + materials: bodyshop.md_responsibility_centers.cieca_pfm, + cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl, + parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates, + tax_tow_rt: bodyshop.md_responsibility_centers.tax_tow_rt, + tax_str_rt: bodyshop.md_responsibility_centers.tax_str_rt, + tax_paint_mat_rt: bodyshop.md_responsibility_centers.tax_paint_mat_rt, + tax_shop_mat_rt: bodyshop.md_responsibility_centers.tax_shop_mat_rt, + tax_sub_rt: bodyshop.md_responsibility_centers.tax_sub_rt, + tax_lbr_rt: bodyshop.md_responsibility_centers.tax_lbr_rt, + tax_levies_rt: bodyshop.md_responsibility_centers.tax_levies_rt + }, + promanager: "USE_ROME" }) }} > From 704d5415d617b167aa162c249ad27f7b15e01157 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 25 Jul 2024 08:38:01 -0700 Subject: [PATCH 4/8] IO-2850 Missing fields from save on Shop Config Taxes Signed-off-by: Allan Carr --- ...fo.responsibilitycenters.taxes.component.jsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/client/src/components/shop-info/shop-info.responsibilitycenters.taxes.component.jsx b/client/src/components/shop-info/shop-info.responsibilitycenters.taxes.component.jsx index 13ce11d7b..e52a70b46 100644 --- a/client/src/components/shop-info/shop-info.responsibilitycenters.taxes.component.jsx +++ b/client/src/components/shop-info/shop-info.responsibilitycenters.taxes.component.jsx @@ -1765,25 +1765,28 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) { - + - + - + - + - + - + - + From abb1464e30a18374d39b45b42eb1a1260e657d7f Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 25 Jul 2024 08:39:42 -0700 Subject: [PATCH 5/8] IO-2849 Missing Translation from Shop Config Signed-off-by: Allan Carr --- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 3 files changed, 3 insertions(+) diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index b46f3c553..3bcf674f8 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1776,6 +1776,7 @@ "prt_tx_in3": "Tax 3 Indicator", "prt_tx_in4": "Tax 4 Indicator", "prt_tx_in5": "Tax 5 Indicator", + "prt_tx_ty1": "Parts Tax Type 1", "prt_type": "Part Type" }, "partsstatus": "Parts Status", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 6c2b46890..77da83843 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1776,6 +1776,7 @@ "prt_tx_in3": "", "prt_tx_in4": "", "prt_tx_in5": "", + "prt_tx_ty1": "", "prt_type": "" }, "partsstatus": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 8003cf969..8f26de61a 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1776,6 +1776,7 @@ "prt_tx_in3": "", "prt_tx_in4": "", "prt_tx_in5": "", + "prt_tx_ty1": "", "prt_type": "" }, "partsstatus": "", From 5f494e4b784b8aa1cf034c680dd613d331f2a969 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 26 Jul 2024 13:28:29 -0700 Subject: [PATCH 6/8] IO-2564 Revert location of query Signed-off-by: Allan Carr --- .../jobs-detail-pli/jobs-detail-pli.container.jsx | 10 +++++++++- .../pages/jobs-detail/jobs-detail.page.component.jsx | 11 +---------- client/src/translations/en_us/common.json | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx index 25b8081d0..ac2f6015d 100644 --- a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx +++ b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx @@ -1,9 +1,17 @@ +import { useQuery } from "@apollo/client"; import queryString from "query-string"; import React from "react"; import { useLocation, useNavigate } from "react-router-dom"; +import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import JobsDetailPliComponent from "./jobs-detail-pli.component"; -export default function JobsDetailPliContainer({ job, billsQuery }) { +export default function JobsDetailPliContainer({ job }) { + const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { + variables: { jobid: job.id }, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only" + }); + const search = queryString.parse(useLocation().search); const history = useNavigate(); diff --git a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx index e2f251b79..c841fcaf7 100644 --- a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx +++ b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx @@ -10,8 +10,6 @@ import Icon, { } from "@ant-design/icons"; import { PageHeader } from "@ant-design/pro-layout"; import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd"; - -import { useQuery } from "@apollo/client"; import Axios from "axios"; import _ from "lodash"; import queryString from "query-string"; @@ -46,7 +44,6 @@ import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container" import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container"; import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container"; import TaskListContainer from "../../components/task-list/task-list.container.jsx"; -import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries.js"; import { QUERY_JOB_TASKS_PAGINATED } from "../../graphql/tasks.queries.js"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; @@ -98,12 +95,6 @@ export function JobsDetailPage({ layout: "vertical" }; - const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { - variables: { jobid: job.id }, - fetchPolicy: "network-only", - nextFetchPolicy: "network-only" - }); - useEffect(() => { //form.setFieldsValue(transormJobToForm(job)); form.resetFields(); @@ -334,7 +325,7 @@ export function JobsDetailPage({ label: HasFeatureAccess({ featureName: "bills", bodyshop }) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"), - children: + children: }, ...(InstanceRenderManager({ imex: true, diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index b46f3c553..a5a9d4ab7 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -230,7 +230,7 @@ "markexported": "Mark Exported", "markforreexport": "Mark for Re-export", "new": "New Bill", - "nobilllines": "", + "nobilllines": "This part has not yet been recieved.", "noneselected": "No bill selected.", "onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.", "printlabels": "Print Labels", From f690596825f5aa7fb6759e67030c58cdc039901c Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 29 Jul 2024 11:21:40 -0700 Subject: [PATCH 7/8] IO-2564 Row Expander Links Move Drawer from Parts Order into seperate componenet and pass props down from main page and then link the BillDetailEdit Container into joblines Signed-off-by: Allan Carr --- .../job-lines-expander.component.jsx | 2 + .../job-detail-lines/job-lines.component.jsx | 20 +- .../job-detail-lines/job-lines.container.jsx | 26 +- .../jobs-detail-pli.container.jsx | 56 +-- ...arts-order-list-table-drawer.component.jsx | 411 ++++++++++++++++++ .../parts-order-list-table.component.jsx | 224 +--------- .../jobs-detail.page.component.jsx | 66 ++- 7 files changed, 538 insertions(+), 267 deletions(-) create mode 100644 client/src/components/parts-order-list-table/parts-order-list-table-drawer.component.jsx 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 64e3f023f..ceec1b2df 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 @@ -11,6 +11,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; import AlertComponent from "../alert/alert.component"; +import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container.jsx"; import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx"; import TaskListContainer from "../task-list/task-list.container.jsx"; @@ -111,6 +112,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) { null}> {t("bills.labels.bills")} + 0 diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx index 96a7f3a87..a639001f9 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -31,19 +31,20 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re // import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container"; import { useSplitTreatments } from "@splitsoftware/splitio-react"; import _ from "lodash"; +import { FaTasks } from "react-icons/fa"; import { selectBodyshop } from "../../redux/user/user.selectors"; import dayjs from "../../utils/day"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component"; import JobCreateIOU from "../job-create-iou/job-create-iou.component"; import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component"; import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component"; import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component"; import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component"; +import PartsOrderDrawer from "../parts-order-list-table/parts-order-list-table-drawer.component"; import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container"; import JobLinesExpander from "./job-lines-expander.component"; import JobLinesPartPriceChange from "./job-lines-part-price-change.component"; -import { FaTasks } from "react-icons/fa"; -import InstanceRenderManager from "../../utils/instanceRenderMgr"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -54,6 +55,7 @@ const mapStateToProps = createStructuredSelector({ const mapDispatchToProps = (dispatch) => ({ setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })), setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })), + setPartsReceiveContext: (context) => dispatch(setModalContext({ context: context, modal: "partsReceive" })), setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })), setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" })) }); @@ -63,6 +65,7 @@ export function JobLinesComponent({ jobRO, technician, setPartsOrderContext, + setPartsReceiveContext, loading, refetch, jobLines, @@ -71,7 +74,11 @@ export function JobLinesComponent({ setJobLineEditContext, form, setBillEnterContext, - setTaskUpsertContext + setTaskUpsertContext, + billsQuery, + handleBillOnRowClick, + handlePartsOrderOnRowClick, + handlePartsDispatchOnRowClick }) { const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK); const { @@ -437,6 +444,13 @@ export function JobLinesComponent({ return (
+ { @@ -22,7 +32,19 @@ function JobLinesContainer({ job, joblines, refetch, form, ...rest }) { }, [joblines, searchText]); return ( - +
+ +
); } diff --git a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx index ac2f6015d..139a19ca4 100644 --- a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx +++ b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx @@ -1,55 +1,13 @@ -import { useQuery } from "@apollo/client"; -import queryString from "query-string"; import React from "react"; -import { useLocation, useNavigate } from "react-router-dom"; -import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import JobsDetailPliComponent from "./jobs-detail-pli.component"; -export default function JobsDetailPliContainer({ job }) { - const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { - variables: { jobid: job.id }, - fetchPolicy: "network-only", - nextFetchPolicy: "network-only" - }); - - const search = queryString.parse(useLocation().search); - const history = useNavigate(); - - const handleBillOnRowClick = (record) => { - if (record) { - if (record.id) { - search.billid = record.id; - history({ search: queryString.stringify(search) }); - } - } else { - delete search.billid; - history({ search: queryString.stringify(search) }); - } - }; - - const handlePartsOrderOnRowClick = (record) => { - if (record) { - if (record.id) { - search.partsorderid = record.id; - history({ search: queryString.stringify(search) }); - } - } else { - delete search.partsorderid; - history({ search: queryString.stringify(search) }); - } - }; - - const handlePartsDispatchOnRowClick = (record) => { - if (record) { - if (record.id) { - search.partsdispatchid = record.id; - history.push({ search: queryString.stringify(search) }); - } - } else { - delete search.partsdispatchid; - history.push({ search: queryString.stringify(search) }); - } - }; +export default function JobsDetailPliContainer({ + job, + billsQuery, + handleBillOnRowClick, + handlePartsOrderOnRowClick, + handlePartsDispatchOnRowClick +}) { return ( ({ + setBillEnterContext: (context) => + dispatch( + setModalContext({ + context: context, + modal: "billEnter" + }) + ), + setPartsReceiveContext: (context) => + dispatch( + setModalContext({ + context: context, + modal: "partsReceive" + }) + ), + setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" })) +}); + +export function PartsOrderListTableDrawerComponent({ + setBillEnterContext, + bodyshop, + jobRO, + job, + billsQuery, + handleOnRowClick, + setPartsReceiveContext, + setTaskUpsertContext +}) { + const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) + .filter((screen) => !!screen[1]) + .slice(-1)[0]; + + const bpoints = { + xs: "100%", + sm: "100%", + md: "100%", + lg: "75%", + xl: "75%", + xxl: "65%" + }; + const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%"; + const responsibilityCenters = bodyshop.md_responsibility_centers; + const Templates = TemplateList("partsorder", { job }); + + const { t } = useTranslation(); + const [state, setState] = useState({ + sortedInfo: {} + }); + + const [returnfrombill, setReturnFromBill] = useState(); + const [billData, setBillData] = useState(); + const search = queryString.parse(useLocation().search); + const selectedpartsorder = search.partsorderid; + + const [billQuery] = useLazyQuery(QUERY_BILL_BY_PK); + const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER); + const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : []; + const { refetch } = billsQuery; + + useEffect(() => { + if (returnfrombill === null) { + setBillData(null); + } else { + const fetchData = async () => { + const result = await billQuery({ + variables: { billid: returnfrombill } + }); + setBillData(result.data); + }; + fetchData(); + } + }, [returnfrombill, billQuery]); + + const recordActions = (record, showView = false) => ( + + {showView && ( + + )} + + + + { + //Delete the parts return.! + + await deletePartsOrder({ + variables: { partsOrderId: record.id }, + update(cache) { + cache.modify({ + fields: { + parts_orders(existingPartsOrders, { readField }) { + return existingPartsOrders.filter((billref) => record.id !== readField("id", billref)); + } + } + }); + } + }); + }} + > + + + null}> + + + + + ); + + const handleTableChange = (pagination, filters, sorter) => { + setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); + }; + + const selectedPartsOrderRecord = parts_orders.find((r) => r.id === selectedpartsorder); + + const rowExpander = (record) => { + const columns = [ + { + title: t("parts_orders.fields.line_desc"), + dataIndex: "line_desc", + key: "line_desc", + sorter: (a, b) => alphaSort(a.line_desc, b.line_desc), + sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order + }, + { + title: t("parts_orders.fields.quantity"), + dataIndex: "quantity", + key: "quantity", + sorter: (a, b) => a.quantity - b.quantity, + sortOrder: state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order + }, + { + title: t("parts_orders.fields.act_price"), + dataIndex: "act_price", + key: "act_price", + sorter: (a, b) => a.act_price - b.act_price, + sortOrder: state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order, + render: (text, record) => {record.act_price} + }, + ...(selectedPartsOrderRecord && selectedPartsOrderRecord.return + ? [ + { + title: t("parts_orders.fields.cost"), + dataIndex: "cost", + key: "cost", + sorter: (a, b) => a.cost - b.cost, + sortOrder: state.sortedInfo.columnKey === "cost" && state.sortedInfo.order, + render: (text, record) => {record.cost} + } + ] + : []), + { + title: t("parts_orders.fields.part_type"), + dataIndex: "part_type", + key: "part_type", + render: (text, record) => (record.part_type ? t(`joblines.fields.part_types.${record.part_type}`) : null) + }, + { + title: t("parts_orders.fields.oem_partno"), + dataIndex: "oem_partno", + key: "oem_partno", + sorter: (a, b) => alphaSort(a.oem_partno, b.oem_partno), + sortOrder: state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order + }, + { + title: t("parts_orders.fields.line_remarks"), + dataIndex: "line_remarks", + key: "line_remarks" + }, + { + title: t("parts_orders.fields.status"), + dataIndex: "status", + key: "status" + }, + + ...(selectedPartsOrderRecord && selectedPartsOrderRecord.return + ? [ + { + title: t("parts_orders.fields.cm_received"), + dataIndex: "cm_received", + key: "cm_received", + render: (text, record) => ( + + ) + } + ] + : []), + { + title: t("parts_orders.fields.backordered_on"), + dataIndex: "backordered_on", + key: "backordered_on", + render: (text, record) => {text} + }, + { + title: t("parts_orders.fields.backordered_eta"), + dataIndex: "backordered_eta", + key: "backordered_eta", + render: (text, record) => ( + + ) + }, + + { + title: t("general.labels.actions"), + dataIndex: "actions", + key: "actions", + render: (text, record) => ( + + + + + ) + } + ]; + + return ( +
+ + + +
{record.comments}
+
+ + ); + }; + + return ( +
+ + handleOnRowClick(null)} + open={selectedpartsorder} + closable + width={drawerPercentage} + > + {selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)} + +
+ ); +} + +export default connect(mapStateToProps, mapDispatchToProps)(PartsOrderListTableDrawerComponent); diff --git a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx index b407964ed..31234c1d1 100644 --- a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx +++ b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx @@ -1,33 +1,23 @@ import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons"; -import { useLazyQuery, useMutation } from "@apollo/client"; -import { Button, Card, Checkbox, Drawer, Grid, Input, Popconfirm, Space, Table } from "antd"; -import { PageHeader } from "@ant-design/pro-layout"; - -import queryString from "query-string"; -import React, { useEffect, useState } from "react"; +import { useMutation } from "@apollo/client"; +import { Button, Card, Checkbox, Input, Popconfirm, Space, Table } from "antd"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; +import { FaTasks } from "react-icons/fa"; import { connect } from "react-redux"; -import { useLocation } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { logImEXEvent } from "../../firebase/firebase.utils"; -import { QUERY_BILL_BY_PK } from "../../graphql/bills.queries"; import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; -import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; import { TemplateList } from "../../utils/TemplateConstants"; import { alphaSort } from "../../utils/sorters"; -import DataLabel from "../data-label/data-label.component"; -import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component"; -import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component"; -import PartsOrderDeleteLine from "../parts-order-delete-line/parts-order-delete-line.component"; -import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component"; +import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component"; import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container"; import PrintWrapper from "../print-wrapper/print-wrapper.component"; -import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component"; -import { FaTasks } from "react-icons/fa"; +import PartsOrderDrawer from "./parts-order-list-table-drawer.component"; const mapStateToProps = createStructuredSelector({ jobRO: selectJobReadOnly, @@ -62,19 +52,6 @@ export function PartsOrderListTableComponent({ setPartsReceiveContext, setTaskUpsertContext }) { - const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) - .filter((screen) => !!screen[1]) - .slice(-1)[0]; - - const bpoints = { - xs: "100%", - sm: "100%", - md: "100%", - lg: "75%", - xl: "75%", - xxl: "65%" - }; - const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%"; const responsibilityCenters = bodyshop.md_responsibility_centers; const Templates = TemplateList("partsorder", { job }); @@ -83,42 +60,17 @@ export function PartsOrderListTableComponent({ sortedInfo: {} }); - const [returnfrombill, setReturnFromBill] = useState(); - const [billData, setBillData] = useState(); - const search = queryString.parse(useLocation().search); - const selectedpartsorder = search.partsorderid; const [searchText, setSearchText] = useState(""); - - const [billQuery] = useLazyQuery(QUERY_BILL_BY_PK); const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER); const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : []; const { refetch } = billsQuery; - useEffect(() => { - if (returnfrombill === null) { - setBillData(null); - } else { - const fetchData = async () => { - const result = await billQuery({ - variables: { billid: returnfrombill } - }); - setBillData(result.data); - }; - fetchData(); - } - }, [returnfrombill, billQuery]); - const recordActions = (record, showView = false) => ( {showView && (
- -
{record.comments}
-
- - ); - }; - const filteredPartsOrders = parts_orders ? searchText === "" ? parts_orders @@ -476,15 +280,13 @@ export function PartsOrderListTableComponent({ } > - handleOnRowClick(null)} - open={selectedpartsorder} - closable - width={drawerPercentage} - > - {selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)} - +
{ //form.setFieldsValue(transormJobToForm(job)); @@ -102,6 +109,42 @@ export function JobsDetailPage({ //useKeyboardSaveShortcut(form.submit); + const handleBillOnRowClick = (record) => { + if (record) { + if (record.id) { + search.billid = record.id; + history({ search: queryString.stringify(search) }); + } + } else { + delete search.billid; + history({ search: queryString.stringify(search) }); + } + }; + + const handlePartsOrderOnRowClick = (record) => { + if (record) { + if (record.id) { + search.partsorderid = record.id; + history({ search: queryString.stringify(search) }); + } + } else { + delete search.partsorderid; + history({ search: queryString.stringify(search) }); + } + }; + + const handlePartsDispatchOnRowClick = (record) => { + if (record) { + if (record.id) { + search.partsdispatchid = record.id; + history.push({ search: queryString.stringify(search) }); + } + } else { + delete search.partsdispatchid; + history.push({ search: queryString.stringify(search) }); + } + }; + const handleFinish = async (values) => { setLoading(true); @@ -301,7 +344,18 @@ export function JobsDetailPage({ id: "job-details-repairdata", label: t("menus.jobsdetail.repairdata"), forceRender: true, - children: + children: ( + + ) }, { key: "rates", @@ -325,7 +379,15 @@ export function JobsDetailPage({ label: HasFeatureAccess({ featureName: "bills", bodyshop }) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"), - children: + children: ( + + ) }, ...(InstanceRenderManager({ imex: true, From 866f24246503e2ec60690efd63dedd7ab8f1b3bc Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 29 Jul 2024 11:30:52 -0700 Subject: [PATCH 8/8] IO-2853 Production Board Date Modal Signed-off-by: Allan Carr --- ...production-list-columns.date.component.jsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/client/src/components/production-list-columns/production-list-columns.date.component.jsx b/client/src/components/production-list-columns/production-list-columns.date.component.jsx index 6b1a5340a..7a639d8e5 100644 --- a/client/src/components/production-list-columns/production-list-columns.date.component.jsx +++ b/client/src/components/production-list-columns/production-list-columns.date.component.jsx @@ -1,11 +1,11 @@ import { useMutation } from "@apollo/client"; -import { Button, Card, Dropdown, TimePicker } from "antd"; -import dayjs from "../../utils/day"; +import { Button, Card, Dropdown, Space, TimePicker } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { DateFormatter } from "../../utils/DateFormatter"; +import dayjs from "../../utils/day"; import FormDatePicker from "../form-date-picker/form-date-picker.component"; export default function ProductionListDate({ record, field, time, pastIndicator }) { @@ -56,23 +56,25 @@ export default function ProductionListDate({ record, field, time, pastIndicator key: "overlayItem1", label: ( e.stopPropagation()}> - e.stopPropagation()} - value={(record[field] && dayjs(record[field])) || null} - onChange={handleChange} - format="MM/DD/YYYY" - isDateOnly={!time} - /> - {time && ( - + e.stopPropagation()} value={(record[field] && dayjs(record[field])) || null} onChange={handleChange} - minuteStep={15} - format="hh:mm a" + format="MM/DD/YYYY" + isDateOnly={!time} /> - )} - + {time && ( + e.stopPropagation()} + value={(record[field] && dayjs(record[field])) || null} + onChange={handleChange} + minuteStep={15} + format="hh:mm a" + /> + )} + + ) }