Files
sure/test/models/pension_entry_test.rb
Chakib cc12c4465d Add retirement / FIRE planning feature
Introduces retirement and FIRE (Financial Independence, Retire Early)
planning as a new top-level feature in the sidebar navigation.

Key features:
- RetirementConfig model: stores retirement planning parameters per family
  (birth year, retirement age, target income, pension system, etc.)
- PensionEntry model: tracks pension statements (Renteninformation) over time
  with pension points, current/projected monthly pension
- German GRV pension calculations:
  - Estimated monthly pension from Entgeltpunkte x Rentenwert
  - After-tax pension estimation
  - Monthly pension gap analysis
- FIRE calculations:
  - FIRE number (capital needed via 4% rule, inflation-adjusted)
  - FIRE progress percentage from current portfolio value
  - Estimated FIRE date (iterative monthly projection)
  - Required monthly savings to close pension gap
- Dashboard view with overview cards, FIRE progress bar, assumptions panel,
  and pension history table with add/delete entries
- Setup and edit views for configuring retirement parameters
- Full i18n support (English + German)
- Minitest coverage for models and controller

Database: 2 new tables (retirement_configs, pension_entries) with UUID PKs
Routes: singular resource with setup, add/destroy pension entry actions

This is an initial implementation focused on the German GRV pension system.
The architecture supports extending to other pension systems (custom/other).
Open to suggestions and improvements from the community - contributions for
additional pension systems, visualization charts, or calculation refinements
are very welcome.
2026-02-23 18:29:45 +01:00

50 lines
1.3 KiB
Ruby

require "test_helper"
class PensionEntryTest < ActiveSupport::TestCase
setup do
@entry_2023 = pension_entries(:entry_2023)
@entry_2024 = pension_entries(:entry_2024)
end
test "valid pension entry" do
assert @entry_2024.valid?
end
test "requires recorded_at" do
@entry_2024.recorded_at = nil
assert_not @entry_2024.valid?
end
test "requires current_points" do
@entry_2024.current_points = nil
assert_not @entry_2024.valid?
end
test "current_points must be non-negative" do
@entry_2024.current_points = -1
assert_not @entry_2024.valid?
end
test "recorded_at must be unique per retirement_config" do
duplicate = @entry_2024.retirement_config.pension_entries.build(
recorded_at: @entry_2024.recorded_at,
current_points: 10.0
)
assert_not duplicate.valid?
end
test "points_gained returns difference from previous entry" do
assert_equal 1.0, @entry_2024.points_gained
end
test "points_gained returns current_points when no previous entry" do
assert_equal 8.5, @entry_2023.points_gained
end
test "chronological scope orders by date ascending" do
entries = @entry_2023.retirement_config.pension_entries.chronological
assert_equal @entry_2023, entries.first
assert_equal @entry_2024, entries.last
end
end