feat: add template_id column to invoices table and update_invoice_template command

This commit is contained in:
Your Name
2026-02-18 14:37:26 +02:00
parent 4a45713c77
commit 6a252facf6
3 changed files with 97 additions and 7 deletions

View File

@@ -62,6 +62,7 @@ pub struct Invoice {
pub total: f64,
pub notes: Option<String>,
pub status: String,
pub template_id: Option<String>,
}
// Client commands
@@ -317,11 +318,11 @@ pub fn get_reports(state: State<AppState>, start_date: String, end_date: String)
pub fn create_invoice(state: State<AppState>, invoice: Invoice) -> Result<i64, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute(
"INSERT INTO invoices (client_id, invoice_number, date, due_date, subtotal, tax_rate, tax_amount, discount, total, notes, status)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)",
"INSERT INTO invoices (client_id, invoice_number, date, due_date, subtotal, tax_rate, tax_amount, discount, total, notes, status, template_id)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)",
params![invoice.client_id, invoice.invoice_number, invoice.date, invoice.due_date,
invoice.subtotal, invoice.tax_rate, invoice.tax_amount, invoice.discount,
invoice.total, invoice.notes, invoice.status],
invoice.total, invoice.notes, invoice.status, invoice.template_id],
).map_err(|e| e.to_string())?;
Ok(conn.last_insert_rowid())
}
@@ -330,7 +331,7 @@ pub fn create_invoice(state: State<AppState>, invoice: Invoice) -> Result<i64, S
pub fn get_invoices(state: State<AppState>) -> Result<Vec<Invoice>, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
let mut stmt = conn.prepare(
"SELECT id, client_id, invoice_number, date, due_date, subtotal, tax_rate, tax_amount, discount, total, notes, status
"SELECT id, client_id, invoice_number, date, due_date, subtotal, tax_rate, tax_amount, discount, total, notes, status, template_id
FROM invoices ORDER BY date DESC"
).map_err(|e| e.to_string())?;
let invoices = stmt.query_map([], |row| {
@@ -347,6 +348,7 @@ pub fn get_invoices(state: State<AppState>) -> Result<Vec<Invoice>, String> {
total: row.get(9)?,
notes: row.get(10)?,
status: row.get(11)?,
template_id: row.get(12)?,
})
}).map_err(|e| e.to_string())?;
invoices.collect::<Result<Vec<_>, _>>().map_err(|e| e.to_string())
@@ -357,11 +359,11 @@ pub fn update_invoice(state: State<AppState>, invoice: Invoice) -> Result<(), St
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute(
"UPDATE invoices SET client_id = ?1, invoice_number = ?2, date = ?3, due_date = ?4,
subtotal = ?5, tax_rate = ?6, tax_amount = ?7, discount = ?8, total = ?9, notes = ?10, status = ?11
WHERE id = ?12",
subtotal = ?5, tax_rate = ?6, tax_amount = ?7, discount = ?8, total = ?9, notes = ?10, status = ?11, template_id = ?12
WHERE id = ?13",
params![invoice.client_id, invoice.invoice_number, invoice.date, invoice.due_date,
invoice.subtotal, invoice.tax_rate, invoice.tax_amount, invoice.discount,
invoice.total, invoice.notes, invoice.status, invoice.id],
invoice.total, invoice.notes, invoice.status, invoice.template_id, invoice.id],
).map_err(|e| e.to_string())?;
Ok(())
}
@@ -373,6 +375,67 @@ pub fn delete_invoice(state: State<AppState>, id: i64) -> Result<(), String> {
Ok(())
}
#[tauri::command]
pub fn update_invoice_template(state: State<AppState>, id: i64, template_id: String) -> Result<(), String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute(
"UPDATE invoices SET template_id = ?1 WHERE id = ?2",
params![template_id, id],
).map_err(|e| e.to_string())?;
Ok(())
}
// Invoice items
#[derive(Debug, Serialize, Deserialize)]
pub struct InvoiceItem {
pub id: Option<i64>,
pub invoice_id: i64,
pub description: String,
pub quantity: f64,
pub rate: f64,
pub amount: f64,
pub time_entry_id: Option<i64>,
}
#[tauri::command]
pub fn get_invoice_items(state: State<AppState>, invoice_id: i64) -> Result<Vec<InvoiceItem>, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
let mut stmt = conn.prepare(
"SELECT id, invoice_id, description, quantity, rate, amount, time_entry_id
FROM invoice_items WHERE invoice_id = ?1 ORDER BY id"
).map_err(|e| e.to_string())?;
let items = stmt.query_map(params![invoice_id], |row| {
Ok(InvoiceItem {
id: Some(row.get(0)?),
invoice_id: row.get(1)?,
description: row.get(2)?,
quantity: row.get(3)?,
rate: row.get(4)?,
amount: row.get(5)?,
time_entry_id: row.get(6)?,
})
}).map_err(|e| e.to_string())?;
items.collect::<Result<Vec<_>, _>>().map_err(|e| e.to_string())
}
#[tauri::command]
pub fn create_invoice_item(state: State<AppState>, item: InvoiceItem) -> Result<i64, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute(
"INSERT INTO invoice_items (invoice_id, description, quantity, rate, amount, time_entry_id)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
params![item.invoice_id, item.description, item.quantity, item.rate, item.amount, item.time_entry_id],
).map_err(|e| e.to_string())?;
Ok(conn.last_insert_rowid())
}
#[tauri::command]
pub fn delete_invoice_items(state: State<AppState>, invoice_id: i64) -> Result<(), String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute("DELETE FROM invoice_items WHERE invoice_id = ?1", params![invoice_id]).map_err(|e| e.to_string())?;
Ok(())
}
// Settings commands
#[tauri::command]
pub fn get_settings(state: State<AppState>) -> Result<std::collections::HashMap<String, String>, String> {
@@ -1053,6 +1116,12 @@ pub fn import_json_data(state: State<AppState>, data: serde_json::Value) -> Resu
Ok(counts)
}
// File save command (bypasses fs plugin scope for user-selected paths)
#[tauri::command]
pub fn save_binary_file(path: String, data: Vec<u8>) -> Result<(), String> {
std::fs::write(&path, &data).map_err(|e| e.to_string())
}
// Mini timer window commands
#[tauri::command]
pub fn open_mini_timer(app: tauri::AppHandle) -> Result<(), String> {