Add project files.

This commit is contained in:
2026-05-11 14:26:48 -04:00
parent f1bb18df7e
commit dfbdf56ff5
19 changed files with 759 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.36227.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RetirementCalculator", "RetirementCalculator\RetirementCalculator.csproj", "{5671F58E-2971-479E-BA6A-C71C80163039}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5671F58E-2971-479E-BA6A-C71C80163039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5671F58E-2971-479E-BA6A-C71C80163039}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5671F58E-2971-479E-BA6A-C71C80163039}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5671F58E-2971-479E-BA6A-C71C80163039}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9372217B-44E3-4776-A872-2CC4C1E2068F}
EndGlobalSection
EndGlobal
+9
View File
@@ -0,0 +1,9 @@
<Application x:Class="RetirementCalculator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RetirementCalculator"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
+14
View File
@@ -0,0 +1,14 @@
using System.Configuration;
using System.Data;
using System.Windows;
namespace RetirementCalculator
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
+10
View File
@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
@@ -0,0 +1,9 @@
namespace RetirementCalculator
{
public class DeductionInformation
{
public double PreTaxDeductions { get; set; }
public double PostTaxDeductions { get; set; }
public double RetirementPercentage { get; set; }
}
}
@@ -0,0 +1,147 @@
namespace RetirementCalculator
{
public class FederalTax
{
public FilingStatus Status { get; set; }
public double StandardDeduction { get; set; }
public List<FederalTaxRate> FederalTaxRates { get; set; }
public FederalTax()
{
FederalTaxRates = new();
}
public FederalTax(FilingStatus status)
{
Status = status;
switch (status)
{
case FilingStatus.Single:
StandardDeduction = 16100;
FederalTaxRates =
[
.. new FederalTaxRate[]
{
new() { TaxableIncomeMinimum = 0, TaxPercentage = 0.1 },
new() { TaxableIncomeMinimum = 12400, TaxPercentage = 0.12 },
new() { TaxableIncomeMinimum = 50400, TaxPercentage = 0.22 },
new() { TaxableIncomeMinimum = 105700, TaxPercentage = 0.24 },
new() { TaxableIncomeMinimum = 201775, TaxPercentage = 0.32 },
new() { TaxableIncomeMinimum = 256225, TaxPercentage = 0.35 },
new() { TaxableIncomeMinimum = 640600, TaxPercentage = 0.37 }
},
];
break;
case FilingStatus.Married:
StandardDeduction = 32200;
FederalTaxRates =
[
.. new FederalTaxRate[]
{
new() { TaxableIncomeMinimum = 0, TaxPercentage = 0 },
new() { TaxableIncomeMinimum = 19300, TaxPercentage = 0.10 },
new() { TaxableIncomeMinimum = 44100, TaxPercentage = 0.12 },
new() { TaxableIncomeMinimum = 120100, TaxPercentage = 0.22 },
new() { TaxableIncomeMinimum = 230700, TaxPercentage = 0.24 },
new() { TaxableIncomeMinimum = 422850, TaxPercentage = 0.32 },
new() { TaxableIncomeMinimum = 531750, TaxPercentage = 0.35 },
new() { TaxableIncomeMinimum = 788000, TaxPercentage = 0.37 }
},
];
break;
case FilingStatus.HeadOfHousehold:
StandardDeduction = 24150;
FederalTaxRates =
[
.. new FederalTaxRate[]
{
new() { TaxableIncomeMinimum = 0, TaxPercentage = 0 },
new() { TaxableIncomeMinimum = 15550, TaxPercentage = 0.10 },
new() { TaxableIncomeMinimum = 33250, TaxPercentage = 0.12 },
new() { TaxableIncomeMinimum = 83000, TaxPercentage = 0.22 },
new() { TaxableIncomeMinimum = 121250, TaxPercentage = 0.24 },
new() { TaxableIncomeMinimum = 217300, TaxPercentage = 0.32 },
new() { TaxableIncomeMinimum = 271750, TaxPercentage = 0.35 },
new() { TaxableIncomeMinimum = 656150, TaxPercentage = 0.37 }
},
];
break;
default:
throw new InvalidOperationException();
}
}
public FederalTax(FilingStatus status, double standardDeduction, params FederalTaxRate[] federalTaxRates)
{
Status = status;
StandardDeduction = standardDeduction;
FederalTaxRates = new();
foreach (FederalTaxRate ftr in federalTaxRates)
{
if (FederalTaxRates.Count == 0)
{
FederalTaxRates.Add(ftr);
}
else
{
bool Inserted = false;
for (int i = 0; i < FederalTaxRates.Count; i++)
{
if (ftr.TaxableIncomeMinimum <= FederalTaxRates.ElementAt(i).TaxableIncomeMinimum)
{
FederalTaxRates.Insert(i, ftr);
Inserted = true;
break;
}
}
if (!Inserted)
{
FederalTaxRates.Add(ftr);
}
}
}
}
public double CalculateTax(PayInformation Pay, DeductionInformation Deductions)
{
double PayPeriods = 1;
switch (Pay.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
double WorkingIncome = Pay.Salary - StandardDeduction - (Deductions.PreTaxDeductions * PayPeriods) - (Pay.Salary * Deductions.RetirementPercentage);
double RunningTax = 0;
if (WorkingIncome <= 0)
return 0;
List<FederalTaxRate> TempRates = new(FederalTaxRates);
TempRates.Reverse();
foreach (FederalTaxRate ftr in TempRates)
{
if (WorkingIncome > ftr.TaxableIncomeMinimum)
{
double TaxableAmount = WorkingIncome - ftr.TaxableIncomeMinimum;
RunningTax += (TaxableAmount * ftr.TaxPercentage);
WorkingIncome -= TaxableAmount;
}
}
return RunningTax / PayPeriods;
}
}
}
@@ -0,0 +1,8 @@
namespace RetirementCalculator
{
public class FederalTaxRate
{
public double TaxableIncomeMinimum { get; set; }
public double TaxPercentage { get; set; }
}
}
@@ -0,0 +1,7 @@
namespace RetirementCalculator
{
public enum FilingStatus
{
Single, Married, HeadOfHousehold
}
}
@@ -0,0 +1,8 @@
namespace RetirementCalculator
{
public class PayInformation
{
public PayPeriod Period { get; set; }
public double Salary { get; set; }
}
}
@@ -0,0 +1,7 @@
namespace RetirementCalculator
{
public enum PayPeriod
{
EveryWeek, EveryOtherWeek, TwiceMonthly, Monthly, Annually
}
}
+130
View File
@@ -0,0 +1,130 @@
namespace RetirementCalculator
{
public class TaxRates
{
public double StateTax { get; set; }
public double LocalTax { get; set; }
public double SocialSecurityTax { get; set; }
public double MedicareTax { get; set; }
public TaxRates()
{
StateTax = 0.0425;
LocalTax = 0.01;
SocialSecurityTax = 0.062;
MedicareTax = 0.0145;
}
public double CalculateStateTax(PayInformation Pay, DeductionInformation Deductions)
{
double PayPeriods = 1;
switch (Pay.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
return ((Pay.Salary - (Deductions.PreTaxDeductions * PayPeriods) - (Pay.Salary * Deductions.RetirementPercentage)) * StateTax) / PayPeriods;
}
public double CalculateLocalTax(PayInformation Pay, DeductionInformation Deductions)
{
double PayPeriods = 1;
switch (Pay.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
return ((Pay.Salary - (Deductions.PreTaxDeductions * PayPeriods) - (Pay.Salary * Deductions.RetirementPercentage)) * LocalTax) / PayPeriods;
}
public double CalculateSocialSecurityTax(PayInformation Pay, DeductionInformation Deductions)
{
double PayPeriods = 1;
switch (Pay.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
return ((Pay.Salary - (Deductions.PreTaxDeductions * PayPeriods)) * SocialSecurityTax) / PayPeriods;
}
public double CalculateMedicareTax(PayInformation Pay, DeductionInformation Deductions)
{
double PayPeriods = 1;
switch (Pay.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
return ((Pay.Salary - (Deductions.PreTaxDeductions * PayPeriods)) * MedicareTax) / PayPeriods;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace RetirementCalculator
{
public abstract class ModelBase : PropertyChangedBase
{
public void SetProperty<T>(ref T storage, T value, string name)
{
if (value == null)
throw new InvalidCastException("ModelBase.UpdateProperty\nValue cannot be null.");
storage = value;
OnPropertyChanged(name);
}
}
}
@@ -0,0 +1,10 @@
using System.ComponentModel;
namespace RetirementCalculator
{
public abstract class PropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
+33
View File
@@ -0,0 +1,33 @@
using System.Windows.Input;
namespace RetirementCalculator
{
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool>? canExecute;
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool>? canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object? parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object? parameter)
{
this.execute(parameter);
}
}
}
+40
View File
@@ -0,0 +1,40 @@
<Window x:Class="RetirementCalculator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RetirementCalculator"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Filing Status:" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="Pay Periods:" Grid.Column="0" Grid.Row="1"/>
<TextBlock Text="Salary:" Grid.Column="0" Grid.Row="2"/>
<TextBlock Text="Pre-Tax Deductions:" Grid.Column="0" Grid.Row="3"/>
<TextBlock Text="Post-Tax Deductions:" Grid.Column="0" Grid.Row="4"/>
<TextBlock Text="Retirement Contribution:" Grid.Column="0" Grid.Row="5"/>
<ComboBox ItemsSource="{Binding FilingStatuses, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding SelectedStatusIndex, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="0"/>
<ComboBox ItemsSource="{Binding PayPeriods, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding SelectedPeriodIndex, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="1"/>
<TextBox Text="{Binding Salary, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="2"/>
<TextBox Text="{Binding PreTax, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="3"/>
<TextBox Text="{Binding PostTax, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="4"/>
<TextBox Text="{Binding RetirementContribution, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="5"/>
<Button Content="Debug" Command="{Binding DoDebug, UpdateSourceTrigger=PropertyChanged}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="6"/>
</Grid>
</Window>
+24
View File
@@ -0,0 +1,24 @@
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace RetirementCalculator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
+141
View File
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace RetirementCalculator
{
public abstract class MainWindowModel : ModelBase
{
private int _selectedPeriodIndex;
private List<string> _payPeriods;
private int _selectedStatusIndex;
private List<string> _filingStatuses;
private FilingStatus _status;
private PayInformation _payInfo;
private DeductionInformation _deductionInfo;
private ICommand _doDebug;
public int SelectedPeriodIndex
{
get { return _selectedPeriodIndex; }
set
{
SetProperty(ref _selectedPeriodIndex, value, nameof(SelectedPeriodIndex));
switch (value)
{
case 0:
Period = PayPeriod.EveryWeek;
break;
case 1:
Period = PayPeriod.EveryOtherWeek;
break;
case 2:
Period = PayPeriod.TwiceMonthly;
break;
case 3:
Period = PayPeriod.Monthly;
break;
case 4:
Period = PayPeriod.Annually;
break;
}
}
}
public List<string> PayPeriods
{
get { return _payPeriods; }
set { SetProperty(ref _payPeriods, value, nameof(PayPeriods)); }
}
public int SelectedStatusIndex
{
get { return _selectedStatusIndex; }
set
{
SetProperty(ref _selectedStatusIndex, value, nameof(SelectedStatusIndex));
switch (value)
{
case 0:
Status = FilingStatus.Single;
break;
case 1:
Status = FilingStatus.Married;
break;
case 2:
Status = FilingStatus.HeadOfHousehold;
break;
}
}
}
public List<string> FilingStatuses
{
get { return _filingStatuses; }
set { SetProperty(ref _filingStatuses, value, nameof(FilingStatuses)); }
}
public FilingStatus Status
{
get { return _status; }
set { SetProperty(ref _status, value, nameof(Status)); }
}
public PayInformation PayInfo
{
get { return _payInfo; }
set { SetProperty(ref _payInfo, value, nameof(PayInfo)); }
}
public double Salary
{
get { return _payInfo.Salary; }
set { _payInfo.Salary = value; OnPropertyChanged(nameof(Salary)); }
}
public PayPeriod Period
{
get { return _payInfo.Period; }
set { _payInfo.Period = value; OnPropertyChanged(nameof(Period)); }
}
public DeductionInformation DeductionInfo
{
get { return _deductionInfo; }
set { SetProperty(ref _deductionInfo, value, nameof(DeductionInfo)); }
}
public double PreTax
{
get { return _deductionInfo.PreTaxDeductions; }
set { _deductionInfo.PreTaxDeductions = value; OnPropertyChanged(nameof(PreTax)); }
}
public double PostTax
{
get { return _deductionInfo.PostTaxDeductions; }
set { _deductionInfo.PostTaxDeductions = value; OnPropertyChanged(nameof(PostTax)); }
}
public double RetirementContribution
{
get { return _deductionInfo.RetirementPercentage; }
set { _deductionInfo.RetirementPercentage = value; OnPropertyChanged(nameof(RetirementContribution)); }
}
public ICommand DoDebug
{
get { return _doDebug; }
set { SetProperty(ref _doDebug, value, nameof(DoDebug)); }
}
public MainWindowModel()
{
_selectedPeriodIndex = -1;
_payPeriods = new();
_selectedStatusIndex = -1;
_filingStatuses = new();
_payInfo = new();
_deductionInfo = new();
_doDebug = new RelayCommand(Placeholder);
}
private void Placeholder(object obj)
{
}
}
}
+107
View File
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace RetirementCalculator
{
public class MainWindowViewModel : MainWindowModel
{
public MainWindowViewModel()
{
InitializeVariables();
InitializeCommands();
}
private void InitializeVariables()
{
SelectedPeriodIndex = -1;
PayPeriods =
[
.. new string[]
{
"Every Week",
"Every Other Week",
"Twice Monthly",
"Monthly",
"Annually"
}
];
SelectedStatusIndex = -1;
FilingStatuses =
[
.. new string[]
{
"Single",
"Married",
"Head of Household"
}
];
PayInfo = new();
DeductionInfo = new();
}
private void InitializeCommands()
{
DoDebug = new RelayCommand(DebugDo);
}
private void DebugDo(object obj)
{
FederalTax ft = new(Status);
TaxRates ot = new();
string MessageFormat =
"Federal Taxes: {0:0.00}\n" +
"State Taxes: {1:0.00}\n" +
"Local Taxes: {2:0.00}\n" +
"Social Security: {3:0.00}\n" +
"Medicare: {4:0.00}\n" +
"Total Taxes: {5:0.00}\n" +
"Retirement Contribution: {6:0.00}\n" +
"Takehome: {7:0.00}";
double fed = ft.CalculateTax(PayInfo, DeductionInfo);
double state = ot.CalculateStateTax(PayInfo, DeductionInfo);
double local = ot.CalculateLocalTax(PayInfo, DeductionInfo);
double ss = ot.CalculateSocialSecurityTax(PayInfo, DeductionInfo);
double med = ot.CalculateMedicareTax(PayInfo, DeductionInfo);
double tot = fed + state + local + ss + med;
double PayPeriods = 1;
switch (PayInfo.Period)
{
case PayPeriod.Annually:
PayPeriods = 1;
break;
case PayPeriod.Monthly:
PayPeriods = 12;
break;
case PayPeriod.TwiceMonthly:
PayPeriods = 24;
break;
case PayPeriod.EveryOtherWeek:
PayPeriods = 26;
break;
case PayPeriod.EveryWeek:
PayPeriods = 52;
break;
default:
PayPeriods = 1;
break;
}
double gp = (PayInfo.Salary / PayPeriods);
double ret = gp * DeductionInfo.RetirementPercentage;
double th = gp - tot - ret - DeductionInfo.PreTaxDeductions;
MessageBox.Show(string.Format(MessageFormat,
fed,
state,
local,
ss,
med,
tot,
ret,
th
));
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="ViewModels\" />
<Folder Include="Views\" />
</ItemGroup>
</Project>