IO-244 IOU Parts

This commit is contained in:
Patrick Fic
2021-12-03 17:39:58 -08:00
parent b539ecaeb1
commit 2e843bbd8a
24 changed files with 422 additions and 5 deletions

View File

@@ -1,6 +1,8 @@
import { UploadOutlined } from "@ant-design/icons";
import Icon, { UploadOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client";
import { MdOpenInNew } from "react-icons/md";
import {
Alert,
Divider,
Form,
Input,
@@ -13,6 +15,7 @@ import {
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -132,6 +135,30 @@ export function BillFormComponent({
/>
</Form.Item>
</LayoutFormRow>
{job &&
job.ious &&
job.ious.length > 0 &&
job.ious.map((iou) => (
<Alert
key={iou.id}
type="warning"
message={
<Space>
{t("bills.labels.iouexists")}
<Link
target="_blank"
rel="noopener noreferrer"
to={`/manage/jobs/${iou.id}?tab=repairdata`}
>
<Space>
{iou.ro_number}
<Icon component={MdOpenInNew} />
</Space>
</Link>
</Space>
}
/>
))}
<LayoutFormRow>
<Form.Item
label={t("bills.fields.invoice_number")}
@@ -337,6 +364,7 @@ export function BillFormComponent({
responsibilityCenters={responsibilityCenters}
disabled={disabled}
/>
<Form.Item
name="upload"
label="Upload"

View File

@@ -0,0 +1,95 @@
import { useApolloClient } from "@apollo/client";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Button, notification, Popconfirm } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useHistory } from "react-router";
import { createStructuredSelector } from "reselect";
import { UPDATE_JOB_LINES_IOU } from "../../graphql/jobs-lines.queries";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { CreateIouForJob } from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(JobCreateIOU);
export function JobCreateIOU({
bodyshop,
currentUser,
jobid,
selectedJobLines,
}) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const client = useApolloClient();
const history = useHistory();
const { IOU_Tracking } = useTreatments(
["IOU_Tracking"],
{},
bodyshop.imexshopid
);
if (IOU_Tracking.treatment !== "on") return null;
const handleCreateIou = async () => {
setLoading(true);
//Query all of the job details to recreate.
const iouId = await CreateIouForJob(
client,
jobid,
{
status: bodyshop.md_ro_statuses.default_open,
bodyshopid: bodyshop.id,
useremail: currentUser.email,
},
selectedJobLines
);
notification.open({
type: "success",
message: t("jobs.successes.ioucreated"),
onClick: () => history.push(`/manage/jobs/${iouId}`),
});
const selectedJobLinesIds = selectedJobLines.map((l) => l.id);
await client.mutate({
mutation: UPDATE_JOB_LINES_IOU,
variables: { ids: selectedJobLinesIds },
update(cache) {
cache.modify({
id: cache.identify(jobid),
fields: {
joblines(existingJobLines, { readField }) {
return existingJobLines.map((a) => {
if (!selectedJobLinesIds.includes(a.id)) return a;
return { ...a, ioucreated: true };
});
},
},
});
},
});
setLoading(false);
};
return (
<Popconfirm
title={t("jobs.labels.createiouwarning")}
onConfirm={handleCreateIou}
>
<Button
loading={loading}
disabled={!selectedJobLines || selectedJobLines.length === 0}
>
{t("jobs.actions.createiou")}
</Button>
</Popconfirm>
);
}

View File

@@ -37,6 +37,7 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import _ from "lodash";
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -427,6 +428,7 @@ export function JobLinesComponent({
>
{t("joblines.actions.new")}
</Button>
<JobCreateIOU jobid={job.id} selectedJobLines={selectedLines} />
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {

View File

@@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import { Input, notification } from "antd";
import { Input, notification, Space } from "antd";
import { FieldTimeOutlined } from "@ant-design/icons";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import { useMutation } from "@apollo/client";
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
@@ -59,6 +60,12 @@ export default function JobLineNotePopup({ jobline, disabled }) {
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
onClick={() => !disabled && setEditing(true)}
>
{jobline.ioucreated && (
<Space>
<FieldTimeOutlined />
{t("joblines.labels.ioucreated")}
</Space>
)}
{jobline.notes}
</div>
);

View File

@@ -2,6 +2,8 @@ import Axios from "axios";
import _ from "lodash";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_NEW_JOB, QUERY_JOB_FOR_DUPE } from "../../graphql/jobs.queries";
import moment from "moment";
import i18n from "i18next";
export default async function DuplicateJob(
apolloClient,
@@ -57,3 +59,71 @@ export default async function DuplicateJob(
return;
}
export async function CreateIouForJob(
apolloClient,
jobId,
config,
jobLinesToKeep
) {
logImEXEvent("job_create_iou");
const { status } = config;
//get a list of all fields on the job
const res = await apolloClient.query({
query: QUERY_JOB_FOR_DUPE,
variables: { id: jobId },
});
const { jobs_by_pk } = res.data;
const existingJob = _.cloneDeep(jobs_by_pk);
delete existingJob.__typename;
delete existingJob.id;
delete existingJob.createdat;
delete existingJob.updatedat;
const newJob = {
...existingJob,
converted: true,
status: status,
iouparent: jobId,
date_open: moment(),
audit_trails: {
data: [
{
useremail: config.useremail,
bodyshopid: config.bodyshopid,
operation: i18n.t("audit_trail.messages.jobioucreated"),
},
],
},
};
const selectedJoblinesIds = jobLinesToKeep.map((l) => l.id);
const _tempLines = _.cloneDeep(existingJob.joblines).filter((l) =>
selectedJoblinesIds.includes(l.id)
);
_tempLines.forEach((line) => {
delete line.id;
delete line.__typename;
line.manual_line = true;
});
delete newJob.joblines;
newJob.joblines = { data: _tempLines };
const res2 = await apolloClient.mutate({
mutation: INSERT_NEW_JOB,
variables: { job: [newJob] },
});
Axios.post("/job/totalsssu", {
id: res2.data.insert_jobs.returning[0].id,
});
//insert the new job. call the callback with the returned ID when done.
return res2.data.insert_jobs.returning[0].id;
}