Compare commits
3 Commits
3adcaa61d3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1289d7cba6 | |||
| d62e295dc6 | |||
| 693c5890ca |
@@ -54,13 +54,20 @@ def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
|||||||
@click.option("-u", "--username", metavar="USERNAME", prompt=True,
|
@click.option("-u", "--username", metavar="USERNAME", prompt=True,
|
||||||
help="The username.", callback=__validate_username,
|
help="The username.", callback=__validate_username,
|
||||||
default=lambda: os.getlogin())
|
default=lambda: os.getlogin())
|
||||||
|
@click.option("--skip-accounts", is_flag=True, default=False,
|
||||||
|
help="Skip initializing accounts.")
|
||||||
|
@click.option("--skip-currencies", is_flag=True, default=False,
|
||||||
|
help="Skip initializing currencies.")
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def init_db_command(username: str) -> None:
|
def init_db_command(username: str, skip_accounts: bool,
|
||||||
|
skip_currencies: bool) -> None:
|
||||||
"""Initializes the accounting database."""
|
"""Initializes the accounting database."""
|
||||||
db.create_all()
|
db.create_all()
|
||||||
init_base_accounts_command()
|
init_base_accounts_command()
|
||||||
init_accounts_command(username)
|
if not skip_accounts:
|
||||||
init_currencies_command(username)
|
init_accounts_command(username)
|
||||||
|
if not skip_currencies:
|
||||||
|
init_currencies_command(username)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo("Accounting database initialized.")
|
click.echo("Accounting database initialized.")
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/1
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/1
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -72,14 +72,10 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app(is_skip_accounts=True)
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import Account, AccountL10n
|
|
||||||
AccountL10n.query.delete()
|
|
||||||
Account.query.delete()
|
|
||||||
db.session.commit()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -105,6 +101,15 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.headers["Location"],
|
self.assertEqual(response.headers["Location"],
|
||||||
f"{PREFIX}/{BANK.code}")
|
f"{PREFIX}/{BANK.code}")
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/1/26
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/1/26
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -22,6 +22,7 @@ import unittest
|
|||||||
import httpx
|
import httpx
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
|
from test_site import db
|
||||||
from testlib import create_test_app, get_client
|
from testlib import create_test_app, get_client
|
||||||
|
|
||||||
LIST_URI: str = "/accounting/base-accounts"
|
LIST_URI: str = "/accounting/base-accounts"
|
||||||
@@ -42,6 +43,15 @@ class BaseAccountTestCase(unittest.TestCase):
|
|||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app()
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/10
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/10
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -45,6 +45,15 @@ class ConsoleCommandTestCase(unittest.TestCase):
|
|||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app()
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_init_db(self) -> None:
|
def test_init_db(self) -> None:
|
||||||
"""Tests the "accounting-init-db" console command.
|
"""Tests the "accounting-init-db" console command.
|
||||||
|
|
||||||
@@ -84,7 +93,7 @@ class ConsoleCommandTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
with open(data_dir / "base_accounts.csv") as fp:
|
with open(data_dir / "base_accounts.csv") as fp:
|
||||||
rows: list[dict[str, str]] = list(csv.DictReader(fp))
|
rows: list[dict[str, str]] = list(csv.DictReader(fp))
|
||||||
data: dict[dict[str, Any]] \
|
data: dict[str, dict[str, Any]] \
|
||||||
= {x["code"]: {"code": x["code"],
|
= {x["code"]: {"code": x["code"],
|
||||||
"title": x["title"],
|
"title": x["title"],
|
||||||
"l10n": {y[5:]: x[y]
|
"l10n": {y[5:]: x[y]
|
||||||
@@ -158,7 +167,7 @@ class ConsoleCommandTestCase(unittest.TestCase):
|
|||||||
from accounting.models import Currency
|
from accounting.models import Currency
|
||||||
|
|
||||||
with open(data_dir / "currencies.csv") as fp:
|
with open(data_dir / "currencies.csv") as fp:
|
||||||
data: dict[dict[str, Any]] \
|
data: dict[str, dict[str, Any]] \
|
||||||
= {x["code"]: {"code": x["code"],
|
= {x["code"]: {"code": x["code"],
|
||||||
"name": x["name"],
|
"name": x["name"],
|
||||||
"l10n": {y[5:]: x[y]
|
"l10n": {y[5:]: x[y]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/1
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/1
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -65,15 +65,9 @@ class CurrencyTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app(is_skip_currencies=True)
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
|
||||||
from accounting.models import Currency, CurrencyL10n
|
|
||||||
CurrencyL10n.query.delete()
|
|
||||||
Currency.query.delete()
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
self.__client: httpx.Client = get_client(self.__app, "editor")
|
self.__client: httpx.Client = get_client(self.__app, "editor")
|
||||||
"""The user client."""
|
"""The user client."""
|
||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
@@ -94,6 +88,15 @@ class CurrencyTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(response.headers["Location"], f"{PREFIX}/{EUR.code}")
|
self.assertEqual(response.headers["Location"], f"{PREFIX}/{EUR.code}")
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/28
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/28
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,7 @@ import httpx
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
from accounting.utils.next_uri import encode_next
|
from accounting.utils.next_uri import encode_next
|
||||||
|
from test_site import db
|
||||||
from testlib import NEXT_URI, Accounts, create_test_app, get_client, \
|
from testlib import NEXT_URI, Accounts, create_test_app, get_client, \
|
||||||
get_csrf_token, add_journal_entry
|
get_csrf_token, add_journal_entry
|
||||||
|
|
||||||
@@ -41,9 +42,6 @@ class DescriptionEditorTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -52,6 +50,15 @@ class DescriptionEditorTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_description_editor(self) -> None:
|
def test_description_editor(self) -> None:
|
||||||
"""Test the description editor.
|
"""Test the description editor.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/24
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/24
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -52,9 +52,6 @@ class CashReceiptJournalEntryTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -63,6 +60,15 @@ class CashReceiptJournalEntryTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
@@ -677,9 +683,6 @@ class CashDisbursementJournalEntryTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -688,6 +691,15 @@ class CashDisbursementJournalEntryTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
@@ -1277,10 +1289,6 @@ class TransferJournalEntryTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, \
|
|
||||||
JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -1289,6 +1297,15 @@ class TransferJournalEntryTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
@@ -2158,9 +2175,6 @@ class JournalEntryReorderTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -2169,6 +2183,15 @@ class JournalEntryReorderTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_change_date(self) -> None:
|
def test_change_date(self) -> None:
|
||||||
"""Tests to change the date of a journal entry.
|
"""Tests to change the date of a journal entry.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/11
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/11
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -49,9 +49,6 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -63,6 +60,15 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
"""The offset test data."""
|
"""The offset test data."""
|
||||||
self.__data.populate()
|
self.__data.populate()
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_add_receivable_offset(self) -> None:
|
def test_add_receivable_offset(self) -> None:
|
||||||
"""Tests to add the receivable offset.
|
"""Tests to add the receivable offset.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/22
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/22
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -45,8 +45,6 @@ class OptionTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import Option
|
|
||||||
Option.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -55,6 +53,15 @@ class OptionTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/9
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/9
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -23,6 +23,7 @@ import unittest
|
|||||||
import httpx
|
import httpx
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
|
from test_site import db
|
||||||
from test_site.lib import BaseTestData
|
from test_site.lib import BaseTestData
|
||||||
from testlib import create_test_app, get_client, get_csrf_token, Accounts
|
from testlib import create_test_app, get_client, get_csrf_token, Accounts
|
||||||
|
|
||||||
@@ -44,16 +45,20 @@ class ReportTestCase(unittest.TestCase):
|
|||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app()
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
|
|
||||||
self.__client: httpx.Client = get_client(self.__app, "editor")
|
self.__client: httpx.Client = get_client(self.__app, "editor")
|
||||||
"""The user client."""
|
"""The user client."""
|
||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -40,10 +40,15 @@ db: SQLAlchemy = SQLAlchemy()
|
|||||||
"""The database instance."""
|
"""The database instance."""
|
||||||
|
|
||||||
|
|
||||||
def create_app(is_testing: bool = False) -> Flask:
|
def create_app(is_testing: bool = False, is_skip_accounts: bool = False,
|
||||||
|
is_skip_currencies: bool = False) -> Flask:
|
||||||
"""Create and configure the application.
|
"""Create and configure the application.
|
||||||
|
|
||||||
:param is_testing: True if we are running for testing, or False otherwise.
|
:param is_testing: True if we are running for testing, or False otherwise.
|
||||||
|
:param is_skip_accounts: True to skip account initialization, or False
|
||||||
|
otherwise.
|
||||||
|
:param is_skip_currencies: True to skip currency initialization, or False
|
||||||
|
otherwise.
|
||||||
:return: The application.
|
:return: The application.
|
||||||
"""
|
"""
|
||||||
import accounting
|
import accounting
|
||||||
@@ -117,15 +122,20 @@ def create_app(is_testing: bool = False) -> Flask:
|
|||||||
accounting.init_app(app, user_utils=UserUtilities())
|
accounting.init_app(app, user_utils=UserUtilities())
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
init_db(app)
|
init_db(app, is_skip_accounts, is_skip_currencies)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
def init_db(app: Flask) -> None:
|
def init_db(app: Flask, is_skip_accounts: bool,
|
||||||
|
is_skip_currencies: bool) -> None:
|
||||||
"""Initializes the database.
|
"""Initializes the database.
|
||||||
|
|
||||||
:param app: The Flask application.
|
:param app: The Flask application.
|
||||||
|
:param is_skip_accounts: True to skip account initialization, or False
|
||||||
|
otherwise.
|
||||||
|
:param is_skip_currencies: True to skip currency initialization, or False
|
||||||
|
otherwise.
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
db.create_all()
|
db.create_all()
|
||||||
@@ -135,7 +145,12 @@ def init_db(app: Flask) -> None:
|
|||||||
db.session.add(User(username=username))
|
db.session.add(User(username=username))
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
runner: FlaskCliRunner = app.test_cli_runner()
|
runner: FlaskCliRunner = app.test_cli_runner()
|
||||||
result: Result = runner.invoke(args=["accounting-init-db", "-u", "editor"])
|
args: list[str] = ["accounting-init-db", "-u", "editor"]
|
||||||
|
if is_skip_accounts:
|
||||||
|
args += ["--skip-accounts"]
|
||||||
|
if is_skip_currencies:
|
||||||
|
args += ["--skip-currencies"]
|
||||||
|
result: Result = runner.invoke(args=args)
|
||||||
assert result.exit_code == 0, result.output + str(result.exception)
|
assert result.exit_code == 0, result.output + str(result.exception)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/8
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/8
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -46,9 +46,6 @@ class UnmatchedOffsetTestCase(unittest.TestCase):
|
|||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
with self.__app.app_context():
|
with self.__app.app_context():
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
|
||||||
JournalEntry.query.delete()
|
|
||||||
JournalEntryLineItem.query.delete()
|
|
||||||
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
self.__encoded_next_uri: str = encode_next(NEXT_URI)
|
||||||
"""The encoded next URI."""
|
"""The encoded next URI."""
|
||||||
|
|
||||||
@@ -57,6 +54,15 @@ class UnmatchedOffsetTestCase(unittest.TestCase):
|
|||||||
self.__csrf_token: str = get_csrf_token(self.__client)
|
self.__csrf_token: str = get_csrf_token(self.__client)
|
||||||
"""The CSRF token."""
|
"""The CSRF token."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_nobody(self) -> None:
|
def test_nobody(self) -> None:
|
||||||
"""Test the permission as nobody.
|
"""Test the permission as nobody.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# The Mia! Accounting Project.
|
# The Mia! Accounting Project.
|
||||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/3
|
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/3
|
||||||
|
|
||||||
# Copyright (c) 2023 imacat.
|
# Copyright (c) 2023-2026 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -27,6 +27,7 @@ from accounting.utils.next_uri import append_next, inherit_next, or_next, \
|
|||||||
encode_next, decode_next
|
encode_next, decode_next
|
||||||
from accounting.utils.pagination import Pagination, DEFAULT_PAGE_SIZE
|
from accounting.utils.pagination import Pagination, DEFAULT_PAGE_SIZE
|
||||||
from accounting.utils.query import parse_query_keywords
|
from accounting.utils.query import parse_query_keywords
|
||||||
|
from test_site import db
|
||||||
from testlib import TEST_SERVER, create_test_app, get_csrf_token, NEXT_URI
|
from testlib import TEST_SERVER, create_test_app, get_csrf_token, NEXT_URI
|
||||||
|
|
||||||
|
|
||||||
@@ -43,6 +44,15 @@ class NextUriTestCase(unittest.TestCase):
|
|||||||
self.__app: Flask = create_test_app()
|
self.__app: Flask = create_test_app()
|
||||||
"""The Flask application."""
|
"""The Flask application."""
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def test_next_uri(self) -> None:
|
def test_next_uri(self) -> None:
|
||||||
"""Tests the next URI utilities with the next URI.
|
"""Tests the next URI utilities with the next URI.
|
||||||
|
|
||||||
@@ -236,6 +246,15 @@ class PaginationTestCase(unittest.TestCase):
|
|||||||
"""The user client."""
|
"""The user client."""
|
||||||
self.__client.headers["Referer"] = TEST_SERVER
|
self.__client.headers["Referer"] = TEST_SERVER
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
"""Tears down the test.
|
||||||
|
This is run once per test.
|
||||||
|
|
||||||
|
:return: None.
|
||||||
|
"""
|
||||||
|
with self.__app.app_context():
|
||||||
|
db.engine.dispose()
|
||||||
|
|
||||||
def __test_success(self, query: str, items: range,
|
def __test_success(self, query: str, items: range,
|
||||||
result: range, is_paged: bool = True,
|
result: range, is_paged: bool = True,
|
||||||
is_reversed: bool | None = None) -> None:
|
is_reversed: bool | None = None) -> None:
|
||||||
|
|||||||
@@ -60,12 +60,18 @@ class Accounts:
|
|||||||
RENT_INCOME: str = "7482-001"
|
RENT_INCOME: str = "7482-001"
|
||||||
|
|
||||||
|
|
||||||
def create_test_app() -> Flask:
|
def create_test_app(is_skip_accounts: bool = False,
|
||||||
|
is_skip_currencies: bool = False) -> Flask:
|
||||||
"""Creates and returns the testing Flask application.
|
"""Creates and returns the testing Flask application.
|
||||||
|
|
||||||
|
:param is_skip_accounts: True to skip account initialization, or False
|
||||||
|
otherwise.
|
||||||
|
:param is_skip_currencies: True to skip currency initialization, or False
|
||||||
|
otherwise.
|
||||||
:return: The testing Flask application.
|
:return: The testing Flask application.
|
||||||
"""
|
"""
|
||||||
app: Flask = create_app(is_testing=True)
|
app: Flask = create_app(is_testing=True, is_skip_accounts=is_skip_accounts,
|
||||||
|
is_skip_currencies=is_skip_currencies)
|
||||||
|
|
||||||
@app.get("/.csrf-token")
|
@app.get("/.csrf-token")
|
||||||
def get_csrf_token_view() -> str:
|
def get_csrf_token_view() -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user