datasynth_core/models/financial_statement_notes.rs
1//! Notes to financial statements models.
2//!
3//! Provides structured data models for the disclosures that accompany the
4//! primary financial statements. Notes are required by virtually every
5//! financial reporting framework (IFRS IAS 1, ASC 235, etc.) and include
6//! accounting policies, detail disclosures, contingencies, subsequent events,
7//! related parties, segment information, and standard-specific items.
8
9use chrono::NaiveDate;
10use rust_decimal::Decimal;
11use serde::{Deserialize, Serialize};
12
13// ---------------------------------------------------------------------------
14// Enums
15// ---------------------------------------------------------------------------
16
17/// High-level category of a note to the financial statements.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum NoteCategory {
21 /// Summary of significant accounting policies (IAS 1.117 / ASC 235-10).
22 #[default]
23 AccountingPolicy,
24 /// Detailed breakdown supporting a line item on the face of the statements.
25 DetailDisclosure,
26 /// Provisions, contingent liabilities, and contingent assets (IAS 37 / ASC 450).
27 Contingency,
28 /// Events after the reporting period (IAS 10 / ASC 855).
29 SubsequentEvent,
30 /// Related party transactions and balances (IAS 24 / ASC 850).
31 RelatedParty,
32 /// Operating segment disclosures (IFRS 8 / ASC 280).
33 SegmentInformation,
34 /// Disclosures specific to a particular accounting standard.
35 StandardSpecific,
36}
37
38/// A typed cell value inside a disclosure table.
39#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case", tag = "type", content = "value")]
41pub enum NoteTableValue {
42 /// Plain text cell.
43 Text(String),
44 /// Monetary or numeric amount.
45 Amount(#[serde(with = "rust_decimal::serde::str")] Decimal),
46 /// Percentage value (stored as a fraction, e.g. 0.25 = 25 %).
47 Percentage(#[serde(with = "rust_decimal::serde::str")] Decimal),
48 /// Date cell.
49 Date(NaiveDate),
50 /// Empty / not applicable cell.
51 Empty,
52}
53
54// ---------------------------------------------------------------------------
55// Note building blocks
56// ---------------------------------------------------------------------------
57
58/// A two-dimensional disclosure table within a note section.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct NoteTable {
61 /// Brief caption describing the table's content.
62 pub caption: String,
63 /// Column headers.
64 pub headers: Vec<String>,
65 /// Data rows — each row has the same length as `headers`.
66 pub rows: Vec<Vec<NoteTableValue>>,
67}
68
69/// A single section within a note (heading + narrative + optional tables).
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct NoteSection {
72 /// Section heading (e.g. "Basis of preparation").
73 pub heading: String,
74 /// Explanatory narrative text.
75 pub narrative: String,
76 /// Optional tabular data supporting the narrative.
77 pub tables: Vec<NoteTable>,
78}
79
80// ---------------------------------------------------------------------------
81// Top-level note
82// ---------------------------------------------------------------------------
83
84/// A complete note to the financial statements.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct FinancialStatementNote {
87 /// Sequential note number (1 = first note in the set).
88 pub note_number: u32,
89 /// Short descriptive title.
90 pub title: String,
91 /// Disclosure category.
92 pub category: NoteCategory,
93 /// One or more content sections within this note.
94 pub content_sections: Vec<NoteSection>,
95 /// Cross-references to other notes or financial statement line items.
96 pub cross_references: Vec<String>,
97}
98
99impl FinancialStatementNote {
100 /// Create a minimal note with a single section and no tables.
101 pub fn simple(
102 note_number: u32,
103 title: impl Into<String>,
104 category: NoteCategory,
105 heading: impl Into<String>,
106 narrative: impl Into<String>,
107 ) -> Self {
108 Self {
109 note_number,
110 title: title.into(),
111 category,
112 content_sections: vec![NoteSection {
113 heading: heading.into(),
114 narrative: narrative.into(),
115 tables: Vec::new(),
116 }],
117 cross_references: Vec::new(),
118 }
119 }
120
121 /// Attach a cross-reference to another note.
122 pub fn with_cross_reference(mut self, reference: impl Into<String>) -> Self {
123 self.cross_references.push(reference.into());
124 self
125 }
126}