Compare commits
15 Commits
v1.0.0
...
3a0e978f76
Author | SHA1 | Date | |
---|---|---|---|
3a0e978f76 | |||
8c10d42d7b | |||
04ec51afbe | |||
fe7a8842ce | |||
66daa5c42c | |||
27fb44937d | |||
7026ed3a65 | |||
fdd3e93778 | |||
def7559457 | |||
7905820d68 | |||
7ae332c975 | |||
86c5b91697 | |||
9168840e64 | |||
21b9cfa8b8 | |||
b0b3b3acb1 |
107
README.rst
107
README.rst
@ -17,47 +17,6 @@ accounting reports:
|
|||||||
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
|
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
|
||||||
receivables.
|
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
|
Installation
|
||||||
============
|
============
|
||||||
@ -72,6 +31,18 @@ You may also download the from the `PyPI project page`_ or the
|
|||||||
`release page`_ on the `Git repository`_.
|
`release page`_ on the `Git repository`_.
|
||||||
|
|
||||||
|
|
||||||
|
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 or do not know how to
|
||||||
|
start one, you may start with the test site.
|
||||||
|
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
|
|
||||||
@ -91,7 +62,7 @@ Configuration
|
|||||||
=============
|
=============
|
||||||
|
|
||||||
You need to pass the Flask *app* and an implementation of
|
You need to pass the Flask *app* and an implementation of
|
||||||
``UserUtilityInterface`` to the ``init_app`` function.
|
`UserUtilityInterface`_ to the `init_app`_ function.
|
||||||
``UserUtilityInterface`` contains everything *Mia! Accounting* needs.
|
``UserUtilityInterface`` contains everything *Mia! Accounting* needs.
|
||||||
|
|
||||||
The following is an example configuration for *Mia! Accounting*.
|
The following is an example configuration for *Mia! Accounting*.
|
||||||
@ -109,7 +80,7 @@ The following is an example configuration for *Mia! Accounting*.
|
|||||||
|
|
||||||
import accounting
|
import accounting
|
||||||
|
|
||||||
class UserUtilities(accounting.UserUtilityInterface[User]):
|
class UserUtils(accounting.UserUtilityInterface[User]):
|
||||||
|
|
||||||
def can_view(self) -> bool:
|
def can_view(self) -> bool:
|
||||||
return True
|
return True
|
||||||
@ -161,8 +132,8 @@ database tables that *Mia! Accounting* uses.
|
|||||||
* ``accounting-init-accounts``
|
* ``accounting-init-accounts``
|
||||||
* ``accounting-init-currencies``
|
* ``accounting-init-currencies``
|
||||||
|
|
||||||
You need to run ``accounting-init-base`` first, and then the other
|
After database tables are created, run
|
||||||
two commands.
|
``accounting-init-base`` first, and then the other two commands.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -196,18 +167,6 @@ base template:
|
|||||||
Check your Flask application and see how it works.
|
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
|
Documentation
|
||||||
=============
|
=============
|
||||||
|
|
||||||
@ -242,29 +201,19 @@ Authors
|
|||||||
|
|
||||||
.. _Flask: https://flask.palletsprojects.com
|
.. _Flask: https://flask.palletsprojects.com
|
||||||
.. _double-entry bookkeeping: https://en.wikipedia.org/wiki/Double-entry_bookkeeping
|
.. _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
|
.. _test site: https://github.com/imacat/mia-accounting/tree/main/tests/test_site
|
||||||
.. _source distribution: https://pypi.org/project/mia-accounting/#files
|
.. _source distribution: https://pypi.org/project/mia-accounting/#files
|
||||||
.. _live demonstration: https://accounting.imacat.idv.tw
|
.. _live demonstration: https://accounting.imacat.idv.tw
|
||||||
|
.. _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
|
||||||
|
.. _CDN: https://en.wikipedia.org/wiki/Content_delivery_network
|
||||||
|
.. _Bootstrap: https://getbootstrap.com
|
||||||
|
.. _FontAwesome: https://fontawesome.com
|
||||||
|
.. _Decimal.js: https://mikemcl.github.io/decimal.js
|
||||||
|
.. _Tempus-Dominus: https://getdatepicker.com
|
||||||
|
.. _UserUtilityInterface: https://mia-accounting.readthedocs.io/en/latest/accounting.utils.html#accounting.utils.user.UserUtilityInterface
|
||||||
|
.. _init_app: https://mia-accounting.readthedocs.io/en/latest/accounting.html#accounting.init_app
|
||||||
|
.. _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/
|
||||||
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io
|
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io
|
||||||
|
@ -13,7 +13,7 @@ sys.path.insert(0, os.path.abspath('../../src/'))
|
|||||||
project = 'Mia! Accounting'
|
project = 'Mia! Accounting'
|
||||||
copyright = '2023, imacat'
|
copyright = '2023, imacat'
|
||||||
author = 'imacat'
|
author = 'imacat'
|
||||||
release = '1.0.0'
|
release = '1.0.1'
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
@ -22,7 +22,7 @@ The following is an example configuration for *Mia! Accounting*.
|
|||||||
|
|
||||||
import accounting
|
import accounting
|
||||||
|
|
||||||
class UserUtilities(accounting.UserUtilityInterface[User]):
|
class UserUtils(accounting.UserUtilityInterface[User]):
|
||||||
|
|
||||||
def can_view(self) -> bool:
|
def can_view(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
57
docs/source/history.rst
Normal file
57
docs/source/history.rst
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
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 needed something in 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! Accounting Django`_
|
||||||
|
application. It took me another 1.5 months to make it an independent
|
||||||
|
module, which I later released as an open source project on PyPI.
|
||||||
|
|
||||||
|
The application worked nicely for my household bookkeeping for two
|
||||||
|
years. However, new demands arose over time, especially with tracking
|
||||||
|
payables and receivables. This was critical `during the pandemic`_ as
|
||||||
|
more payments were made online with credit cards.
|
||||||
|
|
||||||
|
The biggest issue I encountered was with
|
||||||
|
`Django's MTV architectural pattern`_. Django takes over the control
|
||||||
|
flow. I had to override several parts of the `class-based views`_ for
|
||||||
|
different but yet simple control flow logic. In the end, it became
|
||||||
|
very difficult to track whether things went wrong because I overrode
|
||||||
|
something or because it just wouldn't work with the basic assumption
|
||||||
|
of the class-based views. By the time I realized it, it was too late
|
||||||
|
for me to drop Django's MTV and rewrite everything from class-based
|
||||||
|
views to function-based views.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
.. _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! Accounting Django: https://github.com/imacat/mia-accounting-django
|
||||||
|
.. _during the pandemic: https://en.wikipedia.org/wiki/COVID-19_pandemic
|
||||||
|
.. _FastAPI: https://fastapi.tiangolo.com
|
||||||
|
.. _Django's MTV architectural pattern: https://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names
|
||||||
|
.. _class-based views: https://docs.djangoproject.com/en/4.2/topics/class-based-views/
|
||||||
|
.. _microframeworks: https://en.wikipedia.org/wiki/Microframework
|
||||||
|
.. _Flask: https://flask.palletsprojects.com
|
@ -13,6 +13,7 @@ Welcome to Mia! Accounting's documentation!
|
|||||||
intro
|
intro
|
||||||
accounting
|
accounting
|
||||||
examples
|
examples
|
||||||
|
history
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,47 +12,6 @@ accounting reports:
|
|||||||
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
|
In addition, *Mia! Accounting* tracks offsets for unpaid payables and
|
||||||
receivables.
|
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
|
Installation
|
||||||
------------
|
------------
|
||||||
@ -67,6 +26,18 @@ You may also download the from the `PyPI project page`_ or the
|
|||||||
`release page`_ on the `Git repository`_.
|
`release page`_ on the `Git repository`_.
|
||||||
|
|
||||||
|
|
||||||
|
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 or do not know how to
|
||||||
|
start one, you may start with the test site.
|
||||||
|
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@ -97,7 +68,7 @@ Database Initialization
|
|||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
After the configuration, you need to run
|
After the configuration, you need to run
|
||||||
:py:meth:`flask_sqlalchemy.SQLAlchemy.create_all` to create the
|
`flask_sqlalchemy.SQLAlchemy.create_all`_ to create the
|
||||||
database tables that *Mia! Accounting* uses.
|
database tables that *Mia! Accounting* uses.
|
||||||
|
|
||||||
*Mia! Accounting* adds three console commands:
|
*Mia! Accounting* adds three console commands:
|
||||||
@ -106,8 +77,8 @@ database tables that *Mia! Accounting* uses.
|
|||||||
* ``accounting-init-accounts``
|
* ``accounting-init-accounts``
|
||||||
* ``accounting-init-currencies``
|
* ``accounting-init-currencies``
|
||||||
|
|
||||||
You need to run ``accounting-init-base`` first, and then the other
|
After database tables are created, run
|
||||||
two commands.
|
``accounting-init-base`` first, and then the other two commands.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -141,18 +112,6 @@ base template:
|
|||||||
Check your Flask application and see how it works.
|
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
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@ -161,28 +120,17 @@ Refer to the `documentation on Read the Docs`_.
|
|||||||
|
|
||||||
.. _Flask: https://flask.palletsprojects.com
|
.. _Flask: https://flask.palletsprojects.com
|
||||||
.. _double-entry bookkeeping: https://en.wikipedia.org/wiki/Double-entry_bookkeeping
|
.. _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
|
.. _test site: https://github.com/imacat/mia-accounting/tree/main/tests/test_site
|
||||||
.. _source distribution: https://pypi.org/project/mia-accounting/#files
|
.. _source distribution: https://pypi.org/project/mia-accounting/#files
|
||||||
.. _live demonstration: https://accounting.imacat.idv.tw
|
.. _live demonstration: https://accounting.imacat.idv.tw
|
||||||
|
.. _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
|
||||||
|
.. _CDN: https://en.wikipedia.org/wiki/Content_delivery_network
|
||||||
|
.. _Bootstrap: https://getbootstrap.com
|
||||||
|
.. _FontAwesome: https://fontawesome.com
|
||||||
|
.. _Decimal.js: https://mikemcl.github.io/decimal.js
|
||||||
|
.. _Tempus-Dominus: https://getdatepicker.com
|
||||||
|
.. _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/
|
||||||
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io
|
.. _documentation on Read the Docs: https://mia-accounting.readthedocs.io
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mia-accounting"
|
name = "mia-accounting"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
description = "A Flask accounting module."
|
description = "A Flask accounting module."
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
@ -22,6 +22,7 @@ from flask import Blueprint, render_template
|
|||||||
from accounting.models import BaseAccount
|
from accounting.models import BaseAccount
|
||||||
from accounting.utils.pagination import Pagination
|
from accounting.utils.pagination import Pagination
|
||||||
from accounting.utils.permission import has_permission, can_view
|
from accounting.utils.permission import has_permission, can_view
|
||||||
|
from .queries import get_base_account_query
|
||||||
|
|
||||||
bp: Blueprint = Blueprint("base-account", __name__)
|
bp: Blueprint = Blueprint("base-account", __name__)
|
||||||
"""The view blueprint for the base account management."""
|
"""The view blueprint for the base account management."""
|
||||||
@ -34,7 +35,6 @@ def list_accounts() -> str:
|
|||||||
|
|
||||||
:return: The account list.
|
:return: The account list.
|
||||||
"""
|
"""
|
||||||
from .queries import get_base_account_query
|
|
||||||
accounts: list[BaseAccount] = get_base_account_query()
|
accounts: list[BaseAccount] = get_base_account_query()
|
||||||
pagination: Pagination = Pagination[BaseAccount](accounts)
|
pagination: Pagination = Pagination[BaseAccount](accounts)
|
||||||
return render_template("accounting/base-account/list.html",
|
return render_template("accounting/base-account/list.html",
|
||||||
|
@ -34,6 +34,7 @@ from accounting.utils.pagination import Pagination
|
|||||||
from accounting.utils.permission import has_permission, can_view, can_edit
|
from accounting.utils.permission import has_permission, can_view, can_edit
|
||||||
from accounting.utils.user import get_current_user_pk
|
from accounting.utils.user import get_current_user_pk
|
||||||
from .forms import CurrencyForm
|
from .forms import CurrencyForm
|
||||||
|
from .queries import get_currency_query
|
||||||
|
|
||||||
bp: Blueprint = Blueprint("currency", __name__)
|
bp: Blueprint = Blueprint("currency", __name__)
|
||||||
"""The view blueprint for the currency management."""
|
"""The view blueprint for the currency management."""
|
||||||
@ -48,7 +49,6 @@ def list_currencies() -> str:
|
|||||||
|
|
||||||
:return: The currency list.
|
:return: The currency list.
|
||||||
"""
|
"""
|
||||||
from .queries import get_currency_query
|
|
||||||
currencies: list[Currency] = get_currency_query()
|
currencies: list[Currency] = get_currency_query()
|
||||||
pagination: Pagination = Pagination[Currency](currencies)
|
pagination: Pagination = Pagination[Currency](currencies)
|
||||||
return render_template("accounting/currency/list.html",
|
return render_template("accounting/currency/list.html",
|
||||||
|
@ -23,6 +23,7 @@ from flask import abort
|
|||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
from werkzeug.routing import BaseConverter
|
from werkzeug.routing import BaseConverter
|
||||||
|
|
||||||
|
from accounting import db
|
||||||
from accounting.models import JournalEntry, JournalEntryLineItem
|
from accounting.models import JournalEntry, JournalEntryLineItem
|
||||||
from accounting.utils.journal_entry_types import JournalEntryType
|
from accounting.utils.journal_entry_types import JournalEntryType
|
||||||
|
|
||||||
@ -37,13 +38,7 @@ class JournalEntryConverter(BaseConverter):
|
|||||||
:param value: The journal entry ID.
|
:param value: The journal entry ID.
|
||||||
:return: The corresponding journal entry.
|
:return: The corresponding journal entry.
|
||||||
"""
|
"""
|
||||||
journal_entry: JournalEntry | None = JournalEntry.query\
|
journal_entry: JournalEntry | None = db.session.get(JournalEntry, value)
|
||||||
.join(JournalEntryLineItem)\
|
|
||||||
.filter(JournalEntry.id == value)\
|
|
||||||
.options(selectinload(JournalEntry.line_items)
|
|
||||||
.selectinload(JournalEntryLineItem.offsets)
|
|
||||||
.selectinload(JournalEntryLineItem.journal_entry))\
|
|
||||||
.first()
|
|
||||||
if journal_entry is None:
|
if journal_entry is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
return journal_entry
|
return journal_entry
|
||||||
|
@ -31,7 +31,7 @@ from accounting import db
|
|||||||
from accounting.forms import ACCOUNT_REQUIRED, AccountExists, IsDebitAccount, \
|
from accounting.forms import ACCOUNT_REQUIRED, AccountExists, IsDebitAccount, \
|
||||||
IsCreditAccount
|
IsCreditAccount
|
||||||
from accounting.locale import lazy_gettext
|
from accounting.locale import lazy_gettext
|
||||||
from accounting.models import Account, JournalEntryLineItem
|
from accounting.models import Account, JournalEntry, JournalEntryLineItem
|
||||||
from accounting.template_filters import format_amount
|
from accounting.template_filters import format_amount
|
||||||
from accounting.utils.cast import be
|
from accounting.utils.cast import be
|
||||||
from accounting.utils.random_id import new_id
|
from accounting.utils.random_id import new_id
|
||||||
@ -127,10 +127,8 @@ class KeepAccountWhenHavingOffset:
|
|||||||
assert isinstance(form, LineItemForm)
|
assert isinstance(form, LineItemForm)
|
||||||
if field.data is None or form.id.data is None:
|
if field.data is None or form.id.data is None:
|
||||||
return
|
return
|
||||||
line_item: JournalEntryLineItem | None = db.session\
|
line_item: JournalEntryLineItem | None \
|
||||||
.query(JournalEntryLineItem)\
|
= db.session.get(JournalEntryLineItem, form.id.data)
|
||||||
.filter(JournalEntryLineItem.id == form.id.data)\
|
|
||||||
.options(selectinload(JournalEntryLineItem.offsets)).first()
|
|
||||||
if line_item is None or len(line_item.offsets) == 0:
|
if line_item is None or len(line_item.offsets) == 0:
|
||||||
return
|
return
|
||||||
if field.data != line_item.account_code:
|
if field.data != line_item.account_code:
|
||||||
@ -344,14 +342,13 @@ class LineItemForm(FlaskForm):
|
|||||||
def get_offsets() -> list[JournalEntryLineItem]:
|
def get_offsets() -> list[JournalEntryLineItem]:
|
||||||
if not self.is_need_offset or self.id.data is None:
|
if not self.is_need_offset or self.id.data is None:
|
||||||
return []
|
return []
|
||||||
return JournalEntryLineItem.query\
|
return JournalEntryLineItem.query.join(JournalEntry)\
|
||||||
.filter(JournalEntryLineItem.original_line_item_id
|
.filter(JournalEntryLineItem.original_line_item_id
|
||||||
== self.id.data)\
|
== self.id.data)\
|
||||||
|
.order_by(JournalEntry.date, JournalEntry.no,
|
||||||
|
JournalEntryLineItem.no)\
|
||||||
.options(selectinload(JournalEntryLineItem.journal_entry),
|
.options(selectinload(JournalEntryLineItem.journal_entry),
|
||||||
selectinload(JournalEntryLineItem.account),
|
selectinload(JournalEntryLineItem.account)).all()
|
||||||
selectinload(JournalEntryLineItem.offsets)
|
|
||||||
.selectinload(
|
|
||||||
JournalEntryLineItem.journal_entry)).all()
|
|
||||||
setattr(self, "__offsets", get_offsets())
|
setattr(self, "__offsets", get_offsets())
|
||||||
return getattr(self, "__offsets")
|
return getattr(self, "__offsets")
|
||||||
|
|
||||||
|
@ -660,12 +660,8 @@ class JournalEntryLineItem(db.Model):
|
|||||||
nullable=True)
|
nullable=True)
|
||||||
"""The ID of the original line item."""
|
"""The ID of the original line item."""
|
||||||
original_line_item = db.relationship("JournalEntryLineItem",
|
original_line_item = db.relationship("JournalEntryLineItem",
|
||||||
back_populates="offsets",
|
|
||||||
remote_side=id, passive_deletes=True)
|
remote_side=id, passive_deletes=True)
|
||||||
"""The original line item."""
|
"""The original line item."""
|
||||||
offsets = db.relationship("JournalEntryLineItem",
|
|
||||||
back_populates="original_line_item")
|
|
||||||
"""The offset items."""
|
|
||||||
currency_code = db.Column(db.String,
|
currency_code = db.Column(db.String,
|
||||||
db.ForeignKey(Currency.code, onupdate="CASCADE"),
|
db.ForeignKey(Currency.code, onupdate="CASCADE"),
|
||||||
nullable=False)
|
nullable=False)
|
||||||
@ -758,6 +754,21 @@ class JournalEntryLineItem(db.Model):
|
|||||||
"""
|
"""
|
||||||
setattr(self, "__net_balance", net_balance)
|
setattr(self, "__net_balance", net_balance)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def offsets(self) -> list[t.Self]:
|
||||||
|
"""Returns the offset items.
|
||||||
|
|
||||||
|
:return: The offset items.
|
||||||
|
"""
|
||||||
|
if not hasattr(self, "__offsets"):
|
||||||
|
cls: t.Type[t.Self] = self.__class__
|
||||||
|
offsets: list[t.Self] = cls.query.join(JournalEntry)\
|
||||||
|
.filter(JournalEntryLineItem.original_line_item_id == self.id)\
|
||||||
|
.order_by(JournalEntry.date, JournalEntry.no,
|
||||||
|
cls.is_debit, cls.no).all()
|
||||||
|
setattr(self, "__offsets", offsets)
|
||||||
|
return getattr(self, "__offsets")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def query_values(self) -> list[str]:
|
def query_values(self) -> list[str]:
|
||||||
"""Returns the values to be queried.
|
"""Returns the values to be queried.
|
||||||
|
@ -77,6 +77,8 @@ class CSVRow(BaseCSVRow):
|
|||||||
"""Constructs a row in the CSV.
|
"""Constructs a row in the CSV.
|
||||||
|
|
||||||
:param journal_entry_date: The journal entry date.
|
:param journal_entry_date: The journal entry date.
|
||||||
|
:param currency: The currency.
|
||||||
|
:param account: The account.
|
||||||
:param description: The description.
|
:param description: The description.
|
||||||
:param debit: The debit amount.
|
:param debit: The debit amount.
|
||||||
:param credit: The credit amount.
|
:param credit: The credit amount.
|
||||||
@ -116,6 +118,7 @@ class PageParams(BasePageParams):
|
|||||||
"""Constructs the HTML page parameters.
|
"""Constructs the HTML page parameters.
|
||||||
|
|
||||||
:param period: The period.
|
:param period: The period.
|
||||||
|
:param pagination: The pagination.
|
||||||
:param line_items: The line items.
|
:param line_items: The line items.
|
||||||
"""
|
"""
|
||||||
self.period: Period = period
|
self.period: Period = period
|
||||||
|
@ -123,7 +123,7 @@ class JournalEntryAccountSelector {
|
|||||||
option.setShown(false);
|
option.setShown(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isAnyMatched) {
|
if (!isAnyMatched && this.#isShowMore) {
|
||||||
this.#optionList.classList.add("d-none");
|
this.#optionList.classList.add("d-none");
|
||||||
this.#queryNoResult.classList.remove("d-none");
|
this.#queryNoResult.classList.remove("d-none");
|
||||||
} else {
|
} else {
|
||||||
|
@ -50,10 +50,10 @@ First written: 2023/3/14
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% if line_item.balance %}
|
{% if line_item.net_balance %}
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<div>{{ A_("Net balance") }}</div>
|
<div>{{ A_("Net balance") }}</div>
|
||||||
<div>{{ line_item.balance|accounting_format_amount }}</div>
|
<div>{{ line_item.net_balance|accounting_format_amount }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
Reference in New Issue
Block a user