Created
November 10, 2023 06:16
-
-
Save budhash/fddde911292a8fba6fd5a0933b65f3d6 to your computer and use it in GitHub Desktop.
NapkinTax
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| class Income: | |
| def __init__(self): | |
| self.income_sources = {} | |
| def add(self, source, amount): | |
| """Add income to the total, categorizing by source.""" | |
| self.income_sources[source] = self.income_sources.get(source, 0) + amount | |
| def wages(self, amount): | |
| self.add('wages', amount) | |
| def interest(self, amount): | |
| self.add('interest', amount) | |
| def rental(self, amount): | |
| self.add('rental', amount) | |
| def business(self, amount): | |
| self.add('business', amount) | |
| def misc(self, amount): | |
| self.add('misc', amount) | |
| def total(self): | |
| """Calculate the total income from all sources.""" | |
| return sum(self.income_sources.values()) | |
| class RetirementContributions: | |
| def __init__(self): | |
| self.contributions = {} | |
| def add(self, contribution_type, amount): | |
| """Add contributions to the total, categorizing by type.""" | |
| self.contributions[contribution_type] = self.contributions.get(contribution_type, 0) + amount | |
| def traditional_401k(self, amount): | |
| self.add('traditional_401k', amount) | |
| def traditional_ira(self, amount): | |
| self.add('traditional_ira', amount) | |
| def misc(self, amount): | |
| self.add('misc', amount) | |
| def total(self): | |
| """Calculate the total contributions from all types.""" | |
| return sum(self.contributions.values()) | |
| class TaxInfo: | |
| def __init__(self, calculated_tax_amount, tax_rate, blended_tax_rate, standard_deduction): | |
| self.calculated_tax_amount = calculated_tax_amount | |
| self.tax_rate = tax_rate | |
| self.blended_tax_rate = blended_tax_rate | |
| self.standard_deduction = standard_deduction | |
| def print_table(self): | |
| print("+---------------------------+------------------+") | |
| print("| Description | Amount |") | |
| print("+---------------------------+------------------+") | |
| print(f"| Calculated Tax Amount | $ {self.calculated_tax_amount:,.2f} ") | |
| print(f"| Tax Rate | {self.tax_rate:.2f}% ") | |
| print(f"| Blended Tax Rate | {self.blended_tax_rate:.2f}% ") | |
| print(f"| Standard Deduction | $ {self.standard_deduction:,.2f} ") | |
| print("+---------------------------+------------------+") | |
| def print(self): | |
| print(f"Calculated Tax Amount: ${self.calculated_tax_amount}") | |
| print(f"Tax Rate: {self.tax_rate:.2f}%") | |
| print(f"Blended Tax Rate: {self.blended_tax_rate:.2f}%") | |
| print(f"Standard Deduction: ${self.standard_deduction}") | |
| class TaxCalculator: | |
| def __init__(self, tax_metadata): | |
| self.metadata = tax_metadata | |
| def get_standard_deduction(self, filing_type): | |
| return self.metadata['standard_deduction'][filing_type] | |
| def get_brackets(self, filing_type): | |
| return self.metadata['tax_brackets'][filing_type] | |
| def calculate(self, filing_type, income, retirement_contributions): | |
| total_income = income.total() | |
| total_retirement_contributions = retirement_contributions.total() | |
| adjusted_gross_income = total_income - total_retirement_contributions | |
| # Get the standard deduction for the given filing type | |
| standard_deduction = self.get_standard_deduction(filing_type) | |
| # Apply the standard deduction | |
| taxable_income = max(0, adjusted_gross_income - standard_deduction) | |
| # Get the tax brackets for the given filing type | |
| tax_brackets = self.get_brackets(filing_type) | |
| # Calculate the tax liability | |
| tax_liability = 0.0 | |
| tax_rate = 0 | |
| for lower_bound, upper_bound, rate in tax_brackets: | |
| if taxable_income > lower_bound: | |
| tax_rate = float(rate) | |
| # Calculate tax for this bracket | |
| income_in_bracket = min(taxable_income, upper_bound) - lower_bound | |
| tax_liability += income_in_bracket * (rate / 100.0) | |
| else: | |
| # No more income to tax | |
| break | |
| # Calculate the effective tax rate and the blended tax rate | |
| blended_tax_rate = (tax_liability / total_income * 100) if total_income > 0 else 0 | |
| # Return a TaxInfo object with the calculated values | |
| return TaxInfo(calculated_tax_amount=tax_liability, tax_rate=tax_rate, blended_tax_rate=blended_tax_rate, standard_deduction=standard_deduction) | |
| class TaxMetadataHandler: | |
| def load_metadata_from_file(self, year): | |
| try: | |
| with open(f"{year}_tax_data.json", 'r') as file: | |
| return json.load(file) | |
| except FileNotFoundError: | |
| return None | |
| def load_metadata(self, year): | |
| # Hardcoded metadata for 2024 with tax rates included | |
| hardcoded_data = { | |
| '2024': { | |
| 'standard_deduction': {'s': 14600, 'h': 21900, 'j': 29200, 'm': 14600}, | |
| 'tax_brackets': { | |
| 's': [(0, 11600, 10), (11600, 47150, 12), (47150, 100525, 22), (100525, 191950, 24), (191950, 243725, 32), (243725, 609350, 35), (609350, float('inf'), 37)], | |
| 'h': [(0, 16550, 10), (16550, 63100, 12), (63100, 100500, 22), (100500, 191950, 24), (191950, 243700, 32), (243700, 609350, 35), (609350, float('inf'), 37)], | |
| 'j': [(0, 23200, 10), (23200, 94300, 12), (94300, 201050, 22), (201050, 383900, 24), (383900, 487450, 32), (487450, 731200, 35), (731200, float('inf'), 37)], | |
| 'm': [(0, 11600, 10), (11600, 47150, 12), (47150, 100525, 22), (100525, 191950, 24), (191950, 243725, 32), (243725, 365600, 35), (365600, float('inf'), 37)] | |
| } | |
| }, | |
| '2023': { | |
| 'standard_deduction': {'s': 13850, 'h': 20800, 'j': 27700, 'm': 13850}, | |
| 'tax_brackets': { | |
| 's': [(0, 11000, 10), (11000, 44725, 12), (44725, 95375, 22), (95375, 182100, 24), (182100, 231250, 32), (231250, 578125, 35), (578125, float('inf'), 37)], | |
| 'h': [(0, 15700, 10), (15700, 59850, 12), (59850, 95350, 22), (95350, 182100, 24), (182100, 231250, 32), (231250, 578100, 35), (578100, float('inf'), 37)], | |
| 'j': [(0, 22000, 10), (22000, 89450, 12), (89450, 190750, 22), (190750, 364200, 24), (364200, 462500, 32), (462500, 693750, 35), (693750, float('inf'), 37)], | |
| 'm': [(0, 11000, 10), (11000, 44725, 12), (44725, 95375, 22), (95375, 182100, 24), (182100, 231250, 32), (231250, 346875, 35), (346875, float('inf'), 37)] | |
| } | |
| } | |
| } | |
| return hardcoded_data.get(year) | |
| def load_metadata_from_web(self, year): | |
| # Placeholder for future implementation | |
| return None | |
| def get_metadata(self, year): | |
| data = self.load_metadata(year) | |
| if not data: | |
| data = self.load_metadata_from_web(year) | |
| if not data: | |
| data = self.load_metadata_from_file(year) | |
| if not data: | |
| raise Exception(f"No tax metadata found for year {year}") | |
| return data | |
| class NapkinTax: | |
| def __init__(self): | |
| self.metadata_handler = TaxMetadataHandler() | |
| def run(self, year, filing_type, income, retirement_contributions): | |
| try: | |
| metadata = self.metadata_handler.get_metadata(year) | |
| calculator = TaxCalculator(metadata) | |
| tax_info = calculator.calculate(filing_type, income, retirement_contributions) | |
| tax_info.print_table() | |
| except Exception as e: | |
| print(e) | |
| # Handle the exception accordingly | |
| # Example CLI usage (to be integrated with argparse or similar) | |
| income = Income() | |
| income.add('wages', 500000) | |
| retirement_contributions = RetirementContributions() | |
| retirement_contributions.traditional_401k(19000) | |
| napkin_tax = NapkinTax() | |
| napkin_tax.run('2023', 's', income, retirement_contributions) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment