mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-25 17:04:51 +01:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
011e926e02 | ||
|
|
cd1b872b27 | ||
|
|
3791edce63 | ||
|
|
2cb8100129 | ||
|
|
e7e4ccafb6 | ||
|
|
afbbf7b25d | ||
|
|
1eba2b8731 | ||
|
|
afe366c359 | ||
|
|
3ee2bebc5c | ||
|
|
b951e5f069 | ||
|
|
4005a83a0d | ||
|
|
f81f1d83fd | ||
|
|
7816d6c55d | ||
|
|
6e3fdae4fe | ||
|
|
e2da996217 | ||
|
|
cc2e2293ed | ||
|
|
7060f07ccd | ||
|
|
0adb991879 | ||
|
|
20e03df661 | ||
|
|
71f59bfd68 | ||
|
|
6c76535f91 | ||
|
|
5c8fbc9278 | ||
|
|
89b11421c2 | ||
|
|
056fc4fced | ||
|
|
3f9765ec7b | ||
|
|
0d9d13bf31 | ||
|
|
2f6c396eaf | ||
|
|
d12b920e54 | ||
|
|
9edbf7bd5a | ||
|
|
dbd3eea29a | ||
|
|
881fed1895 | ||
|
|
10a0ac42a2 | ||
|
|
1b47c12a22 | ||
|
|
091f73bf8d | ||
|
|
73fe17de64 | ||
|
|
52af1b2260 | ||
|
|
8efa087aee | ||
|
|
6f69f15474 | ||
|
|
905e80cffe | ||
|
|
baae6bb96a | ||
|
|
f5132e24bd | ||
|
|
41303f39a0 | ||
|
|
0fc8b0ee49 | ||
|
|
037014d024 |
@@ -1,3 +1,4 @@
|
||||
from .transactions import *
|
||||
from .accounts import *
|
||||
from .currencies import *
|
||||
from .dca import *
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from apps.api.serializers.currencies import CurrencySerializer
|
||||
from apps.accounts.models import AccountGroup, Account
|
||||
@@ -6,6 +7,8 @@ from apps.currencies.models import Currency
|
||||
|
||||
|
||||
class AccountGroupSerializer(serializers.ModelSerializer):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = AccountGroup
|
||||
fields = "__all__"
|
||||
@@ -31,6 +34,8 @@ class AccountSerializer(serializers.ModelSerializer):
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = [
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from apps.currencies.models import Currency, ExchangeRate
|
||||
|
||||
|
||||
class CurrencySerializer(serializers.ModelSerializer):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = Currency
|
||||
fields = "__all__"
|
||||
@@ -24,6 +28,8 @@ class ExchangeRateSerializer(serializers.ModelSerializer):
|
||||
queryset=Currency.objects.all(), source="to_currency", write_only=True
|
||||
)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = ExchangeRate
|
||||
fields = "__all__"
|
||||
|
||||
85
app/apps/api/serializers/dca.py
Normal file
85
app/apps/api/serializers/dca.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from apps.dca.models import DCAEntry, DCAStrategy
|
||||
|
||||
|
||||
class DCAEntrySerializer(serializers.ModelSerializer):
|
||||
profit_loss = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
profit_loss_percentage = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
current_value = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
entry_price = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = DCAEntry
|
||||
fields = [
|
||||
"id",
|
||||
"strategy",
|
||||
"date",
|
||||
"amount_paid",
|
||||
"amount_received",
|
||||
"notes",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"profit_loss",
|
||||
"profit_loss_percentage",
|
||||
"current_value",
|
||||
"entry_price",
|
||||
]
|
||||
read_only_fields = ["created_at", "updated_at"]
|
||||
|
||||
|
||||
class DCAStrategySerializer(serializers.ModelSerializer):
|
||||
entries = DCAEntrySerializer(many=True, read_only=True)
|
||||
total_invested = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
total_received = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
average_entry_price = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
total_entries = serializers.IntegerField(read_only=True)
|
||||
current_total_value = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
total_profit_loss = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
total_profit_loss_percentage = serializers.DecimalField(
|
||||
max_digits=42, decimal_places=30, read_only=True
|
||||
)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = DCAStrategy
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"target_currency",
|
||||
"payment_currency",
|
||||
"notes",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"entries",
|
||||
"total_invested",
|
||||
"total_received",
|
||||
"average_entry_price",
|
||||
"total_entries",
|
||||
"current_total_value",
|
||||
"total_profit_loss",
|
||||
"total_profit_loss_percentage",
|
||||
]
|
||||
read_only_fields = ["created_at", "updated_at"]
|
||||
@@ -19,6 +19,7 @@ from apps.transactions.models import (
|
||||
TransactionTag,
|
||||
InstallmentPlan,
|
||||
TransactionEntity,
|
||||
RecurringTransaction,
|
||||
)
|
||||
|
||||
|
||||
@@ -47,11 +48,82 @@ class TransactionEntitySerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class InstallmentPlanSerializer(serializers.ModelSerializer):
|
||||
category = TransactionCategoryField(required=False)
|
||||
tags = TransactionTagField(required=False)
|
||||
entities = TransactionEntityField(required=False)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
class Meta:
|
||||
model = InstallmentPlan
|
||||
fields = "__all__"
|
||||
fields = [
|
||||
"id",
|
||||
"account",
|
||||
"type",
|
||||
"description",
|
||||
"number_of_installments",
|
||||
"installment_start",
|
||||
"installment_total_number",
|
||||
"start_date",
|
||||
"reference_date",
|
||||
"end_date",
|
||||
"recurrence",
|
||||
"installment_amount",
|
||||
"category",
|
||||
"tags",
|
||||
"entities",
|
||||
"notes",
|
||||
]
|
||||
read_only_fields = ["installment_total_number", "end_date"]
|
||||
|
||||
def create(self, validated_data):
|
||||
instance = super().create(validated_data)
|
||||
instance.create_transactions()
|
||||
return instance
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance = super().update(instance, validated_data)
|
||||
instance.update_transactions()
|
||||
return instance
|
||||
|
||||
|
||||
class RecurringTransactionSerializer(serializers.ModelSerializer):
|
||||
category = TransactionCategoryField(required=False)
|
||||
tags = TransactionTagField(required=False)
|
||||
entities = TransactionEntityField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = RecurringTransaction
|
||||
fields = [
|
||||
"id",
|
||||
"is_paused",
|
||||
"account",
|
||||
"type",
|
||||
"amount",
|
||||
"description",
|
||||
"category",
|
||||
"tags",
|
||||
"entities",
|
||||
"notes",
|
||||
"reference_date",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"recurrence_type",
|
||||
"recurrence_interval",
|
||||
"last_generated_date",
|
||||
"last_generated_reference_date",
|
||||
]
|
||||
read_only_fields = ["last_generated_date", "last_generated_reference_date"]
|
||||
|
||||
def create(self, validated_data):
|
||||
instance = super().create(validated_data)
|
||||
instance.create_upcoming_transactions()
|
||||
return instance
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance = super().update(instance, validated_data)
|
||||
instance.update_unpaid_transactions()
|
||||
return instance
|
||||
|
||||
|
||||
class TransactionSerializer(serializers.ModelSerializer):
|
||||
|
||||
@@ -9,10 +9,13 @@ router.register(r"categories", views.TransactionCategoryViewSet)
|
||||
router.register(r"tags", views.TransactionTagViewSet)
|
||||
router.register(r"entities", views.TransactionEntityViewSet)
|
||||
router.register(r"installment-plans", views.InstallmentPlanViewSet)
|
||||
router.register(r"recurring-transactions", views.RecurringTransactionViewSet)
|
||||
router.register(r"account-groups", views.AccountGroupViewSet)
|
||||
router.register(r"accounts", views.AccountViewSet)
|
||||
router.register(r"currencies", views.CurrencyViewSet)
|
||||
router.register(r"exchange-rates", views.ExchangeRateViewSet)
|
||||
router.register(r"dca/strategies", views.DCAStrategyViewSet)
|
||||
router.register(r"dca/entries", views.DCAEntryViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from .transactions import *
|
||||
from .accounts import *
|
||||
from .currencies import *
|
||||
from .dca import *
|
||||
|
||||
41
app/apps/api/views/dca.py
Normal file
41
app/apps/api/views/dca.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from apps.dca.models import DCAStrategy, DCAEntry
|
||||
from apps.api.serializers import DCAStrategySerializer, DCAEntrySerializer
|
||||
|
||||
|
||||
class DCAStrategyViewSet(viewsets.ModelViewSet):
|
||||
queryset = DCAStrategy.objects.all()
|
||||
serializer_class = DCAStrategySerializer
|
||||
|
||||
@action(detail=True, methods=["get"])
|
||||
def investment_frequency(self, request, pk=None):
|
||||
strategy = self.get_object()
|
||||
return Response(strategy.investment_frequency_data())
|
||||
|
||||
@action(detail=True, methods=["get"])
|
||||
def price_comparison(self, request, pk=None):
|
||||
strategy = self.get_object()
|
||||
return Response(strategy.price_comparison_data())
|
||||
|
||||
@action(detail=True, methods=["get"])
|
||||
def current_price(self, request, pk=None):
|
||||
strategy = self.get_object()
|
||||
price_data = strategy.current_price()
|
||||
if price_data:
|
||||
price, date = price_data
|
||||
return Response({"price": price, "date": date})
|
||||
return Response({"price": None, "date": None})
|
||||
|
||||
|
||||
class DCAEntryViewSet(viewsets.ModelViewSet):
|
||||
queryset = DCAEntry.objects.all()
|
||||
serializer_class = DCAEntrySerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = DCAEntry.objects.all()
|
||||
strategy_id = self.request.query_params.get("strategy", None)
|
||||
if strategy_id is not None:
|
||||
queryset = queryset.filter(strategy_id=strategy_id)
|
||||
return queryset
|
||||
@@ -1,4 +1,4 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
from rest_framework import viewsets
|
||||
|
||||
from apps.api.serializers import (
|
||||
TransactionSerializer,
|
||||
@@ -6,6 +6,7 @@ from apps.api.serializers import (
|
||||
TransactionTagSerializer,
|
||||
InstallmentPlanSerializer,
|
||||
TransactionEntitySerializer,
|
||||
RecurringTransactionSerializer,
|
||||
)
|
||||
from apps.transactions.models import (
|
||||
Transaction,
|
||||
@@ -13,6 +14,7 @@ from apps.transactions.models import (
|
||||
TransactionTag,
|
||||
InstallmentPlan,
|
||||
TransactionEntity,
|
||||
RecurringTransaction,
|
||||
)
|
||||
from apps.rules.signals import transaction_updated, transaction_created
|
||||
|
||||
@@ -53,10 +55,7 @@ class InstallmentPlanViewSet(viewsets.ModelViewSet):
|
||||
queryset = InstallmentPlan.objects.all()
|
||||
serializer_class = InstallmentPlanSerializer
|
||||
|
||||
def perform_create(self, serializer):
|
||||
instance = serializer.save()
|
||||
instance.create_transactions()
|
||||
|
||||
def perform_update(self, serializer):
|
||||
instance = serializer.save()
|
||||
instance.create_transactions()
|
||||
class RecurringTransactionViewSet(viewsets.ModelViewSet):
|
||||
queryset = RecurringTransaction.objects.all()
|
||||
serializer_class = RecurringTransactionSerializer
|
||||
|
||||
@@ -767,5 +767,7 @@ class RecurringTransactionForm(forms.ModelForm):
|
||||
instance = super().save(**kwargs)
|
||||
if is_new:
|
||||
instance.create_upcoming_transactions()
|
||||
else:
|
||||
instance.update_unpaid_transactions()
|
||||
|
||||
return instance
|
||||
|
||||
@@ -334,10 +334,15 @@ class InstallmentPlan(models.Model):
|
||||
existing_transaction.type = self.type
|
||||
existing_transaction.date = transaction_date
|
||||
existing_transaction.reference_date = transaction_reference_date
|
||||
existing_transaction.amount = self.installment_amount
|
||||
existing_transaction.description = self.description
|
||||
existing_transaction.category = self.category
|
||||
existing_transaction.notes = self.notes
|
||||
|
||||
if (
|
||||
not existing_transaction.is_paid
|
||||
): # Don't update value for paid transactions
|
||||
existing_transaction.amount = self.installment_amount
|
||||
|
||||
existing_transaction.save()
|
||||
|
||||
# Update tags
|
||||
@@ -540,3 +545,33 @@ class RecurringTransaction(models.Model):
|
||||
recurring_transaction.save(
|
||||
update_fields=["last_generated_date", "last_generated_reference_date"]
|
||||
)
|
||||
|
||||
def update_unpaid_transactions(self):
|
||||
"""
|
||||
Updates all unpaid transactions associated with this RecurringTransaction.
|
||||
|
||||
Only unpaid transactions (`is_paid=False`) are modified. Updates fields like
|
||||
amount, description, category, notes, and many-to-many relationships (tags, entities).
|
||||
"""
|
||||
unpaid_transactions = self.transactions.filter(is_paid=False)
|
||||
|
||||
for existing_transaction in unpaid_transactions:
|
||||
# Update fields based on RecurringTransaction
|
||||
existing_transaction.amount = self.amount
|
||||
existing_transaction.description = self.description
|
||||
existing_transaction.category = self.category
|
||||
existing_transaction.notes = self.notes
|
||||
|
||||
# Update many-to-many relationships
|
||||
existing_transaction.tags.set(self.tags.all())
|
||||
existing_transaction.entities.set(self.entities.all())
|
||||
|
||||
# Save updated transaction
|
||||
existing_transaction.save()
|
||||
|
||||
def delete_unpaid_transactions(self):
|
||||
"""
|
||||
Deletes all unpaid transactions associated with this RecurringTransaction.
|
||||
"""
|
||||
today = timezone.localdate(timezone.now())
|
||||
self.transactions.filter(is_paid=False, date__gt=today).delete()
|
||||
|
||||
@@ -53,6 +53,8 @@ urlpatterns = [
|
||||
),
|
||||
path("tags/", views.tags_index, name="tags_index"),
|
||||
path("tags/list/", views.tags_list, name="tags_list"),
|
||||
path("tags/table/active/", views.tags_table_active, name="tags_table_active"),
|
||||
path("tags/table/archived/", views.tags_table_archived, name="tags_table_archived"),
|
||||
path("tags/add/", views.tag_add, name="tag_add"),
|
||||
path(
|
||||
"tags/<int:tag_id>/edit/",
|
||||
@@ -66,6 +68,16 @@ urlpatterns = [
|
||||
),
|
||||
path("entities/", views.entities_index, name="entities_index"),
|
||||
path("entities/list/", views.entities_list, name="entities_list"),
|
||||
path(
|
||||
"entities/table/active/",
|
||||
views.entities_table_active,
|
||||
name="entities_table_active",
|
||||
),
|
||||
path(
|
||||
"entities/table/archived/",
|
||||
views.entities_table_archived,
|
||||
name="entities_table_archived",
|
||||
),
|
||||
path("entities/add/", views.entity_add, name="entity_add"),
|
||||
path(
|
||||
"entities/<int:entity_id>/edit/",
|
||||
@@ -79,6 +91,16 @@ urlpatterns = [
|
||||
),
|
||||
path("categories/", views.categories_index, name="categories_index"),
|
||||
path("categories/list/", views.categories_list, name="categories_list"),
|
||||
path(
|
||||
"categories/table/active/",
|
||||
views.categories_table_active,
|
||||
name="categories_table_active",
|
||||
),
|
||||
path(
|
||||
"categories/table/archived/",
|
||||
views.categories_table_archived,
|
||||
name="categories_table_archived",
|
||||
),
|
||||
path("categories/add/", views.category_add, name="category_add"),
|
||||
path(
|
||||
"categories/<int:category_id>/edit/",
|
||||
|
||||
@@ -25,11 +25,33 @@ def categories_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def categories_list(request):
|
||||
categories = TransactionCategory.objects.all().order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"categories/fragments/list.html",
|
||||
{"categories": categories},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def categories_table_active(request):
|
||||
categories = TransactionCategory.objects.filter(active=True).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"categories/fragments/table.html",
|
||||
{"categories": categories, "active": True},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def categories_table_archived(request):
|
||||
categories = TransactionCategory.objects.filter(active=False).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"categories/fragments/table.html",
|
||||
{"categories": categories, "active": False},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -24,11 +24,33 @@ def entities_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def entities_list(request):
|
||||
entities = TransactionEntity.objects.all().order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"entities/fragments/list.html",
|
||||
{"entities": entities},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def entities_table_active(request):
|
||||
entities = TransactionEntity.objects.filter(active=True).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"entities/fragments/table.html",
|
||||
{"entities": entities, "active": True},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def entities_table_archived(request):
|
||||
entities = TransactionEntity.objects.filter(active=False).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"entities/fragments/table.html",
|
||||
{"entities": entities, "active": False},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -168,12 +168,26 @@ def recurring_transaction_toggle_pause(request, recurring_transaction_id):
|
||||
)
|
||||
current_paused = recurring_transaction.is_paused
|
||||
recurring_transaction.is_paused = not current_paused
|
||||
recurring_transaction.save(update_fields=["is_paused"])
|
||||
|
||||
if current_paused:
|
||||
messages.success(request, _("Recurring transaction unpaused successfully"))
|
||||
today = timezone.localdate(timezone.now())
|
||||
recurring_transaction.last_generated_date = max(
|
||||
recurring_transaction.last_generated_date, today
|
||||
)
|
||||
recurring_transaction.last_generated_reference_date = max(
|
||||
recurring_transaction.last_generated_reference_date, today
|
||||
)
|
||||
recurring_transaction.save(
|
||||
update_fields=[
|
||||
"last_generated_date",
|
||||
"last_generated_reference_date",
|
||||
"is_paused",
|
||||
]
|
||||
)
|
||||
generate_recurring_transactions.defer()
|
||||
messages.success(request, _("Recurring transaction unpaused successfully"))
|
||||
else:
|
||||
recurring_transaction.save(update_fields=["is_paused"])
|
||||
messages.success(request, _("Recurring transaction paused successfully"))
|
||||
|
||||
return HttpResponse(
|
||||
@@ -188,7 +202,7 @@ def recurring_transaction_toggle_pause(request, recurring_transaction_id):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def recurring_transaction_finish(request, recurring_transaction_id):
|
||||
recurring_transaction = get_object_or_404(
|
||||
recurring_transaction: RecurringTransaction = get_object_or_404(
|
||||
RecurringTransaction, id=recurring_transaction_id
|
||||
)
|
||||
today = timezone.localdate(timezone.now()) - relativedelta(days=1)
|
||||
@@ -197,6 +211,9 @@ def recurring_transaction_finish(request, recurring_transaction_id):
|
||||
recurring_transaction.is_paused = True
|
||||
recurring_transaction.save(update_fields=["end_date", "is_paused"])
|
||||
|
||||
# Delete all unpaid transactions associated with this RecurringTransaction
|
||||
recurring_transaction.delete_unpaid_transactions()
|
||||
|
||||
messages.success(request, _("Recurring transaction finished successfully"))
|
||||
|
||||
return HttpResponse(
|
||||
|
||||
@@ -24,11 +24,33 @@ def tags_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def tags_list(request):
|
||||
tags = TransactionTag.objects.all().order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"tags/fragments/list.html",
|
||||
{"tags": tags},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def tags_table_active(request):
|
||||
tags = TransactionTag.objects.filter(active=True).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"tags/fragments/table.html",
|
||||
{"tags": tags, "active": True},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def tags_table_archived(request):
|
||||
tags = TransactionTag.objects.filter(active=False).order_by("id")
|
||||
return render(
|
||||
request,
|
||||
"tags/fragments/table.html",
|
||||
{"tags": tags, "active": False},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-04 21:19+0000\n"
|
||||
"PO-Revision-Date: 2025-01-04 18:22-0300\n"
|
||||
"POT-Creation-Date: 2025-01-11 16:40+0000\n"
|
||||
"PO-Revision-Date: 2025-01-11 13:41-0300\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: pt_BR\n"
|
||||
@@ -66,7 +66,7 @@ msgstr "Novo saldo"
|
||||
#: apps/transactions/forms.py:39 apps/transactions/forms.py:209
|
||||
#: apps/transactions/forms.py:216 apps/transactions/forms.py:395
|
||||
#: apps/transactions/forms.py:637 apps/transactions/models.py:109
|
||||
#: apps/transactions/models.py:228 apps/transactions/models.py:403
|
||||
#: apps/transactions/models.py:228 apps/transactions/models.py:408
|
||||
msgid "Category"
|
||||
msgstr "Categoria"
|
||||
|
||||
@@ -75,7 +75,7 @@ msgstr "Categoria"
|
||||
#: apps/transactions/forms.py:225 apps/transactions/forms.py:233
|
||||
#: apps/transactions/forms.py:388 apps/transactions/forms.py:630
|
||||
#: apps/transactions/models.py:115 apps/transactions/models.py:230
|
||||
#: apps/transactions/models.py:407 templates/includes/navbar.html:98
|
||||
#: apps/transactions/models.py:412 templates/includes/navbar.html:98
|
||||
#: templates/tags/fragments/list.html:5 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
@@ -85,12 +85,13 @@ msgstr "Tags"
|
||||
#: apps/transactions/models.py:39 apps/transactions/models.py:58
|
||||
#: templates/account_groups/fragments/list.html:25
|
||||
#: templates/accounts/fragments/list.html:25
|
||||
#: templates/categories/fragments/list.html:25
|
||||
#: templates/categories/fragments/table.html:16
|
||||
#: templates/currencies/fragments/list.html:26
|
||||
#: templates/entities/fragments/list.html:25
|
||||
#: templates/entities/fragments/table.html:16
|
||||
#: templates/installment_plans/fragments/table.html:16
|
||||
#: templates/recurring_transactions/fragments/table.html:18
|
||||
#: templates/rules/fragments/list.html:26 templates/tags/fragments/list.html:25
|
||||
#: templates/rules/fragments/list.html:26
|
||||
#: templates/tags/fragments/table.html:16
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
@@ -130,6 +131,9 @@ msgstr ""
|
||||
"mês."
|
||||
|
||||
#: apps/accounts/models.py:54 templates/accounts/fragments/list.html:30
|
||||
#: templates/categories/fragments/list.html:24
|
||||
#: templates/entities/fragments/list.html:24
|
||||
#: templates/tags/fragments/list.html:24
|
||||
msgid "Archived"
|
||||
msgstr "Arquivada"
|
||||
|
||||
@@ -141,7 +145,7 @@ msgstr ""
|
||||
#: apps/accounts/models.py:59 apps/rules/models.py:19
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:380
|
||||
#: apps/transactions/forms.py:622 apps/transactions/models.py:84
|
||||
#: apps/transactions/models.py:188 apps/transactions/models.py:385
|
||||
#: apps/transactions/models.py:188 apps/transactions/models.py:390
|
||||
msgid "Account"
|
||||
msgstr "Conta"
|
||||
|
||||
@@ -213,7 +217,7 @@ msgstr "Entidade com esse ID não existe."
|
||||
msgid "Invalid entity data. Provide an ID or name."
|
||||
msgstr "Dados da entidade inválidos. Forneça um ID ou nome."
|
||||
|
||||
#: apps/api/serializers/transactions.py:96
|
||||
#: apps/api/serializers/transactions.py:168
|
||||
msgid "Either 'date' or 'reference_date' must be provided."
|
||||
msgstr "É necessário fornecer “date” ou “reference_date”."
|
||||
|
||||
@@ -416,7 +420,7 @@ msgstr "Moeda de pagamento"
|
||||
|
||||
#: apps/dca/models.py:27 apps/dca/models.py:179 apps/rules/models.py:26
|
||||
#: apps/transactions/forms.py:250 apps/transactions/models.py:105
|
||||
#: apps/transactions/models.py:237 apps/transactions/models.py:413
|
||||
#: apps/transactions/models.py:237 apps/transactions/models.py:418
|
||||
msgid "Notes"
|
||||
msgstr "Notas"
|
||||
|
||||
@@ -513,7 +517,7 @@ msgstr "Já existe um valor para esse campo na regra."
|
||||
|
||||
#: apps/rules/models.py:10 apps/rules/models.py:25
|
||||
#: apps/transactions/forms.py:242 apps/transactions/models.py:104
|
||||
#: apps/transactions/models.py:195 apps/transactions/models.py:399
|
||||
#: apps/transactions/models.py:195 apps/transactions/models.py:404
|
||||
msgid "Description"
|
||||
msgstr "Descrição"
|
||||
|
||||
@@ -522,7 +526,7 @@ msgid "Trigger"
|
||||
msgstr "Gatilho"
|
||||
|
||||
#: apps/rules/models.py:20 apps/transactions/models.py:91
|
||||
#: apps/transactions/models.py:193 apps/transactions/models.py:391
|
||||
#: apps/transactions/models.py:193 apps/transactions/models.py:396
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
@@ -534,12 +538,12 @@ msgstr "Pago"
|
||||
#: apps/rules/models.py:23 apps/transactions/forms.py:62
|
||||
#: apps/transactions/forms.py:241 apps/transactions/forms.py:407
|
||||
#: apps/transactions/forms.py:649 apps/transactions/models.py:95
|
||||
#: apps/transactions/models.py:211 apps/transactions/models.py:415
|
||||
#: apps/transactions/models.py:211 apps/transactions/models.py:420
|
||||
msgid "Reference Date"
|
||||
msgstr "Data de Referência"
|
||||
|
||||
#: apps/rules/models.py:24 apps/transactions/models.py:100
|
||||
#: apps/transactions/models.py:396
|
||||
#: apps/transactions/models.py:401
|
||||
msgid "Amount"
|
||||
msgstr "Quantia"
|
||||
|
||||
@@ -547,7 +551,7 @@ msgstr "Quantia"
|
||||
#: apps/transactions/forms.py:55 apps/transactions/forms.py:403
|
||||
#: apps/transactions/forms.py:645 apps/transactions/models.py:69
|
||||
#: apps/transactions/models.py:120 apps/transactions/models.py:233
|
||||
#: apps/transactions/models.py:410 templates/entities/fragments/list.html:5
|
||||
#: apps/transactions/models.py:415 templates/entities/fragments/list.html:5
|
||||
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:100
|
||||
msgid "Entities"
|
||||
msgstr "Entidades"
|
||||
@@ -682,8 +686,10 @@ msgid "Mute"
|
||||
msgstr "Silenciada"
|
||||
|
||||
#: apps/transactions/models.py:23 apps/transactions/models.py:42
|
||||
#: apps/transactions/models.py:61
|
||||
#: apps/transactions/models.py:61 templates/categories/fragments/list.html:21
|
||||
#: templates/entities/fragments/list.html:21
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
@@ -747,7 +753,7 @@ msgstr "Despesa"
|
||||
msgid "Installment Plan"
|
||||
msgstr "Parcelamento"
|
||||
|
||||
#: apps/transactions/models.py:140 apps/transactions/models.py:436
|
||||
#: apps/transactions/models.py:140 apps/transactions/models.py:441
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Transação Recorrente"
|
||||
|
||||
@@ -792,11 +798,11 @@ msgstr "Parcela inicial"
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "O número da parcela a partir do qual se inicia a contagem"
|
||||
|
||||
#: apps/transactions/models.py:209 apps/transactions/models.py:419
|
||||
#: apps/transactions/models.py:209 apps/transactions/models.py:424
|
||||
msgid "Start Date"
|
||||
msgstr "Data de Início"
|
||||
|
||||
#: apps/transactions/models.py:213 apps/transactions/models.py:420
|
||||
#: apps/transactions/models.py:213 apps/transactions/models.py:425
|
||||
msgid "End Date"
|
||||
msgstr "Data Final"
|
||||
|
||||
@@ -814,44 +820,44 @@ msgstr "Valor da Parcela"
|
||||
msgid "Installment Plans"
|
||||
msgstr "Parcelamentos"
|
||||
|
||||
#: apps/transactions/models.py:378
|
||||
#: apps/transactions/models.py:383
|
||||
msgid "day(s)"
|
||||
msgstr "dia(s)"
|
||||
|
||||
#: apps/transactions/models.py:379
|
||||
#: apps/transactions/models.py:384
|
||||
msgid "week(s)"
|
||||
msgstr "semana(s)"
|
||||
|
||||
#: apps/transactions/models.py:380
|
||||
#: apps/transactions/models.py:385
|
||||
msgid "month(s)"
|
||||
msgstr "mês(es)"
|
||||
|
||||
#: apps/transactions/models.py:381
|
||||
#: apps/transactions/models.py:386
|
||||
msgid "year(s)"
|
||||
msgstr "ano(s)"
|
||||
|
||||
#: apps/transactions/models.py:383
|
||||
#: apps/transactions/models.py:388
|
||||
#: templates/recurring_transactions/fragments/list.html:24
|
||||
msgid "Paused"
|
||||
msgstr "Pausado"
|
||||
|
||||
#: apps/transactions/models.py:422
|
||||
#: apps/transactions/models.py:427
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Tipo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:425
|
||||
#: apps/transactions/models.py:430
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Intervalo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:429
|
||||
#: apps/transactions/models.py:434
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Última data gerada"
|
||||
|
||||
#: apps/transactions/models.py:432
|
||||
#: apps/transactions/models.py:437
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Última data de referência gerada"
|
||||
|
||||
#: apps/transactions/models.py:437 templates/includes/navbar.html:64
|
||||
#: apps/transactions/models.py:442 templates/includes/navbar.html:64
|
||||
#: templates/recurring_transactions/fragments/list.html:5
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
@@ -867,27 +873,27 @@ msgstr "%(value)s tem muitas casas decimais. O máximo é 30."
|
||||
msgid "%(value)s is not a non-negative number"
|
||||
msgstr "%(value)s não é um número positivo"
|
||||
|
||||
#: apps/transactions/views/categories.py:44
|
||||
#: apps/transactions/views/categories.py:66
|
||||
msgid "Category added successfully"
|
||||
msgstr "Categoria adicionada com sucesso"
|
||||
|
||||
#: apps/transactions/views/categories.py:72
|
||||
#: apps/transactions/views/categories.py:94
|
||||
msgid "Category updated successfully"
|
||||
msgstr "Categoria atualizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/categories.py:99
|
||||
#: apps/transactions/views/categories.py:121
|
||||
msgid "Category deleted successfully"
|
||||
msgstr "Categoria apagada com sucesso"
|
||||
|
||||
#: apps/transactions/views/entities.py:43
|
||||
#: apps/transactions/views/entities.py:65
|
||||
msgid "Entity added successfully"
|
||||
msgstr "Entidade adicionada com sucesso"
|
||||
|
||||
#: apps/transactions/views/entities.py:71
|
||||
#: apps/transactions/views/entities.py:93
|
||||
msgid "Entity updated successfully"
|
||||
msgstr "Entidade atualizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/entities.py:98
|
||||
#: apps/transactions/views/entities.py:120
|
||||
msgid "Entity deleted successfully"
|
||||
msgstr "Entidade apagada com sucesso"
|
||||
|
||||
@@ -915,31 +921,31 @@ msgstr "Transação Recorrente adicionada com sucesso"
|
||||
msgid "Recurring Transaction updated successfully"
|
||||
msgstr "Transação Recorrente atualizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/recurring_transactions.py:174
|
||||
#: apps/transactions/views/recurring_transactions.py:188
|
||||
msgid "Recurring transaction unpaused successfully"
|
||||
msgstr "Transação Recorrente despausada com sucesso"
|
||||
|
||||
#: apps/transactions/views/recurring_transactions.py:177
|
||||
#: apps/transactions/views/recurring_transactions.py:191
|
||||
msgid "Recurring transaction paused successfully"
|
||||
msgstr "Transação Recorrente pausada com sucesso"
|
||||
|
||||
#: apps/transactions/views/recurring_transactions.py:200
|
||||
#: apps/transactions/views/recurring_transactions.py:217
|
||||
msgid "Recurring transaction finished successfully"
|
||||
msgstr "Transação Recorrente finalizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/recurring_transactions.py:221
|
||||
#: apps/transactions/views/recurring_transactions.py:238
|
||||
msgid "Recurring Transaction deleted successfully"
|
||||
msgstr "Transação Recorrente apagada com sucesso"
|
||||
|
||||
#: apps/transactions/views/tags.py:43
|
||||
#: apps/transactions/views/tags.py:65
|
||||
msgid "Tag added successfully"
|
||||
msgstr "Tag adicionada com sucesso"
|
||||
|
||||
#: apps/transactions/views/tags.py:71
|
||||
#: apps/transactions/views/tags.py:93
|
||||
msgid "Tag updated successfully"
|
||||
msgstr "Tag atualizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/tags.py:98
|
||||
#: apps/transactions/views/tags.py:120
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "Tag apagada com sucesso"
|
||||
|
||||
@@ -1065,62 +1071,63 @@ msgstr "Editar grupo de conta"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:32
|
||||
#: templates/accounts/fragments/list.html:37
|
||||
#: templates/categories/fragments/list.html:33
|
||||
#: templates/categories/fragments/table.html:24
|
||||
#: templates/currencies/fragments/list.html:33
|
||||
#: templates/dca/fragments/strategy/details.html:63
|
||||
#: templates/entities/fragments/list.html:32
|
||||
#: templates/entities/fragments/table.html:23
|
||||
#: templates/exchange_rates/fragments/table.html:19
|
||||
#: templates/installment_plans/fragments/table.html:23
|
||||
#: templates/recurring_transactions/fragments/table.html:25
|
||||
#: templates/rules/fragments/list.html:33 templates/tags/fragments/list.html:32
|
||||
#: templates/rules/fragments/list.html:33
|
||||
#: templates/tags/fragments/table.html:23
|
||||
msgid "Actions"
|
||||
msgstr "Ações"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:36
|
||||
#: templates/accounts/fragments/list.html:41
|
||||
#: templates/categories/fragments/list.html:37
|
||||
#: templates/categories/fragments/table.html:29
|
||||
#: templates/cotton/transaction/item.html:109
|
||||
#: templates/currencies/fragments/list.html:37
|
||||
#: templates/dca/fragments/strategy/details.html:67
|
||||
#: templates/dca/fragments/strategy/list.html:34
|
||||
#: templates/entities/fragments/list.html:36
|
||||
#: templates/entities/fragments/table.html:28
|
||||
#: templates/exchange_rates/fragments/table.html:23
|
||||
#: templates/installment_plans/fragments/table.html:27
|
||||
#: templates/recurring_transactions/fragments/table.html:29
|
||||
#: templates/rules/fragments/transaction_rule/view.html:22
|
||||
#: templates/rules/fragments/transaction_rule/view.html:48
|
||||
#: templates/tags/fragments/list.html:36
|
||||
#: templates/tags/fragments/table.html:28
|
||||
msgid "Edit"
|
||||
msgstr "Editar"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:43
|
||||
#: templates/accounts/fragments/list.html:48
|
||||
#: templates/categories/fragments/list.html:44
|
||||
#: templates/categories/fragments/table.html:36
|
||||
#: templates/cotton/transaction/item.html:116
|
||||
#: templates/cotton/ui/transactions_action_bar.html:50
|
||||
#: templates/currencies/fragments/list.html:44
|
||||
#: templates/dca/fragments/strategy/details.html:75
|
||||
#: templates/dca/fragments/strategy/list.html:42
|
||||
#: templates/entities/fragments/list.html:43
|
||||
#: templates/entities/fragments/table.html:36
|
||||
#: templates/exchange_rates/fragments/table.html:31
|
||||
#: templates/installment_plans/fragments/table.html:56
|
||||
#: templates/mini_tools/unit_price_calculator.html:18
|
||||
#: templates/recurring_transactions/fragments/table.html:91
|
||||
#: templates/rules/fragments/list.html:44
|
||||
#: templates/rules/fragments/transaction_rule/view.html:56
|
||||
#: templates/tags/fragments/list.html:43
|
||||
#: templates/tags/fragments/table.html:36
|
||||
msgid "Delete"
|
||||
msgstr "Apagar"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:47
|
||||
#: templates/accounts/fragments/list.html:52
|
||||
#: templates/categories/fragments/list.html:48
|
||||
#: templates/categories/fragments/table.html:41
|
||||
#: templates/cotton/transaction/item.html:120
|
||||
#: templates/cotton/ui/transactions_action_bar.html:52
|
||||
#: templates/currencies/fragments/list.html:48
|
||||
#: templates/dca/fragments/strategy/details.html:80
|
||||
#: templates/dca/fragments/strategy/list.html:46
|
||||
#: templates/entities/fragments/list.html:47
|
||||
#: templates/entities/fragments/table.html:40
|
||||
#: templates/exchange_rates/fragments/table.html:36
|
||||
#: templates/installment_plans/fragments/table.html:48
|
||||
#: templates/installment_plans/fragments/table.html:60
|
||||
@@ -1130,40 +1137,40 @@ msgstr "Apagar"
|
||||
#: templates/recurring_transactions/fragments/table.html:96
|
||||
#: templates/rules/fragments/list.html:48
|
||||
#: templates/rules/fragments/transaction_rule/view.html:60
|
||||
#: templates/tags/fragments/list.html:47
|
||||
#: templates/tags/fragments/table.html:40
|
||||
msgid "Are you sure?"
|
||||
msgstr "Tem certeza?"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:48
|
||||
#: templates/accounts/fragments/list.html:53
|
||||
#: templates/categories/fragments/list.html:49
|
||||
#: templates/categories/fragments/table.html:42
|
||||
#: templates/cotton/transaction/item.html:121
|
||||
#: templates/cotton/ui/transactions_action_bar.html:53
|
||||
#: templates/currencies/fragments/list.html:49
|
||||
#: templates/dca/fragments/strategy/details.html:81
|
||||
#: templates/dca/fragments/strategy/list.html:47
|
||||
#: templates/entities/fragments/list.html:48
|
||||
#: templates/entities/fragments/table.html:41
|
||||
#: templates/exchange_rates/fragments/table.html:37
|
||||
#: templates/rules/fragments/list.html:49
|
||||
#: templates/rules/fragments/transaction_rule/view.html:61
|
||||
#: templates/tags/fragments/list.html:48
|
||||
#: templates/tags/fragments/table.html:41
|
||||
msgid "You won't be able to revert this!"
|
||||
msgstr "Você não será capaz de reverter isso!"
|
||||
|
||||
#: templates/account_groups/fragments/list.html:49
|
||||
#: templates/accounts/fragments/list.html:54
|
||||
#: templates/categories/fragments/list.html:50
|
||||
#: templates/categories/fragments/table.html:43
|
||||
#: templates/cotton/transaction/item.html:122
|
||||
#: templates/currencies/fragments/list.html:50
|
||||
#: templates/dca/fragments/strategy/details.html:82
|
||||
#: templates/dca/fragments/strategy/list.html:48
|
||||
#: templates/entities/fragments/list.html:49
|
||||
#: templates/entities/fragments/table.html:42
|
||||
#: templates/exchange_rates/fragments/table.html:38
|
||||
#: templates/installment_plans/fragments/table.html:62
|
||||
#: templates/recurring_transactions/fragments/table.html:98
|
||||
#: templates/rules/fragments/list.html:50
|
||||
#: templates/rules/fragments/transaction_rule/view.html:62
|
||||
#: templates/tags/fragments/list.html:49
|
||||
#: templates/tags/fragments/table.html:42
|
||||
msgid "Yes, delete it!"
|
||||
msgstr "Sim, apague!"
|
||||
|
||||
@@ -1273,11 +1280,11 @@ msgstr "Adicionar categoria"
|
||||
msgid "Edit category"
|
||||
msgstr "Editar categoria"
|
||||
|
||||
#: templates/categories/fragments/list.html:26
|
||||
#: templates/categories/fragments/table.html:17
|
||||
msgid "Muted"
|
||||
msgstr "Silenciada"
|
||||
|
||||
#: templates/categories/fragments/list.html:63
|
||||
#: templates/categories/fragments/table.html:57
|
||||
msgid "No categories"
|
||||
msgstr "Nenhum categoria"
|
||||
|
||||
@@ -1337,10 +1344,44 @@ msgstr "Marcar como não pago"
|
||||
msgid "Yes, delete them!"
|
||||
msgstr "Sim, apague!"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:81
|
||||
#: templates/cotton/ui/transactions_action_bar.html:101
|
||||
#: templates/cotton/ui/transactions_action_bar.html:125
|
||||
#: templates/cotton/ui/transactions_action_bar.html:145
|
||||
#: templates/cotton/ui/transactions_action_bar.html:165
|
||||
#: templates/cotton/ui/transactions_action_bar.html:185
|
||||
#: templates/cotton/ui/transactions_action_bar.html:205
|
||||
#: templates/cotton/ui/transactions_action_bar.html:225
|
||||
msgid "copied!"
|
||||
msgstr "copiado!"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:110
|
||||
msgid "Toggle Dropdown"
|
||||
msgstr "Alternar menu suspenso"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:118
|
||||
msgid "Flat Total"
|
||||
msgstr "Total Fixo"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:138
|
||||
msgid "Real Total"
|
||||
msgstr "Total Real"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:158
|
||||
msgid "Mean"
|
||||
msgstr "Média"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:178
|
||||
msgid "Max"
|
||||
msgstr "Máximo"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:198
|
||||
msgid "Min"
|
||||
msgstr "Minímo"
|
||||
|
||||
#: templates/cotton/ui/transactions_action_bar.html:218
|
||||
msgid "Count"
|
||||
msgstr "Contagem"
|
||||
|
||||
#: templates/currencies/fragments/add.html:5
|
||||
msgid "Add currency"
|
||||
msgstr "Adicionar moeda"
|
||||
@@ -1479,7 +1520,7 @@ msgstr "Adicionar entidade"
|
||||
msgid "Edit entity"
|
||||
msgstr "Editar entidade"
|
||||
|
||||
#: templates/entities/fragments/list.html:59
|
||||
#: templates/entities/fragments/table.html:53
|
||||
msgid "No entities"
|
||||
msgstr "Sem entidades"
|
||||
|
||||
@@ -1800,8 +1841,12 @@ msgid "Finish"
|
||||
msgstr "Finalizar"
|
||||
|
||||
#: templates/recurring_transactions/fragments/table.html:83
|
||||
msgid "This will stop the creation of new transactions"
|
||||
msgstr "Isso interromperá a criação de novas transações"
|
||||
msgid ""
|
||||
"This will stop the creation of new transactions and delete any unpaid "
|
||||
"transactions after today"
|
||||
msgstr ""
|
||||
"Isso interromperá a criação de novas transações e apagará transações não "
|
||||
"pagas depois de hoje"
|
||||
|
||||
#: templates/recurring_transactions/fragments/table.html:84
|
||||
msgid "Yes, finish it!"
|
||||
@@ -1884,7 +1929,7 @@ msgstr "Adicionar tag"
|
||||
msgid "Edit tag"
|
||||
msgstr "Editar tag"
|
||||
|
||||
#: templates/tags/fragments/list.html:59
|
||||
#: templates/tags/fragments/table.html:53
|
||||
msgid "No tags"
|
||||
msgstr "Nenhuma tag"
|
||||
|
||||
@@ -1987,6 +2032,9 @@ msgstr "Visão Anual"
|
||||
msgid "Year"
|
||||
msgstr "Ano"
|
||||
|
||||
#~ msgid "This will stop the creation of new transactions"
|
||||
#~ msgstr "Isso interromperá a criação de novas transações"
|
||||
|
||||
#~ msgid "Is an asset account?"
|
||||
#~ msgstr "É uma conta de ativos?"
|
||||
|
||||
|
||||
@@ -15,53 +15,18 @@
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body table-responsive">
|
||||
{% if categories %}
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
<th scope="col" class="col">{% translate 'Muted' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
<tr class="category">
|
||||
<td class="col-auto text-center">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'category_edit' category_id=category.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'category_delete' category_id=category.id %}"
|
||||
hx-trigger='confirmed'
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ category.name }}</td>
|
||||
<td class="col">
|
||||
{% if category.mute %}<i class="fa-solid fa-check text-success"></i>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No categories" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'categories_table_active' %}" hx-trigger="load, click" hx-target="#categories-table">{% translate 'Active' %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" hx-get="{% url 'categories_table_archived' %}" hx-target="#categories-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="categories-table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
59
app/templates/categories/fragments/table.html
Normal file
59
app/templates/categories/fragments/table.html
Normal file
@@ -0,0 +1,59 @@
|
||||
{% load i18n %}
|
||||
{% if active %}
|
||||
<div class="show-loading" hx-get="{% url 'categories_table_active' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% else %}
|
||||
<div class="show-loading" hx-get="{% url 'categories_table_archived' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% endif %}
|
||||
{% if categories %}
|
||||
<div class="table-responsive">
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
<th scope="col" class="col">{% translate 'Muted' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
<tr class="category">
|
||||
<td class="col-auto text-center">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'category_edit' category_id=category.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'category_delete' category_id=category.id %}"
|
||||
hx-trigger='confirmed'
|
||||
hx-swap="innerHTML"
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ category.name }}</td>
|
||||
<td class="col">
|
||||
{% if category.mute %}<i class="fa-solid fa-check text-success"></i>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No categories" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -4,5 +4,5 @@
|
||||
{% block title %}{% translate 'Categories' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div hx-get="{% url 'categories_list' %}" hx-trigger="load, updated from:window" class="show-loading"></div>
|
||||
<div hx-get="{% url 'categories_list' %}" hx-trigger="load" class="show-loading"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -11,78 +11,228 @@
|
||||
<div class="card slide-in-left">
|
||||
<div class="card-body p-2">
|
||||
{% spaceless %}
|
||||
<div class="btn-group" role="group">
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Select All' %}"
|
||||
_="on click set <#transactions-list input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square-check tw-text-green-400"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Unselect All' %}"
|
||||
_="on click set <#transactions-list input[type='checkbox']/>'s checked to false then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square tw-text-red-400"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="vr mx-3 tw-align-middle"></div>
|
||||
<div class="btn-group me-3" role="group">
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_pay' %}"
|
||||
hx-include=".transaction"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Mark as paid' %}">
|
||||
<i class="fa-regular fa-circle-check tw-text-green-400"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_unpay' %}"
|
||||
hx-include=".transaction"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Mark as unpaid' %}">
|
||||
<i class="fa-regular fa-circle tw-text-red-400"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Select All' %}"
|
||||
_="on click set <#transactions-list input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square-check tw-text-green-400"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Unselect All' %}"
|
||||
_="on click set <#transactions-list input[type='checkbox']/>'s checked to false then call me.blur() then trigger change">
|
||||
<i class="fa-regular fa-square tw-text-red-400"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="vr mx-3 tw-align-middle"></div>
|
||||
<div class="btn-group me-3" role="group">
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_pay' %}"
|
||||
hx-include=".transaction"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Mark as paid' %}">
|
||||
<i class="fa-regular fa-circle-check tw-text-green-400"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_unpay' %}"
|
||||
hx-get="{% url 'transactions_bulk_delete' %}"
|
||||
hx-include=".transaction"
|
||||
hx-trigger="confirmed"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Mark as unpaid' %}">
|
||||
<i class="fa-regular fa-circle tw-text-red-400"></i>
|
||||
data-bs-title="{% translate 'Delete' %}"
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete them!" %}"
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-trash text-danger"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-sm"
|
||||
hx-get="{% url 'transactions_bulk_delete' %}"
|
||||
hx-include=".transaction"
|
||||
hx-trigger="confirmed"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate 'Delete' %}"
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete them!" %}"
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-trash text-danger"></i>
|
||||
</button>
|
||||
<div class="vr mx-3 tw-align-middle"></div>
|
||||
<span _="on selected_transactions_updated from #actions-bar
|
||||
set realTotal to 0.0
|
||||
set flatTotal to 0.0
|
||||
for transaction in <.transaction:has(input[name='transactions']:checked)/>
|
||||
set amt to first <.main-amount .amount/> in transaction
|
||||
set amountValue to parseFloat(amt.getAttribute('data-amount'))
|
||||
if not isNaN(amountValue)
|
||||
set flatTotal to flatTotal + (amountValue * 100)
|
||||
<div class="vr mx-3 tw-align-middle"></div>
|
||||
<div class="btn-group"
|
||||
_="on selected_transactions_updated from #actions-bar
|
||||
set realTotal to math.bignumber(0)
|
||||
set flatTotal to math.bignumber(0)
|
||||
set transactions to <.transaction:has(input[name='transactions']:checked)/>
|
||||
set flatAmountValues to []
|
||||
set realAmountValues to []
|
||||
|
||||
if transaction match .income
|
||||
set realTotal to realTotal + (amountValue * 100)
|
||||
else
|
||||
set realTotal to realTotal - (amountValue * 100)
|
||||
for transaction in transactions
|
||||
set amt to first <.main-amount .amount/> in transaction
|
||||
set amountValue to parseFloat(amt.getAttribute('data-amount'))
|
||||
append amountValue to flatAmountValues
|
||||
|
||||
if not isNaN(amountValue)
|
||||
set flatTotal to math.chain(flatTotal).add(amountValue)
|
||||
|
||||
if transaction match .income
|
||||
append amountValue to realAmountValues
|
||||
set realTotal to math.chain(realTotal).add(amountValue)
|
||||
else
|
||||
append -amountValue to realAmountValues
|
||||
set realTotal to math.chain(realTotal).subtract(amountValue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
set realTotal to realTotal / 100
|
||||
put realTotal.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into me
|
||||
end
|
||||
on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end"
|
||||
class="" role="button"></span>
|
||||
|
||||
set mean to flatTotal.divide(flatAmountValues.length).done().toNumber()
|
||||
set realTotal to realTotal.done().toNumber()
|
||||
set flatTotal to flatTotal.done().toNumber()
|
||||
|
||||
put realTotal.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #real-total-front's innerText
|
||||
put realTotal.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-real-total's innerText
|
||||
put flatTotal.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-flat-total's innerText
|
||||
put Math.max.apply(Math, realAmountValues).toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-max's innerText
|
||||
put Math.min.apply(Math, realAmountValues).toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-min's innerText
|
||||
put mean.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-mean's innerText
|
||||
put flatAmountValues.length.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40}) into #calc-menu-count's innerText
|
||||
end"
|
||||
>
|
||||
<button class="btn btn-secondary btn-sm" _="on click
|
||||
set original_value to #real-total-front's innerText
|
||||
writeText(original_value) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into #real-total-front's innerText
|
||||
wait 1s
|
||||
put original_value into #real-total-front's innerText
|
||||
end">
|
||||
<i class="fa-solid fa-plus fa-fw me-2 text-primary"></i>
|
||||
<span id="real-total-front">0</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside">
|
||||
<span class="visually-hidden">{% trans "Toggle Dropdown" %}</span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Flat Total" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-flat-total"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Real Total" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-real-total"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Mean" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-mean"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Max" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-max"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Min" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-min"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item-text p-0">
|
||||
<div>
|
||||
<div class="text-body-secondary tw-text-xs tw-font-medium px-3">
|
||||
{% trans "Count" %}
|
||||
</div>
|
||||
<div class="dropdown-item px-3 tw-cursor-pointer"
|
||||
id="calc-menu-count"
|
||||
_="on click
|
||||
set original_value to my innerText
|
||||
writeText(my innerText) on navigator.clipboard
|
||||
put '{% translate "copied!" %}' into me
|
||||
wait 1s
|
||||
put original_value into me
|
||||
end">
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,49 +15,18 @@
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body table-responsive">
|
||||
{% if entities %}
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entity in entities %}
|
||||
<tr class="entity">
|
||||
<td class="col-auto">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'entity_edit' entity_id=entity.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'entity_delete' entity_id=entity.id %}"
|
||||
hx-trigger='confirmed'
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ entity.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No entities" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'entities_table_active' %}" hx-trigger="load, click" hx-target="#entities-table">{% translate 'Active' %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" hx-get="{% url 'entities_table_archived' %}" hx-target="#entities-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="entities-table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
55
app/templates/entities/fragments/table.html
Normal file
55
app/templates/entities/fragments/table.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% load i18n %}
|
||||
{% if active %}
|
||||
<div class="show-loading" hx-get="{% url 'entities_table_active' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% else %}
|
||||
<div class="show-loading" hx-get="{% url 'entities_table_archived' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% endif %}
|
||||
{% if entities %}
|
||||
<div class="table-responsive">
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entity in entities %}
|
||||
<tr class="entity">
|
||||
<td class="col-auto">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'entity_edit' entity_id=entity.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'entity_delete' entity_id=entity.id %}"
|
||||
hx-trigger='confirmed'
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ entity.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No entities" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -4,5 +4,5 @@
|
||||
{% block title %}{% translate 'Entities' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div hx-get="{% url 'entities_list' %}" hx-trigger="load, updated from:window" class="show-loading"></div>
|
||||
<div hx-get="{% url 'entities_list' %}" hx-trigger="load" class="show-loading"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -66,11 +66,10 @@
|
||||
})
|
||||
end
|
||||
then set expr to it
|
||||
then call math.evaluate(expr)
|
||||
then call math.evaluate(expr).toNumber()
|
||||
if result exists and result is a Number
|
||||
js(result)
|
||||
return result.toString().replace(new RegExp(',|\\.', 'g'),
|
||||
match => match === '.' ? window.decimalSeparator : window.argSeparator)
|
||||
return result.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 40})
|
||||
end
|
||||
then set localizedResult to it
|
||||
set #calculator-result.innerText to localizedResult
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% block title %}{% if type == "current" %}{% translate 'Current Net Worth' %}{% else %}{% translate 'Projected Net Worth' %}{% endif %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container px-md-3 py-3" _="on load call initializeAccountChart() then initializeCurrencyChart()">
|
||||
<div class="container px-md-3 py-3" _="init call initializeAccountChart() then initializeCurrencyChart() end">
|
||||
<div class="row gx-xl-4 gy-3 mb-4">
|
||||
<div class="col-12 col-xl-5">
|
||||
<div class="row row-cols-1 g-4">
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
hx-swap="innerHTML"
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "This will stop the creation of new transactions" %}"
|
||||
data-text="{% translate "This will stop the creation of new transactions and delete any unpaid transactions after today" %}"
|
||||
data-confirm-text="{% translate "Yes, finish it!" %}"
|
||||
_="install prompt_swal">
|
||||
<i class="fa-solid fa-flag-checkered fa-fw"></i></a>
|
||||
|
||||
@@ -15,49 +15,18 @@
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body table-responsive">
|
||||
{% if tags %}
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for tag in tags %}
|
||||
<tr class="tag">
|
||||
<td class="col-auto">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'tag_edit' tag_id=tag.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'tag_delete' tag_id=tag.id %}"
|
||||
hx-trigger='confirmed'
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ tag.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No tags" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-pills card-header-pills" id="myTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" hx-get="{% url 'tags_table_active' %}" hx-trigger="load, click" hx-target="#tags-table">{% translate 'Active' %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" hx-get="{% url 'tags_table_archived' %}" hx-target="#tags-table" data-bs-toggle="tab" type="button" role="tab" aria-selected="false">{% translate 'Archived' %}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="tags-table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
55
app/templates/tags/fragments/table.html
Normal file
55
app/templates/tags/fragments/table.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% load i18n %}
|
||||
{% if active %}
|
||||
<div class="show-loading" hx-get="{% url 'tags_table_active' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% else %}
|
||||
<div class="show-loading" hx-get="{% url 'tags_table_archived' %}" hx-trigger="updated from:window"
|
||||
hx-swap="outerHTML">
|
||||
{% endif %}
|
||||
{% if tags %}
|
||||
<div class="table-responsive">
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for tag in tags %}
|
||||
<tr class="tag">
|
||||
<td class="col-auto">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'tag_edit' tag_id=tag.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
<a class="btn btn-secondary btn-sm text-danger"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-title="{% translate "Delete" %}"
|
||||
hx-delete="{% url 'tag_delete' tag_id=tag.id %}"
|
||||
hx-trigger='confirmed'
|
||||
data-bypass-on-ctrl="true"
|
||||
data-title="{% translate "Are you sure?" %}"
|
||||
data-text="{% translate "You won't be able to revert this!" %}"
|
||||
data-confirm-text="{% translate "Yes, delete it!" %}"
|
||||
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">{{ tag.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No tags" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -4,5 +4,5 @@
|
||||
{% block title %}{% translate 'Tags' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div hx-get="{% url 'tags_list' %}" hx-trigger="load, updated from:window" class="show-loading"></div>
|
||||
<div hx-get="{% url 'tags_list' %}" hx-trigger="load" class="show-loading"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,18 +2,23 @@ import _hyperscript from 'hyperscript.org/dist/_hyperscript.min';
|
||||
import './_htmx.js';
|
||||
import Alpine from "alpinejs";
|
||||
import mask from '@alpinejs/mask';
|
||||
import { create, all } from 'mathjs';
|
||||
import {create, all} from 'mathjs';
|
||||
|
||||
window.Alpine = Alpine;
|
||||
window._hyperscript = _hyperscript;
|
||||
window.math = create(all, { });
|
||||
window.math = create(all, {
|
||||
number: 'BigNumber', // Default type of number:
|
||||
// 'number' (default), 'BigNumber', or 'Fraction'
|
||||
precision: 64, // Number of significant digits for BigNumbers
|
||||
relTol: 1e-60,
|
||||
absTol: 1e-63
|
||||
});
|
||||
|
||||
Alpine.plugin(mask);
|
||||
Alpine.start();
|
||||
_hyperscript.browserInit();
|
||||
|
||||
|
||||
|
||||
const successAudio = new Audio("/static/sounds/success.mp3");
|
||||
const popAudio = new Audio("/static/sounds/pop.mp3");
|
||||
window.paidSound = successAudio;
|
||||
|
||||
Reference in New Issue
Block a user