Added the "accounting-init-db" console command to replace the trivial "accounting-init-base", "accounting-init-accounts" and "accounting-init-currencies" console commands.
This commit is contained in:
parent
371c80f668
commit
c4a8326bfc
22
README.rst
22
README.rst
@ -47,7 +47,8 @@ Prerequisites
|
|||||||
=============
|
=============
|
||||||
|
|
||||||
You need a running Flask application with database user login.
|
You need a running Flask application with database user login.
|
||||||
The primary key of the user data model must be integer.
|
The primary key of the user data model must be integer. You also
|
||||||
|
need at least one user.
|
||||||
|
|
||||||
The following front-end JavaScript libraries must be loaded. You may
|
The following front-end JavaScript libraries must be loaded. You may
|
||||||
download it locally or use CDN_.
|
download it locally or use CDN_.
|
||||||
@ -122,24 +123,13 @@ The following is an example configuration for *Mia! Accounting*.
|
|||||||
Database Initialization
|
Database Initialization
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
After the configuration, you need to run
|
After the configuration, run the ``accounting-init-db`` console
|
||||||
`flask_sqlalchemy.SQLAlchemy.create_all`_ to create the
|
command to initialize the accounting database. You need to specify
|
||||||
database tables that *Mia! Accounting* uses.
|
the username of a user as the data creator.
|
||||||
|
|
||||||
*Mia! Accounting* adds three console commands:
|
|
||||||
|
|
||||||
* ``accounting-init-base``
|
|
||||||
* ``accounting-init-accounts``
|
|
||||||
* ``accounting-init-currencies``
|
|
||||||
|
|
||||||
After database tables are created, run
|
|
||||||
``accounting-init-base`` first, and then the other two commands.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
% flask --app myapp accounting-init-base
|
% flask --app myapp accounting-init-db -u username
|
||||||
% flask --app myapp accounting-init-accounts
|
|
||||||
% flask --app myapp accounting-init-currencies
|
|
||||||
|
|
||||||
|
|
||||||
Navigation Menu
|
Navigation Menu
|
||||||
|
@ -42,7 +42,8 @@ Prerequisites
|
|||||||
-------------
|
-------------
|
||||||
|
|
||||||
You need a running Flask application with database user login.
|
You need a running Flask application with database user login.
|
||||||
The primary key of the user data model must be integer.
|
The primary key of the user data model must be integer. You also
|
||||||
|
need at least one user.
|
||||||
|
|
||||||
The following front-end JavaScript libraries must be loaded. You may
|
The following front-end JavaScript libraries must be loaded. You may
|
||||||
download it locally or use CDN_.
|
download it locally or use CDN_.
|
||||||
@ -67,24 +68,13 @@ See an example in :ref:`example-userutils`.
|
|||||||
Database Initialization
|
Database Initialization
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
After the configuration, you need to run
|
After the configuration, run the ``accounting-init-db`` console
|
||||||
`flask_sqlalchemy.SQLAlchemy.create_all`_ to create the
|
command to initialize the accounting database. You need to specify
|
||||||
database tables that *Mia! Accounting* uses.
|
the username of a user as the data creator.
|
||||||
|
|
||||||
*Mia! Accounting* adds three console commands:
|
|
||||||
|
|
||||||
* ``accounting-init-base``
|
|
||||||
* ``accounting-init-accounts``
|
|
||||||
* ``accounting-init-currencies``
|
|
||||||
|
|
||||||
After database tables are created, run
|
|
||||||
``accounting-init-base`` first, and then the other two commands.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
% flask --app myapp accounting-init-base
|
% flask --app myapp accounting-init-db -u username
|
||||||
% flask --app myapp accounting-init-accounts
|
|
||||||
% flask --app myapp accounting-init-currencies
|
|
||||||
|
|
||||||
|
|
||||||
Navigation Menu
|
Navigation Menu
|
||||||
|
@ -61,6 +61,9 @@ def init_app(app: Flask, user_utils: UserUtilityInterface,
|
|||||||
bp.add_app_template_global(default_currency_code,
|
bp.add_app_template_global(default_currency_code,
|
||||||
"accounting_default_currency_code")
|
"accounting_default_currency_code")
|
||||||
|
|
||||||
|
from .commands import init_db_command
|
||||||
|
app.cli.add_command(init_db_command)
|
||||||
|
|
||||||
from . import locale
|
from . import locale
|
||||||
locale.init_app(app, bp)
|
locale.init_app(app, bp)
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
"""
|
"""
|
||||||
from flask import Flask, Blueprint
|
from flask import Flask, Blueprint
|
||||||
|
|
||||||
|
from .commands import init_accounts_command
|
||||||
|
|
||||||
|
|
||||||
def init_app(app: Flask, bp: Blueprint) -> None:
|
def init_app(app: Flask, bp: Blueprint) -> None:
|
||||||
"""Initialize the application.
|
"""Initialize the application.
|
||||||
@ -32,6 +34,3 @@ def init_app(app: Flask, bp: Blueprint) -> None:
|
|||||||
|
|
||||||
from .views import bp as account_bp
|
from .views import bp as account_bp
|
||||||
bp.register_blueprint(account_bp, url_prefix="/accounts")
|
bp.register_blueprint(account_bp, url_prefix="/accounts")
|
||||||
|
|
||||||
from .commands import init_accounts_command
|
|
||||||
app.cli.add_command(init_accounts_command)
|
|
||||||
|
@ -17,44 +17,19 @@
|
|||||||
"""The console commands for the account management.
|
"""The console commands for the account management.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
from secrets import randbelow
|
from secrets import randbelow
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from flask.cli import with_appcontext
|
|
||||||
|
|
||||||
from accounting import db
|
from accounting import db
|
||||||
from accounting.models import BaseAccount, Account, AccountL10n
|
from accounting.models import BaseAccount, Account, AccountL10n
|
||||||
from accounting.utils.user import has_user, get_user_pk
|
from accounting.utils.user import get_user_pk
|
||||||
|
|
||||||
AccountData = tuple[int, str, int, str, str, str, bool]
|
AccountData = tuple[int, str, int, str, str, str, bool]
|
||||||
"""The format of the account data, as a list of (ID, base account code, number,
|
"""The format of the account data, as a list of (ID, base account code, number,
|
||||||
English, Traditional Chinese, Simplified Chinese, is-need-offset) tuples."""
|
English, Traditional Chinese, Simplified Chinese, is-need-offset) tuples."""
|
||||||
|
|
||||||
|
|
||||||
def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
|
||||||
value: str) -> str:
|
|
||||||
"""Validates the username for the click console command.
|
|
||||||
|
|
||||||
:param ctx: The console command context.
|
|
||||||
:param param: The console command option.
|
|
||||||
:param value: The username.
|
|
||||||
:raise click.BadParameter: When validation fails.
|
|
||||||
:return: The username.
|
|
||||||
"""
|
|
||||||
value = value.strip()
|
|
||||||
if value == "":
|
|
||||||
raise click.BadParameter("Username empty.")
|
|
||||||
if not has_user(value):
|
|
||||||
raise click.BadParameter(f"User {value} does not exist.")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@click.command("accounting-init-accounts")
|
|
||||||
@click.option("-u", "--username", metavar="USERNAME", prompt=True,
|
|
||||||
help="The username.", callback=__validate_username,
|
|
||||||
default=lambda: os.getlogin())
|
|
||||||
@with_appcontext
|
|
||||||
def init_accounts_command(username: str) -> None:
|
def init_accounts_command(username: str) -> None:
|
||||||
"""Initializes the accounts."""
|
"""Initializes the accounts."""
|
||||||
creator_pk: int = get_user_pk(username)
|
creator_pk: int = get_user_pk(username)
|
||||||
@ -63,8 +38,6 @@ def init_accounts_command(username: str) -> None:
|
|||||||
.filter(db.func.length(BaseAccount.code) == 4)\
|
.filter(db.func.length(BaseAccount.code) == 4)\
|
||||||
.order_by(BaseAccount.code).all()
|
.order_by(BaseAccount.code).all()
|
||||||
if len(bases) == 0:
|
if len(bases) == 0:
|
||||||
click.echo("Please initialize the base accounts with "
|
|
||||||
"\"flask accounting-init-base\" first.")
|
|
||||||
raise click.Abort
|
raise click.Abort
|
||||||
|
|
||||||
existing: list[Account] = Account.query.all()
|
existing: list[Account] = Account.query.all()
|
||||||
@ -73,7 +46,6 @@ def init_accounts_command(username: str) -> None:
|
|||||||
bases_to_add: list[BaseAccount] = [x for x in bases
|
bases_to_add: list[BaseAccount] = [x for x in bases
|
||||||
if x.code not in existing_base_code]
|
if x.code not in existing_base_code]
|
||||||
if len(bases_to_add) == 0:
|
if len(bases_to_add) == 0:
|
||||||
click.echo("No more account to import.")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
existing_id: set[int] = {x.id for x in existing}
|
existing_id: set[int] = {x.id for x in existing}
|
||||||
@ -96,7 +68,6 @@ def init_accounts_command(username: str) -> None:
|
|||||||
data.append((get_new_id(), base.code, 1, base.title_l10n,
|
data.append((get_new_id(), base.code, 1, base.title_l10n,
|
||||||
l10n["zh_Hant"], l10n["zh_Hans"], is_need_offset))
|
l10n["zh_Hant"], l10n["zh_Hans"], is_need_offset))
|
||||||
__add_accounting_accounts(data, creator_pk)
|
__add_accounting_accounts(data, creator_pk)
|
||||||
click.echo(F"{len(data)} added. Accounting accounts initialized.")
|
|
||||||
|
|
||||||
|
|
||||||
def __is_need_offset(base_code: str) -> bool:
|
def __is_need_offset(base_code: str) -> bool:
|
||||||
@ -146,4 +117,3 @@ def __add_accounting_accounts(data: list[AccountData], creator_pk: int)\
|
|||||||
for y in (("zh_Hant", x[4]), ("zh_Hans", x[5]))]
|
for y in (("zh_Hant", x[4]), ("zh_Hans", x[5]))]
|
||||||
db.session.bulk_save_objects(accounts)
|
db.session.bulk_save_objects(accounts)
|
||||||
db.session.bulk_save_objects(l10n)
|
db.session.bulk_save_objects(l10n)
|
||||||
db.session.commit()
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
"""
|
"""
|
||||||
from flask import Flask, Blueprint
|
from flask import Flask, Blueprint
|
||||||
|
|
||||||
|
from .commands import init_base_accounts_command
|
||||||
|
|
||||||
|
|
||||||
def init_app(app: Flask, bp: Blueprint) -> None:
|
def init_app(app: Flask, bp: Blueprint) -> None:
|
||||||
"""Initialize the application.
|
"""Initialize the application.
|
||||||
@ -32,6 +34,3 @@ def init_app(app: Flask, bp: Blueprint) -> None:
|
|||||||
|
|
||||||
from .views import bp as base_account_bp
|
from .views import bp as base_account_bp
|
||||||
bp.register_blueprint(base_account_bp, url_prefix="/base-accounts")
|
bp.register_blueprint(base_account_bp, url_prefix="/base-accounts")
|
||||||
|
|
||||||
from .commands import init_base_accounts_command
|
|
||||||
app.cli.add_command(init_base_accounts_command)
|
|
||||||
|
@ -19,22 +19,17 @@
|
|||||||
"""
|
"""
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
import click
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from flask.cli import with_appcontext
|
|
||||||
|
|
||||||
from accounting import data_dir
|
from accounting import data_dir
|
||||||
from accounting import db
|
from accounting import db
|
||||||
from accounting.models import BaseAccount, BaseAccountL10n
|
from accounting.models import BaseAccount, BaseAccountL10n
|
||||||
|
|
||||||
|
|
||||||
@click.command("accounting-init-base")
|
|
||||||
@with_appcontext
|
|
||||||
def init_base_accounts_command() -> None:
|
def init_base_accounts_command() -> None:
|
||||||
"""Initializes the base accounts."""
|
"""Initializes the base accounts."""
|
||||||
if BaseAccount.query.first() is not None:
|
if BaseAccount.query.first() is not None:
|
||||||
click.echo("Base accounts already exist.")
|
return
|
||||||
raise click.Abort
|
|
||||||
|
|
||||||
with open(data_dir / "base_accounts.csv") as fp:
|
with open(data_dir / "base_accounts.csv") as fp:
|
||||||
data: list[dict[str, str]] = [x for x in csv.DictReader(fp)]
|
data: list[dict[str, str]] = [x for x in csv.DictReader(fp)]
|
||||||
@ -48,5 +43,3 @@ def init_base_accounts_command() -> None:
|
|||||||
for x in data for y in locales]
|
for x in data for y in locales]
|
||||||
db.session.execute(sa.insert(BaseAccount), account_data)
|
db.session.execute(sa.insert(BaseAccount), account_data)
|
||||||
db.session.execute(sa.insert(BaseAccountL10n), l10n_data)
|
db.session.execute(sa.insert(BaseAccountL10n), l10n_data)
|
||||||
db.session.commit()
|
|
||||||
click.echo("Base accounts initialized.")
|
|
||||||
|
62
src/accounting/commands.py
Normal file
62
src/accounting/commands.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# The Mia! Accounting Project.
|
||||||
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/10
|
||||||
|
|
||||||
|
# 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 console commands.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
import click
|
||||||
|
from flask.cli import with_appcontext
|
||||||
|
|
||||||
|
from accounting import db
|
||||||
|
from accounting.account import init_accounts_command
|
||||||
|
from accounting.base_account import init_base_accounts_command
|
||||||
|
from accounting.currency import init_currencies_command
|
||||||
|
from accounting.utils.user import has_user
|
||||||
|
|
||||||
|
|
||||||
|
def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
||||||
|
value: str) -> str:
|
||||||
|
"""Validates the username for the click console command.
|
||||||
|
|
||||||
|
:param ctx: The console command context.
|
||||||
|
:param param: The console command option.
|
||||||
|
:param value: The username.
|
||||||
|
:raise click.BadParameter: When validation fails.
|
||||||
|
:return: The username.
|
||||||
|
"""
|
||||||
|
value = value.strip()
|
||||||
|
if value == "":
|
||||||
|
raise click.BadParameter("Username empty.")
|
||||||
|
if not has_user(value):
|
||||||
|
raise click.BadParameter(f"User {value} does not exist.")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("accounting-init-db")
|
||||||
|
@click.option("-u", "--username", metavar="USERNAME", prompt=True,
|
||||||
|
help="The username.", callback=__validate_username,
|
||||||
|
default=lambda: os.getlogin())
|
||||||
|
@with_appcontext
|
||||||
|
def init_db_command(username: str) -> None:
|
||||||
|
"""Initializes the accounting database."""
|
||||||
|
db.create_all()
|
||||||
|
init_base_accounts_command()
|
||||||
|
init_accounts_command(username)
|
||||||
|
init_currencies_command(username)
|
||||||
|
db.session.commit()
|
||||||
|
click.echo("Accounting database initialized.")
|
@ -19,6 +19,8 @@
|
|||||||
"""
|
"""
|
||||||
from flask import Flask, Blueprint
|
from flask import Flask, Blueprint
|
||||||
|
|
||||||
|
from .commands import init_currencies_command
|
||||||
|
|
||||||
|
|
||||||
def init_app(app: Flask, bp: Blueprint) -> None:
|
def init_app(app: Flask, bp: Blueprint) -> None:
|
||||||
"""Initialize the application.
|
"""Initialize the application.
|
||||||
@ -33,6 +35,3 @@ def init_app(app: Flask, bp: Blueprint) -> None:
|
|||||||
from .views import bp as currency_bp, api_bp as currency_api_bp
|
from .views import bp as currency_bp, api_bp as currency_api_bp
|
||||||
bp.register_blueprint(currency_bp, url_prefix="/currencies")
|
bp.register_blueprint(currency_bp, url_prefix="/currencies")
|
||||||
bp.register_blueprint(currency_api_bp, url_prefix="/api/currencies")
|
bp.register_blueprint(currency_api_bp, url_prefix="/api/currencies")
|
||||||
|
|
||||||
from .commands import init_currencies_command
|
|
||||||
app.cli.add_command(init_currencies_command)
|
|
||||||
|
@ -18,41 +18,15 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import csv
|
import csv
|
||||||
import os
|
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
import click
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from flask.cli import with_appcontext
|
|
||||||
|
|
||||||
from accounting import db, data_dir
|
from accounting import db, data_dir
|
||||||
from accounting.models import Currency, CurrencyL10n
|
from accounting.models import Currency, CurrencyL10n
|
||||||
from accounting.utils.user import has_user, get_user_pk
|
from accounting.utils.user import get_user_pk
|
||||||
|
|
||||||
|
|
||||||
def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
|
||||||
value: str) -> str:
|
|
||||||
"""Validates the username for the click console command.
|
|
||||||
|
|
||||||
:param ctx: The console command context.
|
|
||||||
:param param: The console command option.
|
|
||||||
:param value: The username.
|
|
||||||
:raise click.BadParameter: When validation fails.
|
|
||||||
:return: The username.
|
|
||||||
"""
|
|
||||||
value = value.strip()
|
|
||||||
if value == "":
|
|
||||||
raise click.BadParameter("Username empty.")
|
|
||||||
if not has_user(value):
|
|
||||||
raise click.BadParameter(f"User {value} does not exist.")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@click.command("accounting-init-currencies")
|
|
||||||
@click.option("-u", "--username", metavar="USERNAME", prompt=True,
|
|
||||||
help="The username.", callback=__validate_username,
|
|
||||||
default=lambda: os.getlogin())
|
|
||||||
@with_appcontext
|
|
||||||
def init_currencies_command(username: str) -> None:
|
def init_currencies_command(username: str) -> None:
|
||||||
"""Initializes the currencies."""
|
"""Initializes the currencies."""
|
||||||
existing_codes: set[str] = {x.code for x in Currency.query.all()}
|
existing_codes: set[str] = {x.code for x in Currency.query.all()}
|
||||||
@ -62,7 +36,6 @@ def init_currencies_command(username: str) -> None:
|
|||||||
to_add: list[dict[str, str]] = [x for x in data
|
to_add: list[dict[str, str]] = [x for x in data
|
||||||
if x["code"] not in existing_codes]
|
if x["code"] not in existing_codes]
|
||||||
if len(to_add) == 0:
|
if len(to_add) == 0:
|
||||||
click.echo("No more currency to add.")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
creator_pk: int = get_user_pk(username)
|
creator_pk: int = get_user_pk(username)
|
||||||
@ -78,6 +51,3 @@ def init_currencies_command(username: str) -> None:
|
|||||||
for x in to_add for y in locales]
|
for x in to_add for y in locales]
|
||||||
db.session.execute(sa.insert(Currency), currency_data)
|
db.session.execute(sa.insert(Currency), currency_data)
|
||||||
db.session.execute(sa.insert(CurrencyL10n), l10n_data)
|
db.session.execute(sa.insert(CurrencyL10n), l10n_data)
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
click.echo(F"{len(to_add)} added. Currencies initialized.")
|
|
||||||
|
@ -21,7 +21,6 @@ import unittest
|
|||||||
from datetime import timedelta, date
|
from datetime import timedelta, date
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import sqlalchemy as sa
|
|
||||||
from click.testing import Result
|
from click.testing import Result
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask.testing import FlaskCliRunner
|
from flask.testing import FlaskCliRunner
|
||||||
@ -65,59 +64,6 @@ PREFIX: str = "/accounting/accounts"
|
|||||||
"""The URL prefix for the account management."""
|
"""The URL prefix for the account management."""
|
||||||
|
|
||||||
|
|
||||||
class AccountCommandTestCase(unittest.TestCase):
|
|
||||||
"""The account console command test case."""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""Sets up the test.
|
|
||||||
This is run once per test.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
self.app: Flask = create_test_app()
|
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
from accounting.models import BaseAccount, Account, AccountL10n
|
|
||||||
result: Result
|
|
||||||
result = runner.invoke(args="init-db")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
if BaseAccount.query.first() is None:
|
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
AccountL10n.query.delete()
|
|
||||||
Account.query.delete()
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
def test_init(self) -> None:
|
|
||||||
"""Tests the "accounting-init-account" console command.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
from accounting.models import BaseAccount, Account, AccountL10n
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
result: Result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
with self.app.app_context():
|
|
||||||
bases: list[BaseAccount] = BaseAccount.query\
|
|
||||||
.filter(sa.func.char_length(BaseAccount.code) == 4).all()
|
|
||||||
accounts: list[Account] = Account.query.all()
|
|
||||||
l10n: list[AccountL10n] = AccountL10n.query.all()
|
|
||||||
self.assertEqual({x.code for x in bases},
|
|
||||||
{x.base_code for x in accounts})
|
|
||||||
self.assertEqual(len(accounts), len(bases))
|
|
||||||
self.assertEqual(len(l10n), len(bases) * 2)
|
|
||||||
base_dict: dict[str, BaseAccount] = {x.code: x for x in bases}
|
|
||||||
for account in accounts:
|
|
||||||
base: BaseAccount = base_dict[account.base_code]
|
|
||||||
self.assertEqual(account.no, 1)
|
|
||||||
self.assertEqual(account.title_l10n, base.title_l10n)
|
|
||||||
self.assertEqual({x.locale: x.title for x in account.l10n},
|
|
||||||
{x.locale: x.title for x in base.l10n})
|
|
||||||
|
|
||||||
|
|
||||||
class AccountTestCase(unittest.TestCase):
|
class AccountTestCase(unittest.TestCase):
|
||||||
"""The account test case."""
|
"""The account test case."""
|
||||||
|
|
||||||
@ -131,13 +77,12 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, Account, AccountL10n
|
from accounting.models import Account, AccountL10n
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
self.assertEqual(result.exit_code, 0)
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
AccountL10n.query.delete()
|
AccountL10n.query.delete()
|
||||||
Account.query.delete()
|
Account.query.delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -652,14 +597,6 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(response.headers["Location"], detail_uri)
|
self.assertEqual(response.headers["Location"], detail_uri)
|
||||||
|
|
||||||
response = self.client.post("/accounting/currencies/store",
|
|
||||||
data={"csrf_token": self.csrf_token,
|
|
||||||
"code": "USD",
|
|
||||||
"name": "US Dollars"})
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
self.assertEqual(response.headers["Location"],
|
|
||||||
"/accounting/currencies/USD")
|
|
||||||
|
|
||||||
add_journal_entry(self.client,
|
add_journal_entry(self.client,
|
||||||
form={"csrf_token": self.csrf_token,
|
form={"csrf_token": self.csrf_token,
|
||||||
"next": NEXT_URI,
|
"next": NEXT_URI,
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
"""The test for the base account management.
|
"""The test for the base account management.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import csv
|
|
||||||
import typing as t
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@ -34,59 +32,6 @@ DETAIL_URI: str = "/accounting/base-accounts/1111"
|
|||||||
"""The detail URI."""
|
"""The detail URI."""
|
||||||
|
|
||||||
|
|
||||||
class BaseAccountCommandTestCase(unittest.TestCase):
|
|
||||||
"""The base account console command test case."""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""Sets up the test.
|
|
||||||
This is run once per test.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
from accounting.models import BaseAccount, BaseAccountL10n
|
|
||||||
self.app: Flask = create_test_app()
|
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
result: Result = runner.invoke(args="init-db")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
BaseAccountL10n.query.delete()
|
|
||||||
BaseAccount.query.delete()
|
|
||||||
|
|
||||||
def test_init(self) -> None:
|
|
||||||
"""Tests the "accounting-init-base" console command.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
from accounting import data_dir
|
|
||||||
from accounting.models import BaseAccount
|
|
||||||
|
|
||||||
with open(data_dir / "base_accounts.csv") as fp:
|
|
||||||
data: dict[dict[str, t.Any]] \
|
|
||||||
= {x["code"]: {"code": x["code"],
|
|
||||||
"title": x["title"],
|
|
||||||
"l10n": {y[5:]: x[y]
|
|
||||||
for y in x if y.startswith("l10n-")}}
|
|
||||||
for x in csv.DictReader(fp)}
|
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
result: Result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
with self.app.app_context():
|
|
||||||
accounts: list[BaseAccount] = BaseAccount.query.all()
|
|
||||||
|
|
||||||
self.assertEqual(len(accounts), len(data))
|
|
||||||
for account in accounts:
|
|
||||||
self.assertIn(account.code, data)
|
|
||||||
self.assertEqual(account.title_l10n, data[account.code]["title"])
|
|
||||||
l10n: dict[str, str] = {x.locale: x.title for x in account.l10n}
|
|
||||||
self.assertEqual(len(l10n), len(data[account.code]["l10n"]))
|
|
||||||
for locale in l10n:
|
|
||||||
self.assertIn(locale, data[account.code]["l10n"])
|
|
||||||
self.assertEqual(l10n[locale],
|
|
||||||
data[account.code]["l10n"][locale])
|
|
||||||
|
|
||||||
|
|
||||||
class BaseAccountTestCase(unittest.TestCase):
|
class BaseAccountTestCase(unittest.TestCase):
|
||||||
"""The base account test case."""
|
"""The base account test case."""
|
||||||
|
|
||||||
@ -96,16 +41,14 @@ class BaseAccountTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
from accounting.models import BaseAccount
|
|
||||||
self.app: Flask = create_test_app()
|
self.app: Flask = create_test_app()
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
result: Result = runner.invoke(args="init-db")
|
result: Result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
self.assertEqual(result.exit_code, 0)
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
161
tests/test_commands.py
Normal file
161
tests/test_commands.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
# The Mia! Accounting Project.
|
||||||
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/10
|
||||||
|
|
||||||
|
# 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 test for the console commands.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import csv
|
||||||
|
import typing as t
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from click.testing import Result
|
||||||
|
from flask import Flask
|
||||||
|
from flask.testing import FlaskCliRunner
|
||||||
|
from sqlalchemy.sql.ddl import DropTable
|
||||||
|
|
||||||
|
from test_site import db
|
||||||
|
from testlib import create_test_app
|
||||||
|
|
||||||
|
|
||||||
|
class ConsoleCommandTestCase(unittest.TestCase):
|
||||||
|
"""The console command test case."""
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
"""Sets up the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
self.app: Flask = create_test_app()
|
||||||
|
|
||||||
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
|
with self.app.app_context():
|
||||||
|
result: Result = runner.invoke(args="init-db")
|
||||||
|
self.assertEqual(result.exit_code, 0,
|
||||||
|
result.output + str(result.exception))
|
||||||
|
# Drop every accounting table, to see if accounting-init recreates
|
||||||
|
# them correctly.
|
||||||
|
tables: list[sa.Table] \
|
||||||
|
= [db.metadata.tables[x] for x in db.metadata.tables
|
||||||
|
if x.startswith("accounting_")]
|
||||||
|
for table in tables:
|
||||||
|
db.session.execute(DropTable(table))
|
||||||
|
db.session.commit()
|
||||||
|
inspector: sa.Inspector = sa.inspect(db.session.connection())
|
||||||
|
self.assertEqual(len({x for x in inspector.get_table_names()
|
||||||
|
if x.startswith("accounting_")}),
|
||||||
|
0)
|
||||||
|
|
||||||
|
def test_init(self) -> None:
|
||||||
|
"""Tests the "accounting-init" console command.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
|
with self.app.app_context():
|
||||||
|
result: Result = runner.invoke(
|
||||||
|
args=["accounting-init-db", "-u", "editor"])
|
||||||
|
self.assertEqual(result.exit_code, 0,
|
||||||
|
result.output + str(result.exception))
|
||||||
|
self.__test_base_account_data()
|
||||||
|
self.__test_account_data()
|
||||||
|
self.__test_currency_data()
|
||||||
|
|
||||||
|
def __test_base_account_data(self) -> None:
|
||||||
|
"""Tests the base account data.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
from accounting import data_dir
|
||||||
|
from accounting.models import BaseAccount
|
||||||
|
|
||||||
|
with open(data_dir / "base_accounts.csv") as fp:
|
||||||
|
data: dict[dict[str, t.Any]] \
|
||||||
|
= {x["code"]: {"code": x["code"],
|
||||||
|
"title": x["title"],
|
||||||
|
"l10n": {y[5:]: x[y]
|
||||||
|
for y in x if y.startswith("l10n-")}}
|
||||||
|
for x in csv.DictReader(fp)}
|
||||||
|
|
||||||
|
with self.app.app_context():
|
||||||
|
accounts: list[BaseAccount] = BaseAccount.query.all()
|
||||||
|
|
||||||
|
self.assertEqual(len(accounts), len(data))
|
||||||
|
for account in accounts:
|
||||||
|
self.assertIn(account.code, data)
|
||||||
|
self.assertEqual(account.title_l10n, data[account.code]["title"])
|
||||||
|
l10n: dict[str, str] = {x.locale: x.title for x in account.l10n}
|
||||||
|
self.assertEqual(len(l10n), len(data[account.code]["l10n"]))
|
||||||
|
for locale in l10n:
|
||||||
|
self.assertIn(locale, data[account.code]["l10n"])
|
||||||
|
self.assertEqual(l10n[locale],
|
||||||
|
data[account.code]["l10n"][locale])
|
||||||
|
|
||||||
|
def __test_account_data(self) -> None:
|
||||||
|
"""Tests the account data.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
from accounting.models import BaseAccount, Account, AccountL10n
|
||||||
|
|
||||||
|
with self.app.app_context():
|
||||||
|
bases: list[BaseAccount] = BaseAccount.query\
|
||||||
|
.filter(sa.func.char_length(BaseAccount.code) == 4).all()
|
||||||
|
accounts: list[Account] = Account.query.all()
|
||||||
|
l10n: list[AccountL10n] = AccountL10n.query.all()
|
||||||
|
|
||||||
|
self.assertEqual({x.code for x in bases},
|
||||||
|
{x.base_code for x in accounts})
|
||||||
|
self.assertEqual(len(accounts), len(bases))
|
||||||
|
self.assertEqual(len(l10n), len(bases) * 2)
|
||||||
|
base_dict: dict[str, BaseAccount] = {x.code: x for x in bases}
|
||||||
|
for account in accounts:
|
||||||
|
base: BaseAccount = base_dict[account.base_code]
|
||||||
|
self.assertEqual(account.no, 1)
|
||||||
|
self.assertEqual(account.title_l10n, base.title_l10n)
|
||||||
|
self.assertEqual({x.locale: x.title for x in account.l10n},
|
||||||
|
{x.locale: x.title for x in base.l10n})
|
||||||
|
|
||||||
|
def __test_currency_data(self) -> None:
|
||||||
|
"""Tests the currency data.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
from accounting import data_dir
|
||||||
|
from accounting.models import Currency
|
||||||
|
|
||||||
|
with open(data_dir / "currencies.csv") as fp:
|
||||||
|
data: dict[dict[str, t.Any]] \
|
||||||
|
= {x["code"]: {"code": x["code"],
|
||||||
|
"name": x["name"],
|
||||||
|
"l10n": {y[5:]: x[y]
|
||||||
|
for y in x if y.startswith("l10n-")}}
|
||||||
|
for x in csv.DictReader(fp)}
|
||||||
|
|
||||||
|
with self.app.app_context():
|
||||||
|
currencies: list[Currency] = Currency.query.all()
|
||||||
|
|
||||||
|
self.assertEqual(len(currencies), len(data))
|
||||||
|
for currency in currencies:
|
||||||
|
self.assertIn(currency.code, data)
|
||||||
|
self.assertEqual(currency.name_l10n, data[currency.code]["name"])
|
||||||
|
l10n: dict[str, str] = {x.locale: x.name for x in currency.l10n}
|
||||||
|
self.assertEqual(len(l10n), len(data[currency.code]["l10n"]))
|
||||||
|
for locale in l10n:
|
||||||
|
self.assertIn(locale, data[currency.code]["l10n"])
|
||||||
|
self.assertEqual(l10n[locale],
|
||||||
|
data[currency.code]["l10n"][locale])
|
@ -17,8 +17,6 @@
|
|||||||
"""The test for the currency management.
|
"""The test for the currency management.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import csv
|
|
||||||
import typing as t
|
|
||||||
import unittest
|
import unittest
|
||||||
from datetime import timedelta, date
|
from datetime import timedelta, date
|
||||||
|
|
||||||
@ -59,62 +57,6 @@ PREFIX: str = "/accounting/currencies"
|
|||||||
"""The URL prefix for the currency management."""
|
"""The URL prefix for the currency management."""
|
||||||
|
|
||||||
|
|
||||||
class CurrencyCommandTestCase(unittest.TestCase):
|
|
||||||
"""The account console command test case."""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""Sets up the test.
|
|
||||||
This is run once per test.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
self.app: Flask = create_test_app()
|
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
from accounting.models import Currency, CurrencyL10n
|
|
||||||
result: Result
|
|
||||||
result = runner.invoke(args="init-db")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
CurrencyL10n.query.delete()
|
|
||||||
Currency.query.delete()
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
def test_init(self) -> None:
|
|
||||||
"""Tests the "accounting-init-currencies" console command.
|
|
||||||
|
|
||||||
:return: None.
|
|
||||||
"""
|
|
||||||
from accounting import data_dir
|
|
||||||
from accounting.models import Currency
|
|
||||||
|
|
||||||
with open(data_dir / "currencies.csv") as fp:
|
|
||||||
data: dict[dict[str, t.Any]] \
|
|
||||||
= {x["code"]: {"code": x["code"],
|
|
||||||
"name": x["name"],
|
|
||||||
"l10n": {y[5:]: x[y]
|
|
||||||
for y in x if y.startswith("l10n-")}}
|
|
||||||
for x in csv.DictReader(fp)}
|
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
result: Result = runner.invoke(
|
|
||||||
args=["accounting-init-currencies", "-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
currencies: list[Currency] = Currency.query.all()
|
|
||||||
|
|
||||||
self.assertEqual(len(currencies), len(data))
|
|
||||||
for currency in currencies:
|
|
||||||
self.assertIn(currency.code, data)
|
|
||||||
self.assertEqual(currency.name_l10n, data[currency.code]["name"])
|
|
||||||
l10n: dict[str, str] = {x.locale: x.name for x in currency.l10n}
|
|
||||||
self.assertEqual(len(l10n), len(data[currency.code]["l10n"]))
|
|
||||||
for locale in l10n:
|
|
||||||
self.assertIn(locale, data[currency.code]["l10n"])
|
|
||||||
self.assertEqual(l10n[locale],
|
|
||||||
data[currency.code]["l10n"][locale])
|
|
||||||
|
|
||||||
|
|
||||||
class CurrencyTestCase(unittest.TestCase):
|
class CurrencyTestCase(unittest.TestCase):
|
||||||
"""The currency test case."""
|
"""The currency test case."""
|
||||||
|
|
||||||
@ -132,6 +74,8 @@ class CurrencyTestCase(unittest.TestCase):
|
|||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
CurrencyL10n.query.delete()
|
CurrencyL10n.query.delete()
|
||||||
Currency.query.delete()
|
Currency.query.delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -588,21 +532,6 @@ class CurrencyTestCase(unittest.TestCase):
|
|||||||
list_uri: str = PREFIX
|
list_uri: str = PREFIX
|
||||||
response: httpx.Response
|
response: httpx.Response
|
||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
|
||||||
with self.app.app_context():
|
|
||||||
from accounting.models import BaseAccount
|
|
||||||
if BaseAccount.query.first() is None:
|
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
response = self.client.post("/accounting/accounts/store",
|
|
||||||
data={"csrf_token": self.csrf_token,
|
|
||||||
"base_code": "1111",
|
|
||||||
"title": "Cash"})
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
self.assertEqual(response.headers["Location"],
|
|
||||||
"/accounting/accounts/1111-001")
|
|
||||||
|
|
||||||
response = self.client.post(f"{PREFIX}/store",
|
response = self.client.post(f"{PREFIX}/store",
|
||||||
data={"csrf_token": self.csrf_token,
|
data={"csrf_token": self.csrf_token,
|
||||||
"code": JPY.code,
|
"code": JPY.code,
|
||||||
|
@ -41,19 +41,11 @@ class DescriptionEditorTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
|
@ -58,14 +58,7 @@ class CashReceiptJournalEntryTestCase(unittest.TestCase):
|
|||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
@ -672,19 +665,11 @@ class CashDisbursementJournalEntryTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
@ -1272,14 +1257,7 @@ class TransferJournalEntryTestCase(unittest.TestCase):
|
|||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
@ -2141,19 +2119,11 @@ class JournalEntryReorderTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
|
@ -49,19 +49,11 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
|
@ -51,18 +51,11 @@ class OptionTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, Option
|
from accounting.models import Option
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
Option.query.delete()
|
Option.query.delete()
|
||||||
|
|
||||||
|
@ -46,19 +46,11 @@ class ReportTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
|
@ -45,19 +45,11 @@ class UnmatchedOffsetTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
from accounting.models import BaseAccount, JournalEntry, \
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
JournalEntryLineItem
|
|
||||||
result: Result
|
result: Result
|
||||||
result = runner.invoke(args="init-db")
|
result = runner.invoke(args="init-db")
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
if BaseAccount.query.first() is None:
|
result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
||||||
result = runner.invoke(args="accounting-init-base")
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-currencies",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
result = runner.invoke(args=["accounting-init-accounts",
|
|
||||||
"-u", "editor"])
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
self.assertEqual(result.exit_code, 0)
|
||||||
JournalEntry.query.delete()
|
JournalEntry.query.delete()
|
||||||
JournalEntryLineItem.query.delete()
|
JournalEntryLineItem.query.delete()
|
||||||
|
Loading…
Reference in New Issue
Block a user