Skip to main content

datasynth_core/models/
financial_statements.rs

1//! Financial statement models for period-end reporting.
2
3use chrono::NaiveDate;
4use rust_decimal::Decimal;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8/// Type of financial statement.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum StatementType {
12    /// Balance Sheet (Statement of Financial Position)
13    BalanceSheet,
14    /// Income Statement (Profit & Loss)
15    IncomeStatement,
16    /// Cash Flow Statement
17    CashFlowStatement,
18    /// Statement of Changes in Equity
19    ChangesInEquity,
20}
21
22/// Basis of accounting for the statement.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
24#[serde(rename_all = "snake_case")]
25pub enum StatementBasis {
26    /// US GAAP
27    #[default]
28    UsGaap,
29    /// IFRS
30    Ifrs,
31    /// Statutory/local GAAP
32    Statutory,
33}
34
35/// Cash flow category for cash flow statement items.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum CashFlowCategory {
39    /// Operating activities
40    Operating,
41    /// Investing activities
42    Investing,
43    /// Financing activities
44    Financing,
45}
46
47/// A line item on a financial statement.
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct FinancialStatementLineItem {
50    /// Line item code (e.g., "BS-CASH", "IS-REV")
51    pub line_code: String,
52    /// Display label
53    pub label: String,
54    /// Statement section (e.g., "Current Assets", "Revenue")
55    pub section: String,
56    /// Sort order within section
57    pub sort_order: u32,
58    /// Current period amount
59    #[serde(with = "rust_decimal::serde::str")]
60    pub amount: Decimal,
61    /// Prior period amount (for comparison)
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub amount_prior: Option<Decimal>,
64    /// Indentation level for display hierarchy
65    pub indent_level: u8,
66    /// Whether this is a subtotal/total line
67    pub is_total: bool,
68    /// GL accounts that roll up to this line
69    pub gl_accounts: Vec<String>,
70}
71
72/// A cash flow item (indirect method).
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct CashFlowItem {
75    /// Item code
76    pub item_code: String,
77    /// Display label
78    pub label: String,
79    /// Cash flow category
80    pub category: CashFlowCategory,
81    /// Amount
82    #[serde(with = "rust_decimal::serde::str")]
83    pub amount: Decimal,
84    /// Prior period amount
85    #[serde(default, skip_serializing_if = "Option::is_none")]
86    pub amount_prior: Option<Decimal>,
87    /// Sort order
88    pub sort_order: u32,
89    /// Is this a subtotal line
90    pub is_total: bool,
91}
92
93/// A single line in a consolidation schedule, showing per-entity amounts plus
94/// pre-elimination total, elimination adjustments, and post-elimination total.
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct ConsolidationLineItem {
97    /// Account category (e.g. "Revenue", "Cash", "Payables")
98    pub account_category: String,
99    /// Per-entity amounts: entity_code → net balance
100    #[serde(default)]
101    pub entity_amounts: HashMap<String, Decimal>,
102    /// Sum of all entity amounts before eliminations
103    #[serde(with = "rust_decimal::serde::str")]
104    pub pre_elimination_total: Decimal,
105    /// Net elimination adjustment (positive = increases total, negative = decreases)
106    #[serde(with = "rust_decimal::serde::str")]
107    pub elimination_adjustments: Decimal,
108    /// post_elimination_total = pre_elimination_total + elimination_adjustments
109    #[serde(with = "rust_decimal::serde::str")]
110    pub post_elimination_total: Decimal,
111}
112
113/// A consolidation schedule showing how individual entity amounts roll up into
114/// the consolidated group total with elimination entries applied.
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct ConsolidationSchedule {
117    /// Fiscal period label, e.g. "2024-Q1" or "2024-03"
118    pub period: String,
119    /// One line per account category
120    pub line_items: Vec<ConsolidationLineItem>,
121}
122
123// ============================================================================
124// IFRS 8 / ASC 280 — Operating Segment Reporting
125// ============================================================================
126
127/// Basis for how the entity defines its operating segments.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
129#[serde(rename_all = "snake_case")]
130pub enum SegmentType {
131    /// Segments defined by geographic region (country / continent)
132    Geographic,
133    /// Segments defined by product or service line
134    ProductLine,
135    /// Segments that correspond to separate legal entities
136    LegalEntity,
137}
138
139/// A single IFRS 8 / ASC 280 reportable operating segment.
140///
141/// All monetary fields are expressed in the entity's reporting currency.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct OperatingSegment {
144    /// Unique identifier for this segment record (deterministic UUID)
145    pub segment_id: String,
146    /// Human-readable segment name (e.g. "North America", "Software Products")
147    pub name: String,
148    /// Basis on which the segment is identified
149    pub segment_type: SegmentType,
150    /// Revenue from transactions with external customers
151    #[serde(with = "rust_decimal::serde::str")]
152    pub revenue_external: Decimal,
153    /// Revenue from transactions with other operating segments (eliminated on consolidation)
154    #[serde(with = "rust_decimal::serde::str")]
155    pub revenue_intersegment: Decimal,
156    /// Segment operating profit (before corporate overhead and group tax)
157    #[serde(with = "rust_decimal::serde::str")]
158    pub operating_profit: Decimal,
159    /// Total assets allocated to this segment
160    #[serde(with = "rust_decimal::serde::str")]
161    pub total_assets: Decimal,
162    /// Total liabilities allocated to this segment
163    #[serde(with = "rust_decimal::serde::str")]
164    pub total_liabilities: Decimal,
165    /// Capital expenditure (additions to PP&E and intangibles) in the period
166    #[serde(with = "rust_decimal::serde::str")]
167    pub capital_expenditure: Decimal,
168    /// Depreciation and amortisation charged in the period
169    #[serde(with = "rust_decimal::serde::str")]
170    pub depreciation_amortization: Decimal,
171    /// Fiscal period label for which these figures are reported (e.g. "2024-03")
172    pub period: String,
173    /// Company / group these segments belong to
174    pub company_code: String,
175}
176
177/// Reconciliation of segment totals to the consolidated financial statements
178/// as required by IFRS 8 para. 28 and ASC 280-10-50-30.
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct SegmentReconciliation {
181    /// Fiscal period label (e.g. "2024-03")
182    pub period: String,
183    /// Company / group code
184    pub company_code: String,
185    /// Sum of all reportable segment revenues (external + intersegment)
186    #[serde(with = "rust_decimal::serde::str")]
187    pub segment_revenue_total: Decimal,
188    /// Elimination of intersegment revenues (typically negative)
189    #[serde(with = "rust_decimal::serde::str")]
190    pub intersegment_eliminations: Decimal,
191    /// Consolidated external revenue = segment_revenue_total + intersegment_eliminations
192    #[serde(with = "rust_decimal::serde::str")]
193    pub consolidated_revenue: Decimal,
194    /// Sum of all reportable segment operating profits
195    #[serde(with = "rust_decimal::serde::str")]
196    pub segment_profit_total: Decimal,
197    /// Unallocated corporate overhead (negative amount)
198    #[serde(with = "rust_decimal::serde::str")]
199    pub corporate_overhead: Decimal,
200    /// Consolidated operating profit = segment_profit_total + corporate_overhead
201    #[serde(with = "rust_decimal::serde::str")]
202    pub consolidated_profit: Decimal,
203    /// Sum of all reportable segment assets
204    #[serde(with = "rust_decimal::serde::str")]
205    pub segment_assets_total: Decimal,
206    /// Unallocated corporate / group assets (e.g. deferred tax, goodwill)
207    #[serde(with = "rust_decimal::serde::str")]
208    pub unallocated_assets: Decimal,
209    /// Consolidated total assets = segment_assets_total + unallocated_assets
210    #[serde(with = "rust_decimal::serde::str")]
211    pub consolidated_assets: Decimal,
212}
213
214/// A complete financial statement.
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct FinancialStatement {
217    /// Unique statement identifier
218    pub statement_id: String,
219    /// Company code
220    pub company_code: String,
221    /// Statement type
222    pub statement_type: StatementType,
223    /// Accounting basis
224    pub basis: StatementBasis,
225    /// Reporting period start
226    pub period_start: NaiveDate,
227    /// Reporting period end
228    pub period_end: NaiveDate,
229    /// Fiscal year
230    pub fiscal_year: u16,
231    /// Fiscal period
232    pub fiscal_period: u8,
233    /// Line items
234    pub line_items: Vec<FinancialStatementLineItem>,
235    /// Cash flow items (only for CashFlowStatement)
236    pub cash_flow_items: Vec<CashFlowItem>,
237    /// Currency
238    pub currency: String,
239    /// Whether this is a consolidated statement
240    pub is_consolidated: bool,
241    /// Preparer ID
242    pub preparer_id: String,
243}