diff --git a/client/src/components/invoice-detail-edit/invoice-detail-edit.component.jsx b/client/src/components/invoice-detail-edit/invoice-detail-edit.component.jsx
deleted file mode 100644
index 2f4d49c73..000000000
--- a/client/src/components/invoice-detail-edit/invoice-detail-edit.component.jsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import { DatePicker, Form, Input, Switch, Tag } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import DocumentsUploadContainer from "../documents-upload/documents-upload.container";
-import CurrencyInput from "../form-items-formatted/currency-form-item.component";
-import InvoiceEnterModalLinesComponent from "../invoice-enter-modal/invoice-enter-modal.lines.component";
-import JobSearchSelect from "../job-search-select/job-search-select.component";
-
-export default function InvoiceDetailEditComponent({
- form,
- roAutoCompleteOptions,
- loadLines,
- lineData,
- responsibilityCenters,
-}) {
- const { t } = useTranslation();
- const [amounts, setAmounts] = useState({ invoiceTotal: 0, enteredAmount: 0 });
- const { getFieldsValue } = form;
-
- const calculateTotals = () => {
- setAmounts({
- invoiceTotal: getFieldsValue().total || 0,
- enteredTotal: getFieldsValue("invoicelines").invoicelines
- ? getFieldsValue("invoicelines").invoicelines.reduce(
- (acc, value) =>
- acc + (value && value.actual_cost ? value.actual_cost : 0),
- 0
- )
- : 0,
- });
- };
-
- return (
-
-
-
- {
- if (form.getFieldValue("jobid") !== null) {
- //loadLines({ variables: { id: form.getFieldValue("jobid") } });
- }
- }}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {t("invoicelines.labels.entered")}
-
{amounts.enteredTotal || 0}
-
- {amounts.invoiceTotal - amounts.enteredTotal === 0 ? (
-
{t("invoicelines.labels.reconciled")}
- ) : (
-
- {t("invoicelines.labels.unreconciled")}:
-
- {amounts.invoiceTotal - amounts.enteredTotal}
-
-
- )}
-
-
- );
-}
diff --git a/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx b/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx
index 017e7fdfb..1799e23fc 100644
--- a/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx
+++ b/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx
@@ -8,12 +8,10 @@ import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { QUERY_INVOICE_BY_PK } from "../../graphql/invoices.queries";
-import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
-import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
+import InvoiceFormContainer from "../invoice-form/invoice-form.container";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
-import InvoiceDetailEditComponent from "./invoice-detail-edit.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -29,35 +27,19 @@ export function InvoiceDetailEditContainer({ bodyshop }) {
skip: !!!search.invoiceid,
});
- const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
- fetchPolicy: "network-only",
- variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
- });
-
- const {
- loading: linesLoading,
- data: lineData,
- refetch: loadLines,
- } = useQuery(GET_JOB_LINES_TO_ENTER_INVOICE, {
- variables: { id: data && data.invoices_by_pk.jobid },
- fetchPolicy: "network-only",
- skip: !!!(data && data.invoices_by_pk.id),
- });
-
const handleFinish = (values) => {
console.log("values", values);
};
useEffect(() => {
- // if (data) {
- // loadLines();
- // if (lineData) //form.resetFields();
- // }
- }, [data, lineData]);
+ if (search.invoiceid) {
+ form.resetFields();
+ }
+ }, [form, search.invoiceid]);
if (error) return ;
return (
-
+
);
diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx b/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx
index 79b3fe0a3..bb8b7ab8c 100644
--- a/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx
+++ b/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx
@@ -1,61 +1,27 @@
-import { useLazyQuery, useMutation, useQuery } from "@apollo/react-hooks";
-import { Form, Modal, notification, Button } from "antd";
-import React, { useState, useEffect } from "react";
+import { useMutation } from "@apollo/react-hooks";
+import { Button, Form, Modal, notification } from "antd";
+import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_NEW_INVOICE } from "../../graphql/invoices.queries";
-import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
-import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
-import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectInvoiceEnterModal } from "../../redux/modals/modals.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import InvoiceEnterModalComponent from "./invoice-enter-modal.component";
-import { setModalContext } from "../../redux/modals/modals.actions";
+import InvoiceFormContainer from "../invoice-form/invoice-form.container";
const mapStateToProps = createStructuredSelector({
invoiceEnterModal: selectInvoiceEnterModal,
- bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("invoiceEnter")),
- setInvoiceEnterContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
});
-function InvoiceEnterModalContainer({
- invoiceEnterModal,
- toggleModalVisible,
- bodyshop,
- setInvoiceEnterContext,
-}) {
+function InvoiceEnterModalContainer({ invoiceEnterModal, toggleModalVisible }) {
const [form] = Form.useForm();
const { t } = useTranslation();
const [enterAgain, setEnterAgain] = useState(false);
const [insertInvoice] = useMutation(INSERT_NEW_INVOICE);
- const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
- fetchPolicy: "network-only",
- variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
- skip: !invoiceEnterModal.visible,
- });
-
- const { data: VendorAutoCompleteData } = useQuery(
- SEARCH_VENDOR_AUTOCOMPLETE,
- {
- fetchPolicy: "network-only",
- skip: !invoiceEnterModal.visible,
- }
- );
-
- const [loadLines, { data: lineData }] = useLazyQuery(
- GET_JOB_LINES_TO_ENTER_INVOICE,
- {
- fetchPolicy: "network-only",
- }
- );
-
const handleFinish = (values) => {
insertInvoice({
variables: {
@@ -107,11 +73,7 @@ function InvoiceEnterModalContainer({
return (
-
+
);
diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx b/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx
deleted file mode 100644
index 7fc1de42c..000000000
--- a/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import { DeleteFilled } from "@ant-design/icons";
-import { Button, Form, Input, Select } 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";
-
-export default function InvoiceEnterModalLinesComponent({
- lineData,
- discount,
- form,
- responsibilityCenters,
- calculateTotals,
-}) {
- const { t } = useTranslation();
- const { setFieldsValue, getFieldsValue } = form;
- console.log("calculateTotals", calculateTotals);
- return (
-
-
- {(fields, { add, remove }) => {
- console.log("fields", fields);
- return (
-
- {fields.map((field, index) => (
-
-
-
- {
- setFieldsValue({
- invoicelines: getFieldsValue([
- "invoicelines",
- ]).invoicelines.map((item, idx) => {
- if (idx === index) {
- return {
- ...item,
- line_desc: opt.line_desc,
- actual_price: opt.cost,
- cost_center: opt.part_type
- ? responsibilityCenters.defaults[
- opt.part_type
- ] || null
- : null,
- };
- }
- return item;
- }),
- });
- }}
- />
-
-
-
-
-
-
-
- {
- 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;
- }),
- });
- }}
- />
-
-
- {
- calculateTotals();
- }}
- />
-
-
-
-
- {
- remove(field.name);
- calculateTotals();
- }}
- />
-
-
- ))}
-
-
-
-
- );
- }}
-
-
- );
-}
diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx b/client/src/components/invoice-form/invoice-form.component.jsx
similarity index 71%
rename from client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx
rename to client/src/components/invoice-form/invoice-form.component.jsx
index d848ac8c8..76b171f41 100644
--- a/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx
+++ b/client/src/components/invoice-form/invoice-form.component.jsx
@@ -1,38 +1,25 @@
-import { DatePicker, Form, Input, Switch, Tag } from "antd";
+import { DatePicker, Form, Input, Switch } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import DocumentsUploadContainer from "../documents-upload/documents-upload.container";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
-import InvoiceEnterModalLinesComponent from "./invoice-enter-modal.lines.component";
-import CurrencyFormatter from "../../utils/CurrencyFormatter";
+import InvoiceFormLines from "./invoice-form.lines.component";
-export default function InvoiceEnterModalComponent({
+export default function InvoiceFormComponent({
form,
roAutoCompleteOptions,
vendorAutoCompleteOptions,
lineData,
responsibilityCenters,
loadLines,
+ hideVendor,
}) {
const { t } = useTranslation();
const [discount, setDiscount] = useState(0);
- const [amounts, setAmounts] = useState({ invoiceTotal: 0, enteredAmount: 0 });
- const { getFieldsValue } = form;
- const calculateTotals = () => {
- setAmounts({
- invoiceTotal: getFieldsValue().total || 0,
- enteredTotal: getFieldsValue("invoicelines").invoicelines
- ? getFieldsValue("invoicelines").invoicelines.reduce(
- (acc, value) =>
- acc + (value && value.actual_cost ? value.actual_cost : 0),
- 0
- )
- : 0,
- });
- };
+
const handleVendorSelect = (props, opt) => {
setDiscount(opt.discount);
};
@@ -62,6 +49,7 @@ export default function InvoiceEnterModalComponent({
-
@@ -137,22 +124,8 @@ export default function InvoiceEnterModalComponent({
console.log(form.getFieldsValue());
}}
>
- a
+ Get Field Values
-
- {t("invoicelines.labels.entered")}
- {amounts.enteredTotal || 0}
-
- {amounts.invoiceTotal - amounts.enteredTotal === 0 ? (
- {t("invoicelines.labels.reconciled")}
- ) : (
-
- {t("invoicelines.labels.unreconciled")}:
-
- {amounts.invoiceTotal - amounts.enteredTotal}
-
-
- )}
);
}
diff --git a/client/src/components/invoice-form/invoice-form.container.jsx b/client/src/components/invoice-form/invoice-form.container.jsx
new file mode 100644
index 000000000..8ef37f518
--- /dev/null
+++ b/client/src/components/invoice-form/invoice-form.container.jsx
@@ -0,0 +1,40 @@
+import { useLazyQuery, useQuery } from "@apollo/react-hooks";
+import React from "react";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
+import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
+import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import InvoiceFormComponent from "./invoice-form.component";
+
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+});
+
+export function InvoiceFormContainer({ bodyshop, form, hideVendor }) {
+ const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
+ variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
+ });
+
+ const { data: VendorAutoCompleteData } = useQuery(SEARCH_VENDOR_AUTOCOMPLETE);
+
+ const [loadLines, { data: lineData }] = useLazyQuery(
+ GET_JOB_LINES_TO_ENTER_INVOICE
+ );
+
+ return (
+
+ );
+}
+export default connect(mapStateToProps, null)(InvoiceFormContainer);
diff --git a/client/src/components/invoice-form/invoice-form.lines.component.jsx b/client/src/components/invoice-form/invoice-form.lines.component.jsx
new file mode 100644
index 000000000..4a1948d75
--- /dev/null
+++ b/client/src/components/invoice-form/invoice-form.lines.component.jsx
@@ -0,0 +1,162 @@
+import { DeleteFilled } from "@ant-design/icons";
+import { Button, Form, Input, Select } 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";
+
+export default function InvoiceEnterModalLinesComponent({
+ lineData,
+ discount,
+ form,
+ responsibilityCenters,
+}) {
+ const { t } = useTranslation();
+ const { setFieldsValue, getFieldsValue } = form;
+
+ return (
+
+ {(fields, { add, remove }) => {
+ return (
+
+ {fields.map((field, index) => (
+
+
+
+ {
+ setFieldsValue({
+ invoicelines: getFieldsValue([
+ "invoicelines",
+ ]).invoicelines.map((item, idx) => {
+ if (idx === index) {
+ return {
+ ...item,
+ line_desc: opt.line_desc,
+ actual_price: opt.cost,
+ cost_center: opt.part_type
+ ? responsibilityCenters.defaults[
+ opt.part_type
+ ] || null
+ : null,
+ };
+ }
+ return item;
+ }),
+ });
+ }}
+ />
+
+
+
+
+
+
+
+ {
+ 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;
+ }),
+ });
+ }}
+ />
+
+
+
+
+
+
+
+ {
+ remove(field.name);
+ }}
+ />
+
+
+ ))}
+
+
+
+
+ );
+ }}
+
+ );
+}
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
index 63775e055..f6800aa52 100644
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
+++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
@@ -9,41 +9,49 @@ import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
-
+import { setModalContext } from "../../redux/modals/modals.actions";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
+ setInvoiceEnterContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
});
-export function JobsDetailHeaderActions({ job, bodyshop, refetch }) {
+export function JobsDetailHeaderActions({
+ job,
+ bodyshop,
+ refetch,
+ setInvoiceEnterContext,
+}) {
const { t } = useTranslation();
const client = useApolloClient();
const history = useHistory();
const statusmenu = (
-