fix: avoid PB SDK filter=undefined serialization (caused 400 errors)

The PB JS SDK serializes `filter: undefined` as the literal string
undefined in the URL, which PB rejects with 400 Bad Request.
Switched to conditionally including filter only when non-empty.
This commit is contained in:
Mavis 2026-09-17 23:17:58 +02:00
parent b95599fe83
commit 22ddfe82bf
5 changed files with 49 additions and 13 deletions

View file

@ -15,7 +15,6 @@ export default async function InvoiceDetail({ params }: { params: { id: string }
filter: `invoice="${params.id}"`,
sort: "line_no",
});
lines = lr.items;
} catch (e: any) {
return (
<div className="space-y-4">

View file

@ -25,22 +25,28 @@ export default async function InvoicesPage({
}
filter = parts.join(" && ");
const filterParam = filter ? `&filter=${encodeURIComponent(filter)}` : "";
let records: any[] = [];
try {
const r = await pb.collection("JEI_invoices").getList(1, 200, {
sort: "-invoice_date",
filter: filter || undefined,
});
// Don't pass filter when empty — the SDK serializes `undefined` as the
// literal string "undefined" which PB rejects with 400.
const opts: any = { sort: "-invoice_date", perPage: 200 };
if (filter) opts.filter = filter;
const r = await pb.collection("JEI_invoices").getList(1, 200, opts);
records = r.items;
} catch (e: any) {
// Debug: log full error to server console
console.error("[/invoices] PB error:", e?.status, e?.message, JSON.stringify(e?.data || {}));
const msg = String(e?.message || e);
const status = e?.status ? `[${e.status}] ` : "";
return (
<div className="space-y-4">
<h1 className="text-2xl font-bold text-brand-dark">Invoices</h1>
<div className="bg-red-50 border border-red-200 text-red-800 rounded p-4">
<div className="font-semibold">Cannot reach PocketBase</div>
<div className="text-sm mt-1">{String(e?.message || e)}</div>
<div className="text-xs mt-2">Check PB_TOKEN in .env.local — it expires every ~24h.</div>
<div className="font-semibold">Cannot reach PocketBase {status}</div>
<div className="text-sm mt-1">{msg}</div>
{e?.data && (
<pre className="text-xs mt-2 bg-red-100 p-2 rounded overflow-auto">{JSON.stringify(e.data, null, 2)}</pre>
)}
</div>
</div>
);

View file

@ -22,6 +22,13 @@ export default async function StockCodeDetail({ params }: { params: { code: stri
filter: `stock_code="${sc.id}"`,
expand: "invoice",
});
sc = found.items[0];
if (!sc) return notFound();
// All lines for this stock code, with their invoice (expand)
const lr = await pb.collection("JEI_invoice_lines").getList(1, 500, {
filter: `stock_code="${sc.id}"`,
expand: "invoice",
});
lines = lr.items;
} catch (e: any) {
return (

View file

@ -14,10 +14,10 @@ export default async function StockCodesPage({
// Fetch all stock codes
let codes: any[] = [];
try {
const r = await pb.collection("JEI_stock_codes").getList(1, 500, {
sort: "code",
filter: q ? `code~"${q.replace(/"/g, '\\"')}" || description_goods~"${q.replace(/"/g, '\\"')}"` : undefined,
});
// Don't pass filter when empty — SDK serializes `undefined` as literal "undefined"
const opts: any = { sort: "code", perPage: 500 };
if (q) opts.filter = `code~"${q.replace(/"/g, '\\"')}" || description_goods~"${q.replace(/"/g, '\\"')}"`;
const r = await pb.collection("JEI_stock_codes").getList(1, 500, opts);
codes = r.items;
} catch (e: any) {
return (

View file

@ -0,0 +1,24 @@
// Debug: try to fetch invoices exactly like /invoices page does
import { default as PocketBase } from 'pocketbase';
import fs from 'fs';
const envFile = fs.readFileSync('.env.local', 'utf8');
const token = envFile.match(/PB_TOKEN=(.+)/)[1].trim();
const url = envFile.match(/PB_URL=(.+)/)[1].trim();
process.env.PB_TOKEN = token;
process.env.NEXT_PUBLIC_PB_URL = url;
const pb = new PocketBase(url);
pb.authStore.save(token);
(async () => {
try {
const r = await pb.collection('JEI_invoices').getList(1, 200, {
sort: '-invoice_date',
});
console.log('OK items=' + r.items.length + ' total=' + r.totalItems);
} catch (e) {
console.log('ERR ' + e.status + ': ' + e.message);
console.log('data: ' + JSON.stringify(e.data));
console.log('url: ' + e.url);
}
})();