Add technician side to part dispatching.

This commit is contained in:
Patrick Fic
2023-08-04 13:24:41 -07:00
parent b5cc1c06df
commit 26dc720929
10 changed files with 281 additions and 11 deletions

View File

@@ -1474,6 +1474,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>admin_jobuninvoice</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>admin_jobunvoid</name> <name>admin_jobunvoid</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -3571,6 +3592,27 @@
<folder_node> <folder_node>
<name>validation</name> <name>validation</name>
<children> <children>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>inventoryquantity</name> <name>inventoryquantity</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -4205,6 +4247,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>country</name> <name>country</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -23710,6 +23773,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>date_void</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>ded_amt</name> <name>ded_amt</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -28490,6 +28574,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>contracts</name> <name>contracts</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -36032,6 +36137,27 @@
<folder_node> <folder_node>
<name>errors</name> <name>errors</name>
<children> <children>
<concept_node>
<name>accepting</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>creating</name> <name>creating</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -40888,6 +41014,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>parts_return_slip</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>sublet_order</name> <name>sublet_order</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -44739,6 +44886,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>work_in_progress_jobs</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>work_in_progress_labour</name> <name>work_in_progress_labour</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -8,7 +8,18 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
export default function JobLinesExpander({ jobline, jobid }) { 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)(JobLinesExpander);
export function JobLinesExpander({ jobline, jobid, bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, { const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
fetchPolicy: "network-only", fetchPolicy: "network-only",
@@ -23,7 +34,7 @@ export default function JobLinesExpander({ jobline, jobid }) {
return ( return (
<Row> <Row>
<Col md={24} lg={12}> <Col md={24} lg={8}>
<Typography.Title level={4}> <Typography.Title level={4}>
{t("parts_orders.labels.parts_orders")} {t("parts_orders.labels.parts_orders")}
</Typography.Title> </Typography.Title>
@@ -49,7 +60,7 @@ export default function JobLinesExpander({ jobline, jobid }) {
)} )}
</Timeline> </Timeline>
</Col> </Col>
<Col md={24} lg={12}> <Col md={24} lg={8}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title> <Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Timeline> <Timeline>
{data.billlines.length > 0 ? ( {data.billlines.length > 0 ? (
@@ -71,7 +82,7 @@ export default function JobLinesExpander({ jobline, jobid }) {
</Col> </Col>
<Col span={4}> <Col span={4}>
<span> <span>
{`${t("billlines.fields.actual_cost")}: `} {`${t("billlines.fields.actual_cost")}: `}
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter> <CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
</span> </span>
</Col> </Col>
@@ -89,6 +100,37 @@ export default function JobLinesExpander({ jobline, jobid }) {
)} )}
</Timeline> </Timeline>
</Col> </Col>
<Col md={24} lg={8}>
<Typography.Title level={4}>
{t("parts_dispatch.labels.parts_dispatch")}
</Typography.Title>
<Timeline>
{data.parts_dispatch_lines.length > 0 ? (
data.parts_dispatch_lines.map((line) => (
<Timeline.Item key={line.id}>
<Space split={<Divider type="vertical" />} wrap>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>
{line.parts_dispatch.number}
</Link>
{
bodyshop.employees.find(
(e) => e.id === line.parts_dispatch.employeeid
)?.first_name
}
<Space>
{t("parts_dispatch_lines.fields.accepted_at")}
<DateFormatter>{line.accepted_at}</DateFormatter>
</Space>
</Space>
</Timeline.Item>
))
) : (
<Timeline.Item>
{t("parts_orders.labels.notyetordered")}
</Timeline.Item>
)}
</Timeline>
</Col>
</Row> </Row>
); );
} }

View File

@@ -1,4 +1,4 @@
import { notification, Select } from "antd"; import { notification, Select, Space } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -75,7 +75,10 @@ export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }} style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
onClick={() => !disabled && setEditing(true)} onClick={() => !disabled && setEditing(true)}
> >
{jobline.location} <Space wrap>
{jobline.location}
{jobline.parts_dispatch_lines.length > 0 && "-Disp"}
</Space>
</div> </div>
); );
} }

View File

@@ -1,10 +1,35 @@
import { Button, Card, Col, Row, Table } from "antd"; import { useMutation } from "@apollo/client";
import { Button, Card, Col, Row, Table, notification } from "antd";
import moment from "moment-business-days";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
export default function PartsDispatchExpander({ dispatch, job }) { export default function PartsDispatchExpander({ dispatch, job }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE);
const handleAccept = async ({ partsDispatchLineId }) => {
const accepted_at = moment();
const result = await updateDispatchLine({
variables: { id: partsDispatchLineId, line: { accepted_at } },
optimisticResponse: {
update_parts_dispatch_lines_by_pk: {
accepted_at,
id: partsDispatchLineId,
},
},
});
if (result.errors) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.accepting", {
error: JSON.stringify(result.errors),
}),
});
}
};
const columns = [ const columns = [
{ {
@@ -32,7 +57,11 @@ export default function PartsDispatchExpander({ dispatch, job }) {
record.accepted_at ? ( record.accepted_at ? (
<DateTimeFormatter>{record.accepted_at}</DateTimeFormatter> <DateTimeFormatter>{record.accepted_at}</DateTimeFormatter>
) : ( ) : (
<Button>{t("parts_dispatch.actions.accept")}</Button> <Button
onClick={() => handleAccept({ partsDispatchLineId: record.id })}
>
{t("parts_dispatch.actions.accept")}
</Button>
), ),
}, },
]; ];

View File

@@ -2149,6 +2149,18 @@ export const GET_JOB_LINE_ORDERS = gql`
} }
} }
} }
parts_dispatch_lines(where: { joblineid: { _eq: $joblineid } }) {
id
accepted_at
quantity
parts_dispatch {
id
employeeid
dispatched_at
dispatched_by
number
}
}
parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) { parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) {
id id
act_price act_price

View File

@@ -54,6 +54,7 @@ export const GET_UNACCEPTED_PARTS_DISPATCH = gql`
dispatched_by dispatched_by
parts_dispatch_lines { parts_dispatch_lines {
id id
accepted_at
jobline { jobline {
line_desc line_desc
id id
@@ -64,3 +65,15 @@ export const GET_UNACCEPTED_PARTS_DISPATCH = gql`
} }
} }
`; `;
export const UPDATE_PARTS_DISPATCH_LINE = gql`
mutation UPDATE_PARTS_DISPATCH_LINE(
$id: uuid!
$line: parts_dispatch_lines_set_input!
) {
update_parts_dispatch_lines_by_pk(pk_columns: { id: $id }, _set: $line) {
accepted_at
id
}
}
`;

View File

@@ -4,9 +4,9 @@ import {
SyncOutlined, SyncOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Card, Input, Space, Table } from "antd"; import { Button, Card, Space, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";

View File

@@ -2141,6 +2141,7 @@
"accept": "Accept" "accept": "Accept"
}, },
"errors": { "errors": {
"accepting": "Error accepting parts dispatch. {{error}}",
"creating": "Error dispatching parts. {{error}}" "creating": "Error dispatching parts. {{error}}"
}, },
"fields": { "fields": {
@@ -2433,7 +2434,7 @@
"jobs": { "jobs": {
"individual_job_note": "Job Note RO: {{ro_number}}", "individual_job_note": "Job Note RO: {{ro_number}}",
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}", "parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
"parts_return_slip":"Parts Return PO: {{ro_number}} - {{name}}", "parts_return_slip": "Parts Return PO: {{ro_number}} - {{name}}",
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}" "sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
} }
}, },

View File

@@ -2141,6 +2141,7 @@
"accept": "" "accept": ""
}, },
"errors": { "errors": {
"accepting": "",
"creating": "" "creating": ""
}, },
"fields": { "fields": {

View File

@@ -2141,6 +2141,7 @@
"accept": "" "accept": ""
}, },
"errors": { "errors": {
"accepting": "",
"creating": "" "creating": ""
}, },
"fields": { "fields": {