382 lines
11 KiB
JavaScript
382 lines
11 KiB
JavaScript
import { useMutation } from "@apollo/client";
|
|
import { Button, Form, InputNumber, notification, Popover, Radio, Select, Space } from "antd";
|
|
import axios from "axios";
|
|
import dayjs from "../../utils/day";
|
|
import React, { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { INSERT_NEW_JOB } from "../../graphql/jobs.queries";
|
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
//currentUser: selectCurrentUser
|
|
bodyshop: selectBodyshop,
|
|
currentUser: selectCurrentUser
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
});
|
|
|
|
export function ContractConvertToRo({ bodyshop, currentUser, contract, disabled }) {
|
|
const { t } = useTranslation();
|
|
const [open, setOpen] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
|
const history = useNavigate();
|
|
|
|
const handleFinish = async (values) => {
|
|
setLoading(true);
|
|
|
|
const contractLength = dayjs(contract.actualreturn).diff(dayjs(contract.start), "day");
|
|
const billingLines = [];
|
|
if (contractLength > 0)
|
|
billingLines.push({
|
|
manual_line: true,
|
|
unq_seq: 1,
|
|
line_no: 1,
|
|
line_ref: 1,
|
|
line_desc: t("contracts.fields.dailyrate"),
|
|
db_price: contract.dailyrate,
|
|
act_price: contract.dailyrate,
|
|
part_qty: contractLength,
|
|
part_type: "CCDR",
|
|
tax_part: true,
|
|
mod_lb_hrs: 0,
|
|
db_ref: "io-ccdr"
|
|
// mod_lbr_ty: "PAL",
|
|
});
|
|
const mileageDiff = contract.kmend - contract.kmstart - contract.dailyfreekm * contractLength;
|
|
if (mileageDiff > 0) {
|
|
billingLines.push({
|
|
manual_line: true,
|
|
unq_seq: 2,
|
|
line_no: 2,
|
|
line_ref: 2,
|
|
line_desc: "Fuel Surcharge",
|
|
db_price: contract.excesskmrate,
|
|
act_price: contract.excesskmrate,
|
|
part_type: "CCM",
|
|
part_qty: mileageDiff,
|
|
tax_part: true,
|
|
db_ref: "io-ccm",
|
|
mod_lb_hrs: 0
|
|
});
|
|
}
|
|
|
|
if (values.refuelqty > 0) {
|
|
billingLines.push({
|
|
manual_line: true,
|
|
unq_seq: 3,
|
|
line_no: 3,
|
|
line_ref: 3,
|
|
line_desc: t("contracts.fields.refuelcharge"),
|
|
db_price: contract.refuelcharge,
|
|
act_price: contract.refuelcharge,
|
|
part_qty: values.refuelqty,
|
|
part_type: "CCF",
|
|
tax_part: true,
|
|
db_ref: "io-ccf",
|
|
mod_lb_hrs: 0
|
|
});
|
|
}
|
|
if (values.applyCleanupCharge) {
|
|
billingLines.push({
|
|
manual_line: true,
|
|
unq_seq: 4,
|
|
line_no: 4,
|
|
line_ref: 4,
|
|
line_desc: t("contracts.fields.cleanupcharge"),
|
|
db_price: contract.cleanupcharge,
|
|
act_price: contract.cleanupcharge,
|
|
part_qty: 1,
|
|
part_type: "CCC",
|
|
tax_part: true,
|
|
db_ref: "io-ccc",
|
|
mod_lb_hrs: 0
|
|
});
|
|
}
|
|
if (contract.damagewaiver) {
|
|
//Add for cleanup fee.
|
|
billingLines.push({
|
|
manual_line: true,
|
|
unq_seq: 5,
|
|
line_no: 5,
|
|
line_ref: 5,
|
|
line_desc: t("contracts.fields.damagewaiver"),
|
|
db_price: contract.damagewaiver,
|
|
act_price: contract.damagewaiver,
|
|
part_type: "CCD",
|
|
part_qty: 1,
|
|
tax_part: true,
|
|
db_ref: "io-ccd",
|
|
mod_lb_hrs: 0
|
|
});
|
|
}
|
|
|
|
const newJob = {
|
|
// converted: true,
|
|
shopid: bodyshop.id,
|
|
ownerid: contract.job.ownerid,
|
|
vehicleid: contract.job.vehicleid,
|
|
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
|
|
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
|
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
|
|
ins_co_nm: values.ins_co_nm,
|
|
class: values.class,
|
|
converted: true,
|
|
clm_no: contract.job.clm_no ? `${contract.job.clm_no}-CC` : null,
|
|
ownr_fn: contract.job.owner.ownr_fn,
|
|
ownr_ln: contract.job.owner.ownr_ln,
|
|
ownr_co_nm: contract.job.owner.ownr_co_nm,
|
|
ownr_ph1: contract.job.owner.ownr_ph1,
|
|
ownr_ea: contract.job.owner.ownr_ea,
|
|
v_model_desc: contract.job.vehicle && contract.job.vehicle.v_model_desc,
|
|
v_model_yr: contract.job.vehicle && contract.job.vehicle.v_model_yr,
|
|
v_make_desc: contract.job.vehicle && contract.job.vehicle.v_make_desc,
|
|
v_vin: contract.job.vehicle && contract.job.vehicle.v_vin,
|
|
status: bodyshop.md_ro_statuses.default_completed,
|
|
notes: {
|
|
data: [
|
|
{
|
|
text: t("contracts.labels.noteconvertedfrom", {
|
|
agreementnumber: contract.agreementnumber
|
|
}),
|
|
audit: true,
|
|
created_by: currentUser.email
|
|
}
|
|
]
|
|
},
|
|
joblines: {
|
|
data: billingLines
|
|
},
|
|
parts_tax_rates: {
|
|
PAA: {
|
|
prt_type: "PAA",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAC: {
|
|
prt_type: "PAC",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAL: {
|
|
prt_type: "PAL",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAM: {
|
|
prt_type: "PAM",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAN: {
|
|
prt_type: "PAN",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAR: {
|
|
prt_type: "PAR",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
PAS: {
|
|
prt_type: "PAS",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
CCDR: {
|
|
prt_type: "CCDR",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
CCF: {
|
|
prt_type: "CCF",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
CCM: {
|
|
prt_type: "CCM",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
CCC: {
|
|
prt_type: "CCC",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
},
|
|
CCD: {
|
|
prt_type: "CCD",
|
|
prt_discp: 0,
|
|
prt_mktyp: false,
|
|
prt_mkupp: 0,
|
|
prt_tax_in: true,
|
|
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
|
}
|
|
}
|
|
};
|
|
|
|
//Calcualte the new job totals.
|
|
|
|
const newTotals = (
|
|
await axios.post("/job/totals", {
|
|
job: { ...newJob, joblines: billingLines }
|
|
})
|
|
).data;
|
|
|
|
newJob.clm_total = newTotals.totals.total_repairs.amount / 100;
|
|
newJob.job_totals = newTotals;
|
|
|
|
const result = await insertJob({
|
|
variables: { job: [newJob] }
|
|
// refetchQueries: ["GET_JOB_BY_PK"],
|
|
// awaitRefetchQueries: true,
|
|
});
|
|
|
|
if (!!result.errors) {
|
|
notification["error"]({
|
|
message: t("jobs.errors.inserting", {
|
|
message: JSON.stringify(result.errors)
|
|
})
|
|
});
|
|
} else {
|
|
notification["success"]({
|
|
message: t("jobs.successes.created"),
|
|
onClick: () => {
|
|
history.push(`/manage/jobs/${result.data.insert_jobs.returning[0].id}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
setOpen(false);
|
|
setLoading(false);
|
|
};
|
|
|
|
const popContent = (
|
|
<div>
|
|
<Form onFinish={handleFinish}>
|
|
<Form.Item
|
|
name={["ins_co_nm"]}
|
|
label={t("jobs.fields.ins_co_nm")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<Select>
|
|
{bodyshop.md_ins_cos.map((s) => (
|
|
<Select.Option key={s.name} value={s.name}>
|
|
{s.name}
|
|
</Select.Option>
|
|
))}
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name={"class"}
|
|
label={t("jobs.fields.class")}
|
|
rules={[
|
|
{
|
|
required: bodyshop.enforce_class
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<Select>
|
|
{bodyshop.md_classes.map((s) => (
|
|
<Select.Option key={s} value={s}>
|
|
{s}
|
|
</Select.Option>
|
|
))}
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("contracts.labels.convertform.applycleanupcharge")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
name={"applyCleanupCharge"}
|
|
>
|
|
<Radio.Group>
|
|
<Radio value={true}>{t("general.labels.yes")}</Radio>
|
|
<Radio value={false}>{t("general.labels.no")}</Radio>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("contracts.labels.convertform.refuelqty")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
name={"refuelqty"}
|
|
>
|
|
<InputNumber precision={0} min={0} />
|
|
</Form.Item>
|
|
<Space>
|
|
<Button type="primary" htmlType="submit" loading={loading}>
|
|
{t("contracts.actions.convertoro")}
|
|
</Button>
|
|
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
|
|
</Space>
|
|
</Form>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<Popover content={popContent} open={open}>
|
|
<Button
|
|
onClick={() => setOpen(true)}
|
|
loading={loading}
|
|
disabled={!contract.dailyrate || !contract.actualreturn || disabled}
|
|
>
|
|
{t("contracts.actions.convertoro")}
|
|
</Button>
|
|
</Popover>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(ContractConvertToRo);
|