14 Commits

15 changed files with 662 additions and 167 deletions

40
.readthedocs.yaml Normal file
View File

@ -0,0 +1,40 @@
# The Mia! Accounting Project.
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/5
# 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.
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation in the docs/ directory with Sphinx
# If using Sphinx, optionally build your docs in additional formats such as PDF
formats: all
# Optionally declare the Python requirements required to build your docs
python:
install:
- method: pip
path: .

View File

@ -15,17 +15,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
recursive-include src/accounting/static *
exclude src/accounting/static/js/dummy.js
include src/accounting/translations/*
include src/accounting/translations/*/LC_MESSAGES/*
include docs/*
include docs/source/*
include docs/source/_static/*
include docs/source/_templates/*
include tests/*
recursive-include src/accounting/templates *
recursive-include src/accounting/translations *
recursive-include src/accounting/data *
recursive-include docs *
recursive-exclude docs/build *
recursive-include tests *
exclude tests/test_temp.py
include tests/test_site/*
include tests/test_site/static/*
include tests/test_site/templates/*
include tests/test_site/translations/*
include tests/test_site/translations/*/LC_MESSAGES/*
recursive-exclude tests *.pyc
recursive-exclude tests/instance *

View File

@ -6,28 +6,212 @@ Mia! Accounting
Description
===========
This is the Mia! Accounting project. It is an accounting
module for the Flask_ applications.
*Mia! Accounting* is an accounting module for Flask_ applications.
It implements `double-entry bookkeeping`_, and generates the following
accounting reports:
* Trial balance
* Income statement
* Balance sheet
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
receivables.
You may try the `Mia! Accounting live demonstration`_.
Install
History
=======
Install ``mia-accounting`` with ``pip``.
I created my own private accounting application in Perl_/mod_perl_ in
2007, as part of my personal website. The first revision was made
using Perl/Mojolicious_ in 2019, with the aim of making it
mobile-friendly using Bootstrap_, and with modern back-end and
front-end technologies such as jQuery.
The second revision was done in Python_/Django_ in 2020, as I was
looking to change my career from PHP_/Laravel_ to Python, but lacked
experience with large Python projects. I wanted to add something new
to my portfolio and decided to work on the somewhat outdated
Mojolicious project.
Despite having no prior experience with Django, I spent two months
working late nights to create the `Mia! Account Django application`_.
It took me another 1.5 months to make it an independent module, which
I later released as an open source project.
The application worked nicely for my household bookkeeping for two
years. However, new demands arose over time, especially with tracking
payables and receivables, which became difficult with credit card
payments. This was critical `during the pandemic`_ as more payments
were made online with credit cards.
The biggest issue I encountered was with Django's MVT framework. Due
to my lack of experience with Django during development, I ended up
with mixed function-based view controllers and class-based views. It
became very difficult to track whether problems originated from my
overridden methods or not-overridden methods, or from the Django base
views themselves. I did not fully understand how everything worked.
Therefore, I decided to turn to microframeworks like Flask. After
working with modularized Flask and FastAPI_ applications for two
years, I returned to the project and wrote its third revision using
Flask in 2023.
Installation
============
Install *Mia! Accounting* with ``pip``:
::
pip install mia-accounting
You may also download the from the `PyPI project page`_ or the
`release page`_ on the `Git repository`_.
Usage
=====
This needs to be done. Currently, you can refer to the test site
located in the test directory on the `Mia! Accounting repository`_.
Prerequisites
=============
The test site is running as the
`live demonstration for Mia! Accounting`_.
You need a running Flask application with database user login.
The primary key of the user data model must be integer.
The following front-end JavaScript libraries must be loaded. You may
download it locally or use CDN_.
* Bootstrap_ 5.2.3 or above
* FontAwesome_ 6.2.1 or above
* `Decimal.js`_ 6.4.3 or above
* `Tempus-Dominus`_ 6.4.3 or above
Configuration
=============
You need to pass the Flask *app* and an implementation of
``UserUtilityInterface`` to the ``init_app`` function.
``UserUtilityInterface`` contains everything *Mia! Accounting* needs.
The following is an example configuration for *Mia! Accounting*.
::
from flask import Response, redirect
from .auth import current_user()
from .modules import User
def create_app(test_config=None) -> Flask:
app: Flask = Flask(__name__)
... (Configuration of SQLAlchemy, CSRF, Babel_JS, ... etc) ...
import accounting
class UserUtilities(accounting.UserUtilityInterface[User]):
def can_view(self) -> bool:
return True
def can_edit(self) -> bool:
return "editor" in current_user().roles
def can_admin(self) -> bool:
return current_user().is_admin
def unauthorized(self) -> Response:
return redirect("/login")
@property
def cls(self) -> t.Type[User]:
return User
@property
def pk_column(self) -> Column:
return User.id
@property
def current_user(self) -> User | None:
return current_user()
def get_by_username(self, username: str) -> User | None:
return User.query.filter(User.username == username).first()
def get_pk(self, user: User) -> int:
return user.id
accounting.init_app(app, UserUtils())
... (Any other configuration) ...
return app
Database Initialization
=======================
After the configuration, you need to run
`flask_sqlalchemy.SQLAlchemy.create_all`_ to create the
database tables that *Mia! Accounting* uses.
*Mia! Accounting* adds three console commands:
* ``accounting-init-base``
* ``accounting-init-accounts``
* ``accounting-init-currencies``
You need to run ``accounting-init-base`` first, and then the other
two commands.
::
% flask --app myapp accounting-init-base
% flask --app myapp accounting-init-accounts
% flask --app myapp accounting-init-currencies
Navigation Menu
===============
Include the navigation menu in the `Bootstrap navigation bar`_ in your
base template:
::
<nav class="navbar navbar-expand-lg bg-body-tertiary bg-dark navbar-dark">
<div class="container-fluid">
...
<div id="collapsible-navbar" class="collapse navbar-collapse">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
...
{% include "accounting/include/nav.html" %}
...
</ul>
...
</div>
</div>
</nav>
Check your Flask application and see how it works.
Test Site and Live Demonstration
================================
You may find a working example in the `test site`_ in the
`source distribution`_. It is the simplest website that works with
*Mia! Accounting*. It is used in the automatic tests. It is the same
code run for `live demonstration`_.
If you do not have a running Flask application, you may start with the
test site.
Documentation
=============
Refer to the `documentation on Read the Docs`_.
Copyright
@ -55,6 +239,32 @@ Authors
| imacat@mail.imacat.idv.tw
| 2023/1/27
.. _Flask: https://flask.palletsprojects.com
.. _Mia! Accounting repository: https://github.com/imacat/mia-accounting
.. _live demonstration for Mia! Accounting: https://accounting.imacat.idv.tw
.. _double-entry bookkeeping: https://en.wikipedia.org/wiki/Double-entry_bookkeeping
.. _Mia! Accounting live demonstration: https://accounting.imacat.idv.tw/
.. _Perl: https://www.perl.org
.. _mod_perl: https://perl.apache.org
.. _Mojolicious: https://mojolicious.org
.. _Bootstrap: https://getbootstrap.com
.. _jQuery: https://jquery.com
.. _Python: https://www.python.org
.. _Django: https://www.djangoproject.com
.. _PHP: https://www.php.net
.. _Laravel: https://laravel.com
.. _Mia! Account Django application: https://github.com/imacat/mia-accounting-django
.. _during the pandemic: https://en.wikipedia.org/wiki/COVID-19_pandemic
.. _FastAPI: https://fastapi.tiangolo.com
.. _FontAwesome: https://fontawesome.com
.. _Decimal.js: https://mikemcl.github.io/decimal.js
.. _Tempus-Dominus: https://getdatepicker.com
.. _CDN: https://en.wikipedia.org/wiki/Content_delivery_network
.. _PyPI project page: https://pypi.org/project/mia-accounting
.. _release page: https://github.com/imacat/mia-accounting/releases
.. _Git repository: https://github.com/imacat/mia-accounting
.. _flask_sqlalchemy.SQLAlchemy.create_all: https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/api/#flask_sqlalchemy.SQLAlchemy.create_all
.. _Bootstrap navigation bar: https://getbootstrap.com/docs/5.3/components/navbar/
.. _test site: https://github.com/imacat/mia-accounting/tree/main/tests/test_site
.. _source distribution: https://pypi.org/project/mia-accounting/#files
.. _live demonstration: https://accounting.imacat.idv.tw
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io

View File

@ -13,7 +13,7 @@ sys.path.insert(0, os.path.abspath('../../src/'))
project = 'Mia! Accounting'
copyright = '2023, imacat'
author = 'imacat'
release = '0.11.0'
release = '1.0.0'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

61
docs/source/examples.rst Normal file
View File

@ -0,0 +1,61 @@
Examples
========
.. _example-userutils:
An Example Configuration
------------------------
The following is an example configuration for *Mia! Accounting*.
::
from flask import Response, redirect
from .auth import current_user()
from .modules import User
def create_app(test_config=None) -> Flask:
app: Flask = Flask(__name__)
... (Configuration of SQLAlchemy, CSRF, Babel_JS, ... etc) ...
import accounting
class UserUtilities(accounting.UserUtilityInterface[User]):
def can_view(self) -> bool:
return True
def can_edit(self) -> bool:
return "editor" in current_user().roles
def can_admin(self) -> bool:
return current_user().is_admin
def unauthorized(self) -> Response:
return redirect("/login")
@property
def cls(self) -> t.Type[User]:
return User
@property
def pk_column(self) -> Column:
return User.id
@property
def current_user(self) -> User | None:
return current_user()
def get_by_username(self, username: str) -> User | None:
return User.query.filter(User.username == username).first()
def get_pk(self, user: User) -> int:
return user.id
accounting.init_app(app, UserUtils())
... (Any other configuration) ...
return app

View File

@ -10,6 +10,10 @@ Welcome to Mia! Accounting's documentation!
:maxdepth: 2
:caption: Contents:
intro
accounting
examples
Indices and tables

188
docs/source/intro.rst Normal file
View File

@ -0,0 +1,188 @@
Introduction
============
*Mia! Accounting* is an accounting module for Flask_ applications.
It implements `double-entry bookkeeping`_, and generates the following
accounting reports:
* Trial balance
* Income statement
* Balance sheet
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
receivables.
You may try the `Mia! Accounting live demonstration`_.
History
-------
I created my own private accounting application in Perl_/mod_perl_ in
2007, as part of my personal website. The first revision was made
using Perl/Mojolicious_ in 2019, with the aim of making it
mobile-friendly using Bootstrap_, and with modern back-end and
front-end technologies such as jQuery.
The second revision was done in Python_/Django_ in 2020, as I was
looking to change my career from PHP_/Laravel_ to Python, but lacked
experience with large Python projects. I wanted to add something new
to my portfolio and decided to work on the somewhat outdated
Mojolicious project.
Despite having no prior experience with Django, I spent two months
working late nights to create the `Mia! Account Django application`_.
It took me another 1.5 months to make it an independent module, which
I later released as an open source project.
The application worked nicely for my household bookkeeping for two
years. However, new demands arose over time, especially with tracking
payables and receivables, which became difficult with credit card
payments. This was critical `during the pandemic`_ as more payments
were made online with credit cards.
The biggest issue I encountered was with Django's MVT framework. Due
to my lack of experience with Django during development, I ended up
with mixed function-based view controllers and class-based views. It
became very difficult to track whether problems originated from my
overridden methods or not-overridden methods, or from the Django base
views themselves. I did not fully understand how everything worked.
Therefore, I decided to turn to microframeworks like Flask. After
working with modularized Flask and FastAPI_ applications for two
years, I returned to the project and wrote its third revision using
Flask in 2023.
Installation
------------
Install *Mia! Accounting* with ``pip``:
::
pip install mia-accounting
You may also download the from the `PyPI project page`_ or the
`release page`_ on the `Git repository`_.
Prerequisites
-------------
You need a running Flask application with database user login.
The primary key of the user data model must be integer.
The following front-end JavaScript libraries must be loaded. You may
download it locally or use CDN_.
* Bootstrap_ 5.2.3 or above
* FontAwesome_ 6.2.1 or above
* `Decimal.js`_ 6.4.3 or above
* `Tempus-Dominus`_ 6.4.3 or above
Configuration
-------------
You need to pass the Flask *app* and an implementation of
:py:class:`accounting.utils.user.UserUtilityInterface` to the
:py:func:`accounting.init_app` function. ``UserUtilityInterface``
contains everything *Mia! Accounting* needs.
See an example in :ref:`example-userutils`.
Database Initialization
-----------------------
After the configuration, you need to run
:py:meth:`flask_sqlalchemy.SQLAlchemy.create_all` to create the
database tables that *Mia! Accounting* uses.
*Mia! Accounting* adds three console commands:
* ``accounting-init-base``
* ``accounting-init-accounts``
* ``accounting-init-currencies``
You need to run ``accounting-init-base`` first, and then the other
two commands.
::
% flask --app myapp accounting-init-base
% flask --app myapp accounting-init-accounts
% flask --app myapp accounting-init-currencies
Navigation Menu
---------------
Include the navigation menu in the `Bootstrap navigation bar`_ in your
base template:
::
<nav class="navbar navbar-expand-lg bg-body-tertiary bg-dark navbar-dark">
<div class="container-fluid">
...
<div id="collapsible-navbar" class="collapse navbar-collapse">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
...
{% include "accounting/include/nav.html" %}
...
</ul>
...
</div>
</div>
</nav>
Check your Flask application and see how it works.
Test Site and Live Demonstration
--------------------------------
You may find a working example in the `test site`_ in the
`source distribution`_. It is the simplest website that works with
*Mia! Accounting*. It is used in the automatic tests. It is the same
code run for `live demonstration`_.
If you do not have a running Flask application, you may start with the
test site.
Documentation
-------------
Refer to the `documentation on Read the Docs`_.
.. _Flask: https://flask.palletsprojects.com
.. _double-entry bookkeeping: https://en.wikipedia.org/wiki/Double-entry_bookkeeping
.. _Mia! Accounting live demonstration: https://accounting.imacat.idv.tw/
.. _Perl: https://www.perl.org
.. _mod_perl: https://perl.apache.org
.. _Mojolicious: https://mojolicious.org
.. _Bootstrap: https://getbootstrap.com
.. _jQuery: https://jquery.com
.. _Python: https://www.python.org
.. _Django: https://www.djangoproject.com
.. _PHP: https://www.php.net
.. _Laravel: https://laravel.com
.. _Mia! Account Django application: https://github.com/imacat/mia-accounting-django
.. _during the pandemic: https://en.wikipedia.org/wiki/COVID-19_pandemic
.. _FastAPI: https://fastapi.tiangolo.com
.. _FontAwesome: https://fontawesome.com
.. _Decimal.js: https://mikemcl.github.io/decimal.js
.. _Tempus-Dominus: https://getdatepicker.com
.. _CDN: https://en.wikipedia.org/wiki/Content_delivery_network
.. _PyPI project page: https://pypi.org/project/mia-accounting
.. _release page: https://github.com/imacat/mia-accounting/releases
.. _Git repository: https://github.com/imacat/mia-accounting
.. _Bootstrap navigation bar: https://getbootstrap.com/docs/5.3/components/navbar/
.. _test site: https://github.com/imacat/mia-accounting/tree/main/tests/test_site
.. _source distribution: https://pypi.org/project/mia-accounting/#files
.. _live demonstration: https://accounting.imacat.idv.tw
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io

View File

@ -1,7 +1,7 @@
# The Mia! Accounting Project.
# Author: imacat@mail.imacat.idv.tw (imacat), 2022/8/21
# Copyright (c) 2022 imacat.
# Copyright (c) 2022-2023 imacat.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,6 +15,51 @@
# See the License for the specific language governing permissions and
# limitations under the License.
[project]
name = "mia-accounting"
version = "1.0.0"
description = "A Flask accounting module."
readme = "README.rst"
requires-python = ">=3.11"
authors = [
{name = "imacat", email = "imacat@mail.imacat.idv.tw"},
]
keywords = ["mia", "accounting", "flask"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Framework :: Flask",
"Topic :: Office/Business :: Financial :: Accounting",
]
dependencies = [
"flask",
"Flask-SQLAlchemy",
"Flask-WTF",
"Flask-Babel >= 3",
"Flask-Babel-JS",
]
[project.optional-dependencies]
test = [
"unittest",
"httpx",
"OpenCC",
]
[project.urls]
"Documentation" = "https://mia-accounting.readthedocs.io"
"Repository" = "https://github.com/imacat/mia-accounting"
"Bug Tracker" = "https://github.com/imacat/mia-accounting/issues"
"Demonstration" = "https://accounting.imacat.idv.tw"
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
[tool.setuptools.exclude-package-data]
"*" = [
"babel.cfg",
"*.pot",
"*.po",
]

View File

@ -1,56 +0,0 @@
# The Mia! Accounting Project.
# Author: imacat@mail.imacat.idv.tw (imacat), 2022/8/21
# Copyright (c) 2022-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.
[metadata]
name = mia-accounting
version = 0.11.0
author = imacat
author_email = imacat@mail.imacat.idv.tw
description = The Mia! Accounting project.
long_description = file: README.rst
long_description_content_type = text/x-rst
url = https://github.com/imacat/mia-accounting
project_urls =
Bug Tracker = https://github.com/imacat/mia-accounting/issues
classifiers =
Programming Language :: Python :: 3
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Framework :: Flask
Topic :: Office/Business :: Financial :: Accounting
[options]
package_dir =
= src
python_requires = >=3.11
install_requires =
flask
Flask-SQLAlchemy
Flask-WTF
Flask-Babel >= 3
Flask-Babel-JS
tests_require =
unittest
httpx
OpenCC
[options.package_data]
accounting =
static/**
templates/**
translations/*/LC_MESSAGES/*.mo
data/**

View File

@ -137,6 +137,7 @@ class AccountCollector:
.join(JournalEntry).join(Account)\
.filter(*conditions)\
.group_by(Account.id, Account.base_code, Account.no)\
.having(balance_func != 0)\
.order_by(Account.base_code, Account.no)
account_balances: list[sa.Row] \
= db.session.execute(select_balance).all()

View File

@ -269,6 +269,7 @@ class IncomeStatement(BaseReport):
.join(JournalEntry).join(Account)\
.filter(*conditions)\
.group_by(Account.id)\
.having(balance_func != 0)\
.order_by(Account.base_code, Account.no)
balances: list[sa.Row] = db.session.execute(select_balances).all()
accounts: dict[int, Account] \

View File

@ -191,6 +191,7 @@ class TrialBalance(BaseReport):
.join(JournalEntry).join(Account)\
.filter(*conditions)\
.group_by(Account.id)\
.having(balance_func != 0)\
.order_by(Account.base_code, Account.no)
balances: list[sa.Row] = db.session.execute(select_balances).all()
accounts: dict[int, Account] \

View File

@ -1,15 +1,15 @@
# Chinese (Traditional) translations for the Mia! Accounting project.
# Copyright (C) 2023 imacat
# This file is distributed under the same license as the Mia! Accounting
# Flask project.
# project.
# imacat <imacat@mail.imacat.idv.tw>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: Mia! Accounting 0.0.0\n"
"Project-Id-Version: mia-accounting 1.0.0\n"
"Report-Msgid-Bugs-To: imacat@mail.imacat.idv.tw\n"
"POT-Creation-Date: 2023-03-23 00:45+0800\n"
"PO-Revision-Date: 2023-03-23 00:46+0800\n"
"POT-Creation-Date: 2023-04-06 02:34+0800\n"
"PO-Revision-Date: 2023-04-06 02:34+0800\n"
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
"Language: zh_Hant\n"
"Language-Team: zh_Hant <imacat@mail.imacat.idv.tw>\n"
@ -20,10 +20,10 @@ msgstr ""
"Generated-By: Babel 2.12.1\n"
#: src/accounting/forms.py:33
#: src/accounting/static/js/journal-entry-form.js:980
#: src/accounting/static/js/journal-entry-line-item-editor.js:430
#: src/accounting/static/js/option-form.js:530
#: src/accounting/static/js/option-form.js:796
#: src/accounting/static/js/journal-entry-form.js:1065
#: src/accounting/static/js/journal-entry-line-item-editor.js:411
#: src/accounting/static/js/option-form.js:537
#: src/accounting/static/js/option-form.js:803
msgid "Please select the account."
msgstr "請選擇科目。"
@ -35,22 +35,22 @@ msgstr "沒有這個貨幣。"
msgid "The account does not exist."
msgstr "沒有這個科目。"
#: src/accounting/models.py:563
#: src/accounting/models.py:562
#, python-format
msgid "Cash Disbursement Journal Entry#%(id)s"
msgstr "現金支出傳票#%(id)s"
#: src/accounting/models.py:566
#: src/accounting/models.py:565
#, python-format
msgid "Cash Receipt Journal Entry#%(id)s"
msgstr "現金收入傳票#%(id)s"
#: src/accounting/models.py:567
#: src/accounting/models.py:566
#, python-format
msgid "Transfer Journal Entry#%(id)s"
msgstr "轉帳傳票#%(id)s"
#: src/accounting/models.py:700
#: src/accounting/models.py:699
#, python-format
msgid "%(date)s %(description)s %(amount)s"
msgstr "%(date)s %(description)s %(amount)s"
@ -92,7 +92,7 @@ msgid "A nominal account does not need offset."
msgstr "虛科目不需抵銷。"
#: src/accounting/account/forms.py:75
#: src/accounting/static/js/account-form.js:181
#: src/accounting/static/js/account-form.js:189
msgid "Please select the base account."
msgstr "請選擇基本科目。"
@ -160,8 +160,8 @@ msgstr "不能用這個代碼。"
#: src/accounting/currency/forms.py:62 src/accounting/option/forms.py:124
#: src/accounting/option/forms.py:148
#: src/accounting/static/js/currency-form.js:153
#: src/accounting/static/js/option-form.js:525
#: src/accounting/static/js/option-form.js:780
#: src/accounting/static/js/option-form.js:532
#: src/accounting/static/js/option-form.js:787
msgid "Please fill in the name."
msgstr "請填上名稱。"
@ -218,23 +218,23 @@ msgid "The currency must not be changed when there is offset."
msgstr "抵銷過不可變更貨幣。"
#: src/accounting/journal_entry/forms/currency.py:99
#: src/accounting/static/js/journal-entry-form.js:729
#: src/accounting/static/js/journal-entry-form.js:773
msgid "Please add some line items."
msgstr "請加上分錄。"
#: src/accounting/journal_entry/forms/currency.py:112
#: src/accounting/static/js/journal-entry-form.js:516
#: src/accounting/static/js/journal-entry-form.js:522
msgid "The totals of the debit and credit amounts do not match."
msgstr "借方貸方合計不符。 "
#: src/accounting/journal_entry/forms/journal_entry.py:48
#: src/accounting/static/js/journal-entry-form.js:270
#: src/accounting/static/js/period-chooser.js:273
#: src/accounting/static/js/journal-entry-form.js:264
#: src/accounting/static/js/period-chooser.js:265
msgid "Please fill in the date."
msgstr "請填上日期。"
#: src/accounting/journal_entry/forms/journal_entry.py:64
#: src/accounting/static/js/journal-entry-form.js:275
#: src/accounting/static/js/journal-entry-form.js:269
msgid "The date cannot be earlier than the original line items."
msgstr "日期不可早於原始分錄。"
@ -243,7 +243,7 @@ msgid "The date cannot be later than the offset items."
msgstr "日期不可晚於抵銷日期。"
#: src/accounting/journal_entry/forms/journal_entry.py:88
#: src/accounting/static/js/journal-entry-form.js:305
#: src/accounting/static/js/journal-entry-form.js:299
msgid "Please add some currencies."
msgstr "請加上貨幣。"
@ -284,12 +284,12 @@ msgid "A receivable line item cannot start from credit."
msgstr "不可由貸方新建應收款。"
#: src/accounting/journal_entry/forms/line_item.py:180
#: src/accounting/static/js/journal-entry-line-item-editor.js:455
#: src/accounting/static/js/journal-entry-line-item-editor.js:436
msgid "Please fill in a positive amount."
msgstr "金額請填正數。"
#: src/accounting/journal_entry/forms/line_item.py:222
#: src/accounting/static/js/journal-entry-line-item-editor.js:461
#: src/accounting/static/js/journal-entry-line-item-editor.js:442
#, python-format
msgid ""
"The amount must not exceed the net balance %(balance)s of the original "
@ -297,7 +297,7 @@ msgid ""
msgstr "金額不可超過原始分錄凈額 %(balance)s 。"
#: src/accounting/journal_entry/forms/line_item.py:243
#: src/accounting/static/js/journal-entry-line-item-editor.js:469
#: src/accounting/static/js/journal-entry-line-item-editor.js:450
#, python-format
msgid "The amount must not be less than the offset total %(total)s."
msgstr "金額不可低於抵銷總額 %(total)s 。"
@ -327,8 +327,8 @@ msgid "This account is not for expense."
msgstr "科目不是支出科目。"
#: src/accounting/option/forms.py:137 src/accounting/option/forms.py:161
#: src/accounting/static/js/option-form.js:535
#: src/accounting/static/js/option-form.js:813
#: src/accounting/static/js/option-form.js:542
#: src/accounting/static/js/option-form.js:820
msgid "Please fill in the description template."
msgstr "請填上摘要範本。"
@ -408,18 +408,18 @@ msgstr "去年"
msgid "All"
msgstr "全部"
#: src/accounting/report/reports/balance_sheet.py:422
#: src/accounting/report/reports/balance_sheet.py:426
#: src/accounting/report/reports/balance_sheet.py:438
#: src/accounting/report/reports/balance_sheet.py:440
#: src/accounting/report/reports/balance_sheet.py:423
#: src/accounting/report/reports/balance_sheet.py:427
#: src/accounting/report/reports/balance_sheet.py:439
#: src/accounting/report/reports/balance_sheet.py:441
#: src/accounting/report/reports/income_expenses.py:189
#: src/accounting/report/reports/income_expenses.py:423
#: src/accounting/report/reports/income_statement.py:299
#: src/accounting/report/reports/income_statement.py:300
#: src/accounting/report/reports/ledger.py:171
#: src/accounting/report/reports/ledger.py:380
#: src/accounting/report/reports/trial_balance.py:228
#: src/accounting/report/reports/trial_balance.py:229
#: src/accounting/templates/accounting/journal-entry/disbursement/detail.html:43
#: src/accounting/templates/accounting/journal-entry/include/form-debit-credit.html:37
#: src/accounting/templates/accounting/journal-entry/include/form-debit-credit.html:38
#: src/accounting/templates/accounting/journal-entry/receipt/detail.html:43
#: src/accounting/templates/accounting/journal-entry/transfer/detail.html:39
#: src/accounting/templates/accounting/journal-entry/transfer/detail.html:55
@ -455,7 +455,7 @@ msgstr "日期"
#: src/accounting/report/reports/income_expenses.py:407
#: src/accounting/report/reports/journal.py:156
#: src/accounting/report/reports/trial_balance.py:224
#: src/accounting/report/reports/trial_balance.py:225
#: src/accounting/templates/accounting/journal-entry/include/journal-entry-line-item-editor-modal.html:57
#: src/accounting/templates/accounting/option/include/recurring-item-editor-modal.html:39
#: src/accounting/templates/accounting/report/include/toolbar-buttons.html:90
@ -527,7 +527,7 @@ msgstr "稅後淨利"
msgid "net income or loss for current period"
msgstr "本期損益"
#: src/accounting/report/reports/income_statement.py:300
#: src/accounting/report/reports/income_statement.py:301
#: src/accounting/templates/accounting/journal-entry/include/journal-entry-line-item-editor-modal.html:65
#: src/accounting/templates/accounting/report/income-statement.html:55
msgid "Amount"
@ -543,7 +543,7 @@ msgstr "貨幣"
#: src/accounting/report/reports/journal.py:157
#: src/accounting/report/reports/ledger.py:367
#: src/accounting/report/reports/trial_balance.py:224
#: src/accounting/report/reports/trial_balance.py:225
#: src/accounting/templates/accounting/journal-entry/transfer/detail.html:33
#: src/accounting/templates/accounting/journal-entry/transfer/include/form-currency.html:30
#: src/accounting/templates/accounting/report/journal.html:57
@ -555,7 +555,7 @@ msgstr "借方"
#: src/accounting/report/reports/journal.py:157
#: src/accounting/report/reports/ledger.py:367
#: src/accounting/report/reports/trial_balance.py:225
#: src/accounting/report/reports/trial_balance.py:226
#: src/accounting/templates/accounting/journal-entry/transfer/detail.html:49
#: src/accounting/templates/accounting/journal-entry/transfer/include/form-currency.html:41
#: src/accounting/templates/accounting/report/journal.html:58
@ -581,17 +581,17 @@ msgstr "貸方"
msgid "Search"
msgstr "搜尋"
#: src/accounting/report/utils/report_chooser.py:89
msgid "Journal"
msgstr "日記簿"
#: src/accounting/report/utils/report_chooser.py:92
msgid "Income and Expenses Log"
msgstr "收支帳"
#: src/accounting/report/utils/report_chooser.py:99
#: src/accounting/report/utils/report_chooser.py:105
msgid "Ledger"
msgstr "分類帳"
#: src/accounting/report/utils/report_chooser.py:114
msgid "Income and Expenses Log"
msgstr "收支帳"
#: src/accounting/report/utils/report_chooser.py:117
msgid "Journal"
msgstr "日記簿"
#: src/accounting/report/utils/report_chooser.py:127
msgid "Trial Balance"
@ -605,110 +605,110 @@ msgstr "損益表"
msgid "Balance Sheet"
msgstr "資產負債表"
#: src/accounting/static/js/account-form.js:198
#: src/accounting/static/js/account-form.js:206
msgid "Please fill in the title."
msgstr "請填上標題。"
#: src/accounting/static/js/description-editor.js:756
#: src/accounting/static/js/description-editor.js:934
#: src/accounting/static/js/description-editor.js:951
#: src/accounting/static/js/description-editor.js:1129
msgid "Please fill in the tag."
msgstr "請填上標籤。"
#: src/accounting/static/js/description-editor.js:766
#: src/accounting/static/js/description-editor.js:954
#: src/accounting/static/js/description-editor.js:961
#: src/accounting/static/js/description-editor.js:1149
msgid "Please fill in the origin."
msgstr "請填上起點。"
#: src/accounting/static/js/description-editor.js:776
#: src/accounting/static/js/description-editor.js:964
#: src/accounting/static/js/description-editor.js:971
#: src/accounting/static/js/description-editor.js:1159
msgid "Please fill in the destination."
msgstr "請填上終點。"
#: src/accounting/static/js/description-editor.js:944
#: src/accounting/static/js/description-editor.js:1139
msgid "Please fill in the route."
msgstr "請填上路線名稱。"
#: src/accounting/static/js/description-editor.js:998
#: src/accounting/static/js/description-editor.js:1192
msgid "January"
msgstr "一月"
#: src/accounting/static/js/description-editor.js:998
#: src/accounting/static/js/description-editor.js:1192
msgid "February"
msgstr "二月"
#: src/accounting/static/js/description-editor.js:998
#: src/accounting/static/js/description-editor.js:1192
msgid "March"
msgstr "三月"
#: src/accounting/static/js/description-editor.js:998
#: src/accounting/static/js/description-editor.js:1192
msgid "April"
msgstr "四月"
#: src/accounting/static/js/description-editor.js:999
#: src/accounting/static/js/description-editor.js:1193
msgid "May"
msgstr "五月"
#: src/accounting/static/js/description-editor.js:999
#: src/accounting/static/js/description-editor.js:1193
msgid "June"
msgstr "六月"
#: src/accounting/static/js/description-editor.js:999
#: src/accounting/static/js/description-editor.js:1193
msgid "July"
msgstr "七月"
#: src/accounting/static/js/description-editor.js:999
#: src/accounting/static/js/description-editor.js:1193
msgid "August"
msgstr "八月"
#: src/accounting/static/js/description-editor.js:1000
#: src/accounting/static/js/description-editor.js:1194
msgid "September"
msgstr "九月"
#: src/accounting/static/js/description-editor.js:1000
#: src/accounting/static/js/description-editor.js:1194
msgid "October"
msgstr "十月"
#: src/accounting/static/js/description-editor.js:1000
#: src/accounting/static/js/description-editor.js:1194
msgid "November"
msgstr "十一月"
#: src/accounting/static/js/description-editor.js:1000
#: src/accounting/static/js/description-editor.js:1194
msgid "December"
msgstr "十二月"
#: src/accounting/static/js/journal-entry-form.js:985
#: src/accounting/static/js/journal-entry-line-item-editor.js:449
#: src/accounting/static/js/journal-entry-form.js:1070
#: src/accounting/static/js/journal-entry-line-item-editor.js:430
msgid "Please fill in the amount."
msgstr "請填上金額。"
#: src/accounting/static/js/journal-entry-form.js:1012
#: src/accounting/static/js/journal-entry-form.js:1092
#: src/accounting/templates/accounting/journal-entry/include/detail-line-items.html:34
#: src/accounting/templates/accounting/journal-entry/include/form-line-item.html:38
#, python-format
msgid "Offset %(item)s"
msgstr "抵銷 %(item)s"
#: src/accounting/static/js/period-chooser.js:278
#: src/accounting/static/js/period-chooser.js:270
msgid "The date is too early."
msgstr "日期太早。"
#: src/accounting/static/js/period-chooser.js:377
#: src/accounting/static/js/period-chooser.js:369
msgid "Please fill in the start date."
msgstr "請填上開始日期。"
#: src/accounting/static/js/period-chooser.js:382
#: src/accounting/static/js/period-chooser.js:374
msgid "The start date is too early."
msgstr "開始日期太早。"
#: src/accounting/static/js/period-chooser.js:387
#: src/accounting/static/js/period-chooser.js:379
msgid "The start date cannot be beyond the end date."
msgstr "開始日期不可晚於結束日期。"
#: src/accounting/static/js/period-chooser.js:405
#: src/accounting/static/js/period-chooser.js:397
msgid "Please fill in the end date."
msgstr "請填上結束日期。"
#: src/accounting/static/js/period-chooser.js:410
#: src/accounting/static/js/period-chooser.js:402
msgid "The end date cannot be beyond the start date."
msgstr "結束日期不可早於開始日期。"
@ -777,7 +777,7 @@ msgstr "你確定要刪掉這個科目嗎?"
#: src/accounting/templates/accounting/account/include/form.html:112
#: src/accounting/templates/accounting/currency/detail.html:79
#: src/accounting/templates/accounting/journal-entry/include/account-selector-modal.html:49
#: src/accounting/templates/accounting/journal-entry/include/description-editor-modal.html:193
#: src/accounting/templates/accounting/journal-entry/include/description-editor-modal.html:194
#: src/accounting/templates/accounting/journal-entry/include/detail.html:84
#: src/accounting/templates/accounting/journal-entry/include/journal-entry-line-item-editor-modal.html:70
#: src/accounting/templates/accounting/option/include/recurring-account-selector-modal.html:48
@ -824,7 +824,7 @@ msgstr "科目管理"
#: src/accounting/templates/accounting/account/list.html:32
#: src/accounting/templates/accounting/currency/list.html:32
#: src/accounting/templates/accounting/journal-entry/include/form-debit-credit.html:44
#: src/accounting/templates/accounting/journal-entry/include/form-debit-credit.html:45
#: src/accounting/templates/accounting/journal-entry/include/form.html:64
#: src/accounting/templates/accounting/option/include/form-recurring-expense-income.html:37
#: src/accounting/templates/accounting/report/include/toolbar-buttons.html:26
@ -839,6 +839,8 @@ msgstr "新增"
#: src/accounting/templates/accounting/journal-entry/include/account-selector-modal.html:46
#: src/accounting/templates/accounting/journal-entry/include/original-line-item-selector-modal.html:51
#: src/accounting/templates/accounting/journal-entry/order.html:82
#: src/accounting/templates/accounting/option/detail.html:67
#: src/accounting/templates/accounting/option/detail.html:83
#: src/accounting/templates/accounting/option/include/recurring-account-selector-modal.html:45
#: src/accounting/templates/accounting/report/balance-sheet.html:110
#: src/accounting/templates/accounting/report/income-expenses.html:113
@ -858,7 +860,7 @@ msgstr "%(base)s下的科目"
#: src/accounting/templates/accounting/account/include/form.html:75
#: src/accounting/templates/accounting/account/order.html:62
#: src/accounting/templates/accounting/currency/include/form.html:57
#: src/accounting/templates/accounting/journal-entry/include/description-editor-modal.html:194
#: src/accounting/templates/accounting/journal-entry/include/description-editor-modal.html:195
#: src/accounting/templates/accounting/journal-entry/include/form.html:80
#: src/accounting/templates/accounting/journal-entry/include/journal-entry-line-item-editor-modal.html:71
#: src/accounting/templates/accounting/journal-entry/order.html:61
@ -950,6 +952,7 @@ msgstr "貨幣"
#: src/accounting/templates/accounting/include/nav.html:58
#: src/accounting/templates/accounting/option/detail.html:24
#: src/accounting/templates/accounting/option/detail.html:41
#: src/accounting/templates/accounting/option/form.html:29
msgid "Settings"
msgstr "設定"
@ -1112,7 +1115,7 @@ msgstr "新增現金收入傳票"
msgid "Add a New Transfer Journal Entry"
msgstr "新增轉帳傳票"
#: src/accounting/templates/accounting/option/detail.html:43
#: src/accounting/templates/accounting/option/detail.html:44
#: src/accounting/templates/accounting/option/form.html:51
msgid "Default Currency"
msgstr "預設貨幣"
@ -1122,13 +1125,13 @@ msgstr "預設貨幣"
msgid "Default Account for the Income and Expenses Log"
msgstr "收支帳預設科目"
#: src/accounting/templates/accounting/option/detail.html:52
#: src/accounting/templates/accounting/option/detail.html:54
#: src/accounting/templates/accounting/option/form.html:66
#: src/accounting/templates/accounting/option/form.html:92
msgid "Recurring Expense"
msgstr "常用支出"
#: src/accounting/templates/accounting/option/detail.html:58
#: src/accounting/templates/accounting/option/detail.html:70
#: src/accounting/templates/accounting/option/form.html:72
#: src/accounting/templates/accounting/option/form.html:96
msgid "Recurring Income"

View File

@ -51,7 +51,7 @@ First written: 2023/1/27
<div id="collapsible-navbar" class="collapse navbar-collapse">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% include "/accounting/include/nav.html" %}
{% include "accounting/include/nav.html" %}
</ul>
<!-- The right side -->

View File

@ -1,16 +1,16 @@
# Chinese (Traditional) translations for the Mia! Accounting
# Demonstration website.
# Test website.
# Copyright (C) 2023 imacat
# This file is distributed under the same license as the Mia! Accounting
# Flask Demonstration project.
# project.
# imacat <imacat@mail.imacat.idv.tw>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: Mia! Accounting Demonstration 0.0.0\n"
"Project-Id-Version: mia-accounting-test-site 1.0.0\n"
"Report-Msgid-Bugs-To: imacat@mail.imacat.idv.tw\n"
"POT-Creation-Date: 2023-03-24 08:32+0800\n"
"PO-Revision-Date: 2023-03-24 08:33+0800\n"
"POT-Creation-Date: 2023-04-06 02:34+0800\n"
"PO-Revision-Date: 2023-04-06 02:34+0800\n"
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
"Language: zh_Hant\n"
"Language-Team: zh_Hant <imacat@mail.imacat.idv.tw>\n"