feat(retirement): PR4f demo seed

generate_goals! now also seeds a fully-populated Goal::Retirement for the
demo family admin: a DE GRV state pension + a bAV lump-plus-annuity
source, three years of Renteninformation statements, two adjustments
(mortgage paid off, higher healthcare), and the first two investment
accounts in the bucket — so the dashboard renders with real numbers out
of the box. Idempotent + best-effort (never breaks demo generation).
Tested against a fixture family.
This commit is contained in:
Guillem Arias
2026-05-29 12:43:19 +02:00
parent 979575d01a
commit 53b2a05749
2 changed files with 79 additions and 0 deletions

View File

@@ -1413,6 +1413,60 @@ class Demo::Generator
seed_matched_pledge_demo_for_wedding!(wedding_goal, currency, primary) if wedding_goal && primary
puts " ✅ Seeded #{goals.size} goals"
generate_retirement!(family)
end
# A fully-populated Goal::Retirement (DE-flavoured) so the retirement
# dashboard renders with real numbers in the demo. Owner-scoped to the
# family admin. Idempotent + best-effort (never breaks demo generation).
def generate_retirement!(family)
return if family.goals.where(type: "Goal::Retirement").exists?
owner = family.users.order(:created_at).first
return unless owner
currency = family.primary_currency_code
plan = Goal::Retirement.create!(
family: family, owner: owner, name: "Retirement", currency: currency, state: "active",
retirement_params: {
"birth_year" => Date.current.year - 40, "retire_age" => 55,
"monthly_savings" => 2000, "target_spend" => 3000, "real_return_pct" => 5
}
)
grv = plan.pension_sources.create!(
name: "German Statutory Pension", kind: "state", country: "DE",
pension_system: "de_grv", tax_treatment: "de_renten", payout_shape: "monthly_for_life",
start_age: 67, amount: 1510, currency: "EUR"
)
plan.pension_sources.create!(
name: "bAV — employer scheme", kind: "workplace", country: "DE",
pension_system: "de_bav", tax_treatment: "de_bav", payout_shape: "lump_plus_annuity",
start_age: 65, amount: 620, currency: "EUR", params: { "lump_amount" => 30_000 }
)
[
[ Date.new(2023, 1, 15), 1180, 7.10, "Renteninformation 2023" ],
[ Date.new(2024, 1, 15), 1350, 8.40, "Renteninformation 2024" ],
[ Date.new(2025, 1, 15), 1510, 9.60, "Renteninformation 2025" ]
].each do |received_on, amount, points, doc|
plan.statements.create!(
pension_source: grv, received_on: received_on, projected_monthly_amount: amount,
projected_currency: "EUR", projected_at_age: 67, current_points: points, raw_source_doc: doc
)
end
plan.adjustments.create!(label: "Mortgage paid off", amount_today: -680, currency: currency, from_age: 51, ordinal: 0)
plan.adjustments.create!(label: "Higher healthcare cost", amount_today: 220, currency: currency, from_age: 65, ordinal: 1)
family.accounts.where(accountable_type: "Investment").visible.order(:created_at).first(2).each do |account|
plan.retirement_bucket_entries.create!(account: account)
end
puts " ✅ Seeded retirement plan"
rescue StandardError => e
puts " ⚠️ Skipped retirement seed: #{e.message}"
end
# Bind one matched pledge on the Wedding fund to a real recent demo

View File

@@ -0,0 +1,25 @@
require "test_helper"
class Demo::GeneratorTest < ActiveSupport::TestCase
test "generate_retirement! seeds a populated plan for the family owner" do
family = families(:empty)
assert_not family.goals.where(type: "Goal::Retirement").exists?
Demo::Generator.new.send(:generate_retirement!, family)
plan = family.goals.find_by(type: "Goal::Retirement")
assert plan, "expected a Goal::Retirement to be created"
assert_equal family.users.order(:created_at).first.id, plan.user_id
assert_equal 2, plan.pension_sources.count
assert_equal 3, plan.statements.count
assert_equal 2, plan.adjustments.count
end
test "generate_retirement! is idempotent" do
family = families(:empty)
Demo::Generator.new.send(:generate_retirement!, family)
assert_no_difference -> { family.goals.where(type: "Goal::Retirement").count } do
Demo::Generator.new.send(:generate_retirement!, family)
end
end
end