Reformat all project files to use the prettier config file.
This commit is contained in:
@@ -1,33 +1,33 @@
|
||||
import {DeleteFilled} from "@ant-design/icons";
|
||||
import {useApolloClient, useMutation} from "@apollo/client";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
notification,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Statistic,
|
||||
Switch,
|
||||
Typography,
|
||||
Alert,
|
||||
Button,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
notification,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Statistic,
|
||||
Switch,
|
||||
Typography
|
||||
} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React, {useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
// import { useNavigate } from 'react-router-dom';
|
||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import Dinero from "dinero.js";
|
||||
import dayjs from "../../utils/day";
|
||||
import {Link} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import DateTimePicker from "../../components/form-date-time-picker/form-date-time-picker.component";
|
||||
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
||||
import CurrencyInput from "../../components/form-items-formatted/currency-form-item.component";
|
||||
@@ -35,510 +35,450 @@ import JobsScoreboardAdd from "../../components/job-scoreboard-add-button/job-sc
|
||||
import JobsCloseAutoAllocate from "../../components/jobs-close-auto-allocate/jobs-close-auto-allocate.component";
|
||||
import JobsCloseLines from "../../components/jobs-close-lines/jobs-close-lines.component";
|
||||
import LayoutFormRow from "../../components/layout-form-row/layout-form-row.component";
|
||||
import {generateJobLinesUpdatesForInvoicing} from "../../graphql/jobs-lines.queries";
|
||||
import {UPDATE_JOB} from "../../graphql/jobs.queries";
|
||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||
import {selectJobReadOnly} from "../../redux/application/application.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.queries";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
insertAuditTrail: ({jobid, operation, type}) =>
|
||||
dispatch(insertAuditTrail({jobid, operation, type })),
|
||||
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
||||
});
|
||||
|
||||
export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
||||
const {t} = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const client = useApolloClient();
|
||||
// const history = useNavigate();
|
||||
const [closeJob] = useMutation(UPDATE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail }) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const client = useApolloClient();
|
||||
// const history = useNavigate();
|
||||
const [closeJob] = useMutation(UPDATE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const {treatments: {Qb_Multi_Ar, ClosingPeriod}} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Qb_Multi_Ar", "ClosingPeriod"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid,
|
||||
const {
|
||||
treatments: { Qb_Multi_Ar, ClosingPeriod }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Qb_Multi_Ar", "ClosingPeriod"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
});
|
||||
|
||||
const handleFinish = async ({ removefromproduction, ...values }) => {
|
||||
setLoading(true);
|
||||
const result = await client.mutate({
|
||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines)
|
||||
});
|
||||
if (result.errors) {
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: values.date_invoiced,
|
||||
actual_in: values.actual_in,
|
||||
actual_completion: values.actual_completion,
|
||||
actual_delivery: values.actual_delivery,
|
||||
kmin: values.kmin,
|
||||
kmout: values.kmout,
|
||||
dms_allocation: values.dms_allocation,
|
||||
...(removefromproduction ? { inproduction: false } : {}),
|
||||
...(values.qb_multiple_payers ? { qb_multiple_payers: values.qb_multiple_payers } : {})
|
||||
}
|
||||
},
|
||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
const handleFinish = async ({removefromproduction, ...values}) => {
|
||||
setLoading(true);
|
||||
const result = await client.mutate({
|
||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
|
||||
});
|
||||
if (result.errors) {
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
if (!result.errors) {
|
||||
// notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("job.errors.saving", {
|
||||
error: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: values.date_invoiced,
|
||||
actual_in: values.actual_in,
|
||||
actual_completion: values.actual_completion,
|
||||
actual_delivery: values.actual_delivery,
|
||||
kmin: values.kmin,
|
||||
kmout: values.kmout,
|
||||
dms_allocation: values.dms_allocation,
|
||||
...(removefromproduction ? {inproduction: false} : {}),
|
||||
...(values.qb_multiple_payers
|
||||
? {qb_multiple_payers: values.qb_multiple_payers}
|
||||
: {}),
|
||||
},
|
||||
},
|
||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||
awaitRefetchQueries: true,
|
||||
});
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
|
||||
if (!result.errors) {
|
||||
// notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("job.errors.saving", {
|
||||
error: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.closed")
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobinvoiced(),
|
||||
type: "jobinvoiced"
|
||||
});
|
||||
// history(`/manage/jobs/${job.id}`);
|
||||
} else {
|
||||
setLoading(false);
|
||||
notification["error"]({
|
||||
message: t("job.errors.closing", {
|
||||
error: JSON.stringify(closeResult.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.closed"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobinvoiced(),
|
||||
type: "jobinvoiced",});
|
||||
// history(`/manage/jobs/${job.id}`);
|
||||
} else {
|
||||
setLoading(false);
|
||||
notification["error"]({
|
||||
message: t("job.errors.closing", {
|
||||
error: JSON.stringify(closeResult.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
joblines: job.joblines,
|
||||
actual_in: job.actual_in ? dayjs(job.actual_in) : job.scheduled_in && dayjs(job.scheduled_in),
|
||||
actual_completion: job.actual_completion
|
||||
? dayjs(job.actual_completion)
|
||||
: job.scheduled_completion && dayjs(job.scheduled_completion),
|
||||
actual_delivery: job.actual_delivery
|
||||
? dayjs(job.actual_delivery)
|
||||
: job.scheduled_delivery && dayjs(job.scheduled_delivery),
|
||||
date_invoiced: job.date_invoiced ? dayjs(job.date_invoiced) : dayjs(),
|
||||
kmin: job.kmin,
|
||||
kmout: job.kmout,
|
||||
dms_allocation: job.dms_allocation,
|
||||
qb_multiple_payers: job.qb_multiple_payers
|
||||
}}
|
||||
scrollToFirstError
|
||||
>
|
||||
<PageHeader
|
||||
title={t("jobs.labels.closejob", { ro_number: job.ro_number })}
|
||||
extra={
|
||||
<Space>
|
||||
<JobsCloseAutoAllocate joblines={job.joblines} form={form} disabled={!!job.date_exported || jobRO} />
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
<Popconfirm
|
||||
onConfirm={() => form.submit()}
|
||||
disabled={jobRO}
|
||||
okText={t("general.labels.yes")}
|
||||
cancelText={t("general.labels.no")}
|
||||
title={t("jobs.labels.closeconfirm")}
|
||||
>
|
||||
<Button loading={loading} type="primary" danger disabled={jobRO}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
{(bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid) && (
|
||||
<Link to={`/manage/dms?jobId=${job.id}`}>
|
||||
<Button disabled={job.date_exported || !jobRO}>{t("jobs.actions.sendtodms")}</Button>
|
||||
</Link>
|
||||
)}
|
||||
<JobsScoreboardAdd job={job} disabled={false} />
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
joblines: job.joblines,
|
||||
actual_in: job.actual_in
|
||||
? dayjs(job.actual_in)
|
||||
: job.scheduled_in && dayjs(job.scheduled_in),
|
||||
actual_completion: job.actual_completion
|
||||
? dayjs(job.actual_completion)
|
||||
: job.scheduled_completion && dayjs(job.scheduled_completion),
|
||||
actual_delivery: job.actual_delivery
|
||||
? dayjs(job.actual_delivery)
|
||||
: job.scheduled_delivery && dayjs(job.scheduled_delivery),
|
||||
date_invoiced: job.date_invoiced
|
||||
? dayjs(job.date_invoiced)
|
||||
: dayjs(),
|
||||
kmin: job.kmin,
|
||||
kmout: job.kmout,
|
||||
dms_allocation: job.dms_allocation,
|
||||
qb_multiple_payers: job.qb_multiple_payers,
|
||||
}}
|
||||
scrollToFirstError
|
||||
>
|
||||
<PageHeader
|
||||
title={t("jobs.labels.closejob", {ro_number: job.ro_number})}
|
||||
extra={
|
||||
<Space>
|
||||
<JobsCloseAutoAllocate
|
||||
joblines={job.joblines}
|
||||
form={form}
|
||||
disabled={!!job.date_exported || jobRO}
|
||||
/>
|
||||
|
||||
<Popconfirm
|
||||
onConfirm={() => form.submit()}
|
||||
disabled={jobRO}
|
||||
okText={t("general.labels.yes")}
|
||||
cancelText={t("general.labels.no")}
|
||||
title={t("jobs.labels.closeconfirm")}
|
||||
>
|
||||
<Button loading={loading} type="primary" danger disabled={jobRO}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
{(bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid) && (
|
||||
<Link to={`/manage/dms?jobId=${job.id}`}>
|
||||
<Button disabled={job.date_exported || !jobRO}>
|
||||
{t("jobs.actions.sendtodms")}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<JobsScoreboardAdd job={job} disabled={false}/>
|
||||
</Space>
|
||||
<Space wrap direction="vertical" style={{ width: "100%" }}>
|
||||
<FormsFieldChanged form={form} />
|
||||
{!job.actual_in && job.scheduled_in && <Alert type="warning" message={t("jobs.labels.actual_in_inferred")} />}
|
||||
{!job.actual_completion && job.scheduled_completion && (
|
||||
<Alert type="warning" message={t("jobs.labels.actual_completion_inferred")} />
|
||||
)}
|
||||
{!job.actual_delivery && job.scheduled_delivery && (
|
||||
<Alert type="warning" message={t("jobs.labels.actual_delivery_inferred")} />
|
||||
)}
|
||||
</Space>
|
||||
<LayoutFormRow>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_in")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
name="actual_in"
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_completion")}
|
||||
name="actual_completion"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_delivery")}
|
||||
name="actual_delivery"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_invoiced")}
|
||||
name="date_invoiced"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!bodyshop.cdk_dealerid) return Promise.resolve();
|
||||
if (!value || dayjs(value).isSameOrAfter(dayjs(), "day")) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error(t("jobs.labels.dms.invoicedatefuture")));
|
||||
}
|
||||
}),
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (ClosingPeriod.treatment === "on" && bodyshop.accountingconfig.ClosingPeriod) {
|
||||
if (
|
||||
dayjs(value).isSameOrAfter(dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf("day")) &&
|
||||
dayjs(value).isSameOrBefore(dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf("day"))
|
||||
) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(new Error(t("jobs.labels.closingperiod")));
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} onlyFuture={!!bodyshop.cdk_dealerid} />
|
||||
</Form.Item>
|
||||
{!jobRO && job.inproduction && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.removefromproduction")}
|
||||
name="removefromproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmin")}
|
||||
name="kmin"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmout")}
|
||||
name="kmout"
|
||||
dependencies={["kmin"]}
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("kmin") <= value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
/>
|
||||
|
||||
<Space wrap direction="vertical" style={{width: "100%"}}>
|
||||
<FormsFieldChanged form={form}/>
|
||||
{!job.actual_in && job.scheduled_in && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_in_inferred")}
|
||||
/>
|
||||
)}
|
||||
{!job.actual_completion && job.scheduled_completion && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_completion_inferred")}
|
||||
/>
|
||||
)}
|
||||
{!job.actual_delivery && job.scheduled_delivery && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_delivery_inferred")}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
<LayoutFormRow>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_in")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
name="actual_in"
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_completion")}
|
||||
name="actual_completion"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
return Promise.reject(new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin")));
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.dms_allocation")}
|
||||
name="dms_allocation"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<>
|
||||
<Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col lg={8} md={24}>
|
||||
<Form.List
|
||||
name={["qb_multiple_payers"]}
|
||||
rules={[
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100)
|
||||
})
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_delivery")}
|
||||
name="actual_delivery"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_invoiced")}
|
||||
name="date_invoiced"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (!bodyshop.cdk_dealerid) return Promise.resolve();
|
||||
if (!value || dayjs(value).isSameOrAfter(dayjs(), "day")) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.dms.invoicedatefuture"))
|
||||
);
|
||||
},
|
||||
}),
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (
|
||||
ClosingPeriod.treatment === "on" &&
|
||||
bodyshop.accountingconfig.ClosingPeriod
|
||||
) {
|
||||
if (
|
||||
dayjs(value).isSameOrAfter(
|
||||
dayjs(
|
||||
bodyshop.accountingconfig.ClosingPeriod[0]
|
||||
).startOf("day")
|
||||
) &&
|
||||
dayjs(value).isSameOrBefore(
|
||||
dayjs(
|
||||
bodyshop.accountingconfig.ClosingPeriod[1]
|
||||
).endOf("day")
|
||||
)
|
||||
) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.closingperiod"))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<DateTimePicker
|
||||
disabled={jobRO}
|
||||
onlyFuture={!!bodyshop.cdk_dealerid}
|
||||
/>
|
||||
</Form.Item>
|
||||
{!jobRO && job.inproduction && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.removefromproduction")}
|
||||
name="removefromproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmin")}
|
||||
name="kmin"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmout")}
|
||||
name="kmout"
|
||||
dependencies={["kmin"]}
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("kmin") <= value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin"))
|
||||
);
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.dms_allocation")}
|
||||
name="dms_allocation"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<><Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col lg={8} md={24}>
|
||||
<Form.List
|
||||
name={["qb_multiple_payers"]}
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
|
||||
: Dinero();
|
||||
return discrep.getAmount() >= 0
|
||||
? Promise.resolve()
|
||||
: Promise.reject(new Error(t("jobs.labels.additionalpayeroverallocation")));
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
{(fields, { add, remove }) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<Space>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.name")}
|
||||
key={`${index}name`}
|
||||
name={[field.name, "name"]}
|
||||
rules={[
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100),
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(
|
||||
totalAllocated
|
||||
)
|
||||
: Dinero();
|
||||
return discrep.getAmount() >= 0
|
||||
? Promise.resolve()
|
||||
: Promise.reject(
|
||||
new Error(
|
||||
t("jobs.labels.additionalpayeroverallocation")
|
||||
)
|
||||
);
|
||||
},
|
||||
}),
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(fields, {add, remove}) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<Space>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.name")}
|
||||
key={`${index}name`}
|
||||
name={[field.name, "name"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
style={{minWidth: "12rem"}}
|
||||
disabled={jobRO}
|
||||
>
|
||||
{bodyshop.md_ins_cos.map((s) => (
|
||||
<Select.Option key={s.name} value={s.name}>
|
||||
{s.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
>
|
||||
<Select style={{ minWidth: "12rem" }} disabled={jobRO}>
|
||||
{bodyshop.md_ins_cos.map((s) => (
|
||||
<Select.Option key={s.name} value={s.name}>
|
||||
{s.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.amount")}
|
||||
key={`${index}amount`}
|
||||
name={[field.name, "amount"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.amount")}
|
||||
key={`${index}amount`}
|
||||
name={[field.name, "amount"]}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
|
||||
<DeleteFilled
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
if(!jobRO){
|
||||
remove(field.name);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{width: "100%"}}
|
||||
>
|
||||
{t("jobs.actions.dms.addpayer")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
<DeleteFilled
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
if (!jobRO) {
|
||||
remove(field.name);
|
||||
}
|
||||
}}
|
||||
</Form.List>
|
||||
</Col>
|
||||
<Col lg={16} md={24}>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
//Perform Calculation to determine discrepancy.
|
||||
let totalAllocated = Dinero();
|
||||
/>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("jobs.actions.dms.addpayer")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</Col>
|
||||
<Col lg={16} md={24}>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
//Perform Calculation to determine discrepancy.
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100),
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(
|
||||
totalAllocated
|
||||
)
|
||||
: Dinero();
|
||||
return (
|
||||
<Space size="large" wrap align="center">
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_cust_payable")}
|
||||
value={(job.job_totals
|
||||
? Dinero(job.job_totals.totals.custPayable)
|
||||
: Dinero()
|
||||
).toFormat()}
|
||||
/>
|
||||
<Divider type="vertical"/>
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_repairs")}
|
||||
value={(job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs)
|
||||
: Dinero()
|
||||
).toFormat()}
|
||||
/>
|
||||
<Typography.Title>-</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.dms.totalallocated")}
|
||||
value={totalAllocated.toFormat()}
|
||||
/>
|
||||
<Typography.Title>=</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.pimraryamountpayable")}
|
||||
valueStyle={{
|
||||
color: discrep.getAmount() > 0 ? "green" : "red",
|
||||
}}
|
||||
value={discrep.toFormat()}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
<Divider/>
|
||||
<JobsCloseLines job={job}/>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100)
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
|
||||
: Dinero();
|
||||
return (
|
||||
<Space size="large" wrap align="center">
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_cust_payable")}
|
||||
value={(job.job_totals ? Dinero(job.job_totals.totals.custPayable) : Dinero()).toFormat()}
|
||||
/>
|
||||
<Divider type="vertical" />
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_repairs")}
|
||||
value={(job.job_totals ? Dinero(job.job_totals.totals.total_repairs) : Dinero()).toFormat()}
|
||||
/>
|
||||
<Typography.Title>-</Typography.Title>
|
||||
<Statistic title={t("jobs.labels.dms.totalallocated")} value={totalAllocated.toFormat()} />
|
||||
<Typography.Title>=</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.pimraryamountpayable")}
|
||||
valueStyle={{
|
||||
color: discrep.getAmount() > 0 ? "green" : "red"
|
||||
}}
|
||||
value={discrep.toFormat()}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
<Divider />
|
||||
<JobsCloseLines job={job} />
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseComponent);
|
||||
|
||||
@@ -1,87 +1,82 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Result} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Result } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_JOB_CLOSE_DETAILS} from "../../graphql/jobs.queries";
|
||||
import {setBreadcrumbs, setJobReadOnly, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { QUERY_JOB_CLOSE_DETAILS } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setJobReadOnly, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import IsJobReadOnly from "../../utils/jobReadOnly";
|
||||
import JobsCloseComponent from "./jobs-close.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool))
|
||||
});
|
||||
|
||||
export function JobsCloseContainer({
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
setJobReadOnly,
|
||||
}) {
|
||||
const {jobId} = useParams();
|
||||
const {loading, error, data} = useQuery(QUERY_JOB_CLOSE_DETAILS, {
|
||||
variables: {id: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobReadOnly }) {
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_CLOSE_DETAILS, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
}
|
||||
}, [data, setJobReadOnly]);
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-close", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
}
|
||||
}, [data, setJobReadOnly]);
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-close", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null,
|
||||
});
|
||||
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
label: t("titles.bc.jobs"),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/close`,
|
||||
label: t("titles.bc.jobs-close"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, setSelectedHeader]);
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
label: t("titles.bc.jobs")
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/close`,
|
||||
label: t("titles.bc.jobs-close")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, setSelectedHeader]);
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!!!data.jobs_by_pk) return <NotFound/>;
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.jobs_by_pk) return <NotFound />;
|
||||
|
||||
if (!data.jobs_by_pk.job_totals)
|
||||
return (
|
||||
<Result
|
||||
title={t("jobs.errors.nofinancial")}
|
||||
extra={<JobCalculateTotals job={data.jobs_by_pk}/>}
|
||||
/>
|
||||
);
|
||||
if (!data.jobs_by_pk.job_totals)
|
||||
return <Result title={t("jobs.errors.nofinancial")} extra={<JobCalculateTotals job={data.jobs_by_pk} />} />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:close">
|
||||
<div>
|
||||
<JobsCloseComponent job={data ? data.jobs_by_pk : {}}/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:close">
|
||||
<div>
|
||||
<JobsCloseComponent job={data ? data.jobs_by_pk : {}} />
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(JobsCloseContainer);
|
||||
|
||||
Reference in New Issue
Block a user