139 lines
4.1 KiB
Rust
139 lines
4.1 KiB
Rust
use rusqlite::Connection;
|
|
|
|
pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS clients (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
email TEXT,
|
|
address TEXT,
|
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
// Migrate clients table — add new columns (safe to re-run)
|
|
let migration_columns = [
|
|
"ALTER TABLE clients ADD COLUMN company TEXT",
|
|
"ALTER TABLE clients ADD COLUMN phone TEXT",
|
|
"ALTER TABLE clients ADD COLUMN tax_id TEXT",
|
|
"ALTER TABLE clients ADD COLUMN payment_terms TEXT",
|
|
"ALTER TABLE clients ADD COLUMN notes TEXT",
|
|
];
|
|
for sql in &migration_columns {
|
|
match conn.execute(sql, []) {
|
|
Ok(_) => {}
|
|
Err(e) => {
|
|
let msg = e.to_string();
|
|
if !msg.contains("duplicate column") {
|
|
return Err(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS projects (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
client_id INTEGER,
|
|
name TEXT NOT NULL,
|
|
hourly_rate REAL DEFAULT 0,
|
|
color TEXT DEFAULT '#F59E0B',
|
|
archived INTEGER DEFAULT 0,
|
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (client_id) REFERENCES clients(id)
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS tasks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_id INTEGER NOT NULL,
|
|
name TEXT NOT NULL,
|
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS time_entries (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_id INTEGER NOT NULL,
|
|
task_id INTEGER,
|
|
description TEXT,
|
|
start_time TEXT NOT NULL,
|
|
end_time TEXT,
|
|
duration INTEGER DEFAULT 0,
|
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (project_id) REFERENCES projects(id),
|
|
FOREIGN KEY (task_id) REFERENCES tasks(id)
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS invoices (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
client_id INTEGER NOT NULL,
|
|
invoice_number TEXT NOT NULL,
|
|
date TEXT NOT NULL,
|
|
due_date TEXT,
|
|
subtotal REAL DEFAULT 0,
|
|
tax_rate REAL DEFAULT 0,
|
|
tax_amount REAL DEFAULT 0,
|
|
discount REAL DEFAULT 0,
|
|
total REAL DEFAULT 0,
|
|
notes TEXT,
|
|
status TEXT DEFAULT 'draft',
|
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (client_id) REFERENCES clients(id)
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS invoice_items (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
invoice_id INTEGER NOT NULL,
|
|
description TEXT NOT NULL,
|
|
quantity REAL DEFAULT 1,
|
|
rate REAL DEFAULT 0,
|
|
amount REAL DEFAULT 0,
|
|
time_entry_id INTEGER,
|
|
FOREIGN KEY (invoice_id) REFERENCES invoices(id),
|
|
FOREIGN KEY (time_entry_id) REFERENCES time_entries(id)
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
conn.execute(
|
|
"CREATE TABLE IF NOT EXISTS settings (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT
|
|
)",
|
|
[],
|
|
)?;
|
|
|
|
// Insert default settings
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO settings (key, value) VALUES ('hourly_rate', '50')",
|
|
[],
|
|
)?;
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO settings (key, value) VALUES ('idle_detection', 'true')",
|
|
[],
|
|
)?;
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO settings (key, value) VALUES ('idle_timeout', '5')",
|
|
[],
|
|
)?;
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO settings (key, value) VALUES ('reminder_interval', '30')",
|
|
[],
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|