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;
|
||||
|
||||
@@ -304,21 +304,142 @@ fn compact_statement_period(period: &StatementPeriod) -> Value {
|
||||
}
|
||||
|
||||
fn compact_cash_flow_period(period: &CashFlowPeriod) -> Value {
|
||||
json!({
|
||||
"label": truncate_text(&period.label),
|
||||
"fiscalYear": period.fiscal_year,
|
||||
"fiscalPeriod": period.fiscal_period,
|
||||
"periodStart": period.period_start,
|
||||
"periodEnd": period.period_end,
|
||||
"filedDate": period.filed_date,
|
||||
"form": period.form,
|
||||
"operatingCashFlow": period.operating_cash_flow,
|
||||
"investingCashFlow": period.investing_cash_flow,
|
||||
"financingCashFlow": period.financing_cash_flow,
|
||||
"capex": period.capex,
|
||||
"freeCashFlow": period.free_cash_flow,
|
||||
"endingCash": period.ending_cash,
|
||||
})
|
||||
let mut value = Map::new();
|
||||
value.insert("label".to_string(), json!(truncate_text(&period.label)));
|
||||
value.insert("fiscalYear".to_string(), json!(&period.fiscal_year));
|
||||
value.insert("fiscalPeriod".to_string(), json!(&period.fiscal_period));
|
||||
value.insert("periodStart".to_string(), json!(&period.period_start));
|
||||
value.insert("periodEnd".to_string(), json!(&period.period_end));
|
||||
value.insert("filedDate".to_string(), json!(&period.filed_date));
|
||||
value.insert("form".to_string(), json!(&period.form));
|
||||
value.insert("netIncome".to_string(), json!(period.net_income));
|
||||
value.insert(
|
||||
"depreciationAndAmortization".to_string(),
|
||||
json!(period.depreciation_and_amortization),
|
||||
);
|
||||
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 {
|
||||
@@ -794,12 +915,46 @@ mod tests {
|
||||
period_end: "2025-12-31".to_string(),
|
||||
filed_date: "2026-01-31".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),
|
||||
investing_cash_flow: Some(-50.0),
|
||||
financing_cash_flow: Some(-25.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),
|
||||
exchange_rate_effects: None,
|
||||
net_increase_decrease_cash: Some(5.0),
|
||||
beginning_cash: Some(15.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,
|
||||
),
|
||||
];
|
||||
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] = &[
|
||||
candidate(
|
||||
"us-gaap",
|
||||
@@ -163,6 +532,18 @@ pub(crate) const ENDING_CASH_CONCEPTS: &[ConceptCandidate] = &[
|
||||
),
|
||||
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] = &[
|
||||
candidate(
|
||||
"us-gaap",
|
||||
@@ -309,15 +690,184 @@ pub(crate) fn build_cash_flow_periods(
|
||||
period_end: row.period_end.clone(),
|
||||
filed_date: row.filed_date.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,
|
||||
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,
|
||||
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) {
|
||||
(Some(cfo), Some(capex)) => Some(cfo - capex.abs()),
|
||||
_ => 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),
|
||||
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()
|
||||
|
||||
@@ -297,12 +297,50 @@ pub struct CashFlowPeriod {
|
||||
pub period_end: String,
|
||||
pub filed_date: 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 investing_cash_flow: Option<f64>,
|
||||
pub financing_cash_flow: Option<f64>,
|
||||
// Investing Activities
|
||||
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 exchange_rate_effects: Option<f64>,
|
||||
pub net_increase_decrease_cash: Option<f64>,
|
||||
pub beginning_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)]
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
import React from 'react';
|
||||
import { CashFlowPanelData } from '../../types/financial';
|
||||
import { StatementTableMinimal, formatMoney } from '../ui/StatementTableMinimal';
|
||||
import { formatMoney } from '../ui/StatementTableMinimal';
|
||||
|
||||
interface CashFlowPanelProps {
|
||||
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 }) => {
|
||||
return (
|
||||
<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 }) => {
|
||||
return (
|
||||
<div className="cashflow-panel py-4 overflow-auto">
|
||||
{/* Header - Minimal */}
|
||||
<header className="mb-4">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
@@ -40,22 +274,61 @@ export const CashFlowPanel: React.FC<CashFlowPanelProps> = ({ data }) => {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Table - Minimal styling */}
|
||||
<section>
|
||||
<StatementTableMinimal
|
||||
periods={data.periods}
|
||||
metrics={[
|
||||
{ key: 'cfo', label: 'Operating Cash Flow', render: (period) => formatMoney(period.operatingCashFlow) },
|
||||
{ key: 'cfi', label: 'Investing Cash Flow', render: (period) => formatMoney(period.investingCashFlow) },
|
||||
{ key: 'cff', label: 'Financing Cash Flow', render: (period) => formatMoney(period.financingCashFlow) },
|
||||
{ key: 'capex', label: 'Capex', render: (period) => formatMoney(period.capex) },
|
||||
{ key: 'fcf', label: 'Free Cash Flow', render: (period) => formatMoney(period.freeCashFlow) },
|
||||
{ key: 'endingCash', label: 'Ending Cash', render: (period) => formatMoney(period.endingCash) },
|
||||
]}
|
||||
/>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse font-mono text-sm">
|
||||
<thead className="text-term-text-muted">
|
||||
<tr className="border-b border-term-border-subtle">
|
||||
<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]">
|
||||
Item
|
||||
</th>
|
||||
{data.periods.map((period) => (
|
||||
<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>
|
||||
|
||||
{/* Footer - Minimal attribution */}
|
||||
<footer className="mt-4 border-t border-term-border-subtle pt-4">
|
||||
<SourceAttribution status={data.sourceStatus} />
|
||||
</footer>
|
||||
|
||||
@@ -118,15 +118,35 @@ const summarizeCashFlow = (panel: CashFlowPanelData, sourceCommand?: string) =>
|
||||
const rows = latest
|
||||
? [
|
||||
`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
|
||||
? `Operating cash flow: ${latest.operatingCashFlow.toLocaleString()}.`
|
||||
: null,
|
||||
latest.capex != null ? `Capital expenditures: ${latest.capex.toLocaleString()}.` : null,
|
||||
latest.freeCashFlow != null
|
||||
? `Free cash flow: ${latest.freeCashFlow.toLocaleString()}.`
|
||||
: 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[]
|
||||
: ['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) =>
|
||||
|
||||
@@ -175,12 +175,50 @@ export interface CashFlowPeriod {
|
||||
periodEnd: string;
|
||||
filedDate: 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;
|
||||
investingCashFlow?: number;
|
||||
financingCashFlow?: number;
|
||||
// Investing Activities
|
||||
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;
|
||||
exchangeRateEffects?: number;
|
||||
netIncreaseDecreaseCash?: number;
|
||||
beginningCash?: number;
|
||||
endingCash?: number;
|
||||
cashPaidInterest?: number;
|
||||
cashPaidIncomeTaxes?: number;
|
||||
}
|
||||
|
||||
export interface DividendEvent {
|
||||
|
||||
Reference in New Issue
Block a user