monopyly 1.6.0__py3-none-any.whl → 1.6.2__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 (34) hide show
  1. monopyly/CHANGELOG.md +15 -0
  2. monopyly/_version.py +22 -4
  3. monopyly/banking/forms.py +4 -0
  4. monopyly/common/forms/_forms.py +5 -14
  5. monopyly/common/forms/fields.py +0 -9
  6. monopyly/common/forms/utils.py +3 -3
  7. monopyly/core/context_processors.py +3 -21
  8. monopyly/credit/cards.py +1 -1
  9. monopyly/credit/forms.py +6 -2
  10. monopyly/credit/transactions/activity/parser.py +1 -1
  11. monopyly/static/css/style.css +4 -0
  12. monopyly/static/js/bind-tag-actions.js +174 -86
  13. monopyly/static/js/highlight-discrepant-transactions.js +1 -0
  14. monopyly/templates/banking/account_form/account_form_page_new.html +10 -8
  15. monopyly/templates/banking/account_page.html +24 -24
  16. monopyly/templates/banking/accounts_page.html +8 -6
  17. monopyly/templates/common/tag_tree.html +4 -1
  18. monopyly/templates/common/tags_page.html +15 -13
  19. monopyly/templates/core/index.html +12 -8
  20. monopyly/templates/core/profile.html +18 -19
  21. monopyly/templates/credit/account_page.html +17 -17
  22. monopyly/templates/credit/card_form/card_form_page_new.html +8 -5
  23. monopyly/templates/credit/statement_page.html +43 -44
  24. monopyly/templates/credit/statement_reconciliation/statement_reconciliation_page.html +19 -19
  25. monopyly/templates/credit/statements_page.html +13 -13
  26. monopyly/templates/credit/transaction_form/transaction_form_page_update.html +9 -9
  27. monopyly/templates/credit/transactions_page.html +28 -28
  28. monopyly/templates/layout.html +7 -5
  29. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/METADATA +6 -6
  30. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/RECORD +34 -34
  31. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/WHEEL +1 -1
  32. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/entry_points.txt +0 -0
  33. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/licenses/COPYING +0 -0
  34. {monopyly-1.6.0.dist-info → monopyly-1.6.2.dist-info}/licenses/LICENSE +0 -0
monopyly/CHANGELOG.md CHANGED
@@ -237,4 +237,19 @@
237
237
  - Update JavaScript libraries (jQuery, Chartist)
238
238
 
239
239
 
240
+ ### 1.6.1
241
+
242
+ - Allow pie chart labels to overflow the SVG container
243
+ - Define JavaScript elements in header (deferring execution when logical)
244
+ - Bump dependencies
245
+
246
+
247
+ ### 1.6.2
248
+
249
+ - Fix bug in the transaction tag tree template preventing new subtags in the same subtag subtree
250
+ - Refactor JavaScript used to manage the transaction tag tree
251
+ - Add specificity to the reconciliation tool when parsing payment columns (when otherwise unidentified, payment transactions are determined by the presence of the isolated word "payment" in the description field)
252
+ - Bump dependencies
253
+
254
+
240
255
  <a name="bottom" id="bottom"></a>
monopyly/_version.py CHANGED
@@ -1,16 +1,34 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
3
13
  TYPE_CHECKING = False
4
14
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
15
+ from typing import Tuple
16
+ from typing import Union
17
+
6
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
7
20
  else:
8
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
9
23
 
10
24
  version: str
11
25
  __version__: str
12
26
  __version_tuple__: VERSION_TUPLE
13
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '1.6.2'
32
+ __version_tuple__ = version_tuple = (1, 6, 2)
14
33
 
15
- __version__ = version = '1.6.0'
16
- __version_tuple__ = version_tuple = (1, 6, 0)
34
+ __commit_id__ = commit_id = None
monopyly/banking/forms.py CHANGED
@@ -115,6 +115,10 @@ class BankAccountForm(EntryForm):
115
115
  }
116
116
  return account_type_data
117
117
 
118
+ def gather_entry_data(self, entry):
119
+ """Gather data for the form from the given database entry."""
120
+ raise NotImplementedError
121
+
118
122
  # Fields to identify the bank/account type information for the account
119
123
  bank_info = FormField(BankSubform)
120
124
  account_type_info = FormField(AccountTypeSubform)
@@ -2,10 +2,10 @@
2
2
  General form constructions.
3
3
  """
4
4
 
5
- from abc import ABC, abstractmethod
5
+ from abc import abstractmethod
6
6
  from datetime import date
7
7
 
8
- from flask_wtf import FlaskForm
8
+ from dry_foundation.forms import AbstractFlaskForm, FlaskSubform
9
9
  from wtforms.fields import StringField, SubmitField
10
10
  from wtforms.validators import DataRequired
11
11
 
@@ -15,12 +15,7 @@ from .fields import CurrencyField, DateField
15
15
  form_err_msg = "There was an improper value in your form. Please try again."
16
16
 
17
17
 
18
- class AbstractEntryFormMixinMeta(type(FlaskForm), ABC):
19
- # Defined to allow the forms to also to be abstract base classes
20
- pass
21
-
22
-
23
- class EntryForm(FlaskForm, metaclass=AbstractEntryFormMixinMeta):
18
+ class EntryForm(AbstractFlaskForm):
24
19
  """
25
20
  A form designed to accept database entry information.
26
21
 
@@ -85,11 +80,8 @@ class EntryForm(FlaskForm, metaclass=AbstractEntryFormMixinMeta):
85
80
  )
86
81
 
87
82
 
88
- class EntrySubform(EntryForm):
89
- """Subform disabling CSRF (CSRF is REQUIRED in encapsulating form)."""
90
-
91
- def __init__(self, *args, **kwargs):
92
- super().__init__(meta={"csrf": False}, *args, **kwargs)
83
+ class EntrySubform(FlaskSubform, EntryForm):
84
+ """A subform implementing ``EntryForm`` behavior."""
93
85
 
94
86
 
95
87
  class AcquisitionSubform(EntrySubform):
@@ -149,7 +141,6 @@ class TransactionForm(EntryForm):
149
141
  }
150
142
  return data
151
143
 
152
- @abstractmethod
153
144
  def gather_entry_data(self, entry):
154
145
  if self.subtransaction_model is None:
155
146
  raise RuntimeError(
@@ -24,15 +24,6 @@ class DateField(wtforms_fields.DateField):
24
24
  super().__init__(*args, filters=filters, **kwargs)
25
25
 
26
26
 
27
- class OptionalDateField(DateField):
28
- """A date field where the field value is optional."""
29
-
30
- def process_formdata(self, valuelist):
31
- """Process data from the form, ignoring an ommitted value."""
32
- if valuelist != [""]:
33
- super().process_formdata(valuelist)
34
-
35
-
36
27
  class CurrencyField(wtforms_fields.DecimalField):
37
28
  """A decimal field with currency-specific customizations."""
38
29
 
@@ -113,9 +113,9 @@ def extend_field_list_for_ajax(form_class, field_list_name, field_list_count):
113
113
 
114
114
  Parameters
115
115
  ----------
116
- form_class : flask_wtf.FlaskForm
117
- The class (not class instance) containing the field list to be
118
- extended.
116
+ form_class : type
117
+ The form class (not class instance) containing the field list to
118
+ be extended.
119
119
  field_list_name : str
120
120
  The name of the field list to be extended.
121
121
  field_list_count : int
@@ -2,8 +2,7 @@
2
2
  Filters defined for the application.
3
3
  """
4
4
 
5
- from datetime import date
6
- from importlib import import_module
5
+ from dry_foundation.utils import define_basic_template_global_variables
7
6
 
8
7
  from .actions import determine_summary_balance_svg_viewbox_width
9
8
  from .blueprint import bp
@@ -11,13 +10,8 @@ from .blueprint import bp
11
10
 
12
11
  @bp.app_context_processor
13
12
  def inject_global_template_variables():
14
- """Inject template variablees globally into the template context."""
15
- template_globals = {
16
- "app_version": _display_version(),
17
- "copyright_statement": f"© {date.today().year}",
18
- "date_today": date.today(),
19
- }
20
- return template_globals
13
+ """Inject template variables globally into the template context."""
14
+ return define_basic_template_global_variables("monopyly._version")
21
15
 
22
16
 
23
17
  @bp.app_context_processor
@@ -27,15 +21,3 @@ def inject_utility_functions():
27
21
  "calculate_summary_balance_width": determine_summary_balance_svg_viewbox_width,
28
22
  }
29
23
  return utility_functions
30
-
31
-
32
- def _display_version():
33
- """Show the version (without commit information)."""
34
- try:
35
- version = import_module("monopyly._version").version
36
- except ModuleNotFoundError:
37
- # Fallback action in case Hatch VCS fails
38
- display_version = ""
39
- else:
40
- display_version = version.split("+")[0]
41
- return display_version
monopyly/credit/cards.py CHANGED
@@ -137,7 +137,7 @@ def save_card(form, card_id=None):
137
137
 
138
138
  Parameters
139
139
  ----------
140
- form : flask_wtf.FlaskForm
140
+ form : CreditCardForm
141
141
  The form beign used to provide the data being saved.
142
142
  card_id : int
143
143
  The ID of hte card to be saved. If provided, the named card will
monopyly/credit/forms.py CHANGED
@@ -5,6 +5,7 @@ Generate credit card forms for the user to complete.
5
5
  from flask import abort
6
6
  from wtforms.fields import (
7
7
  BooleanField,
8
+ DateField,
8
9
  FieldList,
9
10
  FormField,
10
11
  IntegerField,
@@ -18,7 +19,6 @@ from ..common.forms import AcquisitionSubform, EntryForm, EntrySubform, Transact
18
19
  from ..common.forms.fields import (
19
20
  CustomChoiceSelectField,
20
21
  LastFourDigitsField,
21
- OptionalDateField,
22
22
  StringField,
23
23
  )
24
24
  from ..common.forms.utils import Autocompleter
@@ -152,6 +152,10 @@ class CardStatementTransferForm(EntryForm):
152
152
  transfer = RadioField("transfer", choices=[("yes", "Yes"), ("no", "No")])
153
153
  submit = SubmitField("Continue")
154
154
 
155
+ def gather_entry_data(self, entry):
156
+ """Gather data for the form from the given database entry."""
157
+ raise NotImplementedError
158
+
155
159
 
156
160
  class CreditTransactionForm(TransactionForm):
157
161
  """Form to input/edit credit card transactions."""
@@ -193,7 +197,7 @@ class CreditTransactionForm(TransactionForm):
193
197
  # Fields to identify the card/bank information for the statement
194
198
  card_info = FormField(CardSubform)
195
199
  # Fields pertaining to the statement
196
- issue_date = OptionalDateField("Statement Date")
200
+ issue_date = DateField("Statement Date", [Optional()])
197
201
 
198
202
  def get_statement(self, transaction_date):
199
203
  """Get the credit card statement described by the form data."""
@@ -213,7 +213,7 @@ class _TransactionActivityParser:
213
213
  def _infer_payment_row(row):
214
214
  # Infer whether the row constitutes a payment transaction
215
215
  contextual_info = [row[i].lower() for i in contextual_column_indices]
216
- return any("payment" in element for element in contextual_info)
216
+ return any("payment" in element.split() for element in contextual_info)
217
217
 
218
218
  payment_rows = list(filter(_infer_payment_row, raw_data))
219
219
  return self._extrapolate_payments_positive(payment_rows, raw_data)
@@ -3481,6 +3481,10 @@ form#pay #make-payment[type="submit"] #prompt {
3481
3481
  min-height: 400px;
3482
3482
  }
3483
3483
 
3484
+ #category-chart.ct-chart svg {
3485
+ overflow: visible;
3486
+ }
3487
+
3484
3488
  #category-chart text.ct-label {
3485
3489
  transition: fill 0.1s ease;
3486
3490
  }
@@ -13,111 +13,199 @@ import { executeAjaxRequest } from './modules/ajax.js';
13
13
 
14
14
 
15
15
  (function() {
16
-
17
- const endpointAddTag = ADD_TAG_ENDPOINT;
18
- const endpointRemoveTag = REMOVE_TAG_ENDPOINT;
19
- // Set animation parameters
20
- const slideTime = 300;
21
16
  // Identify the buttons
22
- const $buttonsAddTag = $('#transaction-tags .new-tag.button');
23
- const $buttonsDelete = $('#transaction-tags .action.button.delete');
24
-
25
- bindTagCreator($buttonsAddTag, $buttonsDelete);
26
-
27
- function bindTagCreator($buttonsAddTag, $buttonsDelete) {
28
- // Bind add tag buttons
29
- $buttonsAddTag.on('click', function() {
30
- const $container = $(this).closest('.tag-container');
31
- const $tags = $container.children('ul.tags');
32
- const $input = $tags.children('input.new-tag');
33
- // Reveal the input
34
- showInput($input);
35
- // Perform actions when focus is lost
36
- $input.on('blur', function() {
37
- if ($input.val()) {
38
- addNewTag($input, $container);
39
- } else {
40
- hideEmptyInput($input);
41
- }
42
- clearInput($input);
43
- });
44
- $input.on('keydown', function() {
45
- if (event.which == 27) {
46
- clearInput($input);
47
- hideEmptyInput($input);
48
- }
49
- });
17
+ const $createTagButtons = $('#transaction-tags .new-tag.button');
18
+ const $deleteTagButtons = $('#transaction-tags .action.button.delete');
19
+ bindTagButtonBehavior($createTagButtons, $deleteTagButtons);
20
+
21
+ })();
22
+
23
+
24
+ /**
25
+ * Create the tag manager.
26
+ *
27
+ * @param {JQuery} $createTagButtons - Buttons for adding subtags to one or
28
+ * more tags.
29
+ * @param {JQuery} $deleteTagButtons - Buttons for removing tags.
30
+ */
31
+ function bindTagButtonBehavior($createTagButtons, $deleteTagButtons) {
32
+ console.log('bind create buttons', $createTagButtons);
33
+ console.log('bind delete buttons', $deleteTagButtons);
34
+ $createTagButtons.on('click', function() {
35
+ const $button = $(this);
36
+ const behavior = new TagCreation($button);
37
+ behavior.perform();
38
+ });
39
+ $deleteTagButtons.on('click', function() {
40
+ const $button = $(this);
41
+ const behavior = new TagDeletion($button);
42
+ behavior.perform();
43
+ });
44
+ }
45
+
46
+
47
+ /**
48
+ * A class for managing transaction tags and the behavior of their buttons.
49
+ */
50
+ class TagButtonBehavior {
51
+
52
+ /**
53
+ * Create the tag manager.
54
+ *
55
+ * @param {JQuery} $button - A button belonging to a tag.
56
+ */
57
+ constructor($button) {
58
+ this.$container = $button.closest('.tag-container');
59
+ this.$tag = this.$container.children('.tag-area').find('.tag');
60
+ this.$tags = this.$container.children('ul.tags');
61
+ this.$input = this.$tags.children('input.new-tag');
62
+ // Set animation parameters
63
+ this.slideTime = 300;
64
+ }
65
+
66
+ }
67
+
68
+ /**
69
+ * A class for managing transaction tags creation behavior.
70
+ */
71
+ class TagCreation extends TagButtonBehavior {
72
+
73
+ #endpoint = ADD_TAG_ENDPOINT;
74
+
75
+ /**
76
+ * Create the tag creator.
77
+ *
78
+ * @param {JQuery} $button - A button belonging to a tag.
79
+ */
80
+ constructor($button) {
81
+ super($button);
82
+ self = this;
83
+ this.$input.on('blur', function() {
84
+ self.#dropInputFocus();
50
85
  });
51
- // Bind remove tag buttons
52
- $buttonsDelete.on('click', function() {
53
- if (confirmDelete()) {
54
- const $container = $(this).closest('.tag-container');
55
- const $tag = $container.find('.tag').first();
56
- // Remove the tag from the database
57
- removeTag($tag);
58
- // Remove the tag from the display
59
- const $tagContainer = $tag.closest('.tag-area');
60
- $tagContainer.slideUp(300, function() {
61
- $(this).remove()
62
- });
86
+ this.$input.on('keydown', function() {
87
+ if (event.key == 'Escape') {
88
+ self.#clearInput();
89
+ this.blur();
90
+ } else if (event.key == 'Enter') {
91
+ this.blur();
63
92
  }
64
93
  });
65
94
  }
66
95
 
67
- function addNewTag($input, $container) {
68
- // Add the input value to the database as a tag
69
- const parentTag = $container.children('.tag-area').find('.tag').text()
96
+ /**
97
+ * Perform the behavior.
98
+ */
99
+ perform() {
100
+ this.#showInput();
101
+ }
102
+
103
+ /**
104
+ * Show the input box to collect new tag information.
105
+ */
106
+ #showInput() {
107
+ console.log('showing input', this.$input);
108
+ self = this;
109
+ this.$input.slideDown(this.slideTime, function() {
110
+ self.$input.addClass('visible');
111
+ self.$input.focus();
112
+ console.log('focus', self.$input);
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Perform a specific action when the input loses focus.
118
+ */
119
+ #dropInputFocus() {
120
+ if (this.$input.val()) {
121
+ this.#createTag();
122
+ this.#hideFilledInput();
123
+ } else {
124
+ this.#hideEmptyInput();
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Create the new tag in the database.
130
+ */
131
+ #createTag() {
70
132
  const rawData = {
71
- 'tag_name': $input.val(),
72
- 'parent': parentTag
133
+ 'tag_name': this.$input.val(),
134
+ 'parent': this.$tag.text()
73
135
  };
74
- // Execute the AJAX request and display update
75
- function addTag(response) {
76
- // Add the AJAX request response to the DOM before the input
77
- $input.before(response);
78
- hideFilledInput($input);
79
- // Bind the buttons for the newly added tag
80
- const $buttonAddTag = $input.prev().find('.new-tag.button');
81
- const $buttonRemoveTag = $input.prev().find('.action.button.delete');
82
- bindTagCreator($buttonAddTag, $buttonRemoveTag);
83
- }
84
- executeAjaxRequest(endpointAddTag, rawData, addTag);
136
+ // Execute the AJAX request and place the new tag
137
+ executeAjaxRequest(this.#endpoint, rawData, this.#placeNewTag.bind(this));
85
138
  }
86
139
 
87
- function showInput($input) {
88
- $input.slideDown(slideTime, function() {
89
- $input.addClass('visible');
90
- $input.focus();
91
- });
140
+ /**
141
+ * Add the new tag to the DOM before the input.
142
+ */
143
+ #placeNewTag(newTagHTML) {
144
+ const $newTag = $(newTagHTML);
145
+ this.$input.before($newTag);
146
+ // Bind behavior functionality to the newly created/placed tag buttons
147
+ bindTagButtonBehavior(
148
+ $newTag.find('.new-tag.button'), $newTag.find('.action.button.delete')
149
+ );
92
150
  }
93
151
 
94
- function hideFilledInput($input) {
95
- // Hide the input immediately
96
- $input.hide();
97
- $input.removeClass('visible');
152
+ /**
153
+ * Hide the input immediately.
154
+ */
155
+ #hideFilledInput() {
156
+ this.$input.hide();
157
+ this.$input.removeClass('visible');
158
+ this.#clearInput();
98
159
  }
99
160
 
100
- function hideEmptyInput($input) {
101
- // Hide the input gracefully
102
- $input.removeClass('visible');
103
- $input.slideUp(slideTime);
161
+ /**
162
+ * Hide the (empty) input gracefully.
163
+ */
164
+ #hideEmptyInput() {
165
+ this.$input.removeClass('visible');
166
+ this.$input.slideUp(this.slideTime);
167
+ console.log('hiding empty input', this.$input);
104
168
  }
105
169
 
106
- function clearInput($input) {
107
- // Clear the input
108
- $input.val('');
170
+ /**
171
+ * Clear the input.
172
+ */
173
+ #clearInput() {
174
+ this.$input.val('');
109
175
  }
110
176
 
111
- function confirmDelete() {
112
- return confirm('Are you sure you want to delete this tag?');
177
+ }
178
+
179
+
180
+ /**
181
+ * A class for managing transaction tags deletion behavior.
182
+ */
183
+ class TagDeletion extends TagButtonBehavior {
184
+
185
+ #endpoint = REMOVE_TAG_ENDPOINT;
186
+
187
+ /**
188
+ * Perform the behavior.
189
+ */
190
+ perform() {
191
+ if (this.#confirmDelete()) {
192
+ this.#removeTag();
193
+ }
113
194
  }
114
195
 
115
- function removeTag($tag) {
116
- // Get the name of the tag
117
- const tagName = $tag.html();
118
- const rawData = {'tag_name': tagName};
119
- // Execute the AJAX request
120
- executeAjaxRequest(endpointRemoveTag, rawData);
196
+ /**
197
+ * Remove the tag from the database.
198
+ */
199
+ #removeTag() {
200
+ const rawData = {'tag_name': this.$tag.html()};
201
+ // Execute the AJAX request to delete the tag
202
+ executeAjaxRequest(this.#endpoint, rawData);
203
+ // Remove the tag from the display
204
+ this.$container.slideUp(this.slideTime, function() {this.remove()});
121
205
  }
122
206
 
123
- })();
207
+ #confirmDelete() {
208
+ return confirm('Are you sure you want to delete this tag?');
209
+ }
210
+
211
+ }
@@ -114,6 +114,7 @@ class DiscrepancyHighlighter {
114
114
  this.removeHighlight($(activity), $matchingTransactionRow);
115
115
  }
116
116
  }
117
+
117
118
  }
118
119
 
119
120
 
@@ -1,6 +1,16 @@
1
1
  {% extends "common/form_page.html" %}
2
2
 
3
3
 
4
+ {% block javascript %}
5
+
6
+ <script type="module" src="{{ url_for('static', filename='js/display-new-bank-inputs.js') }}">
7
+ </script>
8
+ <script type="module" src="{{ url_for('static', filename='js/display-new-account-type-inputs.js') }}">
9
+ </script>
10
+
11
+ {% endblock %}
12
+
13
+
4
14
  {% block title %}
5
15
  New Bank Account
6
16
  {% endblock %}
@@ -13,11 +23,3 @@
13
23
  {% endwith %}
14
24
 
15
25
  {% endblock %}
16
-
17
-
18
- {% block javascript %}
19
- <script type="module" src="{{ url_for('static', filename='js/display-new-bank-inputs.js') }}">
20
- </script>
21
- <script type="module" src="{{ url_for('static', filename='js/display-new-account-type-inputs.js') }}">
22
- </script>
23
- {% endblock %}
@@ -1,6 +1,30 @@
1
1
  {% extends 'layout.html' %}
2
2
 
3
3
 
4
+ {% block javascript %}
5
+
6
+ <script>
7
+ const EXPAND_TRANSACTION_ENDPOINT = "{{ url_for('banking.expand_transaction') }}";
8
+ const LINKED_TRANSACTION_ENDPOINT = "{{ url_for('banking.show_linked_transaction') }}";
9
+ const LOAD_TRANSACTIONS_ENDPOINT = "{{ url_for('banking.load_more_transactions') }}";
10
+ const LOAD_TRANSACTIONS_SELECTORS = {
11
+ "account_id": {{ account.id }},
12
+ "block_count": 1
13
+ };
14
+ const BALANCE_CHART_DATA = {{ chart_data|tojson }};
15
+ </script>
16
+ <script type="module" src="{{ url_for('static', filename='js/load-more-transactions.js') }}">
17
+ </script>
18
+ <script type="module" src="{{ url_for('static', filename='js/expand-transaction.js') }}">
19
+ </script>
20
+ <script type="module" src="{{ url_for('static', filename='js/show-linked-transaction.js') }}">
21
+ </script>
22
+ <script type="module" src="{{ url_for('static', filename='js/create-balance-chart.js') }}">
23
+ </script>
24
+
25
+ {% endblock %}
26
+
27
+
4
28
  {% block header %}
5
29
 
6
30
  <h1>
@@ -57,27 +81,3 @@
57
81
  </div>
58
82
 
59
83
  {% endblock %}
60
-
61
-
62
- {% block javascript %}
63
-
64
- <script>
65
- const EXPAND_TRANSACTION_ENDPOINT = "{{ url_for('banking.expand_transaction') }}";
66
- const LINKED_TRANSACTION_ENDPOINT = "{{ url_for('banking.show_linked_transaction') }}";
67
- const LOAD_TRANSACTIONS_ENDPOINT = "{{ url_for('banking.load_more_transactions') }}";
68
- const LOAD_TRANSACTIONS_SELECTORS = {
69
- "account_id": {{ account.id }},
70
- "block_count": 1
71
- };
72
- const BALANCE_CHART_DATA = {{ chart_data|tojson }};
73
- </script>
74
- <script type="module" src="{{ url_for('static', filename='js/load-more-transactions.js') }}">
75
- </script>
76
- <script type="module" src="{{ url_for('static', filename='js/expand-transaction.js') }}">
77
- </script>
78
- <script type="module" src="{{ url_for('static', filename='js/show-linked-transaction.js') }}">
79
- </script>
80
- <script type="module" src="{{ url_for('static', filename='js/create-balance-chart.js') }}">
81
- </script>
82
-
83
- {% endblock %}
@@ -1,6 +1,14 @@
1
1
  {% extends 'layout.html' %}
2
2
 
3
3
 
4
+ {% block javascript %}
5
+
6
+ <script type="module" src="{{ url_for('static', filename='js/expand-bank-account.js') }}">
7
+ </script>
8
+
9
+ {% endblock %}
10
+
11
+
4
12
  {% block header %}
5
13
 
6
14
  <h1>
@@ -83,9 +91,3 @@
83
91
  </div>
84
92
 
85
93
  {% endblock %}
86
-
87
-
88
- {% block javascript %}
89
- <script type="module" src="{{ url_for('static', filename='js/expand-bank-account.js') }}">
90
- </script>
91
- {% endblock %}