Add searchable and flattened export, history re-export and diagnostics self-test
issueAndArchive keeps an issued invoice even when rendering or archiving fails (Issued - not archived, with a Render & archive action). The export menu offers a searchable PDF or a 300 DPI image-only PDF whose metadata is the invoice number alone; flatten failures offer Retry or searchable export and never silently lower the resolution. History re-exports the original as issued by default and warns when a re-render's layout fingerprint differs. The render client gains a FIFO assemble lane that previews cannot supersede. A Diagnostics panel runs fixtures in the real worker and compares against goldens generated from Node.
This commit is contained in:
+5
-23
@@ -1,4 +1,3 @@
|
||||
import { save } from "@tauri-apps/plugin-dialog";
|
||||
import pkg from "../../package.json";
|
||||
import { parsePrefs, type RenderPrefsV1 } from "../pdf/model/prefs";
|
||||
import { buildRenderModel, type RenderModel } from "../pdf/model/build";
|
||||
@@ -57,6 +56,11 @@ export async function renderInvoicePdf(
|
||||
prefs: RenderPrefsV1 = prefsForInvoice(invoice, settings),
|
||||
): Promise<RenderResult> {
|
||||
const model = await buildModelForInvoice(invoice, settings, bank);
|
||||
return renderModelWithRetry(model, prefs);
|
||||
}
|
||||
|
||||
/** Renders a ready model in the shared client. */
|
||||
export async function renderModelWithRetry(model: RenderModel, prefs: RenderPrefsV1): Promise<RenderResult> {
|
||||
// The live preview shares the client; if it takes the worker first this render is superseded, so go again.
|
||||
for (let attempt = 0; ; attempt++) {
|
||||
try {
|
||||
@@ -66,25 +70,3 @@ export async function renderInvoicePdf(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Asks for a save location and writes the bytes there; null when the dialog is cancelled. */
|
||||
export async function savePdfBytes(bytes: Uint8Array, fileName: string): Promise<string | null> {
|
||||
const suggested = fileName.replace(/[^A-Za-z0-9._-]+/g, "-") || "invoice";
|
||||
const path = await save({
|
||||
defaultPath: `${suggested}.pdf`,
|
||||
filters: [{ name: "PDF document", extensions: ["pdf"] }],
|
||||
});
|
||||
if (!path) return null;
|
||||
await api.writeExportFile(path, bytes);
|
||||
return path;
|
||||
}
|
||||
|
||||
export async function exportInvoicePdf(
|
||||
invoice: Invoice,
|
||||
settings: Settings,
|
||||
bank: BankAccount | null,
|
||||
prefs?: RenderPrefsV1,
|
||||
): Promise<string | null> {
|
||||
const { bytes } = await renderInvoicePdf(invoice, settings, bank, prefs);
|
||||
return savePdfBytes(bytes, invoice.number);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user