use crate::{tax_profile, CliError, Session};
use btctax_adapters::BundledTaxTables;
use btctax_core::{
carryforward_consistency, compute_se_tax, compute_tax_year, schedule_d, se_net_income,
Carryforward, FilingStatus, ScheduleDTotals, TaxOutcome, TaxProfile, TaxTables, Usd,
};
use btctax_store::Passphrase;
use std::path::Path;
fn placeholder_tax_profile() -> TaxProfile {
TaxProfile {
filing_status: FilingStatus::Single,
ordinary_taxable_income: Usd::ZERO,
magi_excluding_crypto: Usd::ZERO,
qualified_dividends_and_other_pref_income: Usd::ZERO,
other_net_capital_gain: Usd::ZERO,
capital_loss_carryforward_in: Carryforward::default(),
w2_ss_wages: Usd::ZERO,
w2_medicare_wages: Usd::ZERO,
schedule_c_expenses: Usd::ZERO,
}
}
pub fn set_profile(
vault: &Path,
pp: &Passphrase,
year: i32,
p: TaxProfile,
) -> Result<(), CliError> {
let mut s = Session::open(vault, pp)?;
tax_profile::set(s.conn(), year, &p)?;
s.save()
}
pub fn show_profile(
vault: &Path,
pp: &Passphrase,
year: i32,
) -> Result<Option<TaxProfile>, CliError> {
tax_profile::get(Session::open(vault, pp)?.conn(), year)
}
pub type TaxYearReport = (
TaxOutcome,
Option<String>,
ScheduleDTotals,
Option<String>,
Option<String>,
Option<String>,
);
pub fn report_tax_year(
vault: &Path,
pp: &Passphrase,
year: i32,
prior_taxable_gifts: Usd,
) -> Result<TaxYearReport, CliError> {
let s = Session::open(vault, pp)?;
let (events, state, cfg) = s.load_events_and_project()?;
let profile = match s.tax_profile(year)? {
Some(p) => Some(p),
None if cfg.pseudo_reconcile => Some(placeholder_tax_profile()),
None => None,
};
let tables = BundledTaxTables::load();
let outcome = compute_tax_year(&events, &state, year, profile.as_ref(), &tables);
let sched_d = schedule_d(&state, year);
let gift_advisory =
crate::render::render_gift_advisory(&state, year, prior_taxable_gifts, &tables);
let schedule_se = match profile.as_ref() {
Some(p) => {
let gross_se = se_net_income(&state, year);
let table_opt = tables.table_for(year);
let table_present = table_opt.is_some();
let se_result = table_opt.and_then(|t| {
compute_se_tax(
&state,
year,
p.filing_status,
t,
p.w2_ss_wages,
p.w2_medicare_wages,
p.schedule_c_expenses,
)
});
crate::render::render_schedule_se(
year,
se_result.as_ref(),
gross_se,
table_present,
p.schedule_c_expenses,
p.w2_ss_wages,
p.w2_medicare_wages,
)
}
None => None,
};
let donation_appraisal_advisory =
crate::render::render_donation_appraisal_advisory(&state, year);
let advisory: Option<String> = if let Some(p) = &profile {
let prior_profile = s.tax_profile(year - 1)?;
if let Some(prev_p) = prior_profile {
let prior_out = compute_tax_year(&events, &state, year - 1, Some(&prev_p), &tables);
if let TaxOutcome::Computed(prev) = prior_out {
carryforward_consistency(
Some(&prev.carryforward_out),
&p.capital_loss_carryforward_in,
)
} else {
None
}
} else {
None
}
} else {
None
};
Ok((
outcome,
advisory,
sched_d,
gift_advisory,
schedule_se,
donation_appraisal_advisory,
))
}