From 7f8261b9cc111e63d118b7637df906973dbde141 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 9 Aug 2025 05:47:18 +0000 Subject: [PATCH 1/4] refactor: Style transaction items for untracked accounts This commit extends the "Untrack Account" feature by applying a special style to transaction items that belong to an untracked account. - The transaction item template is modified to apply a "dimmed" style to transactions from untracked accounts. - The styling follows the precedence: Account (untracked) > Category (muted) > Transaction (hidden). - The dropdown menu for transaction items now shows "Controlled by account" if the transaction's account is untracked. --- app/apps/accounts/models.py | 8 +++++ app/apps/accounts/urls.py | 5 ++++ app/apps/accounts/views/accounts.py | 20 +++++++++++++ app/apps/insights/utils/transactions.py | 2 ++ app/apps/monthly_overview/views.py | 12 ++++++-- app/apps/net_worth/views.py | 20 ++++++++----- app/apps/yearly_overview/views.py | 1 + app/templates/accounts/fragments/list.html | 13 +++++++++ app/templates/cotton/transaction/item.html | 34 ++++++++++++++-------- 9 files changed, 92 insertions(+), 23 deletions(-) diff --git a/app/apps/accounts/models.py b/app/apps/accounts/models.py index e6efbc8..a387206 100644 --- a/app/apps/accounts/models.py +++ b/app/apps/accounts/models.py @@ -62,6 +62,11 @@ class Account(SharedObject): verbose_name=_("Archived"), help_text=_("Archived accounts don't show up nor count towards your net worth"), ) + untracked_by = models.ManyToManyField( + settings.AUTH_USER_MODEL, + blank=True, + related_name="untracked_accounts", + ) objects = SharedObjectManager() all_objects = models.Manager() # Unfiltered manager @@ -75,6 +80,9 @@ class Account(SharedObject): def __str__(self): return self.name + def is_untracked_by(self, user): + return self.untracked_by.filter(pk=user.pk).exists() + def clean(self): super().clean() if self.exchange_currency == self.currency: diff --git a/app/apps/accounts/urls.py b/app/apps/accounts/urls.py index 699b830..ffe2781 100644 --- a/app/apps/accounts/urls.py +++ b/app/apps/accounts/urls.py @@ -31,6 +31,11 @@ urlpatterns = [ views.account_take_ownership, name="account_take_ownership", ), + path( + "account//toggle-untracked/", + views.account_toggle_untracked, + name="account_toggle_untracked", + ), path("account-groups/", views.account_groups_index, name="account_groups_index"), path("account-groups/list/", views.account_groups_list, name="account_groups_list"), path("account-groups/add/", views.account_group_add, name="account_group_add"), diff --git a/app/apps/accounts/views/accounts.py b/app/apps/accounts/views/accounts.py index 53b70ae..422a152 100644 --- a/app/apps/accounts/views/accounts.py +++ b/app/apps/accounts/views/accounts.py @@ -155,6 +155,26 @@ def account_delete(request, pk): ) +@only_htmx +@login_required +@require_http_methods(["POST"]) +def account_toggle_untracked(request, pk): + account = get_object_or_404(Account, id=pk) + if account.is_untracked_by(request.user): + account.untracked_by.remove(request.user) + messages.success(request, _("Account is now tracked.")) + else: + account.untracked_by.add(request.user) + messages.success(request, _("Account is now untracked.")) + + return HttpResponse( + status=204, + headers={ + "HX-Trigger": "updated", + }, + ) + + @only_htmx @login_required @require_http_methods(["GET"]) diff --git a/app/apps/insights/utils/transactions.py b/app/apps/insights/utils/transactions.py index 5b919d9..4fd5100 100644 --- a/app/apps/insights/utils/transactions.py +++ b/app/apps/insights/utils/transactions.py @@ -95,4 +95,6 @@ def get_transactions(request, include_unpaid=True, include_silent=False): Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True) ) + transactions = transactions.exclude(account__in=request.user.untracked_accounts.all()) + return transactions diff --git a/app/apps/monthly_overview/views.py b/app/apps/monthly_overview/views.py index 8624201..61587fc 100644 --- a/app/apps/monthly_overview/views.py +++ b/app/apps/monthly_overview/views.py @@ -107,9 +107,15 @@ def transactions_list(request, month: int, year: int): @require_http_methods(["GET"]) def monthly_summary(request, month: int, year: int): # Base queryset with all required filters - base_queryset = Transaction.objects.filter( - reference_date__year=year, reference_date__month=month, account__is_asset=False - ).exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)) + base_queryset = ( + Transaction.objects.filter( + reference_date__year=year, + reference_date__month=month, + account__is_asset=False, + ) + .exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)) + .exclude(account__in=request.user.untracked_accounts.all()) + ) data = calculate_currency_totals(base_queryset, ignore_empty=True) percentages = calculate_percentage_distribution(data) diff --git a/app/apps/net_worth/views.py b/app/apps/net_worth/views.py index 07bbbfb..4e3362a 100644 --- a/app/apps/net_worth/views.py +++ b/app/apps/net_worth/views.py @@ -27,10 +27,12 @@ def net_worth(request): view_type = request.session.get("networth_view_type", "current") if view_type == "current": - transactions_currency_queryset = Transaction.objects.filter( - is_paid=True, account__is_archived=False - ).order_by( - "account__currency__name", + transactions_currency_queryset = ( + Transaction.objects.filter(is_paid=True, account__is_archived=False) + .order_by( + "account__currency__name", + ) + .exclude(account__in=request.user.untracked_accounts.all()) ) transactions_account_queryset = Transaction.objects.filter( is_paid=True, account__is_archived=False @@ -39,10 +41,12 @@ def net_worth(request): "account__name", ) else: - transactions_currency_queryset = Transaction.objects.filter( - account__is_archived=False - ).order_by( - "account__currency__name", + transactions_currency_queryset = ( + Transaction.objects.filter(account__is_archived=False) + .order_by( + "account__currency__name", + ) + .exclude(account__in=request.user.untracked_accounts.all()) ) transactions_account_queryset = Transaction.objects.filter( account__is_archived=False diff --git a/app/apps/yearly_overview/views.py b/app/apps/yearly_overview/views.py index 881e9df..1444476 100644 --- a/app/apps/yearly_overview/views.py +++ b/app/apps/yearly_overview/views.py @@ -95,6 +95,7 @@ def yearly_overview_by_currency(request, year: int): transactions = ( Transaction.objects.filter(**filter_params) .exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)) + .exclude(account__in=request.user.untracked_accounts.all()) .order_by("account__currency__name") ) diff --git a/app/templates/accounts/fragments/list.html b/app/templates/accounts/fragments/list.html index 207c761..8aa009a 100644 --- a/app/templates/accounts/fragments/list.html +++ b/app/templates/accounts/fragments/list.html @@ -71,6 +71,19 @@ hx-get="{% url 'account_share_settings' pk=account.id %}"> {% endif %} + + {% if account.is_untracked_by user %} + + {% else %} + + {% endif %} + {{ account.name }} diff --git a/app/templates/cotton/transaction/item.html b/app/templates/cotton/transaction/item.html index e48d609..5bb650e 100644 --- a/app/templates/cotton/transaction/item.html +++ b/app/templates/cotton/transaction/item.html @@ -33,7 +33,7 @@ {% endif %} -
+
{# Date#}
@@ -91,7 +91,7 @@ {% endwith %}
-
+
diff --git a/app/templates/cotton/transaction/item.html b/app/templates/cotton/transaction/item.html index 5bb650e..d182af4 100644 --- a/app/templates/cotton/transaction/item.html +++ b/app/templates/cotton/transaction/item.html @@ -33,7 +33,7 @@
{% endif %}
-
+
{# Date#}
@@ -91,7 +91,7 @@ {% endwith %}
-
+