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}