Skip to main content

btctax_cli/cmd/
admin.rs

1//! `config`, `export-snapshot` (FR10), `backup-key` — administrative commands. Config surfaces the TP8
2//! (c)/(b) treatment + the pre-2025 lot method; export/backup arrive in Task 15.
3use crate::config::{set_fee_treatment, set_pre2025_method as config_set_pre2025_method};
4use crate::render::write_csv_exports;
5use crate::{CliConfig, CliError, Session};
6use btctax_adapters::BundledTaxTables;
7use btctax_core::{compute_se_tax, FeeTreatment, LotMethod, TaxTables};
8use btctax_store::Passphrase;
9use std::path::{Path, PathBuf};
10
11pub fn show_config(vault_path: &Path, pp: &Passphrase) -> Result<CliConfig, CliError> {
12    Session::open(vault_path, pp)?.config()
13}
14
15/// Persist a new TP8 fee treatment (None = leave unchanged), then return the resulting config.
16pub fn set_config(
17    vault_path: &Path,
18    pp: &Passphrase,
19    fee_treatment: Option<FeeTreatment>,
20) -> Result<CliConfig, CliError> {
21    let mut session = Session::open(vault_path, pp)?;
22    if let Some(t) = fee_treatment {
23        set_fee_treatment(session.conn(), t)?;
24        session.save()?;
25    }
26    session.config()
27}
28
29/// Persist the pre-2025 lot identification method and attestation flag, then return the resulting config.
30pub fn set_pre2025_method(
31    vault_path: &Path,
32    pp: &Passphrase,
33    m: LotMethod,
34    attested: bool,
35) -> Result<CliConfig, CliError> {
36    let mut session = Session::open(vault_path, pp)?;
37    config_set_pre2025_method(session.conn(), m, attested)?;
38    session.save()?;
39    session.config()
40}
41
42/// FR10 / NFR2 exception: decrypted SQLite image (via the store) + the projected ledger as CSV.
43/// When `tax_year` is `Some(y)`, the per-tax-year Form 8949 + Schedule D CSVs are also written,
44/// year-scoped to `y` (P2-B); when `None`, only the all-years CSVs are written.
45pub fn export_snapshot(
46    vault_path: &Path,
47    pp: &Passphrase,
48    out_dir: &Path,
49    tax_year: Option<i32>,
50) -> Result<PathBuf, CliError> {
51    let session = Session::open(vault_path, pp)?;
52    let sqlite = session.vault().export_snapshot(out_dir)?; // writes out_dir/snapshot.sqlite
53    let (state, _cfg) = session.project()?;
54    // P2-D: standalone Schedule SE §1401 figure for the year-scoped export. Needs the year's filing
55    // status (profile) + the year's ss_wage_base (bundled table); `None` when either is absent or
56    // there is no business SE income. The "present but no table" note is a text-report concern
57    // (render_schedule_se) — the CSV carries the computed figure only.
58    let se_result = match tax_year {
59        Some(y) => {
60            let tables = BundledTaxTables::load();
61            session.tax_profile(y)?.and_then(|p| {
62                tables.table_for(y).and_then(|t| {
63                    compute_se_tax(
64                        &state,
65                        y,
66                        p.filing_status,
67                        t,
68                        p.w2_ss_wages,
69                        p.w2_medicare_wages,
70                        p.schedule_c_expenses,
71                    )
72                })
73            })
74        }
75        None => None,
76    };
77    let donation_details = session.donation_details()?;
78    write_csv_exports(
79        out_dir,
80        &state,
81        tax_year,
82        se_result.as_ref(),
83        &donation_details,
84    )?;
85    Ok(sqlite)
86}
87
88/// §8: export the passphrase-protected key (escape hatch; HIGH-security write).
89pub fn backup_key(vault_path: &Path, pp: &Passphrase, out_path: &Path) -> Result<(), CliError> {
90    Session::open(vault_path, pp)?
91        .vault()
92        .backup_key(out_path)?;
93    Ok(())
94}