Add detailed cash flow statement line items
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use rig::completion::Message;
|
use rig::completion::Message;
|
||||||
|
|
||||||
@@ -304,21 +304,142 @@ fn compact_statement_period(period: &StatementPeriod) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compact_cash_flow_period(period: &CashFlowPeriod) -> Value {
|
fn compact_cash_flow_period(period: &CashFlowPeriod) -> Value {
|
||||||
json!({
|
let mut value = Map::new();
|
||||||
"label": truncate_text(&period.label),
|
value.insert("label".to_string(), json!(truncate_text(&period.label)));
|
||||||
"fiscalYear": period.fiscal_year,
|
value.insert("fiscalYear".to_string(), json!(&period.fiscal_year));
|
||||||
"fiscalPeriod": period.fiscal_period,
|
value.insert("fiscalPeriod".to_string(), json!(&period.fiscal_period));
|
||||||
"periodStart": period.period_start,
|
value.insert("periodStart".to_string(), json!(&period.period_start));
|
||||||
"periodEnd": period.period_end,
|
value.insert("periodEnd".to_string(), json!(&period.period_end));
|
||||||
"filedDate": period.filed_date,
|
value.insert("filedDate".to_string(), json!(&period.filed_date));
|
||||||
"form": period.form,
|
value.insert("form".to_string(), json!(&period.form));
|
||||||
"operatingCashFlow": period.operating_cash_flow,
|
value.insert("netIncome".to_string(), json!(period.net_income));
|
||||||
"investingCashFlow": period.investing_cash_flow,
|
value.insert(
|
||||||
"financingCashFlow": period.financing_cash_flow,
|
"depreciationAndAmortization".to_string(),
|
||||||
"capex": period.capex,
|
json!(period.depreciation_and_amortization),
|
||||||
"freeCashFlow": period.free_cash_flow,
|
);
|
||||||
"endingCash": period.ending_cash,
|
value.insert(
|
||||||
})
|
"stockBasedCompensation".to_string(),
|
||||||
|
json!(period.stock_based_compensation),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"deferredIncomeTaxes".to_string(),
|
||||||
|
json!(period.deferred_income_taxes),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"impairmentCharges".to_string(),
|
||||||
|
json!(period.impairment_charges),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"lossGainOnSaleOfAssets".to_string(),
|
||||||
|
json!(period.loss_gain_on_sale_of_assets),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"otherNonCashItems".to_string(),
|
||||||
|
json!(period.other_non_cash_items),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"accountsReceivable".to_string(),
|
||||||
|
json!(period.accounts_receivable),
|
||||||
|
);
|
||||||
|
value.insert("inventory".to_string(), json!(period.inventory));
|
||||||
|
value.insert(
|
||||||
|
"prepaidExpensesAndOtherCurrentAssets".to_string(),
|
||||||
|
json!(period.prepaid_expenses_and_other_current_assets),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"accountsPayable".to_string(),
|
||||||
|
json!(period.accounts_payable),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"accruedExpenses".to_string(),
|
||||||
|
json!(period.accrued_expenses),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"deferredRevenue".to_string(),
|
||||||
|
json!(period.deferred_revenue),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"otherWorkingCapitalChanges".to_string(),
|
||||||
|
json!(period.other_working_capital_changes),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"changeInOperatingAssets".to_string(),
|
||||||
|
json!(period.change_in_operating_assets),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"changeInOperatingLiabilities".to_string(),
|
||||||
|
json!(period.change_in_operating_liabilities),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"otherOperatingAdjustments".to_string(),
|
||||||
|
json!(period.other_operating_adjustments),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"operatingCashFlow".to_string(),
|
||||||
|
json!(period.operating_cash_flow),
|
||||||
|
);
|
||||||
|
value.insert("capex".to_string(), json!(period.capex));
|
||||||
|
value.insert(
|
||||||
|
"proceedsFromSaleOfPpe".to_string(),
|
||||||
|
json!(period.proceeds_from_sale_of_ppe),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"purchasesOfInvestments".to_string(),
|
||||||
|
json!(period.purchases_of_investments),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"salesOfInvestments".to_string(),
|
||||||
|
json!(period.sales_of_investments),
|
||||||
|
);
|
||||||
|
value.insert("acquisitions".to_string(), json!(period.acquisitions));
|
||||||
|
value.insert(
|
||||||
|
"otherInvestingActivities".to_string(),
|
||||||
|
json!(period.other_investing_activities),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"investingCashFlow".to_string(),
|
||||||
|
json!(period.investing_cash_flow),
|
||||||
|
);
|
||||||
|
value.insert("debtIssuance".to_string(), json!(period.debt_issuance));
|
||||||
|
value.insert("debtRepayment".to_string(), json!(period.debt_repayment));
|
||||||
|
value.insert("equityIssuance".to_string(), json!(period.equity_issuance));
|
||||||
|
value.insert(
|
||||||
|
"stockRepurchases".to_string(),
|
||||||
|
json!(period.stock_repurchases),
|
||||||
|
);
|
||||||
|
value.insert("dividendsPaid".to_string(), json!(period.dividends_paid));
|
||||||
|
value.insert(
|
||||||
|
"financeLeaseObligations".to_string(),
|
||||||
|
json!(period.finance_lease_obligations),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"otherFinancingActivities".to_string(),
|
||||||
|
json!(period.other_financing_activities),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"financingCashFlow".to_string(),
|
||||||
|
json!(period.financing_cash_flow),
|
||||||
|
);
|
||||||
|
value.insert("freeCashFlow".to_string(), json!(period.free_cash_flow));
|
||||||
|
value.insert(
|
||||||
|
"exchangeRateEffects".to_string(),
|
||||||
|
json!(period.exchange_rate_effects),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"netIncreaseDecreaseCash".to_string(),
|
||||||
|
json!(period.net_increase_decrease_cash),
|
||||||
|
);
|
||||||
|
value.insert("beginningCash".to_string(), json!(period.beginning_cash));
|
||||||
|
value.insert("endingCash".to_string(), json!(period.ending_cash));
|
||||||
|
value.insert(
|
||||||
|
"cashPaidInterest".to_string(),
|
||||||
|
json!(period.cash_paid_interest),
|
||||||
|
);
|
||||||
|
value.insert(
|
||||||
|
"cashPaidIncomeTaxes".to_string(),
|
||||||
|
json!(period.cash_paid_income_taxes),
|
||||||
|
);
|
||||||
|
Value::Object(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compact_dividend_event(event: &DividendEvent) -> Value {
|
fn compact_dividend_event(event: &DividendEvent) -> Value {
|
||||||
@@ -794,12 +915,46 @@ mod tests {
|
|||||||
period_end: "2025-12-31".to_string(),
|
period_end: "2025-12-31".to_string(),
|
||||||
filed_date: "2026-01-31".to_string(),
|
filed_date: "2026-01-31".to_string(),
|
||||||
form: "10-K".to_string(),
|
form: "10-K".to_string(),
|
||||||
|
net_income: Some(30.0),
|
||||||
|
depreciation_and_amortization: Some(15.0),
|
||||||
|
stock_based_compensation: Some(5.0),
|
||||||
|
deferred_income_taxes: Some(2.0),
|
||||||
|
impairment_charges: None,
|
||||||
|
loss_gain_on_sale_of_assets: None,
|
||||||
|
other_non_cash_items: Some(1.0),
|
||||||
|
accounts_receivable: Some(-4.0),
|
||||||
|
inventory: Some(-2.0),
|
||||||
|
prepaid_expenses_and_other_current_assets: Some(-1.0),
|
||||||
|
accounts_payable: Some(3.0),
|
||||||
|
accrued_expenses: Some(2.0),
|
||||||
|
deferred_revenue: Some(1.0),
|
||||||
|
other_working_capital_changes: None,
|
||||||
|
change_in_operating_assets: Some(-8.0),
|
||||||
|
change_in_operating_liabilities: Some(3.0),
|
||||||
|
other_operating_adjustments: None,
|
||||||
operating_cash_flow: Some(100.0),
|
operating_cash_flow: Some(100.0),
|
||||||
investing_cash_flow: Some(-50.0),
|
|
||||||
financing_cash_flow: Some(-25.0),
|
|
||||||
capex: Some(-10.0),
|
capex: Some(-10.0),
|
||||||
|
proceeds_from_sale_of_ppe: Some(1.0),
|
||||||
|
purchases_of_investments: Some(-40.0),
|
||||||
|
sales_of_investments: Some(20.0),
|
||||||
|
acquisitions: None,
|
||||||
|
other_investing_activities: None,
|
||||||
|
investing_cash_flow: Some(-50.0),
|
||||||
|
debt_issuance: Some(50.0),
|
||||||
|
debt_repayment: Some(-30.0),
|
||||||
|
equity_issuance: Some(10.0),
|
||||||
|
stock_repurchases: Some(-15.0),
|
||||||
|
dividends_paid: Some(-20.0),
|
||||||
|
finance_lease_obligations: Some(-5.0),
|
||||||
|
other_financing_activities: None,
|
||||||
|
financing_cash_flow: Some(-25.0),
|
||||||
free_cash_flow: Some(90.0),
|
free_cash_flow: Some(90.0),
|
||||||
|
exchange_rate_effects: None,
|
||||||
|
net_increase_decrease_cash: Some(5.0),
|
||||||
|
beginning_cash: Some(15.0),
|
||||||
ending_cash: Some(20.0),
|
ending_cash: Some(20.0),
|
||||||
|
cash_paid_interest: Some(4.0),
|
||||||
|
cash_paid_income_taxes: Some(6.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,375 @@ pub(crate) const CAPEX_CONCEPTS: &[ConceptCandidate] = &[
|
|||||||
UnitFamily::Currency,
|
UnitFamily::Currency,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
pub(crate) const NET_INCOME_CF_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "NetIncomeLoss", UnitFamily::Currency),
|
||||||
|
candidate("ifrs-full", "ProfitLoss", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const DEPRECIATION_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"DepreciationDepletionAndAmortization",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"DepreciationAndAmortization",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"ifrs-full",
|
||||||
|
"DepreciationAndAmortisation",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const STOCK_BASED_COMPENSATION_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "ShareBasedCompensation", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "StockCompensationExpense", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const DEFERRED_INCOME_TAXES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"DeferredIncomeTaxExpenseBenefit",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"DeferredIncomeTaxesAndTaxCredits",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInDeferredIncomeTaxes",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const IMPAIRMENT_CHARGES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "AssetImpairmentCharges", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "GoodwillImpairmentLosses", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ImpairmentOfGoodwillAndIndefiniteLivedIntangibleAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const LOSS_GAIN_ON_SALE_OF_ASSETS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "LossGainOnSaleOfAssets", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"GainLossOnSaleOfPropertyPlantEquipment",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"GainLossOnDispositionOfAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const OTHER_NON_CASH_ITEMS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "OtherNoncashIncomeExpense", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "OtherNoncashExpense", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherNoncashItemsIncludedInNetIncomeLoss",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const ACCOUNTS_RECEIVABLE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccountsReceivable",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ChangesInAccountReceivables",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const INVENTORY_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInInventories",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "ChangesInInventories", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const PREPAIDS_AND_OTHER_CURRENT_ASSETS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInPrepaidDeferredExpenseAndOtherAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInPrepaidExpenseAndOtherAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInOtherCurrentAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const ACCOUNTS_PAYABLE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccountsPayable",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "ChangesInAccountPayables", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const ACCRUED_EXPENSES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccruedLiabilities",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccruedExpenses",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccruedIncomeTaxesPayable",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const DEFERRED_REVENUE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInContractWithCustomerLiability",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInDeferredRevenue",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const OTHER_WORKING_CAPITAL_CHANGES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInOperatingCapital",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInOperatingAssetsAndLiabilitiesNet",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherAssetsAndLiabilitiesNet",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const CHANGE_IN_OPERATING_ASSETS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccountsReceivable",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ChangesInAccountReceivables",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const CHANGE_IN_OPERATING_LIABILITIES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"IncreaseDecreaseInAccountsPayable",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "ChangesInAccountPayables", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const OTHER_OPERATING_ADJUSTMENTS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherAdjustmentsToReconcileNetIncomeLossToCashProvidedByUsedInOperatingActivities",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "OtherNoncashIncomeExpense", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const PROCEEDS_FROM_SALE_OF_PPE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromSaleOfPropertyPlantAndEquipment",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromSaleOfPropertyPlantAndEquipmentAndIntangibleAssets",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const PURCHASES_OF_INVESTMENTS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "PaymentsForInvestments", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "PurchaseOfInvestments", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsToAcquireInvestments",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const SALES_OF_INVESTMENTS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromSaleOfInvestments",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "MaturitiesOfInvestments", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const ACQUISITIONS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsToAcquireBusinessesNetOfCashAcquired",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsToAcquireBusinesses",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsMadeForAcquisitionOfBusiness",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const OTHER_INVESTING_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherCashPaymentsForInvestingActivities",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherInvestingActivitiesNetCashFlow",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const DEBT_ISSUANCE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromIssuanceOfDebt",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromIssuanceOfLongTermDebt",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const DEBT_REPAYMENT_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "PaymentsOfLongTermDebt", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "RepaymentsOfLongTermDebt", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "RepaymentsOfDebt", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const EQUITY_ISSUANCE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromIssuanceOfCommonStock",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromStockOptionsExercised",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"ProceedsFromIssuanceOfSharesUnderIncentiveAndShareBasedCompensationPlansIncludingStockOptions",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const STOCK_REPURCHASES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsForRepurchaseOfCommonStock",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("us-gaap", "RepurchaseOfCommonStock", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsForRepurchaseOfTreasuryStock",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const DIVIDENDS_PAID_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "PaymentsOfDividends", UnitFamily::Currency),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsOfDividendsCommonStock",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const FINANCE_LEASE_OBLIGATIONS_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsOfFinanceLeaseObligations",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"PaymentsOfCapitalLeaseObligations",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const OTHER_FINANCING_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherCashPaymentsForFinancingActivities",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"OtherFinancingActivitiesNetCashFlow",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const EXCHANGE_RATE_EFFECTS_CONCEPTS: &[ConceptCandidate] = &[candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"EffectOfExchangeRateOnCashAndCashEquivalents",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
)];
|
||||||
|
pub(crate) const NET_INCREASE_DECREASE_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalentsPeriodIncreaseDecreaseIncludingExchangeRateEffect",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"CashAndCashEquivalentsPeriodIncreaseDecrease",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"ifrs-full",
|
||||||
|
"IncreaseDecreaseInCashAndCashEquivalents",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
pub(crate) const BEGINNING_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalentsAtBeginningOfPeriod",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"CashAndCashEquivalentsAtBeginningOfPeriod",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate(
|
||||||
|
"us-gaap",
|
||||||
|
"CashAndCashEquivalentsAtCarryingValue",
|
||||||
|
UnitFamily::Currency,
|
||||||
|
),
|
||||||
|
candidate("ifrs-full", "CashAndCashEquivalents", UnitFamily::Currency),
|
||||||
|
];
|
||||||
pub(crate) const ENDING_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
pub(crate) const ENDING_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
candidate(
|
candidate(
|
||||||
"us-gaap",
|
"us-gaap",
|
||||||
@@ -163,6 +532,18 @@ pub(crate) const ENDING_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
|||||||
),
|
),
|
||||||
candidate("ifrs-full", "CashAndCashEquivalents", UnitFamily::Currency),
|
candidate("ifrs-full", "CashAndCashEquivalents", UnitFamily::Currency),
|
||||||
];
|
];
|
||||||
|
pub(crate) const CASH_PAID_INTEREST_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "InterestPaidNet", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "InterestPaid", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "CashPaidForInterest", UnitFamily::Currency),
|
||||||
|
candidate("ifrs-full", "InterestPaid", UnitFamily::Currency),
|
||||||
|
];
|
||||||
|
pub(crate) const CASH_PAID_INCOME_TAXES_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
|
candidate("us-gaap", "IncomeTaxesPaidNet", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "IncomeTaxesPaid", UnitFamily::Currency),
|
||||||
|
candidate("us-gaap", "CashPaidForIncomeTaxes", UnitFamily::Currency),
|
||||||
|
candidate("ifrs-full", "IncomeTaxesPaid", UnitFamily::Currency),
|
||||||
|
];
|
||||||
pub(crate) const DIVIDEND_PER_SHARE_CONCEPTS: &[ConceptCandidate] = &[
|
pub(crate) const DIVIDEND_PER_SHARE_CONCEPTS: &[ConceptCandidate] = &[
|
||||||
candidate(
|
candidate(
|
||||||
"us-gaap",
|
"us-gaap",
|
||||||
@@ -309,15 +690,184 @@ pub(crate) fn build_cash_flow_periods(
|
|||||||
period_end: row.period_end.clone(),
|
period_end: row.period_end.clone(),
|
||||||
filed_date: row.filed_date.clone(),
|
filed_date: row.filed_date.clone(),
|
||||||
form: row.form.clone(),
|
form: row.form.clone(),
|
||||||
|
net_income: value_for_period(facts, &row, NET_INCOME_CF_CONCEPTS, latest_xbrl),
|
||||||
|
depreciation_and_amortization: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
DEPRECIATION_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
stock_based_compensation: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
STOCK_BASED_COMPENSATION_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
deferred_income_taxes: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
DEFERRED_INCOME_TAXES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
impairment_charges: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
IMPAIRMENT_CHARGES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
loss_gain_on_sale_of_assets: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
LOSS_GAIN_ON_SALE_OF_ASSETS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
other_non_cash_items: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
OTHER_NON_CASH_ITEMS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
accounts_receivable: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
ACCOUNTS_RECEIVABLE_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
inventory: value_for_period(facts, &row, INVENTORY_CONCEPTS, latest_xbrl),
|
||||||
|
prepaid_expenses_and_other_current_assets: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
PREPAIDS_AND_OTHER_CURRENT_ASSETS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
accounts_payable: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
ACCOUNTS_PAYABLE_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
accrued_expenses: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
ACCRUED_EXPENSES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
deferred_revenue: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
DEFERRED_REVENUE_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
other_working_capital_changes: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
OTHER_WORKING_CAPITAL_CHANGES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
change_in_operating_assets: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
CHANGE_IN_OPERATING_ASSETS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
change_in_operating_liabilities: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
CHANGE_IN_OPERATING_LIABILITIES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
other_operating_adjustments: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
OTHER_OPERATING_ADJUSTMENTS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
operating_cash_flow,
|
operating_cash_flow,
|
||||||
investing_cash_flow: value_for_period(facts, &row, CFI_CONCEPTS, latest_xbrl),
|
|
||||||
financing_cash_flow: value_for_period(facts, &row, CFF_CONCEPTS, latest_xbrl),
|
|
||||||
capex,
|
capex,
|
||||||
|
proceeds_from_sale_of_ppe: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
PROCEEDS_FROM_SALE_OF_PPE_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
purchases_of_investments: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
PURCHASES_OF_INVESTMENTS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
sales_of_investments: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
SALES_OF_INVESTMENTS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
acquisitions: value_for_period(facts, &row, ACQUISITIONS_CONCEPTS, latest_xbrl),
|
||||||
|
other_investing_activities: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
OTHER_INVESTING_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
investing_cash_flow: value_for_period(facts, &row, CFI_CONCEPTS, latest_xbrl),
|
||||||
|
debt_issuance: value_for_period(facts, &row, DEBT_ISSUANCE_CONCEPTS, latest_xbrl),
|
||||||
|
debt_repayment: value_for_period(facts, &row, DEBT_REPAYMENT_CONCEPTS, latest_xbrl),
|
||||||
|
equity_issuance: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
EQUITY_ISSUANCE_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
stock_repurchases: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
STOCK_REPURCHASES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
dividends_paid: value_for_period(facts, &row, DIVIDENDS_PAID_CONCEPTS, latest_xbrl),
|
||||||
|
finance_lease_obligations: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
FINANCE_LEASE_OBLIGATIONS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
other_financing_activities: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
OTHER_FINANCING_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
financing_cash_flow: value_for_period(facts, &row, CFF_CONCEPTS, latest_xbrl),
|
||||||
free_cash_flow: match (operating_cash_flow, capex) {
|
free_cash_flow: match (operating_cash_flow, capex) {
|
||||||
(Some(cfo), Some(capex)) => Some(cfo - capex.abs()),
|
(Some(cfo), Some(capex)) => Some(cfo - capex.abs()),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
exchange_rate_effects: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
EXCHANGE_RATE_EFFECTS_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
net_increase_decrease_cash: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
NET_INCREASE_DECREASE_CASH_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
beginning_cash: value_for_period(facts, &row, BEGINNING_CASH_CONCEPTS, latest_xbrl),
|
||||||
ending_cash: value_for_period(facts, &row, ENDING_CASH_CONCEPTS, latest_xbrl),
|
ending_cash: value_for_period(facts, &row, ENDING_CASH_CONCEPTS, latest_xbrl),
|
||||||
|
cash_paid_interest: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
CASH_PAID_INTEREST_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
|
cash_paid_income_taxes: value_for_period(
|
||||||
|
facts,
|
||||||
|
&row,
|
||||||
|
CASH_PAID_INCOME_TAXES_CONCEPTS,
|
||||||
|
latest_xbrl,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -297,12 +297,50 @@ pub struct CashFlowPeriod {
|
|||||||
pub period_end: String,
|
pub period_end: String,
|
||||||
pub filed_date: String,
|
pub filed_date: String,
|
||||||
pub form: String,
|
pub form: String,
|
||||||
|
// Operating Activities
|
||||||
|
pub net_income: Option<f64>,
|
||||||
|
pub depreciation_and_amortization: Option<f64>,
|
||||||
|
pub stock_based_compensation: Option<f64>,
|
||||||
|
pub deferred_income_taxes: Option<f64>,
|
||||||
|
pub impairment_charges: Option<f64>,
|
||||||
|
pub loss_gain_on_sale_of_assets: Option<f64>,
|
||||||
|
pub other_non_cash_items: Option<f64>,
|
||||||
|
pub accounts_receivable: Option<f64>,
|
||||||
|
pub inventory: Option<f64>,
|
||||||
|
pub prepaid_expenses_and_other_current_assets: Option<f64>,
|
||||||
|
pub accounts_payable: Option<f64>,
|
||||||
|
pub accrued_expenses: Option<f64>,
|
||||||
|
pub deferred_revenue: Option<f64>,
|
||||||
|
pub other_working_capital_changes: Option<f64>,
|
||||||
|
pub change_in_operating_assets: Option<f64>,
|
||||||
|
pub change_in_operating_liabilities: Option<f64>,
|
||||||
|
pub other_operating_adjustments: Option<f64>,
|
||||||
pub operating_cash_flow: Option<f64>,
|
pub operating_cash_flow: Option<f64>,
|
||||||
pub investing_cash_flow: Option<f64>,
|
// Investing Activities
|
||||||
pub financing_cash_flow: Option<f64>,
|
|
||||||
pub capex: Option<f64>,
|
pub capex: Option<f64>,
|
||||||
|
pub proceeds_from_sale_of_ppe: Option<f64>,
|
||||||
|
pub purchases_of_investments: Option<f64>,
|
||||||
|
pub sales_of_investments: Option<f64>,
|
||||||
|
pub acquisitions: Option<f64>,
|
||||||
|
pub other_investing_activities: Option<f64>,
|
||||||
|
pub investing_cash_flow: Option<f64>,
|
||||||
|
// Financing Activities
|
||||||
|
pub debt_issuance: Option<f64>,
|
||||||
|
pub debt_repayment: Option<f64>,
|
||||||
|
pub equity_issuance: Option<f64>,
|
||||||
|
pub stock_repurchases: Option<f64>,
|
||||||
|
pub dividends_paid: Option<f64>,
|
||||||
|
pub finance_lease_obligations: Option<f64>,
|
||||||
|
pub other_financing_activities: Option<f64>,
|
||||||
|
pub financing_cash_flow: Option<f64>,
|
||||||
|
// Summary
|
||||||
pub free_cash_flow: Option<f64>,
|
pub free_cash_flow: Option<f64>,
|
||||||
|
pub exchange_rate_effects: Option<f64>,
|
||||||
|
pub net_increase_decrease_cash: Option<f64>,
|
||||||
|
pub beginning_cash: Option<f64>,
|
||||||
pub ending_cash: Option<f64>,
|
pub ending_cash: Option<f64>,
|
||||||
|
pub cash_paid_interest: Option<f64>,
|
||||||
|
pub cash_paid_income_taxes: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||||
|
|||||||
@@ -1,11 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CashFlowPanelData } from '../../types/financial';
|
import { CashFlowPanelData } from '../../types/financial';
|
||||||
import { StatementTableMinimal, formatMoney } from '../ui/StatementTableMinimal';
|
import { formatMoney } from '../ui/StatementTableMinimal';
|
||||||
|
|
||||||
interface CashFlowPanelProps {
|
interface CashFlowPanelProps {
|
||||||
data: CashFlowPanelData;
|
data: CashFlowPanelData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CashFlowRow = CashFlowPanelData['periods'][number];
|
||||||
|
|
||||||
|
interface SectionHeader {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
isSectionHeader: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MetricRow {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
indent?: boolean;
|
||||||
|
isSectionHeader?: false;
|
||||||
|
render: (period: CashFlowRow) => React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
type CashFlowMetric = SectionHeader | MetricRow;
|
||||||
|
|
||||||
const SourceAttribution: React.FC<{ status: CashFlowPanelData['sourceStatus'] }> = ({ status }) => {
|
const SourceAttribution: React.FC<{ status: CashFlowPanelData['sourceStatus'] }> = ({ status }) => {
|
||||||
return (
|
return (
|
||||||
<div className="text-[11px] font-mono text-term-text-muted">
|
<div className="text-[11px] font-mono text-term-text-muted">
|
||||||
@@ -17,10 +35,226 @@ const SourceAttribution: React.FC<{ status: CashFlowPanelData['sourceStatus'] }>
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const metrics: CashFlowMetric[] = [
|
||||||
|
{ key: 'section-operating', label: 'Operating Activities', isSectionHeader: true },
|
||||||
|
{
|
||||||
|
key: 'netIncome',
|
||||||
|
label: 'Net Income / Net Earnings',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.netIncome),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'depreciationAndAmortization',
|
||||||
|
label: 'Depreciation & Amortization',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.depreciationAndAmortization),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stockBasedCompensation',
|
||||||
|
label: 'Stock-Based Compensation',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.stockBasedCompensation),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'deferredIncomeTaxes',
|
||||||
|
label: 'Deferred Income Taxes',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.deferredIncomeTaxes),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'impairmentCharges',
|
||||||
|
label: 'Impairment Charges',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.impairmentCharges),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'lossGainOnSaleOfAssets',
|
||||||
|
label: 'Loss / Gain on Sale of Assets',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.lossGainOnSaleOfAssets),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'otherNonCashItems',
|
||||||
|
label: 'Other Non-Cash Items',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.otherNonCashItems),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'accountsReceivable',
|
||||||
|
label: 'Accounts Receivable',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.accountsReceivable),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'inventory',
|
||||||
|
label: 'Inventory',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.inventory),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'prepaidExpensesAndOtherCurrentAssets',
|
||||||
|
label: 'Prepaid Expenses and Other Current Assets',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.prepaidExpensesAndOtherCurrentAssets),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'accountsPayable',
|
||||||
|
label: 'Accounts Payable',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.accountsPayable),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'accruedExpenses',
|
||||||
|
label: 'Accrued Expenses',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.accruedExpenses),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'deferredRevenue',
|
||||||
|
label: 'Deferred Revenue',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.deferredRevenue),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'otherWorkingCapitalChanges',
|
||||||
|
label: 'Other Working Capital Changes',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.otherWorkingCapitalChanges),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operatingCashFlow',
|
||||||
|
label: 'Net Cash Provided by Operating Activities',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.operatingCashFlow),
|
||||||
|
},
|
||||||
|
{ key: 'section-investing', label: 'Investing Activities', isSectionHeader: true },
|
||||||
|
{
|
||||||
|
key: 'capex',
|
||||||
|
label: 'Capital Expenditures / Purchases of Property and Equipment',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.capex),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'proceedsFromSaleOfPpe',
|
||||||
|
label: 'Proceeds from Sale of Property and Equipment',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.proceedsFromSaleOfPpe),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'acquisitions',
|
||||||
|
label: 'Acquisitions, Net of Cash Acquired',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.acquisitions),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'purchasesOfInvestments',
|
||||||
|
label: 'Purchases of Investments',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.purchasesOfInvestments),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'salesOfInvestments',
|
||||||
|
label: 'Proceeds from Sale or Maturity of Investments',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.salesOfInvestments),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'otherInvestingActivities',
|
||||||
|
label: 'Other Investing Activities',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.otherInvestingActivities),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'investingCashFlow',
|
||||||
|
label: 'Net Cash Used in Investing Activities',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.investingCashFlow),
|
||||||
|
},
|
||||||
|
{ key: 'section-financing', label: 'Financing Activities', isSectionHeader: true },
|
||||||
|
{
|
||||||
|
key: 'debtIssuance',
|
||||||
|
label: 'Proceeds from Debt Issuance',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.debtIssuance),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'debtRepayment',
|
||||||
|
label: 'Repayments of Debt',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.debtRepayment),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'equityIssuance',
|
||||||
|
label: 'Proceeds from Equity Issuance',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.equityIssuance),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stockRepurchases',
|
||||||
|
label: 'Repurchases of Common Stock',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.stockRepurchases),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dividendsPaid',
|
||||||
|
label: 'Dividends Paid',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.dividendsPaid),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'financeLeaseObligations',
|
||||||
|
label: 'Payment of Finance Lease Obligations',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.financeLeaseObligations),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'otherFinancingActivities',
|
||||||
|
label: 'Other Financing Activities',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.otherFinancingActivities),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'financingCashFlow',
|
||||||
|
label: 'Net Cash Provided by / Used in Financing Activities',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.financingCashFlow),
|
||||||
|
},
|
||||||
|
{ key: 'section-summary', label: 'Supplemental / Other Cash Flow', isSectionHeader: true },
|
||||||
|
{
|
||||||
|
key: 'exchangeRateEffects',
|
||||||
|
label: 'Effect of Exchange Rate Changes on Cash',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.exchangeRateEffects),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'netIncreaseDecreaseCash',
|
||||||
|
label: 'Net Increase / Decrease in Cash and Cash Equivalents',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.netIncreaseDecreaseCash),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'beginningCash',
|
||||||
|
label: 'Cash and Cash Equivalents at Beginning of Period',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.beginningCash),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'endingCash',
|
||||||
|
label: 'Cash and Cash Equivalents at End of Period',
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.endingCash),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'cashPaidInterest',
|
||||||
|
label: 'Cash Paid for Interest',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.cashPaidInterest),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'cashPaidIncomeTaxes',
|
||||||
|
label: 'Cash Paid for Income Taxes',
|
||||||
|
indent: true,
|
||||||
|
render: (period: CashFlowRow) => formatMoney(period.cashPaidIncomeTaxes),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const CashFlowPanel: React.FC<CashFlowPanelProps> = ({ data }) => {
|
export const CashFlowPanel: React.FC<CashFlowPanelProps> = ({ data }) => {
|
||||||
return (
|
return (
|
||||||
<div className="cashflow-panel py-4 overflow-auto">
|
<div className="cashflow-panel py-4 overflow-auto">
|
||||||
{/* Header - Minimal */}
|
|
||||||
<header className="mb-4">
|
<header className="mb-4">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -40,22 +274,61 @@ export const CashFlowPanel: React.FC<CashFlowPanelProps> = ({ data }) => {
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Table - Minimal styling */}
|
|
||||||
<section>
|
<section>
|
||||||
<StatementTableMinimal
|
<div className="overflow-x-auto">
|
||||||
periods={data.periods}
|
<table className="min-w-full border-collapse font-mono text-sm">
|
||||||
metrics={[
|
<thead className="text-term-text-muted">
|
||||||
{ key: 'cfo', label: 'Operating Cash Flow', render: (period) => formatMoney(period.operatingCashFlow) },
|
<tr className="border-b border-term-border-subtle">
|
||||||
{ key: 'cfi', label: 'Investing Cash Flow', render: (period) => formatMoney(period.investingCashFlow) },
|
<th className="sticky left-0 border-r border-term-border-subtle bg-term-bg px-3 py-2 text-left text-[10px] uppercase tracking-[0.18em]">
|
||||||
{ key: 'cff', label: 'Financing Cash Flow', render: (period) => formatMoney(period.financingCashFlow) },
|
Item
|
||||||
{ key: 'capex', label: 'Capex', render: (period) => formatMoney(period.capex) },
|
</th>
|
||||||
{ key: 'fcf', label: 'Free Cash Flow', render: (period) => formatMoney(period.freeCashFlow) },
|
{data.periods.map((period) => (
|
||||||
{ key: 'endingCash', label: 'Ending Cash', render: (period) => formatMoney(period.endingCash) },
|
<th
|
||||||
]}
|
key={period.label}
|
||||||
/>
|
className="border-b border-term-border-subtle px-3 py-2 text-right text-[10px] uppercase tracking-[0.18em]"
|
||||||
|
>
|
||||||
|
{period.label}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{metrics.map((metric) => {
|
||||||
|
if (metric.isSectionHeader) {
|
||||||
|
return (
|
||||||
|
<tr key={metric.key} className="border-b border-term-border-subtle">
|
||||||
|
<th
|
||||||
|
colSpan={data.periods.length + 1}
|
||||||
|
className="bg-term-bg-secondary px-3 py-2 text-left text-[10px] uppercase tracking-[0.18em] font-semibold text-term-text-muted"
|
||||||
|
>
|
||||||
|
{metric.label}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelClass = metric.indent
|
||||||
|
? 'pl-6 font-normal text-term-text-muted'
|
||||||
|
: 'font-medium text-term-text';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr key={metric.key} className="border-b border-term-border-subtle last:border-b-0">
|
||||||
|
<th className={`sticky left-0 border-r border-term-border-subtle bg-term-bg px-3 py-2 text-left text-term-text ${labelClass}`}>
|
||||||
|
{metric.label}
|
||||||
|
</th>
|
||||||
|
{data.periods.map((period) => (
|
||||||
|
<td key={`${metric.key}-${period.label}`} className="px-3 py-2 text-right text-term-text">
|
||||||
|
<span className="inline-block">{metric.render(period)}</span>
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Footer - Minimal attribution */}
|
|
||||||
<footer className="mt-4 border-t border-term-border-subtle pt-4">
|
<footer className="mt-4 border-t border-term-border-subtle pt-4">
|
||||||
<SourceAttribution status={data.sourceStatus} />
|
<SourceAttribution status={data.sourceStatus} />
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -118,15 +118,35 @@ const summarizeCashFlow = (panel: CashFlowPanelData, sourceCommand?: string) =>
|
|||||||
const rows = latest
|
const rows = latest
|
||||||
? [
|
? [
|
||||||
`Latest period: ${latest.label}.`,
|
`Latest period: ${latest.label}.`,
|
||||||
|
latest.netIncome != null ? `Net income: ${latest.netIncome.toLocaleString()}.` : null,
|
||||||
|
latest.depreciationAndAmortization != null
|
||||||
|
? `Depreciation & amortization: ${latest.depreciationAndAmortization.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
latest.operatingCashFlow != null
|
latest.operatingCashFlow != null
|
||||||
? `Operating cash flow: ${latest.operatingCashFlow.toLocaleString()}.`
|
? `Operating cash flow: ${latest.operatingCashFlow.toLocaleString()}.`
|
||||||
: null,
|
: null,
|
||||||
|
latest.capex != null ? `Capital expenditures: ${latest.capex.toLocaleString()}.` : null,
|
||||||
latest.freeCashFlow != null
|
latest.freeCashFlow != null
|
||||||
? `Free cash flow: ${latest.freeCashFlow.toLocaleString()}.`
|
? `Free cash flow: ${latest.freeCashFlow.toLocaleString()}.`
|
||||||
: null,
|
: null,
|
||||||
|
latest.investingCashFlow != null
|
||||||
|
? `Investing cash flow: ${latest.investingCashFlow.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
|
latest.financingCashFlow != null
|
||||||
|
? `Financing cash flow: ${latest.financingCashFlow.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
|
latest.dividendsPaid != null
|
||||||
|
? `Dividends paid: ${latest.dividendsPaid.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
|
latest.stockRepurchases != null
|
||||||
|
? `Stock repurchases: ${latest.stockRepurchases.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
|
latest.endingCash != null
|
||||||
|
? `Ending cash: ${latest.endingCash.toLocaleString()}.`
|
||||||
|
: null,
|
||||||
].filter(Boolean) as string[]
|
].filter(Boolean) as string[]
|
||||||
: ['No cash flow rows loaded.'];
|
: ['No cash flow rows loaded.'];
|
||||||
return summarizeStatementPanel('cash flow summary', panel.symbol, panel.latestFiling, rows, sourceCommand);
|
return summarizeStatementPanel('cash flow statement', panel.symbol, panel.latestFiling, rows, sourceCommand);
|
||||||
};
|
};
|
||||||
|
|
||||||
const summarizeDividends = (panel: DividendsPanelData, sourceCommand?: string) =>
|
const summarizeDividends = (panel: DividendsPanelData, sourceCommand?: string) =>
|
||||||
|
|||||||
@@ -175,12 +175,50 @@ export interface CashFlowPeriod {
|
|||||||
periodEnd: string;
|
periodEnd: string;
|
||||||
filedDate: string;
|
filedDate: string;
|
||||||
form: string;
|
form: string;
|
||||||
|
// Operating Activities
|
||||||
|
netIncome?: number;
|
||||||
|
depreciationAndAmortization?: number;
|
||||||
|
stockBasedCompensation?: number;
|
||||||
|
deferredIncomeTaxes?: number;
|
||||||
|
impairmentCharges?: number;
|
||||||
|
lossGainOnSaleOfAssets?: number;
|
||||||
|
otherNonCashItems?: number;
|
||||||
|
accountsReceivable?: number;
|
||||||
|
inventory?: number;
|
||||||
|
prepaidExpensesAndOtherCurrentAssets?: number;
|
||||||
|
accountsPayable?: number;
|
||||||
|
accruedExpenses?: number;
|
||||||
|
deferredRevenue?: number;
|
||||||
|
otherWorkingCapitalChanges?: number;
|
||||||
|
changeInOperatingAssets?: number;
|
||||||
|
changeInOperatingLiabilities?: number;
|
||||||
|
otherOperatingAdjustments?: number;
|
||||||
operatingCashFlow?: number;
|
operatingCashFlow?: number;
|
||||||
investingCashFlow?: number;
|
// Investing Activities
|
||||||
financingCashFlow?: number;
|
|
||||||
capex?: number;
|
capex?: number;
|
||||||
|
proceedsFromSaleOfPpe?: number;
|
||||||
|
purchasesOfInvestments?: number;
|
||||||
|
salesOfInvestments?: number;
|
||||||
|
acquisitions?: number;
|
||||||
|
otherInvestingActivities?: number;
|
||||||
|
investingCashFlow?: number;
|
||||||
|
// Financing Activities
|
||||||
|
debtIssuance?: number;
|
||||||
|
debtRepayment?: number;
|
||||||
|
equityIssuance?: number;
|
||||||
|
stockRepurchases?: number;
|
||||||
|
dividendsPaid?: number;
|
||||||
|
financeLeaseObligations?: number;
|
||||||
|
otherFinancingActivities?: number;
|
||||||
|
financingCashFlow?: number;
|
||||||
|
// Summary
|
||||||
freeCashFlow?: number;
|
freeCashFlow?: number;
|
||||||
|
exchangeRateEffects?: number;
|
||||||
|
netIncreaseDecreaseCash?: number;
|
||||||
|
beginningCash?: number;
|
||||||
endingCash?: number;
|
endingCash?: number;
|
||||||
|
cashPaidInterest?: number;
|
||||||
|
cashPaidIncomeTaxes?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DividendEvent {
|
export interface DividendEvent {
|
||||||
|
|||||||
Reference in New Issue
Block a user