monopyly 1.4.8__py3-none-any.whl → 1.5.1__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 (77) hide show
  1. monopyly/CHANGELOG.md +18 -0
  2. monopyly/__init__.py +2 -2
  3. monopyly/_version.py +14 -2
  4. monopyly/auth/actions.py +12 -0
  5. monopyly/auth/routes.py +30 -21
  6. monopyly/auth/tools.py +1 -2
  7. monopyly/cli/apps.py +1 -1
  8. monopyly/cli/launch.py +3 -0
  9. monopyly/common/forms/_forms.py +56 -2
  10. monopyly/common/forms/utils.py +1 -2
  11. monopyly/common/transactions.py +162 -0
  12. monopyly/core/routes.py +0 -6
  13. monopyly/credit/actions.py +29 -0
  14. monopyly/credit/forms.py +25 -0
  15. monopyly/credit/routes.py +115 -7
  16. monopyly/credit/transactions/_transactions.py +15 -0
  17. monopyly/credit/transactions/activity/__init__.py +3 -0
  18. monopyly/credit/transactions/activity/data.py +161 -0
  19. monopyly/credit/transactions/activity/parser.py +282 -0
  20. monopyly/credit/transactions/activity/reconciliation.py +456 -0
  21. monopyly/database/models.py +6 -0
  22. monopyly/static/css/style.css +1328 -270
  23. monopyly/static/img/icons/statement-pair.png +0 -0
  24. monopyly/static/img/icons/statement-thick.png +0 -0
  25. monopyly/static/img/icons/statement.png +0 -0
  26. monopyly/static/js/bind-tag-actions.js +1 -1
  27. monopyly/static/js/create-balance-chart.js +1 -1
  28. monopyly/static/js/create-category-chart.js +27 -0
  29. monopyly/static/js/define-filter.js +1 -1
  30. monopyly/static/js/expand-transaction.js +10 -0
  31. monopyly/static/js/highlight-discrepant-transactions.js +124 -0
  32. monopyly/static/js/modules/expand-transaction.js +12 -3
  33. monopyly/static/js/modules/form-suggestions.js +60 -0
  34. monopyly/static/js/modules/manage-overlays.js +1 -3
  35. monopyly/static/js/show-credit-activity-loader.js +29 -0
  36. monopyly/static/js/toggle-navigation.js +35 -0
  37. monopyly/static/js/update-card-status.js +1 -1
  38. monopyly/static/js/use-suggested-amount.js +11 -0
  39. monopyly/static/js/use-suggested-merchant.js +11 -0
  40. monopyly/templates/auth/change_password.html +21 -0
  41. monopyly/templates/auth/login.html +3 -1
  42. monopyly/templates/auth/register.html +17 -7
  43. monopyly/templates/banking/account_page.html +3 -1
  44. monopyly/templates/banking/account_summaries.html +1 -1
  45. monopyly/templates/banking/accounts_page.html +11 -15
  46. monopyly/templates/banking/transactions_table/expanded_row_content.html +18 -20
  47. monopyly/templates/common/transaction_form/subtransaction_subform.html +10 -1
  48. monopyly/templates/common/transactions_table/linked_bank_transaction.html +1 -1
  49. monopyly/templates/common/transactions_table/linked_credit_transaction.html +1 -1
  50. monopyly/templates/common/transactions_table/transaction_condensed.html +2 -2
  51. monopyly/templates/common/transactions_table/transaction_expanded.html +3 -3
  52. monopyly/templates/common/transactions_table/transactions.html +1 -1
  53. monopyly/templates/core/credits.html +10 -8
  54. monopyly/templates/core/index.html +10 -0
  55. monopyly/templates/core/profile.html +3 -3
  56. monopyly/templates/credit/statement_page.html +33 -0
  57. monopyly/templates/credit/statement_reconciliation/discrepant_records.html +25 -0
  58. monopyly/templates/credit/statement_reconciliation/statement_reconciliation_inquiry.html +23 -0
  59. monopyly/templates/credit/statement_reconciliation/statement_reconciliation_page.html +86 -0
  60. monopyly/templates/credit/statement_reconciliation/summary.html +45 -0
  61. monopyly/templates/credit/statement_reconciliation/unrecorded_activities.html +24 -0
  62. monopyly/templates/credit/statement_summary.html +2 -2
  63. monopyly/templates/credit/statements.html +1 -1
  64. monopyly/templates/credit/transaction_form/transaction_form.html +9 -1
  65. monopyly/templates/credit/transaction_form/transaction_form_page.html +2 -0
  66. monopyly/templates/credit/transaction_form/transaction_form_page_update.html +9 -0
  67. monopyly/templates/credit/transaction_submission_page.html +64 -63
  68. monopyly/templates/credit/transactions_table/expanded_row_content.html +18 -12
  69. monopyly/templates/layout.html +37 -29
  70. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/METADATA +8 -7
  71. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/RECORD +75 -58
  72. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/WHEEL +1 -1
  73. monopyly/static/img/icons/statement-pair.svg +0 -281
  74. monopyly/static/img/icons/statement.svg +0 -294
  75. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/entry_points.txt +0 -0
  76. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/licenses/COPYING +0 -0
  77. {monopyly-1.4.8.dist-info → monopyly-1.5.1.dist-info}/licenses/LICENSE +0 -0
Binary file
@@ -43,7 +43,7 @@ import { executeAjaxRequest } from './modules/ajax.js';
43
43
  });
44
44
  });
45
45
  // Bind remove tag buttons
46
- $buttonsDelete.on('click', function () {
46
+ $buttonsDelete.on('click', function() {
47
47
  if (confirmDelete()) {
48
48
  const $container = $(this).closest('.tag-container');
49
49
  const $tag = $container.find('.tag').first();
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Prepare a chart using the `chartist.js` library.
2
+ * Prepare a line graph of balances using the `chartist.js` library.
3
3
  *
4
4
  * Creates a chart using data (provided in the HTML template) for bank
5
5
  * balances over time. Data (x, y) pairs are passed in as timestamps
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Prepare a donut chart of category subtotals using the `chartist.js` library.
3
+ *
4
+ * Creates a donut chart using data (provided in the HTML template) for
5
+ * transaction categories based on their subtotals.
6
+ */
7
+
8
+
9
+ function createCategoryChart(data) {
10
+
11
+ const options = {
12
+ donut: true,
13
+ donutWidth: 40,
14
+ chartPadding: 40,
15
+ labelOffset: 50,
16
+ labelDirection: "explode"
17
+ };
18
+ new Chartist.Pie("#category-chart", data, options);
19
+
20
+ }
21
+
22
+
23
+ (function() {
24
+
25
+ createCategoryChart(CATEGORY_CHART_DATA);
26
+
27
+ })();
@@ -17,7 +17,7 @@
17
17
  let defaultText;
18
18
  inactiveCardFilters.hover(
19
19
  // Change text when hovering over the filter
20
- function () {
20
+ function() {
21
21
  const $this = $(this);
22
22
  const defaultWidth = $this.width();
23
23
  defaultText = $this.text();
@@ -15,4 +15,14 @@ import {
15
15
 
16
16
  (function() {
17
17
  const toggleManager = new TransactionToggleManager(displaySubtransactions)
18
+ // For mobile layouts, expand transactions when the row is clicked
19
+ if (window.innerWidth <= 600) {
20
+ const $transactions = $('.transaction');
21
+ $transactions.on('click', function(event) {
22
+ if (!this.classList.contains('selected')) {
23
+ const $transactionExpandButton = $(this).find('.more.button');
24
+ $transactionExpandButton.trigger('click');
25
+ }
26
+ });
27
+ }
18
28
  })();
@@ -0,0 +1,124 @@
1
+ /*
2
+ * Highlight transactions with discrepancies on the reconcilation page.
3
+ */
4
+
5
+
6
+ /**
7
+ * A class for highlighting transaction/activity discrepancies.
8
+ */
9
+ class DiscrepancyHighlighter {
10
+
11
+ /**
12
+ * Create the highlighter.
13
+ */
14
+ constructor() {
15
+ const highlighter = this;
16
+ this.$transactionContainer = $("#statement-transactions-container");
17
+ const $transactions = this.$transactionContainer.find(".transaction");
18
+ this.$transactionRows = $transactions.find(".condensed .row-content");
19
+ this.$discrepantActivities = $(".discrepant-activity");
20
+ // Toggle highlighting based on clicking
21
+ this.clickedTransactionID = null;
22
+ this.$discrepantActivities.on("click", function() {
23
+ highlighter.toggleClickTransactionHighlight(this);
24
+ });
25
+ // Toggle highlighting based on hovering
26
+ this.$discrepantActivities.hover(
27
+ function() {highlighter.addHoverTransactionHighlight(this)},
28
+ function() {highlighter.removeHoverTransactionHighlight(this)},
29
+ )
30
+ // Remove highlighting if anywhere else on the page is clicked
31
+ $(document).on("click", function(event) {
32
+ const $target = $(event.target);
33
+ if (highlighter.#isExtraneousClick($target)) {
34
+ highlighter.removeHighlight(
35
+ highlighter.$discrepantActivities, highlighter.$transactionRows
36
+ );
37
+ }
38
+ });
39
+ }
40
+
41
+ #isExtraneousClick($target) {
42
+ const isNotDiscrepantActivity = (
43
+ $target.closest(this.$discrepantActivities).length == 0
44
+ );
45
+ const isNotTransactionContainer = (
46
+ $target.closest(this.$transactionContainer).length == 0
47
+ );
48
+ return isNotDiscrepantActivity && isNotTransactionContainer;
49
+ }
50
+
51
+ /**
52
+ * Get the transaction (row) from the container with matching transaction ID.
53
+ *
54
+ * @param {object} activity - The activity object to match.
55
+ */
56
+ getMatchingTransactionRow(activity) {
57
+ const transactionID = activity.dataset.transactionId;
58
+ const selector = `.transaction[data-transaction-id='${transactionID}']`;
59
+ return this.$transactionContainer.find(selector).find(".condensed .row-content");
60
+ }
61
+
62
+ addHighlight($activities, $transactionRows) {
63
+ $activities.addClass("discrepancy-highlight");
64
+ $transactionRows.addClass("discrepancy-highlight");
65
+ }
66
+
67
+ removeHighlight($activities, $transactionRows) {
68
+ $activities.removeClass("discrepancy-highlight");
69
+ $transactionRows.removeClass("discrepancy-highlight");
70
+ this.clickedTransactionID = null;
71
+ }
72
+
73
+ /**
74
+ * Add highlighting to a transaction.
75
+ *
76
+ * @param {object} activity - The activity to highlight.
77
+ */
78
+ toggleClickTransactionHighlight(activity) {
79
+ const $matchingTransactionRow = this.getMatchingTransactionRow(activity);
80
+ const transactionID = activity.dataset.transactionId;
81
+ if (transactionID != this.clickedTransactionID) {
82
+ // Remove highlighting from all other transactions and add it to this one
83
+ this.removeHighlight(this.$discrepantActivities, this.$transactionRows);
84
+ this.addHighlight($(activity), $matchingTransactionRow);
85
+ // Update the tracker to indicate that an activity was clicked
86
+ this.clickedTransactionID = transactionID;
87
+ } else {
88
+ this.removeHighlight($(activity), $matchingTransactionRow);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Add highlighting to a transaction.
94
+ *
95
+ * @param {object} activity - The activity to highlight.
96
+ */
97
+ addHoverTransactionHighlight(activity) {
98
+ // Only add hover highlighting if a transaction has not been clicked
99
+ if (this.clickedTransactionID == null) {
100
+ const $matchingTransactionRow = this.getMatchingTransactionRow(activity);
101
+ this.addHighlight($(activity), $matchingTransactionRow);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Remove highlighting from a transaction.
107
+ *
108
+ * @param {object} activity - The activity to stop highlighting.
109
+ */
110
+ removeHoverTransactionHighlight(activity) {
111
+ // Only remove hover highlighting if a transaction has not been clicked
112
+ if (this.clickedTransactionID == null) {
113
+ const $matchingTransactionRow = this.getMatchingTransactionRow(activity);
114
+ this.removeHighlight($(activity), $matchingTransactionRow);
115
+ }
116
+ }
117
+ }
118
+
119
+
120
+ (function() {
121
+
122
+ const highlighter = new DiscrepancyHighlighter();
123
+
124
+ })();
@@ -37,19 +37,25 @@ class TransactionToggleManager {
37
37
 
38
38
  #registerClickExpand(callback) {
39
39
  const self = this;
40
- this.$iconsMoreInfoButtons.on('click', function() {
40
+ this.$iconsMoreInfoButtons.on('click', function(event) {
41
41
  const $transaction = self.getButtonTransaction(this);
42
42
  const toggler = new TransactionToggler($transaction);
43
43
  toggler.expand(callback);
44
+ // Do not propagate any additional events up the DOM tree
45
+ // (this avoids recursion in mobile mode when parents are tapped)
46
+ event.stopPropagation();
44
47
  });
45
48
  }
46
49
 
47
50
  #registerClickCollapse() {
48
51
  const self = this;
49
- this.$iconsLessInfoButtons.on('click', function() {
52
+ this.$iconsLessInfoButtons.on('click', function(event) {
50
53
  const $transaction = self.getButtonTransaction(this);
51
54
  const toggler = new TransactionToggler($transaction);
52
55
  toggler.collapse();
56
+ // Do not propagate any additional events up the DOM tree
57
+ // (this avoids recursion in mobile mode when parents are tapped)
58
+ event.stopPropagation();
53
59
  });
54
60
  }
55
61
  }
@@ -88,7 +94,10 @@ class TransactionToggler {
88
94
  this.$transaction.addClass('selected');
89
95
  }
90
96
 
91
- collapse($transaction) {
97
+ /**
98
+ * Collapse the transaction
99
+ */
100
+ collapse() {
92
101
  this.#toggleTransaction(this.$extendedRow, this.$condensedRow);
93
102
  this.$transaction.removeClass('selected');
94
103
  }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Facilitate the replacement of form values with suggestions.
3
+ */
4
+
5
+
6
+ /**
7
+ * A class for replacing elements of a form with suggested values.
8
+ */
9
+ class SuggestionSelector {
10
+
11
+ /**
12
+ * Create the suggestion selector.
13
+ *
14
+ * @param {JQuery} $suggestion - An object that will have its text
15
+ * used to determine the value for replacement
16
+ */
17
+ constructor($suggestion) {
18
+ this.$suggestion = $suggestion;
19
+ const selector = this;
20
+ this.$suggestion.on("click", function() {
21
+ selector.#replaceValue();
22
+ });
23
+ }
24
+
25
+ /**
26
+ * Replace the value of the input field (by ID) with the suggested value.
27
+ */
28
+ #replaceValue() {
29
+ const $formField = this.$suggestion.closest(".form-field.suggestable");
30
+ const $input = $formField.find("input");
31
+ $input.val(this.getSuggestionText());
32
+ }
33
+
34
+ /**
35
+ * Get the text of the suggestion from the suggestion object.
36
+ */
37
+ getSuggestionText() {
38
+ return this.$suggestion.text();
39
+ }
40
+
41
+ }
42
+
43
+
44
+ /**
45
+ * A class for replacing amount values on a form with suggested values.
46
+ */
47
+ class AmountSuggestionSelector extends SuggestionSelector {
48
+
49
+ /**
50
+ * Get the text of the amount suggestion from the suggestion object.
51
+ */
52
+ getSuggestionText() {
53
+ return this.$suggestion.text().replace("$", "").replace(",", "");
54
+ }
55
+
56
+
57
+ }
58
+
59
+
60
+ export { SuggestionSelector, AmountSuggestionSelector };
@@ -26,7 +26,7 @@ class OverlayManager {
26
26
  /**
27
27
  * Add the overlay.
28
28
  *
29
- * @param {string} The AJAX request response containing the overlay.
29
+ * @param {string} response - The AJAX request response containing the overlay.
30
30
  */
31
31
  addOverlay(response) {
32
32
  this.$container.prepend(response)
@@ -55,7 +55,6 @@ class OverlayManager {
55
55
  * Bind an exit capability to the escape key in the overlay.
56
56
  */
57
57
  #bindCloseFromEscapeKey() {
58
- const manager = this;
59
58
  $(window).on('keydown', this.#closeOnEscapePress.bind(this))
60
59
  }
61
60
 
@@ -82,4 +81,3 @@ class OverlayManager {
82
81
 
83
82
 
84
83
  export { OverlayManager };
85
-
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Show the modal for loading credit activity.
3
+ *
4
+ * Shows the overlay that gives a user the ability to upload a
5
+ * file containing credit activity for comparison against the
6
+ * current statement.
7
+ */
8
+
9
+ import { executeAjaxRequest } from "./modules/ajax.js";
10
+ import { OverlayManager } from "./modules/manage-overlays.js";
11
+
12
+
13
+ (function() {
14
+
15
+ const $linkButton = $("#reconciliation-button");
16
+ const $container = $(".details[id^='credit-'][id$='-details']");
17
+ const overlayManager = new OverlayManager($container);
18
+
19
+ // Define the action to execute after executing the request
20
+ function action(response) {
21
+ overlayManager.addOverlay(response);
22
+ }
23
+
24
+ // Add AJAX request action to the link button
25
+ $linkButton.on("click", function() {
26
+ $.get(CREDIT_ACTIVITY_RECONCILIATION_ENDPOINT, action);
27
+ });
28
+
29
+ })();
@@ -0,0 +1,35 @@
1
+ /* Toggle the navigation menu for mobile views.
2
+ */
3
+
4
+ (function() {
5
+
6
+ // Identify the navigation menu and icon
7
+ const $menu = $('#header-menu');
8
+ const $menuLinks = $menu.find(".menu-links")
9
+ const $toggleButton = $menu.find('.toggle-button');
10
+
11
+
12
+ $(document).on('click', function(event) {
13
+ const targetIsToggleButton = $(event.target).closest($toggleButton).length;
14
+ const targetIsMenu = $(event.target).closest($menuLinks).length;
15
+ const mobileMenuIsActive = $toggleButton.hasClass('active');
16
+ if (targetIsToggleButton || ! targetIsMenu && mobileMenuIsActive) {
17
+ // Toggle the (vertical) navigation menu on/off when the button is clicked
18
+ // (clicking outside the menu returns the menu to its original state)
19
+ toggleMenu($toggleButton, $menuLinks);
20
+ }
21
+ });
22
+
23
+ })();
24
+
25
+
26
+ function toggleMenu($toggleButton, $menuLinks) {
27
+ $menuLinks.slideToggle({
28
+ duration: 300,
29
+ start: function() {
30
+ $(this).css('display', 'flex');
31
+ },
32
+ });
33
+ $toggleButton.toggleClass('active');
34
+ }
35
+
@@ -24,7 +24,7 @@ import {
24
24
  const $toggleSwitch = $(this);
25
25
  const $card = $toggleSwitch.closest(".credit-card");
26
26
  const $cardFront = $card.find(".card-face.front");
27
- const $checkbox = $toggleSwitch.find("input[type="checkbox"]");
27
+ const $checkbox = $toggleSwitch.find('input[type="checkbox"]');
28
28
  const cardActive = $checkbox.is(":checked");
29
29
  const cardID = $checkbox.data("card-id");
30
30
  const rawData = {
@@ -0,0 +1,11 @@
1
+ /* Replace transaction form subtotal field value with a suggestion.
2
+ */
3
+ import { AmountSuggestionSelector } from './modules/form-suggestions.js';
4
+
5
+
6
+ (function() {
7
+
8
+ const $suggestion = $(".amount-suggestion .currency");
9
+ new AmountSuggestionSelector($suggestion);
10
+
11
+ })();
@@ -0,0 +1,11 @@
1
+ /* Replace credit transaction form merchant field value with a suggestion.
2
+ */
3
+ import { SuggestionSelector } from './modules/form-suggestions.js';
4
+
5
+
6
+ (function() {
7
+
8
+ const $suggestion = $(".merchant-suggestion .merchant");
9
+ new SuggestionSelector($suggestion);
10
+
11
+ })();
@@ -0,0 +1,21 @@
1
+ {% extends 'layout.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}Change Password{% endblock %}</h1>
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+
9
+ <form id="change-password" method="post">
10
+ <p class="instructions">
11
+ Use this form to change the password for user: <b>{{ g.user.username }}</b>
12
+ </p>
13
+
14
+ <label for="password">Current Password</label>
15
+ <input type="password" name="current-password" id="current-password" required>
16
+ <label for="new-password">New Password</label>
17
+ <input type="password" name="new-password" id="new-password" required>
18
+ <input class="button" type="submit" value="Update" />
19
+ </form>
20
+
21
+ {% endblock %}
@@ -5,11 +5,13 @@
5
5
  {% endblock %}
6
6
 
7
7
  {% block content %}
8
- <form method="post">
8
+
9
+ <form id="log-in" method="post">
9
10
  <label for="username">Username</label>
10
11
  <input name="username" id="username" required>
11
12
  <label for="password">Password</label>
12
13
  <input type="password" name="password" id="password" required>
13
14
  <input class="button" type="submit" value="Log In" />
14
15
  </form>
16
+
15
17
  {% endblock %}
@@ -5,11 +5,21 @@
5
5
  {% endblock %}
6
6
 
7
7
  {% block content %}
8
- <form method="post">
9
- <label for="username">Username</label>
10
- <input name="username" id="username" required>
11
- <label for="password">Password</label>
12
- <input type="password" name="password" id="password" required>
13
- <input class="button" type="submit" value="Register" />
14
- </form>
8
+
9
+ {% if not config['REGISTRATION'] %}
10
+ <div class="no-registration-notice">
11
+ <b>Notice:</b> The app is not currently accepting new registrations.
12
+ </div>
13
+ {% endif %}
14
+
15
+ {% with input_status = 'required' if config['REGISTRATION'] else 'disabled' %}
16
+ <form id="register" method="post">
17
+ <label for="username">Username</label>
18
+ <input name="username" id="username" {{ input_status }}>
19
+ <label for="password">Password</label>
20
+ <input type="password" name="password" id="password" {{ input_status }}>
21
+ <input class="button" type="submit" value="Register" />
22
+ </form>
23
+ {% endwith %}
24
+
15
25
  {% endblock %}
@@ -22,7 +22,9 @@
22
22
  {% include 'banking/account_summary.html' %}
23
23
  </div>
24
24
 
25
- <div id="balance-chart" class="ct-chart ct-octave"></div>
25
+ <div id="balance-chart-container">
26
+ <div id="balance-chart" class="ct-chart ct-octave"></div>
27
+ </div>
26
28
 
27
29
  <div id="account-transactions-container" class="transactions-container">
28
30
  {% with transactions = account_transactions %}
@@ -13,7 +13,7 @@
13
13
  {% endif %}
14
14
  </h2>
15
15
 
16
- <div class="account-blocks">
16
+ <div class="account-blocks stack-buttons">
17
17
  {% for account in accounts|sort(attribute='last_four_digits') %}
18
18
 
19
19
  <a class="account-block button-block" href="{{ url_for('banking.load_account_details', account_id=account.id) }}">
@@ -51,22 +51,18 @@
51
51
 
52
52
  <section id="bank-account-settings">
53
53
 
54
- <div id="account-type-container">
55
- <h2>Bank Account Types</h2>
56
-
57
- <div class="account-types">
58
- {% for account_type in account_types %}
59
-
60
- <div class="account-type">
61
- {{ account_type.type_name }}
62
- {% if account_type.type_abbreviation %}
63
- ({{ account_type.type_abbreviation }})
64
- {% endif %}
65
- </div>
66
-
67
- {% endfor %}
68
- </div>
54
+ <div id="account-type-container" class="box-table">
55
+ <h2 class="box-header">Bank Account Types</h2>
56
+ {% for account_type in account_types %}
57
+
58
+ <div class="account-type box-row">
59
+ {{ account_type.type_name }}
60
+ {% if account_type.type_abbreviation %}
61
+ ({{ account_type.type_abbreviation }})
62
+ {% endif %}
63
+ </div>
69
64
 
65
+ {% endfor %}
70
66
  </div>
71
67
 
72
68
  </section>
@@ -1,39 +1,37 @@
1
- <div class="setting">
1
+ <div class="setting column">
2
2
 
3
3
  <div class="date column">
4
- <div class="month">
5
- {{ transaction.transaction_date.strftime('%b')|upper }}
6
- </div>
7
- <div class="day">
8
- {{ transaction.transaction_date.strftime('%d')|upper }}
9
- </div>
10
- <div class="year">
11
- {{ transaction.transaction_date.year }}
4
+ <div class="stacked-date">
5
+ <div class="month">
6
+ {{ transaction.transaction_date.strftime('%b')|upper }}
7
+ </div>
8
+ <div class="day">
9
+ {{ transaction.transaction_date.strftime('%d')|upper }}
10
+ </div>
11
+ <div class="year">
12
+ {{ transaction.transaction_date.year }}
13
+ </div>
12
14
  </div>
13
- <div class="full">
15
+ <div class="full-date">
14
16
  {{ transaction.transaction_date }}
15
17
  </div>
16
18
  </div>
17
19
 
18
- <div class="description">
20
+ <div class="description column">
19
21
 
20
22
  <div class="description-header">
21
23
  <div class="brief">
22
24
  {% if transaction|is_single_bank_transfer %}
23
- Transfer
25
+ <span class="transaction-type">Transfer</span>
24
26
  {% else %}
25
- {% if transaction.merchant %}
26
- {% set merchant_reference = ": " + transaction.merchant %}
27
- {% else %}
28
- {% set merchant_reference = "" %}
29
- {% endif %}
30
27
  {% if transaction.total > 0 %}
31
- Deposit{{ merchant_reference }}
28
+ {% set transaction_type = "Deposit" %}
32
29
  {% elif transaction.total < 0 %}
33
- Withdrawal{{ merchant_reference }}
30
+ {% set transaction_type = "Withdrawal" %}
34
31
  {% else %}
35
- Exchange
32
+ {% set transaction_type = "Exchange" %}
36
33
  {% endif %}
34
+ <span class="transaction-type">{{ transaction_type }}{{ ":" if transaction.merchant else "" }}</span> {{ transaction.merchant if transaction.merchant else "" }}
37
35
  {% endif %}
38
36
 
39
37
  </div>
@@ -4,10 +4,19 @@
4
4
 
5
5
  <div class="form-line">
6
6
 
7
- <div class="form-field subtotal-field">
7
+ <div class="form-field subtotal-field suggestable">
8
+
8
9
  {{ subform.subtotal.label }}
9
10
  <span class="currency-symbol">$</span>
10
11
  {{ subform.subtotal(class_="currency") }}
12
+
13
+ {% if form and form.suggestions.get('amount') %}
14
+ <div class="form-suggestion amount-suggestion">
15
+ <span>Suggested: </span>
16
+ <span class="suggested-value currency">${{ form.suggestions['amount']|currency }}</span>
17
+ </div>
18
+ {% endif %}
19
+
11
20
  </div>
12
21
 
13
22
  <div class="form-field note-field autocomplete">
@@ -23,6 +23,6 @@
23
23
  <img class="icon" src="{{ url_for('static', filename='img/icons/edit.png') }}" />
24
24
  </a>
25
25
  <a class="button" href="{{ url_for('banking.load_account_details', account_id=transaction.account_id) }}">
26
- <img class="icon" src="{{ url_for('static', filename='img/icons/statement.png') }}" />
26
+ <img class="icon" src="{{ url_for('static', filename='img/icons/statement-thick.png') }}" />
27
27
  </a>
28
28
  </div>
@@ -23,6 +23,6 @@
23
23
  <img class="icon" src="{{ url_for('static', filename='img/icons/edit.png') }}" />
24
24
  </a>
25
25
  <a class="button" href="{{ url_for('credit.load_statement_details', statement_id=transaction.statement_id) }}">
26
- <img class="icon" src="{{ url_for('static', filename='img/icons/statement.png') }}" />
26
+ <img class="icon" src="{{ url_for('static', filename='img/icons/statement-thick.png') }}" />
27
27
  </a>
28
28
  </div>
@@ -1,7 +1,7 @@
1
1
  <div class="condensed">
2
- <div class="row">
2
+ <div class="row-content{{ ' highlight' if transaction.highlight else '' }}">
3
3
 
4
- <div class="row-content">
4
+ <div class="transaction-info">
5
5
  {% include condensed_row_content_template %}
6
6
  </div>
7
7