# DrCr: Web-based double-entry bookkeeping framework # Copyright (C) 2022–2023 Lee Yingtong Li (RunasSudo) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from drcr.database import db from drcr.models import AccountConfiguration, Amount, Transaction, TrialBalancer from drcr.reports import Calculated, Report, Section, Spacer, Subtotal, entries_for_kind def base_income_tax(taxable_income): income = taxable_income.quantity if income <= 1820000: return Amount(0, '$') if income <= 4500000: return Amount(int((income - 1820000) * 0.19), '$') if income <= 12000000: return Amount(int(509200 + (income - 4500000) * 0.325), '$') if income <= 18000000: return Amount(int(2946700 + (income - 12000000) * 0.37), '$') return Amount(int(5166700 + (income - 18000000) * 0.45), '$') def medicare_levy(taxable_income): if taxable_income.quantity < 2920700: raise NotImplementedError('Medicare levy reduction is not implemented') return Amount(int(taxable_income.quantity * 0.02), '$') def tax_summary_report(): # Get trial balance balancer = TrialBalancer() #balancer.apply_transactions(all_transactions()) balancer.apply_transactions(db.session.scalars(db.select(Transaction).options(db.selectinload(Transaction.postings))).all()) accounts = dict(sorted(balancer.accounts.items())) # Get account configurations account_configurations = AccountConfiguration.get_all_kinds() report = Report(title='Tax summary') report.entries = [ Section( entries=[ Section( title='Salary or wages (1)', entries=entries_for_kind(account_configurations, accounts, 'austax.income1', neg=True, floor=100) + [Subtotal('Total item 1', id='income1')] ), Spacer(), Section( title='Australian Government allowances and payments (5)', entries=entries_for_kind(account_configurations, accounts, 'austax.income5', neg=True) + [Subtotal('Total item 5', id='income5', floor=100)] ), Spacer(), Calculated( 'Total assessable income', lambda r: r.by_id('income1').amount + r.by_id('income5').amount, id='assessable', heading=True, bordered=True ), Spacer(), Section( title='Work-related self-education expenses (D4)', entries=entries_for_kind(account_configurations, accounts, 'austax.d4') + [Subtotal('Total item D4', id='d4', floor=100)] ), Spacer(), Section( title='Other work-related expenses (D5)', entries=entries_for_kind(account_configurations, accounts, 'austax.d5') + [Subtotal('Total item D5', id='d5', floor=100)] ), Spacer(), Calculated( 'Total deductions', lambda r: r.by_id('d4').amount + r.by_id('d5').amount, id='deductions', heading=True, bordered=True ), Spacer(), Calculated( 'Net taxable income', lambda r: r.by_id('assessable').amount - r.by_id('deductions').amount, id='taxable', heading=True, bordered=True ), Spacer(), Section( entries=[ Calculated( 'Base income tax', lambda _: base_income_tax(report.by_id('taxable').amount) ), Calculated( 'Medicare levy', lambda _: medicare_levy(report.by_id('taxable').amount) ), Subtotal('Total income tax', id='total_tax', bordered=True) ] ), Spacer(), Section( title='PAYG withheld amounts', entries=entries_for_kind(account_configurations, accounts, 'austax.paygw') + [Subtotal('Total withheld amounts', id='paygw')] ), Spacer(), Calculated( 'Income tax payable (refundable)', lambda _: report.by_id('total_tax').amount - report.by_id('paygw').amount, heading=True, bordered=True ) ] ) ] report.calculate() return report