Added ReportUrl to help building the report chooser in the accounting application.

This commit is contained in:
依瑪貓 2020-07-14 07:41:19 +08:00
parent 39c75f772a
commit ea354ae101
4 changed files with 118 additions and 18 deletions

View File

@ -63,42 +63,42 @@ First written: 2020/7/9
<span class="d-md-none">{% trans "Book" context "Accounting|" as text %}{{ text|force_escape }}</span> <span class="d-md-none">{% trans "Book" context "Accounting|" as text %}{{ text|force_escape }}</span>
</button> </button>
<div class="dropdown-menu subject-picker"> <div class="dropdown-menu subject-picker">
<a class="dropdown-item {% if request.resolver_match.url_name == "cash" %} active {% endif %}" href="{% url "accounting:cash.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "cash" %} active {% endif %}" href="{{ reports.cash }}">
<i class="fas fa-money-bill-wave"></i> <i class="fas fa-money-bill-wave"></i>
{% trans "Cash Account" context "Accounting|" as text %} {% trans "Cash Account" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "cash-summary" %} active {% endif %}" href="{% url "accounting:cash-summary.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "cash-summary" %} active {% endif %}" href="{{ reports.cash_summary }}">
<i class="fas fa-money-bill-wave"></i> <i class="fas fa-money-bill-wave"></i>
{% trans "Cash Summary" context "Accounting|" as text %} {% trans "Cash Summary" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "ledger" %} active {% endif %}" href="{% url "accounting:ledger.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "ledger" %} active {% endif %}" href="{{ reports.ledger }}">
<i class="fas fa-file-invoice-dollar"></i> <i class="fas fa-file-invoice-dollar"></i>
{% trans "Ledger" context "Accounting|" as text %} {% trans "Ledger" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "ledger-summary" %} active {% endif %}" href="{% url "accounting:ledger-summary.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "ledger-summary" %} active {% endif %}" href="{{ reports.ledger_summary }}">
<i class="fas fa-file-invoice-dollar"></i> <i class="fas fa-file-invoice-dollar"></i>
{% trans "Ledger Summary" context "Accounting|" as text %} {% trans "Ledger Summary" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "journal" %} active {% endif %}" href="{% url "accounting:journal.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "journal" %} active {% endif %}" href="{{ reports.journal }}">
<i class="fas fa-book"></i> <i class="fas fa-book"></i>
{% trans "Journal" context "Accounting|" as text %} {% trans "Journal" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "trial-balance" %} active {% endif %}" href="{% url "accounting:trial-balance.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "trial-balance" %} active {% endif %}" href="{{ reports.trial_balance }}">
<i class="fas fa-balance-scale-right"></i> <i class="fas fa-balance-scale-right"></i>
{% trans "Trial Balance" context "Accounting|" as text %} {% trans "Trial Balance" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "income-statement" %} active {% endif %}" href="{% url "accounting:income-statement.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "income-statement" %} active {% endif %}" href="{{ reports.income_statement }}">
<i class="fas fa-file-invoice"></i> <i class="fas fa-file-invoice"></i>
{% trans "Income Statement" context "Accounting|" as text %} {% trans "Income Statement" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}
</a> </a>
<a class="dropdown-item {% if request.resolver_match.url_name == "balance-sheet" %} active {% endif %}" href="{% url "accounting:balance-sheet.home" %}"> <a class="dropdown-item {% if request.resolver_match.url_name == "balance-sheet" %} active {% endif %}" href="{{ reports.balance_sheet }}">
<i class="fas fa-balance-scale"></i> <i class="fas fa-balance-scale"></i>
{% trans "Balance Sheet" context "Accounting|" as text %} {% trans "Balance Sheet" context "Accounting|" as text %}
{{ text|force_escape }} {{ text|force_escape }}

91
accounting/utils.py Normal file
View File

@ -0,0 +1,91 @@
from django.conf import settings
from django.urls import reverse
from accounting.models import Subject
from mia_core.period import Period
class ReportUrl:
"""The URL of the accounting reports.
Args:
**kwargs: the keyword arguments:
period (Period): The currently-specified period.
cash (Subject): The currently-specified subject of the
cash account or cash summary.
ledger (Subject): The currently-specified subject of the
ledger or leger summary.
Attributes:
cash (str): The URL of the cash account.
cash_summary (str): The URL of the cash summary.
ledger (str): The URL of the ledger.
ledger_summary (str): The URL of the ledger summary.
journal (str): The URL of the journal.
trial_balance (str): The URL of the trial balance.
income_statement (str): The URL of the income statement.
balance_sheet (str): The URL of the balance sheet.
"""
_period = None
_cash_subject = None
_ledger_subject = None
def __init__(self, **kwargs):
if "period" in kwargs:
self._period = kwargs["period"]
else:
self._period = Period(None, None, None, None)
if "cash" in kwargs:
self._cash_subject = kwargs["cash"]
else:
self._cash_subject = Subject.objects.filter(
code=settings.ACCOUNTING["DEFAULT_CASH_SUBJECT"]
).first()
if "ledger" in kwargs:
self._ledger_subject = kwargs["ledger"]
else:
self._ledger_subject = Subject.objects.filter(
code=settings.ACCOUNTING["DEFAULT_LEDGER_SUBJECT"]
).first()
@property
def cash(self):
return reverse(
"accounting:cash",
args=[self._cash_subject.code, self._period.spec])
@property
def cash_summary(self):
return reverse(
"accounting:cash-summary", args=[self._cash_subject.code])
@property
def ledger(self):
return reverse(
"accounting:ledger",
args=[self._ledger_subject.code, self._period.spec])
@property
def ledger_summary(self):
return reverse(
"accounting:ledger-summary",
args=[self._ledger_subject.code])
@property
def journal(self):
return reverse("accounting:journal", args=[self._period.spec])
@property
def trial_balance(self):
return reverse(
"accounting:trial-balance", args=[self._period.spec])
@property
def income_statement(self):
return reverse(
"accounting:income-statement", args=[self._period.spec])
@property
def balance_sheet(self):
return reverse(
"accounting:balance-sheet", args=[self._period.spec])

View File

@ -30,6 +30,7 @@ from django.utils.translation import get_language, pgettext
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
from accounting.models import Record, Transaction, Subject from accounting.models import Record, Transaction, Subject
from accounting.utils import ReportUrl
from mia import settings from mia import settings
from mia_core.digest_auth import digest_login_required from mia_core.digest_auth import digest_login_required
from mia_core.period import Period from mia_core.period import Period
@ -198,4 +199,5 @@ ORDER BY
"pagination": pagination, "pagination": pagination,
"subject": subject, "subject": subject,
"period": period, "period": period,
"reports": ReportUrl(cash=subject, period=period)
}) })

View File

@ -33,10 +33,10 @@ class Period:
"""The template helper for the period chooser. """The template helper for the period chooser.
Args: Args:
language (str): The current language. language (str|None): The current language.
data_start (date): The available first day of the data. data_start (date|None): The available first day of the data.
data_end (date): The available last day of the data. data_end (date|None): The available last day of the data.
spec (str): The current period specification spec (str|None): The current period specification
Attributes: Attributes:
spec (date): The currently-working period specification. spec (date): The currently-working period specification.
@ -322,7 +322,7 @@ class Period:
"""The period parser. """The period parser.
Args: Args:
spec (str): The period specification. spec (str|None): The period specification.
Attributes: Attributes:
spec (str): The currently-using period specification. spec (str): The currently-using period specification.
@ -339,6 +339,9 @@ class Period:
error = None error = None
def __init__(self, spec): def __init__(self, spec):
if spec is None:
self.set_this_month()
return
self.spec = spec self.spec = spec
# A specific month # A specific month
m = re.match("^([0-9]{4})-([0-9]{2})$", spec) m = re.match("^([0-9]{4})-([0-9]{2})$", spec)
@ -457,16 +460,20 @@ class Period:
# Wrong period format # Wrong period format
self.invalid_period() self.invalid_period()
def set_this_month(self):
"""Sets the period to this month."""
today = localdate()
self.spec = dateformat.format(today, "Y-m")
self.start = date(today.year, today.month, 1)
self.end = self.get_month_last_day(self.start)
self.description = gettext("This Month")
def invalid_period(self): def invalid_period(self):
"""Sets the period when the period specification is """Sets the period when the period specification is
invalid. invalid.
""" """
self.error = gettext("Invalid period.") self.error = gettext("Invalid period.")
today = localdate() self.set_this_month()
self.spec = dateformat.format(localdate(), "Y-m")
self.start = date(today.year, today.month, 1)
self.end = self.get_month_last_day(self.start)
self.description = gettext("This Month")
@staticmethod @staticmethod
def get_month_last_day(day): def get_month_last_day(day):