diff --git a/client/src/components/invoices-by-vendor-list/invoices-by-vendor-list.component.jsx b/client/src/components/invoices-by-vendor-list/invoices-by-vendor-list.component.jsx
index d0f70cea9..953a655c8 100644
--- a/client/src/components/invoices-by-vendor-list/invoices-by-vendor-list.component.jsx
+++ b/client/src/components/invoices-by-vendor-list/invoices-by-vendor-list.component.jsx
@@ -1,159 +1,161 @@
-import React, { useState } from "react";
-import { QUERY_INVOICES_BY_VENDOR_PAGINATED } from "../../graphql/invoices.queries";
-import { useQuery } from "@apollo/react-hooks";
-import queryString from "query-string";
-import { useHistory, useLocation } from "react-router-dom";
-import { Table, Input } from "antd";
-import { useTranslation } from "react-i18next";
-import { alphaSort } from "../../utils/sorters";
-import AlertComponent from "../alert/alert.component";
-import { DateFormatter } from "../../utils/DateFormatter";
-import CurrencyFormatter from "../../utils/CurrencyFormatter";
+//DEPRECATED.
-export default function InvoicesByVendorList() {
- const search = queryString.parse(useLocation().search);
- const history = useHistory();
- const { page, sortcolumn, sortorder } = search;
+// import React, { useState } from "react";
+// import { QUERY_INVOICES_BY_VENDOR_PAGINATED } from "../../graphql/invoices.queries";
+// import { useQuery } from "@apollo/react-hooks";
+// import queryString from "query-string";
+// import { useHistory, useLocation } from "react-router-dom";
+// import { Table, Input } from "antd";
+// import { useTranslation } from "react-i18next";
+// import { alphaSort } from "../../utils/sorters";
+// import AlertComponent from "../alert/alert.component";
+// import { DateFormatter } from "../../utils/DateFormatter";
+// import CurrencyFormatter from "../../utils/CurrencyFormatter";
- const { loading, error, data } = useQuery(
- QUERY_INVOICES_BY_VENDOR_PAGINATED,
- {
- variables: {
- vendorId: search.vendorid,
- offset: page ? (page - 1) * 25 : 0,
- limit: 25,
- order: [
- {
- [sortcolumn || "date"]: sortorder
- ? sortorder === "descend"
- ? "desc"
- : "asc"
- : "desc",
- },
- ],
- },
- skip: !!!search.vendorid,
- }
- );
+// export default function InvoicesByVendorList() {
+// const search = queryString.parse(useLocation().search);
+// const history = useHistory();
+// const { page, sortcolumn, sortorder } = search;
- const { t } = useTranslation();
+// const { loading, error, data } = useQuery(
+// QUERY_INVOICES_BY_VENDOR_PAGINATED,
+// {
+// variables: {
+// vendorId: search.vendorid,
+// offset: page ? (page - 1) * 25 : 0,
+// limit: 25,
+// order: [
+// {
+// [sortcolumn || "date"]: sortorder
+// ? sortorder === "descend"
+// ? "desc"
+// : "asc"
+// : "desc",
+// },
+// ],
+// },
+// skip: !!!search.vendorid,
+// }
+// );
- const [state, setState] = useState({
- sortedInfo: {},
- search: "",
- });
+// const { t } = useTranslation();
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- search.page = pagination.current;
- search.sortcolumn = sorter.columnKey;
- search.sortorder = sorter.order;
- history.push({ search: queryString.stringify(search) });
- };
+// const [state, setState] = useState({
+// sortedInfo: {},
+// search: "",
+// });
- const handleOnRowClick = (record) => {
- if (record) {
- if (record.id) {
- search.invoiceid = record.id;
- history.push({ search: queryString.stringify(search) });
- }
- } else {
- delete search.invoiceid;
- history.push({ search: queryString.stringify(search) });
- }
- };
+// const handleTableChange = (pagination, filters, sorter) => {
+// setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
+// search.page = pagination.current;
+// search.sortcolumn = sorter.columnKey;
+// search.sortorder = sorter.order;
+// history.push({ search: queryString.stringify(search) });
+// };
- const columns = [
- {
- title: t("invoices.fields.invoice_number"),
- dataIndex: "invoice_number",
- key: "invoice_number",
- sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
- sortOrder:
- state.sortedInfo.columnKey === "invoice_number" &&
- state.sortedInfo.order,
- },
- {
- title: t("invoices.fields.date"),
- dataIndex: "date",
- key: "date",
+// const handleOnRowClick = (record) => {
+// if (record) {
+// if (record.id) {
+// search.invoiceid = record.id;
+// history.push({ search: queryString.stringify(search) });
+// }
+// } else {
+// delete search.invoiceid;
+// history.push({ search: queryString.stringify(search) });
+// }
+// };
- sorter: (a, b) => a.date - b.date,
- sortOrder:
- state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
- render: (text, record) => {record.date},
- },
- {
- title: t("invoices.fields.total"),
- dataIndex: "total",
- key: "total",
+// const columns = [
+// {
+// title: t("invoices.fields.invoice_number"),
+// dataIndex: "invoice_number",
+// key: "invoice_number",
+// sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
+// sortOrder:
+// state.sortedInfo.columnKey === "invoice_number" &&
+// state.sortedInfo.order,
+// },
+// {
+// title: t("invoices.fields.date"),
+// dataIndex: "date",
+// key: "date",
- sorter: (a, b) => a.total - b.total,
- sortOrder:
- state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
- render: (text, record) => (
- {record.total}
- ),
- },
- ];
+// sorter: (a, b) => a.date - b.date,
+// sortOrder:
+// state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
+// render: (text, record) => {record.date},
+// },
+// {
+// title: t("invoices.fields.total"),
+// dataIndex: "total",
+// key: "total",
- const handleSearch = (e) => {
- setState({ ...state, search: e.target.value });
- };
+// sorter: (a, b) => a.total - b.total,
+// sortOrder:
+// state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+// render: (text, record) => (
+// {record.total}
+// ),
+// },
+// ];
- const dataSource = state.search
- ? data.invoices.filter(
- (i) =>
- (i.invoice_number || "")
- .toLowerCase()
- .includes(state.search.toLowerCase()) ||
- (i.amount || "").toString().includes(state.search)
- )
- : (data && data.invoices) || [];
+// const handleSearch = (e) => {
+// setState({ ...state, search: e.target.value });
+// };
- if (error) return ;
+// const dataSource = state.search
+// ? data.invoices.filter(
+// (i) =>
+// (i.invoice_number || "")
+// .toLowerCase()
+// .includes(state.search.toLowerCase()) ||
+// (i.amount || "").toString().includes(state.search)
+// )
+// : (data && data.invoices) || [];
- return (
-
{
- return (
-
-
-
- );
- }}
- dataSource={dataSource}
- size='small'
- scroll={{ x: true }}
- pagination={{
- position: "top",
- pageSize: 25,
- current: parseInt(page || 1),
- total: data ? data.invoices_aggregate.aggregate.count : 0,
- }}
- columns={columns}
- rowKey='id'
- onChange={handleTableChange}
- rowSelection={{
- onSelect: (record) => {
- handleOnRowClick(record);
- },
- selectedRowKeys: [search.invoiceid],
- type: "radio",
- }}
- onRow={(record, rowIndex) => {
- return {
- onClick: (event) => {
- handleOnRowClick(record);
- }, // click row
- };
- }}
- />
- );
-}
+// if (error) return ;
+
+// return (
+// {
+// return (
+//
+//
+//
+// );
+// }}
+// dataSource={dataSource}
+// size='small'
+// scroll={{ x: true }}
+// pagination={{
+// position: "top",
+// pageSize: 25,
+// current: parseInt(page || 1),
+// total: data ? data.invoices_aggregate.aggregate.count : 0,
+// }}
+// columns={columns}
+// rowKey='id'
+// onChange={handleTableChange}
+// rowSelection={{
+// onSelect: (record) => {
+// handleOnRowClick(record);
+// },
+// selectedRowKeys: [search.invoiceid],
+// type: "radio",
+// }}
+// onRow={(record, rowIndex) => {
+// return {
+// onClick: (event) => {
+// handleOnRowClick(record);
+// }, // click row
+// };
+// }}
+// />
+// );
+// }
diff --git a/client/src/components/invoices-list-table/invoices-list-table.component.jsx b/client/src/components/invoices-list-table/invoices-list-table.component.jsx
index aa1c1ef61..6a350520f 100644
--- a/client/src/components/invoices-list-table/invoices-list-table.component.jsx
+++ b/client/src/components/invoices-list-table/invoices-list-table.component.jsx
@@ -94,7 +94,8 @@ export function InvoicesListTableComponent({
render: (text, record) => (
+ to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}
+ >
@@ -243,11 +245,11 @@ export function InvoicesListTableComponent({
@@ -261,37 +263,45 @@ export function InvoicesListTableComponent({
(
-
+
-
-
{" "}
-
+ {job ? (
+
+
+
+
+ ) : null}
+
+
{
@@ -305,7 +315,7 @@ export function InvoicesListTableComponent({
expandedRowRender={rowExpander}
pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns}
- rowKey='id'
+ rowKey="id"
dataSource={invoices}
onChange={handleTableChange}
expandable={{
diff --git a/client/src/graphql/invoices.queries.js b/client/src/graphql/invoices.queries.js
index d2a765c3d..9c98f5820 100644
--- a/client/src/graphql/invoices.queries.js
+++ b/client/src/graphql/invoices.queries.js
@@ -11,13 +11,27 @@ export const INSERT_NEW_INVOICE = gql`
`;
export const QUERY_ALL_INVOICES_PAGINATED = gql`
- query QUERY_ALL_INVOICES_PAGINATED($offset: Int, $limit: Int) {
- invoices(offset: $offset, limit: $limit, order_by: { date: desc }) {
+ query QUERY_ALL_INVOICES_PAGINATED(
+ $search: String
+ $offset: Int
+ $limit: Int
+ $order: [invoices_order_by!]!
+ ) {
+ search_invoices(
+ args: { search: $search }
+ offset: $offset
+ limit: $limit
+ order_by: $order
+ ) {
id
vendor {
id
name
}
+ federal_tax_rate
+ local_tax_rate
+ state_tax_rate
+ is_credit_memo
total
invoice_number
date
@@ -34,6 +48,11 @@ export const QUERY_ALL_INVOICES_PAGINATED = gql`
line_desc
}
}
+ search_invoices_aggregate(args: { search: $search }) {
+ aggregate {
+ count(distinct: true)
+ }
+ }
}
`;
diff --git a/client/src/pages/invoices/invoices.page.component.jsx b/client/src/pages/invoices/invoices.page.component.jsx
new file mode 100644
index 000000000..6c979ee71
--- /dev/null
+++ b/client/src/pages/invoices/invoices.page.component.jsx
@@ -0,0 +1,195 @@
+import { SyncOutlined } from "@ant-design/icons";
+import { Button, Checkbox, Input, Table, Typography } from "antd";
+import queryString from "query-string";
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
+import { Link, useHistory, useLocation } from "react-router-dom";
+import { setModalContext } from "../../redux/modals/modals.actions";
+import CurrencyFormatter from "../../utils/CurrencyFormatter";
+import { DateFormatter } from "../../utils/DateFormatter";
+import { alphaSort } from "../../utils/sorters";
+
+const mapDispatchToProps = (dispatch) => ({
+ setPartsOrderContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "partsOrder" })),
+ setInvoiceEnterContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
+});
+
+export function InvoicesListPage({
+ loading,
+ data,
+ refetch,
+ total,
+ setPartsOrderContext,
+ setInvoiceEnterContext,
+}) {
+ const { t } = useTranslation();
+ const [state, setState] = useState({
+ sortedInfo: {},
+ });
+ const history = useHistory();
+ const search = queryString.parse(useLocation().search);
+ const { page } = search;
+
+ const selectedInvoice = search.invoiceid;
+ const columns = [
+ {
+ title: t("invoices.fields.vendorname"),
+ dataIndex: "vendorname",
+ key: "vendorname",
+ // sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
+ // sortOrder:
+ // state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
+ render: (text, record) => {record.vendor.name},
+ },
+ {
+ title: t("invoices.fields.invoice_number"),
+ dataIndex: "invoice_number",
+ key: "invoice_number",
+ sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
+ sortOrder:
+ state.sortedInfo.columnKey === "invoice_number" &&
+ state.sortedInfo.order,
+ },
+ {
+ title: t("invoices.fields.date"),
+ dataIndex: "date",
+ key: "date",
+ sorter: (a, b) => a.date - b.date,
+ sortOrder:
+ state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
+ render: (text, record) => {record.date},
+ },
+ {
+ title: t("invoices.fields.total"),
+ dataIndex: "total",
+ key: "total",
+ sorter: (a, b) => a.total - b.total,
+ sortOrder:
+ state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+ render: (text, record) => (
+ {record.total}
+ ),
+ },
+ {
+ title: t("invoices.fields.is_credit_memo"),
+ dataIndex: "is_credit_memo",
+ key: "is_credit_memo",
+ sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
+ sortOrder:
+ state.sortedInfo.columnKey === "is_credit_memo" &&
+ state.sortedInfo.order,
+ render: (text, record) => ,
+ },
+ {
+ title: t("general.labels.actions"),
+ dataIndex: "actions",
+ key: "actions",
+ render: (text, record) => (
+
+
+
+
+
+
+ ),
+ },
+ ];
+
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
+ search.page = pagination.current;
+ search.sortcolumn = sorter.columnKey;
+ search.sortorder = sorter.order;
+ history.push({ search: queryString.stringify(search) });
+ };
+
+ const handleOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ search.invoiceid = record.id;
+ history.push({ search: queryString.stringify(search) });
+ }
+ } else {
+ delete search.invoiceid;
+ history.push({ search: queryString.stringify(search) });
+ }
+ };
+
+ return (
+
+
+ {t("invoices.labels.invoices")}
+
+
(
+
+
+
+
+ {
+ search.search = value;
+ history.push({ search: queryString.stringify(search) });
+ }}
+ />
+
+
+ )}
+ scroll={{ x: "50%", y: "40rem" }}
+ pagination={{
+ position: "top",
+ pageSize: 25,
+ current: parseInt(page || 1),
+ total: total,
+ }}
+ columns={columns}
+ rowKey="id"
+ dataSource={data}
+ onChange={handleTableChange}
+ />
+
+ );
+}
+export default connect(null, mapDispatchToProps)(InvoicesListPage);
diff --git a/client/src/pages/invoices/invoices.page.container.jsx b/client/src/pages/invoices/invoices.page.container.jsx
index e42355029..791ac8d20 100644
--- a/client/src/pages/invoices/invoices.page.container.jsx
+++ b/client/src/pages/invoices/invoices.page.container.jsx
@@ -1,11 +1,13 @@
-import { Col, Row } from "antd";
+import queryString from "query-string";
import React, { useEffect } from "react";
+import { useQuery } from "react-apollo";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
+import { useLocation } from "react-router-dom";
import InvoiceDetailEditContainer from "../../components/invoice-detail-edit/invoice-detail-edit.container";
-import InvoicesByVendorList from "../../components/invoices-by-vendor-list/invoices-by-vendor-list.component";
-import VendorsList from "../../components/invoices-vendors-list/invoices-vendors-list.component";
+import { QUERY_ALL_INVOICES_PAGINATED } from "../../graphql/invoices.queries";
import { setBreadcrumbs } from "../../redux/application/application.actions";
+import InvoicesPageComponent from "./invoices.page.component";
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -13,6 +15,9 @@ const mapDispatchToProps = (dispatch) => ({
export function InvoicesPageContainer({ setBreadcrumbs }) {
const { t } = useTranslation();
+ const searchParams = queryString.parse(useLocation().search);
+ const { page, sortcolumn, sortorder, search } = searchParams;
+
useEffect(() => {
document.title = t("titles.invoices-list");
setBreadcrumbs([
@@ -20,20 +25,37 @@ export function InvoicesPageContainer({ setBreadcrumbs }) {
]);
}, [t, setBreadcrumbs]);
+ const { loading, error, data, refetch } = useQuery(
+ QUERY_ALL_INVOICES_PAGINATED,
+ {
+ variables: {
+ search: search || "",
+ offset: page ? (page - 1) * 25 : 0,
+ limit: 25,
+ order: [
+ {
+ [sortcolumn || "date"]: sortorder
+ ? sortorder === "descend"
+ ? "desc"
+ : "asc"
+ : "desc",
+ },
+ ],
+ },
+ }
+ );
+
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
);
}
export default connect(null, mapDispatchToProps)(InvoicesPageContainer);
diff --git a/hasura/migrations/1595971170482_run_sql_migration/down.yaml b/hasura/migrations/1595971170482_run_sql_migration/down.yaml
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/hasura/migrations/1595971170482_run_sql_migration/down.yaml
@@ -0,0 +1 @@
+[]
diff --git a/hasura/migrations/1595971170482_run_sql_migration/up.yaml b/hasura/migrations/1595971170482_run_sql_migration/up.yaml
new file mode 100644
index 000000000..12d51c766
--- /dev/null
+++ b/hasura/migrations/1595971170482_run_sql_migration/up.yaml
@@ -0,0 +1,6 @@
+- args:
+ cascade: true
+ read_only: false
+ sql: CREATE INDEX idx_invoices_invoicenumber ON invoices USING GIN (invoice_number
+ gin_trgm_ops);
+ type: run_sql
diff --git a/hasura/migrations/1595971216422_run_sql_migration/down.yaml b/hasura/migrations/1595971216422_run_sql_migration/down.yaml
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/hasura/migrations/1595971216422_run_sql_migration/down.yaml
@@ -0,0 +1 @@
+[]
diff --git a/hasura/migrations/1595971216422_run_sql_migration/up.yaml b/hasura/migrations/1595971216422_run_sql_migration/up.yaml
new file mode 100644
index 000000000..5e9aff249
--- /dev/null
+++ b/hasura/migrations/1595971216422_run_sql_migration/up.yaml
@@ -0,0 +1,12 @@
+- args:
+ cascade: true
+ read_only: false
+ sql: "CREATE OR REPLACE FUNCTION public.search_invoices(search text)\n RETURNS
+ SETOF invoices\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search
+ = '' then\n return query select * from invoices ;\n else \n return query
+ SELECT\n *\nFROM\n payments\nWHERE\n search <% (invoice_number);\n end if;\n\n\tEND\n$function$;"
+ type: run_sql
+- args:
+ name: search_invoices
+ schema: public
+ type: track_function
diff --git a/hasura/migrations/1595973678869_run_sql_migration/down.yaml b/hasura/migrations/1595973678869_run_sql_migration/down.yaml
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/hasura/migrations/1595973678869_run_sql_migration/down.yaml
@@ -0,0 +1 @@
+[]
diff --git a/hasura/migrations/1595973678869_run_sql_migration/up.yaml b/hasura/migrations/1595973678869_run_sql_migration/up.yaml
new file mode 100644
index 000000000..410506db0
--- /dev/null
+++ b/hasura/migrations/1595973678869_run_sql_migration/up.yaml
@@ -0,0 +1,8 @@
+- args:
+ cascade: true
+ read_only: false
+ sql: "CREATE OR REPLACE FUNCTION public.search_invoices(search text)\n RETURNS
+ SETOF invoices\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search
+ = '' then\n return query select * from invoices ;\n else \n return query
+ SELECT\n *\nFROM\n invoices\nWHERE\n search <% (invoice_number);\n end if;\n\n\tEND\n$function$;"
+ type: run_sql
diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml
index ec3eb9d2c..0c32e1e3c 100644
--- a/hasura/migrations/metadata.yaml
+++ b/hasura/migrations/metadata.yaml
@@ -4053,6 +4053,9 @@ tables:
- active:
_eq: true
functions:
+- function:
+ schema: public
+ name: search_invoices
- function:
schema: public
name: search_jobs