From 4bf0545ecfa57e7432f6398c3a3a0b0d825286fc Mon Sep 17 00:00:00 2001 From: Greg Grothaus Date: Thu, 4 Apr 2024 13:45:03 -0700 Subject: [PATCH] Add a section on survivor benefits. (#356) --- src/lib/components/Slider.svelte | 3 + src/lib/components/SurvivorReport.svelte | 635 +++++++++++++++++++++++ src/lib/recipient.ts | 11 +- src/routes/calculator/+page.svelte | 7 + src/stories/SurvivorReport.stories.ts | 62 +++ 5 files changed, 716 insertions(+), 2 deletions(-) create mode 100644 src/lib/components/SurvivorReport.svelte create mode 100644 src/stories/SurvivorReport.stories.ts diff --git a/src/lib/components/Slider.svelte b/src/lib/components/Slider.svelte index 28943fe..23d6797 100644 --- a/src/lib/components/Slider.svelte +++ b/src/lib/components/Slider.svelte @@ -278,6 +278,9 @@ ticks.forEach((element) => { element.x = valueToPosition(element.value, floor, ceiling, width); }); + ticks = ticks.filter( + (element) => element.value >= floor && element.value <= ceiling + ); } else { for (let i = floor; i <= ceil; i += step) { ticks.push({ diff --git a/src/lib/components/SurvivorReport.svelte b/src/lib/components/SurvivorReport.svelte new file mode 100644 index 0000000..3090b74 --- /dev/null +++ b/src/lib/components/SurvivorReport.svelte @@ -0,0 +1,635 @@ + + +
+

Survivor Benefits

+ +
+

+ Beta + This section is recently added and is thus more likely to have errors. +

+

+ As the spouse with the higher earnings, should die + before , + may be eligible for survivor benefits on earnings record. Survivor benefits would replace benefits with a value that can be as high as + personal benefit. +

+

+ Survivor benefits are also sometimes known as widow or widower benefits. +

+ + +
+

There are a eligibility rules that must be met:

+
    +
  1. + must have been married to for at least 9 months. +
  2. +
  3. + can't have remarried before age 60. +
  4. +
  5. + must have earned enough Social Security Credits + at the time of death, by meeting one of: +
      +
    • Earned at least 40 credits.
    • +
    • + Earned at least age at the time of + death minus 22 credits. +
    • +
    • + died prior to age 28 and earned at least + 6 credits. +
    • +
    +
  6. +
+

+ The benefit calculation starts with a consideration of age at death and the age filed for benefits + while alive. There are four different scenarios: +

+
    +
  • + files for benefits before the time of death + and ... +
  • +
      +
    • + filed on or after + {breakEvenAge.years()} years, {breakEvenAge.modMonths()} + months ({breakEvenDate.monthName()}, {breakEvenDate.year()}): +

      + The survivor benefit will be based on personal benefit at the time of death. +

      +
    • +
    • + filed earlier than + {breakEvenAge.years()} years, {breakEvenAge.modMonths()} + months ({breakEvenDate.monthName()}, {breakEvenDate.year()}): +

      + The survivor benefit will be based on the minimum of 82.5% Primary Insurance Amount: {higherEarner + .pia() + .primaryInsuranceAmount() + .string()} x 82.5% = {higherEarner + .pia() + .primaryInsuranceAmount() + .times(0.825) + .wholeDollars()} +

      +
    • +
    +
  • + died before filing for benefits and ... +
  • +
      +
    • + died after reaching normal + retirement age of {$higherEarner.normalRetirementAge().years()} + years + {#if $higherEarner.normalRetirementAge().modMonths() > 0} + {$higherEarner.normalRetirementAge().modMonths()}, months + {/if}({$higherEarner.normalRetirementDate().monthName()}, {$higherEarner + .normalRetirementDate() + .year()}): +

      + The survivor benefit will be based on personal benefit would have received + if filing at the time of death. +

      +
    • +
    • + died on or before reaching + normal retirement age of {$higherEarner + .normalRetirementAge() + .years()} + years + {#if $higherEarner.normalRetirementAge().modMonths() > 0} + {$higherEarner.normalRetirementAge().modMonths()}, months + {/if}({$higherEarner.normalRetirementDate().monthName()}, {$higherEarner + .normalRetirementDate() + .year()}): +

      + The survivor benefit will be based on + Primary Insurance Amount: + {higherEarner.pia().primaryInsuranceAmount().wholeDollars()} +

      +
    • +
    +
+

+ The survivor benefit is then subject to reductions if claims them before normal {#if adjustedNormalRetirementAge}survivor + {/if}retirement age{#if !adjustedNormalRetirementAge}  of {lowerEarner + .survivorNormalRetirementAge() + .years()} years {#if lowerEarner + .survivorNormalRetirementAge() + .modMonths() > 0}, + {lowerEarner.survivorNormalRetirementAge().modMonths()} months + {/if} ({lowerEarner.survivorNormalRetirementDate().monthName()}, {lowerEarner + .survivorNormalRetirementDate() + .year()}){/if}. The earliest that can claim is age + 60. +

+ {#if adjustedNormalRetirementAge} +

+ The normal survivor retirement age is slightly different than the + normal retirement age. normal survivor + retirement age is: + {lowerEarner.survivorNormalRetirementAge().years()} years, {lowerEarner + .survivorNormalRetirementAge() + .modMonths()} months ({lowerEarner.survivorNormalRetirementDate().monthName()}, {lowerEarner + .survivorNormalRetirementDate() + .year()}). +

+ {/if} +

+ If claims the survivor benefit at age 60, the + benefit is reduced by 28.5%. If claims the survivor + benefit at normal {#if adjustedNormalRetirementAge}survivor + {/if}retirement age, the benefit is not reduced. Between those two + ages, the benefit is reduced between 28.5% and 0% proportionally to + the filing time between age 60 and the normal {#if adjustedNormalRetirementAge}survivor + {/if}retirement age. +

+
+
+ +

+ Adjust the following settings to see how they affect the survivor benefit: +

+
+
+ 1. +
+
+ + + + +
+
+
+ + {#if fileVsDeath == "fileBeforeDeath"} +

+ 2. Estimate the age that files for benefits: +

+
+ +
+

+ The maximum surivor benefit is + + {lowerEarner + .survivorBenefit( + higherEarner, + /* deceasedFilingDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(beforeDeathSliderMonths_) + ), + /* deceasedDeathDate = 70 */ + higherEarner.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 70, months: 0 }) + ), + /* survivorFilingDate = 70 */ + lowerEarner.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 70, months: 0 }) + ) + ) + .wholeDollars()}. +

+ {:else} +

+ 2. Estimate the age that dies: +

+
+ +
+

+ The maximum surivor benefit is + + {lowerEarner + .survivorBenefit( + higherEarner, + /* deceasedFilingDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(afterDeathSliderMonths_) + ), + /* deceasedDeathDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(afterDeathSliderMonths_) + ), + /* survivorFilingDate = 70 */ + lowerEarner.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 70, months: 0 }) + ) + ) + .wholeDollars()}. +

+ {/if} +

+ 3. Estimate the age that files for survivor benefits: +

+
+ +
+
+ Survivor Benefit Amount: + {#if fileVsDeath == "fileBeforeDeath"} + {lowerEarner + .survivorBenefit( + higherEarner, + /* deceasedFilingDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(beforeDeathSliderMonths_) + ), + /* deceasedDeathDate = 70 */ + higherEarner.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 70, months: 0 }) + ), + /* survivorFilingDate */ + lowerEarner.birthdate.dateAtSsaAge( + new MonthDuration(survivorSliderMonths_) + ) + ) + .wholeDollars()} + {:else} + {lowerEarner + .survivorBenefit( + higherEarner, + /* deceasedFilingDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(afterDeathSliderMonths_) + ), + /* deceasedDeathDate */ + higherEarner.birthdate.dateAtSsaAge( + new MonthDuration(afterDeathSliderMonths_) + ), + /* survivorFilingDate */ + lowerEarner.birthdate.dateAtSsaAge( + new MonthDuration(survivorSliderMonths_) + ) + ) + .wholeDollars()} + {/if} +
+
+
+
+ + diff --git a/src/lib/recipient.ts b/src/lib/recipient.ts index 459af87..f76e49d 100644 --- a/src/lib/recipient.ts +++ b/src/lib/recipient.ts @@ -781,14 +781,21 @@ export class Recipient { // filed for benefits on the date of death. baseSurvivorBenefit = deceased.benefitOnDate( deceasedDeathDate, - deceasedDeathDate + deceased.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 71, months: 0 }) + ) ); } } else { // If the deceased recipient filed for benefits before death, then the base survivor benefit is the greater of the deceased recipient's benefit at the time of death or 82.5% of the deceased recipient's PIA. baseSurvivorBenefit = Money.max( deceased.pia().primaryInsuranceAmount().times(0.825), - deceased.benefitOnDate(deceasedFilingDate, deceasedDeathDate) + deceased.benefitOnDate( + deceasedFilingDate, + deceased.birthdate.dateAtSsaAge( + MonthDuration.initFromYearsMonths({ years: 71, months: 0 }) + ) + ) ); } diff --git a/src/routes/calculator/+page.svelte b/src/routes/calculator/+page.svelte index deb2ad1..06440d9 100644 --- a/src/routes/calculator/+page.svelte +++ b/src/routes/calculator/+page.svelte @@ -15,6 +15,7 @@ import CombinedHeading from "$lib/components/CombinedHeading.svelte"; import CombinedChart from "$lib/components/CombinedChart.svelte"; import SpousalReport from "$lib/components/SpousalReport.svelte"; + import SurvivorReport from "$lib/components/SurvivorReport.svelte"; import RecipientName from "$lib/components/RecipientName.svelte"; import Sponsor from "$lib/components/Sponsor.svelte"; @@ -135,6 +136,12 @@ spouse={context.spouse} /> + + + = { + component: SurvivorReport, + title: "Report/Survivor/SurvivorReport", + tags: ["autodocs"], + parameters: { + layout: "fullscreen", + }, +}; +export default meta; + +const Template = ({ ...args }) => ({ + Component: SurvivorReport, + props: args, +}); + +let recipient = new Recipient(); +recipient.name = "Alex"; +recipient.markFirst(); +recipient.earningsRecords = parsePaste(demo); +recipient.birthdate = Birthdate.FromYMD(1950, 6, 1); + +let spouse = new Recipient(); +spouse.name = "Chris"; +spouse.markSecond(); +spouse.earningsRecords = parsePaste(demo_spouse_low); +spouse.birthdate = Birthdate.FromYMD(1950, 6, 1); + +// Default is someone with sufficient earned credits. +export const Default = Template.bind({}); +Default.args = { + recipient: recipient, + spouse: spouse, +}; + +let recipient2 = new Recipient(); +recipient2.name = "Alex"; +recipient2.markFirst(); +recipient2.earningsRecords = parsePaste(demo); +recipient2.birthdate = Birthdate.FromYMD(1942, 6, 1); + +let spouse2 = new Recipient(); +spouse2.name = "Chris"; +spouse2.markSecond(); +spouse2.earningsRecords = parsePaste(demo_spouse_low); +spouse2.birthdate = Birthdate.FromYMD(1942, 6, 1); + +// Default is someone with sufficient earned credits. +export const Older1942 = Template.bind({}); +Older1942.args = { + recipient: recipient2, + spouse: spouse2, +};