From 759a8ac58c83d2c3598cce8f9e8915a28fb1e610 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 3 May 2023 16:29:01 -0700 Subject: [PATCH] IO-2261 Opensearch for Payments, Bills and All Jobs --- .../jobs-list-paginated.component.jsx | 6 +- .../payment-list-paginated.component.jsx | 72 ++++++++++++++----- client/src/graphql/bills.queries.js | 6 +- client/src/graphql/payments.queries.js | 15 ++-- .../src/pages/bills/bills.page.component.jsx | 69 +++++++++++++----- .../src/pages/bills/bills.page.container.jsx | 9 ++- .../src/pages/jobs-all/jobs-all.container.jsx | 2 +- .../payments-all.container.page.jsx | 11 +-- os-loader.js | 50 +++++++++---- server/opensearch/os-handler.js | 44 +++++++++--- 10 files changed, 198 insertions(+), 86 deletions(-) diff --git a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx index faa8470cc..7ce46616b 100644 --- a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx +++ b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx @@ -1,5 +1,6 @@ import { SyncOutlined } from "@ant-design/icons"; import { Button, Card, Input, Space, Table, Typography } from "antd"; +import axios from "axios"; import _ from "lodash"; import queryString from "query-string"; import React, { useEffect, useState } from "react"; @@ -11,7 +12,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import StartChatButton from "../chat-open-button/chat-open-button.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; -import axios from "axios"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, @@ -209,11 +209,11 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) { search: value || search.search, index: "jobs", }); - setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source)); } catch (error) { + console.log("Error while fetching search results", error); } finally { - //setLoading(false) + // setLoading(false); } } diff --git a/client/src/components/payments-list-paginated/payment-list-paginated.component.jsx b/client/src/components/payments-list-paginated/payment-list-paginated.component.jsx index 50b3d2b98..a502a52b9 100644 --- a/client/src/components/payments-list-paginated/payment-list-paginated.component.jsx +++ b/client/src/components/payments-list-paginated/payment-list-paginated.component.jsx @@ -1,7 +1,8 @@ import { EditFilled, SyncOutlined } from "@ant-design/icons"; import { Button, Card, Input, Space, Table, Typography } from "antd"; +import axios from "axios"; import queryString from "query-string"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link, useHistory, useLocation } from "react-router-dom"; @@ -10,11 +11,11 @@ import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter"; -import { alphaSort } from "../../utils/sorters"; import { TemplateList } from "../../utils/TemplateConstants"; +import { alphaSort } from "../../utils/sorters"; import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container"; -import PrintWrapperComponent from "../print-wrapper/print-wrapper.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; +import PrintWrapperComponent from "../print-wrapper/print-wrapper.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser @@ -39,6 +40,7 @@ export function PaymentsListPaginated({ bodyshop, }) { const search = queryString.parse(useLocation().search); + const [openSearchResults, setOpenSearchResults] = useState([]); const { page, sortcolumn, sortorder } = search; const history = useHistory(); const [state, setState] = useState({ @@ -54,11 +56,15 @@ export function PaymentsListPaginated({ key: "ro_number", sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number), sortOrder: sortcolumn === "ro_number" && sortorder, - render: (text, record) => ( - - {record.job.ro_number || t("general.labels.na")} - - ), + render: (text, record) => { + return record.job ? ( + + {record.job.ro_number || t("general.labels.na")} + + ) : ( + {t("general.labels.na")} + ); + }, }, { title: t("payments.fields.paymentnum"), @@ -75,13 +81,13 @@ export function PaymentsListPaginated({ sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln), sortOrder: sortcolumn === "owner" && sortorder, render: (text, record) => { - return record.job.owner ? ( - - + return record.job?.owner ? ( + + ) : ( - + ); }, @@ -177,6 +183,28 @@ export function PaymentsListPaginated({ history.push({ search: queryString.stringify(search) }); }; + useEffect(() => { + if (search.search && search.search.trim() !== "") { + // setLoading(true); + searchPayments(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + async function searchPayments(value) { + try { + const searchData = await axios.post("/search", { + search: value || search.search, + index: "payments", + }); + setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source)); + } catch (error) { + console.log("Error while fetching search results", error); + } finally { + // setLoading(false); + } + } + return ( { search.search = value; history.push({ search: queryString.stringify(search) }); + searchPayments(value); }} enterButton /> @@ -221,15 +250,20 @@ export function PaymentsListPaginated({ diff --git a/client/src/graphql/bills.queries.js b/client/src/graphql/bills.queries.js index 4d39eda47..6406edfe1 100644 --- a/client/src/graphql/bills.queries.js +++ b/client/src/graphql/bills.queries.js @@ -20,13 +20,11 @@ export const DELETE_BILL = gql` export const QUERY_ALL_BILLS_PAGINATED = gql` query QUERY_ALL_BILLS_PAGINATED( - $search: String $offset: Int $limit: Int $order: [bills_order_by!]! ) { - search_bills( - args: { search: $search } + bills( offset: $offset limit: $limit order_by: $order @@ -51,7 +49,7 @@ export const QUERY_ALL_BILLS_PAGINATED = gql` ro_number } } - search_bills_aggregate(args: { search: $search }) { + bills_aggregate { aggregate { count(distinct: true) } diff --git a/client/src/graphql/payments.queries.js b/client/src/graphql/payments.queries.js index 554e6c497..5141e9acf 100644 --- a/client/src/graphql/payments.queries.js +++ b/client/src/graphql/payments.queries.js @@ -12,13 +12,11 @@ export const INSERT_NEW_PAYMENT = gql` export const QUERY_ALL_PAYMENTS_PAGINATED = gql` query QUERY_ALL_PAYMENTS_PAGINATED( - $search: String $offset: Int $limit: Int $order: [payments_order_by!]! ) { - search_payments( - args: { search: $search } + payments( offset: $offset limit: $limit order_by: $order @@ -31,9 +29,16 @@ export const QUERY_ALL_PAYMENTS_PAGINATED = gql` job { id ro_number + ownerid + ownr_co_nm ownr_fn ownr_ln - ownr_co_nm + owner { + id + ownr_co_nm + ownr_fn + ownr_ln + } } transactionid memo @@ -44,7 +49,7 @@ export const QUERY_ALL_PAYMENTS_PAGINATED = gql` stripeid payer } - search_payments_aggregate(args: { search: $search }) { + payments_aggregate { aggregate { count(distinct: true) } diff --git a/client/src/pages/bills/bills.page.component.jsx b/client/src/pages/bills/bills.page.component.jsx index d9dc322e1..8647a6ded 100644 --- a/client/src/pages/bills/bills.page.component.jsx +++ b/client/src/pages/bills/bills.page.component.jsx @@ -1,7 +1,8 @@ -import { SyncOutlined, EditFilled } from "@ant-design/icons"; +import { EditFilled, SyncOutlined } from "@ant-design/icons"; import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd"; +import axios from "axios"; import queryString from "query-string"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link, useHistory, useLocation } from "react-router-dom"; @@ -11,8 +12,8 @@ import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper. import { setModalContext } from "../../redux/modals/modals.actions"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; -import { alphaSort, dateSort } from "../../utils/sorters"; import { TemplateList } from "../../utils/TemplateConstants"; +import { alphaSort, dateSort } from "../../utils/sorters"; const mapDispatchToProps = (dispatch) => ({ setPartsOrderContext: (context) => @@ -29,15 +30,16 @@ export function BillsListPage({ setPartsOrderContext, setBillEnterContext, }) { - const { t } = useTranslation(); + const search = queryString.parse(useLocation().search); + const [openSearchResults, setOpenSearchResults] = useState([]); + const { page } = search; + const history = useHistory(); const [state, setState] = useState({ sortedInfo: {}, + filteredInfo: { text: "" }, }); - const history = useHistory(); - const search = queryString.parse(useLocation().search); - const { page } = search; const Templates = TemplateList("bill"); - + const { t } = useTranslation(); const columns = [ { title: t("bills.fields.vendorname"), @@ -199,11 +201,32 @@ export function BillsListPage({ search.sortcolumn = sorter.order ? sorter.columnKey : null; search.sortorder = sorter.order; } - search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order }); history.push({ search: queryString.stringify(search) }); }; + useEffect(() => { + if (search.search && search.search.trim() !== "") { + // setLoading(true); + searchBills(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + async function searchBills(value) { + try { + const searchData = await axios.post("/search", { + search: value || search.search, + index: "bills", + }); + setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source)); + } catch (error) { + console.log("Error while fetching search results", error); + } finally { + // setLoading(false); + } + } + return ( { search.search = value; history.push({ search: queryString.stringify(search) }); + searchBills(value); }} + enterButton /> } @@ -252,18 +277,24 @@ export function BillsListPage({
diff --git a/client/src/pages/bills/bills.page.container.jsx b/client/src/pages/bills/bills.page.container.jsx index a0340187b..22a8b61b9 100644 --- a/client/src/pages/bills/bills.page.container.jsx +++ b/client/src/pages/bills/bills.page.container.jsx @@ -1,6 +1,6 @@ +import { useQuery } from "@apollo/client"; import queryString from "query-string"; import React, { useEffect } from "react"; -import { useQuery } from "@apollo/client"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useLocation } from "react-router-dom"; @@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) { const { t } = useTranslation(); const searchParams = queryString.parse(useLocation().search); - const { page, sortcolumn, sortorder, search, searchObj } = searchParams; + const { page, sortcolumn, sortorder, searchObj } = searchParams; useEffect(() => { document.title = t("titles.bills-list"); @@ -38,7 +38,6 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) { fetchPolicy: "network-only", nextFetchPolicy: "network-only", variables: { - search: search || "", offset: page ? (page - 1) * 25 : 0, limit: 25, order: [ @@ -61,10 +60,10 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
diff --git a/client/src/pages/jobs-all/jobs-all.container.jsx b/client/src/pages/jobs-all/jobs-all.container.jsx index faa161571..2518d6c16 100644 --- a/client/src/pages/jobs-all/jobs-all.container.jsx +++ b/client/src/pages/jobs-all/jobs-all.container.jsx @@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch) => ({ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) { const searchParams = queryString.parse(useLocation().search); - const { page, sortcolumn, sortorder, search, statusFilters } = searchParams; + const { page, sortcolumn, sortorder, statusFilters } = searchParams; const { loading, error, data, refetch } = useQuery( QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED, diff --git a/client/src/pages/payments-all/payments-all.container.page.jsx b/client/src/pages/payments-all/payments-all.container.page.jsx index 53f3959b3..07547bc2e 100644 --- a/client/src/pages/payments-all/payments-all.container.page.jsx +++ b/client/src/pages/payments-all/payments-all.container.page.jsx @@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) { const searchParams = queryString.parse(useLocation().search); - const { page, sortcolumn, sortorder, search } = searchParams; + const { page, sortcolumn, sortorder, searchObj } = searchParams; const { loading, error, data, refetch } = useQuery( QUERY_ALL_PAYMENTS_PAGINATED, @@ -34,11 +34,12 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) { fetchPolicy: "network-only", nextFetchPolicy: "network-only", variables: { - search: search || "", offset: page ? (page - 1) * 25 : 0, limit: 25, order: [ - { + searchObj + ? JSON.parse(searchObj) + : { [sortcolumn || "date"]: sortorder ? sortorder === "descend" ? "desc" @@ -66,8 +67,8 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) { refetch={refetch} loading={loading} searchParams={searchParams} - total={data ? data.search_payments_aggregate.aggregate.count : 0} - payments={data ? data.search_payments : []} + total={data ? data.payments_aggregate.aggregate.count : 0} + payments={data ? data.payments : []} /> ); diff --git a/os-loader.js b/os-loader.js index f8b8de52a..335a04778 100644 --- a/os-loader.js +++ b/os-loader.js @@ -50,7 +50,7 @@ const getClient = async () => { async function OpenSearchUpdateHandler(req, res) { try { - var osClient = await getClient(); + var osClient = await getClient(); // const osClient = new Client({ // node: `https://imex:password@search-imexonline-search-ixp2stfvwp6qocjsowzjzyreoy.ca-central-1.es.amazonaws.com`, // }); @@ -74,12 +74,18 @@ async function OpenSearchUpdateHandler(req, res) { const jobsData = await gqlclient.request(`query{jobs{ id bodyshopid:shopid - ro_number clm_no + clm_total + comment + ins_co_nm + ownr_co_nm ownr_fn ownr_ln + ownr_ph1 + ownr_ph2 + plate_no + ro_number status - ownr_co_nm v_model_yr v_make_desc v_model_desc @@ -128,12 +134,12 @@ async function OpenSearchUpdateHandler(req, res) { vehicles { id bodyshopid: shopid -v_model_yr -v_model_desc -v_make_desc -v_color -v_vin -plate_no + plate_no + v_model_yr + v_model_desc + v_make_desc + v_color + v_vin } } `); @@ -155,11 +161,25 @@ plate_no payments { id amount - paymentnum + created_at + exportedat memo + payer + paymentnum transactionid + type job { id + ownerid + ownr_co_nm + ownr_fn + ownr_ln + owner { + id + ownr_co_nm + ownr_fn + ownr_ln + } ro_number bodyshopid: shopid } @@ -187,9 +207,11 @@ plate_no const billsData = await gqlclient.request(`{ bills { id - total - invoice_number date + exported + invoice_number + is_credit_memo + total vendor { name id @@ -200,9 +222,7 @@ plate_no bodyshopid: shopid } } - } - - `); + }`); for (let i = 0; i <= billsData.bills.length / batchSize; i++) { const slicedArray = billsData.bills.slice( i * batchSize, diff --git a/server/opensearch/os-handler.js b/server/opensearch/os-handler.js index e1db64fa9..9e45b8791 100644 --- a/server/opensearch/os-handler.js +++ b/server/opensearch/os-handler.js @@ -66,18 +66,21 @@ async function OpenSearchUpdateHandler(req, res) { document = _.pick(req.body.event.data.new, [ "id", "bodyshopid", - "ro_number", "clm_no", + "clm_total", + "comment", + "ins_co_nm", + "ownr_co_nm", "ownr_fn", "ownr_ln", + "ownr_ph1", + "ownr_ph2", + "plate_no", + "ro_number", "status", - "ownr_co_nm", "v_model_yr", "v_make_desc", "v_model_desc", - "clm_total", - "plate_no", - "ownr_ph1", ]); document.bodyshopid = req.body.event.data.new.shopid; break; @@ -127,8 +130,10 @@ async function OpenSearchUpdateHandler(req, res) { document = { ..._.pick(req.body.event.data.new, [ "id", - "invoice_number", "date", + "exported", + "invoice_number", + "is_credit_memo", ]), ...bill.bills_by_pk, bodyshopid: bill.bills_by_pk.job.shopid, @@ -145,15 +150,34 @@ async function OpenSearchUpdateHandler(req, res) { id ro_number shopid + ownerid + ownr_co_nm + ownr_fn + ownr_ln + owner { + id + ownr_co_nm + ownr_fn + ownr_ln + } } } - } - - `, + } + `, { paymentId: req.body.event.data.new.id } ); document = { - ..._.pick(req.body.event.data.new, ["id", "invoice_number"]), + ..._.pick(req.body.event.data.new, [ + "id", + "amount", + "created_at", + "exportedat", + "memo", + "payer", + "paymentnum", + "transactionid", + "type", + ]), ...payment.payments_by_pk, bodyshopid: bill.payments_by_pk.job.shopid, };