Added CashAccountConverter and LedgerAccountConverter and applied them in the URL patterns of the accounting application.

This commit is contained in:
依瑪貓 2020-07-23 08:33:53 +08:00
parent 6ae25ddca7
commit 8890e60fbb
10 changed files with 155 additions and 115 deletions

View File

@ -18,7 +18,10 @@
"""The URL converters. """The URL converters.
""" """
from accounting.models import Transaction
from django.utils.translation import pgettext
from accounting.models import Transaction, Record, Account
from mia_core.period import Period from mia_core.period import Period
@ -67,3 +70,75 @@ class PeriodConverter:
if isinstance(value, Period): if isinstance(value, Period):
return value.spec return value.spec
return value return value
class CashAccountConverter:
"""The path converter for the cash account."""
regex = "0|(11|12|21|22)[1-9]{1,3}"
def to_python(self, value):
"""Returns the cash account by the account code.
Args:
value (str): The account code.
Returns:
Account: The account.
"""
if value == "0":
return Account(
code="0",
title=pgettext(
"Accounting|", "current assets and liabilities"),
)
try:
account = Account.objects.get(code=value)
except Account.DoesNotExist:
raise ValueError
if Record.objects.filter(account=account).count() == 0:
raise ValueError
return account
def to_url(self, value):
"""Returns the code of an account.
Args:
value (Account): The account.
Returns:
str: The account code.
"""
return value.code
class LedgerAccountConverter:
"""The path converter for the ledger account."""
regex = "[1-9]{1,5}"
def to_python(self, value):
"""Returns the ledger accountby the account code.
Args:
value (str): The account code.
Returns:
Account: The account.
"""
try:
account = Account.objects.get(code=value)
except Account.DoesNotExist:
raise ValueError
if Record.objects.filter(account__code__startswith=value).count() == 0:
raise ValueError
return account
def to_url(self, value):
"""Returns the code of an account.
Args:
value (Account): The account.
Returns:
str: The account code.
"""
return value.code

View File

@ -72,13 +72,13 @@ First written: 2020/7/15
<div class="dropdown-menu account-picker"> <div class="dropdown-menu account-picker">
<div class="dropdown-header">{% trans "Shortcuts" context "Accounting|Account|" as text %}{{ text|force_escape }}</div> <div class="dropdown-header">{% trans "Shortcuts" context "Accounting|Account|" as text %}{{ text|force_escape }}</div>
{% for account in shortcut_accounts %} {% for account in shortcut_accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash-summary" account.code %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash-summary" account %}">
{{ account.title|title }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}
<div class="dropdown-header">{% trans "All" context "Accounting|Account|" as text %}{{ text|force_escape }}</div> <div class="dropdown-header">{% trans "All" context "Accounting|Account|" as text %}{{ text|force_escape }}</div>
{% for account in all_accounts %} {% for account in all_accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash-summary" account.code %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash-summary" account %}">
{{ account.code }} {{ account.title|title }} {{ account.code }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}
@ -111,7 +111,7 @@ First written: 2020/7/15
<td class="amount {% if item.cumulative_balance < 0 %} text-danger {% endif %}">{{ item.cumulative_balance|accounting_amount }}</td> <td class="amount {% if item.cumulative_balance < 0 %} text-danger {% endif %}">{{ item.cumulative_balance|accounting_amount }}</td>
<td class="actions"> <td class="actions">
{% if item.month is not None %} {% if item.month is not None %}
<a class="btn btn-info" role="button" href="{% url "accounting:cash" current_account.code item.month|date:"Y-m" %}"> <a class="btn btn-info" role="button" href="{% url "accounting:cash" current_account item.month|date:"Y-m" %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
<span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span> <span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span>
</a> </a>
@ -127,7 +127,7 @@ First written: 2020/7/15
{% for item in item_list %} {% for item in item_list %}
<li class="list-group-item {% if item.balance < 0 %} list-group-item-danger {% endif %}"> <li class="list-group-item {% if item.balance < 0 %} list-group-item-danger {% endif %}">
{% if item.month is not None %} {% if item.month is not None %}
<a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:cash" current_account.code item.month|date:"Y-m" %}"> <a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:cash" current_account item.month|date:"Y-m" %}">
{{ item.label }} {{ item.label }}
<div> <div>
<span class="badge badge-success badge-pill"> <span class="badge badge-success badge-pill">

View File

@ -73,13 +73,13 @@ First written: 2020/7/1
<div class="dropdown-menu account-picker"> <div class="dropdown-menu account-picker">
<div class="dropdown-header">{% trans "Shortcuts" context "Accounting|Account|" as text %}{{ text|force_escape }}</div> <div class="dropdown-header">{% trans "Shortcuts" context "Accounting|Account|" as text %}{{ text|force_escape }}</div>
{% for account in shortcut_accounts %} {% for account in shortcut_accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash" account.code period %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash" account period %}">
{{ account.title|title }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}
<div class="dropdown-header">{% trans "All" context "Accounting|Account|" as text %}{{ text|force_escape }}</div> <div class="dropdown-header">{% trans "All" context "Accounting|Account|" as text %}{{ text|force_escape }}</div>
{% for account in all_accounts %} {% for account in all_accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash" account.code period %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:cash" account period %}">
{{ account.code }} {{ account.title|title }} {{ account.code }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}

View File

@ -112,7 +112,7 @@ First written: 2020/7/19
<td class="amount {% if item.balance < 0 %} text-danger {% endif %}">{{ item.balance|accounting_amount }}</td> <td class="amount {% if item.balance < 0 %} text-danger {% endif %}">{{ item.balance|accounting_amount }}</td>
<td class="amount"></td> <td class="amount"></td>
<td class="actions"> <td class="actions">
<a href="{% url "accounting:ledger" item.code period %}" class="btn btn-info" role="button"> <a href="{% url "accounting:ledger" item period %}" class="btn btn-info" role="button">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
<span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span> <span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span>
</a> </a>
@ -172,7 +172,7 @@ First written: 2020/7/19
</li> </li>
{% for item in group.details %} {% for item in group.details %}
<li class="list-group-item d-flex justify-content-between align-items-center account"> <li class="list-group-item d-flex justify-content-between align-items-center account">
<a class="list-group-item-action" href="{% url "accounting:ledger" item.code period %}"> <a class="list-group-item-action" href="{% url "accounting:ledger" item period %}">
{{ item.title|title }} {{ item.title|title }}
<div class="float-right"> <div class="float-right">
<span class="badge {% if item.balance < 0 %} badge-warning {% else %} badge-secondary {% endif %} badge-pill"> <span class="badge {% if item.balance < 0 %} badge-warning {% else %} badge-secondary {% endif %} badge-pill">

View File

@ -71,7 +71,7 @@ First written: 2020/7/16
</button> </button>
<div class="dropdown-menu account-picker"> <div class="dropdown-menu account-picker">
{% for account in accounts %} {% for account in accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:ledger-summary" account.code %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}>" href="{% url "accounting:ledger-summary" account %}">
{{ account.title|title }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}
@ -104,7 +104,7 @@ First written: 2020/7/16
<td class="amount {% if item.cumulative_balance < 0 %} text-danger {% endif %}">{{ item.cumulative_balance|accounting_amount }}</td> <td class="amount {% if item.cumulative_balance < 0 %} text-danger {% endif %}">{{ item.cumulative_balance|accounting_amount }}</td>
<td class="actions"> <td class="actions">
{% if item.month is not None %} {% if item.month is not None %}
<a class="btn btn-info" role="button" href="{% url "accounting:ledger" current_account.code item.month|date:"Y-m" %}"> <a class="btn btn-info" role="button" href="{% url "accounting:ledger" current_account item.month|date:"Y-m" %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
<span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span> <span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span>
</a> </a>
@ -120,7 +120,7 @@ First written: 2020/7/16
{% for item in item_list %} {% for item in item_list %}
<li class="list-group-item {% if current_account.code|first in "12" and item.balance < 0 %} list-group-item-danger {% endif %}"> <li class="list-group-item {% if current_account.code|first in "12" and item.balance < 0 %} list-group-item-danger {% endif %}">
{% if item.month is not None %} {% if item.month is not None %}
<a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" current_account.code item.month|date:"Y-m" %}"> <a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" current_account item.month|date:"Y-m" %}">
{{ item.label }} {{ item.label }}
<div> <div>
<span class="badge badge-success badge-pill"> <span class="badge badge-success badge-pill">

View File

@ -72,7 +72,7 @@ First written: 2020/7/16
</button> </button>
<div class="dropdown-menu account-picker"> <div class="dropdown-menu account-picker">
{% for account in accounts %} {% for account in accounts %}
<a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}" href="{% url "accounting:ledger" account.code period %}"> <a class="dropdown-item {% if account.code == current_account.code %} active {% endif %}" href="{% url "accounting:ledger" account period %}">
{{ account.code }} {{ account.title|title }} {{ account.code }} {{ account.title|title }}
</a> </a>
{% endfor %} {% endfor %}

View File

@ -101,7 +101,7 @@ First written: 2020/7/19
<td class="amount">{{ item.debit|accounting_amount }}</td> <td class="amount">{{ item.debit|accounting_amount }}</td>
<td class="amount">{{ item.credit|accounting_amount }}</td> <td class="amount">{{ item.credit|accounting_amount }}</td>
<td class="actions"> <td class="actions">
<a href="{% url "accounting:ledger" item.code period %}" class="btn btn-info" role="button"> <a href="{% url "accounting:ledger" item period %}" class="btn btn-info" role="button">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
<span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span> <span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span>
</a> </a>
@ -133,7 +133,7 @@ First written: 2020/7/19
<ul class="list-group d-lg-none trial-balance-list"> <ul class="list-group d-lg-none trial-balance-list">
{% for item in item_list %} {% for item in item_list %}
<li class="list-group-item"> <li class="list-group-item">
<a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" item.code period.spec %}"> <a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" item period.spec %}">
{{ item.title }} {{ item.title }}
<div> <div>
{% if item.debit is not None %} {% if item.debit is not None %}

View File

@ -26,26 +26,27 @@ from . import views, converters
from .views import reports from .views import reports
register_converter(converters.TransactionTypeConverter, "txn-type") register_converter(converters.TransactionTypeConverter, "txn-type")
register_converter(converters.PeriodConverter, "period") register_converter(converters.PeriodConverter, "period")
register_converter(converters.CashAccountConverter, "cash-account")
register_converter(converters.LedgerAccountConverter, "ledger-account")
app_name = "accounting" app_name = "accounting"
urlpatterns = [ urlpatterns = [
path("", views.home, name="home"), path("", views.home, name="home"),
path("cash", reports.cash_default, name="cash.home"), path("cash", reports.cash_default, name="cash.home"),
path("cash/<str:account_code>/<period:period>", path("cash/<cash-account:account>/<period:period>",
reports.cash, name="cash"), reports.cash, name="cash"),
path("cash-summary", path("cash-summary",
reports.cash_summary_default, name="cash-summary.home"), reports.cash_summary_default, name="cash-summary.home"),
path("cash-summary/<str:account_code>", path("cash-summary/<cash-account:account>",
reports.cash_summary, name="cash-summary"), reports.cash_summary, name="cash-summary"),
path("ledger", path("ledger",
reports.ledger_default, name="ledger.home"), reports.ledger_default, name="ledger.home"),
path("ledger/<str:account_code>/<period:period>", path("ledger/<ledger-account:account>/<period:period>",
reports.ledger, name="ledger"), reports.ledger, name="ledger"),
path("ledger-summary", path("ledger-summary",
reports.ledger_summary_default, name="ledger-summary.home"), reports.ledger_summary_default, name="ledger-summary.home"),
path("ledger-summary/<str:account_code>", path("ledger-summary/<ledger-account:account>",
reports.ledger_summary, name="ledger-summary"), reports.ledger_summary, name="ledger-summary"),
path("journal", path("journal",
reports.journal_default, name="journal.home"), reports.journal_default, name="journal.home"),

View File

@ -48,8 +48,8 @@ class ReportUrl:
balance_sheet (str): The URL of the balance sheet. balance_sheet (str): The URL of the balance sheet.
""" """
_period = None _period = None
_cash_account = None _cash = None
_ledger_account = None _ledger = None
def __init__(self, **kwargs): def __init__(self, **kwargs):
if "period" in kwargs: if "period" in kwargs:
@ -57,54 +57,46 @@ class ReportUrl:
else: else:
self._period = Period() self._period = Period()
if "cash" in kwargs: if "cash" in kwargs:
self._cash_account = kwargs["cash"] self._cash = kwargs["cash"]
else: else:
self._cash_account = Account.objects.get( self._cash = Account.objects.get(
code=settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"]) code=settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"])
if "ledger" in kwargs: if "ledger" in kwargs:
self._ledger_account = kwargs["ledger"] self._ledger = kwargs["ledger"]
else: else:
self._ledger_account = Account.objects.get( self._ledger = Account.objects.get(
code=settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"]) code=settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"])
@property @property
def cash(self): def cash(self):
return reverse( return reverse(
"accounting:cash", "accounting:cash", args=(self._cash, self._period))
args=[self._cash_account.code, self._period])
@property @property
def cash_summary(self): def cash_summary(self):
return reverse( return reverse("accounting:cash-summary", args=(self._cash,))
"accounting:cash-summary", args=[self._cash_account.code])
@property @property
def ledger(self): def ledger(self):
return reverse( return reverse(
"accounting:ledger", "accounting:ledger", args=(self._ledger, self._period))
args=[self._ledger_account.code, self._period])
@property @property
def ledger_summary(self): def ledger_summary(self):
return reverse( return reverse("accounting:ledger-summary", args=(self._ledger,))
"accounting:ledger-summary",
args=[self._ledger_account.code])
@property @property
def journal(self): def journal(self):
return reverse("accounting:journal", args=[self._period]) return reverse("accounting:journal", args=(self._period,))
@property @property
def trial_balance(self): def trial_balance(self):
return reverse( return reverse("accounting:trial-balance", args=(self._period,))
"accounting:trial-balance", args=[self._period])
@property @property
def income_statement(self): def income_statement(self):
return reverse( return reverse("accounting:income-statement", args=(self._period,))
"accounting:income-statement", args=[self._period])
@property @property
def balance_sheet(self): def balance_sheet(self):
return reverse( return reverse("accounting:balance-sheet", args=(self._period,))
"accounting:balance-sheet", args=[self._period])

View File

@ -51,35 +51,28 @@ def cash_default(request):
HttpResponseRedirect: The redirection to the default account HttpResponseRedirect: The redirection to the default account
and month. and month.
""" """
account_code = settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"] account = Account.objects.get(
code=settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"])
period_spec = dateformat.format(timezone.localdate(), "Y-m") period_spec = dateformat.format(timezone.localdate(), "Y-m")
return HttpResponseRedirect( return HttpResponseRedirect(
reverse("accounting:cash", args=(account_code, period_spec))) reverse("accounting:cash", args=(account, period_spec)))
@require_GET @require_GET
@digest_login_required @digest_login_required
def cash(request, account_code, period): def cash(request, account, period):
"""The cash account. """The cash account.
Args: Args:
request (HttpRequest) The request. request (HttpRequest) The request.
account_code (str): The code of the specified account. account (Account): The account.
period (Period): The period. period (Period): The period.
Returns: Returns:
HttpResponse: The response. HttpResponse: The response.
""" """
# The account
accounts = _cash_accounts()
current_account = None
for account in accounts:
if account.code == account_code:
current_account = account
if current_account is None:
raise Http404()
# The accounting records # The accounting records
if current_account.code == "0": if account.code == "0":
records = list( records = list(
Record.objects Record.objects
.filter( .filter(
@ -114,14 +107,14 @@ def cash(request, account_code, period):
Q(transaction__in=Transaction.objects.filter( Q(transaction__in=Transaction.objects.filter(
Q(date__gte=period.start), Q(date__gte=period.start),
Q(date__lte=period.end), Q(date__lte=period.end),
Q(record__account__code__startswith=account_code))), Q(record__account__code__startswith=account.code))),
~Q(account__code__startswith=account_code)) ~Q(account__code__startswith=account.code))
.order_by("transaction__date", "transaction__ord", .order_by("transaction__date", "transaction__ord",
"is_credit", "ord")) "is_credit", "ord"))
balance_before = Record.objects\ balance_before = Record.objects\
.filter( .filter(
transaction__date__lt=period.start, transaction__date__lt=period.start,
account__code__startswith=current_account.code)\ account__code__startswith=account.code)\
.aggregate( .aggregate(
balance=Coalesce(Sum(Case(When( balance=Coalesce(Sum(Case(When(
is_credit=True, then=-1), is_credit=True, then=-1),
@ -133,7 +126,7 @@ def cash(request, account_code, period):
record.balance = balance record.balance = balance
record_sum = Record( record_sum = Record(
transaction=Transaction(date=records[-1].transaction.date), transaction=Transaction(date=records[-1].transaction.date),
account=current_account, account=account,
summary=pgettext("Accounting|", "Total"), summary=pgettext("Accounting|", "Total"),
balance=balance balance=balance
) )
@ -152,13 +145,14 @@ def cash(request, account_code, period):
records = pagination.items records = pagination.items
_find_imbalanced(records) _find_imbalanced(records)
_find_order_holes(records) _find_order_holes(records)
accounts = _cash_accounts()
shortcut_accounts = settings.ACCOUNTING["CASH_SHORTCUT_ACCOUNTS"] shortcut_accounts = settings.ACCOUNTING["CASH_SHORTCUT_ACCOUNTS"]
return render(request, "accounting/cash.html", { return render(request, "accounting/cash.html", {
"item_list": records, "item_list": records,
"pagination": pagination, "pagination": pagination,
"current_account": current_account, "current_account": account,
"period": period, "period": period,
"reports": ReportUrl(cash=current_account, period=period), "reports": ReportUrl(cash=account, period=period),
"shortcut_accounts": [x for x in accounts "shortcut_accounts": [x for x in accounts
if x.code in shortcut_accounts], if x.code in shortcut_accounts],
"all_accounts": [x for x in accounts "all_accounts": [x for x in accounts
@ -178,33 +172,28 @@ def cash_summary_default(request):
Returns: Returns:
HttpResponseRedirect: The redirection to the default account. HttpResponseRedirect: The redirection to the default account.
""" """
account_code = settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"] account = Account.objects.get(
code=settings.ACCOUNTING["DEFAULT_CASH_ACCOUNT"])
return HttpResponseRedirect( return HttpResponseRedirect(
reverse("accounting:cash-summary", args=(account_code,))) reverse("accounting:cash-summary", args=(account,)))
@require_GET @require_GET
@digest_login_required @digest_login_required
def cash_summary(request, account_code): def cash_summary(request, account):
"""The cash account summary. """The cash account summary.
Args: Args:
request (HttpRequest) The request. request (HttpRequest) The request.
account_code (str): The code of the specified account. account (Account): The account.
Returns: Returns:
HttpResponse: The response. HttpResponse: The response.
""" """
# The account # The account
accounts = _cash_accounts() accounts = _cash_accounts()
current_account = None
for account in accounts:
if account.code == account_code:
current_account = account
if current_account is None:
raise Http404()
# The month summaries # The month summaries
if current_account.code == "0": if account.code == "0":
months = [RecordSummary(**x) for x in Record.objects months = [RecordSummary(**x) for x in Record.objects
.filter( .filter(
Q(transaction__in=Transaction.objects.filter( Q(transaction__in=Transaction.objects.filter(
@ -233,8 +222,8 @@ def cash_summary(request, account_code):
months = [RecordSummary(**x) for x in Record.objects months = [RecordSummary(**x) for x in Record.objects
.filter( .filter(
Q(transaction__in=Transaction.objects.filter( Q(transaction__in=Transaction.objects.filter(
record__account__code__startswith=account_code)), record__account__code__startswith=account.code)),
~Q(account__code__startswith=account_code)) ~Q(account__code__startswith=account.code))
.annotate(month=TruncMonth("transaction__date")) .annotate(month=TruncMonth("transaction__date"))
.values("month") .values("month")
.order_by("month") .order_by("month")
@ -264,8 +253,8 @@ def cash_summary(request, account_code):
return render(request, "accounting/cash-summary.html", { return render(request, "accounting/cash-summary.html", {
"item_list": pagination.items, "item_list": pagination.items,
"pagination": pagination, "pagination": pagination,
"current_account": current_account, "current_account": account,
"reports": ReportUrl(cash=current_account), "reports": ReportUrl(cash=account),
"shortcut_accounts": [x for x in accounts if "shortcut_accounts": [x for x in accounts if
x.code in shortcut_accounts], x.code in shortcut_accounts],
"all_accounts": [x for x in accounts if "all_accounts": [x for x in accounts if
@ -286,54 +275,46 @@ def ledger_default(request):
HttpResponseRedirect: The redirection to the default account HttpResponseRedirect: The redirection to the default account
and month. and month.
""" """
account_code = settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"] account = Account.objects.get(
code=settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"])
period_spec = dateformat.format(timezone.localdate(), "Y-m") period_spec = dateformat.format(timezone.localdate(), "Y-m")
return HttpResponseRedirect( return HttpResponseRedirect(
reverse("accounting:ledger", reverse("accounting:ledger", args=(account, period_spec)))
args=(account_code, period_spec)))
@require_GET @require_GET
@digest_login_required @digest_login_required
def ledger(request, account_code, period): def ledger(request, account, period):
"""The ledger. """The ledger.
Args: Args:
request (HttpRequest) The request. request (HttpRequest) The request.
account_code (str): The code of the specified account. account (Account): The account.
period (Period): The period. period (Period): The period.
Returns: Returns:
HttpResponse: The response. HttpResponse: The response.
""" """
# The account
accounts = _ledger_accounts()
current_account = None
for account in accounts:
if account.code == account_code:
current_account = account
if current_account is None:
raise Http404()
# The accounting records # The accounting records
records = list( records = list(
Record.objects Record.objects
.filter( .filter(
transaction__date__gte=period.start, transaction__date__gte=period.start,
transaction__date__lte=period.end, transaction__date__lte=period.end,
account__code__startswith=current_account.code) account__code__startswith=account.code)
.order_by("transaction__date", "transaction__ord", "is_credit", "ord")) .order_by("transaction__date", "transaction__ord", "is_credit", "ord"))
if re.match("^[1-3]", current_account.code) is not None: if re.match("^[1-3]", account.code) is not None:
balance = Record.objects\ balance = Record.objects\
.filter( .filter(
transaction__date__lt=period.start, transaction__date__lt=period.start,
account__code__startswith=current_account.code)\ account__code__startswith=account.code)\
.aggregate( .aggregate(
balance=Coalesce(Sum(Case(When( balance=Coalesce(Sum(Case(When(
is_credit=True, then=-1), is_credit=True, then=-1),
default=1) * F("amount")), 0))["balance"] default=1) * F("amount")), 0))["balance"]
record_brought_forward = Record( record_brought_forward = Record(
transaction=Transaction(date=period.start), transaction=Transaction(date=period.start),
account=current_account, account=account,
summary=pgettext("Accounting|", "Brought Forward"), summary=pgettext("Accounting|", "Brought Forward"),
is_credit=balance < 0, is_credit=balance < 0,
amount=abs(balance), amount=abs(balance),
@ -355,10 +336,10 @@ def ledger(request, account_code, period):
return render(request, "accounting/ledger.html", { return render(request, "accounting/ledger.html", {
"item_list": records, "item_list": records,
"pagination": pagination, "pagination": pagination,
"current_account": current_account, "current_account": account,
"period": period, "period": period,
"reports": ReportUrl(ledger=current_account, period=period), "reports": ReportUrl(ledger=account, period=period),
"accounts": accounts, "accounts": _ledger_accounts(),
}) })
@ -374,35 +355,27 @@ def ledger_summary_default(request):
Returns: Returns:
HttpResponseRedirect: The redirection to the default account. HttpResponseRedirect: The redirection to the default account.
""" """
account_code = settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"] account = Account.objects.get(
print(account_code) code=settings.ACCOUNTING["DEFAULT_LEDGER_ACCOUNT"])
return HttpResponseRedirect( return HttpResponseRedirect(
reverse("accounting:ledger-summary", args=(account_code,))) reverse("accounting:ledger-summary", args=(account,)))
@require_GET @require_GET
@digest_login_required @digest_login_required
def ledger_summary(request, account_code): def ledger_summary(request, account):
"""The ledger summary report. """The ledger summary report.
Args: Args:
request (HttpRequest) The request. request (HttpRequest) The request.
account_code (str): The code of the specified account. account (Account): The account.
Returns: Returns:
HttpResponse: The response. HttpResponse: The response.
""" """
# The account
accounts = _ledger_accounts()
current_account = None
for account in accounts:
if account.code == account_code:
current_account = account
if current_account is None:
raise Http404()
# The month summaries # The month summaries
months = [RecordSummary(**x) for x in Record.objects months = [RecordSummary(**x) for x in Record.objects
.filter(account__code__startswith=current_account.code) .filter(account__code__startswith=account.code)
.annotate(month=TruncMonth("transaction__date")) .annotate(month=TruncMonth("transaction__date"))
.values("month") .values("month")
.order_by("month") .order_by("month")
@ -431,9 +404,9 @@ def ledger_summary(request, account_code):
return render(request, "accounting/ledger-summary.html", { return render(request, "accounting/ledger-summary.html", {
"item_list": pagination.items, "item_list": pagination.items,
"pagination": pagination, "pagination": pagination,
"current_account": current_account, "current_account": account,
"reports": ReportUrl(ledger=current_account), "reports": ReportUrl(ledger=account),
"accounts": accounts, "accounts": _ledger_accounts(),
}) })
@ -763,8 +736,7 @@ def balance_sheet(request, period):
.filter(balance__isnull=False) .filter(balance__isnull=False)
.order_by("code")) .order_by("code"))
for account in accounts: for account in accounts:
account.url = reverse( account.url = reverse("accounting:ledger", args=(account, period))
"accounting:ledger", args=(account.code, period))
balance = Record.objects\ balance = Record.objects\
.filter( .filter(
Q(transaction__date__lt=period.start) Q(transaction__date__lt=period.start)