Reset all data stages a wipe behind a typed RESET confirmation and applies it on the next start, before the database is opened. It deletes the database, assets, PDF archive, imported fonts and every backup, then the setup wizard shows again. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
148 lines
7.8 KiB
TypeScript
148 lines
7.8 KiB
TypeScript
import { invoke } from "@tauri-apps/api/core";
|
|
import type {
|
|
BankAccount,
|
|
Client,
|
|
DraftSummary,
|
|
Invoice,
|
|
InvoiceInput,
|
|
InvoiceSeries,
|
|
InvoiceSummary,
|
|
ItemPreset,
|
|
Settings,
|
|
} from "./types";
|
|
import type { LogoAsset } from "./logo";
|
|
import type { Payment, PaymentInput } from "./payments";
|
|
import type { BackupStatus, BackupSummary, PendingRestore } from "./backup";
|
|
import type { LedgerRow } from "./historyExport";
|
|
import type {
|
|
ErpnextConfig,
|
|
ErpnextConfigInput,
|
|
ErpnextConnectionTest,
|
|
ErpnextOptions,
|
|
ErpnextPaymentPushResult,
|
|
ErpnextPushResult,
|
|
ErpnextSyncStatus,
|
|
} from "./erpnext";
|
|
import type { FontInspection, ImportMeta, RemoveOutcome, UserFontRow } from "./fontImport";
|
|
|
|
export interface ArchiveStatus {
|
|
archived: boolean;
|
|
sha256?: string;
|
|
fingerprint?: string;
|
|
archivedAt?: string;
|
|
}
|
|
|
|
export const api = {
|
|
getSettings: () => invoke<Settings>("get_settings"),
|
|
saveSettings: (settings: Settings) => invoke<Settings>("save_settings", { settings }),
|
|
|
|
listBanks: () => invoke<BankAccount[]>("list_banks"),
|
|
saveBank: (bank: BankAccount) => invoke<BankAccount>("save_bank", { bank }),
|
|
deleteBank: (id: number) => invoke<void>("delete_bank", { id }),
|
|
|
|
getActiveSeries: () => invoke<InvoiceSeries | null>("get_active_series"),
|
|
listSeries: () => invoke<InvoiceSeries[]>("list_series"),
|
|
startNewSeries: (prefix: string, padding: number) =>
|
|
invoke<InvoiceSeries>("start_new_series", { prefix, padding }),
|
|
|
|
listClients: () => invoke<Client[]>("list_clients"),
|
|
saveClient: (client: Client) => invoke<Client>("save_client", { client }),
|
|
deleteClient: (id: number) => invoke<void>("delete_client", { id }),
|
|
|
|
listItemPresets: () => invoke<ItemPreset[]>("list_item_presets"),
|
|
saveItemPreset: (preset: ItemPreset) => invoke<ItemPreset>("save_item_preset", { preset }),
|
|
deleteItemPreset: (id: number) => invoke<void>("delete_item_preset", { id }),
|
|
|
|
peekNextInvoiceNumber: () => invoke<string>("peek_next_invoice_number"),
|
|
issueInvoice: (input: InvoiceInput, renderPrefs: object) =>
|
|
invoke<Invoice>("issue_invoice", { input, renderPrefs }),
|
|
cancelInvoice: (id: number, reason: string) =>
|
|
invoke<Invoice>("cancel_invoice", { id, reason }),
|
|
listInvoices: () => invoke<InvoiceSummary[]>("list_invoices"),
|
|
listInvoiceLedger: () => invoke<LedgerRow[]>("list_invoice_ledger"),
|
|
getInvoice: (id: number) => invoke<Invoice>("get_invoice", { id }),
|
|
|
|
recordPayment: (input: PaymentInput) => invoke<Payment>("record_payment", { input }),
|
|
listPayments: (invoiceId: number) => invoke<Payment[]>("list_payments", { invoiceId }),
|
|
deletePayment: (id: number) => invoke<void>("delete_payment", { id }),
|
|
|
|
saveDraft: (id: number | null, payload: unknown) =>
|
|
invoke<number>("save_draft", { id, payload }),
|
|
listDrafts: () => invoke<DraftSummary[]>("list_drafts"),
|
|
getDraft: (id: number) => invoke<unknown>("get_draft", { id }),
|
|
deleteDraft: (id: number) => invoke<void>("delete_draft", { id }),
|
|
|
|
importAsset: (sourcePath: string, kind: string) =>
|
|
invoke<string>("import_asset", { sourcePath, kind }),
|
|
saveAssetBytes: (kind: string, fileName: string, dataBase64: string) =>
|
|
invoke<string>("save_asset_bytes", { kind, fileName, dataBase64 }),
|
|
importLogo: (sourcePath: string) => invoke<LogoAsset>("import_logo", { sourcePath }),
|
|
saveLogoBytes: (fileName: string, dataBase64: string) =>
|
|
invoke<LogoAsset>("save_logo_bytes", { fileName, dataBase64 }),
|
|
ensureLogoDerived: () => invoke<Settings>("ensure_logo_derived"),
|
|
removeLogo: () => invoke<Settings>("remove_logo"),
|
|
readAssetDataUri: (path: string) => invoke<string>("read_asset_data_uri", { path }),
|
|
removeAsset: (path: string) => invoke<void>("remove_asset", { path }),
|
|
|
|
// Raw-body commands: the payload is the bytes themselves (no base64); metadata goes in headers.
|
|
// Header values must be visible ASCII, hence the encodeURIComponent on paths.
|
|
archivePdf: (invoiceId: number, bytes: Uint8Array, fingerprint: string) =>
|
|
invoke<string>("archive_pdf", bytes, {
|
|
headers: { "x-invoice-id": String(invoiceId), "x-fingerprint": fingerprint },
|
|
}),
|
|
readArchive: async (invoiceId: number): Promise<Uint8Array> =>
|
|
new Uint8Array(await invoke<ArrayBuffer>("read_archive", { invoiceId })),
|
|
archiveStatus: (invoiceId: number) => invoke<ArchiveStatus>("archive_status", { invoiceId }),
|
|
// Imported fonts (Now, Gotham, Open Sauce One). The font bytes are the raw body; metadata goes in headers.
|
|
inspectFont: (bytes: Uint8Array) => invoke<FontInspection>("inspect_font", bytes),
|
|
importFont: (bytes: Uint8Array, meta: ImportMeta) =>
|
|
invoke<UserFontRow>("import_font", bytes, {
|
|
headers: {
|
|
"x-face": encodeURIComponent(meta.face),
|
|
"x-file-name": encodeURIComponent(meta.fileName),
|
|
"x-licence-ack": String(meta.licenceAcknowledged),
|
|
...(meta.weight !== undefined ? { "x-weight": String(meta.weight) } : {}),
|
|
...(meta.italic !== undefined ? { "x-style": meta.italic ? "italic" : "normal" } : {}),
|
|
},
|
|
}),
|
|
listUserFonts: (includeHidden = false) => invoke<UserFontRow[]>("list_user_fonts", { includeHidden }),
|
|
getUserFontBytes: async (sha256: string): Promise<Uint8Array> =>
|
|
new Uint8Array(await invoke<ArrayBuffer>("get_user_font_bytes", { sha256 })),
|
|
removeUserFont: (id: number) => invoke<RemoveOutcome>("remove_user_font", { id }),
|
|
writeExportFile: (path: string, bytes: Uint8Array) =>
|
|
invoke<string>("write_export_file", bytes, { headers: { "x-path": encodeURIComponent(path) } }),
|
|
getLastExportDir: () => invoke<string>("get_last_export_dir"),
|
|
revealInFolder: (path: string) => invoke<void>("reveal_in_folder", { path }),
|
|
openFile: (path: string) => invoke<void>("open_file", { path }),
|
|
|
|
// Backup and restore. A restore is staged now and applied by the next start (see commands/backup.rs).
|
|
createBackup: (dest: string) => invoke<BackupSummary>("create_backup", { dest }),
|
|
restoreBackup: (path: string) => invoke<PendingRestore>("restore_backup", { path }),
|
|
cancelPendingRestore: () => invoke<void>("cancel_pending_restore"),
|
|
getBackupStatus: () => invoke<BackupStatus>("get_backup_status"),
|
|
setAutoBackup: (enabled: boolean) => invoke<boolean>("set_auto_backup", { enabled }),
|
|
restartApp: () => invoke<void>("restart_app"),
|
|
// Stages a wipe of all data; it is carried out by the next start (see commands/reset.rs), so restart afterwards.
|
|
resetAllData: () => invoke<void>("reset_all_data"),
|
|
|
|
// ERPNext integration. All HTTP runs in Rust; the API secret is write-only from the webview.
|
|
erpnextGetConfig: () => invoke<ErpnextConfig>("erpnext_get_config"),
|
|
erpnextSaveConfig: (config: ErpnextConfigInput) => invoke<ErpnextConfig>("erpnext_save_config", { config }),
|
|
erpnextTestConnection: (config: ErpnextConfigInput) =>
|
|
invoke<ErpnextConnectionTest>("erpnext_test_connection", { config }),
|
|
erpnextLoadOptions: (config: ErpnextConfigInput) => invoke<ErpnextOptions>("erpnext_load_options", { config }),
|
|
/** `submit` omitted follows the "submit on push" setting. A failed push resolves with `ok: false`. */
|
|
erpnextPushInvoice: (id: number, submit?: boolean) =>
|
|
invoke<ErpnextPushResult>("erpnext_push_invoice", { id, submit: submit ?? null }),
|
|
/** One result per distinct id, in order; a failing row never stops the rest. */
|
|
erpnextPushInvoices: (ids: number[], submit?: boolean) =>
|
|
invoke<ErpnextPushResult[]>("erpnext_push_invoices", { ids, submit: submit ?? null }),
|
|
erpnextPushPayment: (paymentId: number) =>
|
|
invoke<ErpnextPaymentPushResult>("erpnext_push_payment", { paymentId }),
|
|
erpnextSyncStatus: (id: number) => invoke<ErpnextSyncStatus>("erpnext_sync_status", { id }),
|
|
/** Every invoice that has a sync row (invoices never pushed are absent). */
|
|
erpnextSyncStatuses: () => invoke<ErpnextSyncStatus[]>("erpnext_sync_statuses"),
|
|
/** `<base>/app/sales-invoice/<name>`; rejects when the invoice was never sent. */
|
|
erpnextOpenUrl: (id: number) => invoke<string>("erpnext_open_url", { id }),
|
|
};
|