IO-2278 Begin parts dispatching including basic items and schema.

This commit is contained in:
Patrick Fic
2023-06-01 13:27:08 -07:00
parent de62e994bd
commit 68f4237e15
13 changed files with 388 additions and 16 deletions

View File

@@ -45,6 +45,7 @@ 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";
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -440,6 +441,11 @@ export function JobLinesComponent({
</Space>
</Tag>
)}
<JobLineDispatchButton
selectedLines={selectedLines}
setSelectedLines={setSelectedLines}
job={job}
/>
<Button
disabled={
(job && !job.converted) ||
@@ -448,15 +454,6 @@ export function JobLinesComponent({
technician
}
onClick={() => {
// setPartsOrderContext({
// actions: { refetch: refetch },
// context: {
// jobId: job.id,
// job: job,
// linesToOrder: selectedLines,
// },
// });
setBillEnterContext({
actions: { refetch: refetch },
context: {

View File

@@ -0,0 +1,152 @@
import React, { useState } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { Button, Form, Popover, Select, Space } from "antd";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { useTranslation } from "react-i18next";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
import { TemplateList } from "../../utils/TemplateConstants";
import { useMutation } from "@apollo/client";
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobLineDispatchButton);
export function JobLineDispatchButton({
setSelectedLines,
selectedLines,
bodyshop,
jobRO,
job,
currentUser,
}) {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const Templates = TemplateList("job_special", {
ro_number: job.ro_number,
});
const { t } = useTranslation();
const [dispatchLines] = useMutation(UPDATE_JOB_LINE);
const handleConvert = async (values) => {
try {
setLoading(true);
//THIS HAS NOT YET BEEN TESTED. START BY FINISHING THIS FUNCTION.
const result = await dispatchLines({
variables: {
joblinesids: selectedLines.map((l) => l.id),
employeeid: values.employeeid,
note: {
audit: true,
type: "parts",
jobid: job.id,
created_by: currentUser.email,
text: `${t("joblines.labels.dispatchaudit")}
${selectedLines.map((line) => `line.line_desc \r\n`)}
`,
},
},
});
setVisible(false);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
const popMenu = (
<div>
<Form layout="vertical" form={form} onFinish={handleConvert}>
<Form.Item
name={"employeeid"}
label={t("jobs.fields.employeeid")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
showSearch
style={{ width: 200 }}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
}
>
{bodyshop.employees
.filter((emp) => emp.active)
.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<PrintWrapperComponent
disabled={!form.getFieldValue("employeeid")}
templateObject={{
name: Templates.parts_dispatch.key,
variables: { id: job.id },
}}
messageObject={{
subject: Templates.parts_dispatch.subject,
}}
id={job.id}
/>
);
}}
</Form.Item>
<Space wrap>
<Button type="danger" onClick={() => form.submit()} loading={loading}>
{t("general.actions.save")}
</Button>
<Button onClick={() => setVisible(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
</div>
);
return (
<Popover open={visible} content={popMenu}>
<Button
disabled={selectedLines.length === 0 || jobRO}
loading={loading}
onClick={() => setVisible(true)}
>
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
</Button>
</Popover>
);
}

View File

@@ -9,9 +9,11 @@ export default function PrintWrapperComponent({
children,
id,
emailOnly = false,
disabled,
}) {
const [loading, setLoading] = useState(false);
const handlePrint = async (type) => {
if (disabled) return;
setLoading(true);
await GenerateDocument(templateObject, messageObject, type, id);
setLoading(false);
@@ -20,8 +22,18 @@ export default function PrintWrapperComponent({
return (
<Space>
{children || null}
{!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
<MailFilled onClick={() => handlePrint("e")} />
{!emailOnly && (
<PrinterFilled
disabled={disabled}
onClick={() => handlePrint("p")}
style={{ cursor: disabled ? "not-allowed" : null }}
/>
)}
<MailFilled
disabled={disabled}
onClick={() => handlePrint("e")}
style={{ cursor: disabled ? "not-allowed" : null }}
/>
{loading && <Spin />}
</Space>
);