diff --git a/src/accounting/account/views.py b/src/accounting/account/views.py index 20259bc..6fae6ac 100644 --- a/src/accounting/account/views.py +++ b/src/accounting/account/views.py @@ -27,6 +27,7 @@ from werkzeug.datastructures import ImmutableMultiDict from accounting import db from accounting.locale import lazy_gettext from accounting.models import Account, BaseAccount +from accounting.utils.cast import s from accounting.utils.flash_errors import flash_form_errors from accounting.utils.next_uri import inherit_next, or_next from accounting.utils.pagination import Pagination @@ -86,7 +87,7 @@ def add_account() -> redirect: form.populate_obj(account) db.session.add(account) db.session.commit() - flash(lazy_gettext("The account is added successfully"), "success") + flash(s(lazy_gettext("The account is added successfully")), "success") return redirect(inherit_next(__get_detail_uri(account))) @@ -138,12 +139,12 @@ def update_account(account: Account) -> redirect: with db.session.no_autoflush: form.populate_obj(account) if not account.is_modified: - flash(lazy_gettext("The account was not modified."), "success") + flash(s(lazy_gettext("The account was not modified.")), "success") return redirect(inherit_next(__get_detail_uri(account))) account.updated_by_id = get_current_user_pk() account.updated_at = sa.func.now() db.session.commit() - flash(lazy_gettext("The account is updated successfully."), "success") + flash(s(lazy_gettext("The account is updated successfully.")), "success") return redirect(inherit_next(__get_detail_uri(account))) @@ -159,7 +160,7 @@ def delete_account(account: Account) -> redirect: account.delete() sort_accounts_in(account.base_code, account.id) db.session.commit() - flash(lazy_gettext("The account is deleted successfully."), "success") + flash(s(lazy_gettext("The account is deleted successfully.")), "success") return redirect(or_next(__get_list_uri())) @@ -186,10 +187,10 @@ def sort_accounts(base: BaseAccount) -> redirect: form: AccountReorderForm = AccountReorderForm(base) form.save_order() if not form.is_modified: - flash(lazy_gettext("The order was not modified."), "success") + flash(s(lazy_gettext("The order was not modified.")), "success") return redirect(or_next(__get_list_uri())) db.session.commit() - flash(lazy_gettext("The order is updated successfully."), "success") + flash(s(lazy_gettext("The order is updated successfully.")), "success") return redirect(or_next(__get_list_uri())) diff --git a/src/accounting/currency/views.py b/src/accounting/currency/views.py index 2dba542..1983f04 100644 --- a/src/accounting/currency/views.py +++ b/src/accounting/currency/views.py @@ -27,6 +27,7 @@ from werkzeug.datastructures import ImmutableMultiDict from accounting import db from accounting.locale import lazy_gettext from accounting.models import Currency +from accounting.utils.cast import s from accounting.utils.flash_errors import flash_form_errors from accounting.utils.next_uri import inherit_next, or_next from accounting.utils.pagination import Pagination @@ -88,7 +89,7 @@ def add_currency() -> redirect: form.populate_obj(currency) db.session.add(currency) db.session.commit() - flash(lazy_gettext("The currency is added successfully"), "success") + flash(s(lazy_gettext("The currency is added successfully")), "success") return redirect(inherit_next(__get_detail_uri(currency))) @@ -141,12 +142,12 @@ def update_currency(currency: Currency) -> redirect: with db.session.no_autoflush: form.populate_obj(currency) if not currency.is_modified: - flash(lazy_gettext("The currency was not modified."), "success") + flash(s(lazy_gettext("The currency was not modified.")), "success") return redirect(inherit_next(__get_detail_uri(currency))) currency.updated_by_id = get_current_user_pk() currency.updated_at = sa.func.now() db.session.commit() - flash(lazy_gettext("The currency is updated successfully."), "success") + flash(s(lazy_gettext("The currency is updated successfully.")), "success") return redirect(inherit_next(__get_detail_uri(currency))) @@ -161,7 +162,7 @@ def delete_currency(currency: Currency) -> redirect: """ currency.delete() db.session.commit() - flash(lazy_gettext("The currency is deleted successfully."), "success") + flash(s(lazy_gettext("The currency is deleted successfully.")), "success") return redirect(or_next(url_for("accounting.currency.list"))) diff --git a/src/accounting/report/reports/income_expenses.py b/src/accounting/report/reports/income_expenses.py index f91c36a..1571ecf 100644 --- a/src/accounting/report/reports/income_expenses.py +++ b/src/accounting/report/reports/income_expenses.py @@ -37,6 +37,7 @@ from accounting.report.utils.option_link import OptionLink from accounting.report.utils.report_chooser import ReportChooser from accounting.report.utils.report_type import ReportType from accounting.report.utils.urls import income_expenses_url +from accounting.utils.cast import be from accounting.utils.pagination import Pagination @@ -120,7 +121,7 @@ class EntryCollector: else_=-JournalEntry.amount)) select: sa.Select = sa.Select(balance_func)\ .join(Transaction).join(Account)\ - .filter(JournalEntry.currency_code == self.__currency.code, + .filter(be(JournalEntry.currency_code == self.__currency.code), self.__account_condition, Transaction.date < self.__period.start) balance: int | None = db.session.scalar(select) @@ -342,7 +343,7 @@ class PageParams(BasePageParams): self.account.id == 0)] in_use: sa.Select = sa.Select(JournalEntry.account_id)\ .join(Account)\ - .filter(JournalEntry.currency_code == self.currency.code, + .filter(be(JournalEntry.currency_code == self.currency.code), sa.or_(Account.base_code.startswith("11"), Account.base_code.startswith("12"), Account.base_code.startswith("21"), diff --git a/src/accounting/report/reports/ledger.py b/src/accounting/report/reports/ledger.py index 43f9be8..70cb03e 100644 --- a/src/accounting/report/reports/ledger.py +++ b/src/accounting/report/reports/ledger.py @@ -36,6 +36,7 @@ from accounting.report.utils.option_link import OptionLink from accounting.report.utils.report_chooser import ReportChooser from accounting.report.utils.report_type import ReportType from accounting.report.utils.urls import ledger_url +from accounting.utils.cast import be from accounting.utils.pagination import Pagination @@ -116,8 +117,8 @@ class EntryCollector: (JournalEntry.is_debit, JournalEntry.amount), else_=-JournalEntry.amount)) select: sa.Select = sa.Select(balance_func).join(Transaction)\ - .filter(JournalEntry.currency_code == self.__currency.code, - JournalEntry.account_id == self.__account.id, + .filter(be(JournalEntry.currency_code == self.__currency.code), + be(JournalEntry.account_id == self.__account.id), Transaction.date < self.__period.start) balance: int | None = db.session.scalar(select) if balance is None: @@ -303,7 +304,7 @@ class PageParams(BasePageParams): :return: The account options. """ in_use: sa.Select = sa.Select(JournalEntry.account_id)\ - .filter(JournalEntry.currency_code == self.currency.code)\ + .filter(be(JournalEntry.currency_code == self.currency.code))\ .group_by(JournalEntry.account_id) return [OptionLink(str(x), ledger_url(self.currency, x, self.period), x.id == self.account.id) diff --git a/src/accounting/report/reports/search.py b/src/accounting/report/reports/search.py index 8abd93e..e5ac29d 100644 --- a/src/accounting/report/reports/search.py +++ b/src/accounting/report/reports/search.py @@ -32,6 +32,7 @@ from accounting.report.utils.base_report import BaseReport from accounting.report.utils.csv_export import csv_download from accounting.report.utils.report_chooser import ReportChooser from accounting.report.utils.report_type import ReportType +from accounting.utils.cast import be from accounting.utils.pagination import Pagination from accounting.utils.query import parse_query_keywords from .journal import get_csv_rows @@ -124,7 +125,7 @@ class EntryCollector: try: txn_date = datetime.strptime(k, "%Y") conditions.append( - sa.extract("year", Transaction.date) == txn_date.year) + be(sa.extract("year", Transaction.date) == txn_date.year)) except ValueError: pass try: diff --git a/src/accounting/transaction/views.py b/src/accounting/transaction/views.py index ca38ece..99b793a 100644 --- a/src/accounting/transaction/views.py +++ b/src/accounting/transaction/views.py @@ -28,6 +28,7 @@ from werkzeug.datastructures import ImmutableMultiDict from accounting import db from accounting.locale import lazy_gettext from accounting.models import Transaction +from accounting.utils.cast import s from accounting.utils.flash_errors import flash_form_errors from accounting.utils.next_uri import inherit_next, or_next from accounting.utils.permission import has_permission, can_view, can_edit @@ -87,7 +88,7 @@ def add_transaction(txn_type: TransactionType) -> redirect: form.populate_obj(txn) db.session.add(txn) db.session.commit() - flash(lazy_gettext("The transaction is added successfully"), "success") + flash(s(lazy_gettext("The transaction is added successfully")), "success") return redirect(inherit_next(__get_detail_uri(txn))) @@ -141,12 +142,13 @@ def update_transaction(txn: Transaction) -> redirect: with db.session.no_autoflush: form.populate_obj(txn) if not form.is_modified: - flash(lazy_gettext("The transaction was not modified."), "success") + flash(s(lazy_gettext("The transaction was not modified.")), "success") return redirect(inherit_next(__get_detail_uri(txn))) txn.updated_by_id = get_current_user_pk() txn.updated_at = sa.func.now() db.session.commit() - flash(lazy_gettext("The transaction is updated successfully."), "success") + flash(s(lazy_gettext("The transaction is updated successfully.")), + "success") return redirect(inherit_next(__get_detail_uri(txn))) @@ -162,7 +164,8 @@ def delete_transaction(txn: Transaction) -> redirect: txn.delete() sort_transactions_in(txn.date, txn.id) db.session.commit() - flash(lazy_gettext("The transaction is deleted successfully."), "success") + flash(s(lazy_gettext("The transaction is deleted successfully.")), + "success") return redirect(or_next(__get_default_page_uri())) @@ -193,10 +196,10 @@ def sort_transactions(txn_date: date) -> redirect: form: TransactionReorderForm = TransactionReorderForm(txn_date) form.save_order() if not form.is_modified: - flash(lazy_gettext("The order was not modified."), "success") + flash(s(lazy_gettext("The order was not modified.")), "success") return redirect(or_next(__get_default_page_uri())) db.session.commit() - flash(lazy_gettext("The order is updated successfully."), "success") + flash(s(lazy_gettext("The order is updated successfully.")), "success") return redirect(or_next(__get_default_page_uri())) diff --git a/src/accounting/utils/cast.py b/src/accounting/utils/cast.py new file mode 100644 index 0000000..0908b65 --- /dev/null +++ b/src/accounting/utils/cast.py @@ -0,0 +1,43 @@ +# The Mia! Accounting Flask Project. +# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/15 + +# Copyright (c) 2023 imacat. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""The utility to cast a SQLAlchemy column into the column type, to avoid +warnings from the IDE. + +This module should not import any other module from the application. + +""" +import typing as t + +import sqlalchemy as sa + + +def be(expression: t.Any) -> sa.BinaryExpression: + """Casts the SQLAlchemy binary expression to the binary expression type. + + :param expression: The binary expression. + :return: The binary expression itself. + """ + return expression + + +def s(message: t.Any) -> str: + """Casts the LazyString message to the string type. + + :param message: The message. + :return: The binary expression itself. + """ + return message