monopyly 1.4.6__tar.gz → 1.4.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {monopyly-1.4.6 → monopyly-1.4.8}/PKG-INFO +15 -4
- monopyly-1.4.8/monopyly/CHANGELOG.md +195 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/README.md +14 -3
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/__init__.py +20 -1
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/_version.py +2 -2
- monopyly-1.4.8/monopyly/auth/actions.py +13 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/accounts.py +1 -1
- monopyly-1.4.8/monopyly/banking/actions.py +85 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/routes.py +2 -1
- monopyly-1.4.8/monopyly/cli/apps.py +108 -0
- monopyly-1.4.6/monopyly/cli/run.py → monopyly-1.4.8/monopyly/cli/launch.py +18 -10
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/forms/_forms.py +4 -1
- monopyly-1.4.8/monopyly/core/actions.py +121 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/core/blueprint.py +1 -1
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/core/context_processors.py +10 -0
- monopyly-1.4.8/monopyly/core/errors.py +9 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/core/filters.py +4 -2
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/core/routes.py +22 -9
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/routes.py +9 -1
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/transactions/_transactions.py +1 -1
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/css/style.css +166 -73
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/make-payment.js +4 -2
- monopyly-1.4.8/monopyly/templates/banking/account_summaries.html +35 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/account_summaries_page.html +2 -1
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/account_summary.html +7 -2
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/accounts_page.html +2 -2
- monopyly-1.4.8/monopyly/templates/core/credits.html +32 -0
- monopyly-1.4.8/monopyly/templates/core/errors/400.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/401.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/403.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/404.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/405.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/408.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/418.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/425.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/500.html +8 -0
- monopyly-1.4.8/monopyly/templates/core/errors/error.html +31 -0
- {monopyly-1.4.6/monopyly/templates → monopyly-1.4.8/monopyly/templates/core}/profile.html +3 -1
- monopyly-1.4.8/monopyly/templates/core/story.html +62 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/statement_summary.html +7 -2
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/statements.html +7 -6
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/layout.html +11 -2
- {monopyly-1.4.6 → monopyly-1.4.8}/pyproject.toml +1 -1
- monopyly-1.4.6/monopyly/auth/actions.py +0 -8
- monopyly-1.4.6/monopyly/banking/actions.py +0 -44
- monopyly-1.4.6/monopyly/cli/apps.py +0 -85
- monopyly-1.4.6/monopyly/core/actions.py +0 -34
- monopyly-1.4.6/monopyly/templates/banking/account_summaries.html +0 -21
- monopyly-1.4.6/monopyly/templates/credits.html +0 -20
- monopyly-1.4.6/monopyly/templates/story.html +0 -47
- {monopyly-1.4.6 → monopyly-1.4.8}/.gitignore +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/COPYING +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/LICENSE +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/README.md +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/auth/blueprint.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/auth/routes.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/auth/tools.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/banks.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/blueprint.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/filters.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/forms.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/banking/transactions.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/forms/__init__.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/forms/fields.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/forms/utils.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/forms/validators.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/transactions.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/common/utils.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/config/__init__.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/config/default_settings.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/config/settings.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/core/internal_transactions.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/accounts.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/actions.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/blueprint.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/cards.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/forms.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/statements.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/credit/transactions/__init__.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/database/__init__.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/database/models.py +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/database/preloads.sql +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/database/schema.sql +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/database/views.sql +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/browserconfig.xml +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-114.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-120.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-144.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-150.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-152.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-16.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-160.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-180.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-192.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-310.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-32.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-57.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-60.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-64.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-70.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-72.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-76.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon-96.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon.ico +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/favicon/favicon.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/bank-account-details.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/bank-account-summaries.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/bank-accounts.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/credit-account-details.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/credit-transactions.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/homepage-user.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/homepage.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/about/statement-details.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/cards/chase-card.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/cards/discover-card.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/cards/new-card.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/cards/template-card.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/arrow-down.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/arrow-left.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/arrow-up.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/checkmark.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/delete-orange-thick.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/delete-orange.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/delete-thick.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/delete.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/edit.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/link.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/minus-thick.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/minus.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/plus-thick.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/plus.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/refresh.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/save.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/sort-asc.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/sort-desc.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/statement-pair.svg +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/statement.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/statement.svg +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/icons/x-thick.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/img/statement.png +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/jquery-3.7.0.min.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/add-subtransaction.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/add-transfer.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/autocomplete-transaction.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/bind-tag-actions.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/create-balance-chart.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/define-filter.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/display-new-account-type-inputs.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/display-new-bank-inputs.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/display-new-credit-account-inputs.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/expand-bank-account.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/expand-bank.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/expand-transaction.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/flip-card.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/hide-homepage-block.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/infer-card.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/infer-statement.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/ajax.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/autocomplete-input.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/expand-box-row.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/expand-transaction.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/manage-acquisition-form.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/manage-overlays.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/manage-subforms.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/update-database-widget.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/modules/update-display-ajax.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/show-linked-transaction.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-account-statement-parameters.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-bank-name.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-card-status.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-statement-parameters.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-statements-display.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/static/js/update-transactions-display.js +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/auth/login.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/auth/register.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/account_form/account_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/account_form/account_form_page_new.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/account_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/bank_info_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/transaction_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/transaction_form_page_new.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/transaction_form_page_update.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transaction_form/transfer_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transactions_table/condensed_row_content.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transactions_table/expanded_row_content.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transactions_table/transaction_field_titles.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/banking/transactions_table/transactions.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/form_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transaction_form/subform.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transaction_form/subtransaction_subform.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/linked_bank_transaction.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/linked_credit_transaction.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/linked_transaction_overlay.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/subtransactions.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/transaction_condensed.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/transaction_expanded.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/common/transactions_table/transactions.html +0 -0
- {monopyly-1.4.6/monopyly/templates → monopyly-1.4.8/monopyly/templates/core}/index.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/account_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_form/card_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_form/card_form_page_new.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_form/transfer_statement_inquiry.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_graphic/card_back.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_graphic/card_front.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/card_submission_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/cards.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/cards_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/statement_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/statements_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/tag_tree/subtag_tree.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/tag_tree/tag_tree.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/tags_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transaction_form/transaction_form.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transaction_form/transaction_form_page_new.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transaction_form/transaction_form_page_update.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transaction_submission_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transactions_page.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transactions_table/condensed_row_content.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transactions_table/expanded_row_content.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transactions_table/transaction_field_titles.html +0 -0
- {monopyly-1.4.6 → monopyly-1.4.8}/monopyly/templates/credit/transactions_table/transactions.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: monopyly
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.8
|
|
4
4
|
Summary: A homemade personal finance manager.
|
|
5
5
|
Project-URL: Download, https://pypi.org/project/monopyly
|
|
6
6
|
Project-URL: Homepage, http://monopyly.com
|
|
@@ -58,17 +58,28 @@ To install the app, simply run
|
|
|
58
58
|
$ pip install monopyly
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
The package requires a recent version of Python (3.
|
|
61
|
+
The package requires a recent version of Python (3.10+).
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
## Getting started
|
|
65
65
|
|
|
66
|
-
Once the package is properly installed, run the app from the command line (the default options should be sensible, but you may customize the host and port if necessary):
|
|
66
|
+
Once the package is properly installed, run the app in local mode from the command line (the default options should be sensible, but you may customize the host and port if necessary):
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
$ monopyly
|
|
69
|
+
$ monopyly local --browser [--host HOST] [--port PORT]
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
Local mode indicates that the app is just going to be run using a locally hosted server, accessible to just your machine.
|
|
73
|
+
Other available modes are `development` and `production`, for those looking to either develop the application or host the application on a server.
|
|
74
|
+
|
|
75
|
+
<div class="warning">
|
|
76
|
+
<h5>Use your brain when choosing a mode!</h5>
|
|
77
|
+
<small>
|
|
78
|
+
If you intend to be the only user of the app, served just from your PC, local mode is fine; you will be served well-enough by the built-in Python server, and you do not need to configure secret keys for the application.
|
|
79
|
+
If you plan to host the application, however, <b>DO NOT</b> use local mode (or development mode) and run the app in production mode instead.
|
|
80
|
+
</small>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
72
83
|
By using the `--browser` option in development mode, this will open to an empty homepage with a welcome message.
|
|
73
84
|
|
|
74
85
|
<img class="screenshot" src="https://raw.githubusercontent.com/mitchnegus/monopyly/main/monopyly/static/img/about/homepage.png" alt="user homepage" width="800px">
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
<a class="latest-release" href="#bottom">Latest</a>
|
|
4
|
+
|
|
5
|
+
## 1.0.0
|
|
6
|
+
|
|
7
|
+
- Initial release
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 1.0.1
|
|
11
|
+
|
|
12
|
+
- Added dependencies to `setup.py` for self-contained installation
|
|
13
|
+
- Added this changelog
|
|
14
|
+
- Added a generally comprehensive [README](README.md)
|
|
15
|
+
- Fixed a few minor bugs with the display interface
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### 1.0.2
|
|
19
|
+
|
|
20
|
+
- Added image support to PyPI description
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### 1.0.3
|
|
24
|
+
|
|
25
|
+
- Implemented (rudimentary) interface for adding and removing transaction tags
|
|
26
|
+
- Added button to add more statements to a transaction (from submission complete page)
|
|
27
|
+
- Fixed bug in updating a transaction's statement date to a new statement
|
|
28
|
+
- Fixed bug where tags where not saved on new transactions
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### 1.0.4
|
|
32
|
+
|
|
33
|
+
- Improved tagging interface with a 'Manage Tags' page
|
|
34
|
+
- Introduced statement level statistics
|
|
35
|
+
- Renamed database files to end with `.sqlite` extension
|
|
36
|
+
- Moved menus on 'Statement Details' and 'Account Details' pages into the sidebar to prevent overlap on collapsed screens
|
|
37
|
+
- Renamed `show_*` route functions to `load_*` to clarify that they are for loading the associated pages (as opposed to just displaying content)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### 1.0.5
|
|
41
|
+
|
|
42
|
+
- Transactions may be split into an arbitrary number of subtransactions, each with a separate subtotal and note
|
|
43
|
+
- Backend properly handles duplicate/ancestor tags; all tags are saved in the database, but only the lowest-level child tag must be entered
|
|
44
|
+
- Removed statement level statistics display (not yet mature)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## 1.1.0
|
|
48
|
+
|
|
49
|
+
- Added banking interface
|
|
50
|
+
- Added interface for displaying linked transactions (including between bank transactions and credit transactions)
|
|
51
|
+
- Grayed out pending transactions
|
|
52
|
+
- Fixed bug where transaction tags appeared in front of header bar
|
|
53
|
+
- Improved modularity of autocomplete JavaScript
|
|
54
|
+
- Improved modularity of transaction table templates (for banking and credit transactions)
|
|
55
|
+
- Minor cosmetic enhancements
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## 1.2.0
|
|
59
|
+
|
|
60
|
+
- Database backend converted to use SQLAlchemy (2.0)
|
|
61
|
+
- Complete test suite created
|
|
62
|
+
- Banking interface updated to use subtransactions
|
|
63
|
+
- Added the ability to transfer statements when a new credit card is added to an account
|
|
64
|
+
- Fixed error on handling subtransactions in credit forms
|
|
65
|
+
- Fixed error updating transaction display from widget bar
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
### 1.2.1
|
|
69
|
+
|
|
70
|
+
- Improve development functionality; better/safer cleaning with a separate database and preloaded data
|
|
71
|
+
- Add custom form fields for consistent app-wide form implementations
|
|
72
|
+
- Overhaul documentation formatting with _isort_ and _Black_
|
|
73
|
+
- Fixed bug where multiple subtransactions failed to update properly
|
|
74
|
+
- Fixed error where validation was not raised for blank inputs to a `CustomChoiceSelectField`
|
|
75
|
+
- Fixed errors in field validation for nested subforms with unset values
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### 1.2.2
|
|
79
|
+
|
|
80
|
+
- Use `pyproject.toml` via Hatch
|
|
81
|
+
- Added version information to app footer
|
|
82
|
+
- Fixed bug where bank name failed to show on 'Credit Account Details' page
|
|
83
|
+
- Improved JavaScript management for acquisition forms
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### 1.2.3
|
|
87
|
+
|
|
88
|
+
- Add currency symbol to the amount field(s)
|
|
89
|
+
- Allow subform fields to be removed from forms
|
|
90
|
+
- Change 'Vendor' field name to 'Merchant' for better generalizability
|
|
91
|
+
- Remove wildcard imports from the package source code
|
|
92
|
+
- Update form styles to be more browser compatible
|
|
93
|
+
- Impose boolean constraint on boolean/integer database fields
|
|
94
|
+
- Use metaclasses for database handler to avoid stacking classmethod and property (deprecated in Python 3.11)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## 1.3.0
|
|
98
|
+
|
|
99
|
+
- Add a merchant field and tags to bank transactions
|
|
100
|
+
- Add an enhanced autocompletion for assigning transaction tags
|
|
101
|
+
- Add a settings page for allowing bank names to be changed (and eventually allowing passwords to be updated, among other functionality)
|
|
102
|
+
- Leverage SQLAlchemy 2.0 `DeclarativeBase` class and `declared_attr` decorators
|
|
103
|
+
- Simplify `Model` base to avoid explicitly defining column attributes
|
|
104
|
+
- Update the database backup script to work as part of the package
|
|
105
|
+
- Swap the README instructions for the 'About' page (and move the story to a separate page)
|
|
106
|
+
- Improve utilization of `pyroject.toml`
|
|
107
|
+
- Factor out the database handlers (now found in the Authanor package dependency)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
### 1.3.1
|
|
111
|
+
|
|
112
|
+
- Upgrade jQuery version to 3.7.0
|
|
113
|
+
- Use recommended `importlib` method for pytest
|
|
114
|
+
- Automatically use the transferring bank as the merchant in bank transfers
|
|
115
|
+
- For transfers between accounts at the same bank, do not show 'Withdrawal' or 'Deposit' headers; just mark as 'Transfer'
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## 1.4.0
|
|
119
|
+
|
|
120
|
+
- Add charts showing historical balances to bank account details page
|
|
121
|
+
- Show projected balances for bank transactions occurring in the future
|
|
122
|
+
- Allow users to remove the welcome block from the homepage
|
|
123
|
+
- Make use of `data-*` HTML tag attributes rather than ID parsing
|
|
124
|
+
- Prevent JavaScript errors on statement pages when buttons are non-existent
|
|
125
|
+
- Clean up transaction table overflow for transaction notes
|
|
126
|
+
- Generalize transaction forms using Jinja `super` blocks
|
|
127
|
+
- Convert JavaScript files to be named using kebab case
|
|
128
|
+
- Use Fuisce in place of Authanor for db/testing interfaces
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
### 1.4.1
|
|
132
|
+
|
|
133
|
+
- Use local time for determining projected balances
|
|
134
|
+
- Show future credit statement payments as "scheduled" (and improve logic for displaying paid notices)
|
|
135
|
+
- Fix incorrect return type in `CreditStatementHandler.infer_statement` method
|
|
136
|
+
- Distinguish between inline code and "fenced" code using a Markdown library extension
|
|
137
|
+
- Use more `data-*` attributes for processing transaction IDs
|
|
138
|
+
- Fix bug where linked transactions did not use jQuery reference
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
### 1.4.2
|
|
142
|
+
|
|
143
|
+
- Configure production mode via Gunicorn
|
|
144
|
+
- Standardize CLI usage messages
|
|
145
|
+
- Make browser usage optional in CLI run script
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
### 1.4.3
|
|
149
|
+
|
|
150
|
+
- Reconfigure makefile for smoother installation
|
|
151
|
+
- Fix bug where transaction toggling failed on filter updates
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### 1.4.4
|
|
155
|
+
|
|
156
|
+
- Update date-to-timestamp conversion to be timezone invariant
|
|
157
|
+
- Fix database initialization for development mode
|
|
158
|
+
- Fix bug where credit card number was not displayed in card summary
|
|
159
|
+
- Use Beautiful Soup to make tests more robust
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### 1.4.5
|
|
163
|
+
|
|
164
|
+
- Fix bug where a transaction for a new statement was marked as invalid on entry
|
|
165
|
+
- Sort bank account displays by account type and last four digits
|
|
166
|
+
- Use SQLAlchemy 'selectin' loading mode for commonly loaded relationships
|
|
167
|
+
- Give tags a property for identifying their depth in the user's "tag tree"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
### 1.4.6
|
|
171
|
+
|
|
172
|
+
- Bump dependencies (including patching security vulnerability in gunicorn)
|
|
173
|
+
- Add a function for acquiring a statement and all of its transactions
|
|
174
|
+
- Add a convenience method to the statement handler for getting the preceding statement
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
### 1.4.7
|
|
178
|
+
|
|
179
|
+
- Create custom error pages for error responses (400, 404, 500, etc.)
|
|
180
|
+
- Render the changelog and show it via the app
|
|
181
|
+
- Display bank account type subtotals on the bank account summaries page
|
|
182
|
+
- Set the current date as the default for transaction form inputs
|
|
183
|
+
- Use the `strict` argument to the built-in `zip` function to strengthen tests
|
|
184
|
+
- Refresh the table of transactions after making a payment on a credit card statement
|
|
185
|
+
- Use SVG to handle long values in account/statement summary boxes; fixes bugs in page rendering (long value overflow) and hover actions not happening because of conflicting overlap with the sidebar
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
### 1.4.8
|
|
189
|
+
|
|
190
|
+
- Set username collection to be case insensitive
|
|
191
|
+
- Use Flask/Gunicorn APIs (rather than subprocess CLI calls) to launch the app
|
|
192
|
+
- Fix bug in the ordering of balances in the bank account balance charts for transactions on duplicate dates
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
<a name="bottom" id="bottom"></a>
|
|
@@ -22,17 +22,28 @@ To install the app, simply run
|
|
|
22
22
|
$ pip install monopyly
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
The package requires a recent version of Python (3.
|
|
25
|
+
The package requires a recent version of Python (3.10+).
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
## Getting started
|
|
29
29
|
|
|
30
|
-
Once the package is properly installed, run the app from the command line (the default options should be sensible, but you may customize the host and port if necessary):
|
|
30
|
+
Once the package is properly installed, run the app in local mode from the command line (the default options should be sensible, but you may customize the host and port if necessary):
|
|
31
31
|
|
|
32
32
|
```
|
|
33
|
-
$ monopyly
|
|
33
|
+
$ monopyly local --browser [--host HOST] [--port PORT]
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
Local mode indicates that the app is just going to be run using a locally hosted server, accessible to just your machine.
|
|
37
|
+
Other available modes are `development` and `production`, for those looking to either develop the application or host the application on a server.
|
|
38
|
+
|
|
39
|
+
<div class="warning">
|
|
40
|
+
<h5>Use your brain when choosing a mode!</h5>
|
|
41
|
+
<small>
|
|
42
|
+
If you intend to be the only user of the app, served just from your PC, local mode is fine; you will be served well-enough by the built-in Python server, and you do not need to configure secret keys for the application.
|
|
43
|
+
If you plan to host the application, however, <b>DO NOT</b> use local mode (or development mode) and run the app in production mode instead.
|
|
44
|
+
</small>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
36
47
|
By using the `--browser` option in development mode, this will open to an empty homepage with a welcome message.
|
|
37
48
|
|
|
38
49
|
<img class="screenshot" src="monopyly/static/img/about/homepage.png" alt="user homepage" width="800px">
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Run
|
|
2
|
+
Run the Monopyly app.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from flask import Flask
|
|
6
6
|
|
|
7
7
|
from monopyly.config import DevelopmentConfig, ProductionConfig
|
|
8
|
+
from monopyly.core.errors import render_error_template
|
|
8
9
|
from monopyly.database import SQLAlchemy, register_db_cli_commands
|
|
9
10
|
|
|
10
11
|
|
|
@@ -32,6 +33,7 @@ def create_app(test_config=None):
|
|
|
32
33
|
def init_app(app):
|
|
33
34
|
"""Initialize the app."""
|
|
34
35
|
register_blueprints(app)
|
|
36
|
+
register_errorhandlers(app)
|
|
35
37
|
register_db_cli_commands(app)
|
|
36
38
|
|
|
37
39
|
|
|
@@ -57,3 +59,20 @@ def register_blueprints(app):
|
|
|
57
59
|
app.register_blueprint(auth_bp)
|
|
58
60
|
app.register_blueprint(banking_bp)
|
|
59
61
|
app.register_blueprint(credit_bp)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def register_errorhandlers(app):
|
|
65
|
+
"""Register error handlers with the app."""
|
|
66
|
+
handled_error_codes = [
|
|
67
|
+
400,
|
|
68
|
+
401,
|
|
69
|
+
403,
|
|
70
|
+
404,
|
|
71
|
+
405,
|
|
72
|
+
408,
|
|
73
|
+
418,
|
|
74
|
+
# 425 -- not yet supported
|
|
75
|
+
500,
|
|
76
|
+
]
|
|
77
|
+
for code in handled_error_codes:
|
|
78
|
+
app.register_error_handler(code, render_error_template)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Module describing logical authorization actions (to be used in routes)."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_username_and_password(form):
|
|
5
|
+
"""
|
|
6
|
+
Get username and password from a form.
|
|
7
|
+
|
|
8
|
+
Get the username and password from the given form. Username should
|
|
9
|
+
be case insensitive.
|
|
10
|
+
"""
|
|
11
|
+
username = form["username"].lower()
|
|
12
|
+
password = form["password"]
|
|
13
|
+
return username, password
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Module describing logical banking actions (to be used in routes)."""
|
|
2
|
+
|
|
3
|
+
from collections import UserList, namedtuple
|
|
4
|
+
|
|
5
|
+
from ..common.utils import convert_date_to_midnight_timestamp
|
|
6
|
+
from .accounts import BankAccountHandler, BankAccountTypeHandler
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_bank_account_type_grouping(bank):
|
|
10
|
+
"""Get a summary of accounts for the given bank, grouped by type."""
|
|
11
|
+
# Get a grouping (by account type) of accounts at the given bank
|
|
12
|
+
type_accounts = {}
|
|
13
|
+
for account_type in BankAccountTypeHandler.get_types_for_bank(bank.id):
|
|
14
|
+
# Get only accounts for the logged in user and the given bank
|
|
15
|
+
type_accounts[account_type] = BankAccountHandler.get_accounts(
|
|
16
|
+
bank_ids=(bank.id,),
|
|
17
|
+
account_type_ids=(account_type.id,),
|
|
18
|
+
)
|
|
19
|
+
return type_accounts
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_balance_chart_data(transactions):
|
|
23
|
+
"""
|
|
24
|
+
Build a dataset to be passed to a `chartist.js` chart constructor.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
transactions : list
|
|
29
|
+
A list of transactions to be used for generating the chart data.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
chart_data : list
|
|
34
|
+
A list containing (x, y) pairs, each consisting of the Unix
|
|
35
|
+
timestamp (in milliseconds) and the bank account balance.
|
|
36
|
+
"""
|
|
37
|
+
return list(_BalanceChartData(transactions))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class _BalanceChartData(UserList):
|
|
41
|
+
"""
|
|
42
|
+
A list of balances to be passed to a `chartist.js` chart constructor.
|
|
43
|
+
|
|
44
|
+
A special list-like object containing transaction data formatted for
|
|
45
|
+
use in a balance chart created by the `chartist.js` library. This
|
|
46
|
+
converts each transaction into an (x, y) pair consisting of a Unix
|
|
47
|
+
timestamp (in milleseconds) and a corresponding bank account
|
|
48
|
+
balance. For transactions occurring on the same day (the finest
|
|
49
|
+
granularity recorded by the Monopyly app), a slight offset is
|
|
50
|
+
added to each timestamp to guarantee a smooth representation in the
|
|
51
|
+
rendered chart.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
transactions : list
|
|
56
|
+
A list of transactions to be used for generating the chart data.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
_DAILY_MILLISECONDS = 86_400_000
|
|
60
|
+
offset = 1
|
|
61
|
+
point = namedtuple("DataPoint", ["timestamp", "balance"])
|
|
62
|
+
|
|
63
|
+
def __init__(self, transactions):
|
|
64
|
+
super().__init__()
|
|
65
|
+
transaction_groups = self._group_transactions_by_date(transactions)
|
|
66
|
+
self._prepare_chart_data(transaction_groups)
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _group_transactions_by_date(transactions):
|
|
70
|
+
date_groups = {}
|
|
71
|
+
for transaction in transactions:
|
|
72
|
+
group = date_groups.setdefault(transaction.transaction_date, [])
|
|
73
|
+
group.append(transaction)
|
|
74
|
+
return date_groups
|
|
75
|
+
|
|
76
|
+
def _prepare_chart_data(self, transaction_groups):
|
|
77
|
+
# Assign chart data to the list as tuples, adding offsets for duplicated dates
|
|
78
|
+
for transaction_date, transaction_group in transaction_groups.items():
|
|
79
|
+
base_timestamp = convert_date_to_midnight_timestamp(
|
|
80
|
+
transaction_date, milliseconds=True
|
|
81
|
+
)
|
|
82
|
+
offset = self._DAILY_MILLISECONDS / len(transaction_group)
|
|
83
|
+
for i, transaction in enumerate(transaction_group):
|
|
84
|
+
adjusted_timestamp = base_timestamp + (i * offset)
|
|
85
|
+
self.data.append((adjusted_timestamp, transaction.balance))
|
|
@@ -79,7 +79,8 @@ def load_account_details(account_id):
|
|
|
79
79
|
"banking/account_page.html",
|
|
80
80
|
account=account,
|
|
81
81
|
account_transactions=transactions[:100],
|
|
82
|
-
|
|
82
|
+
# Reverse the chart transactions to be chronologically ascending
|
|
83
|
+
chart_data=get_balance_chart_data(reversed(transactions)),
|
|
83
84
|
)
|
|
84
85
|
|
|
85
86
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Application objects for running the app via the CLI."""
|
|
2
|
+
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
from gunicorn.app.base import BaseApplication
|
|
7
|
+
|
|
8
|
+
from .. import create_app
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LocalApplication:
|
|
12
|
+
"""
|
|
13
|
+
An object for running the application locally.
|
|
14
|
+
|
|
15
|
+
This application object will run the Flask application using the
|
|
16
|
+
built-in Python server on localhost, just like the Flask development
|
|
17
|
+
mode. However, it will launch from port 5001 to avoid conflicting
|
|
18
|
+
with other Python servers that may attempt to run on the default
|
|
19
|
+
port 5000.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
mode_name = "local"
|
|
23
|
+
default_port = "5001"
|
|
24
|
+
_debug = None
|
|
25
|
+
|
|
26
|
+
def __init__(self, host=None, port=None, **options):
|
|
27
|
+
"""Initialize the application in development mode."""
|
|
28
|
+
self._host = host
|
|
29
|
+
self._port = port or self.default_port
|
|
30
|
+
if options:
|
|
31
|
+
raise NotImplementedError(
|
|
32
|
+
f"Options besides `host` and `port` are not handled in {self.mode_name} mode."
|
|
33
|
+
)
|
|
34
|
+
self.application = create_app()
|
|
35
|
+
|
|
36
|
+
def run(self):
|
|
37
|
+
"""Run the Monopyly application in development mode."""
|
|
38
|
+
self.application.run(
|
|
39
|
+
host=self._host,
|
|
40
|
+
port=self._port,
|
|
41
|
+
debug=self._debug,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DevelopmentApplication(LocalApplication):
|
|
46
|
+
"""
|
|
47
|
+
An object for running the application in development mode.
|
|
48
|
+
|
|
49
|
+
This application object will run the Flask application using the
|
|
50
|
+
built-in Python server on localhost, just like the Flask development
|
|
51
|
+
mode.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
mode_name = "development"
|
|
55
|
+
default_port = None # traditionally 5000
|
|
56
|
+
_debug = True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ProductionApplication(BaseApplication):
|
|
60
|
+
"""
|
|
61
|
+
An object for running the application in production mode (via Gunicorn).
|
|
62
|
+
|
|
63
|
+
This application object will run the Flask application using a
|
|
64
|
+
Gunicorn server instead of the built-in Python server.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
default_port = None # traditionally 8000
|
|
68
|
+
_default_worker_count = (multiprocessing.cpu_count() * 2) + 1
|
|
69
|
+
|
|
70
|
+
def __init__(self, host=None, port=None, **options):
|
|
71
|
+
"""Initialize the application in production mode."""
|
|
72
|
+
if port and not host:
|
|
73
|
+
raise ValueError("A host must be specified when the port is given.")
|
|
74
|
+
self._host = host
|
|
75
|
+
self._port = port or self.default_port
|
|
76
|
+
self.options = options
|
|
77
|
+
self.options["bind"] = self._determine_binding(options.get("bind"))
|
|
78
|
+
self.options.setdefault("workers", self._default_worker_count)
|
|
79
|
+
self.application = create_app()
|
|
80
|
+
super().__init__()
|
|
81
|
+
|
|
82
|
+
def _determine_binding(self, bind_option):
|
|
83
|
+
# Parse any socket binding options
|
|
84
|
+
if self._host and bind_option:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
"The `host` may not be specified directly if the `bind` option is used."
|
|
87
|
+
)
|
|
88
|
+
if self._host:
|
|
89
|
+
bind_values = [self._host]
|
|
90
|
+
if self._port:
|
|
91
|
+
bind_values.append(self._port)
|
|
92
|
+
bind_option = ":".join(bind_values)
|
|
93
|
+
return bind_option
|
|
94
|
+
|
|
95
|
+
def load_config(self):
|
|
96
|
+
config = {
|
|
97
|
+
key: value
|
|
98
|
+
for key, value in self.options.items()
|
|
99
|
+
if key in self.cfg.settings and value is not None
|
|
100
|
+
}
|
|
101
|
+
for key, value in config.items():
|
|
102
|
+
self.cfg.set(key.lower(), value)
|
|
103
|
+
|
|
104
|
+
def load(self):
|
|
105
|
+
return self.application
|
|
106
|
+
|
|
107
|
+
def run(self, *args, **kwargs):
|
|
108
|
+
return super().run(*args, **kwargs)
|
|
@@ -16,26 +16,34 @@ from rich.console import Console
|
|
|
16
16
|
|
|
17
17
|
from .apps import DevelopmentApplication, LocalApplication, ProductionApplication
|
|
18
18
|
|
|
19
|
-
# Set the Flask environment variable
|
|
20
|
-
os.environ["FLASK_APP"] = "monopyly"
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
args = parse_arguments()
|
|
25
|
-
app_launcher = Launcher(args.mode, host=args.host, port=args.port)
|
|
20
|
+
def main(mode, host=None, port=None, backup=False, browser=False):
|
|
21
|
+
app_launcher = Launcher(mode, host=host, port=port)
|
|
26
22
|
# Initialize the database and run the app
|
|
27
23
|
app_launcher.initialize_database()
|
|
28
|
-
if
|
|
24
|
+
if backup:
|
|
29
25
|
app_launcher.backup_database()
|
|
30
26
|
app_launcher.launch()
|
|
31
|
-
if
|
|
27
|
+
if mode in ("development", "local"):
|
|
32
28
|
# Enable browser viewing in development mode
|
|
33
|
-
if
|
|
29
|
+
if browser:
|
|
34
30
|
app_launcher.open_browser(delay=1)
|
|
35
31
|
# Wait for the exit command to stop
|
|
36
32
|
app_launcher.wait_for_exit()
|
|
37
33
|
|
|
38
34
|
|
|
35
|
+
def main_cli():
|
|
36
|
+
"""Run the app as a command line program."""
|
|
37
|
+
args = parse_arguments()
|
|
38
|
+
main(
|
|
39
|
+
args.mode,
|
|
40
|
+
host=args.host,
|
|
41
|
+
port=args.port,
|
|
42
|
+
backup=args.backup,
|
|
43
|
+
browser=args.browser,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
39
47
|
def parse_arguments():
|
|
40
48
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
41
49
|
parser.add_argument("--host", help="the host address where the app will be run")
|
|
@@ -121,4 +129,4 @@ class Launcher:
|
|
|
121
129
|
|
|
122
130
|
|
|
123
131
|
if __name__ == "__main__":
|
|
124
|
-
|
|
132
|
+
main_cli()
|
|
@@ -3,6 +3,7 @@ General form constructions.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
+
from datetime import date
|
|
6
7
|
|
|
7
8
|
from flask_wtf import FlaskForm
|
|
8
9
|
from wtforms.fields import FieldList, FormField, SelectField, StringField, SubmitField
|
|
@@ -165,7 +166,9 @@ class TransactionForm(EntryForm):
|
|
|
165
166
|
return data
|
|
166
167
|
|
|
167
168
|
# Fields pertaining to the transaction
|
|
168
|
-
transaction_date = DateField(
|
|
169
|
+
transaction_date = DateField(
|
|
170
|
+
"Transaction Date", validators=[DataRequired()], default=date.today
|
|
171
|
+
)
|
|
169
172
|
# Subtransactions should be defined as a `FieldList` in a subclass
|
|
170
173
|
subtransactions = None
|
|
171
174
|
submit = SubmitField("Save Transaction")
|