2023-02-01 15:37:56 +08:00
|
|
|
# The Mia! Accounting Flask Project.
|
|
|
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/1/30
|
|
|
|
|
|
|
|
# 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 views for the account management.
|
|
|
|
|
|
|
|
"""
|
|
|
|
from urllib.parse import parse_qsl, urlencode
|
|
|
|
|
|
|
|
from flask import Blueprint, render_template, session, redirect, flash, \
|
|
|
|
url_for, request
|
|
|
|
from werkzeug.datastructures import ImmutableMultiDict
|
|
|
|
|
2023-02-08 11:13:09 +08:00
|
|
|
from accounting import db
|
2023-02-01 15:37:56 +08:00
|
|
|
from accounting.locale import lazy_gettext
|
2023-02-01 15:44:58 +08:00
|
|
|
from accounting.models import Account, BaseAccount
|
2023-02-01 16:30:02 +08:00
|
|
|
from accounting.utils.next_url import inherit_next, or_next
|
2023-02-01 15:37:56 +08:00
|
|
|
from accounting.utils.pagination import Pagination
|
|
|
|
from accounting.utils.permission import can_view, has_permission, can_edit
|
2023-02-03 10:19:52 +08:00
|
|
|
from .forms import AccountForm, sort_accounts_in, AccountReorderForm
|
2023-02-01 15:37:56 +08:00
|
|
|
|
|
|
|
bp: Blueprint = Blueprint("account", __name__)
|
|
|
|
"""The view blueprint for the account management."""
|
|
|
|
|
|
|
|
|
|
|
|
@bp.get("", endpoint="list")
|
|
|
|
@has_permission(can_view)
|
|
|
|
def list_accounts() -> str:
|
2023-02-06 11:07:18 +08:00
|
|
|
"""Lists the accounts.
|
2023-02-01 15:37:56 +08:00
|
|
|
|
|
|
|
:return: The account list.
|
|
|
|
"""
|
|
|
|
from .query import get_account_query
|
|
|
|
accounts: list[BaseAccount] = get_account_query()
|
|
|
|
pagination: Pagination = Pagination[BaseAccount](accounts)
|
|
|
|
return render_template("accounting/account/list.html",
|
|
|
|
list=pagination.list, pagination=pagination)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.get("/create", endpoint="create")
|
|
|
|
@has_permission(can_edit)
|
|
|
|
def show_add_account_form() -> str:
|
|
|
|
"""Shows the form to add an account.
|
|
|
|
|
|
|
|
:return: The form to add an account.
|
|
|
|
"""
|
|
|
|
if "form" in session:
|
|
|
|
form = AccountForm(ImmutableMultiDict(parse_qsl(session["form"])))
|
|
|
|
del session["form"]
|
|
|
|
form.validate()
|
|
|
|
else:
|
|
|
|
form = AccountForm()
|
|
|
|
return render_template("accounting/account/create.html",
|
|
|
|
form=form)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.post("/store", endpoint="store")
|
|
|
|
@has_permission(can_edit)
|
|
|
|
def add_account() -> redirect:
|
|
|
|
"""Adds an account.
|
|
|
|
|
|
|
|
:return: The redirection to the account detail on success, or the account
|
|
|
|
creation form on error.
|
|
|
|
"""
|
|
|
|
form = AccountForm(request.form)
|
|
|
|
if not form.validate():
|
|
|
|
for key in form.errors:
|
|
|
|
for error in form.errors[key]:
|
|
|
|
flash(error, "error")
|
|
|
|
session["form"] = urlencode(list(request.form.items()))
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(inherit_next(url_for("accounting.account.create")))
|
2023-02-01 15:37:56 +08:00
|
|
|
account: Account = Account()
|
|
|
|
form.populate_obj(account)
|
|
|
|
db.session.add(account)
|
|
|
|
db.session.commit()
|
|
|
|
flash(lazy_gettext("The account is added successfully"), "success")
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(inherit_next(url_for("accounting.account.detail",
|
|
|
|
account=account)))
|
2023-02-01 15:37:56 +08:00
|
|
|
|
|
|
|
|
|
|
|
@bp.get("/<account:account>", endpoint="detail")
|
|
|
|
@has_permission(can_view)
|
|
|
|
def show_account_detail(account: Account) -> str:
|
|
|
|
"""Shows the account detail.
|
|
|
|
|
2023-02-03 09:26:11 +08:00
|
|
|
:param account: The account.
|
|
|
|
:return: The detail.
|
2023-02-01 15:37:56 +08:00
|
|
|
"""
|
|
|
|
return render_template("accounting/account/detail.html", obj=account)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.get("/<account:account>/edit", endpoint="edit")
|
|
|
|
@has_permission(can_edit)
|
|
|
|
def show_account_edit_form(account: Account) -> str:
|
|
|
|
"""Shows the form to edit an account.
|
|
|
|
|
2023-02-03 09:26:11 +08:00
|
|
|
:param account: The account.
|
|
|
|
:return: The form to edit the account.
|
2023-02-01 15:37:56 +08:00
|
|
|
"""
|
|
|
|
form: AccountForm
|
|
|
|
if "form" in session:
|
|
|
|
form = AccountForm(ImmutableMultiDict(parse_qsl(session["form"])))
|
|
|
|
del session["form"]
|
|
|
|
form.validate()
|
|
|
|
else:
|
|
|
|
form = AccountForm(obj=account)
|
|
|
|
return render_template("accounting/account/edit.html",
|
|
|
|
account=account, form=form)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.post("/<account:account>/update", endpoint="update")
|
|
|
|
@has_permission(can_edit)
|
|
|
|
def update_account(account: Account) -> redirect:
|
|
|
|
"""Updates an account.
|
|
|
|
|
2023-02-03 09:26:11 +08:00
|
|
|
:param account: The account.
|
2023-02-01 15:37:56 +08:00
|
|
|
:return: The redirection to the account detail on success, or the account
|
|
|
|
edit form on error.
|
|
|
|
"""
|
|
|
|
form = AccountForm(request.form)
|
|
|
|
if not form.validate():
|
|
|
|
for key in form.errors:
|
|
|
|
for error in form.errors[key]:
|
|
|
|
flash(error, "error")
|
|
|
|
session["form"] = urlencode(list(request.form.items()))
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(inherit_next(url_for("accounting.account.edit",
|
|
|
|
account=account)))
|
2023-02-01 15:37:56 +08:00
|
|
|
with db.session.no_autoflush:
|
|
|
|
form.populate_obj(account)
|
2023-02-07 11:14:15 +08:00
|
|
|
if not account.is_modified:
|
2023-02-01 15:37:56 +08:00
|
|
|
flash(lazy_gettext("The account was not modified."), "success")
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(inherit_next(url_for("accounting.account.detail",
|
|
|
|
account=account)))
|
2023-02-01 15:37:56 +08:00
|
|
|
form.post_update(account)
|
|
|
|
db.session.commit()
|
|
|
|
flash(lazy_gettext("The account is updated successfully."), "success")
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(inherit_next(url_for("accounting.account.detail",
|
|
|
|
account=account)))
|
2023-02-01 15:37:56 +08:00
|
|
|
|
|
|
|
|
|
|
|
@bp.post("/<account:account>/delete", endpoint="delete")
|
|
|
|
@has_permission(can_edit)
|
|
|
|
def delete_account(account: Account) -> redirect:
|
|
|
|
"""Deletes an account.
|
|
|
|
|
2023-02-03 09:26:11 +08:00
|
|
|
:param account: The account.
|
2023-02-01 15:37:56 +08:00
|
|
|
:return: The redirection to the account list on success, or the account
|
|
|
|
detail on error.
|
|
|
|
"""
|
2023-02-07 00:22:23 +08:00
|
|
|
account.delete()
|
2023-02-01 15:37:56 +08:00
|
|
|
sort_accounts_in(account.base_code, account.id)
|
|
|
|
db.session.commit()
|
|
|
|
flash(lazy_gettext("The account is deleted successfully."), "success")
|
2023-02-01 16:30:02 +08:00
|
|
|
return redirect(or_next(url_for("accounting.account.list")))
|
2023-02-03 09:21:07 +08:00
|
|
|
|
|
|
|
|
2023-02-03 10:27:29 +08:00
|
|
|
@bp.get("/bases/<baseAccount:base>", endpoint="order")
|
2023-02-03 12:29:37 +08:00
|
|
|
@has_permission(can_view)
|
2023-02-03 10:19:52 +08:00
|
|
|
def show_account_order(base: BaseAccount) -> str:
|
|
|
|
"""Shows the order of the accounts under a same base account.
|
2023-02-03 09:21:07 +08:00
|
|
|
|
|
|
|
:param base: The base account.
|
2023-02-03 10:19:52 +08:00
|
|
|
:return: The order of the accounts under the base account.
|
2023-02-03 09:21:07 +08:00
|
|
|
"""
|
2023-02-03 10:19:52 +08:00
|
|
|
return render_template("accounting/account/order.html", base=base)
|
2023-02-03 09:21:07 +08:00
|
|
|
|
|
|
|
|
2023-02-03 10:27:29 +08:00
|
|
|
@bp.post("/bases/<baseAccount:base>", endpoint="sort")
|
2023-02-03 09:21:07 +08:00
|
|
|
@has_permission(can_edit)
|
|
|
|
def sort_accounts(base: BaseAccount) -> redirect:
|
2023-02-03 10:19:52 +08:00
|
|
|
"""Reorders the accounts under a base account.
|
2023-02-03 09:21:07 +08:00
|
|
|
|
|
|
|
:param base: The base account.
|
2023-02-03 09:26:11 +08:00
|
|
|
:return: The redirection to the incoming account or the account list. The
|
2023-02-03 10:19:52 +08:00
|
|
|
reordering operation does not fail.
|
2023-02-03 09:21:07 +08:00
|
|
|
"""
|
2023-02-03 10:19:52 +08:00
|
|
|
form: AccountReorderForm = AccountReorderForm(base)
|
2023-02-03 09:21:07 +08:00
|
|
|
form.save_order()
|
|
|
|
if not form.is_modified:
|
|
|
|
flash(lazy_gettext("The order was not modified."), "success")
|
|
|
|
return redirect(or_next(url_for("accounting.account.list")))
|
|
|
|
db.session.commit()
|
|
|
|
flash(lazy_gettext("The order is updated successfully."), "success")
|
|
|
|
return redirect(or_next(url_for("accounting.account.list")))
|