Add PDF archive store, raw-body IPC and export file helpers

The searchable PDF can be archived content-addressed under the local data
dir with its sha256 and layout fingerprint; a different PDF for an archived
invoice is refused and reads verify the hash. Export writes go through a
raw-body command that remembers the last folder; reveal-in-folder and open
fall back to xdg-open / explorer. Adds a Windows-safe export file name
builder. Migration M4 adds the archive columns and last export dir.
This commit is contained in:
2026-10-04 05:54:26 +05:30
parent cedf4839bd
commit 7162dac6e7
17 changed files with 891 additions and 36 deletions
+3 -1
View File
@@ -17,7 +17,7 @@ const INVOICE_COLS: &str = "id, number, series_id, invoice_date, due_date, clien
tax_type, tax_rate, cgst_amount, sgst_amount, igst_amount, total, amount_in_words,
bank_account_id, bank_snapshot, signature_path, notes, status, created_at, updated_at,
doc_type, reverse_charge, COALESCE(vendor_snapshot, ''), snapshot_origin, cancelled_at,
cancel_reason, archived_pdf_sha256, COALESCE(render_prefs, '')";
cancel_reason, archived_pdf_sha256, COALESCE(render_prefs, ''), archived_fingerprint, archived_at";
fn map_invoice(row: &Row) -> rusqlite::Result<Invoice> {
Ok(Invoice {
@@ -56,6 +56,8 @@ fn map_invoice(row: &Row) -> rusqlite::Result<Invoice> {
cancel_reason: row.get(32)?,
archived_pdf_sha256: row.get(33)?,
render_prefs: row.get(34)?,
archived_fingerprint: row.get(35)?,
archived_at: row.get(36)?,
items: Vec::new(),
})
}