Compare commits

..

No commits in common. "56fa6f3633c38ec6541331f7a36e4e6cc20f3394" and "e25855450c8a17e85e8cf6fec611def1bf46d5f4" have entirely different histories.

8 changed files with 65 additions and 104 deletions

View File

@ -18,7 +18,7 @@ from flask import render_template, url_for
from drcr.models import AccountConfiguration, Posting, Transaction, TrialBalancer, reporting_commodity
from drcr.database import db
from drcr.webapp import eofy_date, sofy_date
from drcr.webapp import eofy_date
import drcr.plugins
from . import views # Load routes
@ -49,32 +49,25 @@ def plugin_init():
drcr.plugins.transaction_providers.append(make_tax_transactions)
@assert_aud
def make_tax_transactions(transactions, start_date=None, end_date=None, api_stage_until=None):
if api_stage_until is not None and api_stage_until < 300:
return transactions
def make_tax_transactions(start_date=None, end_date=None):
# Get EOFY date
dt = eofy_date()
if (start_date is not None and start_date > dt) or (end_date is not None and end_date < dt):
return transactions
return []
# Get trial balance
balancer = TrialBalancer.from_cached(start_date=sofy_date(), end_date=dt)
balancer.apply_transactions(transactions)
report = tax_summary_report(balancer)
report = tax_summary_report()
tax_amount = report.by_id('total_tax').amount - report.by_id('offsets').amount
# Estimated tax payable
transactions.append(Transaction(
transactions = [Transaction(
dt=dt,
description='Estimated income tax',
postings=[
Posting(account='Income Tax', quantity=tax_amount.quantity, commodity=reporting_commodity()),
Posting(account='Income Tax Control', quantity=-tax_amount.quantity, commodity=reporting_commodity())
]
))
)]
# Mandatory study loan repayment
loan_repayment = report.by_id('loan_repayment').amount
@ -88,6 +81,9 @@ def make_tax_transactions(transactions, start_date=None, end_date=None, api_stag
]
))
# Get trial balance
balancer = TrialBalancer.from_cached()
accounts = dict(sorted(balancer.accounts.items()))
# Get account configurations

View File

@ -82,7 +82,10 @@ def study_loan_repayment(year, taxable_income, rfb_grossedup):
return Amount(rate * repayment_income.quantity, reporting_commodity())
@assert_aud
def tax_summary_report(balancer):
def tax_summary_report():
# Get trial balance
balancer = TrialBalancer.from_cached(start_date=sofy_date(), end_date=eofy_date())
accounts = dict(sorted(balancer.accounts.items()))
# Get account configurations

View File

@ -16,11 +16,10 @@
from flask import redirect, render_template, request, url_for
from drcr.models import AccountConfiguration, Amount, Posting, Transaction, TrialBalancer, reporting_commodity
from drcr.models import AccountConfiguration, Amount, Posting, Transaction, reporting_commodity
from drcr.database import db
from drcr.plugins import render_plugin_template
from drcr.transactions import api_transactions
from drcr.webapp import all_accounts, app, eofy_date, sofy_date
from drcr.webapp import all_accounts, app, eofy_date
from .models import CGTAsset, CGTCostAdjustment
from .reports import tax_summary_report
@ -238,9 +237,5 @@ def cgt_assets():
@app.route('/tax/summary')
@assert_aud
def tax_summary():
# Get trial balance
balancer = TrialBalancer.from_cached(start_date=sofy_date(), end_date=eofy_date())
balancer.apply_transactions(api_transactions(api_stage_until=299))
report = tax_summary_report(balancer)
report = tax_summary_report()
return render_template('report.html', report=report)

View File

@ -19,8 +19,7 @@ from flask import abort, redirect, render_template, request, url_for
from .. import AMOUNT_DPS
from ..database import db
from ..models import Amount, Posting, Transaction, TrialBalancer, queue_invalidate_running_balances, reporting_commodity
from ..transactions import all_transactions
from ..webapp import all_accounts, app
from ..webapp import all_accounts, all_transactions, app
from .models import BalanceAssertion
from ..statements.models import StatementLineReconciliation

View File

@ -17,8 +17,7 @@
from flask import url_for
from .models import AccountConfiguration, Amount, TrialBalancer, reporting_commodity
from .transactions import all_transactions, api_transactions
from .webapp import eofy_date, sofy_date
from .webapp import all_transactions, api_transactions, eofy_date, sofy_date
from datetime import datetime, timedelta

View File

@ -1,72 +0,0 @@
# DrCr: Web-based double-entry bookkeeping framework
# Copyright (C) 2022–2024 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 .database import db
from .models import Transaction
from .plugins import transaction_providers
from .statements.models import StatementLine
def limit_query_dt(query, field, start_date=None, end_date=None):
"""Helper function to limit the query between the start and end dates"""
if start_date and end_date:
return query.where((field >= start_date) & (field <= end_date))
if start_date:
return query.where(field >= start_date)
if end_date:
return query.where(field <= end_date)
return query
def all_transactions(start_date=None, end_date=None, api_stage_until=None, join_postings=True):
"""Return all transactions, including from DB and API"""
transactions = db_transactions(start_date=start_date, end_date=end_date, join_postings=join_postings)
transactions.extend(api_transactions(start_date=start_date, end_date=end_date, api_stage_until=api_stage_until))
return transactions
def db_transactions(start_date=None, end_date=None, join_postings=True):
"""Return only transactions from DB"""
# All Transactions in database between start_date and end_date
query = db.select(Transaction)
query = limit_query_dt(query, Transaction.dt, start_date, end_date)
if join_postings:
query = query.options(db.selectinload(Transaction.postings))
transactions = db.session.scalars(query).all()
return transactions
def api_transactions(start_date=None, end_date=None, api_stage_until=None):
"""Return only transactions from API"""
# Stage 0: DB transactions
# Stage 100: Ordinary transactions
# Stage 200: Closing entries prior to tax
# Stage 300: Tax entries
# Stage 400: Closing entries after tax
transactions = []
# Unreconciled StatementLines
query = db.select(StatementLine).where(StatementLine.reconciliation == None)
query = limit_query_dt(query, StatementLine.dt, start_date, end_date)
transactions.extend(line.into_transaction() for line in db.session.scalars(query).all())
# Plugins
for transaction_provider in transaction_providers:
transactions = transaction_provider(transactions, start_date=start_date, end_date=end_date, api_stage_until=api_stage_until)
return transactions

View File

@ -20,8 +20,7 @@ from .database import db
from .models import AccountConfiguration, Amount, Balance, Posting, TrialBalancer, reporting_commodity
from .plugins import account_kinds, advanced_reports, data_sources
from .reports import balance_sheet_report, income_statement_report
from .transactions import all_transactions, api_transactions
from .webapp import app
from .webapp import all_transactions, api_transactions, app
from datetime import datetime
from itertools import groupby

View File

@ -23,7 +23,8 @@ from flask_sqlalchemy.record_queries import get_recorded_queries
from .database import db
from .models import Amount, Metadata, Transaction, reporting_commodity
from .plugins import init_plugins
from .plugins import init_plugins, transaction_providers
from .statements.models import StatementLine
from datetime import datetime, timedelta
import time
@ -31,10 +32,51 @@ import time
app.config['SQLALCHEMY_RECORD_QUERIES'] = app.debug
db.init_app(app)
def all_accounts():
"""Return all accounts in alphabetical order"""
def limit_query_dt(query, field, start_date=None, end_date=None):
"""Helper function to limit the query between the start and end dates"""
return db.session.scalars('SELECT DISTINCT account FROM postings ORDER BY account').all()
if start_date and end_date:
return query.where((field >= start_date) & (field <= end_date))
if start_date:
return query.where(field >= start_date)
if end_date:
return query.where(field <= end_date)
return query
def all_transactions(start_date=None, end_date=None, join_postings=True):
"""Return all transactions, including from DB and API"""
# All Transactions in database between start_date and end_date
query = db.select(Transaction)
query = limit_query_dt(query, Transaction.dt, start_date, end_date)
if join_postings:
query = query.options(db.selectinload(Transaction.postings))
transactions = db.session.scalars(query).all()
transactions.extend(api_transactions(start_date=start_date, end_date=end_date))
return transactions
def api_transactions(start_date=None, end_date=None):
"""Return only transactions from API"""
transactions = []
# Unreconciled StatementLines
query = db.select(StatementLine).where(StatementLine.reconciliation == None)
query = limit_query_dt(query, StatementLine.dt, start_date, end_date)
transactions.extend(line.into_transaction() for line in db.session.scalars(query).all())
# Plugins
for transaction_provider in transaction_providers:
transactions.extend(transaction_provider(start_date=start_date, end_date=end_date))
return transactions
def all_accounts():
# TODO: Can this be cached?
return sorted(list(set(p.account for t in all_transactions() for p in t.postings)))
def eofy_date():
"""Get the datetime for the end of the financial year"""