DrCr/austax/reports.py

130 lines
4.3 KiB
Python

# 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 <https://www.gnu.org/licenses/>.
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