Compare commits

..

10 Commits

8 changed files with 32 additions and 26 deletions

View File

@ -22,6 +22,7 @@ from flask import Blueprint, render_template
from accounting.models import BaseAccount from accounting.models import BaseAccount
from accounting.utils.pagination import Pagination from accounting.utils.pagination import Pagination
from accounting.utils.permission import has_permission, can_view from accounting.utils.permission import has_permission, can_view
from .queries import get_base_account_query
bp: Blueprint = Blueprint("base-account", __name__) bp: Blueprint = Blueprint("base-account", __name__)
"""The view blueprint for the base account management.""" """The view blueprint for the base account management."""
@ -34,7 +35,6 @@ def list_accounts() -> str:
:return: The account list. :return: The account list.
""" """
from .queries import get_base_account_query
accounts: list[BaseAccount] = get_base_account_query() accounts: list[BaseAccount] = get_base_account_query()
pagination: Pagination = Pagination[BaseAccount](accounts) pagination: Pagination = Pagination[BaseAccount](accounts)
return render_template("accounting/base-account/list.html", return render_template("accounting/base-account/list.html",

View File

@ -34,6 +34,7 @@ from accounting.utils.pagination import Pagination
from accounting.utils.permission import has_permission, can_view, can_edit from accounting.utils.permission import has_permission, can_view, can_edit
from accounting.utils.user import get_current_user_pk from accounting.utils.user import get_current_user_pk
from .forms import CurrencyForm from .forms import CurrencyForm
from .queries import get_currency_query
bp: Blueprint = Blueprint("currency", __name__) bp: Blueprint = Blueprint("currency", __name__)
"""The view blueprint for the currency management.""" """The view blueprint for the currency management."""
@ -48,7 +49,6 @@ def list_currencies() -> str:
:return: The currency list. :return: The currency list.
""" """
from .queries import get_currency_query
currencies: list[Currency] = get_currency_query() currencies: list[Currency] = get_currency_query()
pagination: Pagination = Pagination[Currency](currencies) pagination: Pagination = Pagination[Currency](currencies)
return render_template("accounting/currency/list.html", return render_template("accounting/currency/list.html",

View File

@ -23,6 +23,7 @@ from flask import abort
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from werkzeug.routing import BaseConverter from werkzeug.routing import BaseConverter
from accounting import db
from accounting.models import JournalEntry, JournalEntryLineItem from accounting.models import JournalEntry, JournalEntryLineItem
from accounting.utils.journal_entry_types import JournalEntryType from accounting.utils.journal_entry_types import JournalEntryType
@ -37,13 +38,7 @@ class JournalEntryConverter(BaseConverter):
:param value: The journal entry ID. :param value: The journal entry ID.
:return: The corresponding journal entry. :return: The corresponding journal entry.
""" """
journal_entry: JournalEntry | None = JournalEntry.query\ journal_entry: JournalEntry | None = db.session.get(JournalEntry, value)
.join(JournalEntryLineItem)\
.filter(JournalEntry.id == value)\
.options(selectinload(JournalEntry.line_items)
.selectinload(JournalEntryLineItem.offsets)
.selectinload(JournalEntryLineItem.journal_entry))\
.first()
if journal_entry is None: if journal_entry is None:
abort(404) abort(404)
return journal_entry return journal_entry

View File

@ -31,7 +31,7 @@ from accounting import db
from accounting.forms import ACCOUNT_REQUIRED, AccountExists, IsDebitAccount, \ from accounting.forms import ACCOUNT_REQUIRED, AccountExists, IsDebitAccount, \
IsCreditAccount IsCreditAccount
from accounting.locale import lazy_gettext from accounting.locale import lazy_gettext
from accounting.models import Account, JournalEntryLineItem from accounting.models import Account, JournalEntry, JournalEntryLineItem
from accounting.template_filters import format_amount from accounting.template_filters import format_amount
from accounting.utils.cast import be from accounting.utils.cast import be
from accounting.utils.random_id import new_id from accounting.utils.random_id import new_id
@ -127,10 +127,8 @@ class KeepAccountWhenHavingOffset:
assert isinstance(form, LineItemForm) assert isinstance(form, LineItemForm)
if field.data is None or form.id.data is None: if field.data is None or form.id.data is None:
return return
line_item: JournalEntryLineItem | None = db.session\ line_item: JournalEntryLineItem | None \
.query(JournalEntryLineItem)\ = db.session.get(JournalEntryLineItem, form.id.data)
.filter(JournalEntryLineItem.id == form.id.data)\
.options(selectinload(JournalEntryLineItem.offsets)).first()
if line_item is None or len(line_item.offsets) == 0: if line_item is None or len(line_item.offsets) == 0:
return return
if field.data != line_item.account_code: if field.data != line_item.account_code:
@ -344,14 +342,13 @@ class LineItemForm(FlaskForm):
def get_offsets() -> list[JournalEntryLineItem]: def get_offsets() -> list[JournalEntryLineItem]:
if not self.is_need_offset or self.id.data is None: if not self.is_need_offset or self.id.data is None:
return [] return []
return JournalEntryLineItem.query\ return JournalEntryLineItem.query.join(JournalEntry)\
.filter(JournalEntryLineItem.original_line_item_id .filter(JournalEntryLineItem.original_line_item_id
== self.id.data)\ == self.id.data)\
.order_by(JournalEntry.date, JournalEntry.no,
JournalEntryLineItem.no)\
.options(selectinload(JournalEntryLineItem.journal_entry), .options(selectinload(JournalEntryLineItem.journal_entry),
selectinload(JournalEntryLineItem.account), selectinload(JournalEntryLineItem.account)).all()
selectinload(JournalEntryLineItem.offsets)
.selectinload(
JournalEntryLineItem.journal_entry)).all()
setattr(self, "__offsets", get_offsets()) setattr(self, "__offsets", get_offsets())
return getattr(self, "__offsets") return getattr(self, "__offsets")

View File

@ -660,12 +660,8 @@ class JournalEntryLineItem(db.Model):
nullable=True) nullable=True)
"""The ID of the original line item.""" """The ID of the original line item."""
original_line_item = db.relationship("JournalEntryLineItem", original_line_item = db.relationship("JournalEntryLineItem",
back_populates="offsets",
remote_side=id, passive_deletes=True) remote_side=id, passive_deletes=True)
"""The original line item.""" """The original line item."""
offsets = db.relationship("JournalEntryLineItem",
back_populates="original_line_item")
"""The offset items."""
currency_code = db.Column(db.String, currency_code = db.Column(db.String,
db.ForeignKey(Currency.code, onupdate="CASCADE"), db.ForeignKey(Currency.code, onupdate="CASCADE"),
nullable=False) nullable=False)
@ -758,6 +754,21 @@ class JournalEntryLineItem(db.Model):
""" """
setattr(self, "__net_balance", net_balance) setattr(self, "__net_balance", net_balance)
@property
def offsets(self) -> list[t.Self]:
"""Returns the offset items.
:return: The offset items.
"""
if not hasattr(self, "__offsets"):
cls: t.Type[t.Self] = self.__class__
offsets: list[t.Self] = cls.query.join(JournalEntry)\
.filter(JournalEntryLineItem.original_line_item_id == self.id)\
.order_by(JournalEntry.date, JournalEntry.no,
cls.is_debit, cls.no).all()
setattr(self, "__offsets", offsets)
return getattr(self, "__offsets")
@property @property
def query_values(self) -> list[str]: def query_values(self) -> list[str]:
"""Returns the values to be queried. """Returns the values to be queried.

View File

@ -77,6 +77,8 @@ class CSVRow(BaseCSVRow):
"""Constructs a row in the CSV. """Constructs a row in the CSV.
:param journal_entry_date: The journal entry date. :param journal_entry_date: The journal entry date.
:param currency: The currency.
:param account: The account.
:param description: The description. :param description: The description.
:param debit: The debit amount. :param debit: The debit amount.
:param credit: The credit amount. :param credit: The credit amount.
@ -116,6 +118,7 @@ class PageParams(BasePageParams):
"""Constructs the HTML page parameters. """Constructs the HTML page parameters.
:param period: The period. :param period: The period.
:param pagination: The pagination.
:param line_items: The line items. :param line_items: The line items.
""" """
self.period: Period = period self.period: Period = period

View File

@ -123,7 +123,7 @@ class JournalEntryAccountSelector {
option.setShown(false); option.setShown(false);
} }
} }
if (!isAnyMatched) { if (!isAnyMatched && this.#isShowMore) {
this.#optionList.classList.add("d-none"); this.#optionList.classList.add("d-none");
this.#queryNoResult.classList.remove("d-none"); this.#queryNoResult.classList.remove("d-none");
} else { } else {

View File

@ -50,10 +50,10 @@ First written: 2023/3/14
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
{% if line_item.balance %} {% if line_item.net_balance %}
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div>{{ A_("Net balance") }}</div> <div>{{ A_("Net balance") }}</div>
<div>{{ line_item.balance|accounting_format_amount }}</div> <div>{{ line_item.net_balance|accounting_format_amount }}</div>
</div> </div>
{% else %} {% else %}
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">