#!/usr/bin/python3 ''' Calculate SARS tax on payments ''' import locale import math import pprint import re import sys ''' Rates from https://www.sars.gov.za/Tax-Rates/Income-Tax/Pages/Rates%20of%20Tax%20for%20Individuals.aspx low is the lowest value for that bracket; rate is the tax percentage applied to that bracket ''' tax_rates = [ dict( rate = 18, high = 205_900, ), dict( rate = 26, high = 321_600, ), dict( rate = 31, high = 445_100, ), dict( rate = 36, high = 584_200, ), dict( rate = 39, high = 744_800, ), dict( rate = 41, high = 1_577_300, ), dict( rate = 45, ), ] for r in tax_rates: idx = tax_rates.index(r) if not r.get('high'): if idx < len(tax_rates) - 1: high = tax_rates[idx+1].get('low') r['high'] = high - 1 if not r.get('low'): if idx > 0: low = tax_rates[idx-1].get('high') r['low'] = low + 1 else: r['low'] = 1 #pprint.pprint(tax_rates) locale.setlocale( locale.LC_MONETARY, 'en_ZA.UTF-8' ) locale._override_localeconv = {'mon_thousands_sep': ' ', 'mon_decimal_point': '.'} currency = locale.localeconv() class colour: PURPLE = '\033[95m' CYAN = '\033[96m' DARKCYAN = '\033[36m' BLUE = '\033[94m' GREEN = '\033[92m' YELLOW = '\033[93m' RED = '\033[91m' BOLD = '\033[1m' UNDERLINE = '\033[4m' END = '\033[0m' if len(sys.argv) < 2: error() elif isinstance(sys.argv[1], str): try: amount = "".join(sys.argv[1:]).strip(currency.get('currency_symbol')) amount = re.sub('[,.](\d{2})$','.\g<1>', amount) # convert decimal separator to . amount = re.sub('[ ,](\d{3})','\g<1>', amount) # convert thousands separator to '' amount = locale.atof(amount) amount = int(amount) except Exception as e: error(e) else: error() ''' Are we dealing with a monthly amount or annual amount? Assume anything over R100k is annual. If earning more than 100k per month, convert to --month/--year commandline option ''' if amount > 100_000: is_annual = True else: is_annual = False print("Notice: value {} determined to be per month, dividing tax rates by 12".format(locale.currency(amount, grouping=True))) total_tax = 0 for r in tax_rates: low = (r.get('low') - 1) high = r.get('high') rate = r.get('rate') if not is_annual: low = math.ceil(low/12) high = math.ceil(high/12) if amount >= low: bracket = amount if high and amount > high: bracket = high current = math.ceil(bracket - low) total_tax += math.ceil(current * rate / 100) print(" {:>6} - {:>6} = {:>6} / {} = {:>6}".format(bracket, low, current, rate, total_tax)) if amount < high: break remainder = amount - total_tax print("\nTotal tax on {} is {}{}{}, leaving {}".format( locale.currency(amount, grouping=True), colour.BOLD, locale.currency(total_tax, grouping=True), colour.END, locale.currency(remainder, grouping=True) )) def error(e): if e: print(e); print("{0}: Please enter the annual or monthly amount before tax".format(sys.argv[0])) sys.exit()