IO-1914 Added inventory page.

This commit is contained in:
Patrick Fic
2022-05-31 12:38:07 -07:00
parent 912756e0f9
commit d28d4d6283
25 changed files with 830 additions and 7 deletions

View File

@@ -17292,6 +17292,69 @@
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>consumedbyjob</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>frombillinvoicenumber</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>fromvendor</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>inventory</name>
<definition_loaded>false</definition_loaded>
@@ -17313,6 +17376,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>showall</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>showavailable</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>
</children>
</folder_node>
<folder_node>
@@ -30064,6 +30169,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>inventory</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>jobs</name>
<definition_loaded>false</definition_loaded>
@@ -42492,6 +42618,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>inventory</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>jobs</name>
<definition_loaded>false</definition_loaded>
@@ -43313,6 +43460,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>inventory</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>jobs</name>
<definition_loaded>false</definition_loaded>

View File

@@ -18,7 +18,6 @@ export const CalculateBillTotal = (invoice) => {
amount: Math.round((i.actual_cost || 0) * 100),
}).multiply(i.quantity || 1);
console.log(i, itemTotal.toFormat);
subtotal = subtotal.add(itemTotal);
if (i.applicable_taxes.federal) {
federalTax = federalTax.add(

View File

@@ -200,6 +200,13 @@ function Header({
{t("menus.header.enterbills")}
</Menu.Item>
<Menu.Divider key="div4" />
<Menu.Item
key="inventory"
icon={<Icon component={FaFileInvoiceDollar} />}
>
<Link to="/manage/inventory">{t("menus.header.inventory")}</Link>
</Menu.Item>
<Menu.Divider key="div7" />
<Menu.Item key="allpayments" icon={<BankFilled />}>
<Link to="/manage/payments">{t("menus.header.allpayments")}</Link>
</Menu.Item>
@@ -216,7 +223,6 @@ function Header({
{t("menus.header.enterpayment")}
</Menu.Item>
<Menu.Divider key="div5" />
<Menu.Item key="timetickets" icon={<FieldTimeOutlined />}>
<Link to="/manage/timetickets">
{t("menus.header.timetickets")}
@@ -235,7 +241,6 @@ function Header({
{t("menus.header.entertimeticket")}
</Menu.Item>
<Menu.Divider key="div6" />
<Menu.SubMenu
key="accountingexport"
title={t("menus.header.export")}

View File

@@ -0,0 +1,156 @@
import { SyncOutlined } from "@ant-design/icons";
import { Button, Card, Input, Space, Table, Typography } from "antd";
import _ from "lodash";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
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";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
const search = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, invfilters } = search;
const history = useHistory();
const { t } = useTranslation();
const columns = [
{
title: t("billlines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
sorter: true, //(a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder: sortcolumn === "line_desc" && sortorder,
},
{
title: t("inventory.labels.frombillinvoicenumber"),
dataIndex: "vendorname",
key: "vendorname",
ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => record.billline?.bill?.invoice_number,
},
{
title: t("inventory.labels.fromvendor"),
dataIndex: "vendorname",
key: "vendorname",
ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => record.billline?.bill?.vendor?.name,
},
{
title: t("billlines.fields.actual_price"),
dataIndex: "actual_price",
key: "actual_price",
render: (text, record) => (
<CurrencyFormatter>{record.actual_price}</CurrencyFormatter>
),
},
{
title: t("billlines.fields.actual_cost"),
dataIndex: "actual_cost",
key: "actual_cost",
render: (text, record) => (
<CurrencyFormatter>{record.actual_cost}</CurrencyFormatter>
),
},
{
title: t("inventory.labels.consumedbyjob"),
dataIndex: "consumedbyjob",
key: "consumedbyjob",
ellipsis: true,
render: (text, record) => record.bill?.job?.ro_number,
},
];
const handleTableChange = (pagination, filters, sorter) => {
search.page = pagination.current;
search.sortcolumn = sorter.column && sorter.column.key;
search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) });
};
return (
<Card
extra={
<Space wrap>
{search.search && (
<>
<Typography.Title level={4}>
{t("general.labels.searchresults", { search: search.search })}
</Typography.Title>
<Button
onClick={() => {
delete search.search;
history.push({ search: queryString.stringify(search) });
}}
>
{t("general.actions.clear")}
</Button>
</>
)}
<Button
onClick={() => {
if (search.showall) delete search.showall;
else {
search.showall = true;
}
history.push({ search: queryString.stringify(search) });
}}
>
{search.showall
? t("inventory.labels.showavailable")
: t("inventory.labels.showall")}
</Button>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={search.search || t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
dataSource={jobs}
onChange={handleTableChange}
/>
</Card>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(JobsList);

View File

@@ -0,0 +1,67 @@
import { useQuery } from "@apollo/client";
import queryString from "query-string";
import React from "react";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { QUERY_INVENTORY_PAGINATED } from "../../graphql/inventory.queries";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import AlertComponent from "../alert/alert.component";
import InventoryListPaginated from "./inventory-list.component";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
const mapStateToProps = createStructuredSelector({
//bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
export function InventoryList({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, search, showall } = searchParams;
const { loading, error, data, refetch } = useQuery(
QUERY_INVENTORY_PAGINATED,
{
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
search: search || "",
offset: page ? (page - 1) * 25 : 0,
limit: 25,
consumedIsNull: showall === "true" ? null : true,
order: [
{
[sortcolumn || "created_at"]:
sortorder && sortorder !== "false"
? sortorder === "descend"
? "desc"
: "asc"
: "desc",
},
],
},
}
);
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<RbacWrapper action="jobs:list-all">
<InventoryListPaginated
refetch={refetch}
loading={loading}
searchParams={searchParams}
total={data ? data.search_inventory_aggregate.aggregate.count : 0}
jobs={data ? data.search_inventory : []}
/>
</RbacWrapper>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(InventoryList);

View File

@@ -25,7 +25,7 @@ const ret = {
"jobs:detail": 1,
"jobs:partsqueue": 4,
"jobs:checklist-view": 2,
"jobs:list-ready": 1,
"bills:enter": 2,
"bills:view": 2,
"bills:list": 2,
@@ -66,5 +66,7 @@ const ret = {
"timetickets:shiftedit": 5,
"users:editaccess": 4,
"inventory:list": 1,
};
export default ret;

View File

@@ -633,6 +633,18 @@ export default function ShopInfoRbacComponent({ form }) {
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.inventory.list")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "inventory:list"]}
>
<InputNumber />
</Form.Item>
</LayoutFormRow>
</RbacWrapper>
);

View File

@@ -47,3 +47,53 @@ export const QUERY_OUTSTANDING_INVENTORY = gql`
}
}
`;
export const QUERY_INVENTORY_PAGINATED = gql`
query QUERY_INVENTORY_PAGINATED(
$search: String
$offset: Int
$limit: Int
$order: [inventory_order_by!]
$consumedIsNull: Boolean
) {
search_inventory(
args: { search: $search }
offset: $offset
limit: $limit
order_by: $order
where: { consumedbybillid: { _is_null: $consumedIsNull } }
) {
id
line_desc
actual_price
actual_cost
bill {
id
invoice_number
job {
ro_number
id
}
}
billline {
id
bill {
id
invoice_number
vendor {
id
name
}
}
}
}
search_inventory_aggregate(
args: { search: $search }
where: { consumedbybillid: { _is_null: $consumedIsNull } }
) {
aggregate {
count(distinct: true)
}
}
}
`;

View File

@@ -0,0 +1,32 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import InventoryList from "../../components/inventory-list/inventory-list.container";
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
export function InventoryPage({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.inventory");
setSelectedHeader("inventory");
setBreadcrumbs([{ link: "/manage/jobs", label: t("titles.bc.inventory") }]);
}, [t, setBreadcrumbs, setSelectedHeader]);
return (
<RbacWrapper action="inventory:list">
<InventoryList />
</RbacWrapper>
);
}
export default connect(null, mapDispatchToProps)(InventoryPage);

View File

@@ -34,6 +34,7 @@ const JobsPage = lazy(() => import("../jobs/jobs.page"));
const JobsDetailPage = lazy(() =>
import("../jobs-detail/jobs-detail.page.container")
);
const InventoryListPage = lazy(() => import("../inventory/inventory.page"));
const ProfilePage = lazy(() => import("../profile/profile.container.page"));
const JobsAvailablePage = lazy(() =>
import("../jobs-available/jobs-available.page.container")
@@ -250,6 +251,11 @@ export function Manage({ match, conflict, bodyshop }) {
<Route path={`${match.path}/jobs/:jobId`} component={JobsDetailPage} />
</Switch>
<Route exact path={`${match.path}/temporarydocs/`} component={TempDocs} />
<Route
exact
path={`${match.path}/inventory/`}
component={InventoryListPage}
/>
<Route
exact
path={`${match.path}/courtesycars/`}

View File

@@ -1078,7 +1078,12 @@
"inserting": "Error inserting inventory item. {{error}}"
},
"labels": {
"inventory": "Inventory"
"consumedbyjob": "Consumed by Job",
"frombillinvoicenumber": "Original Bill Invoice Number",
"fromvendor": "Original Bill Vendor",
"inventory": "Inventory",
"showall": "Show All Inventory",
"showavailable": "Show Only Available Inventory"
},
"successes": {
"inserted": "Added line to inventory."
@@ -1769,6 +1774,7 @@
"export-logs": "Export Logs",
"help": "Help",
"home": "Home",
"inventory": "Inventory",
"jobs": "Jobs",
"newjob": "Create New Job",
"owners": "Owners",
@@ -2537,6 +2543,7 @@
"dashboard": "Dashboard",
"dms": "DMS Export",
"export-logs": "Export Logs",
"inventory": "Inventory",
"jobs": "Jobs",
"jobs-active": "Active Jobs",
"jobs-admin": "Admin",
@@ -2577,6 +2584,7 @@
"dashboard": "Dashboard | $t(titles.app)",
"dms": "DMS Export | $t(titles.app)",
"export-logs": "Export Logs | $t(titles.app)",
"inventory": "Inventory | $t(titles.app)",
"jobs": "Active Jobs | $t(titles.app)",
"jobs-admin": "Job {{ro_number}} - Admin | $t(titles.app)",
"jobs-all": "All Jobs | $t(titles.app)",

View File

@@ -1078,7 +1078,12 @@
"inserting": ""
},
"labels": {
"inventory": ""
"consumedbyjob": "",
"frombillinvoicenumber": "",
"fromvendor": "",
"inventory": "",
"showall": "",
"showavailable": ""
},
"successes": {
"inserted": ""
@@ -1769,6 +1774,7 @@
"export-logs": "",
"help": "",
"home": "Casa",
"inventory": "",
"jobs": "Trabajos",
"newjob": "",
"owners": "propietarios",
@@ -2537,6 +2543,7 @@
"dashboard": "",
"dms": "",
"export-logs": "",
"inventory": "",
"jobs": "",
"jobs-active": "",
"jobs-admin": "",
@@ -2577,6 +2584,7 @@
"dashboard": "",
"dms": "",
"export-logs": "",
"inventory": "",
"jobs": "Todos los trabajos | $t(titles.app)",
"jobs-admin": "",
"jobs-all": "",

View File

@@ -1078,7 +1078,12 @@
"inserting": ""
},
"labels": {
"inventory": ""
"consumedbyjob": "",
"frombillinvoicenumber": "",
"fromvendor": "",
"inventory": "",
"showall": "",
"showavailable": ""
},
"successes": {
"inserted": ""
@@ -1769,6 +1774,7 @@
"export-logs": "",
"help": "",
"home": "Accueil",
"inventory": "",
"jobs": "Emplois",
"newjob": "",
"owners": "Propriétaires",
@@ -2537,6 +2543,7 @@
"dashboard": "",
"dms": "",
"export-logs": "",
"inventory": "",
"jobs": "",
"jobs-active": "",
"jobs-admin": "",
@@ -2577,6 +2584,7 @@
"dashboard": "",
"dms": "",
"export-logs": "",
"inventory": "",
"jobs": "Tous les emplois | $t(titles.app)",
"jobs-admin": "",
"jobs-all": "",

View File

@@ -10,6 +10,9 @@
- function:
schema: public
name: search_exportlog
- function:
schema: public
name: search_inventory
- function:
schema: public
name: search_jobs

View File

@@ -2199,6 +2199,7 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
allow_aggregations: true
update_permissions:
- role: user
permission:

View File

@@ -0,0 +1,40 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.search_inventory (search text)
-- RETURNS SETOF inventory
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
-- IF search = '' THEN
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory;
-- ELSE
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory i,
-- billlines bl,
-- bills b,
-- vendors v
-- WHERE
-- i.billlineid = bl.id
-- AND bl.billid = b.id
-- AND b.vendorid = v.id
-- AND i.line_desc ILIKE '%' || search || '%'
-- OR b.invoice_number ILIKE '%' || search || '%'
-- OR v.name ILIKE '%' || search || '%'
-- ORDER BY
-- i.line_desc ILIKE '%' || search || '%'
-- OR NULL,
-- b.invoice_number ILIKE '%' || search || '%'
-- OR NULL,
-- v.name ILIKE '%' || search || '%'
-- OR NULL;
-- END IF;
-- END
-- $function$;

View File

@@ -0,0 +1,38 @@
CREATE OR REPLACE FUNCTION public.search_inventory (search text)
RETURNS SETOF inventory
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
IF search = '' THEN
RETURN query
SELECT
*
FROM
inventory;
ELSE
RETURN query
SELECT
*
FROM
inventory i,
billlines bl,
bills b,
vendors v
WHERE
i.billlineid = bl.id
AND bl.billid = b.id
AND b.vendorid = v.id
AND i.line_desc ILIKE '%' || search || '%'
OR b.invoice_number ILIKE '%' || search || '%'
OR v.name ILIKE '%' || search || '%'
ORDER BY
i.line_desc ILIKE '%' || search || '%'
OR NULL,
b.invoice_number ILIKE '%' || search || '%'
OR NULL,
v.name ILIKE '%' || search || '%'
OR NULL;
END IF;
END
$function$;

View File

@@ -0,0 +1,37 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.search_inventory (search text)
-- RETURNS SETOF inventory
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
-- IF search = '' THEN
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory;
-- ELSE
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory inner JOIN billlines ON inventory.billlineid = billlines.id
-- inner JOIN bills ON billlines.billid = bills.id
-- inner JOIN vendors ON bills.vendorid = vendors.id
--
-- WHERE
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR bills.invoice_number ILIKE '%' || search || '%'
-- OR vendors.name ILIKE '%' || search || '%'
-- ORDER BY
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR NULL,
-- bills.invoice_number ILIKE '%' || search || '%'
-- OR NULL,
-- vendors.name ILIKE '%' || search || '%'
-- OR NULL;
-- END IF;
-- END
-- $function$;

View File

@@ -0,0 +1,35 @@
CREATE OR REPLACE FUNCTION public.search_inventory (search text)
RETURNS SETOF inventory
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
IF search = '' THEN
RETURN query
SELECT
*
FROM
inventory;
ELSE
RETURN query
SELECT
*
FROM
inventory inner JOIN billlines ON inventory.billlineid = billlines.id
inner JOIN bills ON billlines.billid = bills.id
inner JOIN vendors ON bills.vendorid = vendors.id
WHERE
inventory.line_desc ILIKE '%' || search || '%'
OR bills.invoice_number ILIKE '%' || search || '%'
OR vendors.name ILIKE '%' || search || '%'
ORDER BY
inventory.line_desc ILIKE '%' || search || '%'
OR NULL,
bills.invoice_number ILIKE '%' || search || '%'
OR NULL,
vendors.name ILIKE '%' || search || '%'
OR NULL;
END IF;
END
$function$;

View File

@@ -0,0 +1,37 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.search_inventory (search text)
-- RETURNS SETOF inventory
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
-- IF search = '' THEN
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory;
-- ELSE
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory inner JOIN billlines ON inventory.billlineid = billlines.id
-- inner JOIN bills ON billlines.billid = bills.id
-- inner JOIN vendors ON bills.vendorid = vendors.id
--
-- WHERE
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR bills.invoice_number ILIKE '%' || search || '%'
-- OR vendors.name ILIKE '%' || search || '%'
-- ORDER BY
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR NULL,
-- bills.invoice_number ILIKE '%' || search || '%'
-- OR NULL,
-- vendors.name ILIKE '%' || search || '%'
-- OR NULL;
-- END IF;
-- END
-- $function$;

View File

@@ -0,0 +1,35 @@
CREATE OR REPLACE FUNCTION public.search_inventory (search text)
RETURNS SETOF inventory
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
IF search = '' THEN
RETURN query
SELECT
*
FROM
inventory;
ELSE
RETURN query
SELECT
*
FROM
inventory inner JOIN billlines ON inventory.billlineid = billlines.id
inner JOIN bills ON billlines.billid = bills.id
inner JOIN vendors ON bills.vendorid = vendors.id
WHERE
inventory.line_desc ILIKE '%' || search || '%'
OR bills.invoice_number ILIKE '%' || search || '%'
OR vendors.name ILIKE '%' || search || '%'
ORDER BY
inventory.line_desc ILIKE '%' || search || '%'
OR NULL,
bills.invoice_number ILIKE '%' || search || '%'
OR NULL,
vendors.name ILIKE '%' || search || '%'
OR NULL;
END IF;
END
$function$;

View File

@@ -0,0 +1,37 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.search_inventory (search text)
-- RETURNS SETOF inventory
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
-- IF search = '' THEN
-- RETURN query
-- SELECT
-- *
-- FROM
-- inventory;
-- ELSE
-- RETURN query
-- SELECT
-- inventory.*
-- FROM
-- inventory inner JOIN billlines ON inventory.billlineid = billlines.id
-- inner JOIN bills ON billlines.billid = bills.id
-- inner JOIN vendors ON bills.vendorid = vendors.id
--
-- WHERE
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR bills.invoice_number ILIKE '%' || search || '%'
-- OR vendors.name ILIKE '%' || search || '%'
-- ORDER BY
-- inventory.line_desc ILIKE '%' || search || '%'
-- OR NULL,
-- bills.invoice_number ILIKE '%' || search || '%'
-- OR NULL,
-- vendors.name ILIKE '%' || search || '%'
-- OR NULL;
-- END IF;
-- END
-- $function$;

View File

@@ -0,0 +1,35 @@
CREATE OR REPLACE FUNCTION public.search_inventory (search text)
RETURNS SETOF inventory
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
IF search = '' THEN
RETURN query
SELECT
*
FROM
inventory;
ELSE
RETURN query
SELECT
inventory.*
FROM
inventory inner JOIN billlines ON inventory.billlineid = billlines.id
inner JOIN bills ON billlines.billid = bills.id
inner JOIN vendors ON bills.vendorid = vendors.id
WHERE
inventory.line_desc ILIKE '%' || search || '%'
OR bills.invoice_number ILIKE '%' || search || '%'
OR vendors.name ILIKE '%' || search || '%'
ORDER BY
inventory.line_desc ILIKE '%' || search || '%'
OR NULL,
bills.invoice_number ILIKE '%' || search || '%'
OR NULL,
vendors.name ILIKE '%' || search || '%'
OR NULL;
END IF;
END
$function$;

View File

@@ -0,0 +1,3 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- create index inventory_linedescidx on inventory(line_desc);

View File

@@ -0,0 +1 @@
create index inventory_linedescidx on inventory(line_desc);