Updating styling on parts and invoicing modals BOD-404
This commit is contained in:
@@ -9789,6 +9789,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>fields</name>
|
<name>fields</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>allpartslocation</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>date</name>
|
<name>date</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -10109,6 +10130,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>invoice_lines</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>invoice_total</name>
|
<name>invoice_total</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ function InvoiceEnterModalContainer({
|
|||||||
<Form
|
<Form
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
autoComplete={"off"}
|
autoComplete={"off"}
|
||||||
|
layout="vertical"
|
||||||
form={form}
|
form={form}
|
||||||
onFinishFailed={() => {
|
onFinishFailed={() => {
|
||||||
setEnterAgain(false);
|
setEnterAgain(false);
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import { Button, Form, Input, Select, Statistic, Switch, Upload } from "antd";
|
import {
|
||||||
|
Button,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Statistic,
|
||||||
|
Switch,
|
||||||
|
Typography,
|
||||||
|
Upload,
|
||||||
|
} from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -8,6 +18,7 @@ import AlertComponent from "../alert/alert.component";
|
|||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
import InvoiceFormLines from "./invoice-form.lines.component";
|
import InvoiceFormLines from "./invoice-form.lines.component";
|
||||||
import "./invoice-form.styles.scss";
|
import "./invoice-form.styles.scss";
|
||||||
@@ -54,8 +65,8 @@ export function InvoiceFormComponent({
|
|||||||
}, [form, setDiscount, vendorAutoCompleteOptions, loadLines]);
|
}, [form, setDiscount, vendorAutoCompleteOptions, loadLines]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="invoice-form-wrapper">
|
<div>
|
||||||
<div className="invoice-form-invoice-details">
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="jobid"
|
name="jobid"
|
||||||
label={t("invoices.fields.ro_number")}
|
label={t("invoices.fields.ro_number")}
|
||||||
@@ -91,8 +102,9 @@ export function InvoiceFormComponent({
|
|||||||
onSelect={handleVendorSelect}
|
onSelect={handleVendorSelect}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</LayoutFormRow>
|
||||||
<div className="invoice-form-invoice-details">
|
|
||||||
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.invoice_number")}
|
label={t("invoices.fields.invoice_number")}
|
||||||
name="invoice_number"
|
name="invoice_number"
|
||||||
@@ -167,7 +179,10 @@ export function InvoiceFormComponent({
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</LayoutFormRow>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{t("invoices.labels.invoice_lines")}
|
||||||
|
</Typography.Title>
|
||||||
<InvoiceFormLines
|
<InvoiceFormLines
|
||||||
lineData={lineData}
|
lineData={lineData}
|
||||||
discount={discount}
|
discount={discount}
|
||||||
@@ -211,7 +226,7 @@ export function InvoiceFormComponent({
|
|||||||
if (!!totals)
|
if (!!totals)
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="invoice-form-totals">
|
<Space>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.subtotal")}
|
title={t("invoices.labels.subtotal")}
|
||||||
value={totals.subtotal.toFormat()}
|
value={totals.subtotal.toFormat()}
|
||||||
@@ -251,7 +266,7 @@ export function InvoiceFormComponent({
|
|||||||
value={totals.discrepancy.toFormat()}
|
value={totals.discrepancy.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Space>
|
||||||
{form.getFieldValue("is_credit_memo") ? (
|
{form.getFieldValue("is_credit_memo") ? (
|
||||||
<AlertComponent
|
<AlertComponent
|
||||||
type="warning"
|
type="warning"
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
import { DeleteFilled, WarningOutlined } from "@ant-design/icons";
|
import { DeleteFilled, WarningOutlined } from "@ant-design/icons";
|
||||||
import { Button, Form, Input, InputNumber, Select, Switch } from "antd";
|
import {
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
Select,
|
||||||
|
Switch,
|
||||||
|
} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import InvoiceLineSearchSelect from "../invoice-line-search-select/invoice-line-search-select.component";
|
import InvoiceLineSearchSelect from "../invoice-line-search-select/invoice-line-search-select.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
export default function InvoiceEnterModalLinesComponent({
|
export default function InvoiceEnterModalLinesComponent({
|
||||||
lineData,
|
lineData,
|
||||||
discount,
|
discount,
|
||||||
@@ -21,197 +30,202 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<div className="invoice-form-lines-wrapper">
|
<div className="invoice-form-lines-wrapper">
|
||||||
{fields.map((field, index) => (
|
{fields.map((field, index) => (
|
||||||
<Form.Item required={false} key={field.key}>
|
<Form.Item required={false} key={field.key}>
|
||||||
<div className="invoice-form-line">
|
<div>
|
||||||
<Form.Item
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
label={t("invoicelines.fields.jobline")}
|
<LayoutFormRow style={{ flex: 1 }} grow>
|
||||||
key={`${index}joblinename`}
|
<Form.Item
|
||||||
name={[field.name, "joblineid"]}
|
label={t("invoicelines.fields.jobline")}
|
||||||
rules={[
|
key={`${index}joblinename`}
|
||||||
{
|
name={[field.name, "joblineid"]}
|
||||||
required: true,
|
rules={[
|
||||||
message: t("general.validation.required"),
|
{
|
||||||
},
|
required: true,
|
||||||
]}
|
message: t("general.validation.required"),
|
||||||
>
|
},
|
||||||
<InvoiceLineSearchSelect
|
]}
|
||||||
options={lineData}
|
>
|
||||||
onSelect={(value, opt) => {
|
<InvoiceLineSearchSelect
|
||||||
setFieldsValue({
|
options={lineData}
|
||||||
invoicelines: getFieldsValue([
|
onSelect={(value, opt) => {
|
||||||
"invoicelines",
|
setFieldsValue({
|
||||||
]).invoicelines.map((item, idx) => {
|
invoicelines: getFieldsValue([
|
||||||
if (idx === index) {
|
"invoicelines",
|
||||||
return {
|
]).invoicelines.map((item, idx) => {
|
||||||
...item,
|
if (idx === index) {
|
||||||
line_desc: opt.line_desc,
|
return {
|
||||||
quantity: opt.part_qty || 1,
|
...item,
|
||||||
actual_price: opt.cost,
|
line_desc: opt.line_desc,
|
||||||
cost_center: opt.part_type
|
quantity: opt.part_qty || 1,
|
||||||
? responsibilityCenters.defaults.costs[
|
actual_price: opt.cost,
|
||||||
opt.part_type
|
cost_center: opt.part_type
|
||||||
] || null
|
? responsibilityCenters.defaults.costs[
|
||||||
: null,
|
opt.part_type
|
||||||
};
|
] || null
|
||||||
}
|
: null,
|
||||||
return item;
|
};
|
||||||
}),
|
}
|
||||||
});
|
return item;
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.line_desc")}
|
||||||
|
key={`${index}line_desc`}
|
||||||
|
name={[field.name, "line_desc"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.quantity")}
|
||||||
|
key={`${index}quantity`}
|
||||||
|
name={[field.name, "quantity"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber precision={0} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.actual")}
|
||||||
|
key={`${index}actual_price`}
|
||||||
|
name={[field.name, "actual_price"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<CurrencyInput
|
||||||
|
min={0}
|
||||||
|
onBlur={(e) => {
|
||||||
|
setFieldsValue({
|
||||||
|
invoicelines: getFieldsValue(
|
||||||
|
"invoicelines"
|
||||||
|
).invoicelines.map((item, idx) => {
|
||||||
|
if (idx === index) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
actual_cost: !!item.actual_cost
|
||||||
|
? item.actual_cost
|
||||||
|
: parseFloat(e.target.value) *
|
||||||
|
(1 - discount),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.actual_cost")}
|
||||||
|
key={`${index}actual_cost`}
|
||||||
|
name={[field.name, "actual_cost"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<CurrencyInput min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
const line = getFieldsValue(["invoicelines"])
|
||||||
|
.invoicelines[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("invoicelines.fields.cost_center")}
|
||||||
|
key={`${index}cost_center`}
|
||||||
|
name={[field.name, "cost_center"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select style={{ width: "150px" }}>
|
||||||
|
{responsibilityCenters.costs.map((item) => (
|
||||||
|
<Select.Option key={item.name}>
|
||||||
|
{item.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.federal_tax_applicable")}
|
||||||
|
key={`${index}fedtax`}
|
||||||
|
initialValue={true}
|
||||||
|
valuePropName="checked"
|
||||||
|
name={[field.name, "applicable_taxes", "federal"]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.state_tax_applicable")}
|
||||||
|
key={`${index}statetax`}
|
||||||
|
valuePropName="checked"
|
||||||
|
name={[field.name, "applicable_taxes", "state"]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("invoicelines.fields.local_tax_applicable")}
|
||||||
|
key={`${index}localtax`}
|
||||||
|
valuePropName="checked"
|
||||||
|
name={[field.name, "applicable_taxes", "local"]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
</LayoutFormRow>
|
||||||
|
<FormListMoveArrows
|
||||||
|
move={move}
|
||||||
|
index={index}
|
||||||
|
total={fields.length}
|
||||||
|
/>
|
||||||
|
<DeleteFilled
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</div>
|
||||||
|
<Divider />
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.line_desc")}
|
|
||||||
key={`${index}line_desc`}
|
|
||||||
name={[field.name, "line_desc"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.quantity")}
|
|
||||||
key={`${index}quantity`}
|
|
||||||
name={[field.name, "quantity"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputNumber precision={0} min={0} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.actual")}
|
|
||||||
key={`${index}actual_price`}
|
|
||||||
name={[field.name, "actual_price"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<CurrencyInput
|
|
||||||
min={0}
|
|
||||||
onBlur={(e) => {
|
|
||||||
setFieldsValue({
|
|
||||||
invoicelines: getFieldsValue(
|
|
||||||
"invoicelines"
|
|
||||||
).invoicelines.map((item, idx) => {
|
|
||||||
if (idx === index) {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
actual_cost: !!item.actual_cost
|
|
||||||
? item.actual_cost
|
|
||||||
: parseFloat(e.target.value) * (1 - discount),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.actual_cost")}
|
|
||||||
key={`${index}actual_cost`}
|
|
||||||
name={[field.name, "actual_cost"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<CurrencyInput min={0} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item shouldUpdate>
|
|
||||||
{() => {
|
|
||||||
const line = getFieldsValue(["invoicelines"])
|
|
||||||
.invoicelines[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 null;
|
|
||||||
return <WarningOutlined style={{ color: "red" }} />;
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.cost_center")}
|
|
||||||
key={`${index}cost_center`}
|
|
||||||
name={[field.name, "cost_center"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select style={{ width: "150px" }}>
|
|
||||||
{responsibilityCenters.costs.map((item) => (
|
|
||||||
<Select.Option key={item.name}>
|
|
||||||
{item.name}
|
|
||||||
</Select.Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.federal_tax_applicable")}
|
|
||||||
key={`${index}fedtax`}
|
|
||||||
initialValue={true}
|
|
||||||
valuePropName="checked"
|
|
||||||
name={[field.name, "applicable_taxes", "federal"]}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.state_tax_applicable")}
|
|
||||||
key={`${index}statetax`}
|
|
||||||
valuePropName="checked"
|
|
||||||
name={[field.name, "applicable_taxes", "state"]}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("invoicelines.fields.local_tax_applicable")}
|
|
||||||
key={`${index}localtax`}
|
|
||||||
valuePropName="checked"
|
|
||||||
name={[field.name, "applicable_taxes", "local"]}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<DeleteFilled
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
))}
|
))}
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button
|
<Button
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
add();
|
add();
|
||||||
}}
|
}}
|
||||||
style={{ width: "50%" }}
|
style={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
{t("invoicelines.actions.newline")}
|
{t("invoicelines.actions.newline")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
.invoice-form-wrapper {
|
// .invoice-form-wrapper {
|
||||||
display: flex;
|
// display: flex;
|
||||||
flex-direction: column;
|
// flex-direction: column;
|
||||||
justify-content: left;
|
// justify-content: left;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.invoice-form-totals {
|
// .invoice-form-totals {
|
||||||
display: flex;
|
// display: flex;
|
||||||
justify-content: space-around;
|
// justify-content: space-around;
|
||||||
align-items: flex-start;
|
// align-items: flex-start;
|
||||||
flex-wrap: wrap;
|
// flex-wrap: wrap;
|
||||||
& > * {
|
// & > * {
|
||||||
padding: 5px;
|
// padding: 5px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
.invoice-form-invoice-details {
|
// .invoice-form-invoice-details {
|
||||||
display: flex;
|
// display: flex;
|
||||||
align-items: flex-start;
|
// align-items: flex-start;
|
||||||
flex-wrap: wrap;
|
// flex-wrap: wrap;
|
||||||
& > * {
|
// & > * {
|
||||||
padding: 5px;
|
// padding: 5px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
.invoice-form-lines-wrapper {
|
// .invoice-form-lines-wrapper {
|
||||||
border: 3px ridge rgba(28, 110, 164, 0.24);
|
// border: 3px ridge rgba(28, 110, 164, 0.24);
|
||||||
border-radius: 4px;
|
// border-radius: 4px;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.invoice-form-line {
|
// .invoice-form-line {
|
||||||
display: flex;
|
// display: flex;
|
||||||
flex-wrap: wrap;
|
// flex-wrap: wrap;
|
||||||
align-items: flex-start;
|
// align-items: flex-start;
|
||||||
justify-content: space-around;
|
// justify-content: space-around;
|
||||||
border-bottom: 2px dashed rgba(7, 7, 7, 0.4);
|
// border-bottom: 2px dashed rgba(7, 7, 7, 0.4);
|
||||||
F & > * {
|
// F & > * {
|
||||||
margin: 5px;
|
// margin: 5px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const InvoiceLineSearchSelect = (
|
|||||||
autoFocus
|
autoFocus
|
||||||
value={option}
|
value={option}
|
||||||
style={{
|
style={{
|
||||||
width: 300,
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
onChange={setOption}
|
onChange={setOption}
|
||||||
optionFilterProp="line_desc"
|
optionFilterProp="line_desc"
|
||||||
@@ -48,12 +48,18 @@ const InvoiceLineSearchSelect = (
|
|||||||
<Row justify="center" align="middle">
|
<Row justify="center" align="middle">
|
||||||
<Col span={12}>{item.line_desc}</Col>
|
<Col span={12}>{item.line_desc}</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Tag color="blue">{item.oem_partno}</Tag>
|
{item.oem_partno ? (
|
||||||
|
<Tag color="blue">{item.oem_partno}</Tag>
|
||||||
|
) : null}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Tag color="green">
|
{item.act_price ? (
|
||||||
<CurrencyFormatter>{item.act_price || 0}</CurrencyFormatter>
|
<Tag color="green">
|
||||||
</Tag>
|
<CurrencyFormatter>
|
||||||
|
{item.act_price || 0}
|
||||||
|
</CurrencyFormatter>
|
||||||
|
</Tag>
|
||||||
|
) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Option>
|
</Option>
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ export function JobLinesComponent({
|
|||||||
setPartsOrderContext({
|
setPartsOrderContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
jobId: job.jobId,
|
jobId: job.id,
|
||||||
linesToOrder: selectedLines,
|
linesToOrder: selectedLines,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -348,7 +348,7 @@ export function JobLinesComponent({
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setJobLineEditContext({
|
setJobLineEditContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: { jobid: job.jobId },
|
context: { jobid: job.id },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -372,7 +372,7 @@ export function JobLinesComponent({
|
|||||||
{record.parts_order_lines.map((item) => (
|
{record.parts_order_lines.map((item) => (
|
||||||
<div key={item.id}>
|
<div key={item.id}>
|
||||||
<Link
|
<Link
|
||||||
to={`/manage/jobs/${job.jobId}?tab=partssublet&partsorderid=${item.parts_order.id}`}
|
to={`/manage/jobs/${job.id}?tab=partssublet&partsorderid=${item.parts_order.id}`}
|
||||||
>
|
>
|
||||||
{item.parts_order.order_number || ""}
|
{item.parts_order.order_number || ""}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const JobSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
value={option}
|
value={option}
|
||||||
style={{
|
style={{
|
||||||
width: 300,
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ import React from "react";
|
|||||||
import { Row, Col, Typography } from "antd";
|
import { Row, Col, Typography } from "antd";
|
||||||
import "./layout-form-row.styles.scss";
|
import "./layout-form-row.styles.scss";
|
||||||
|
|
||||||
export default function LayoutFormRow({ header, children, grow = false }) {
|
export default function LayoutFormRow({
|
||||||
|
header,
|
||||||
|
children,
|
||||||
|
grow = false,
|
||||||
|
...restProps
|
||||||
|
}) {
|
||||||
if (!!!children.length) {
|
if (!!!children.length) {
|
||||||
//We have only one element. It's going to get the whole thing.
|
//We have only one element. It's going to get the whole thing.
|
||||||
return (
|
return (
|
||||||
@@ -20,7 +25,7 @@ export default function LayoutFormRow({ header, children, grow = false }) {
|
|||||||
if (spanOverride) return { span: spanOverride };
|
if (spanOverride) return { span: spanOverride };
|
||||||
return {
|
return {
|
||||||
xs: {
|
xs: {
|
||||||
span: 24,
|
span: !grow ? 24 : Math.max(12, 24 / children.length),
|
||||||
},
|
},
|
||||||
sm: {
|
sm: {
|
||||||
span: !grow ? 12 : Math.max(12, 24 / children.length),
|
span: !grow ? 12 : Math.max(12, 24 / children.length),
|
||||||
@@ -38,7 +43,7 @@ export default function LayoutFormRow({ header, children, grow = false }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="imex-form-row">
|
<div className="imex-form-row" {...restProps}>
|
||||||
{header ? <Typography.Title level={4}>{header}</Typography.Title> : null}
|
{header ? <Typography.Title level={4}>{header}</Typography.Title> : null}
|
||||||
<Row {...rowGutter}>
|
<Row {...rowGutter}>
|
||||||
{children.map(
|
{children.map(
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { DeleteFilled } from "@ant-design/icons";
|
import { DeleteFilled } from "@ant-design/icons";
|
||||||
import { Form, Input, InputNumber, Radio } from "antd";
|
import { Form, Input, InputNumber, Radio, Typography } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
|
|
||||||
export default function PartsOrderModalComponent({
|
export default function PartsOrderModalComponent({
|
||||||
vendorList,
|
vendorList,
|
||||||
@@ -19,85 +20,84 @@ export default function PartsOrderModalComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Form.Item
|
<LayoutFormRow>
|
||||||
name="vendorid"
|
<Form.Item
|
||||||
label={t("vendors.fields.name")}
|
name="vendorid"
|
||||||
rules={[
|
label={t("vendors.fields.name")}
|
||||||
{
|
rules={[
|
||||||
required: true,
|
{
|
||||||
message: t("general.validation.required"),
|
required: true,
|
||||||
},
|
message: t("general.validation.required"),
|
||||||
]}
|
},
|
||||||
>
|
]}
|
||||||
<VendorSearchSelect
|
>
|
||||||
options={vendorList}
|
<VendorSearchSelect
|
||||||
disabled={isReturn}
|
options={vendorList}
|
||||||
preferredMake={preferredMake}
|
disabled={isReturn}
|
||||||
/>
|
preferredMake={preferredMake}
|
||||||
</Form.Item>
|
/>
|
||||||
<Form.Item
|
</Form.Item>
|
||||||
name="deliver_by"
|
<Form.Item
|
||||||
rules={[
|
name="deliver_by"
|
||||||
{
|
rules={[
|
||||||
required: true,
|
{
|
||||||
message: t("general.validation.required"),
|
required: true,
|
||||||
},
|
message: t("general.validation.required"),
|
||||||
]}
|
},
|
||||||
label={t("parts_orders.fields.deliver_by")}
|
]}
|
||||||
>
|
label={t("parts_orders.fields.deliver_by")}
|
||||||
<FormDatePicker />
|
>
|
||||||
</Form.Item>
|
<FormDatePicker />
|
||||||
{t("parts_orders.labels.inthisorder")}
|
</Form.Item>
|
||||||
|
</LayoutFormRow>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{t("parts_orders.labels.inthisorder")}
|
||||||
|
</Typography.Title>
|
||||||
<Form.List name={["parts_order_lines", "data"]}>
|
<Form.List name={["parts_order_lines", "data"]}>
|
||||||
{(fields, { add, remove, move }) => {
|
{(fields, { add, remove, move }) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => (
|
{fields.map((field, index) => (
|
||||||
<Form.Item required={false} key={field.key}>
|
<Form.Item required={false} key={field.key}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
<Form.Item
|
<LayoutFormRow grow style={{ flex: 1 }}>
|
||||||
label={t("parts_orders.fields.line_desc")}
|
<Form.Item
|
||||||
key={`${index}line_desc`}
|
label={t("parts_orders.fields.line_desc")}
|
||||||
name={[field.name, "line_desc"]}
|
key={`${index}line_desc`}
|
||||||
rules={[
|
name={[field.name, "line_desc"]}
|
||||||
{
|
rules={[
|
||||||
required: true,
|
{
|
||||||
message: t("general.validation.required"),
|
required: true,
|
||||||
},
|
message: t("general.validation.required"),
|
||||||
]}
|
},
|
||||||
>
|
]}
|
||||||
<Input />
|
>
|
||||||
</Form.Item>
|
<Input />
|
||||||
<Form.Item
|
</Form.Item>
|
||||||
label={t("parts_orders.fields.line_remarks")}
|
<Form.Item
|
||||||
key={`${index}line_remarks`}
|
label={t("parts_orders.fields.line_remarks")}
|
||||||
name={[field.name, "line_remarks"]}
|
key={`${index}line_remarks`}
|
||||||
>
|
name={[field.name, "line_remarks"]}
|
||||||
<Input />
|
>
|
||||||
</Form.Item>
|
<Input />
|
||||||
<Form.Item
|
</Form.Item>
|
||||||
label={t("parts_orders.fields.db_price")}
|
<Form.Item
|
||||||
key={`${index}db_price`}
|
label={t("parts_orders.fields.act_price")}
|
||||||
name={[field.name, "db_price"]}
|
key={`${index}act_price`}
|
||||||
>
|
name={[field.name, "act_price"]}
|
||||||
<CurrencyInput />
|
>
|
||||||
</Form.Item>
|
<CurrencyInput />
|
||||||
<Form.Item
|
</Form.Item>
|
||||||
label={t("parts_orders.fields.act_price")}
|
<Form.Item
|
||||||
key={`${index}act_price`}
|
label={t("parts_orders.fields.quantity")}
|
||||||
name={[field.name, "act_price"]}
|
key={`${index}quantity`}
|
||||||
>
|
name={[field.name, "quantity"]}
|
||||||
<CurrencyInput />
|
>
|
||||||
</Form.Item>
|
<InputNumber />
|
||||||
<Form.Item
|
</Form.Item>
|
||||||
label={t("parts_orders.fields.quantity")}
|
</LayoutFormRow>
|
||||||
key={`${index}quantity`}
|
|
||||||
name={[field.name, "quantity"]}
|
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
<DeleteFilled
|
<DeleteFilled
|
||||||
|
style={{ margin: "1rem" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -223,21 +223,24 @@ export function PartsOrderModalContainer({
|
|||||||
forceRender
|
forceRender
|
||||||
>
|
>
|
||||||
{error ? <AlertComponent message={error.message} type="error" /> : null}
|
{error ? <AlertComponent message={error.message} type="error" /> : null}
|
||||||
<LoadingSpinner loading={loading}>
|
<Form
|
||||||
<Form
|
form={form}
|
||||||
form={form}
|
layout="vertical"
|
||||||
autoComplete="no"
|
autoComplete="no"
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
>
|
>
|
||||||
|
{loading ? (
|
||||||
|
<LoadingSpinner />
|
||||||
|
) : (
|
||||||
<PartsOrderModalComponent
|
<PartsOrderModalComponent
|
||||||
vendorList={(data && data.vendors) || []}
|
vendorList={(data && data.vendors) || []}
|
||||||
sendTypeState={sendTypeState}
|
sendTypeState={sendTypeState}
|
||||||
isReturn={isReturn}
|
isReturn={isReturn}
|
||||||
preferredMake={data && data.jobs[0] && data.jobs[0].v_make_desc}
|
preferredMake={data && data.jobs[0] && data.jobs[0].v_make_desc}
|
||||||
/>
|
/>
|
||||||
</Form>
|
)}
|
||||||
</LoadingSpinner>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function ScheduleJobModalContainer({
|
|||||||
const [updateJobStatus] = useMutation(UPDATE_JOBS);
|
const [updateJobStatus] = useMutation(UPDATE_JOBS);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.resetFields();
|
if (job) form.resetFields();
|
||||||
}, [job, form]);
|
}, [job, form]);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Select, Tag } from "antd";
|
import { Col, Row, Select, Tag } from "antd";
|
||||||
import React, { useEffect, useState, forwardRef } from "react";
|
import React, { useEffect, useState, forwardRef } from "react";
|
||||||
import { HeartOutlined } from "@ant-design/icons";
|
import { HeartOutlined } from "@ant-design/icons";
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
@@ -30,7 +30,7 @@ const VendorSearchSelect = (
|
|||||||
showSearch
|
showSearch
|
||||||
value={option}
|
value={option}
|
||||||
style={{
|
style={{
|
||||||
width: 300,
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
onChange={setOption}
|
onChange={setOption}
|
||||||
optionFilterProp="name"
|
optionFilterProp="name"
|
||||||
@@ -45,21 +45,27 @@ const VendorSearchSelect = (
|
|||||||
name={o.name}
|
name={o.name}
|
||||||
discount={o.discount}
|
discount={o.discount}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex" }}>
|
<Row>
|
||||||
{o.name}
|
<Col span={16}>{o.name}</Col>
|
||||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
<Col span={4}>
|
||||||
<HeartOutlined />
|
<HeartOutlined />
|
||||||
</div>
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Option>
|
</Option>
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
{options
|
{options
|
||||||
? options.map((o) => (
|
? options.map((o) => (
|
||||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||||
<div style={{ display: "flex" }}>
|
<Row>
|
||||||
{o.name}
|
<Col span={20}>{o.name}</Col>
|
||||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
<Col span={4}>
|
||||||
</div>
|
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Option>
|
</Option>
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
|
|||||||
@@ -652,6 +652,7 @@
|
|||||||
"validation": "Please ensure all fields are entered correctly. "
|
"validation": "Please ensure all fields are entered correctly. "
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"allpartslocation": "Parts Bin",
|
||||||
"date": "Invoice Date",
|
"date": "Invoice Date",
|
||||||
"federal_tax_rate": "Federal Tax Rate",
|
"federal_tax_rate": "Federal Tax Rate",
|
||||||
"invoice_number": "Invoice Number",
|
"invoice_number": "Invoice Number",
|
||||||
@@ -669,6 +670,7 @@
|
|||||||
"entered_total": "Total of Entered Lines",
|
"entered_total": "Total of Entered Lines",
|
||||||
"enteringcreditmemo": "You are entering a credit memo. Please ensure you are also entering positive values.",
|
"enteringcreditmemo": "You are entering a credit memo. Please ensure you are also entering positive values.",
|
||||||
"federal_tax": "Federal Tax",
|
"federal_tax": "Federal Tax",
|
||||||
|
"invoice_lines": "Invoice Lines",
|
||||||
"invoice_total": "Invoice Total Amount",
|
"invoice_total": "Invoice Total Amount",
|
||||||
"invoices": "Invoices",
|
"invoices": "Invoices",
|
||||||
"local_tax": "Local Tax",
|
"local_tax": "Local Tax",
|
||||||
|
|||||||
@@ -652,6 +652,7 @@
|
|||||||
"validation": ""
|
"validation": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"allpartslocation": "",
|
||||||
"date": "",
|
"date": "",
|
||||||
"federal_tax_rate": "",
|
"federal_tax_rate": "",
|
||||||
"invoice_number": "",
|
"invoice_number": "",
|
||||||
@@ -669,6 +670,7 @@
|
|||||||
"entered_total": "",
|
"entered_total": "",
|
||||||
"enteringcreditmemo": "",
|
"enteringcreditmemo": "",
|
||||||
"federal_tax": "",
|
"federal_tax": "",
|
||||||
|
"invoice_lines": "",
|
||||||
"invoice_total": "",
|
"invoice_total": "",
|
||||||
"invoices": "",
|
"invoices": "",
|
||||||
"local_tax": "",
|
"local_tax": "",
|
||||||
|
|||||||
@@ -652,6 +652,7 @@
|
|||||||
"validation": ""
|
"validation": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"allpartslocation": "",
|
||||||
"date": "",
|
"date": "",
|
||||||
"federal_tax_rate": "",
|
"federal_tax_rate": "",
|
||||||
"invoice_number": "",
|
"invoice_number": "",
|
||||||
@@ -669,6 +670,7 @@
|
|||||||
"entered_total": "",
|
"entered_total": "",
|
||||||
"enteringcreditmemo": "",
|
"enteringcreditmemo": "",
|
||||||
"federal_tax": "",
|
"federal_tax": "",
|
||||||
|
"invoice_lines": "",
|
||||||
"invoice_total": "",
|
"invoice_total": "",
|
||||||
"invoices": "",
|
"invoices": "",
|
||||||
"local_tax": "",
|
"local_tax": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user