datasynth_core/models/pension.rs
1//! Pension models — IAS 19 / ASC 715.
2//!
3//! This module provides data models for defined benefit pension plans,
4//! including actuarial assumptions, defined benefit obligation (DBO)
5//! roll-forwards, plan asset roll-forwards, and pension disclosures.
6
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9
10// ---------------------------------------------------------------------------
11// Enums
12// ---------------------------------------------------------------------------
13
14/// Type of pension plan.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
16#[serde(rename_all = "snake_case")]
17pub enum PensionPlanType {
18 /// Traditional defined benefit — benefit formula-driven obligation.
19 #[default]
20 DefinedBenefit,
21 /// Hybrid cash balance — lump sum account with interest credits.
22 HybridCashBalance,
23}
24
25// ---------------------------------------------------------------------------
26// Actuarial Assumptions
27// ---------------------------------------------------------------------------
28
29/// Actuarial assumptions used to measure the defined benefit obligation.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct ActuarialAssumptions {
32 /// Discount rate used to present-value future benefit payments (e.g. 0.04 = 4%).
33 #[serde(with = "rust_decimal::serde::str")]
34 pub discount_rate: Decimal,
35 /// Expected annual salary growth rate (e.g. 0.03 = 3%).
36 #[serde(with = "rust_decimal::serde::str")]
37 pub salary_growth_rate: Decimal,
38 /// Expected annual pension increase rate post-retirement (e.g. 0.02 = 2%).
39 #[serde(with = "rust_decimal::serde::str")]
40 pub pension_increase_rate: Decimal,
41 /// Long-term expected return on plan assets (e.g. 0.06 = 6%).
42 #[serde(with = "rust_decimal::serde::str")]
43 pub expected_return_on_plan_assets: Decimal,
44}
45
46// ---------------------------------------------------------------------------
47// Defined Benefit Plan
48// ---------------------------------------------------------------------------
49
50/// A defined benefit pension plan sponsored by an entity.
51///
52/// One plan is generated per reporting entity. The plan references its
53/// obligation and asset roll-forwards via `plan_id`.
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct DefinedBenefitPlan {
56 /// Unique plan identifier (e.g. "PLAN-1000-DB").
57 pub id: String,
58 /// Company / entity code that sponsors this plan.
59 pub entity_code: String,
60 /// Human-readable plan name (e.g. "Acme Corp Retirement Plan").
61 pub plan_name: String,
62 /// Plan type — defined benefit or hybrid cash balance.
63 pub plan_type: PensionPlanType,
64 /// Number of active plan participants (employees enrolled).
65 pub participant_count: u32,
66 /// Actuarial assumptions used for valuation.
67 pub assumptions: ActuarialAssumptions,
68 /// Reporting currency code (e.g. "USD").
69 pub currency: String,
70}
71
72// ---------------------------------------------------------------------------
73// DBO Roll-forward
74// ---------------------------------------------------------------------------
75
76/// Defined Benefit Obligation (DBO) roll-forward for one reporting period.
77///
78/// Reconciles opening to closing DBO per IAS 19.140 / ASC 715-20-50.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct PensionObligation {
81 /// Reference to the parent `DefinedBenefitPlan.id`.
82 pub plan_id: String,
83 /// Period label (e.g. "2024-01" or "FY2024").
84 pub period: String,
85 /// DBO at start of period.
86 #[serde(with = "rust_decimal::serde::str")]
87 pub dbo_opening: Decimal,
88 /// Current service cost — present value of benefits earned by employees
89 /// during the current period.
90 #[serde(with = "rust_decimal::serde::str")]
91 pub service_cost: Decimal,
92 /// Interest cost — unwinding of the discount on the obligation
93 /// (`dbo_opening × discount_rate`).
94 #[serde(with = "rust_decimal::serde::str")]
95 pub interest_cost: Decimal,
96 /// Actuarial gains (negative) or losses (positive) arising from
97 /// changes in assumptions or experience adjustments.
98 #[serde(with = "rust_decimal::serde::str")]
99 pub actuarial_gains_losses: Decimal,
100 /// Benefits paid to retirees during the period (reduces DBO).
101 #[serde(with = "rust_decimal::serde::str")]
102 pub benefits_paid: Decimal,
103 /// DBO at end of period.
104 /// Identity: `dbo_opening + service_cost + interest_cost + actuarial_gains_losses − benefits_paid`
105 #[serde(with = "rust_decimal::serde::str")]
106 pub dbo_closing: Decimal,
107}
108
109// ---------------------------------------------------------------------------
110// Plan Assets Roll-forward
111// ---------------------------------------------------------------------------
112
113/// Plan assets roll-forward for one reporting period.
114///
115/// Tracks the fair value of assets held in trust to fund pension obligations.
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct PlanAssets {
118 /// Reference to the parent `DefinedBenefitPlan.id`.
119 pub plan_id: String,
120 /// Period label.
121 pub period: String,
122 /// Fair value of plan assets at start of period.
123 #[serde(with = "rust_decimal::serde::str")]
124 pub fair_value_opening: Decimal,
125 /// Expected return on plan assets
126 /// (`fair_value_opening × expected_return_on_plan_assets`).
127 #[serde(with = "rust_decimal::serde::str")]
128 pub expected_return: Decimal,
129 /// Actuarial gain (positive) or loss (negative) on plan assets
130 /// (actual return vs. expected return).
131 #[serde(with = "rust_decimal::serde::str")]
132 pub actuarial_gain_loss: Decimal,
133 /// Employer contributions paid into the plan trust.
134 #[serde(with = "rust_decimal::serde::str")]
135 pub employer_contributions: Decimal,
136 /// Benefits paid out of the plan trust during the period.
137 #[serde(with = "rust_decimal::serde::str")]
138 pub benefits_paid: Decimal,
139 /// Fair value of plan assets at end of period.
140 /// Identity: `fair_value_opening + expected_return + actuarial_gain_loss + employer_contributions − benefits_paid`
141 #[serde(with = "rust_decimal::serde::str")]
142 pub fair_value_closing: Decimal,
143}
144
145// ---------------------------------------------------------------------------
146// Pension Disclosure
147// ---------------------------------------------------------------------------
148
149/// Summary pension disclosure amounts for a reporting period.
150///
151/// Provides the key balance-sheet and income-statement figures required by
152/// IAS 19 / ASC 715 disclosures.
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct PensionDisclosure {
155 /// Reference to the parent `DefinedBenefitPlan.id`.
156 pub plan_id: String,
157 /// Period label.
158 pub period: String,
159 /// Net pension liability recognised on the balance sheet
160 /// (`dbo_closing − fair_value_closing`).
161 /// Positive = under-funded (liability); negative = over-funded (asset).
162 #[serde(with = "rust_decimal::serde::str")]
163 pub net_pension_liability: Decimal,
164 /// Total pension expense recognised in profit or loss
165 /// (`service_cost + interest_cost − expected_return`).
166 #[serde(with = "rust_decimal::serde::str")]
167 pub pension_expense: Decimal,
168 /// Remeasurements recognised in Other Comprehensive Income (OCI).
169 /// Combines obligation actuarial gains/losses and plan asset actuarial gains/losses.
170 /// Negative = gain in OCI; positive = loss recognised in OCI.
171 #[serde(with = "rust_decimal::serde::str")]
172 pub oci_remeasurements: Decimal,
173 /// Funding ratio: `fair_value_closing / dbo_closing` (expressed as a decimal, e.g. 0.95).
174 /// Zero when DBO is zero.
175 #[serde(with = "rust_decimal::serde::str")]
176 pub funding_ratio: Decimal,
177}