Start the setup wizard blank and add a Run setup again button

The first-run seed no longer inserts the original vendor's name, address, contact
details, PAN or bank account; the wizard now starts empty and requires a name and
state. Settings > Data gets a Run setup again button that clears the onboarded flag.
Re-running the wizard keeps the active invoice series unless the prefix or padding
changes. The sample logo moves out of public/ so it no longer ships in the app.
This commit is contained in:
2026-10-05 09:39:02 +05:30
parent e786580d42
commit c3e2e05e89
11 changed files with 109 additions and 56 deletions
+25 -35
View File
@@ -436,8 +436,8 @@ fn prune_backups(backup_dir: &Path, keep: usize) -> std::io::Result<()> {
}
/// Insert the first-run defaults the very first time the app is opened.
/// Vendor details are pre-filled from the owner's existing invoice. The vendor
/// has no GSTIN yet, so the defaults describe an unregistered supplier (no tax).
/// The defaults are neutral: no vendor, bank or tax identity is pre-filled, so the setup wizard
/// starts blank. The vendor is an unregistered supplier (no tax) until the wizard says otherwise.
fn seed(conn: &Connection) -> rusqlite::Result<()> {
let settings_count: i64 =
conn.query_row("SELECT COUNT(*) FROM app_settings", [], |r| r.get(0))?;
@@ -447,38 +447,8 @@ fn seed(conn: &Connection) -> rusqlite::Result<()> {
(id, vendor_name, vendor_address, vendor_email, vendor_phone,
vendor_pan, vendor_gstin, vendor_state_code, default_tax_rate,
default_tax_type, payment_terms_days, currency, onboarded, theme)
VALUES (1, ?1, ?2, ?3, ?4, ?5, ?6, '29', 18, 'none', 30, 'INR', 0, 'g10')"#,
params![
"Test Vendor",
"1 Test Road, Bangalore - 560001",
"vendor@example.com",
"9000000000",
"ABCDE1234F",
"",
],
)?;
}
let bank_count: i64 =
conn.query_row("SELECT COUNT(*) FROM bank_accounts", [], |r| r.get(0))?;
if bank_count == 0 {
conn.execute(
r#"INSERT INTO bank_accounts
(label, bank_name, account_name, account_no, branch, ifsc, is_default)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, 1)"#,
params![
"Primary",
"State Bank of India",
"Test Vendor",
"000000000000",
"000001",
"TEST0000001",
],
)?;
let bank_id = conn.last_insert_rowid();
conn.execute(
"UPDATE app_settings SET default_bank_id = ?1 WHERE id = 1",
params![bank_id],
VALUES (1, '', '', '', '', '', '', '', 18, 'none', 30, 'INR', 0, 'g10')"#,
[],
)?;
}
@@ -497,6 +467,25 @@ fn seed(conn: &Connection) -> rusqlite::Result<()> {
Ok(())
}
/// Sample vendor and bank for command-logic unit tests (production seeds none). Fake values only.
#[cfg(test)]
pub(crate) fn seed_test_fixture(conn: &Connection) -> rusqlite::Result<()> {
conn.execute(
r#"UPDATE app_settings SET vendor_name = 'Test Vendor', vendor_address = '1 Test Road, Bangalore - 560001',
vendor_email = 'vendor@example.com', vendor_phone = '9000000000', vendor_pan = 'ABCDE1234F',
vendor_state_code = '29' WHERE id = 1"#,
[],
)?;
conn.execute(
r#"INSERT INTO bank_accounts (label, bank_name, account_name, account_no, branch, ifsc, is_default)
VALUES ('Primary', 'Test Bank', 'Test Vendor', '000000000000', '000001', 'TEST0000001', 1)"#,
[],
)?;
let bank_id = conn.last_insert_rowid();
conn.execute("UPDATE app_settings SET default_bank_id = ?1 WHERE id = 1", params![bank_id])?;
Ok(())
}
/// A migrated, seeded in-memory database for unit tests of the command logic.
#[cfg(test)]
pub fn open_in_memory() -> Result<Connection, DbError> {
@@ -504,6 +493,7 @@ pub fn open_in_memory() -> Result<Connection, DbError> {
conn.pragma_update(None, "foreign_keys", "ON")?;
migrations().to_latest(&mut conn)?;
seed(&conn)?;
seed_test_fixture(&conn)?;
Ok(conn)
}
@@ -726,7 +716,7 @@ CREATE INDEX IF NOT EXISTS idx_invoices_created ON invoices(created_at DESC);
.unwrap();
assert_eq!(tax_type, "none");
assert_eq!(gst_reg, "unregistered");
assert_eq!(name, "Test Vendor");
assert_eq!(name, "");
assert!(backups_in(&backups).is_empty());
}