390 lines
17 KiB
JavaScript
390 lines
17 KiB
JavaScript
import { DeleteFilled, WarningOutlined } from "@ant-design/icons";
|
|
import {
|
|
Button,
|
|
Divider,
|
|
Form,
|
|
Input,
|
|
InputNumber,
|
|
Select,
|
|
Switch,
|
|
} from "antd";
|
|
import React from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component";
|
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
const mapStateToProps = createStructuredSelector({
|
|
//currentUser: selectCurrentUser
|
|
bodyshop: selectBodyshop,
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
});
|
|
|
|
export function BillEnterModalLinesComponent({
|
|
bodyshop,
|
|
disabled,
|
|
lineData,
|
|
discount,
|
|
form,
|
|
responsibilityCenters,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const { setFieldsValue, getFieldsValue, getFieldValue } = form;
|
|
|
|
return (
|
|
<Form.List name="billlines">
|
|
{(fields, { add, remove, move }) => {
|
|
return (
|
|
<div className="invoice-form-lines-wrapper">
|
|
{fields.map((field, index) => (
|
|
<Form.Item required={false} key={field.key}>
|
|
<div>
|
|
<div style={{ display: "flex", alignItems: "center" }}>
|
|
<LayoutFormRow style={{ flex: 1 }} grow>
|
|
<Form.Item
|
|
label={t("billlines.fields.jobline")}
|
|
key={`${index}joblinename`}
|
|
name={[field.name, "joblineid"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<BillLineSearchSelect
|
|
disabled={disabled}
|
|
options={lineData}
|
|
onSelect={(value, opt) => {
|
|
setFieldsValue({
|
|
billlines: getFieldsValue([
|
|
"billlines",
|
|
]).billlines.map((item, idx) => {
|
|
if (idx === index) {
|
|
return {
|
|
...item,
|
|
line_desc: opt.line_desc,
|
|
quantity: opt.part_qty || 1,
|
|
actual_price: opt.cost,
|
|
cost_center: opt.part_type
|
|
? responsibilityCenters.defaults.costs[
|
|
opt.part_type
|
|
] || null
|
|
: null,
|
|
};
|
|
}
|
|
return item;
|
|
}),
|
|
});
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
label={t("billlines.fields.line_desc")}
|
|
key={`${index}line_desc`}
|
|
name={[field.name, "line_desc"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<Input disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.quantity")}
|
|
key={`${index}quantity`}
|
|
name={[field.name, "quantity"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<InputNumber
|
|
precision={0}
|
|
min={0}
|
|
disabled={disabled}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.actual_price")}
|
|
key={`${index}actual_price`}
|
|
name={[field.name, "actual_price"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<CurrencyInput
|
|
min={0}
|
|
disabled={disabled}
|
|
onBlur={(e) => {
|
|
setFieldsValue({
|
|
billlines: getFieldsValue(
|
|
"billlines"
|
|
).billlines.map((item, idx) => {
|
|
if (idx === index) {
|
|
return {
|
|
...item,
|
|
actual_cost: !!item.actual_cost
|
|
? item.actual_cost
|
|
: Math.round(
|
|
(parseFloat(e.target.value) *
|
|
(1 - discount) +
|
|
Number.EPSILON) *
|
|
100
|
|
) / 100,
|
|
};
|
|
}
|
|
return item;
|
|
}),
|
|
});
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.actual_cost")}
|
|
key={`${index}actual_cost`}
|
|
name={[field.name, "actual_cost"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<CurrencyInput min={0} disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item shouldUpdate>
|
|
{() => {
|
|
const line = getFieldsValue(["billlines"]).billlines[
|
|
index
|
|
];
|
|
if (!!!line) return null;
|
|
const lineDiscount = (
|
|
1 -
|
|
Math.round(
|
|
(line.actual_cost / line.actual_price) * 100
|
|
) /
|
|
100
|
|
).toPrecision(2);
|
|
|
|
if (lineDiscount - discount === 0) return <div />;
|
|
return <WarningOutlined style={{ color: "red" }} />;
|
|
}}
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.cost_center")}
|
|
key={`${index}cost_center`}
|
|
name={[field.name, "cost_center"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<Select style={{ width: "150px" }} disabled={disabled}>
|
|
{responsibilityCenters.costs.map((item) => (
|
|
<Select.Option key={item.name}>
|
|
{item.name}
|
|
</Select.Option>
|
|
))}
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.federal_tax_applicable")}
|
|
key={`${index}fedtax`}
|
|
initialValue={true}
|
|
valuePropName="checked"
|
|
name={[field.name, "applicable_taxes", "federal"]}
|
|
>
|
|
<Switch disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.state_tax_applicable")}
|
|
key={`${index}statetax`}
|
|
valuePropName="checked"
|
|
name={[field.name, "applicable_taxes", "state"]}
|
|
>
|
|
<Switch disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.local_tax_applicable")}
|
|
key={`${index}localtax`}
|
|
valuePropName="checked"
|
|
name={[field.name, "applicable_taxes", "local"]}
|
|
>
|
|
<Switch disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.labels.deductfromlabor")}
|
|
key={`${index}deductfromlabor`}
|
|
valuePropName="checked"
|
|
name={[field.name, "deductfromlabor"]}
|
|
>
|
|
<Switch disabled={disabled} />
|
|
</Form.Item>
|
|
<Form.Item
|
|
shouldUpdate={(prev, cur) =>
|
|
prev.billlines[index] &&
|
|
prev.billlines[index].deductfromlabor !==
|
|
cur.billlines[index] &&
|
|
cur.billlines[index].deductfromlabor
|
|
}
|
|
>
|
|
{() => {
|
|
if (
|
|
getFieldValue([
|
|
"billlines",
|
|
field.name,
|
|
"deductfromlabor",
|
|
])
|
|
)
|
|
return (
|
|
<div>
|
|
<Form.Item
|
|
label={t("joblines.fields.mod_lbr_ty")}
|
|
key={`${index}modlbrty`}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
name={[
|
|
field.name,
|
|
"lbr_adjustment",
|
|
"mod_lbr_ty",
|
|
]}
|
|
>
|
|
<Select allowClear>
|
|
<Select.Option value="LAA">
|
|
{t("joblines.fields.lbr_types.LAA")}
|
|
</Select.Option>
|
|
<Select.Option value="LAB">
|
|
{t("joblines.fields.lbr_types.LAB")}
|
|
</Select.Option>
|
|
<Select.Option value="LAD">
|
|
{t("joblines.fields.lbr_types.LAD")}
|
|
</Select.Option>
|
|
<Select.Option value="LAE">
|
|
{t("joblines.fields.lbr_types.LAE")}
|
|
</Select.Option>
|
|
<Select.Option value="LAF">
|
|
{t("joblines.fields.lbr_types.LAF")}
|
|
</Select.Option>
|
|
<Select.Option value="LAG">
|
|
{t("joblines.fields.lbr_types.LAG")}
|
|
</Select.Option>
|
|
<Select.Option value="LAM">
|
|
{t("joblines.fields.lbr_types.LAM")}
|
|
</Select.Option>
|
|
<Select.Option value="LAR">
|
|
{t("joblines.fields.lbr_types.LAR")}
|
|
</Select.Option>
|
|
<Select.Option value="LAS">
|
|
{t("joblines.fields.lbr_types.LAS")}
|
|
</Select.Option>
|
|
<Select.Option value="LAU">
|
|
{t("joblines.fields.lbr_types.LAU")}
|
|
</Select.Option>
|
|
<Select.Option value="LA1">
|
|
{t("joblines.fields.lbr_types.LA1")}
|
|
</Select.Option>
|
|
<Select.Option value="LA2">
|
|
{t("joblines.fields.lbr_types.LA2")}
|
|
</Select.Option>
|
|
<Select.Option value="LA3">
|
|
{t("joblines.fields.lbr_types.LA3")}
|
|
</Select.Option>
|
|
<Select.Option value="LA4">
|
|
{t("joblines.fields.lbr_types.LA4")}
|
|
</Select.Option>
|
|
</Select>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("jobs.labels.adjustmentrate")}
|
|
name={[field.name, "lbr_adjustment", "rate"]}
|
|
initialValue={
|
|
bodyshop.default_adjustment_rate
|
|
}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required"),
|
|
},
|
|
]}
|
|
>
|
|
<InputNumber precision={2} min={0.01} />
|
|
</Form.Item>
|
|
</div>
|
|
);
|
|
return <span />;
|
|
}}
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("billlines.fields.location")}
|
|
key={`${index}location`}
|
|
name={[field.name, "location"]}
|
|
>
|
|
<Select style={{ width: "10rem" }} disabled={disabled}>
|
|
{bodyshop.md_parts_locations.map((loc, idx) => (
|
|
<Select.Option key={idx} value={loc}>
|
|
{loc}
|
|
</Select.Option>
|
|
))}
|
|
</Select>
|
|
</Form.Item>
|
|
</LayoutFormRow>
|
|
<FormListMoveArrows
|
|
move={move}
|
|
index={index}
|
|
total={fields.length}
|
|
/>
|
|
<DeleteFilled
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
remove(field.name);
|
|
}}
|
|
/>
|
|
</div>
|
|
<Divider />
|
|
</div>
|
|
</Form.Item>
|
|
))}
|
|
<Form.Item>
|
|
<Button
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
add();
|
|
}}
|
|
style={{ width: "100%" }}
|
|
>
|
|
{t("billlines.actions.newline")}
|
|
</Button>
|
|
</Form.Item>
|
|
</div>
|
|
);
|
|
}}
|
|
</Form.List>
|
|
);
|
|
}
|
|
|
|
export default connect(
|
|
mapStateToProps,
|
|
mapDispatchToProps
|
|
)(BillEnterModalLinesComponent);
|