From 17be91888312d910c5f45e40159623e1463ce4fb Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Fri, 29 May 2026 10:46:48 -0500 Subject: [PATCH] new Filter --- migrations/add-invoice-items-filter-index.sql | 1 + public/js/views/invoice-view.js | 53 ++++++++++++++++++- schema.sql | 7 +++ src/routes/invoices.js | 17 ++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 migrations/add-invoice-items-filter-index.sql diff --git a/migrations/add-invoice-items-filter-index.sql b/migrations/add-invoice-items-filter-index.sql new file mode 100644 index 0000000..73bb80f --- /dev/null +++ b/migrations/add-invoice-items-filter-index.sql @@ -0,0 +1 @@ +CREATE INDEX idx_invoice_items_invoice_qbo ON public.invoice_items USING btree (invoice_id, qbo_item_id); diff --git a/public/js/views/invoice-view.js b/public/js/views/invoice-view.js index 36ae8dc..9ccf0de 100644 --- a/public/js/views/invoice-view.js +++ b/public/js/views/invoice-view.js @@ -6,6 +6,8 @@ let filterCustomer = localStorage.getItem('inv_filterCustomer') || ''; let filterStatus = localStorage.getItem('inv_filterStatus') || 'unpaid'; let groupBy = localStorage.getItem('inv_groupBy') || 'none'; let filterWorker = localStorage.getItem('inv_filterWorker') || ''; +let filterItemType = localStorage.getItem('inv_filterItemType') === 'true'; +let filterEmptyCost = localStorage.getItem('inv_filterEmptyCost') === 'true'; const OVERDUE_DAYS = 30; @@ -196,6 +198,8 @@ function saveSettings() { localStorage.setItem('inv_groupBy', groupBy); localStorage.setItem('inv_filterCustomer', filterCustomer); localStorage.setItem('inv_filterWorker', filterWorker); + localStorage.setItem('inv_filterItemType', filterItemType); + localStorage.setItem('inv_filterEmptyCost', filterEmptyCost); } // ============================================================ @@ -204,7 +208,14 @@ function saveSettings() { export async function loadInvoices() { try { - const response = await fetch('/api/invoices'); + const params = new URLSearchParams(); + if (filterItemType) { + params.set('has_parts_or_subscription', 'true'); + if (filterEmptyCost) params.set('empty_cost_only', 'true'); + } + const qs = params.toString(); + const url = qs ? `/api/invoices?${qs}` : '/api/invoices'; + const response = await fetch(url); invoices = await response.json(); renderInvoiceView(); loadLastSync(); @@ -599,6 +610,13 @@ export function injectToolbar() {
+
+ + +
+