monopyly 1.5.0__tar.gz → 1.5.1__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.5.0 → monopyly-1.5.1}/PKG-INFO +8 -8
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/CHANGELOG.md +11 -0
- monopyly-1.5.1/monopyly/_version.py +16 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/auth/actions.py +12 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/auth/routes.py +30 -21
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/auth/tools.py +1 -2
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/forms/utils.py +1 -2
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/routes.py +0 -6
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/forms.py +1 -1
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/routes.py +19 -1
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/activity/parser.py +14 -6
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/css/style.css +191 -11
- monopyly-1.5.1/monopyly/templates/auth/change_password.html +21 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/auth/login.html +3 -1
- monopyly-1.5.1/monopyly/templates/auth/register.html +25 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/profile.html +2 -2
- monopyly-1.5.1/monopyly/templates/credit/transaction_submission_page.html +89 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/layout.html +2 -2
- {monopyly-1.5.0 → monopyly-1.5.1}/pyproject.toml +6 -6
- monopyly-1.5.0/monopyly/_version.py +0 -4
- monopyly-1.5.0/monopyly/templates/auth/register.html +0 -15
- monopyly-1.5.0/monopyly/templates/credit/transaction_submission_page.html +0 -96
- {monopyly-1.5.0 → monopyly-1.5.1}/.gitignore +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/COPYING +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/LICENSE +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/README.md +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/README.md +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/auth/blueprint.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/accounts.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/actions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/banks.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/blueprint.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/filters.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/forms.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/routes.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/banking/transactions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/cli/apps.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/cli/launch.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/forms/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/forms/_forms.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/forms/fields.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/forms/validators.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/transactions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/common/utils.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/config/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/config/default_settings.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/config/settings.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/actions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/blueprint.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/context_processors.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/errors.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/filters.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/core/internal_transactions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/accounts.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/actions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/blueprint.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/cards.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/statements.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/_transactions.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/activity/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/activity/data.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/credit/transactions/activity/reconciliation.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/database/__init__.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/database/models.py +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/database/preloads.sql +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/database/schema.sql +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/database/views.sql +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/browserconfig.xml +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-114.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-120.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-144.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-150.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-152.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-16.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-160.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-180.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-192.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-310.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-32.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-57.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-60.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-64.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-70.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-72.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-76.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon-96.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon.ico +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/favicon/favicon.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/bank-account-details.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/bank-account-summaries.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/bank-accounts.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/credit-account-details.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/credit-transactions.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/homepage-user.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/homepage.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/about/statement-details.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/cards/chase-card.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/cards/discover-card.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/cards/new-card.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/cards/template-card.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/arrow-down.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/arrow-left.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/arrow-up.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/checkmark.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/delete-orange-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/delete-orange.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/delete-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/delete.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/edit.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/link.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/minus-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/minus.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/plus-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/plus.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/refresh.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/save.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/sort-asc.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/sort-desc.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/statement-pair.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/statement-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/statement.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/icons/x-thick.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/img/statement.png +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/jquery-3.7.0.min.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/add-subtransaction.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/add-transfer.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/autocomplete-transaction.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/bind-tag-actions.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/create-balance-chart.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/create-category-chart.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/define-filter.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/display-new-account-type-inputs.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/display-new-bank-inputs.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/display-new-credit-account-inputs.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/expand-bank-account.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/expand-bank.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/expand-transaction.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/flip-card.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/hide-homepage-block.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/highlight-discrepant-transactions.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/infer-card.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/infer-statement.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/make-payment.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/ajax.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/autocomplete-input.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/expand-box-row.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/expand-transaction.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/form-suggestions.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/manage-acquisition-form.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/manage-overlays.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/manage-subforms.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/update-database-widget.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/modules/update-display-ajax.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/show-credit-activity-loader.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/show-linked-transaction.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/toggle-navigation.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-account-statement-parameters.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-bank-name.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-card-status.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-statement-parameters.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-statements-display.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/update-transactions-display.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/use-suggested-amount.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/static/js/use-suggested-merchant.js +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_form/account_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_form/account_form_page_new.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_summaries.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_summaries_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/account_summary.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/accounts_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/bank_info_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/transaction_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/transaction_form_page_new.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/transaction_form_page_update.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transaction_form/transfer_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transactions_table/condensed_row_content.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transactions_table/expanded_row_content.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transactions_table/transaction_field_titles.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/banking/transactions_table/transactions.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/form_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transaction_form/subform.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transaction_form/subtransaction_subform.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/linked_bank_transaction.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/linked_credit_transaction.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/linked_transaction_overlay.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/subtransactions.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/transaction_condensed.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/transaction_expanded.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/common/transactions_table/transactions.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/credits.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/400.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/401.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/403.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/404.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/405.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/408.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/418.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/425.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/500.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/errors/error.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/index.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/core/story.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/account_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_form/card_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_form/card_form_page_new.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_form/transfer_statement_inquiry.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_graphic/card_back.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_graphic/card_front.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/card_submission_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/cards.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/cards_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_reconciliation/discrepant_records.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_reconciliation/statement_reconciliation_inquiry.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_reconciliation/statement_reconciliation_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_reconciliation/summary.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_reconciliation/unrecorded_activities.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statement_summary.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statements.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/statements_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/tag_tree/subtag_tree.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/tag_tree/tag_tree.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/tags_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transaction_form/transaction_form.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transaction_form/transaction_form_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transaction_form/transaction_form_page_new.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transaction_form/transaction_form_page_update.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transactions_page.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transactions_table/condensed_row_content.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transactions_table/expanded_row_content.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transactions_table/transaction_field_titles.html +0 -0
- {monopyly-1.5.0 → monopyly-1.5.1}/monopyly/templates/credit/transactions_table/transactions.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: monopyly
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.1
|
|
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
|
|
@@ -23,16 +23,16 @@ Classifier: Topic :: Office/Business :: Financial
|
|
|
23
23
|
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
24
24
|
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
|
|
25
25
|
Requires-Python: <3.11,>=3.10
|
|
26
|
-
Requires-Dist: authanor==1.1.
|
|
26
|
+
Requires-Dist: authanor==1.1.1
|
|
27
27
|
Requires-Dist: flask-wtf==1.2.1
|
|
28
28
|
Requires-Dist: flask==3.0.3
|
|
29
29
|
Requires-Dist: fuisce==1.0.2
|
|
30
|
-
Requires-Dist: gunicorn==
|
|
31
|
-
Requires-Dist: markdown==3.
|
|
32
|
-
Requires-Dist: nltk==3.
|
|
30
|
+
Requires-Dist: gunicorn==23.0.0
|
|
31
|
+
Requires-Dist: markdown==3.7
|
|
32
|
+
Requires-Dist: nltk==3.9.1
|
|
33
33
|
Requires-Dist: python-dateutil==2.9.0
|
|
34
|
-
Requires-Dist: rich==13.
|
|
35
|
-
Requires-Dist: sqlalchemy==2.0.
|
|
34
|
+
Requires-Dist: rich==13.8.1
|
|
35
|
+
Requires-Dist: sqlalchemy==2.0.35
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
38
|
<div id="header">
|
|
@@ -199,4 +199,15 @@
|
|
|
199
199
|
- Create a tool for reconciling credit card transactions with information collected from external resources (e.g., CSVs downloaded from a user's online credit card account)
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
### 1.5.1
|
|
203
|
+
|
|
204
|
+
- Bump dependencies (including patching security vulnerability in NLTK)
|
|
205
|
+
- Style credit transaction submissions as receipts
|
|
206
|
+
- Style flash messages according to content
|
|
207
|
+
- Return to statement details page after deleting a transaction (rather than returning to the general transactions page)
|
|
208
|
+
- Allow users to change their password
|
|
209
|
+
- Warn users before form submission if the configuration currently disallows registration
|
|
210
|
+
- Increase the flexibility of the credit activity parser
|
|
211
|
+
|
|
212
|
+
|
|
202
213
|
<a name="bottom" id="bottom"></a>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# file generated by setuptools_scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
TYPE_CHECKING = False
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from typing import Tuple, Union
|
|
6
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
+
else:
|
|
8
|
+
VERSION_TUPLE = object
|
|
9
|
+
|
|
10
|
+
version: str
|
|
11
|
+
__version__: str
|
|
12
|
+
__version_tuple__: VERSION_TUPLE
|
|
13
|
+
version_tuple: VERSION_TUPLE
|
|
14
|
+
|
|
15
|
+
__version__ = version = '1.5.1'
|
|
16
|
+
__version_tuple__ = version_tuple = (1, 5, 1)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"""Module describing logical authorization actions (to be used in routes)."""
|
|
2
2
|
|
|
3
|
+
from flask import current_app
|
|
4
|
+
from sqlalchemy import select
|
|
5
|
+
|
|
6
|
+
from ..database.models import User
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
def get_username_and_password(form):
|
|
5
10
|
"""
|
|
@@ -11,3 +16,10 @@ def get_username_and_password(form):
|
|
|
11
16
|
username = form["username"].lower()
|
|
12
17
|
password = form["password"]
|
|
13
18
|
return username, password
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def identify_user(username):
|
|
22
|
+
"""Identify the user in the database based on the username."""
|
|
23
|
+
user_query = select(User).where(User.username == username)
|
|
24
|
+
user = current_app.db.session.scalar(user_query)
|
|
25
|
+
return user
|
|
@@ -5,6 +5,7 @@ Routes for site authentication.
|
|
|
5
5
|
from flask import (
|
|
6
6
|
current_app,
|
|
7
7
|
flash,
|
|
8
|
+
g,
|
|
8
9
|
redirect,
|
|
9
10
|
render_template,
|
|
10
11
|
request,
|
|
@@ -16,7 +17,7 @@ from sqlalchemy import select
|
|
|
16
17
|
from werkzeug.security import check_password_hash, generate_password_hash
|
|
17
18
|
|
|
18
19
|
from ..database.models import User
|
|
19
|
-
from .actions import get_username_and_password
|
|
20
|
+
from .actions import get_username_and_password, identify_user
|
|
20
21
|
from .blueprint import bp
|
|
21
22
|
|
|
22
23
|
|
|
@@ -33,24 +34,17 @@ def register():
|
|
|
33
34
|
error = "Username is required."
|
|
34
35
|
elif not password:
|
|
35
36
|
error = "Password is required."
|
|
37
|
+
elif user := identify_user(username):
|
|
38
|
+
error = f"User {username} is already registered."
|
|
36
39
|
else:
|
|
37
|
-
#
|
|
38
|
-
user_query = select(User).where(User.username == username)
|
|
39
|
-
user = current_app.db.session.scalar(user_query)
|
|
40
|
-
if user:
|
|
41
|
-
error = f"User {username} is already registered."
|
|
42
|
-
else:
|
|
43
|
-
error = None
|
|
44
|
-
# Add the username and hashed password to the database
|
|
45
|
-
if not error:
|
|
40
|
+
# Create a new user
|
|
46
41
|
new_user = User(
|
|
47
42
|
username=username,
|
|
48
43
|
password=generate_password_hash(password),
|
|
49
44
|
)
|
|
50
45
|
current_app.db.session.add(new_user)
|
|
51
46
|
return redirect(url_for("auth.login"))
|
|
52
|
-
|
|
53
|
-
flash(error)
|
|
47
|
+
flash(error)
|
|
54
48
|
# Display the registration page
|
|
55
49
|
return render_template("auth/register.html")
|
|
56
50
|
|
|
@@ -60,23 +54,17 @@ def login():
|
|
|
60
54
|
if request.method == "POST":
|
|
61
55
|
# Get username and passwords from the form
|
|
62
56
|
username, password = get_username_and_password(request.form)
|
|
63
|
-
# Get user information from the database
|
|
64
|
-
user_query = select(User).where(User.username == username)
|
|
65
|
-
user = current_app.db.session.scalar(user_query)
|
|
66
57
|
# Check for errors in the accessed information
|
|
67
|
-
if user is None:
|
|
58
|
+
if (user := identify_user(username)) is None:
|
|
68
59
|
error = "That user is not yet registered."
|
|
69
60
|
elif not check_password_hash(user.password, password):
|
|
70
61
|
error = "Incorrect username and password combination."
|
|
71
62
|
else:
|
|
72
|
-
|
|
73
|
-
# Set the user ID securely for a new session
|
|
74
|
-
if not error:
|
|
63
|
+
# Set the user ID securely for a new session
|
|
75
64
|
session.clear()
|
|
76
65
|
session["user_id"] = user.id
|
|
77
66
|
return redirect(url_for("core.index"))
|
|
78
|
-
|
|
79
|
-
flash(error)
|
|
67
|
+
flash(error)
|
|
80
68
|
# Display the login page
|
|
81
69
|
return render_template("auth/login.html")
|
|
82
70
|
|
|
@@ -86,3 +74,24 @@ def logout():
|
|
|
86
74
|
# End the session and clear the user ID
|
|
87
75
|
session.clear()
|
|
88
76
|
return redirect(url_for("core.index"))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@bp.route("/change_password", methods=("GET", "POST"))
|
|
80
|
+
@db_transaction
|
|
81
|
+
def change_password():
|
|
82
|
+
if request.method == "POST":
|
|
83
|
+
current_password = request.form["current-password"]
|
|
84
|
+
new_password = request.form["new-password"]
|
|
85
|
+
if check_password_hash(g.user.password, current_password):
|
|
86
|
+
# Merge the user item (dissociated from the current session) for updating
|
|
87
|
+
g.user = current_app.db.session.merge(g.user)
|
|
88
|
+
g.user.password = generate_password_hash(new_password)
|
|
89
|
+
flash("Password updated successfully.", category="success")
|
|
90
|
+
return redirect(url_for("core.load_profile"))
|
|
91
|
+
else:
|
|
92
|
+
flash(
|
|
93
|
+
"The provided value for the current password does not match the "
|
|
94
|
+
"value of the current password set on this account.",
|
|
95
|
+
category="error",
|
|
96
|
+
)
|
|
97
|
+
return render_template("auth/change_password.html")
|
|
@@ -14,8 +14,7 @@ from .blueprint import bp
|
|
|
14
14
|
@bp.before_app_request
|
|
15
15
|
def load_logged_in_user():
|
|
16
16
|
# Match the user's information with the session
|
|
17
|
-
user_id
|
|
18
|
-
if user_id is None:
|
|
17
|
+
if (user_id := session.get("user_id")) is None:
|
|
19
18
|
g.user = None
|
|
20
19
|
else:
|
|
21
20
|
query = select(User).where(User.id == user_id)
|
|
@@ -145,7 +145,6 @@ def execute_on_form_validation(func):
|
|
|
145
145
|
else:
|
|
146
146
|
# Show an error to the user and print the errors for the admin
|
|
147
147
|
flash(form_err_msg)
|
|
148
|
-
|
|
149
|
-
raise ValidationError("The form did not validate properly.")
|
|
148
|
+
raise ValidationError(f"The form did not validate properly: {form.errors}")
|
|
150
149
|
|
|
151
150
|
return wrapper
|
|
@@ -5,7 +5,6 @@ Routes for core functionality.
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from flask import g, render_template, render_template_string, session
|
|
8
|
-
from werkzeug.exceptions import abort
|
|
9
8
|
|
|
10
9
|
from ..auth.tools import login_required
|
|
11
10
|
from ..banking.accounts import BankAccountHandler
|
|
@@ -85,8 +84,3 @@ def load_profile():
|
|
|
85
84
|
banks = BankHandler.get_banks()
|
|
86
85
|
# Return banks as a list to allow multiple reuse
|
|
87
86
|
return render_template("core/profile.html", banks=list(banks))
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
@bp.route("/change_password")
|
|
91
|
-
def change_password():
|
|
92
|
-
abort(418)
|
|
@@ -301,7 +301,7 @@ class CreditTransactionForm(TransactionForm):
|
|
|
301
301
|
|
|
302
302
|
def _extract_merchant_suggestion(self, data):
|
|
303
303
|
# Use the merchant transaction data as a suggestion source
|
|
304
|
-
if merchant :=
|
|
304
|
+
if merchant := data.get("merchant"):
|
|
305
305
|
merchant_tokens = ActivityMatchmaker.tokenize(merchant)
|
|
306
306
|
# Suggest a known merchant with the closest distance to the activity merchant
|
|
307
307
|
score_records = []
|
|
@@ -201,6 +201,8 @@ def load_statement_details(statement_id):
|
|
|
201
201
|
categories = categorize(transactions)
|
|
202
202
|
# Get bank accounts for potential payments
|
|
203
203
|
bank_accounts = BankAccountHandler.get_accounts()
|
|
204
|
+
# Save a pointer to this statement to allow easy returns
|
|
205
|
+
session["statement_focus"] = statement_id
|
|
204
206
|
return render_template(
|
|
205
207
|
"credit/statement_page.html",
|
|
206
208
|
statement=statement,
|
|
@@ -210,6 +212,18 @@ def load_statement_details(statement_id):
|
|
|
210
212
|
)
|
|
211
213
|
|
|
212
214
|
|
|
215
|
+
@bp.before_app_request
|
|
216
|
+
def clear_statement_focus():
|
|
217
|
+
exempt_endpoints = (
|
|
218
|
+
"credit.expand_transaction",
|
|
219
|
+
"credit.delete_transaction",
|
|
220
|
+
"static",
|
|
221
|
+
None,
|
|
222
|
+
)
|
|
223
|
+
if request.endpoint not in exempt_endpoints:
|
|
224
|
+
session.pop("statement_focus", None)
|
|
225
|
+
|
|
226
|
+
|
|
213
227
|
@bp.route("/_update_statement_due_date/<int:statement_id>", methods=("POST",))
|
|
214
228
|
@login_required
|
|
215
229
|
@db_transaction
|
|
@@ -307,7 +321,7 @@ def clear_reconciliation_info():
|
|
|
307
321
|
"credit.update_transaction",
|
|
308
322
|
"credit.infer_statement",
|
|
309
323
|
"credit.suggest_transaction_autocomplete",
|
|
310
|
-
"credit.
|
|
324
|
+
"credit.delete_transaction",
|
|
311
325
|
"static",
|
|
312
326
|
None,
|
|
313
327
|
)
|
|
@@ -483,6 +497,10 @@ def add_subtransaction_fields():
|
|
|
483
497
|
@db_transaction
|
|
484
498
|
def delete_transaction(transaction_id):
|
|
485
499
|
CreditTransactionHandler.delete_entry(transaction_id)
|
|
500
|
+
if statement_id := session.pop("statement_focus", None):
|
|
501
|
+
return redirect(
|
|
502
|
+
url_for("credit.load_statement_details", statement_id=statement_id)
|
|
503
|
+
)
|
|
486
504
|
return redirect(url_for("credit.load_transactions"))
|
|
487
505
|
|
|
488
506
|
|
|
@@ -4,12 +4,14 @@ import csv
|
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from flask import current_app
|
|
7
|
+
from flask import abort, current_app
|
|
8
8
|
from werkzeug.utils import secure_filename
|
|
9
9
|
|
|
10
10
|
from ....common.utils import parse_date
|
|
11
11
|
from .data import ActivityLoadingError, TransactionActivities, TransactionActivityLoader
|
|
12
12
|
|
|
13
|
+
SUPPORTED_BANKS = ("Bank of America", "Chase", "Discover")
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
def parse_transaction_activity_file(transaction_file):
|
|
15
17
|
"""
|
|
@@ -91,7 +93,7 @@ class _TransactionDateColumnIdentifier(_ColumnIdentifier):
|
|
|
91
93
|
elif "date" in standardized_title.split():
|
|
92
94
|
if "trans." in standardized_title:
|
|
93
95
|
return True
|
|
94
|
-
elif standardized_title == "date":
|
|
96
|
+
elif standardized_title == "date" or standardized_title == "posted date":
|
|
95
97
|
return None
|
|
96
98
|
return False
|
|
97
99
|
|
|
@@ -104,8 +106,8 @@ class _TransactionTotalColumnIdentifier(_ColumnIdentifier):
|
|
|
104
106
|
|
|
105
107
|
class _TransactionDescriptionColumnIdentifier(_ColumnIdentifier):
|
|
106
108
|
def check(self, standardized_title):
|
|
107
|
-
"""Check if the title indicates this column contains a description."""
|
|
108
|
-
return standardized_title in ("description", "desc.")
|
|
109
|
+
"""Check if the title indicates this column contains a description (payee)."""
|
|
110
|
+
return standardized_title in ("description", "desc.", "payee")
|
|
109
111
|
|
|
110
112
|
|
|
111
113
|
class _TransactionCategoryColumnIdentifier(_ColumnIdentifier):
|
|
@@ -184,9 +186,15 @@ class _TransactionActivityParser:
|
|
|
184
186
|
}
|
|
185
187
|
for column_type in self.column_types:
|
|
186
188
|
if raw_column_indices[column_type] is None:
|
|
187
|
-
|
|
188
|
-
f"The '{column_type}' column could not be identified in the data."
|
|
189
|
+
current_app.logger.debug(
|
|
190
|
+
f"The '{column_type}' column could not be identified in the data. "
|
|
191
|
+
)
|
|
192
|
+
msg = (
|
|
193
|
+
"The data was unable to be parsed, most likely because it did not "
|
|
194
|
+
"match a recognized format. Supported data formats include those "
|
|
195
|
+
f"from the following banks: {', '.join(SUPPORTED_BANKS)}."
|
|
189
196
|
)
|
|
197
|
+
abort(400, msg)
|
|
190
198
|
return raw_column_indices
|
|
191
199
|
|
|
192
200
|
def _determine_expenditure_sign(self, raw_data):
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
--masthead-height: 50px;
|
|
12
12
|
--masthead-color: #2b2b2b;
|
|
13
13
|
--border-gray: #dddddd;
|
|
14
|
+
--button-background-base: #fbfbfb;
|
|
15
|
+
--button-background: linear-gradient(#fbfbfb, #efefef);
|
|
16
|
+
--button-block-background-base: #eeeeee;
|
|
17
|
+
--button-block-background: linear-gradient(#eeeeee, #e6e6e6);
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
html {
|
|
@@ -386,6 +390,35 @@ aside.sidebar {
|
|
|
386
390
|
}
|
|
387
391
|
|
|
388
392
|
|
|
393
|
+
/*
|
|
394
|
+
* Provide styles for flashed messages
|
|
395
|
+
*/
|
|
396
|
+
.flash.success,
|
|
397
|
+
.flash.warning,
|
|
398
|
+
.flash.error {
|
|
399
|
+
margin: 20px 0;
|
|
400
|
+
padding: 10px 20px;
|
|
401
|
+
border-radius: 10px;
|
|
402
|
+
box-shadow: 1px 1px 4px #ddd;
|
|
403
|
+
font-size: 0.9em;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.flash.success {
|
|
407
|
+
border: 1px solid #6fda6f;
|
|
408
|
+
background: linear-gradient(45deg, #e6efe1, #f5fef1);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.flash.warning {
|
|
412
|
+
border: 1px solid #dac96f;
|
|
413
|
+
background: linear-gradient(45deg, #efede1, #fefbf1);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.flash.error {
|
|
417
|
+
border: 1px solid #da6f6f;
|
|
418
|
+
background: linear-gradient(45deg, #f3e8e8, #fef1f1);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
389
422
|
/*
|
|
390
423
|
* Provide styles for error pages
|
|
391
424
|
*/
|
|
@@ -459,8 +492,8 @@ aside.sidebar {
|
|
|
459
492
|
border: 1px solid var(--border-gray);
|
|
460
493
|
border-radius: 10px;
|
|
461
494
|
box-shadow: 1px 1px 3px #bbbbbb;
|
|
462
|
-
background-color:
|
|
463
|
-
background-image:
|
|
495
|
+
background-color: var(--button-block-background-base);
|
|
496
|
+
background-image: var(--button-block-background);
|
|
464
497
|
color: inherit;
|
|
465
498
|
}
|
|
466
499
|
|
|
@@ -546,15 +579,16 @@ aside.sidebar {
|
|
|
546
579
|
left: 0;
|
|
547
580
|
height: 100%;
|
|
548
581
|
width: 100%;
|
|
582
|
+
display: flex;
|
|
583
|
+
flex-direction: column;
|
|
584
|
+
justify-content: center;
|
|
585
|
+
align-items: center;
|
|
549
586
|
background-color: rgba(0, 0, 0, 0.75);
|
|
550
587
|
z-index: 50; /* in front of content, but behind the header */
|
|
551
588
|
}
|
|
552
589
|
|
|
553
590
|
.modal {
|
|
554
|
-
|
|
555
|
-
top: 0%;
|
|
556
|
-
left: 50%;
|
|
557
|
-
transform: translate(-50%, 15%);
|
|
591
|
+
min-width: 200px;
|
|
558
592
|
}
|
|
559
593
|
|
|
560
594
|
.modal-box {
|
|
@@ -638,8 +672,8 @@ form input.button {
|
|
|
638
672
|
align-items: center;
|
|
639
673
|
margin-top: 20px;
|
|
640
674
|
padding: 10px;
|
|
641
|
-
background-color:
|
|
642
|
-
background-image:
|
|
675
|
+
background-color: var(--button-background-base);
|
|
676
|
+
background-image: var(--button-background);
|
|
643
677
|
color: #333333;
|
|
644
678
|
font-weight:bold;
|
|
645
679
|
text-align: center;
|
|
@@ -2564,6 +2598,21 @@ form .autocomplete-box .item.active {
|
|
|
2564
2598
|
}
|
|
2565
2599
|
|
|
2566
2600
|
|
|
2601
|
+
/*
|
|
2602
|
+
* Customization for the 'Registration' page
|
|
2603
|
+
*/
|
|
2604
|
+
.no-registration-notice {
|
|
2605
|
+
width: 60%;
|
|
2606
|
+
margin: 25px auto;
|
|
2607
|
+
padding: 10px;
|
|
2608
|
+
border: 1px solid var(--moneytree-leaves);
|
|
2609
|
+
border-radius: 10px;
|
|
2610
|
+
box-shadow: 0 0 10px var(--moneytree-leaves);
|
|
2611
|
+
background-color: #f5f5f5;
|
|
2612
|
+
text-align: center;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
|
|
2567
2616
|
/*
|
|
2568
2617
|
* Customization for the 'Profile' page
|
|
2569
2618
|
*/
|
|
@@ -3532,7 +3581,6 @@ form#pay #make-payment[type="submit"] #prompt {
|
|
|
3532
3581
|
#statement-reconciliation.modal {
|
|
3533
3582
|
width: 50%;
|
|
3534
3583
|
min-width: 300px;
|
|
3535
|
-
transform: translate(-50%, 100%);
|
|
3536
3584
|
}
|
|
3537
3585
|
|
|
3538
3586
|
#statement-reconciliation.modal .modal-box {
|
|
@@ -3604,13 +3652,145 @@ form#credit-transaction .merchant-field {
|
|
|
3604
3652
|
/*
|
|
3605
3653
|
* Customization for the transaction submission page
|
|
3606
3654
|
*/
|
|
3607
|
-
#
|
|
3608
|
-
|
|
3655
|
+
#submission {
|
|
3656
|
+
display: flex;
|
|
3657
|
+
flex-direction: column;
|
|
3658
|
+
align-items: center;
|
|
3659
|
+
width: 50%;
|
|
3609
3660
|
margin: auto;
|
|
3610
3661
|
}
|
|
3662
|
+
@media screen and (max-width: 600px) {
|
|
3663
|
+
/* Mobile layout */
|
|
3664
|
+
#submission {
|
|
3665
|
+
width: 90%;
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
#submission-title {
|
|
3670
|
+
text-align: center;
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
#receipt {
|
|
3674
|
+
width: 60%;
|
|
3675
|
+
min-width: 250px;
|
|
3676
|
+
max-width: 300px;
|
|
3677
|
+
margin: 40px auto;
|
|
3678
|
+
padding: 10px 20px 30px;
|
|
3679
|
+
box-shadow: 2px 2px 6px #bbbbbb;
|
|
3680
|
+
background-color: #fafafa;
|
|
3681
|
+
font-family: monospace;
|
|
3682
|
+
}
|
|
3683
|
+
@media screen and (max-width: 600px) {
|
|
3684
|
+
/* Mobile layout */
|
|
3685
|
+
#receipt {
|
|
3686
|
+
margin: 10px auto 30px;
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3611
3689
|
|
|
3612
3690
|
#receipt-title {
|
|
3691
|
+
margin-bottom: 20px;
|
|
3613
3692
|
text-align: center;
|
|
3693
|
+
color: var(--silver-dollar);
|
|
3694
|
+
font-size: 10pt;
|
|
3695
|
+
font-weight: 400;
|
|
3696
|
+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
3697
|
+
letter-spacing: 2px;
|
|
3698
|
+
text-transform: uppercase;
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
#receipt .receipt-item {
|
|
3702
|
+
display: flex;
|
|
3703
|
+
margin: 15px 0;
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
#receipt .receipt-item .receipt-key {
|
|
3707
|
+
font-weight: bold;
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3710
|
+
#receipt #receipt-header {
|
|
3711
|
+
margin-bottom: 40px;
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
#receipt #receipt-header #receipt-merchant {
|
|
3715
|
+
font-size: 14pt;
|
|
3716
|
+
justify-content: center;
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
#receipt #receipt-header #receipt-date {
|
|
3720
|
+
font-size: 10pt;
|
|
3721
|
+
font-weight: normal;
|
|
3722
|
+
justify-content: center;
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
#receipt .receipt-subtransaction {
|
|
3726
|
+
display: flex;
|
|
3727
|
+
gap: 10px 20px;
|
|
3728
|
+
margin: 10px 0;
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3731
|
+
#receipt .receipt-subtransaction .note,
|
|
3732
|
+
#receipt #receipt-total .total {
|
|
3733
|
+
flex: 4;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
#receipt .receipt-subtransaction .amount,
|
|
3737
|
+
#receipt #receipt-total .amount {
|
|
3738
|
+
flex: 1;
|
|
3739
|
+
text-align: right;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3742
|
+
#receipt #receipt-card {
|
|
3743
|
+
margin-top: 40px;
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
#receipt #receipt-card .receipt-item {
|
|
3747
|
+
flex-direction: column;
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
#receipt #receipt-card .receipt-item .receipt-key {
|
|
3751
|
+
margin-bottom: 5px;
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
#receipt #receipt-card .receipt-item .receipt-value {
|
|
3755
|
+
margin-left: 0;
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
#submission-actions {
|
|
3759
|
+
display: flex;
|
|
3760
|
+
flex-direction: column;
|
|
3761
|
+
gap: 3px;
|
|
3762
|
+
align-items: center;
|
|
3763
|
+
width: 100%;
|
|
3764
|
+
max-width: 400px;
|
|
3765
|
+
}
|
|
3766
|
+
@media screen and (max-width: 600px) {
|
|
3767
|
+
/* Mobile layout */
|
|
3768
|
+
#submission-actions {
|
|
3769
|
+
gap: 5px;
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
#submission-actions .submission.button {
|
|
3774
|
+
width: 100%;
|
|
3775
|
+
padding: 3px 10px;
|
|
3776
|
+
border: 1px solid var(--border-gray);
|
|
3777
|
+
border-radius: 5px;
|
|
3778
|
+
background-color: var(--button-background-base);
|
|
3779
|
+
background-image: var(--button-background);;
|
|
3780
|
+
font-size: 12pt;
|
|
3781
|
+
text-decoration: none;
|
|
3782
|
+
box-sizing: border-box;
|
|
3783
|
+
}
|
|
3784
|
+
@media screen and (max-width: 600px) {
|
|
3785
|
+
/* Mobile layout */
|
|
3786
|
+
#submission-actions .submission.button {
|
|
3787
|
+
padding: 10px;
|
|
3788
|
+
font-size: 10pt;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3792
|
+
#submission-actions .submission.button:hover {
|
|
3793
|
+
filter: brightness(0.98);
|
|
3614
3794
|
}
|
|
3615
3795
|
|
|
3616
3796
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{% extends 'layout.html' %}
|
|
2
|
+
|
|
3
|
+
{% block header %}
|
|
4
|
+
<h1>{% block title %}Change Password{% endblock %}</h1>
|
|
5
|
+
{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block content %}
|
|
8
|
+
|
|
9
|
+
<form id="change-password" method="post">
|
|
10
|
+
<p class="instructions">
|
|
11
|
+
Use this form to change the password for user: <b>{{ g.user.username }}</b>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<label for="password">Current Password</label>
|
|
15
|
+
<input type="password" name="current-password" id="current-password" required>
|
|
16
|
+
<label for="new-password">New Password</label>
|
|
17
|
+
<input type="password" name="new-password" id="new-password" required>
|
|
18
|
+
<input class="button" type="submit" value="Update" />
|
|
19
|
+
</form>
|
|
20
|
+
|
|
21
|
+
{% endblock %}
|
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
{% endblock %}
|
|
6
6
|
|
|
7
7
|
{% block content %}
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
<form id="log-in" method="post">
|
|
9
10
|
<label for="username">Username</label>
|
|
10
11
|
<input name="username" id="username" required>
|
|
11
12
|
<label for="password">Password</label>
|
|
12
13
|
<input type="password" name="password" id="password" required>
|
|
13
14
|
<input class="button" type="submit" value="Log In" />
|
|
14
15
|
</form>
|
|
16
|
+
|
|
15
17
|
{% endblock %}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{% extends 'layout.html' %}
|
|
2
|
+
|
|
3
|
+
{% block header %}
|
|
4
|
+
<h1>{% block title %}Register{% endblock %}</h1>
|
|
5
|
+
{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block content %}
|
|
8
|
+
|
|
9
|
+
{% if not config['REGISTRATION'] %}
|
|
10
|
+
<div class="no-registration-notice">
|
|
11
|
+
<b>Notice:</b> The app is not currently accepting new registrations.
|
|
12
|
+
</div>
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
{% with input_status = 'required' if config['REGISTRATION'] else 'disabled' %}
|
|
16
|
+
<form id="register" method="post">
|
|
17
|
+
<label for="username">Username</label>
|
|
18
|
+
<input name="username" id="username" {{ input_status }}>
|
|
19
|
+
<label for="password">Password</label>
|
|
20
|
+
<input type="password" name="password" id="password" {{ input_status }}>
|
|
21
|
+
<input class="button" type="submit" value="Register" />
|
|
22
|
+
</form>
|
|
23
|
+
{% endwith %}
|
|
24
|
+
|
|
25
|
+
{% endblock %}
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
<div class=user-settings">
|
|
26
26
|
|
|
27
27
|
<div class="password">
|
|
28
|
-
<a style="color: gray;" href="{{ url_for('
|
|
29
|
-
Change password
|
|
28
|
+
<a style="color: gray;" href="{{ url_for('auth.change_password') }}">
|
|
29
|
+
Change password
|
|
30
30
|
</a>
|
|
31
31
|
</div>
|
|
32
32
|
|