mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-04-24 09:38:35 +02:00
Merge pull request #282
feat: allow single transactions to be hidden from summaries fix #274
This commit is contained in:
@@ -91,6 +91,8 @@ def get_transactions(request, include_unpaid=True, include_silent=False):
|
|||||||
transactions = transactions.filter(is_paid=True)
|
transactions = transactions.filter(is_paid=True)
|
||||||
|
|
||||||
if not include_silent:
|
if not include_silent:
|
||||||
transactions = transactions.exclude(Q(category__mute=True) & ~Q(category=None))
|
transactions = transactions.exclude(
|
||||||
|
Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)
|
||||||
|
)
|
||||||
|
|
||||||
return transactions
|
return transactions
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ def emergency_fund(request):
|
|||||||
reference_date__gte=start_date,
|
reference_date__gte=start_date,
|
||||||
reference_date__lte=end_date,
|
reference_date__lte=end_date,
|
||||||
category__mute=False,
|
category__mute=False,
|
||||||
|
mute=False,
|
||||||
)
|
)
|
||||||
.values("reference_date", "account__currency")
|
.values("reference_date", "account__currency")
|
||||||
.annotate(monthly_total=Sum("amount"))
|
.annotate(monthly_total=Sum("amount"))
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ def monthly_summary(request, month: int, year: int):
|
|||||||
# Base queryset with all required filters
|
# Base queryset with all required filters
|
||||||
base_queryset = Transaction.objects.filter(
|
base_queryset = Transaction.objects.filter(
|
||||||
reference_date__year=year, reference_date__month=month, account__is_asset=False
|
reference_date__year=year, reference_date__month=month, account__is_asset=False
|
||||||
).exclude(Q(category__mute=True) & ~Q(category=None))
|
).exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||||
|
|
||||||
data = calculate_currency_totals(base_queryset, ignore_empty=True)
|
data = calculate_currency_totals(base_queryset, ignore_empty=True)
|
||||||
percentages = calculate_percentage_distribution(data)
|
percentages = calculate_percentage_distribution(data)
|
||||||
@@ -143,7 +143,7 @@ def monthly_account_summary(request, month: int, year: int):
|
|||||||
base_queryset = Transaction.objects.filter(
|
base_queryset = Transaction.objects.filter(
|
||||||
reference_date__year=year,
|
reference_date__year=year,
|
||||||
reference_date__month=month,
|
reference_date__month=month,
|
||||||
).exclude(Q(category__mute=True) & ~Q(category=None))
|
).exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||||
|
|
||||||
account_data = calculate_account_totals(transactions_queryset=base_queryset.all())
|
account_data = calculate_account_totals(transactions_queryset=base_queryset.all())
|
||||||
account_percentages = calculate_percentage_distribution(account_data)
|
account_percentages = calculate_percentage_distribution(account_data)
|
||||||
@@ -168,7 +168,7 @@ def monthly_currency_summary(request, month: int, year: int):
|
|||||||
base_queryset = Transaction.objects.filter(
|
base_queryset = Transaction.objects.filter(
|
||||||
reference_date__year=year,
|
reference_date__year=year,
|
||||||
reference_date__month=month,
|
reference_date__month=month,
|
||||||
).exclude(Q(category__mute=True) & ~Q(category=None))
|
).exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||||
|
|
||||||
currency_data = calculate_currency_totals(base_queryset.all(), ignore_empty=True)
|
currency_data = calculate_currency_totals(base_queryset.all(), ignore_empty=True)
|
||||||
currency_percentages = calculate_percentage_distribution(currency_data)
|
currency_percentages = calculate_percentage_distribution(currency_data)
|
||||||
|
|||||||
@@ -290,11 +290,15 @@ class QuickTransactionForm(forms.ModelForm):
|
|||||||
"category",
|
"category",
|
||||||
"tags",
|
"tags",
|
||||||
"entities",
|
"entities",
|
||||||
|
"mute",
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
"notes": forms.Textarea(attrs={"rows": 3}),
|
"notes": forms.Textarea(attrs={"rows": 3}),
|
||||||
"account": TomSelect(clear_button=False, group_by="group"),
|
"account": TomSelect(clear_button=False, group_by="group"),
|
||||||
}
|
}
|
||||||
|
help_texts = {
|
||||||
|
"mute": _("Muted transactions won't be displayed on monthly summaries")
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@@ -356,6 +360,7 @@ class QuickTransactionForm(forms.ModelForm):
|
|||||||
css_class="form-row",
|
css_class="form-row",
|
||||||
),
|
),
|
||||||
"notes",
|
"notes",
|
||||||
|
Switch("mute"),
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.instance and self.instance.pk:
|
if self.instance and self.instance.pk:
|
||||||
@@ -616,6 +621,7 @@ class TransferForm(forms.Form):
|
|||||||
description=description,
|
description=description,
|
||||||
category=from_category,
|
category=from_category,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
mute=True,
|
||||||
)
|
)
|
||||||
from_transaction.tags.set(self.cleaned_data.get("from_tags", []))
|
from_transaction.tags.set(self.cleaned_data.get("from_tags", []))
|
||||||
|
|
||||||
@@ -630,6 +636,7 @@ class TransferForm(forms.Form):
|
|||||||
description=description,
|
description=description,
|
||||||
category=to_category,
|
category=to_category,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
mute=True,
|
||||||
)
|
)
|
||||||
to_transaction.tags.set(self.cleaned_data.get("to_tags", []))
|
to_transaction.tags.set(self.cleaned_data.get("to_tags", []))
|
||||||
|
|
||||||
@@ -868,7 +875,7 @@ class TransactionCategoryForm(forms.ModelForm):
|
|||||||
fields = ["name", "mute", "active"]
|
fields = ["name", "mute", "active"]
|
||||||
labels = {"name": _("Category name")}
|
labels = {"name": _("Category name")}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
"mute": _("Muted categories won't count towards your monthly total")
|
"mute": _("Muted categories won't be displayed on monthly summaries")
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|||||||
18
app/apps/transactions/migrations/0045_transaction_mute.py
Normal file
18
app/apps/transactions/migrations/0045_transaction_mute.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-07-19 18:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('transactions', '0044_alter_quicktransaction_unique_together'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='transaction',
|
||||||
|
name='mute',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Mute'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-07-19 18:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('transactions', '0045_transaction_mute'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='quicktransaction',
|
||||||
|
name='mute',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Mute'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -299,6 +299,7 @@ class Transaction(OwnedObject):
|
|||||||
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
||||||
date = models.DateField(verbose_name=_("Date"))
|
date = models.DateField(verbose_name=_("Date"))
|
||||||
reference_date = MonthYearModelField(verbose_name=_("Reference Date"))
|
reference_date = MonthYearModelField(verbose_name=_("Reference Date"))
|
||||||
|
mute = models.BooleanField(default=False, verbose_name=_("Mute"))
|
||||||
|
|
||||||
amount = models.DecimalField(
|
amount = models.DecimalField(
|
||||||
max_digits=42,
|
max_digits=42,
|
||||||
@@ -918,6 +919,7 @@ class QuickTransaction(OwnedObject):
|
|||||||
verbose_name=_("Type"),
|
verbose_name=_("Type"),
|
||||||
)
|
)
|
||||||
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
is_paid = models.BooleanField(default=True, verbose_name=_("Paid"))
|
||||||
|
mute = models.BooleanField(default=False, verbose_name=_("Mute"))
|
||||||
|
|
||||||
amount = models.DecimalField(
|
amount = models.DecimalField(
|
||||||
max_digits=42,
|
max_digits=42,
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ urlpatterns = [
|
|||||||
views.transaction_pay,
|
views.transaction_pay,
|
||||||
name="transaction_pay",
|
name="transaction_pay",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"transaction/<int:transaction_id>/mute/",
|
||||||
|
views.transaction_mute,
|
||||||
|
name="transaction_mute",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"transaction/<int:transaction_id>/delete/",
|
"transaction/<int:transaction_id>/delete/",
|
||||||
views.transaction_delete,
|
views.transaction_delete,
|
||||||
|
|||||||
@@ -388,6 +388,26 @@ def transaction_pay(request, transaction_id):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@only_htmx
|
||||||
|
@login_required
|
||||||
|
@require_http_methods(["GET"])
|
||||||
|
def transaction_mute(request, transaction_id):
|
||||||
|
transaction = get_object_or_404(Transaction, pk=transaction_id)
|
||||||
|
|
||||||
|
new_mute = False if transaction.mute else True
|
||||||
|
transaction.mute = new_mute
|
||||||
|
transaction.save()
|
||||||
|
transaction_updated.send(sender=transaction)
|
||||||
|
|
||||||
|
response = render(
|
||||||
|
request,
|
||||||
|
"transactions/fragments/item.html",
|
||||||
|
context={"transaction": transaction, **request.GET},
|
||||||
|
)
|
||||||
|
response.headers["HX-Trigger"] = "selective_update"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def transaction_all_index(request):
|
def transaction_all_index(request):
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ def yearly_overview_by_currency(request, year: int):
|
|||||||
|
|
||||||
transactions = (
|
transactions = (
|
||||||
Transaction.objects.filter(**filter_params)
|
Transaction.objects.filter(**filter_params)
|
||||||
.exclude(Q(category__mute=True) & ~Q(category=None))
|
.exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||||
.order_by("account__currency__name")
|
.order_by("account__currency__name")
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ def yearly_overview_by_account(request, year: int):
|
|||||||
|
|
||||||
transactions = (
|
transactions = (
|
||||||
Transaction.objects.filter(**filter_params)
|
Transaction.objects.filter(**filter_params)
|
||||||
.exclude(Q(category__mute=True) & ~Q(category=None))
|
.exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||||
.order_by(
|
.order_by(
|
||||||
"account__group__name",
|
"account__group__name",
|
||||||
"account__name",
|
"account__name",
|
||||||
|
|||||||
@@ -146,6 +146,21 @@
|
|||||||
<i class="fa-solid fa-ellipsis fa-fw"></i>
|
<i class="fa-solid fa-ellipsis fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
{% if transaction.category.mute %}
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item disabled d-flex align-items-center" aria-disabled="true">
|
||||||
|
<i class="fa-solid fa-eye fa-fw me-2"></i>
|
||||||
|
<div>
|
||||||
|
{% translate 'Show on summaries' %}
|
||||||
|
<div class="d-block text-body-secondary tw:text-xs tw:font-medium">{% translate 'Controlled by category' %}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% elif transaction.mute %}
|
||||||
|
<li><a class="dropdown-item" href="#" hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}" hx-target="closest .transaction" hx-swap="outerHTML"><i class="fa-solid fa-eye fa-fw me-2"></i>{% translate 'Show on summaries' %}</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li><a class="dropdown-item" href="#" hx-get="{% url 'transaction_mute' transaction_id=transaction.id %}" hx-target="closest .transaction" hx-swap="outerHTML"><i class="fa-solid fa-eye-slash fa-fw me-2"></i>{% translate 'Hide from summaries' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
<li><a class="dropdown-item" href="#" hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"><i class="fa-solid fa-clone fa-fw me-2"></i>{% translate 'Duplicate' %}</a></li>
|
<li><a class="dropdown-item" href="#" hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"><i class="fa-solid fa-clone fa-fw me-2"></i>{% translate 'Duplicate' %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
Reference in New Issue
Block a user