use crate::cells::push_money;
use crate::error::FormsError;
use crate::map::ScheduleSeMap;
use crate::pdf;
use crate::verify::{verify_flat, FlatPlacement};
use btctax_core::{SeTaxResult, Usd};
use rust_decimal_macros::dec;
const SE_COL_MID: usize = 0;
const SE_COL_AMOUNT: usize = 1;
const SE_CLUSTERS_UNIFIED: &[(f32, f32)] = &[(410.0, 482.0), (504.0, 576.0)];
const SE_CLUSTERS_2017: &[(f32, f32)] = &[(350.0, 433.0), (476.0, 554.0)];
fn se_clusters(year: i32) -> &'static [(f32, f32)] {
match year {
2017 => SE_CLUSTERS_2017,
_ => SE_CLUSTERS_UNIFIED,
}
}
pub const SE_FLOOR: Usd = dec!(400);
pub fn fill_schedule_se_with_map(
se: &SeTaxResult,
w2_ss_wages: Usd,
ss_wage_base: Usd,
map: &ScheduleSeMap,
) -> Result<Option<Vec<u8>>, FormsError> {
if se.base < SE_FLOOR {
return Ok(None);
}
let line9 = {
let v = ss_wage_base - w2_ss_wages;
if v < Usd::ZERO {
Usd::ZERO
} else {
v
}
};
let skip_8b_to_10 = w2_ss_wages >= ss_wage_base;
let line12 = se.ss + se.medicare;
let mut writes: Vec<(String, pdf::FieldValue)> = Vec::new();
let mut placements: Vec<FlatPlacement> = Vec::new();
let plan: [(Usd, usize, bool); 12] = [
(se.net_se, SE_COL_AMOUNT, true), (se.net_se, SE_COL_AMOUNT, true), (se.base, SE_COL_AMOUNT, true), (se.base, SE_COL_AMOUNT, true), (se.base, SE_COL_AMOUNT, true), (w2_ss_wages, SE_COL_MID, true), (w2_ss_wages, SE_COL_AMOUNT, !skip_8b_to_10), (line9, SE_COL_AMOUNT, !skip_8b_to_10), (se.ss, SE_COL_AMOUNT, !skip_8b_to_10), (se.medicare, SE_COL_AMOUNT, true), (line12, SE_COL_AMOUNT, true), (se.deductible_half, SE_COL_MID, true), ];
for (ord, (cell, (value, col, include))) in map.lines().iter().zip(plan).enumerate() {
if !include {
continue;
}
push_money(
&mut writes,
&mut placements,
cell,
value,
col,
Some((0, ord as u32)),
);
}
for fqn in &map.prefilled_exempt {
placements.push(FlatPlacement::free(fqn.clone(), crate::cells::page_of(fqn)));
}
let mut doc = pdf::load(pdf::schedule_se_pdf(map.year)?)?;
let index = pdf::index(&pdf::collect_fields(&doc)?);
pdf::drop_xfa_and_set_needappearances(&mut doc)?;
pdf::apply_writes(&mut doc, &index, &writes)?;
pdf::strip_nondeterminism(&mut doc);
let bytes = pdf::save(&mut doc)?;
let check = pdf::load(&bytes)?;
let fields = pdf::collect_fields(&check)?;
verify_flat(&check, &fields, &placements, se_clusters(map.year))?;
Ok(Some(bytes))
}