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:
parent
b95599fe83
commit
22ddfe82bf
5 changed files with 49 additions and 13 deletions
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
24
scripts/debug_invoices.mjs
Normal file
24
scripts/debug_invoices.mjs
Normal 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);
|
||||
}
|
||||
})();
|
||||
Loading…
Reference in a new issue