Added conversion of cc contract to RO. BOD-234
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
import React, { useState } from "react";
|
||||
import { Button, notification, Popover, Radio, Form, InputNumber } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "react-apollo";
|
||||
import { INSERT_NEW_JOB } from "../../graphql/jobs.queries";
|
||||
import moment from "moment";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import { useHistory } from "react-router-dom";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function ContractConvertToRo({ bodyshop, currentUser, contract }) {
|
||||
const { t } = useTranslation();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
||||
const history = useHistory();
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
|
||||
const contractLength = moment(contract.actualreturn).diff(
|
||||
moment(contract.start),
|
||||
"days"
|
||||
);
|
||||
const billingLines = [
|
||||
{
|
||||
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,
|
||||
// mod_lbr_ty: "PAL",
|
||||
},
|
||||
];
|
||||
|
||||
const mileageDiff =
|
||||
contract.kmend - contract.kmstart - contract.dailyfreekm * contractLength;
|
||||
if (mileageDiff > 0) {
|
||||
billingLines.push({
|
||||
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,
|
||||
mod_lb_hrs: 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (values.refuelqty > 0) {
|
||||
billingLines.push({
|
||||
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,
|
||||
mod_lb_hrs: 0,
|
||||
});
|
||||
}
|
||||
if (values.applyCleanupCharge) {
|
||||
billingLines.push({
|
||||
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,
|
||||
mod_lb_hrs: 0,
|
||||
});
|
||||
}
|
||||
if (contract.damagewaiver) {
|
||||
//Add for cleanup fee.
|
||||
billingLines.push({
|
||||
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,
|
||||
mod_lb_hrs: 0,
|
||||
});
|
||||
}
|
||||
|
||||
const newJob = {
|
||||
// converted: true,
|
||||
shopid: bodyshop.id,
|
||||
ownerid: contract.job.ownerid,
|
||||
vehicleid: contract.job.vehicleid,
|
||||
federal_tax_rate: bodyshop.invoice_tax_rates.federal_tax_rate / 100,
|
||||
state_tax_rate: bodyshop.invoice_tax_rates.state_tax_rate / 100,
|
||||
local_tax_rate: bodyshop.invoice_tax_rates.local_tax_rate / 100,
|
||||
clm_no: `${contract.job.clm_no}-CC`,
|
||||
clm_total: 1234, //TODO
|
||||
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.v_model_desc,
|
||||
v_model_yr: contract.job.vehicle.v_model_yr,
|
||||
v_make_desc: contract.job.vehicle.v_make_desc,
|
||||
v_vin: contract.job.vehicle.v_vin,
|
||||
status: bodyshop.md_ro_statuses.default_completed,
|
||||
notes: {
|
||||
data: [
|
||||
{
|
||||
text: t("contracts.labels.noteconvertedfrom", {
|
||||
agreementnumber: contract.agreementnumber,
|
||||
}),
|
||||
created_by: currentUser.email,
|
||||
},
|
||||
],
|
||||
},
|
||||
joblines: {
|
||||
data: billingLines,
|
||||
},
|
||||
parts_tax_rates: {
|
||||
CCDR: {
|
||||
prt_type: "CCDR",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: 0.07,
|
||||
},
|
||||
CCF: {
|
||||
prt_type: "CCF",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: 0.07,
|
||||
},
|
||||
CCM: {
|
||||
prt_type: "CCM",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: 0.07,
|
||||
},
|
||||
CCC: {
|
||||
prt_type: "CCC",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: 0.07,
|
||||
},
|
||||
CCD: {
|
||||
prt_type: "CCD",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: 0.07,
|
||||
},
|
||||
},
|
||||
};
|
||||
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}`
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const popContent = (
|
||||
<div>
|
||||
<Form onFinish={handleFinish}>
|
||||
<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>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{t("contracts.actions.convertoro")}
|
||||
</Button>
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Popover content={popContent} visible={visible}>
|
||||
<Button onClick={() => setVisible(true)} loading={loading}>
|
||||
{t("contracts.actions.convertoro")}
|
||||
</Button>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ContractConvertToRo);
|
||||
@@ -36,7 +36,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
return acc;
|
||||
}
|
||||
}, Dinero({ amount: 0 }));
|
||||
|
||||
console.log("job.federal_tax_rate ", job.federal_tax_rate);
|
||||
console.log(subtotal.percentage((job.federal_tax_rate || 0) * 100));
|
||||
let ret = {
|
||||
subtotal: subtotal,
|
||||
federal_tax: subtotal.percentage((job.federal_tax_rate || 0) * 100),
|
||||
@@ -219,15 +220,28 @@ function CalculatePartsTotals(jobLines) {
|
||||
const ret = jobLines.reduce(
|
||||
(acc, value) => {
|
||||
switch (value.part_type) {
|
||||
case "PAA":
|
||||
case "PAC":
|
||||
case "PAG":
|
||||
case "PAL":
|
||||
case "PAM":
|
||||
case "PAN":
|
||||
case "PAO":
|
||||
case "PAP":
|
||||
case "PAR":
|
||||
case "PAS":
|
||||
case "PASL":
|
||||
return {
|
||||
...acc,
|
||||
sublets: {
|
||||
...acc.sublets,
|
||||
subtotal: acc.sublets.subtotal.add(
|
||||
Dinero({ amount: Math.round(value.act_price * 100) })
|
||||
),
|
||||
//TODO Add Adjustments in
|
||||
},
|
||||
};
|
||||
// case "PAA":
|
||||
// case "PAC":
|
||||
// case "PAG":
|
||||
// case "PAL":
|
||||
// case "PAM":
|
||||
// case "PAN":
|
||||
// case "PAO":
|
||||
// case "PAP":
|
||||
// case "PAR":
|
||||
default:
|
||||
return {
|
||||
...acc,
|
||||
parts: {
|
||||
@@ -258,20 +272,8 @@ function CalculatePartsTotals(jobLines) {
|
||||
//TODO Add Adjustments in
|
||||
},
|
||||
};
|
||||
case "PAS":
|
||||
case "PASL":
|
||||
return {
|
||||
...acc,
|
||||
sublets: {
|
||||
...acc.sublets,
|
||||
subtotal: acc.sublets.subtotal.add(
|
||||
Dinero({ amount: Math.round(value.act_price * 100) })
|
||||
),
|
||||
//TODO Add Adjustments in
|
||||
},
|
||||
};
|
||||
default:
|
||||
return acc;
|
||||
// default:
|
||||
// return acc;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,7 +90,6 @@ export function JobsAvailableContainer({
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.created"),
|
||||
onClick: () => {
|
||||
console.log("r", r);
|
||||
history.push(
|
||||
`/manage/jobs/${r.data.insert_jobs.returning[0].id}`
|
||||
);
|
||||
@@ -121,11 +120,12 @@ export function JobsAvailableContainer({
|
||||
setSelectedOwner(null);
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent type='error' message={error.message} />;
|
||||
if (error) return <AlertComponent type="error" message={error.message} />;
|
||||
return (
|
||||
<LoadingSpinner
|
||||
loading={insertLoading}
|
||||
message={t("jobs.labels.creating_new_job")}>
|
||||
message={t("jobs.labels.creating_new_job")}
|
||||
>
|
||||
<JobsAvailableComponent
|
||||
loading={loading}
|
||||
data={data}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Col, Form, Input, Row, Divider } from "antd";
|
||||
import { Col, Form, Input, Row, Divider, Select } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
@@ -80,7 +80,17 @@ export function JobsDetailFinancials({ job, bodyshop }) {
|
||||
<Col {...colSpan}>
|
||||
<FormRow header={t("jobs.forms.dedinfo")}>
|
||||
<Form.Item label={t("jobs.fields.ded_status")} name="ded_status">
|
||||
<Input />
|
||||
<Select>
|
||||
<Select.Option value="W">
|
||||
{t("jobs.labels.deductible.waived")}
|
||||
</Select.Option>
|
||||
<Select.Option value="Y">
|
||||
{t("jobs.labels.deductible.yes")}
|
||||
</Select.Option>
|
||||
<Select.Option value="N">
|
||||
{t("jobs.labels.deductible.no")}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
||||
<CurrencyInput />
|
||||
|
||||
Reference in New Issue
Block a user