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() {
+
+ + +
+