Allow splitting API transactions into multiple stages
This commit is contained in:
parent
97893a9c12
commit
56fa6f3633
@ -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
|
||||
from drcr.webapp import eofy_date, sofy_date
|
||||
import drcr.plugins
|
||||
|
||||
from . import views # Load routes
|
||||
@ -49,14 +49,21 @@ def plugin_init():
|
||||
drcr.plugins.transaction_providers.append(make_tax_transactions)
|
||||
|
||||
@assert_aud
|
||||
def make_tax_transactions(transactions, start_date=None, end_date=None):
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
report = tax_summary_report()
|
||||
# Get trial balance
|
||||
balancer = TrialBalancer.from_cached(start_date=sofy_date(), end_date=dt)
|
||||
balancer.apply_transactions(transactions)
|
||||
|
||||
report = tax_summary_report(balancer)
|
||||
tax_amount = report.by_id('total_tax').amount - report.by_id('offsets').amount
|
||||
|
||||
# Estimated tax payable
|
||||
@ -81,10 +88,6 @@ def make_tax_transactions(transactions, start_date=None, end_date=None):
|
||||
]
|
||||
))
|
||||
|
||||
# Get trial balance
|
||||
balancer = TrialBalancer.from_cached()
|
||||
balancer.apply_transactions(transactions)
|
||||
|
||||
accounts = dict(sorted(balancer.accounts.items()))
|
||||
|
||||
# Get account configurations
|
||||
|
@ -82,10 +82,7 @@ def study_loan_repayment(year, taxable_income, rfb_grossedup):
|
||||
return Amount(rate * repayment_income.quantity, reporting_commodity())
|
||||
|
||||
@assert_aud
|
||||
def tax_summary_report():
|
||||
# Get trial balance
|
||||
balancer = TrialBalancer.from_cached(start_date=sofy_date(), end_date=eofy_date())
|
||||
|
||||
def tax_summary_report(balancer):
|
||||
accounts = dict(sorted(balancer.accounts.items()))
|
||||
|
||||
# Get account configurations
|
||||
|
@ -16,10 +16,11 @@
|
||||
|
||||
from flask import redirect, render_template, request, url_for
|
||||
|
||||
from drcr.models import AccountConfiguration, Amount, Posting, Transaction, reporting_commodity
|
||||
from drcr.models import AccountConfiguration, Amount, Posting, Transaction, TrialBalancer, reporting_commodity
|
||||
from drcr.database import db
|
||||
from drcr.plugins import render_plugin_template
|
||||
from drcr.webapp import all_accounts, app, eofy_date
|
||||
from drcr.transactions import api_transactions
|
||||
from drcr.webapp import all_accounts, app, eofy_date, sofy_date
|
||||
|
||||
from .models import CGTAsset, CGTCostAdjustment
|
||||
from .reports import tax_summary_report
|
||||
@ -237,5 +238,9 @@ def cgt_assets():
|
||||
@app.route('/tax/summary')
|
||||
@assert_aud
|
||||
def tax_summary():
|
||||
report = tax_summary_report()
|
||||
# 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)
|
||||
return render_template('report.html', report=report)
|
||||
|
@ -19,7 +19,8 @@ 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 ..webapp import all_accounts, all_transactions, app
|
||||
from ..transactions import all_transactions
|
||||
from ..webapp import all_accounts, app
|
||||
from .models import BalanceAssertion
|
||||
from ..statements.models import StatementLineReconciliation
|
||||
|
||||
|
@ -17,7 +17,8 @@
|
||||
from flask import url_for
|
||||
|
||||
from .models import AccountConfiguration, Amount, TrialBalancer, reporting_commodity
|
||||
from .webapp import all_transactions, api_transactions, eofy_date, sofy_date
|
||||
from .transactions import all_transactions, api_transactions
|
||||
from .webapp import eofy_date, sofy_date
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
72
drcr/transactions.py
Normal file
72
drcr/transactions.py
Normal file
@ -0,0 +1,72 @@
|
||||
# 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
|
@ -20,7 +20,8 @@ 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 .webapp import all_transactions, api_transactions, app
|
||||
from .transactions import all_transactions, api_transactions
|
||||
from .webapp import app
|
||||
|
||||
from datetime import datetime
|
||||
from itertools import groupby
|
||||
|
@ -23,8 +23,7 @@ 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, transaction_providers
|
||||
from .statements.models import StatementLine
|
||||
from .plugins import init_plugins
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import time
|
||||
@ -32,48 +31,6 @@ import time
|
||||
app.config['SQLALCHEMY_RECORD_QUERIES'] = app.debug
|
||||
db.init_app(app)
|
||||
|
||||
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, 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 = transaction_provider(transactions, start_date=start_date, end_date=end_date)
|
||||
|
||||
return transactions
|
||||
|
||||
def all_accounts():
|
||||
"""Return all accounts in alphabetical order"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user