Files
bodyshop/client/src/components/contract-convert-to-ro/contract-convert-to-ro.component.jsx

391 lines
11 KiB
JavaScript

import { useMutation } from "@apollo/client/react";
import { Button, Form, InputNumber, Popover, Radio, Select, Space } from "antd";
import axios from "axios";
import dayjs from "../../utils/day";
import { 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";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
currentUser: selectCurrentUser
});
const mapDispatchToProps = () => ({
//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 notification = useNotification();
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_ph2: contract.job.owner.ownr_ph2,
ownr_ph1_ty: contract.job.owner.ownr_ph1_ty,
ownr_ph2_ty: contract.job.owner.ownr_ph2_ty,
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
}
}
};
if (currentUser?.email) {
newJob.created_user_email = currentUser.email;
}
//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);