monopyly 1.5.1__py3-none-any.whl → 1.6.0__py3-none-any.whl

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 (97) hide show
  1. monopyly/CHANGELOG.md +27 -0
  2. monopyly/README.md +3 -3
  3. monopyly/__init__.py +22 -27
  4. monopyly/_version.py +2 -2
  5. monopyly/auth/blueprint.py +2 -0
  6. monopyly/auth/routes.py +2 -3
  7. monopyly/banking/accounts.py +7 -7
  8. monopyly/banking/actions.py +20 -17
  9. monopyly/banking/banks.py +1 -1
  10. monopyly/banking/blueprint.py +2 -0
  11. monopyly/banking/filters.py +6 -6
  12. monopyly/banking/forms.py +3 -5
  13. monopyly/banking/routes.py +72 -10
  14. monopyly/banking/transactions.py +15 -7
  15. monopyly/common/forms/__init__.py +8 -0
  16. monopyly/common/forms/_forms.py +1 -2
  17. monopyly/common/forms/fields.py +0 -2
  18. monopyly/common/forms/utils.py +1 -1
  19. monopyly/common/transactions.py +89 -14
  20. monopyly/core/actions.py +2 -8
  21. monopyly/core/blueprint.py +2 -0
  22. monopyly/core/filters.py +0 -2
  23. monopyly/core/routes.py +1 -1
  24. monopyly/credit/accounts.py +1 -1
  25. monopyly/credit/actions.py +4 -5
  26. monopyly/credit/blueprint.py +2 -0
  27. monopyly/credit/cards.py +7 -3
  28. monopyly/credit/forms.py +3 -5
  29. monopyly/credit/routes.py +65 -87
  30. monopyly/credit/statements.py +1 -1
  31. monopyly/credit/transactions/__init__.py +2 -0
  32. monopyly/credit/transactions/_transactions.py +18 -8
  33. monopyly/credit/transactions/activity/__init__.py +6 -0
  34. monopyly/credit/transactions/activity/parser.py +0 -1
  35. monopyly/credit/transactions/activity/reconciliation.py +25 -4
  36. monopyly/database/__init__.py +1 -59
  37. monopyly/database/models.py +198 -276
  38. monopyly/database/preloads.sql +6 -1
  39. monopyly/scripts/screenshot_application.py +100 -0
  40. monopyly/static/chartist-1.5.0.min.js +8 -0
  41. monopyly/static/css/style.css +35 -14
  42. monopyly/static/img/about/bank-account-details.png +0 -0
  43. monopyly/static/img/about/bank-account-summaries.png +0 -0
  44. monopyly/static/img/about/bank-accounts.png +0 -0
  45. monopyly/static/img/about/credit-account-details.png +0 -0
  46. monopyly/static/img/about/credit-statement-details.png +0 -0
  47. monopyly/static/img/about/credit-transactions.png +0 -0
  48. monopyly/static/img/about/homepage-user.png +0 -0
  49. monopyly/static/img/about/homepage.png +0 -0
  50. monopyly/static/jquery-3.7.1.min.js +2 -0
  51. monopyly/static/js/add-transfer.js +8 -9
  52. monopyly/static/js/bind-tag-actions.js +6 -0
  53. monopyly/static/js/create-balance-chart.js +2 -2
  54. monopyly/static/js/create-category-chart.js +1 -1
  55. monopyly/static/js/load-more-transactions.js +27 -0
  56. monopyly/static/js/modules/expand-transaction.js +7 -6
  57. monopyly/static/js/modules/update-display-ajax.js +20 -1
  58. monopyly/static/js/update-transactions-display.js +8 -2
  59. monopyly/templates/banking/account_page.html +15 -16
  60. monopyly/templates/banking/account_summaries.html +2 -2
  61. monopyly/templates/banking/account_summary.html +1 -1
  62. monopyly/templates/banking/accounts_page.html +2 -2
  63. monopyly/templates/banking/transactions_table/table.html +3 -0
  64. monopyly/templates/banking/transactions_table/transactions.html +0 -1
  65. monopyly/templates/common/tag_tree.html +25 -0
  66. monopyly/templates/{credit → common}/tags_page.html +7 -3
  67. monopyly/templates/common/transactions_table/linked_bank_transaction.html +2 -2
  68. monopyly/templates/common/transactions_table/table.html +6 -0
  69. monopyly/templates/common/transactions_table/transactions.html +9 -15
  70. monopyly/templates/core/index.html +112 -101
  71. monopyly/templates/core/profile.html +1 -1
  72. monopyly/templates/credit/statement_page.html +2 -2
  73. monopyly/templates/credit/statement_reconciliation/statement_reconciliation_inquiry.html +1 -1
  74. monopyly/templates/credit/statement_reconciliation/statement_reconciliation_page.html +3 -3
  75. monopyly/templates/credit/statement_summary.html +2 -2
  76. monopyly/templates/credit/transaction_submission_page.html +3 -3
  77. monopyly/templates/credit/transactions_page.html +19 -3
  78. monopyly/templates/credit/transactions_table/condensed_row_content.html +2 -3
  79. monopyly/templates/credit/transactions_table/expanded_row_content.html +5 -5
  80. monopyly/templates/credit/transactions_table/table.html +3 -0
  81. monopyly/templates/credit/transactions_table/transactions.html +0 -1
  82. monopyly/templates/layout.html +9 -4
  83. {monopyly-1.5.1.dist-info → monopyly-1.6.0.dist-info}/METADATA +12 -13
  84. {monopyly-1.5.1.dist-info → monopyly-1.6.0.dist-info}/RECORD +88 -87
  85. monopyly-1.6.0.dist-info/entry_points.txt +3 -0
  86. monopyly/cli/apps.py +0 -108
  87. monopyly/cli/launch.py +0 -135
  88. monopyly/config/__init__.py +0 -1
  89. monopyly/config/default_settings.py +0 -56
  90. monopyly/config/settings.py +0 -59
  91. monopyly/static/jquery-3.7.0.min.js +0 -2
  92. monopyly/templates/credit/tag_tree/subtag_tree.html +0 -22
  93. monopyly/templates/credit/tag_tree/tag_tree.html +0 -13
  94. monopyly-1.5.1.dist-info/entry_points.txt +0 -2
  95. {monopyly-1.5.1.dist-info → monopyly-1.6.0.dist-info}/WHEEL +0 -0
  96. {monopyly-1.5.1.dist-info → monopyly-1.6.0.dist-info}/licenses/COPYING +0 -0
  97. {monopyly-1.5.1.dist-info → monopyly-1.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,45 +1,45 @@
1
- from authanor.database.models import AuthorizedAccessMixin, Model
2
- from sqlalchemy import Column, Date, Float, ForeignKey, Integer, String, Table
3
- from sqlalchemy.ext.hybrid import hybrid_property
4
- from sqlalchemy.orm import mapped_column, relationship
1
+ import datetime
2
+
3
+ from dry_foundation.database.models import AuthorizedAccessMixin, Model
4
+ from sqlalchemy import Column, ForeignKey, Integer, Table
5
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
5
6
 
6
7
 
7
8
  class User(Model):
8
9
  __tablename__ = "users"
9
10
  # Columns
10
- id = mapped_column(Integer, primary_key=True)
11
- username = mapped_column(String, nullable=False)
12
- password = mapped_column(String, nullable=False)
11
+ id: Mapped[int] = mapped_column(primary_key=True)
12
+ username: Mapped[str]
13
+ password: Mapped[str]
13
14
  # Relationships
14
- banks = relationship(
15
- "Bank",
16
- back_populates="user",
17
- cascade="all, delete",
18
- )
19
- bank_account_types = relationship(
20
- "BankAccountTypeView",
21
- viewonly=True,
22
- back_populates="user",
15
+ banks: Mapped["Bank"] = relationship(back_populates="user", cascade="all, delete")
16
+ bank_account_type_views: Mapped[list["BankAccountTypeView"]] = relationship(
17
+ back_populates="user", viewonly=True
23
18
  )
24
19
 
25
20
 
26
21
  class InternalTransaction(Model):
27
22
  __tablename__ = "internal_transactions"
28
23
  # Columns
29
- id = mapped_column(Integer, primary_key=True)
24
+ id: Mapped[int] = mapped_column(primary_key=True)
30
25
  # Relationships
31
- bank_transactions = relationship(
32
- "BankTransactionView",
33
- back_populates="internal_transaction",
26
+ bank_transactions: Mapped[list["BankTransaction"]] = relationship(
27
+ back_populates="internal_transaction"
28
+ )
29
+ bank_transaction_views: Mapped[list["BankTransactionView"]] = relationship(
30
+ back_populates="internal_transaction", viewonly=True
31
+ )
32
+ credit_transactions: Mapped[list["CreditTransaction"]] = relationship(
33
+ back_populates="internal_transaction"
34
34
  )
35
- credit_transactions = relationship(
36
- "CreditTransactionView",
37
- back_populates="internal_transaction",
35
+ credit_transaction_views: Mapped[list["CreditTransactionView"]] = relationship(
36
+ back_populates="internal_transaction", viewonly=True
38
37
  )
39
38
 
39
+ @property
40
+ def transaction_views(self):
41
+ return self.bank_transaction_views + self.credit_transaction_views
40
42
 
41
- # Not sure why these tables are necessary, because they should already be reflected;
42
- # perhaps explore or wait until sqlalchemy 2.0
43
43
 
44
44
  bank_tag_link_table = Table(
45
45
  "bank_tag_links",
@@ -67,23 +67,22 @@ credit_tag_link_table = Table(
67
67
 
68
68
  class TransactionTag(AuthorizedAccessMixin, Model):
69
69
  __tablename__ = "transaction_tags"
70
+ _alt_authorized_ids = (0,)
70
71
  # Columns
71
- id = mapped_column(Integer, primary_key=True)
72
- user_id = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
73
- parent_id = mapped_column(Integer, ForeignKey("transaction_tags.id"))
74
- tag_name = mapped_column(String, nullable=False)
72
+ id: Mapped[int] = mapped_column(primary_key=True)
73
+ user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
74
+ parent_id: Mapped[int | None] = mapped_column(ForeignKey("transaction_tags.id"))
75
+ tag_name: Mapped[str]
75
76
  # Relationships
76
- parent = relationship("TransactionTag", back_populates="children", remote_side=[id])
77
- children = relationship("TransactionTag", back_populates="parent")
78
- bank_subtransactions = relationship(
79
- "BankSubtransaction",
80
- secondary=bank_tag_link_table,
81
- back_populates="tags",
77
+ parent: Mapped["TransactionTag"] = relationship(
78
+ back_populates="children", remote_side=[id]
82
79
  )
83
- credit_subtransactions = relationship(
84
- "CreditSubtransaction",
85
- secondary=credit_tag_link_table,
86
- back_populates="tags",
80
+ children: Mapped[list["TransactionTag"]] = relationship(back_populates="parent")
81
+ bank_subtransactions: Mapped[list["BankSubtransaction"]] = relationship(
82
+ back_populates="tags", secondary=bank_tag_link_table
83
+ )
84
+ credit_subtransactions: Mapped[list["CreditSubtransaction"]] = relationship(
85
+ back_populates="tags", secondary=credit_tag_link_table
87
86
  )
88
87
 
89
88
  @property
@@ -97,21 +96,16 @@ class TransactionTag(AuthorizedAccessMixin, Model):
97
96
  class Bank(AuthorizedAccessMixin, Model):
98
97
  __tablename__ = "banks"
99
98
  # Columns
100
- id = mapped_column(Integer, primary_key=True)
101
- user_id = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
102
- bank_name = mapped_column(String, nullable=False)
99
+ id: Mapped[int] = mapped_column(primary_key=True)
100
+ user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
101
+ bank_name: Mapped[str]
103
102
  # Relationships
104
- user = relationship("User", back_populates="banks")
105
- bank_accounts = relationship(
106
- "BankAccountView",
107
- viewonly=True,
108
- back_populates="bank",
109
- cascade="all, delete",
103
+ user: Mapped["User"] = relationship(back_populates="banks")
104
+ bank_account_views: Mapped[list["BankAccountView"]] = relationship(
105
+ back_populates="bank", cascade="all, delete", viewonly=True
110
106
  )
111
- credit_accounts = relationship(
112
- "CreditAccount",
113
- back_populates="bank",
114
- cascade="all, delete",
107
+ credit_accounts: Mapped[list["CreditAccount"]] = relationship(
108
+ back_populates="bank", cascade="all, delete"
115
109
  )
116
110
 
117
111
 
@@ -119,16 +113,13 @@ class BankAccountType(AuthorizedAccessMixin, Model):
119
113
  __tablename__ = "bank_account_types"
120
114
  _alt_authorized_ids = (0,)
121
115
  # Columns
122
- id = mapped_column(Integer, primary_key=True)
123
- user_id = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
124
- type_name = mapped_column(String, nullable=False)
125
- type_abbreviation = mapped_column(String)
116
+ id: Mapped[int] = mapped_column(primary_key=True)
117
+ user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
118
+ type_name: Mapped[str]
119
+ type_abbreviation: Mapped[str | None]
126
120
  # Relationships
127
- view = relationship(
128
- "BankAccountTypeView",
129
- viewonly=True,
130
- back_populates="account_type",
131
- uselist=False,
121
+ view: Mapped["BankAccountTypeView"] = relationship(
122
+ back_populates="account_type", uselist=False, viewonly=True
132
123
  )
133
124
 
134
125
 
@@ -137,20 +128,15 @@ class BankAccountTypeView(AuthorizedAccessMixin, Model):
137
128
  _alt_authorized_ids = (0,)
138
129
  # Columns
139
130
  id = mapped_column(Integer, ForeignKey("bank_account_types.id"), primary_key=True)
140
- user_id = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
141
- type_name = mapped_column(String, nullable=False)
142
- type_abbreviation = mapped_column(String)
143
- type_common_name = mapped_column(String, nullable=False)
131
+ user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
132
+ type_name: Mapped[str]
133
+ type_abbreviation: Mapped[str | None]
134
+ type_common_name: Mapped[str]
144
135
  # Relationships
145
- account_type = relationship(
146
- "BankAccountType",
147
- back_populates="view",
148
- )
149
- user = relationship("User", back_populates="bank_account_types")
150
- accounts = relationship(
151
- "BankAccountView",
152
- viewonly=True,
153
- back_populates="account_type",
136
+ account_type: Mapped["BankAccountType"] = relationship(back_populates="view")
137
+ user: Mapped["User"] = relationship(back_populates="bank_account_type_views")
138
+ account_views: Mapped[list["BankAccountView"]] = relationship(
139
+ back_populates="account_type_view", viewonly=True
154
140
  )
155
141
 
156
142
 
@@ -158,21 +144,16 @@ class BankAccount(AuthorizedAccessMixin, Model):
158
144
  __tablename__ = "bank_accounts"
159
145
  _user_id_join_chain = (Bank,)
160
146
  # Columns
161
- id = mapped_column(Integer, primary_key=True)
162
- bank_id = mapped_column(Integer, ForeignKey("banks.id"), nullable=False)
163
- account_type_id = mapped_column(
164
- Integer,
165
- ForeignKey("bank_account_types_view.id"),
166
- nullable=False,
167
- )
168
- last_four_digits = mapped_column(String, nullable=False)
169
- active = mapped_column(Integer, nullable=False)
147
+ id: Mapped[int] = mapped_column(primary_key=True)
148
+ bank_id: Mapped[int] = mapped_column(ForeignKey("banks.id"))
149
+ account_type_id: Mapped[int] = mapped_column(
150
+ ForeignKey("bank_account_types_view.id")
151
+ )
152
+ last_four_digits: Mapped[str]
153
+ active: Mapped[int]
170
154
  # Relationships
171
- view = relationship(
172
- "BankAccountView",
173
- viewonly=True,
174
- back_populates="account",
175
- uselist=False,
155
+ view: Mapped["BankAccountView"] = relationship(
156
+ back_populates="account", uselist=False, viewonly=True
176
157
  )
177
158
 
178
159
 
@@ -180,27 +161,23 @@ class BankAccountView(AuthorizedAccessMixin, Model):
180
161
  __tablename__ = "bank_accounts_view"
181
162
  _user_id_join_chain = (Bank,)
182
163
  # Columns
183
- id = mapped_column(Integer, ForeignKey("bank_accounts.id"), primary_key=True)
184
- bank_id = mapped_column(Integer, ForeignKey("banks.id"), nullable=False)
185
- account_type_id = mapped_column(
186
- Integer,
187
- ForeignKey("bank_account_types_view.id"),
188
- nullable=False,
189
- )
190
- last_four_digits = mapped_column(String, nullable=False)
191
- active = mapped_column(Integer, nullable=False)
192
- balance = mapped_column(Float, nullable=False)
193
- projected_balance = mapped_column(Float, nullable=False)
164
+ id: Mapped[int] = mapped_column(ForeignKey("bank_accounts.id"), primary_key=True)
165
+ bank_id: Mapped[int] = mapped_column(ForeignKey("banks.id"))
166
+ account_type_id: Mapped[int] = mapped_column(
167
+ ForeignKey("bank_account_types_view.id")
168
+ )
169
+ last_four_digits: Mapped[str]
170
+ active: Mapped[int]
171
+ balance: Mapped[float]
172
+ projected_balance: Mapped[float]
194
173
  # Relationships
195
- account = relationship("BankAccount", back_populates="view")
196
- bank = relationship("Bank", back_populates="bank_accounts")
197
- account_type = relationship(
198
- "BankAccountTypeView",
199
- viewonly=True,
200
- back_populates="accounts",
174
+ account: Mapped["BankAccount"] = relationship(back_populates="view")
175
+ bank: Mapped["Bank"] = relationship(back_populates="bank_account_views")
176
+ account_type_view: Mapped["BankAccountTypeView"] = relationship(
177
+ back_populates="account_views", viewonly=True
201
178
  )
202
- transactions = relationship(
203
- "BankTransactionView", viewonly=True, back_populates="account"
179
+ transaction_views: Mapped[list["BankTransactionView"]] = relationship(
180
+ back_populates="account_view", viewonly=True
204
181
  )
205
182
 
206
183
 
@@ -210,25 +187,19 @@ class BankTransaction(AuthorizedAccessMixin, Model):
210
187
  # Denote the transaction subtype
211
188
  subtype = "bank"
212
189
  # Columns
213
- id = mapped_column(Integer, primary_key=True)
214
- internal_transaction_id = mapped_column(
215
- Integer,
216
- ForeignKey("internal_transactions.id"),
217
- )
218
- account_id = mapped_column(
219
- Integer,
220
- ForeignKey("bank_accounts_view.id"),
221
- nullable=False,
222
- )
223
- transaction_date = mapped_column(Date, nullable=False)
224
- merchant = mapped_column(String)
225
- # ((Should have optional merchant field?))
190
+ id: Mapped[int] = mapped_column(primary_key=True)
191
+ internal_transaction_id: Mapped[int | None] = mapped_column(
192
+ ForeignKey("internal_transactions.id")
193
+ )
194
+ account_id: Mapped[int] = mapped_column(ForeignKey("bank_accounts_view.id"))
195
+ transaction_date: Mapped[datetime.date]
196
+ merchant: Mapped[str | None]
226
197
  # Relationships
227
- view = relationship(
228
- "BankTransactionView",
229
- viewonly=True,
230
- back_populates="transaction",
231
- uselist=False,
198
+ view: Mapped["BankTransactionView"] = relationship(
199
+ back_populates="transaction", uselist=False, viewonly=True
200
+ )
201
+ internal_transaction: Mapped["InternalTransaction"] = relationship(
202
+ back_populates="bank_transactions"
232
203
  )
233
204
 
234
205
 
@@ -238,35 +209,28 @@ class BankTransactionView(AuthorizedAccessMixin, Model):
238
209
  # Denote the transaction subtype
239
210
  subtype = "bank"
240
211
  # Columns
241
- id = mapped_column(Integer, ForeignKey("bank_transactions.id"), primary_key=True)
242
- internal_transaction_id = mapped_column(
243
- Integer,
244
- ForeignKey("internal_transactions.id"),
245
- )
246
- account_id = mapped_column(
247
- Integer,
248
- ForeignKey("bank_accounts_view.id"),
249
- nullable=False,
250
- )
251
- transaction_date = mapped_column(Date, nullable=False)
252
- merchant = mapped_column(String)
253
- total = mapped_column(Float)
254
- notes = mapped_column(String)
255
- balance = mapped_column(Float)
256
- # ((Should have optional merchant field?))
212
+ id: Mapped[int] = mapped_column(
213
+ ForeignKey("bank_transactions.id"), primary_key=True
214
+ )
215
+ internal_transaction_id: Mapped[int | None] = mapped_column(
216
+ ForeignKey("internal_transactions.id")
217
+ )
218
+ account_id: Mapped[int] = mapped_column(ForeignKey("bank_accounts_view.id"))
219
+ transaction_date: Mapped[datetime.date]
220
+ merchant: Mapped[str | None]
221
+ total: Mapped[float]
222
+ notes: Mapped[str | None]
223
+ balance: Mapped[float]
257
224
  # Relationships
258
- transaction = relationship(
259
- "BankTransaction",
260
- back_populates="view",
225
+ transaction: Mapped["BankTransaction"] = relationship(back_populates="view")
226
+ internal_transaction: Mapped["InternalTransaction"] = relationship(
227
+ back_populates="bank_transaction_views"
261
228
  )
262
- internal_transaction = relationship(
263
- "InternalTransaction", back_populates="bank_transactions"
229
+ account_view: Mapped["BankAccountView"] = relationship(
230
+ back_populates="transaction_views", viewonly=True
264
231
  )
265
- account = relationship("BankAccountView", back_populates="transactions")
266
- subtransactions = relationship(
267
- "BankSubtransaction",
268
- back_populates="transaction",
269
- lazy="selectin",
232
+ subtransactions: Mapped[list["BankSubtransaction"]] = relationship(
233
+ back_populates="transaction_view", lazy="selectin", cascade="all, delete"
270
234
  )
271
235
 
272
236
 
@@ -274,24 +238,17 @@ class BankSubtransaction(AuthorizedAccessMixin, Model):
274
238
  __tablename__ = "bank_subtransactions"
275
239
  _user_id_join_chain = (BankTransactionView, BankAccountView, Bank)
276
240
  # Columns
277
- id = mapped_column(Integer, primary_key=True)
278
- transaction_id = mapped_column(
279
- Integer,
280
- ForeignKey("bank_transactions_view.id"),
281
- nullable=False,
282
- )
283
- subtotal = mapped_column(Float, nullable=False)
284
- note = mapped_column(String, nullable=False)
241
+ id: Mapped[int] = mapped_column(primary_key=True)
242
+ transaction_id: Mapped[int] = mapped_column(ForeignKey("bank_transactions_view.id"))
243
+ subtotal: Mapped[float]
244
+ note: Mapped[str]
285
245
  # Relationships
286
- transaction = relationship(
287
- "BankTransactionView",
288
- viewonly=True,
289
- back_populates="subtransactions",
246
+ transaction_view: Mapped["BankTransactionView"] = relationship(
247
+ back_populates="subtransactions", viewonly=True
290
248
  )
291
- tags = relationship(
292
- "TransactionTag",
293
- secondary=bank_tag_link_table,
249
+ tags: Mapped[list["TransactionTag"]] = relationship(
294
250
  back_populates="bank_subtransactions",
251
+ secondary=bank_tag_link_table,
295
252
  lazy="selectin",
296
253
  )
297
254
 
@@ -300,17 +257,15 @@ class CreditAccount(AuthorizedAccessMixin, Model):
300
257
  __tablename__ = "credit_accounts"
301
258
  _user_id_join_chain = (Bank,)
302
259
  # Columns
303
- id = mapped_column(Integer, primary_key=True)
304
- bank_id = mapped_column(Integer, ForeignKey("banks.id"), nullable=False)
305
- statement_issue_day = mapped_column(Integer, nullable=False)
306
- statement_due_day = mapped_column(Integer, nullable=False)
260
+ id: Mapped[int] = mapped_column(primary_key=True)
261
+ bank_id: Mapped[int] = mapped_column(ForeignKey("banks.id"))
262
+ statement_issue_day: Mapped[int]
263
+ statement_due_day: Mapped[int]
307
264
  # ((Should probably have an 'active' field))
308
265
  # Relationships
309
- bank = relationship("Bank", back_populates="credit_accounts")
310
- cards = relationship(
311
- "CreditCard",
312
- back_populates="account",
313
- cascade="all, delete",
266
+ bank: Mapped["Bank"] = relationship(back_populates="credit_accounts")
267
+ cards: Mapped[list["CreditCard"]] = relationship(
268
+ back_populates="account", cascade="all, delete"
314
269
  )
315
270
 
316
271
 
@@ -318,20 +273,14 @@ class CreditCard(AuthorizedAccessMixin, Model):
318
273
  __tablename__ = "credit_cards"
319
274
  _user_id_join_chain = (CreditAccount, Bank)
320
275
  # Columns
321
- id = mapped_column(Integer, primary_key=True)
322
- account_id = mapped_column(
323
- Integer,
324
- ForeignKey("credit_accounts.id"),
325
- nullable=False,
326
- )
327
- last_four_digits = mapped_column(String, nullable=False)
328
- active = mapped_column(Integer, nullable=False)
276
+ id: Mapped[int] = mapped_column(primary_key=True)
277
+ account_id: Mapped[int] = mapped_column(ForeignKey("credit_accounts.id"))
278
+ last_four_digits: Mapped[str]
279
+ active: Mapped[int]
329
280
  # Relationships
330
- account = relationship("CreditAccount", back_populates="cards")
331
- statements = relationship(
332
- "CreditStatementView",
333
- viewonly=True,
334
- back_populates="card",
281
+ account: Mapped["CreditAccount"] = relationship(back_populates="cards")
282
+ statement_views: Mapped[list["CreditStatementView"]] = relationship(
283
+ back_populates="card", viewonly=True
335
284
  )
336
285
 
337
286
 
@@ -339,16 +288,13 @@ class CreditStatement(AuthorizedAccessMixin, Model):
339
288
  __tablename__ = "credit_statements"
340
289
  _user_id_join_chain = (CreditCard, CreditAccount, Bank)
341
290
  # Columns
342
- id = mapped_column(Integer, primary_key=True)
343
- card_id = mapped_column(Integer, ForeignKey("credit_cards.id"), nullable=False)
344
- issue_date = mapped_column(Date, nullable=False)
345
- due_date = mapped_column(Date, nullable=False)
346
- # Relationship
347
- view = relationship(
348
- "CreditStatementView",
349
- viewonly=True,
350
- back_populates="statement",
351
- uselist=False,
291
+ id: Mapped[int] = mapped_column(primary_key=True)
292
+ card_id: Mapped[int] = mapped_column(ForeignKey("credit_cards.id"))
293
+ issue_date: Mapped[datetime.date]
294
+ due_date: Mapped[datetime.date]
295
+ # Relationships
296
+ view: Mapped["CreditStatementView"] = relationship(
297
+ back_populates="statement", uselist=False, viewonly=True
352
298
  )
353
299
 
354
300
 
@@ -356,20 +302,19 @@ class CreditStatementView(AuthorizedAccessMixin, Model):
356
302
  __tablename__ = "credit_statements_view"
357
303
  _user_id_join_chain = (CreditCard, CreditAccount, Bank)
358
304
  # Columns
359
- id = mapped_column(Integer, ForeignKey("credit_statements.id"), primary_key=True)
360
- card_id = mapped_column(Integer, ForeignKey("credit_cards.id"), nullable=False)
361
- issue_date = mapped_column(Date, nullable=False)
362
- due_date = mapped_column(Date, nullable=False)
363
- balance = mapped_column(Float, nullable=False)
364
- payment_date = mapped_column(Date)
305
+ id: Mapped[int] = mapped_column(
306
+ ForeignKey("credit_statements.id"), primary_key=True
307
+ )
308
+ card_id: Mapped[int] = mapped_column(ForeignKey("credit_cards.id"))
309
+ issue_date: Mapped[datetime.date]
310
+ due_date: Mapped[datetime.date]
311
+ balance: Mapped[float]
312
+ payment_date: Mapped[datetime.date]
365
313
  # Relationships
366
- statement = relationship(
367
- "CreditStatement",
368
- back_populates="view",
369
- )
370
- card = relationship("CreditCard", back_populates="statements")
371
- transactions = relationship(
372
- "CreditTransactionView", viewonly=True, back_populates="statement"
314
+ statement: Mapped["CreditStatement"] = relationship(back_populates="view")
315
+ card: Mapped["CreditCard"] = relationship(back_populates="statement_views")
316
+ transaction_views: Mapped[list["CreditTransactionView"]] = relationship(
317
+ back_populates="statement_view", viewonly=True
373
318
  )
374
319
 
375
320
 
@@ -379,24 +324,19 @@ class CreditTransaction(AuthorizedAccessMixin, Model):
379
324
  # Denote the transaction subtype
380
325
  subtype = "credit"
381
326
  # Columns
382
- id = mapped_column(Integer, primary_key=True)
383
- internal_transaction_id = mapped_column(
384
- Integer,
385
- ForeignKey("internal_transactions.id"),
386
- )
387
- statement_id = mapped_column(
388
- Integer,
389
- ForeignKey("credit_statements_view.id"),
390
- nullable=False,
391
- )
392
- transaction_date = mapped_column(Date, nullable=False)
393
- merchant = mapped_column(String, nullable=False)
327
+ id: Mapped[int] = mapped_column(primary_key=True)
328
+ internal_transaction_id: Mapped[int | None] = mapped_column(
329
+ ForeignKey("internal_transactions.id")
330
+ )
331
+ statement_id: Mapped[int] = mapped_column(ForeignKey("credit_statements_view.id"))
332
+ transaction_date: Mapped[datetime.date]
333
+ merchant: Mapped[str]
394
334
  # Relationships
395
- view = relationship(
396
- "CreditTransactionView",
397
- viewonly=True,
398
- back_populates="transaction",
399
- uselist=False,
335
+ view: Mapped["CreditTransactionView"] = relationship(
336
+ back_populates="transaction", uselist=False, viewonly=True
337
+ )
338
+ internal_transaction: Mapped["InternalTransaction"] = relationship(
339
+ back_populates="credit_transactions"
400
340
  )
401
341
 
402
342
 
@@ -406,42 +346,29 @@ class CreditTransactionView(AuthorizedAccessMixin, Model):
406
346
  # Denote the transaction subtype
407
347
  subtype = "credit"
408
348
  # Columns
409
- id = mapped_column(
410
- Integer,
411
- ForeignKey("credit_transactions.id"),
412
- primary_key=True,
413
- )
414
- internal_transaction_id = mapped_column(
415
- Integer,
416
- ForeignKey("internal_transactions.id"),
349
+ id: Mapped[int] = mapped_column(
350
+ ForeignKey("credit_transactions.id"), primary_key=True
417
351
  )
418
- statement_id = mapped_column(
419
- Integer,
420
- ForeignKey("credit_statements_view.id"),
421
- nullable=False,
352
+ internal_transaction_id: Mapped[int | None] = mapped_column(
353
+ ForeignKey("internal_transactions.id")
422
354
  )
423
- transaction_date = mapped_column(Date, nullable=False)
424
- merchant = mapped_column(String, nullable=False)
425
- total = mapped_column(Float, nullable=False)
426
- notes = mapped_column(String, nullable=False)
355
+ statement_id: Mapped[int] = mapped_column(ForeignKey("credit_statements_view.id"))
356
+ transaction_date: Mapped[datetime.date]
357
+ merchant: Mapped[str]
358
+ total: Mapped[float]
359
+ notes: Mapped[str]
427
360
  # Relationships
428
- transaction = relationship(
429
- "CreditTransaction",
430
- back_populates="view",
431
- uselist=False,
432
- )
433
- internal_transaction = relationship(
434
- "InternalTransaction", back_populates="credit_transactions"
435
- )
436
- statement = relationship(
437
- "CreditStatementView",
438
- viewonly=True,
439
- back_populates="transactions",
440
- )
441
- subtransactions = relationship(
442
- "CreditSubtransaction",
443
- back_populates="transaction",
444
- lazy="selectin",
361
+ transaction: Mapped["CreditTransaction"] = relationship(
362
+ back_populates="view", uselist=False
363
+ )
364
+ internal_transaction: Mapped["InternalTransaction"] = relationship(
365
+ back_populates="credit_transaction_views"
366
+ )
367
+ statement_view: Mapped["CreditStatementView"] = relationship(
368
+ back_populates="transaction_views", viewonly=True
369
+ )
370
+ subtransactions: Mapped[list["CreditSubtransaction"]] = relationship(
371
+ back_populates="transaction_view", lazy="selectin", cascade="all, delete"
445
372
  )
446
373
 
447
374
 
@@ -455,24 +382,19 @@ class CreditSubtransaction(AuthorizedAccessMixin, Model):
455
382
  Bank,
456
383
  )
457
384
  # Columns
458
- id = mapped_column(Integer, primary_key=True)
459
- transaction_id = mapped_column(
460
- Integer,
461
- ForeignKey("credit_transactions_view.id"),
462
- nullable=False,
463
- )
464
- subtotal = mapped_column(Float, nullable=False)
465
- note = mapped_column(String, nullable=False)
385
+ id: Mapped[int] = mapped_column(primary_key=True)
386
+ transaction_id: Mapped[int] = mapped_column(
387
+ ForeignKey("credit_transactions_view.id")
388
+ )
389
+ subtotal: Mapped[float]
390
+ note: Mapped[str]
466
391
  # Relationships
467
- transaction = relationship(
468
- "CreditTransactionView",
469
- viewonly=True,
470
- back_populates="subtransactions",
392
+ transaction_view: Mapped["CreditTransactionView"] = relationship(
393
+ back_populates="subtransactions", viewonly=True
471
394
  )
472
- tags = relationship(
473
- "TransactionTag",
474
- secondary=credit_tag_link_table,
395
+ tags: Mapped[list["TransactionTag"]] = relationship(
475
396
  back_populates="credit_subtransactions",
397
+ secondary=credit_tag_link_table,
476
398
  lazy="selectin",
477
399
  )
478
400
 
@@ -4,7 +4,12 @@ INSERT INTO users
4
4
  VALUES
5
5
  (0, 'global', 'n/a');
6
6
 
7
- /* Set some default account types (user_id=0 indicates the "global" user) */
7
+ /* Set a default transaction tag for credit payments */
8
+ INSERT INTO transaction_tags
9
+ (user_id, parent_id, tag_name)
10
+ VALUES (0, NULL, 'Credit payments');
11
+
12
+ /* Set some default account types */
8
13
  INSERT INTO bank_account_types
9
14
  (user_id, type_name, type_abbreviation)
10
15
  VALUES