Skip to content

Instantly share code, notes, and snippets.

@derikwhittaker
Last active August 6, 2024 19:52
Show Gist options
  • Select an option

  • Save derikwhittaker/5f8ff0e0502c7e7a90ef1061e3d3082a to your computer and use it in GitHub Desktop.

Select an option

Save derikwhittaker/5f8ff0e0502c7e7a90ef1061e3d3082a to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
public class Earning
{
public string Code { get; set; }
public string Type { get; set; }
public decimal Hours { get; set; }
public decimal Rate { get; set; }
public bool IsTaxable { get; set; }
}
public abstract class Deduction
{
public string Code { get; set; }
public string Type { get; set; }
public int Priority { get; set; }
public abstract decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes);
}
public class PercentageDeduction : Deduction
{
public decimal Value { get; set; }
public bool IsPreTax { get; set; }
public override decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes)
{
if (IsPreTax)
{
return taxableEarnings * (Value / 100);
}
else
{
return (taxableEarnings - preTaxDeductions - taxes) * (Value / 100);
}
}
}
public class FlatDeduction : Deduction
{
public decimal Value { get; set; }
public bool IsPreTax { get; set; }
public override decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes)
{
if (IsPreTax)
{
return Value;
}
else
{
return Value;
}
}
}
public abstract class Tax
{
public string Code { get; set; }
public string Type { get; set; }
public int Priority { get; set; }
public abstract decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions);
}
public class PercentageTax : Tax
{
public decimal Value { get; set; }
public override decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions)
{
return (taxableEarnings - preTaxDeductions) * (Value / 100);
}
}
public class CappedPercentageTax : Tax
{
public decimal Value { get; set; }
public decimal Cap { get; set; }
public override decimal CalculateAmount(decimal taxableEarnings, decimal preTaxDeductions)
{
decimal taxAmount = (taxableEarnings - preTaxDeductions) * (Value / 100);
return Math.Min(taxAmount, Cap);
}
}
public class PayrollCalculator
{
public decimal CalculateNetPay(List<Earning> earnings, List<Deduction> deductions, List<Tax> taxes)
{
decimal grossPay = 0;
decimal taxableEarnings = 0;
decimal preTaxDeductions = 0;
decimal taxesAmount = 0;
decimal postTaxDeductions = 0;
decimal nonTaxableEarnings = 0;
var withheldAmounts = new List<dynamic>();
// Calculate earnings
foreach (var earning in earnings)
{
if (earning.Type == "hourly")
{
decimal earningsAmount = earning.Hours * earning.Rate;
grossPay += earningsAmount;
if (earning.IsTaxable)
{
taxableEarnings += earningsAmount;
}
else
{
nonTaxableEarnings += earningsAmount;
}
}
else if (earning.Type == "salary")
{
grossPay += earning.Rate;
if (earning.IsTaxable)
{
taxableEarnings += earning.Rate;
}
else
{
nonTaxableEarnings += earning.Rate;
}
}
}
// Calculate pre-tax deductions
foreach (var deduction in deductions)
{
if (deduction is PercentageDeduction percentageDeduction && percentageDeduction.IsPreTax)
{
decimal deductionAmount = percentageDeduction.CalculateAmount(taxableEarnings, preTaxDeductions, taxesAmount);
preTaxDeductions += deductionAmount;
withheldAmounts.Add(new { code = deduction.Code, amount = deductionAmount, deficit = 0 });
}
else if (deduction is FlatDeduction flatDeduction && flatDeduction.IsPreTax)
{
preTaxDeductions += flatDeduction.Value;
withheldAmounts.Add(new { code = deduction.Code, amount = flatDeduction.Value, deficit = 0 });
}
}
// Calculate taxes
foreach (var tax in taxes)
{
if (tax is PercentageTax percentageTax)
{
decimal taxAmount = percentageTax.CalculateAmount(taxableEarnings, preTaxDeductions);
taxesAmount += taxAmount;
withheldAmounts.Add(new { code = tax.Code, amount = taxAmount, deficit = 0 });
}
else if (tax is CappedPercentageTax cappedPercentageTax)
{
decimal taxAmount = cappedPercentageTax.CalculateAmount(taxableEarnings, preTaxDeductions);
taxesAmount += taxAmount;
decimal deficit = cappedPercentageTax.CalculateAmount(taxableEarnings, preTaxDeductions) - taxAmount;
withheldAmounts.Add(new { code = tax.Code, amount = taxAmount, deficit = deficit });
}
}
// Calculate post-tax deductions
foreach (var deduction in deductions)
{
if (deduction is PercentageDeduction percentageDeduction && !percentageDeduction.IsPreTax)
{
decimal deductionAmount = percentageDeduction.CalculateAmount(taxableEarnings, preTaxDeductions, taxesAmount);
postTaxDeductions += deductionAmount;
withheldAmounts.Add(new { code = deduction.Code, amount = deductionAmount, deficit = 0 });
}
else if (deduction is FlatDeduction flatDeduction && !flatDeduction.IsPreTax)
{
postTaxDeductions += flatDeduction.Value;
withheldAmounts.Add(new { code = deduction.Code, amount = flatDeduction.Value, deficit = 0 });
}
}
// Calculate net pay
decimal netPay = taxableEarnings - preTaxDeductions - taxesAmount - postTaxDeductions + nonTaxableEarnings;
return netPay;
}
}
public class Program
{
public static void Main()
{
// Sample input object
var input = new
{
earnings = new List<Earning>
{
new Earning { Code = "overtime", Type = "hourly", Hours = 20, Rate = 15, IsTaxable = true },
new Earning { Code = "regular", Type = "hourly", Hours = 20, Rate = 13, IsTaxable = false },
new Earning { Code = "bonus", Type = "salary", Rate = 1500, IsTaxable = true }
},
deductions = new List<Deduction>
{
new PercentageDeduction { Code = "401k", Type = "percentage", Priority = 1, Value = 10, IsPreTax = false },
new FlatDeduction { Code = "healthInsurance", Type = "flat", Priority = 2, Value = 20, IsPreTax = true }
},
taxes = new List<Tax>
{
new PercentageTax { Code = "federalIncome", Type = "percentage", Priority = 1, Value = 10 },
new CappedPercentageTax { Code = "fica", Type = "cappedPercentage", Priority = 2, Value = 10, Cap = 50 }
}
};
var calculator = new PayrollCalculator();
decimal netPay = calculator.CalculateNetPay(input.earnings, input.deductions, input.taxes);
// Output results
Console.WriteLine("Net Pay to Employee: $" + netPay);
}
}
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Sample input object
var input = new
{
earnings = new List<dynamic>
{
new { code = "overtime", type = "hourly", hours = 20, rate = 15, isTaxable = true },
new { code = "regular", type = "hourly", hours = 20, rate = 13, isTaxable = false },
new { code = "bonus", type = "salary", amount = 1500, isTaxable = true }
},
deductions = new List<dynamic>
{
new { code = "401k", type = "percentage", priority = 1, value = 10, isPreTax = false },
new { code = "healthInsurance", type = "flat", priority = 2, value = 20, isPreTax = true }
},
taxes = new List<dynamic>
{
new { code = "federalIncome", type = "percentage", priority = 1, value = 10 },
new { code = "fica", type = "cappedPercentage", priority = 2, value = 10, cap = 50 }
}
};
// Calculate net pay
var netPay = CalculateNetPay(input);
// Output results
Console.WriteLine("Gross Pay: $" + netPay.grossPay);
Console.WriteLine("Net Pay to Employee: $" + netPay.netPay);
Console.WriteLine("Amounts Withheld for Deductions and Taxes:");
foreach (var item in netPay.withheldAmounts)
{
Console.WriteLine(item.code + ": $" + item.amount + (item.deficit > 0 ? " (Deficit: $" + item.deficit + ")" : ""));
}
}
public static dynamic CalculateNetPay(dynamic input)
{
decimal grossPay = 0;
decimal taxableEarnings = 0;
decimal preTaxDeductions = 0;
decimal taxes = 0;
decimal postTaxDeductions = 0;
decimal nonTaxableEarnings = 0;
var withheldAmounts = new List<dynamic>();
// Calculate earnings
foreach (var earning in input.earnings)
{
if (earning.type == "hourly")
{
decimal earnings = earning.hours * earning.rate;
grossPay += earnings;
if (earning.isTaxable)
{
taxableEarnings += earnings;
}
else
{
nonTaxableEarnings += earnings;
}
}
else if (earning.type == "salary")
{
grossPay += earning.amount;
if (earning.isTaxable)
{
taxableEarnings += earning.amount;
}
else
{
nonTaxableEarnings += earning.amount;
}
}
}
// Calculate pre-tax deductions
foreach (var deduction in input.deductions)
{
if (deduction.isPreTax)
{
if (deduction.type == "percentage")
{
decimal deductionAmount = taxableEarnings * (deduction.value / 100);
preTaxDeductions += deductionAmount;
withheldAmounts.Add(new { code = deduction.code, amount = deductionAmount, deficit = 0 });
}
else if (deduction.type == "flat")
{
preTaxDeductions += deduction.value;
withheldAmounts.Add(new { code = deduction.code, amount = deduction.value, deficit = 0 });
}
}
}
// Calculate taxes
foreach (var tax in input.taxes)
{
if (tax.type == "percentage")
{
decimal taxAmount = (taxableEarnings - preTaxDeductions) * (tax.value / 100);
taxes += taxAmount;
withheldAmounts.Add(new { code = tax.code, amount = taxAmount, deficit = 0 });
}
else if (tax.type == "cappedPercentage")
{
decimal taxAmount = (taxableEarnings - preTaxDeductions) * (tax.value / 100);
decimal cappedTaxAmount = Math.Min(taxAmount, tax.cap);
taxes += cappedTaxAmount;
decimal deficit = taxAmount - cappedTaxAmount;
withheldAmounts.Add(new { code = tax.code, amount = cappedTaxAmount, deficit = deficit });
}
}
// Calculate post-tax deductions
foreach (var deduction in input.deductions)
{
if (!deduction.isPreTax)
{
if (deduction.type == "percentage")
{
decimal deductionAmount = (taxableEarnings - preTaxDeductions - taxes) * (deduction.value / 100);
postTaxDeductions += deductionAmount;
withheldAmounts.Add(new { code = deduction.code, amount = deductionAmount, deficit = 0 });
}
else if (deduction.type == "flat")
{
postTaxDeductions += deduction.value;
withheldAmounts.Add(new { code = deduction.code, amount = deduction.value, deficit = 0 });
}
}
}
// Calculate net pay
decimal netPay = taxableEarnings - preTaxDeductions - taxes - postTaxDeductions + nonTaxableEarnings;
return new { grossPay, netPay, withheldAmounts };
}
}
using System;
using System.Collections.Generic;
using System.Linq;
public class Earning
{
public string Code { get; set; }
public string Type { get; set; }
public decimal Hours { get; set; }
public decimal Rate { get; set; }
public bool IsTaxable { get; set; }
}
public abstract class Deduction
{
public string Code { get; set; }
public string Type { get; set; }
public int Priority { get; set; }
public abstract decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes);
}
public class PercentageDeduction : Deduction
{
public decimal Value { get; set; }
public bool IsPreTax { get; set; }
public override decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes) =>
IsPreTax ? taxableEarnings * (Value / 100) : (taxableEarnings - preTaxDeductions - taxes) * (Value / 100);
}
public class FlatDeduction : Deduction
{
public decimal Value { get; set; }
public bool IsPreTax { get; set; }
public override decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions, decimal taxes) =>
IsPreTax ? Value : Value;
}
public abstract class Tax
{
public string Code { get; set; }
public string Type { get; set; }
public int Priority { get; set; }
public abstract decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions);
}
public class PercentageTax : Tax
{
public decimal Value { get; set; }
public override decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions) =>
(taxableEarnings - preTaxDeductions) * (Value / 100);
}
public class CappedPercentageTax : Tax
{
public decimal Value { get; set; }
public decimal Cap { get; set; }
public override decimal Calculate(decimal taxableEarnings, decimal preTaxDeductions) =>
Math.Min((taxableEarnings - preTaxDeductions) * (Value / 100), Cap);
}
public class PayrollCalculator
{
public decimal CalculateNetPay(List<Earning> earnings, List<Deduction> deductions, List<Tax> taxes) =>
earnings.Sum(e => e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) -
deductions.Sum(d => d.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(dd => dd.Priority < d.Priority).Sum(dd => dd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(ddd => ddd.Priority < dd.Priority).Sum(ddd => ddd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(dddd => dddd.Priority < ddd.Priority).Sum(dddd => dddd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
taxes.Where(t => t.Priority < d.Priority).Sum(t => t.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(dd => dd.Priority < t.Priority).Sum(dd => dd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(ddd => ddd.Priority < dd.Priority).Sum(ddd => ddd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
deductions.Where(dddd => dddd.Priority < ddd.Priority).Sum(dddd => dddd.Calculate(
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0),
0)))))))))))))) +
earnings.Sum(e => e.IsTaxable ? (e.Type == "hourly" ? e.Hours * e.Rate : e.Rate) : 0);
}
public class Program
{
public static void Main()
{
var input = new
{
earnings = new List<Earning>
{
new Earning { Code = "overtime", Type = "hourly", Hours = 20, Rate = 15, IsTaxable = true },
new Earning { Code = "regular", Type = "hourly", Hours = 20, Rate = 13, IsTaxable = false },
new Earning { Code = "bonus", Type = "salary", Rate = 1500, IsTaxable = true }
},
deductions = new List<Deduction>
{
new PercentageDeduction { Code = "401k", Type = "percentage", Priority = 1, Value = 10, IsPreTax = false },
new FlatDeduction { Code = "healthInsurance", Type = "flat", Priority = 2, Value = 20, IsPreTax = true }
},
taxes = new List<Tax>
{
new PercentageTax { Code = "federalIncome", Type = "percentage", Priority = 1, Value = 10 },
new CappedPercentageTax { Code = "fica", Type = "cappedPercentage", Priority = 2, Value = 10, Cap = 50 }
}
};
var calculator = new PayrollCalculator();
decimal netPay = calculator.CalculateNetPay(input.earnings, input.deductions, input.taxes);
Console.WriteLine("Net Pay to Employee: $" + netPay);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment