Add history window controls and expand taxonomy pack support
- add 3Y/5Y/10Y financial history filtering and reorganize normalization details UI - add new fiscal taxonomy surface/income bridge/KPI packs and update Rust taxonomy loading - auto-detect Homebrew SQLite for native `sqlite-vec` in local dev/e2e with docs and env guidance
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1762,4 +1762,130 @@ mod tests {
|
||||
Some(-15.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_software_balance_overrides() {
|
||||
let mut rows = empty_map();
|
||||
rows.get_mut("balance").unwrap().extend([
|
||||
row(
|
||||
"software-costs",
|
||||
"us-gaap:CapitalizedSoftwareCosts",
|
||||
"balance",
|
||||
55.0,
|
||||
),
|
||||
row(
|
||||
"software-defrev",
|
||||
"us-gaap:DeferredRevenueSoftware",
|
||||
"balance",
|
||||
21.0,
|
||||
),
|
||||
]);
|
||||
|
||||
let model = build_compact_surface_model(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
"us-gaap",
|
||||
FiscalPack::Software,
|
||||
vec![],
|
||||
)
|
||||
.expect("compact model should build");
|
||||
|
||||
let balance_rows = model.surface_rows.get("balance").unwrap();
|
||||
let software_costs = balance_rows
|
||||
.iter()
|
||||
.find(|row| row.key == "capitalized_software_costs")
|
||||
.unwrap();
|
||||
let deferred_revenue = balance_rows
|
||||
.iter()
|
||||
.find(|row| row.key == "deferred_revenue")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
software_costs.values.get("p1").copied().flatten(),
|
||||
Some(55.0)
|
||||
);
|
||||
assert_eq!(
|
||||
deferred_revenue.values.get("p1").copied().flatten(),
|
||||
Some(21.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_broadcaster_programming_library_balance_row() {
|
||||
let mut rows = empty_map();
|
||||
rows.get_mut("balance").unwrap().push(row(
|
||||
"broadcast-library",
|
||||
"us-gaap:ProgrammingLibrary",
|
||||
"balance",
|
||||
88.0,
|
||||
));
|
||||
|
||||
let model = build_compact_surface_model(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
"us-gaap",
|
||||
FiscalPack::EntertainmentBroadcasters,
|
||||
vec![],
|
||||
)
|
||||
.expect("compact model should build");
|
||||
|
||||
let programming_library = model
|
||||
.surface_rows
|
||||
.get("balance")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "programming_library")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
programming_library.values.get("p1").copied().flatten(),
|
||||
Some(88.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_defined_benefit_plan_balance_rows() {
|
||||
let mut rows = empty_map();
|
||||
rows.get_mut("balance").unwrap().extend([
|
||||
row(
|
||||
"plan-assets",
|
||||
"us-gaap:FairValueOfPlanAssets",
|
||||
"balance",
|
||||
140.0,
|
||||
),
|
||||
row(
|
||||
"pbo",
|
||||
"us-gaap:ProjectedBenefitObligation",
|
||||
"balance",
|
||||
125.0,
|
||||
),
|
||||
]);
|
||||
|
||||
let model = build_compact_surface_model(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
"us-gaap",
|
||||
FiscalPack::PlanDefinedBenefit,
|
||||
vec![],
|
||||
)
|
||||
.expect("compact model should build");
|
||||
|
||||
let plan_assets = model
|
||||
.surface_rows
|
||||
.get("balance")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "plan_assets")
|
||||
.unwrap();
|
||||
let obligations = model
|
||||
.surface_rows
|
||||
.get("balance")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "benefit_obligations")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(plan_assets.values.get("p1").copied().flatten(), Some(140.0));
|
||||
assert_eq!(obligations.values.get("p1").copied().flatten(), Some(125.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,4 +440,58 @@ mod tests {
|
||||
let core_bridge = load_income_bridge(FiscalPack::Core).expect("core bridge should load");
|
||||
assert_eq!(core_bridge.pack, "core");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loads_all_non_core_pack_assets() {
|
||||
let packs = [
|
||||
FiscalPack::BankLender,
|
||||
FiscalPack::Insurance,
|
||||
FiscalPack::ReitRealEstate,
|
||||
FiscalPack::BrokerAssetManager,
|
||||
FiscalPack::Agriculture,
|
||||
FiscalPack::ContractorsConstruction,
|
||||
FiscalPack::ContractorsFederalGovernment,
|
||||
FiscalPack::DevelopmentStage,
|
||||
FiscalPack::EntertainmentBroadcasters,
|
||||
FiscalPack::EntertainmentCableTelevision,
|
||||
FiscalPack::EntertainmentCasinos,
|
||||
FiscalPack::EntertainmentFilms,
|
||||
FiscalPack::EntertainmentMusic,
|
||||
FiscalPack::ExtractiveMining,
|
||||
FiscalPack::MortgageBanking,
|
||||
FiscalPack::TitlePlant,
|
||||
FiscalPack::Franchisors,
|
||||
FiscalPack::NotForProfit,
|
||||
FiscalPack::PlanDefinedBenefit,
|
||||
FiscalPack::PlanDefinedContribution,
|
||||
FiscalPack::PlanHealthWelfare,
|
||||
FiscalPack::RealEstateGeneral,
|
||||
FiscalPack::RealEstateCommonInterest,
|
||||
FiscalPack::RealEstateRetailLand,
|
||||
FiscalPack::RealEstateTimeSharing,
|
||||
FiscalPack::Software,
|
||||
FiscalPack::Steamship,
|
||||
];
|
||||
|
||||
for pack in packs {
|
||||
let surface_pack = load_surface_pack(pack)
|
||||
.unwrap_or_else(|error| panic!("surface pack {} failed: {error}", pack.as_str()));
|
||||
assert_eq!(surface_pack.pack, pack.as_str());
|
||||
assert!(
|
||||
!surface_pack.surfaces.is_empty(),
|
||||
"{} should define surfaces",
|
||||
pack.as_str()
|
||||
);
|
||||
|
||||
let bridge = load_income_bridge(pack)
|
||||
.unwrap_or_else(|error| panic!("income bridge {} failed: {error}", pack.as_str()));
|
||||
assert_eq!(bridge.pack, pack.as_str());
|
||||
assert!(bridge.rows.contains_key("revenue"));
|
||||
assert!(bridge.rows.contains_key("net_income"));
|
||||
|
||||
let kpi_pack = load_kpi_pack(pack)
|
||||
.unwrap_or_else(|error| panic!("kpi pack {} failed: {error}", pack.as_str()));
|
||||
assert_eq!(kpi_pack.pack, pack.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1800,6 +1800,113 @@ mod tests {
|
||||
assert_eq!(revenue.resolution_method.as_deref(), Some("direct"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_software_gross_profit_from_revenue_minus_cost_of_software_revenue() {
|
||||
let rows = empty_rows();
|
||||
let mut model = empty_model();
|
||||
model.surface_rows.get_mut("income").unwrap().extend([
|
||||
surface_row("revenue", 150.0),
|
||||
surface_row("cost_of_software_revenue", 45.0),
|
||||
]);
|
||||
|
||||
apply_universal_income_rows(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
&[],
|
||||
"us-gaap",
|
||||
FiscalPack::Software,
|
||||
&mut model,
|
||||
)
|
||||
.expect("software universal income rows should build");
|
||||
|
||||
let gross_profit = model
|
||||
.surface_rows
|
||||
.get("income")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "gross_profit")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
gross_profit.values.get("p1").copied().flatten(),
|
||||
Some(105.0)
|
||||
);
|
||||
assert_eq!(
|
||||
gross_profit.resolution_method.as_deref(),
|
||||
Some("formula_derived")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_development_stage_sga_from_general_and_administrative() {
|
||||
let rows = empty_rows();
|
||||
let mut model = empty_model();
|
||||
model
|
||||
.surface_rows
|
||||
.get_mut("income")
|
||||
.unwrap()
|
||||
.push(surface_row("general_and_administrative", 22.0));
|
||||
|
||||
apply_universal_income_rows(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
&[],
|
||||
"us-gaap",
|
||||
FiscalPack::DevelopmentStage,
|
||||
&mut model,
|
||||
)
|
||||
.expect("development stage universal income rows should build");
|
||||
|
||||
let sga = model
|
||||
.surface_rows
|
||||
.get("income")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "selling_general_and_administrative")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(sga.values.get("p1").copied().flatten(), Some(22.0));
|
||||
assert_eq!(sga.resolution_method.as_deref(), Some("formula_derived"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emits_not_meaningful_not_for_profit_net_income_row() {
|
||||
let rows = empty_rows();
|
||||
let mut model = empty_model();
|
||||
model.surface_rows.get_mut("income").unwrap().extend([
|
||||
surface_row("contribution_revenue", 120.0),
|
||||
surface_row("administrative_expense", 40.0),
|
||||
surface_row("change_in_net_assets", 80.0),
|
||||
]);
|
||||
|
||||
apply_universal_income_rows(
|
||||
&[period("p1")],
|
||||
&rows,
|
||||
&[],
|
||||
"us-gaap",
|
||||
FiscalPack::NotForProfit,
|
||||
&mut model,
|
||||
)
|
||||
.expect("not-for-profit universal income rows should build");
|
||||
|
||||
let net_income = model
|
||||
.surface_rows
|
||||
.get("income")
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|row| row.key == "net_income")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(net_income.values.get("p1").copied().flatten(), None);
|
||||
assert_eq!(
|
||||
net_income.resolution_method.as_deref(),
|
||||
Some("not_meaningful")
|
||||
);
|
||||
assert!(net_income
|
||||
.warning_codes
|
||||
.contains(&"net_income_not_meaningful_not_for_profit".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_income_tax_expense_from_pretax_income_minus_net_income() {
|
||||
let mut rows = empty_rows();
|
||||
|
||||
Reference in New Issue
Block a user