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