Skip to main content

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}