diff --git a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx index 4380c77d2..e70e57a94 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx @@ -164,6 +164,7 @@ export function BillDetailEditcontainer({ if (!search.billid) return <>; //
{t("bills.labels.noneselected")}
; const exported = data && data.bills_by_pk && data.bills_by_pk.exported; + const isinhouse = data && data.bills_by_pk && data.bills_by_pk.isinhouse; return ( <> @@ -207,7 +208,7 @@ export function BillDetailEditcontainer({ initialValues={transformData(data)} layout="vertical" > - + {t("general.labels.media")} {bodyshop.uselocalmediaserver ? ( - + ({}); + +export default connect(mapStateToProps, mapDispatchToProps)(JobLinesExpander); + +export function JobLinesExpander({ jobline, jobid, technician }) { const { t } = useTranslation(); const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, { fetchPolicy: "network-only", @@ -33,11 +45,15 @@ export default function JobLinesExpander({ jobline, jobid }) { - - {line.parts_order.order_number} - + {!technician ? ( + + {line.parts_order.order_number} + + ) : ( + `${line.parts_order.order_number}` + )} {line.parts_order.order_date} @@ -63,17 +79,22 @@ export default function JobLinesExpander({ jobline, jobid }) { {t("bills.labels.bills")} + {data.billlines.length > 0 ? ( data.billlines.map((line) => ( - - {line.bill.invoice_number} - + {!technician ? ( + + {line.bill.invoice_number} + + ) : ( + `${line.bill.invoice_number}` + )} @@ -95,9 +116,7 @@ export default function JobLinesExpander({ jobline, jobid }) { )) ) : ( - - {t("bills.labels.nobilllines")} - + {t("bills.labels.nobilllines")} )} 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 d3f074fbf..6e290f053 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -1,12 +1,12 @@ import { DeleteFilled, + EditFilled, FilterFilled, + HomeOutlined, + MinusCircleTwoTone, + PlusCircleTwoTone, SyncOutlined, WarningFilled, - EditFilled, - PlusCircleTwoTone, - MinusCircleTwoTone, - HomeOutlined, } from "@ant-design/icons"; import { useMutation } from "@apollo/client"; import { @@ -20,6 +20,8 @@ import { Tag, } from "antd"; import axios from "axios"; +import _ from "lodash"; +import moment from "moment"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -28,23 +30,19 @@ import { DELETE_JOB_LINE_BY_PK } from "../../graphql/jobs-lines.queries"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectTechnician } from "../../redux/tech/tech.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; import { onlyUnique } from "../../utils/arrayHelper"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { alphaSort } from "../../utils/sorters"; +import JobCreateIOU from "../job-create-iou/job-create-iou.component"; +import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component"; import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component"; import JobLineNotePopup from "../job-line-note-popup/job-line-note-popup.component"; import JobLineStatusPopup from "../job-line-status-popup/job-line-status-popup.component"; import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-reference.component"; -// import AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container"; -// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container"; -// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container"; +import PartsOrderDrawer from "../parts-order-list-table/parts-order-list-table-drawer.component"; import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container"; -import _ from "lodash"; -import JobCreateIOU from "../job-create-iou/job-create-iou.component"; import JobLinesExpander from "./job-lines-expander.component"; -import { selectBodyshop } from "../../redux/user/user.selectors"; -import moment from "moment"; -import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -57,6 +55,8 @@ const mapDispatchToProps = (dispatch) => ({ 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" })), }); @@ -66,6 +66,7 @@ export function JobLinesComponent({ jobRO, technician, setPartsOrderContext, + setPartsReceiveContext, loading, refetch, jobLines, @@ -74,6 +75,8 @@ export function JobLinesComponent({ setJobLineEditContext, form, setBillEnterContext, + billsQuery, + handlePartsOrderOnRowClick, }) { const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK); @@ -341,7 +344,7 @@ export function JobLinesComponent({ key: "actions", render: (text, record) => ( - {(record.manual_line || jobIsPrivate) && ( + {(record.manual_line || jobIsPrivate) && !technician && ( <> + )} + + + + { + //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 30cabe1cb..8b809eaca 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,40 +1,21 @@ import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons"; -import { useLazyQuery, useMutation } from "@apollo/client"; -import { - Button, - Card, - Checkbox, - Drawer, - Grid, - Input, - PageHeader, - Popconfirm, - Space, - Table, -} from "antd"; -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 { 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 PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container"; import PrintWrapper from "../print-wrapper/print-wrapper.component"; +import PartsOrderDrawer from "./parts-order-list-table-drawer.component"; const mapStateToProps = createStructuredSelector({ jobRO: selectJobReadOnly, @@ -57,21 +38,6 @@ export function PartsOrderListTableComponent({ handleOnRowClick, setPartsReceiveContext, }) { - 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 }); @@ -80,42 +46,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 @@ -502,15 +281,12 @@ export function PartsOrderListTableComponent({ } > - handleOnRowClick(null)} - visible={selectedpartsorder} - closable - width={drawerPercentage} - > - {selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)} - +
{ //form.setFieldsValue(transormJobToForm(job)); form.resetFields(); }, [form, job]); + const handleBillOnRowClick = (record) => { + if (record) { + if (record.id) { + search.billid = record.id; + history.push({ search: queryString.stringify(search) }); + } + } else { + delete search.billid; + history.push({ search: queryString.stringify(search) }); + } + }; + + const handlePartsOrderOnRowClick = (record) => { + if (record) { + if (record.id) { + search.partsorderid = record.id; + history.push({ search: queryString.stringify(search) }); + } + } else { + delete search.partsorderid; + history.push({ search: queryString.stringify(search) }); + } + }; + //useKeyboardSaveShortcut(form.submit); const handleFinish = async (values) => { @@ -286,6 +318,9 @@ export function JobsDetailPage({ @@ -322,7 +357,12 @@ export function JobsDetailPage({ } key="partssublet" > - +