monopyly 1.5.0__tar.gz → 1.5.2__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.
Files changed (239) hide show
  1. {monopyly-1.5.0 → monopyly-1.5.2}/.gitignore +4 -0
  2. {monopyly-1.5.0 → monopyly-1.5.2}/PKG-INFO +12 -13
  3. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/CHANGELOG.md +23 -0
  4. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/README.md +2 -2
  5. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/__init__.py +22 -27
  6. monopyly-1.5.2/monopyly/_version.py +16 -0
  7. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/auth/actions.py +12 -0
  8. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/auth/routes.py +31 -22
  9. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/auth/tools.py +1 -2
  10. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/accounts.py +3 -3
  11. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/banks.py +1 -1
  12. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/routes.py +1 -1
  13. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/transactions.py +14 -5
  14. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/forms/utils.py +1 -2
  15. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/transactions.py +17 -7
  16. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/actions.py +0 -7
  17. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/routes.py +0 -6
  18. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/accounts.py +1 -1
  19. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/cards.py +7 -3
  20. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/forms.py +1 -1
  21. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/routes.py +46 -25
  22. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/statements.py +1 -1
  23. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/_transactions.py +18 -5
  24. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/activity/parser.py +14 -6
  25. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/activity/reconciliation.py +20 -1
  26. monopyly-1.5.2/monopyly/database/__init__.py +46 -0
  27. monopyly-1.5.2/monopyly/database/models.py +391 -0
  28. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/css/style.css +191 -11
  29. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/create-balance-chart.js +1 -1
  30. monopyly-1.5.2/monopyly/templates/auth/change_password.html +21 -0
  31. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/auth/login.html +3 -1
  32. monopyly-1.5.2/monopyly/templates/auth/register.html +25 -0
  33. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/profile.html +2 -2
  34. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_reconciliation/statement_reconciliation_inquiry.html +1 -1
  35. monopyly-1.5.2/monopyly/templates/credit/transaction_submission_page.html +89 -0
  36. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transactions_table/condensed_row_content.html +0 -1
  37. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/layout.html +2 -2
  38. {monopyly-1.5.0 → monopyly-1.5.2}/pyproject.toml +10 -10
  39. monopyly-1.5.0/monopyly/_version.py +0 -4
  40. monopyly-1.5.0/monopyly/cli/apps.py +0 -108
  41. monopyly-1.5.0/monopyly/cli/launch.py +0 -135
  42. monopyly-1.5.0/monopyly/config/__init__.py +0 -1
  43. monopyly-1.5.0/monopyly/config/default_settings.py +0 -56
  44. monopyly-1.5.0/monopyly/config/settings.py +0 -59
  45. monopyly-1.5.0/monopyly/database/__init__.py +0 -101
  46. monopyly-1.5.0/monopyly/database/models.py +0 -483
  47. monopyly-1.5.0/monopyly/templates/auth/register.html +0 -15
  48. monopyly-1.5.0/monopyly/templates/credit/transaction_submission_page.html +0 -96
  49. {monopyly-1.5.0 → monopyly-1.5.2}/COPYING +0 -0
  50. {monopyly-1.5.0 → monopyly-1.5.2}/LICENSE +0 -0
  51. {monopyly-1.5.0 → monopyly-1.5.2}/README.md +0 -0
  52. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/auth/blueprint.py +0 -0
  53. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/actions.py +0 -0
  54. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/blueprint.py +0 -0
  55. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/filters.py +0 -0
  56. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/banking/forms.py +0 -0
  57. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/forms/__init__.py +0 -0
  58. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/forms/_forms.py +0 -0
  59. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/forms/fields.py +0 -0
  60. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/forms/validators.py +0 -0
  61. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/common/utils.py +0 -0
  62. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/blueprint.py +0 -0
  63. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/context_processors.py +0 -0
  64. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/errors.py +0 -0
  65. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/filters.py +0 -0
  66. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/core/internal_transactions.py +0 -0
  67. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/actions.py +0 -0
  68. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/blueprint.py +0 -0
  69. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/__init__.py +0 -0
  70. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/activity/__init__.py +0 -0
  71. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/credit/transactions/activity/data.py +0 -0
  72. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/database/preloads.sql +0 -0
  73. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/database/schema.sql +0 -0
  74. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/database/views.sql +0 -0
  75. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/browserconfig.xml +0 -0
  76. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-114.png +0 -0
  77. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-120.png +0 -0
  78. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-144.png +0 -0
  79. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-150.png +0 -0
  80. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-152.png +0 -0
  81. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-16.png +0 -0
  82. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-160.png +0 -0
  83. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-180.png +0 -0
  84. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-192.png +0 -0
  85. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-310.png +0 -0
  86. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-32.png +0 -0
  87. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-57.png +0 -0
  88. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-60.png +0 -0
  89. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-64.png +0 -0
  90. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-70.png +0 -0
  91. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-72.png +0 -0
  92. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-76.png +0 -0
  93. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon-96.png +0 -0
  94. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon.ico +0 -0
  95. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/favicon/favicon.png +0 -0
  96. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/bank-account-details.png +0 -0
  97. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/bank-account-summaries.png +0 -0
  98. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/bank-accounts.png +0 -0
  99. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/credit-account-details.png +0 -0
  100. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/credit-transactions.png +0 -0
  101. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/homepage-user.png +0 -0
  102. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/homepage.png +0 -0
  103. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/about/statement-details.png +0 -0
  104. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/cards/chase-card.png +0 -0
  105. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/cards/discover-card.png +0 -0
  106. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/cards/new-card.png +0 -0
  107. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/cards/template-card.png +0 -0
  108. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/arrow-down.png +0 -0
  109. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/arrow-left.png +0 -0
  110. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/arrow-up.png +0 -0
  111. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/checkmark.png +0 -0
  112. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/delete-orange-thick.png +0 -0
  113. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/delete-orange.png +0 -0
  114. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/delete-thick.png +0 -0
  115. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/delete.png +0 -0
  116. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/edit.png +0 -0
  117. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/link.png +0 -0
  118. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/minus-thick.png +0 -0
  119. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/minus.png +0 -0
  120. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/plus-thick.png +0 -0
  121. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/plus.png +0 -0
  122. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/refresh.png +0 -0
  123. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/save.png +0 -0
  124. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/sort-asc.png +0 -0
  125. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/sort-desc.png +0 -0
  126. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/statement-pair.png +0 -0
  127. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/statement-thick.png +0 -0
  128. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/statement.png +0 -0
  129. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/icons/x-thick.png +0 -0
  130. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/img/statement.png +0 -0
  131. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/jquery-3.7.0.min.js +0 -0
  132. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/add-subtransaction.js +0 -0
  133. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/add-transfer.js +0 -0
  134. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/autocomplete-transaction.js +0 -0
  135. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/bind-tag-actions.js +0 -0
  136. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/create-category-chart.js +0 -0
  137. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/define-filter.js +0 -0
  138. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/display-new-account-type-inputs.js +0 -0
  139. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/display-new-bank-inputs.js +0 -0
  140. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/display-new-credit-account-inputs.js +0 -0
  141. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/expand-bank-account.js +0 -0
  142. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/expand-bank.js +0 -0
  143. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/expand-transaction.js +0 -0
  144. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/flip-card.js +0 -0
  145. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/hide-homepage-block.js +0 -0
  146. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/highlight-discrepant-transactions.js +0 -0
  147. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/infer-card.js +0 -0
  148. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/infer-statement.js +0 -0
  149. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/make-payment.js +0 -0
  150. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/ajax.js +0 -0
  151. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/autocomplete-input.js +0 -0
  152. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/expand-box-row.js +0 -0
  153. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/expand-transaction.js +0 -0
  154. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/form-suggestions.js +0 -0
  155. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/manage-acquisition-form.js +0 -0
  156. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/manage-overlays.js +0 -0
  157. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/manage-subforms.js +0 -0
  158. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/update-database-widget.js +0 -0
  159. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/modules/update-display-ajax.js +0 -0
  160. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/show-credit-activity-loader.js +0 -0
  161. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/show-linked-transaction.js +0 -0
  162. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/toggle-navigation.js +0 -0
  163. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-account-statement-parameters.js +0 -0
  164. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-bank-name.js +0 -0
  165. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-card-status.js +0 -0
  166. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-statement-parameters.js +0 -0
  167. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-statements-display.js +0 -0
  168. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/update-transactions-display.js +0 -0
  169. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/use-suggested-amount.js +0 -0
  170. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/static/js/use-suggested-merchant.js +0 -0
  171. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_form/account_form.html +0 -0
  172. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_form/account_form_page_new.html +0 -0
  173. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_page.html +0 -0
  174. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_summaries.html +0 -0
  175. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_summaries_page.html +0 -0
  176. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/account_summary.html +0 -0
  177. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/accounts_page.html +0 -0
  178. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/bank_info_form.html +0 -0
  179. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/transaction_form.html +0 -0
  180. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/transaction_form_page.html +0 -0
  181. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/transaction_form_page_new.html +0 -0
  182. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/transaction_form_page_update.html +0 -0
  183. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transaction_form/transfer_form.html +0 -0
  184. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transactions_table/condensed_row_content.html +0 -0
  185. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transactions_table/expanded_row_content.html +0 -0
  186. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transactions_table/transaction_field_titles.html +0 -0
  187. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/banking/transactions_table/transactions.html +0 -0
  188. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/form_page.html +0 -0
  189. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transaction_form/subform.html +0 -0
  190. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transaction_form/subtransaction_subform.html +0 -0
  191. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transaction_form/transaction_form_page.html +0 -0
  192. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/linked_bank_transaction.html +0 -0
  193. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/linked_credit_transaction.html +0 -0
  194. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/linked_transaction_overlay.html +0 -0
  195. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/subtransactions.html +0 -0
  196. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/transaction_condensed.html +0 -0
  197. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/transaction_expanded.html +0 -0
  198. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/common/transactions_table/transactions.html +0 -0
  199. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/credits.html +0 -0
  200. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/400.html +0 -0
  201. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/401.html +0 -0
  202. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/403.html +0 -0
  203. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/404.html +0 -0
  204. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/405.html +0 -0
  205. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/408.html +0 -0
  206. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/418.html +0 -0
  207. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/425.html +0 -0
  208. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/500.html +0 -0
  209. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/errors/error.html +0 -0
  210. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/index.html +0 -0
  211. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/core/story.html +0 -0
  212. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/account_page.html +0 -0
  213. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_form/card_form.html +0 -0
  214. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_form/card_form_page_new.html +0 -0
  215. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_form/transfer_statement_inquiry.html +0 -0
  216. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_graphic/card_back.html +0 -0
  217. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_graphic/card_front.html +0 -0
  218. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/card_submission_page.html +0 -0
  219. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/cards.html +0 -0
  220. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/cards_page.html +0 -0
  221. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_page.html +0 -0
  222. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_reconciliation/discrepant_records.html +0 -0
  223. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_reconciliation/statement_reconciliation_page.html +0 -0
  224. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_reconciliation/summary.html +0 -0
  225. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_reconciliation/unrecorded_activities.html +0 -0
  226. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statement_summary.html +0 -0
  227. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statements.html +0 -0
  228. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/statements_page.html +0 -0
  229. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/tag_tree/subtag_tree.html +0 -0
  230. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/tag_tree/tag_tree.html +0 -0
  231. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/tags_page.html +0 -0
  232. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transaction_form/transaction_form.html +0 -0
  233. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transaction_form/transaction_form_page.html +0 -0
  234. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transaction_form/transaction_form_page_new.html +0 -0
  235. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transaction_form/transaction_form_page_update.html +0 -0
  236. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transactions_page.html +0 -0
  237. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transactions_table/expanded_row_content.html +0 -0
  238. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transactions_table/transaction_field_titles.html +0 -0
  239. {monopyly-1.5.0 → monopyly-1.5.2}/monopyly/templates/credit/transactions_table/transactions.html +0 -0
@@ -1,4 +1,5 @@
1
1
  *.swp
2
+ *vimrc*.vim
2
3
  .ipynb_checkpoints
3
4
 
4
5
  # Byte-compiled / optimized / DLL files
@@ -85,3 +86,6 @@ monopyly/static/favicon/*.ai
85
86
 
86
87
  # Flask instance files/data
87
88
  instance/
89
+
90
+ # PyPI Token
91
+ .TOKEN
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: monopyly
3
- Version: 1.5.0
3
+ Version: 1.5.2
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,15 @@ 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.0
27
- Requires-Dist: flask-wtf==1.2.1
28
- Requires-Dist: flask==3.0.3
29
- Requires-Dist: fuisce==1.0.2
30
- Requires-Dist: gunicorn==22.0.0
31
- Requires-Dist: markdown==3.6
32
- Requires-Dist: nltk==3.8.1
26
+ Requires-Dist: dry-foundation==1.3.0
27
+ Requires-Dist: flask-wtf==1.2.2
28
+ Requires-Dist: flask==3.1.2
29
+ Requires-Dist: gunicorn==23.0.0
30
+ Requires-Dist: markdown==3.9
31
+ Requires-Dist: nltk==3.9.1
33
32
  Requires-Dist: python-dateutil==2.9.0
34
- Requires-Dist: rich==13.7.1
35
- Requires-Dist: sqlalchemy==2.0.29
33
+ Requires-Dist: rich==14.1.0
34
+ Requires-Dist: sqlalchemy==2.0.43
36
35
  Description-Content-Type: text/markdown
37
36
 
38
37
  <div id="header">
@@ -64,10 +63,10 @@ The package requires a recent version of Python (3.10+).
64
63
 
65
64
  ## Getting started
66
65
 
67
- 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):
66
+ Once the package is properly installed, launch 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):
68
67
 
69
68
  ```
70
- $ monopyly local --browser [--host HOST] [--port PORT]
69
+ $ monopyly launch local --browser [--host HOST] [--port PORT]
71
70
  ```
72
71
 
73
72
  Local mode indicates that the app is just going to be run using a locally hosted server, accessible to just your machine.
@@ -199,4 +199,27 @@
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
+ - Fix issues with the application launcher not launching the browser; couple application launch process more tightly with click
211
+ - Use type annotations for SQLAlchemy ORM declarative mappings
212
+ - Increase the flexibility of the credit activity parser
213
+
214
+
215
+ ### 1.5.2
216
+
217
+ - Use smoothing on charts for up to 100 transactions
218
+ - Improve tokenization normalization for credit reconciliation
219
+ - Remove statement requiring activity files be located in the `Downloads` directory
220
+ - Do not clear the reconciliation info when adding subtransaction fields via POST request
221
+ - Incorporate support for enhanced database handler selection subsets
222
+ - Bump dependencies (including support for recent SQLAlchemy versions)
223
+
224
+
202
225
  <a name="bottom" id="bottom"></a>
@@ -27,10 +27,10 @@ The package requires a recent version of Python (3.10+).
27
27
 
28
28
  ## Getting started
29
29
 
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):
30
+ Once the package is properly installed, launch 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 local --browser [--host HOST] [--port PORT]
33
+ $ monopyly launch local --browser [--host HOST] [--port PORT]
34
34
  ```
35
35
 
36
36
  Local mode indicates that the app is just going to be run using a locally hosted server, accessible to just your machine.
@@ -2,39 +2,29 @@
2
2
  Run the Monopyly app.
3
3
  """
4
4
 
5
- from flask import Flask
5
+ from dry_foundation import DryFlask, Factory, interact
6
6
 
7
- from monopyly.config import DevelopmentConfig, ProductionConfig
8
- from monopyly.core.errors import render_error_template
9
- from monopyly.database import SQLAlchemy, register_db_cli_commands
7
+ from .core.errors import render_error_template
8
+ from .database import SQLAlchemy
10
9
 
11
10
 
12
- def create_app(test_config=None, debug=None):
13
- # Create and configure the app
14
- app = Flask(__name__, instance_relative_config=True)
15
-
16
- # Prepare the app configuration
17
- if test_config:
18
- config = test_config
19
- else:
20
- # Load the development/production config when not testing
21
- if app.debug or debug:
22
- config = DevelopmentConfig.configure_for_instance(app.instance_path)
23
- else:
24
- config = ProductionConfig.configure_for_instance(app.instance_path)
25
- app.config.from_object(config)
26
-
27
- # Initialize the app, including CLI commands and blueprints
28
- init_app(app)
29
- return app
30
-
11
+ @Factory(db_interface=SQLAlchemy)
12
+ def create_app(config=None):
13
+ """
14
+ Create the Flask application.
31
15
 
32
- @SQLAlchemy.interface_selector
33
- def init_app(app):
34
- """Initialize the app."""
16
+ Create the Flask app, including configurations as specified. This
17
+ will configure the app using the configuration objects made
18
+ available by the Monopyly application and initialize the app
19
+ by registering app blueprints, routes, and commands.
20
+ """
21
+ # Create and configure the app
22
+ app = DryFlask(__name__, app_name="Monopyly")
23
+ app.configure(config)
24
+ # Register blueprints and error handlers specific to this app
35
25
  register_blueprints(app)
36
26
  register_errorhandlers(app)
37
- register_db_cli_commands(app)
27
+ return app
38
28
 
39
29
 
40
30
  def register_blueprints(app):
@@ -76,3 +66,8 @@ def register_errorhandlers(app):
76
66
  ]
77
67
  for code in handled_error_codes:
78
68
  app.register_error_handler(code, render_error_template)
69
+
70
+
71
+ def main():
72
+ """The entry point to the Monopyly application."""
73
+ interact(__name__)
@@ -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.2'
16
+ __version_tuple__ = version_tuple = (1, 5, 2)
@@ -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
@@ -2,21 +2,22 @@
2
2
  Routes for site authentication.
3
3
  """
4
4
 
5
+ from dry_foundation.database import db_transaction
5
6
  from flask import (
6
7
  current_app,
7
8
  flash,
9
+ g,
8
10
  redirect,
9
11
  render_template,
10
12
  request,
11
13
  session,
12
14
  url_for,
13
15
  )
14
- from fuisce.database import db_transaction
15
16
  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
- # Get user information from the database
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
- else:
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
- error = None
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
- else:
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 = session.get("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)
@@ -3,7 +3,7 @@ Tools for interacting with bank accounts in the database.
3
3
  """
4
4
 
5
5
  import sqlalchemy.sql.functions as sql_func
6
- from authanor.database.handler import DatabaseViewHandler
6
+ from dry_foundation.database.handler import DatabaseViewHandler
7
7
  from werkzeug.exceptions import abort
8
8
 
9
9
  from ..common.forms.utils import execute_on_form_validation
@@ -229,10 +229,10 @@ class BankAccountHandler(
229
229
  return account
230
230
 
231
231
  @classmethod
232
- def _filter_entries(cls, query, criteria):
232
+ def _filter_entries(cls, query, criteria, offset, limit):
233
233
  # Add a join to enable filtering by bank account type
234
234
  query = query.join(BankAccountTypeView)
235
- return super()._filter_entries(query, criteria)
235
+ return super()._filter_entries(query, criteria, offset, limit)
236
236
 
237
237
  @classmethod
238
238
  def delete_entry(cls, entry_id):
@@ -2,7 +2,7 @@
2
2
  Tools for interacting with banks in the database.
3
3
  """
4
4
 
5
- from authanor.database.handler import DatabaseHandler
5
+ from dry_foundation.database.handler import DatabaseHandler
6
6
 
7
7
  from ..database.models import Bank
8
8
 
@@ -2,8 +2,8 @@
2
2
  Routes for banking financials.
3
3
  """
4
4
 
5
+ from dry_foundation.database import db_transaction
5
6
  from flask import jsonify, redirect, render_template, request, url_for
6
- from fuisce.database import db_transaction
7
7
 
8
8
  from ..auth.tools import login_required
9
9
  from ..common.forms.utils import extend_field_list_for_ajax
@@ -2,7 +2,7 @@
2
2
  Tools for interacting with the bank transactions in the database.
3
3
  """
4
4
 
5
- from authanor.database.handler import DatabaseViewHandler
5
+ from dry_foundation.database.handler import DatabaseViewHandler
6
6
 
7
7
  from ..common.forms.utils import execute_on_form_validation
8
8
  from ..common.transactions import TransactionHandler, TransactionTagHandler
@@ -36,7 +36,9 @@ class BankTransactionHandler(
36
36
 
37
37
  @classmethod
38
38
  @DatabaseViewHandler.view_query
39
- def get_transactions(cls, account_ids=None, active=None, sort_order="DESC"):
39
+ def get_transactions(
40
+ cls, account_ids=None, active=None, sort_order="DESC", offset=None, limit=None
41
+ ):
40
42
  """
41
43
  Get bank transactions from the database.
42
44
 
@@ -61,6 +63,13 @@ class BankTransactionHandler(
61
63
  An indicator of whether the transactions should be ordered
62
64
  in ascending (oldest at top) or descending (newest at top)
63
65
  order. The default is descending order.
66
+ offset : int, optional
67
+ The number of transactions by which to offset the results
68
+ returned by this query. The default is `None`, in which case
69
+ no offset will be added.
70
+ limit : int, optional
71
+ A limit on the number of transactions retrieved from the
72
+ database.
64
73
 
65
74
  Returns
66
75
  -------
@@ -71,7 +80,7 @@ class BankTransactionHandler(
71
80
  criteria.add_match_filter(cls.model, "account_id", account_ids)
72
81
  criteria.add_match_filter(BankAccountView, "active", active)
73
82
  transactions = super()._get_transactions(
74
- criteria=criteria, sort_order=sort_order
83
+ criteria=criteria, sort_order=sort_order, offset=None, limit=None
75
84
  )
76
85
  return transactions
77
86
 
@@ -150,7 +159,7 @@ class BankTagHandler(TransactionTagHandler, model=TransactionTagHandler.model):
150
159
  return tags
151
160
 
152
161
  @classmethod
153
- def _filter_entries(cls, query, criteria):
162
+ def _filter_entries(cls, query, criteria, offset, limit):
154
163
  # Add a join to enable filtering by transaction ID or subtransaction ID
155
164
  join_transaction = BankTransactionView in criteria.discriminators
156
165
  join_subtransaction = (
@@ -160,7 +169,7 @@ class BankTagHandler(TransactionTagHandler, model=TransactionTagHandler.model):
160
169
  query = query.join(bank_tag_link_table).join(BankSubtransaction)
161
170
  if join_transaction:
162
171
  query = query.join(BankTransactionView)
163
- return super()._filter_entries(query, criteria)
172
+ return super()._filter_entries(query, criteria, offset, limit)
164
173
 
165
174
 
166
175
  @execute_on_form_validation
@@ -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
- print(form.errors)
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
@@ -4,7 +4,7 @@ Tools for building a common transaction interface.
4
4
 
5
5
  from abc import abstractmethod
6
6
 
7
- from authanor.database.handler import DatabaseHandler, DatabaseViewHandler
7
+ from dry_foundation.database.handler import DatabaseHandler, DatabaseViewHandler
8
8
  from flask import current_app
9
9
 
10
10
  from ..database.models import (
@@ -31,17 +31,27 @@ class TransactionHandler(DatabaseViewHandler):
31
31
  """
32
32
 
33
33
  @classmethod
34
- def _customize_entries_query(cls, query, criteria, column_orders):
34
+ def _customize_entries_query(
35
+ cls, query, criteria, column_orders, offset=None, limit=None
36
+ ):
35
37
  # Group transactions and order by transaction date
36
38
  query = query.group_by(cls.model.id)
37
- return super()._customize_entries_query(query, criteria, column_orders)
39
+ return super()._customize_entries_query(
40
+ query, criteria, column_orders, offset=offset, limit=limit
41
+ )
38
42
 
39
43
  @classmethod
40
- def _get_transactions(cls, criteria=None, sort_order="DESC"):
44
+ def _get_transactions(
45
+ cls, criteria=None, sort_order="DESC", offset=None, limit=None
46
+ ):
41
47
  # Specify transaction order
42
48
  column_orders = {cls.model.transaction_date: sort_order}
43
49
  entries = cls.get_entries(
44
- entry_ids=None, criteria=criteria, column_orders=column_orders
50
+ entry_ids=None,
51
+ criteria=criteria,
52
+ column_orders=column_orders,
53
+ offset=offset,
54
+ limit=limit,
45
55
  )
46
56
  return entries
47
57
 
@@ -232,10 +242,10 @@ class TransactionTagHandler(DatabaseHandler, model=TransactionTag):
232
242
  return tags
233
243
 
234
244
  @classmethod
235
- def _filter_entries(cls, query, criteria):
245
+ def _filter_entries(cls, query, criteria, offset, limit):
236
246
  # Only get distinct tag entries
237
247
  query = query.distinct()
238
- return super()._filter_entries(query, criteria)
248
+ return super()._filter_entries(query, criteria, offset, limit)
239
249
 
240
250
  @classmethod
241
251
  def get_subtags(cls, tag):
@@ -1,15 +1,8 @@
1
1
  """Module describing logical core actions (to be used in routes)."""
2
2
 
3
- from datetime import datetime
4
-
5
3
  import markdown
6
4
 
7
5
 
8
- def get_timestamp():
9
- """Get a timestamp for backup filenames."""
10
- return datetime.now().strftime("%Y%m%d_%H%M%S")
11
-
12
-
13
6
  class MarkdownConverter:
14
7
 
15
8
  replacements = {
@@ -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)
@@ -2,7 +2,7 @@
2
2
  Tools for interacting with credit accounts in the database.
3
3
  """
4
4
 
5
- from authanor.database.handler import DatabaseHandler
5
+ from dry_foundation.database.handler import DatabaseHandler
6
6
 
7
7
  from ..database.models import CreditAccount
8
8
 
@@ -2,7 +2,7 @@
2
2
  Tools for interacting with credit cards in the database.
3
3
  """
4
4
 
5
- from authanor.database.handler import DatabaseHandler
5
+ from dry_foundation.database.handler import DatabaseHandler
6
6
 
7
7
  from ..common.forms.utils import execute_on_form_validation
8
8
  from ..database.models import Bank, CreditAccount, CreditCard
@@ -99,8 +99,12 @@ class CreditCardHandler(DatabaseHandler, model=CreditCard):
99
99
  return card
100
100
 
101
101
  @classmethod
102
- def _customize_entries_query(cls, query, filters, sort_order):
103
- query = super()._customize_entries_query(query, filters, sort_order)
102
+ def _customize_entries_query(
103
+ cls, query, filters, sort_order, offset=None, limit=None
104
+ ):
105
+ query = super()._customize_entries_query(
106
+ query, filters, sort_order, offset=offset, limit=limit
107
+ )
104
108
  # Order cards by active status (active cards first)
105
109
  query = query.order_by(cls.model.active.desc())
106
110
  return query
@@ -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 := self._extract_suggestion(data, "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 = []