diff --git a/app/apps/common/widgets/datepicker.py b/app/apps/common/widgets/datepicker.py index a9ee922..dd54885 100644 --- a/app/apps/common/widgets/datepicker.py +++ b/app/apps/common/widgets/datepicker.py @@ -227,3 +227,56 @@ class AirMonthYearPickerInput(AirDatePickerInput): except (ValueError, KeyError): return None return None + + +class AirYearPickerInput(AirDatePickerInput): + def __init__(self, attrs=None, format=None, *args, **kwargs): + super().__init__(attrs=attrs, format=format, *args, **kwargs) + # Store the display format for AirDatepicker + self.display_format = "yyyy" + # Store the Python format for internal use + self.python_format = "%Y" + + def build_attrs(self, base_attrs, extra_attrs=None): + attrs = super().build_attrs(base_attrs, extra_attrs) + + # Add data attributes for AirDatepicker configuration + attrs["data-now-button-txt"] = _("Today") + attrs["data-date-format"] = "yyyy" + + return attrs + + def format_value(self, value): + """Format the value for display in the widget.""" + if value: + self.attrs["data-value"] = ( + value # We use this to dynamically select the initial date on AirDatePicker + ) + + if value is None: + return "" + if isinstance(value, str): + try: + value = datetime.datetime.strptime(value, "%Y-%m-%d").date() + except ValueError: + return value + if isinstance(value, (datetime.datetime, datetime.date)): + # Use Django's date translation + return f"{value.year}" + return value + + def value_from_datadict(self, data, files, name): + """Convert the value from the widget format back to a format Django can handle.""" + value = super().value_from_datadict(data, files, name) + if value: + try: + # Split the value into month name and year + year_str = value + year = int(year_str) + + if year: + # Return the first day of the month in Django's expected format + return datetime.date(year, 1, 1).strftime("%Y-%m-%d") + except (ValueError, KeyError): + return None + return None diff --git a/app/apps/insights/forms.py b/app/apps/insights/forms.py new file mode 100644 index 0000000..12ce0d2 --- /dev/null +++ b/app/apps/insights/forms.py @@ -0,0 +1,110 @@ +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout, Field, Row, Column +from django import forms +from django.utils.translation import gettext_lazy as _ + +from apps.common.widgets.datepicker import ( + AirMonthYearPickerInput, + AirYearPickerInput, + AirDatePickerInput, +) + + +class SingleMonthForm(forms.Form): + month = forms.DateField( + widget=AirMonthYearPickerInput(clear_button=False), label="", required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.disable_csrf = True + + self.helper.layout = Layout(Field("month")) + + +class SingleYearForm(forms.Form): + year = forms.DateField( + widget=AirYearPickerInput(clear_button=False), label="", required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.disable_csrf = True + + self.helper.layout = Layout(Field("year")) + + +class MonthRangeForm(forms.Form): + month_from = forms.DateField( + widget=AirMonthYearPickerInput(clear_button=False), label="", required=False + ) + month_to = forms.DateField( + widget=AirMonthYearPickerInput(clear_button=False), label="", required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.disable_csrf = True + + self.helper.layout = Layout( + Row( + Column("month_from", css_class="form-group col-md-6"), + Column("month_to", css_class="form-group col-md-6"), + ), + ) + + +class YearRangeForm(forms.Form): + year_from = forms.DateField( + widget=AirYearPickerInput(clear_button=False), label="", required=False + ) + year_to = forms.DateField( + widget=AirYearPickerInput(clear_button=False), label="", required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.disable_csrf = True + + self.helper.layout = Layout( + Row( + Column("year_from", css_class="form-group col-md-6"), + Column("year_to", css_class="form-group col-md-6"), + ), + ) + + +class DateRangeForm(forms.Form): + date_from = forms.DateField( + widget=AirDatePickerInput(clear_button=False), label="", required=False + ) + date_to = forms.DateField( + widget=AirDatePickerInput(clear_button=False), label="", required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_tag = False + self.helper.disable_csrf = True + + self.helper.layout = Layout( + Row( + Column("date_from", css_class="form-group col-md-6"), + Column("date_to", css_class="form-group col-md-6"), + css_class="mb-0", + ), + ) diff --git a/app/apps/insights/urls.py b/app/apps/insights/urls.py index ed73eb0..66ed5f6 100644 --- a/app/apps/insights/urls.py +++ b/app/apps/insights/urls.py @@ -4,5 +4,14 @@ from . import views urlpatterns = [ path("insights/", views.index, name="insights_index"), - path("insights/sankey/", views.sankey, name="sankey"), + path( + "insights/sankey/account/", + views.sankey_by_account, + name="insights_sankey_by_account", + ), + path( + "insights/sankey/currency/", + views.sankey_by_currency, + name="insights_sankey_by_currency", + ), ] diff --git a/app/apps/insights/utils/sankey.py b/app/apps/insights/utils/sankey.py index 05e1fc2..0feed4a 100644 --- a/app/apps/insights/utils/sankey.py +++ b/app/apps/insights/utils/sankey.py @@ -1,4 +1,3 @@ -from django.db.models import Sum from django.utils.translation import gettext_lazy as _ from decimal import Decimal from typing import Dict, List, TypedDict @@ -17,41 +16,64 @@ class SankeyFlow(TypedDict): percentage: float -def generate_sankey_data(transactions_queryset): +def generate_sankey_data_by_account(transactions_queryset): """ - Generates Sankey diagram data from transaction queryset. - Uses a 1-5 scale for flows based on percentages. + Generates Sankey diagram data from transaction queryset using account as intermediary. """ - nodes: Dict[str, SankeyNode] = {} + nodes: Dict[str, Dict] = {} flows: List[SankeyFlow] = [] # Aggregate transactions income_data = {} # {(category, currency, account) -> amount} expense_data = {} # {(category, currency, account) -> amount} - total_amount = Decimal("0") + total_income_by_currency = {} # {currency -> amount} + total_expense_by_currency = {} # {currency -> amount} + total_volume_by_currency = {} # {currency -> amount} for transaction in transactions_queryset: currency = transaction.account.currency account = transaction.account category = transaction.category or _("Uncategorized") - key = (category, currency, account) + amount = transaction.amount if transaction.type == "IN": - income_data[key] = income_data.get(key, Decimal("0")) + transaction.amount + income_data[key] = income_data.get(key, Decimal("0")) + amount + total_income_by_currency[currency] = ( + total_income_by_currency.get(currency, Decimal("0")) + amount + ) else: - expense_data[key] = expense_data.get(key, Decimal("0")) + transaction.amount + expense_data[key] = expense_data.get(key, Decimal("0")) + amount + total_expense_by_currency[currency] = ( + total_expense_by_currency.get(currency, Decimal("0")) + amount + ) - total_amount += transaction.amount + total_volume_by_currency[currency] = ( + total_volume_by_currency.get(currency, Decimal("0")) + amount + ) + + def get_node_id(node_type: str, name: str, account_id: int) -> str: + """Generate unique node ID.""" + return f"{node_type}_{name}_{account_id}".lower().replace(" ", "_") + + def add_node(node_id: str, display_name: str) -> None: + """Add node with both ID and display name.""" + nodes[node_id] = {"id": node_id, "name": display_name} + + def add_flow( + from_node_id: str, to_node_id: str, amount: Decimal, currency, is_income: bool + ) -> None: + """ + Add flow with percentage based on total transaction volume for the specific currency. + """ + total_volume = total_volume_by_currency.get(currency, Decimal("0")) + percentage = (amount / total_volume) * 100 if total_volume else 0 + scaled_flow = percentage / 100 - # Function to add flow - def add_flow(from_node, to_node, amount, currency): - percentage = (amount / total_amount) * 100 if total_amount else 0 - scaled_flow = 1 + min(percentage / 20, 4) # Scale 1-5, capping at 100% flows.append( { - "from_node": from_node, - "to_node": to_node, + "from_node": from_node_id, + "to_node": to_node_id, "flow": float(scaled_flow), "currency": { "code": currency.code, @@ -63,40 +85,164 @@ def generate_sankey_data(transactions_queryset): "percentage": float(percentage), } ) - nodes[from_node] = {"name": from_node} - nodes[to_node] = {"name": to_node} # Process income for (category, currency, account), amount in income_data.items(): - category_name = f"{category} ({currency.code})" - account_name = f"{account.name} ({currency.code})" - add_flow(category_name, account_name, amount, currency) + category_node_id = get_node_id("income", category, account.id) + account_node_id = get_node_id("account", account.name, account.id) + add_node(category_node_id, str(category)) + add_node(account_node_id, account.name) + add_flow(category_node_id, account_node_id, amount, currency, is_income=True) # Process expenses for (category, currency, account), amount in expense_data.items(): - category_name = f"{category} ({currency.code})" - account_name = f"{account.name} ({currency.code})" - add_flow(account_name, category_name, amount, currency) + category_node_id = get_node_id("expense", category, account.id) + account_node_id = get_node_id("account", account.name, account.id) + add_node(category_node_id, str(category)) + add_node(account_node_id, account.name) + add_flow(account_node_id, category_node_id, amount, currency, is_income=False) # Calculate and add savings flows savings_data = {} # {(account, currency) -> amount} - for (category, currency, account), amount in income_data.items(): key = (account, currency) savings_data[key] = savings_data.get(key, Decimal("0")) + amount - for (category, currency, account), amount in expense_data.items(): key = (account, currency) savings_data[key] = savings_data.get(key, Decimal("0")) - amount for (account, currency), amount in savings_data.items(): if amount > 0: - account_name = f"{account.name} ({currency.code})" - savings_name = f"{_('Savings')} ({currency.code})" - add_flow(account_name, savings_name, amount, currency) + account_node_id = get_node_id("account", account.name, account.id) + savings_node_id = get_node_id("savings", _("Saved"), account.id) + add_node(savings_node_id, str(_("Saved"))) + add_flow(account_node_id, savings_node_id, amount, currency, is_income=True) + + # Calculate total across all currencies (for reference only) + total_amount = sum(float(amount) for amount in total_income_by_currency.values()) return { "nodes": list(nodes.values()), "flows": flows, - "total_amount": float(total_amount), + "total_amount": total_amount, + "total_by_currency": { + curr.code: float(amount) + for curr, amount in total_income_by_currency.items() + }, + } + + +def generate_sankey_data_by_currency(transactions_queryset): + """ + Generates Sankey diagram data from transaction queryset, using currency as intermediary. + """ + nodes: Dict[str, Dict] = {} + flows: List[SankeyFlow] = [] + + # Aggregate transactions + income_data = {} # {(category, currency) -> amount} + expense_data = {} # {(category, currency) -> amount} + total_income_by_currency = {} # {currency -> amount} + total_expense_by_currency = {} # {currency -> amount} + total_volume_by_currency = {} # {currency -> amount} + + for transaction in transactions_queryset: + currency = transaction.account.currency + category = transaction.category or _("Uncategorized") + key = (category, currency) + amount = transaction.amount + + if transaction.type == "IN": + income_data[key] = income_data.get(key, Decimal("0")) + amount + total_income_by_currency[currency] = ( + total_income_by_currency.get(currency, Decimal("0")) + amount + ) + else: + expense_data[key] = expense_data.get(key, Decimal("0")) + amount + total_expense_by_currency[currency] = ( + total_expense_by_currency.get(currency, Decimal("0")) + amount + ) + + total_volume_by_currency[currency] = ( + total_volume_by_currency.get(currency, Decimal("0")) + amount + ) + + def get_node_id(node_type: str, name: str, currency_id: int) -> str: + """Generate unique node ID including currency information.""" + return f"{node_type}_{name}_{currency_id}".lower().replace(" ", "_") + + def add_node(node_id: str, display_name: str) -> None: + """Add node with both ID and display name.""" + nodes[node_id] = {"id": node_id, "name": display_name} + + def add_flow( + from_node_id: str, to_node_id: str, amount: Decimal, currency, is_income: bool + ) -> None: + """ + Add flow with percentage based on total transaction volume for the specific currency. + """ + total_volume = total_volume_by_currency.get(currency, Decimal("0")) + percentage = (amount / total_volume) * 100 if total_volume else 0 + scaled_flow = percentage / 100 + + flows.append( + { + "from_node": from_node_id, + "to_node": to_node_id, + "flow": float(scaled_flow), + "currency": { + "code": currency.code, + "name": currency.name, + "prefix": currency.prefix, + "suffix": currency.suffix, + "decimal_places": currency.decimal_places, + }, + "original_amount": float(amount), + "percentage": float(percentage), + } + ) + + # Process income + for (category, currency), amount in income_data.items(): + category_node_id = get_node_id("income", category, currency.id) + currency_node_id = get_node_id("currency", currency.name, currency.id) + add_node(category_node_id, str(category)) + add_node(currency_node_id, currency.name) + add_flow(category_node_id, currency_node_id, amount, currency, is_income=True) + + # Process expenses + for (category, currency), amount in expense_data.items(): + category_node_id = get_node_id("expense", category, currency.id) + currency_node_id = get_node_id("currency", currency.name, currency.id) + add_node(category_node_id, str(category)) + add_node(currency_node_id, currency.name) + add_flow(currency_node_id, category_node_id, amount, currency, is_income=False) + + # Calculate and add savings flows + savings_data = {} # {currency -> amount} + for (category, currency), amount in income_data.items(): + savings_data[currency] = savings_data.get(currency, Decimal("0")) + amount + for (category, currency), amount in expense_data.items(): + savings_data[currency] = savings_data.get(currency, Decimal("0")) - amount + + for currency, amount in savings_data.items(): + if amount > 0: + currency_node_id = get_node_id("currency", currency.name, currency.id) + savings_node_id = get_node_id("savings", _("Saved"), currency.id) + add_node(savings_node_id, str(_("Saved"))) + add_flow( + currency_node_id, savings_node_id, amount, currency, is_income=True + ) + + # Calculate total across all currencies (for reference only) + total_amount = sum(float(amount) for amount in total_income_by_currency.values()) + + return { + "nodes": list(nodes.values()), + "flows": flows, + "total_amount": total_amount, + "total_by_currency": { + curr.name: float(amount) + for curr, amount in total_income_by_currency.items() + }, } diff --git a/app/apps/insights/utils/transactions.py b/app/apps/insights/utils/transactions.py new file mode 100644 index 0000000..5c3b3a1 --- /dev/null +++ b/app/apps/insights/utils/transactions.py @@ -0,0 +1,96 @@ +from django.db.models import Q +from django.utils import timezone + +from dateutil.relativedelta import relativedelta + +from apps.transactions.models import Transaction +from apps.insights.forms import ( + SingleMonthForm, + SingleYearForm, + MonthRangeForm, + YearRangeForm, + DateRangeForm, +) + + +def get_transactions(request, include_unpaid=True, include_silent=False): + transactions = Transaction.objects.all() + + filter_type = request.GET.get("type", None) + + if filter_type is not None: + if filter_type == "month": + form = SingleMonthForm(request.GET) + + if form.is_valid(): + month = form.cleaned_data["month"].replace(day=1) + else: + month = timezone.localdate(timezone.now()).replace(day=1) + + transactions = transactions.filter( + reference_date__month=month.month, reference_date__year=month.year + ) + elif filter_type == "year": + form = SingleYearForm(request.GET) + if form.is_valid(): + year = form.cleaned_data["year"].replace(day=1, month=1) + else: + year = timezone.localdate(timezone.now()).replace(day=1, month=1) + + transactions = transactions.filter(reference_date__year=year.year) + elif filter_type == "month-range": + form = MonthRangeForm(request.GET) + if form.is_valid(): + month_from = form.cleaned_data["month_from"].replace(day=1) + month_to = form.cleaned_data["month_to"].replace(day=1) + else: + month_from = timezone.localdate(timezone.now()).replace(day=1) + month_to = ( + timezone.localdate(timezone.now()) + relativedelta(months=1) + ).replace(day=1) + + transactions = transactions.filter( + reference_date__gte=month_from, + reference_date__lte=month_to, + ) + elif filter_type == "year-range": + form = YearRangeForm(request.GET) + if form.is_valid(): + year_from = form.cleaned_data["year_from"].replace(day=1, month=1) + year_to = form.cleaned_data["year_to"].replace(day=31, month=12) + else: + year_from = timezone.localdate(timezone.now()).replace(day=1, month=1) + year_to = ( + timezone.localdate(timezone.now()) + relativedelta(years=1) + ).replace(day=31, month=12) + + transactions = transactions.filter( + reference_date__gte=year_from, + reference_date__lte=year_to, + ) + elif filter_type == "date-range": + form = DateRangeForm(request.GET) + if form.is_valid(): + date_from = form.cleaned_data["date_from"] + date_to = form.cleaned_data["date_to"] + else: + date_from = timezone.localdate(timezone.now()) + date_to = timezone.localdate(timezone.now()) + relativedelta(months=1) + + transactions = transactions.filter( + date__gte=date_from, + date__lte=date_to, + ) + else: # Default to current month + month = timezone.localdate(timezone.now()) + transactions = transactions.filter( + reference_date__month=month.month, reference_date__year=month.year + ) + + if not include_unpaid: + transactions = transactions.filter(is_paid=True) + + if not include_silent: + transactions = transactions.exclude(Q(category__mute=True) & ~Q(category=None)) + + return transactions diff --git a/app/apps/insights/views.py b/app/apps/insights/views.py index 3171c88..40fc42a 100644 --- a/app/apps/insights/views.py +++ b/app/apps/insights/views.py @@ -1,21 +1,94 @@ +from django.contrib.auth.decorators import login_required from django.shortcuts import render +from django.utils import timezone +from django.views.decorators.http import require_http_methods + +from dateutil.relativedelta import relativedelta from apps.transactions.models import Transaction -from apps.insights.utils.sankey import generate_sankey_data +from apps.insights.utils.sankey import ( + generate_sankey_data_by_account, + generate_sankey_data_by_currency, +) +from apps.insights.forms import ( + SingleMonthForm, + SingleYearForm, + MonthRangeForm, + YearRangeForm, + DateRangeForm, +) +from apps.common.decorators.htmx import only_htmx +from apps.insights.utils.transactions import get_transactions +@login_required +@require_http_methods(["GET"]) def index(request): - return render(request, "insights/pages/index.html") - - -def sankey(request): - # Get filtered transactions - transactions = Transaction.objects.filter(date__year=2025) - - # Generate Sankey data - sankey_data = generate_sankey_data(transactions) - print(sankey_data) + date = timezone.localdate(timezone.now()) + month_form = SingleMonthForm(initial={"month": date.replace(day=1)}) + year_form = SingleYearForm(initial={"year": date.replace(day=1)}) + month_range_form = MonthRangeForm( + initial={ + "month_from": date.replace(day=1), + "month_to": date.replace(day=1) + relativedelta(months=1), + } + ) + year_range_form = YearRangeForm( + initial={ + "year_from": date.replace(day=1, month=1), + "year_to": date.replace(day=1, month=1) + relativedelta(years=1), + } + ) + date_range_form = DateRangeForm( + initial={ + "date_from": date, + "date_to": date + relativedelta(months=1), + } + ) return render( - request, "insights/fragments/sankey.html", {"sankey_data": sankey_data} + request, + "insights/pages/index.html", + context={ + "month_form": month_form, + "year_form": year_form, + "month_range_form": month_range_form, + "year_range_form": year_range_form, + "date_range_form": date_range_form, + }, + ) + + +@only_htmx +@login_required +@require_http_methods(["GET", "POST"]) +def sankey_by_account(request): + # Get filtered transactions + + transactions = get_transactions(request) + + # Generate Sankey data + sankey_data = generate_sankey_data_by_account(transactions) + + return render( + request, + "insights/fragments/sankey.html", + {"sankey_data": sankey_data, "type": "account"}, + ) + + +@only_htmx +@login_required +@require_http_methods(["GET", "POST"]) +def sankey_by_currency(request): + # Get filtered transactions + transactions = get_transactions(request) + + # Generate Sankey data + sankey_data = generate_sankey_data_by_currency(transactions) + + return render( + request, + "insights/fragments/sankey.html", + {"sankey_data": sankey_data, "type": "currency"}, ) diff --git a/app/apps/transactions/views/transactions.py b/app/apps/transactions/views/transactions.py index 4494877..5854309 100644 --- a/app/apps/transactions/views/transactions.py +++ b/app/apps/transactions/views/transactions.py @@ -555,6 +555,4 @@ def get_recent_transactions(request, filter_type=None): for t in queryset: data.append({"text": str(t), "value": str(t.id)}) - print(data) - return JsonResponse(data, safe=False) diff --git a/app/locale/de/LC_MESSAGES/django.po b/app/locale/de/LC_MESSAGES/django.po index cd7d84c..1efba41 100644 --- a/app/locale/de/LC_MESSAGES/django.po +++ b/app/locale/de/LC_MESSAGES/django.po @@ -2,13 +2,13 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. -# +# #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-15 00:38-0300\n" +"POT-Creation-Date: 2025-02-16 00:03-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -85,7 +85,7 @@ msgstr "" #: apps/transactions/forms.py:315 apps/transactions/forms.py:471 #: apps/transactions/forms.py:716 apps/transactions/models.py:209 #: apps/transactions/models.py:380 apps/transactions/models.py:562 -#: templates/includes/navbar.html:105 templates/tags/fragments/list.html:5 +#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5 #: templates/tags/pages/index.html:4 msgid "Tags" msgstr "" @@ -114,7 +114,7 @@ msgstr "" #: apps/accounts/models.py:13 templates/account_groups/fragments/list.html:5 #: templates/account_groups/pages/index.html:4 -#: templates/includes/navbar.html:115 +#: templates/includes/navbar.html:118 msgid "Account Groups" msgstr "" @@ -162,8 +162,8 @@ msgstr "" #: apps/accounts/models.py:60 apps/transactions/filters.py:53 #: templates/accounts/fragments/list.html:5 -#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:111 -#: templates/includes/navbar.html:113 +#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114 +#: templates/includes/navbar.html:116 #: templates/monthly_overview/pages/overview.html:94 #: templates/transactions/fragments/summary.html:12 #: templates/transactions/pages/transactions.html:72 @@ -332,6 +332,7 @@ msgid "Cache cleared successfully" msgstr "" #: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186 +#: apps/common/widgets/datepicker.py:244 msgid "Today" msgstr "" @@ -386,8 +387,8 @@ msgstr "" #: apps/currencies/models.py:40 apps/transactions/filters.py:60 #: templates/currencies/fragments/list.html:5 -#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 -#: templates/includes/navbar.html:121 +#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122 +#: templates/includes/navbar.html:124 #: templates/monthly_overview/pages/overview.html:81 #: templates/transactions/fragments/summary.html:8 #: templates/transactions/pages/transactions.html:59 @@ -416,7 +417,7 @@ msgstr "" #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6 #: templates/exchange_rates/pages/index.html:4 -#: templates/includes/navbar.html:123 +#: templates/includes/navbar.html:126 msgid "Exchange Rates" msgstr "" @@ -676,7 +677,7 @@ msgstr "" #: apps/import_app/forms.py:61 #: templates/import_app/fragments/profiles/list.html:62 -#: templates/includes/navbar.html:131 +#: templates/includes/navbar.html:134 msgid "Import" msgstr "" @@ -744,6 +745,15 @@ msgstr "" msgid "Run deleted successfully" msgstr "" +#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154 +msgid "Uncategorized" +msgstr "" + +#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119 +#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235 +msgid "Saved" +msgstr "" + #: apps/rules/forms.py:20 msgid "Run on creation" msgstr "" @@ -760,7 +770,7 @@ msgstr "" msgid "Set field" msgstr "" -#: apps/rules/forms.py:65 +#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84 msgid "To" msgstr "" @@ -801,7 +811,7 @@ msgstr "" #: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29 #: apps/rules/models.py:256 apps/transactions/models.py:192 -#: apps/transactions/models.py:551 +#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85 msgid "Amount" msgstr "" @@ -828,7 +838,7 @@ msgstr "" #: apps/transactions/forms.py:731 apps/transactions/models.py:161 #: apps/transactions/models.py:214 apps/transactions/models.py:383 #: apps/transactions/models.py:565 templates/entities/fragments/list.html:5 -#: templates/entities/pages/index.html:4 templates/includes/navbar.html:107 +#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110 msgid "Entities" msgstr "" @@ -982,7 +992,7 @@ msgid "Transaction Type" msgstr "" #: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5 -#: templates/categories/pages/index.html:4 templates/includes/navbar.html:103 +#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106 msgid "Categories" msgstr "" @@ -1119,8 +1129,8 @@ msgstr "" msgid "Transaction" msgstr "" -#: apps/transactions/models.py:256 templates/includes/navbar.html:54 -#: templates/includes/navbar.html:101 +#: apps/transactions/models.py:256 templates/includes/navbar.html:57 +#: templates/includes/navbar.html:104 #: templates/recurring_transactions/fragments/list_transactions.html:5 #: templates/recurring_transactions/fragments/table.html:37 #: templates/transactions/pages/transactions.html:5 @@ -1184,7 +1194,7 @@ msgstr "" msgid "Installment Amount" msgstr "" -#: apps/transactions/models.py:391 templates/includes/navbar.html:69 +#: apps/transactions/models.py:391 templates/includes/navbar.html:72 #: templates/installment_plans/fragments/list.html:5 #: templates/installment_plans/pages/index.html:4 msgid "Installment Plans" @@ -1227,7 +1237,7 @@ msgstr "" msgid "Last Generated Reference Date" msgstr "" -#: apps/transactions/models.py:592 templates/includes/navbar.html:71 +#: apps/transactions/models.py:592 templates/includes/navbar.html:74 #: templates/recurring_transactions/fragments/list.html:5 #: templates/recurring_transactions/pages/index.html:4 msgid "Recurring Transactions" @@ -2070,7 +2080,7 @@ msgid "Edit exchange rate" msgstr "" #: templates/exchange_rates/fragments/list.html:25 -#: templates/includes/navbar.html:58 +#: templates/includes/navbar.html:61 #: templates/installment_plans/fragments/list.html:21 #: templates/yearly_overview/pages/overview_by_account.html:92 #: templates/yearly_overview/pages/overview_by_currency.html:94 @@ -2100,7 +2110,7 @@ msgstr "" #: templates/exchange_rates_services/fragments/list.html:6 #: templates/exchange_rates_services/pages/index.html:4 -#: templates/includes/navbar.html:133 +#: templates/includes/navbar.html:136 msgid "Automatic Exchange Rates" msgstr "" @@ -2237,52 +2247,56 @@ msgstr "" msgid "Current" msgstr "" -#: templates/includes/navbar.html:63 +#: templates/includes/navbar.html:50 +msgid "Insights" +msgstr "" + +#: templates/includes/navbar.html:66 msgid "Trash Can" msgstr "" -#: templates/includes/navbar.html:79 +#: templates/includes/navbar.html:82 msgid "Tools" msgstr "" -#: templates/includes/navbar.html:83 +#: templates/includes/navbar.html:86 msgid "Dollar Cost Average Tracker" msgstr "" -#: templates/includes/navbar.html:86 +#: templates/includes/navbar.html:89 #: templates/mini_tools/unit_price_calculator.html:5 #: templates/mini_tools/unit_price_calculator.html:10 msgid "Unit Price Calculator" msgstr "" -#: templates/includes/navbar.html:89 +#: templates/includes/navbar.html:92 #: templates/mini_tools/currency_converter/currency_converter.html:8 #: templates/mini_tools/currency_converter/currency_converter.html:15 msgid "Currency Converter" msgstr "" -#: templates/includes/navbar.html:98 +#: templates/includes/navbar.html:101 msgid "Management" msgstr "" -#: templates/includes/navbar.html:127 +#: templates/includes/navbar.html:130 msgid "Automation" msgstr "" -#: templates/includes/navbar.html:129 templates/rules/fragments/list.html:5 +#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5 #: templates/rules/pages/index.html:4 msgid "Rules" msgstr "" -#: templates/includes/navbar.html:143 +#: templates/includes/navbar.html:146 msgid "Only use this if you know what you're doing" msgstr "" -#: templates/includes/navbar.html:144 +#: templates/includes/navbar.html:147 msgid "Django Admin" msgstr "" -#: templates/includes/navbar.html:153 +#: templates/includes/navbar.html:156 msgid "Calculator" msgstr "" @@ -2314,6 +2328,44 @@ msgstr "" msgid "Confirm" msgstr "" +#: templates/insights/fragments/sankey.html:83 +msgid "From" +msgstr "" + +#: templates/insights/fragments/sankey.html:86 +msgid "Percentage" +msgstr "" + +#: templates/insights/pages/index.html:33 +msgid "Month" +msgstr "" + +#: templates/insights/pages/index.html:36 +#: templates/yearly_overview/pages/overview_by_account.html:61 +#: templates/yearly_overview/pages/overview_by_currency.html:63 +msgid "Year" +msgstr "" + +#: templates/insights/pages/index.html:39 +msgid "Month Range" +msgstr "" + +#: templates/insights/pages/index.html:42 +msgid "Year Range" +msgstr "" + +#: templates/insights/pages/index.html:45 +msgid "Date Range" +msgstr "" + +#: templates/insights/pages/index.html:74 +msgid "Account Flow" +msgstr "" + +#: templates/insights/pages/index.html:81 +msgid "Currency Flow" +msgstr "" + #: templates/installment_plans/fragments/add.html:5 msgid "Add installment plan" msgstr "" @@ -2678,8 +2730,3 @@ msgstr "" #: templates/yearly_overview/pages/overview_by_currency.html:9 msgid "Yearly Overview" msgstr "" - -#: templates/yearly_overview/pages/overview_by_account.html:61 -#: templates/yearly_overview/pages/overview_by_currency.html:63 -msgid "Year" -msgstr "" diff --git a/app/locale/nl/LC_MESSAGES/django.po b/app/locale/nl/LC_MESSAGES/django.po index b5c329e..27784aa 100644 --- a/app/locale/nl/LC_MESSAGES/django.po +++ b/app/locale/nl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-15 00:42-0300\n" +"POT-Creation-Date: 2025-02-16 00:03-0300\n" "PO-Revision-Date: 2025-02-12 06:58+0100\n" "Last-Translator: Dimitri Decrock \n" "Language-Team: \n" @@ -86,7 +86,7 @@ msgstr "Categorie" #: apps/transactions/forms.py:315 apps/transactions/forms.py:471 #: apps/transactions/forms.py:716 apps/transactions/models.py:209 #: apps/transactions/models.py:380 apps/transactions/models.py:562 -#: templates/includes/navbar.html:105 templates/tags/fragments/list.html:5 +#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5 #: templates/tags/pages/index.html:4 msgid "Tags" msgstr "Labels" @@ -115,7 +115,7 @@ msgstr "Accountgroep" #: apps/accounts/models.py:13 templates/account_groups/fragments/list.html:5 #: templates/account_groups/pages/index.html:4 -#: templates/includes/navbar.html:115 +#: templates/includes/navbar.html:118 msgid "Account Groups" msgstr "Accountgroepen" @@ -167,8 +167,8 @@ msgstr "Rekening" #: apps/accounts/models.py:60 apps/transactions/filters.py:53 #: templates/accounts/fragments/list.html:5 -#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:111 -#: templates/includes/navbar.html:113 +#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114 +#: templates/includes/navbar.html:116 #: templates/monthly_overview/pages/overview.html:94 #: templates/transactions/fragments/summary.html:12 #: templates/transactions/pages/transactions.html:72 @@ -338,6 +338,7 @@ msgid "Cache cleared successfully" msgstr "Categorie succesvol bijgewerkt" #: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186 +#: apps/common/widgets/datepicker.py:244 msgid "Today" msgstr "Vandaag" @@ -392,8 +393,8 @@ msgstr "Cijfers na de komma" #: apps/currencies/models.py:40 apps/transactions/filters.py:60 #: templates/currencies/fragments/list.html:5 -#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 -#: templates/includes/navbar.html:121 +#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122 +#: templates/includes/navbar.html:124 #: templates/monthly_overview/pages/overview.html:81 #: templates/transactions/fragments/summary.html:8 #: templates/transactions/pages/transactions.html:59 @@ -422,7 +423,7 @@ msgstr "Datum en Tijd" #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6 #: templates/exchange_rates/pages/index.html:4 -#: templates/includes/navbar.html:123 +#: templates/includes/navbar.html:126 msgid "Exchange Rates" msgstr "Wisselkoersen" @@ -696,7 +697,7 @@ msgstr "Selecteer een bestand" #: apps/import_app/forms.py:61 #: templates/import_app/fragments/profiles/list.html:62 -#: templates/includes/navbar.html:131 +#: templates/includes/navbar.html:134 msgid "Import" msgstr "Importeer" @@ -764,6 +765,19 @@ msgstr "Importrun met succes in de wachtrij geplaatst" msgid "Run deleted successfully" msgstr "Run met succes verwijderd" +#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154 +#, fuzzy +#| msgid "Categories" +msgid "Uncategorized" +msgstr "Categorieën" + +#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119 +#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "Opslaan" + #: apps/rules/forms.py:20 msgid "Run on creation" msgstr "Uitvoeren na het aanmaken" @@ -780,7 +794,7 @@ msgstr "Als..." msgid "Set field" msgstr "Veld instellen" -#: apps/rules/forms.py:65 +#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84 msgid "To" msgstr "Naar" @@ -821,7 +835,7 @@ msgstr "Referentiedatum" #: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29 #: apps/rules/models.py:256 apps/transactions/models.py:192 -#: apps/transactions/models.py:551 +#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85 msgid "Amount" msgstr "Bedrag" @@ -848,7 +862,7 @@ msgstr "Interne ID" #: apps/transactions/forms.py:731 apps/transactions/models.py:161 #: apps/transactions/models.py:214 apps/transactions/models.py:383 #: apps/transactions/models.py:565 templates/entities/fragments/list.html:5 -#: templates/entities/pages/index.html:4 templates/includes/navbar.html:107 +#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110 msgid "Entities" msgstr "Bedrijven" @@ -1005,7 +1019,7 @@ msgid "Transaction Type" msgstr "Soort transactie" #: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5 -#: templates/categories/pages/index.html:4 templates/includes/navbar.html:103 +#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106 msgid "Categories" msgstr "Categorieën" @@ -1148,8 +1162,8 @@ msgstr "Verwijderd Op" msgid "Transaction" msgstr "Verrichting" -#: apps/transactions/models.py:256 templates/includes/navbar.html:54 -#: templates/includes/navbar.html:101 +#: apps/transactions/models.py:256 templates/includes/navbar.html:57 +#: templates/includes/navbar.html:104 #: templates/recurring_transactions/fragments/list_transactions.html:5 #: templates/recurring_transactions/fragments/table.html:37 #: templates/transactions/pages/transactions.html:5 @@ -1217,7 +1231,7 @@ msgstr "Terugkeerpatroon" msgid "Installment Amount" msgstr "Termijnbedrag" -#: apps/transactions/models.py:391 templates/includes/navbar.html:69 +#: apps/transactions/models.py:391 templates/includes/navbar.html:72 #: templates/installment_plans/fragments/list.html:5 #: templates/installment_plans/pages/index.html:4 msgid "Installment Plans" @@ -1260,7 +1274,7 @@ msgstr "Laatste Gegenereerde Datum" msgid "Last Generated Reference Date" msgstr "Laatste Gegenereerde Referentiedatum" -#: apps/transactions/models.py:592 templates/includes/navbar.html:71 +#: apps/transactions/models.py:592 templates/includes/navbar.html:74 #: templates/recurring_transactions/fragments/list.html:5 #: templates/recurring_transactions/pages/index.html:4 msgid "Recurring Transactions" @@ -2103,7 +2117,7 @@ msgid "Edit exchange rate" msgstr "Wisselkoers bewerken" #: templates/exchange_rates/fragments/list.html:25 -#: templates/includes/navbar.html:58 +#: templates/includes/navbar.html:61 #: templates/installment_plans/fragments/list.html:21 #: templates/yearly_overview/pages/overview_by_account.html:92 #: templates/yearly_overview/pages/overview_by_currency.html:94 @@ -2133,7 +2147,7 @@ msgstr "Paginanavigatie" #: templates/exchange_rates_services/fragments/list.html:6 #: templates/exchange_rates_services/pages/index.html:4 -#: templates/includes/navbar.html:133 +#: templates/includes/navbar.html:136 msgid "Automatic Exchange Rates" msgstr "Automatische Wisselkoersen" @@ -2271,52 +2285,56 @@ msgstr "Netto Waarde" msgid "Current" msgstr "Huidige" -#: templates/includes/navbar.html:63 +#: templates/includes/navbar.html:50 +msgid "Insights" +msgstr "" + +#: templates/includes/navbar.html:66 msgid "Trash Can" msgstr "Prullenbak" -#: templates/includes/navbar.html:79 +#: templates/includes/navbar.html:82 msgid "Tools" msgstr "Hulpmiddelen" -#: templates/includes/navbar.html:83 +#: templates/includes/navbar.html:86 msgid "Dollar Cost Average Tracker" msgstr "Dollar Kostgemiddelde Tracker" -#: templates/includes/navbar.html:86 +#: templates/includes/navbar.html:89 #: templates/mini_tools/unit_price_calculator.html:5 #: templates/mini_tools/unit_price_calculator.html:10 msgid "Unit Price Calculator" msgstr "Eenheidsprijs berekenen" -#: templates/includes/navbar.html:89 +#: templates/includes/navbar.html:92 #: templates/mini_tools/currency_converter/currency_converter.html:8 #: templates/mini_tools/currency_converter/currency_converter.html:15 msgid "Currency Converter" msgstr "Valuta omrekenen" -#: templates/includes/navbar.html:98 +#: templates/includes/navbar.html:101 msgid "Management" msgstr "Beheer" -#: templates/includes/navbar.html:127 +#: templates/includes/navbar.html:130 msgid "Automation" msgstr "Automatisatie" -#: templates/includes/navbar.html:129 templates/rules/fragments/list.html:5 +#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5 #: templates/rules/pages/index.html:4 msgid "Rules" msgstr "Regels" -#: templates/includes/navbar.html:143 +#: templates/includes/navbar.html:146 msgid "Only use this if you know what you're doing" msgstr "Gebruik dit alleen als je weet wat je doet" -#: templates/includes/navbar.html:144 +#: templates/includes/navbar.html:147 msgid "Django Admin" msgstr "Django Beheerder" -#: templates/includes/navbar.html:153 +#: templates/includes/navbar.html:156 msgid "Calculator" msgstr "Rekenmachine" @@ -2350,6 +2368,54 @@ msgstr "Annuleer" msgid "Confirm" msgstr "Bevestig" +#: templates/insights/fragments/sankey.html:83 +msgid "From" +msgstr "" + +#: templates/insights/fragments/sankey.html:86 +msgid "Percentage" +msgstr "" + +#: templates/insights/pages/index.html:33 +#, fuzzy +#| msgid "Monthly" +msgid "Month" +msgstr "Maandelijks" + +#: templates/insights/pages/index.html:36 +#: templates/yearly_overview/pages/overview_by_account.html:61 +#: templates/yearly_overview/pages/overview_by_currency.html:63 +msgid "Year" +msgstr "Jaar" + +#: templates/insights/pages/index.html:39 +#, fuzzy +#| msgid "Unchanged" +msgid "Month Range" +msgstr "Ongewijzigd" + +#: templates/insights/pages/index.html:42 +msgid "Year Range" +msgstr "" + +#: templates/insights/pages/index.html:45 +#, fuzzy +#| msgid "Date and Time" +msgid "Date Range" +msgstr "Datum en Tijd" + +#: templates/insights/pages/index.html:74 +#, fuzzy +#| msgid "Account" +msgid "Account Flow" +msgstr "Rekening" + +#: templates/insights/pages/index.html:81 +#, fuzzy +#| msgid "Currency Code" +msgid "Currency Flow" +msgstr "Munteenheids Code" + #: templates/installment_plans/fragments/add.html:5 msgid "Add installment plan" msgstr "Afbetalingsplan toevoegen" @@ -2723,11 +2789,6 @@ msgstr "Bedragen tonen" msgid "Yearly Overview" msgstr "Jaaroverzicht" -#: templates/yearly_overview/pages/overview_by_account.html:61 -#: templates/yearly_overview/pages/overview_by_currency.html:63 -msgid "Year" -msgstr "Jaar" - #, fuzzy #~| msgid "Start Date" #~ msgid "Search Date" diff --git a/app/locale/pt_BR/LC_MESSAGES/django.po b/app/locale/pt_BR/LC_MESSAGES/django.po index c15c90f..5f97276 100644 --- a/app/locale/pt_BR/LC_MESSAGES/django.po +++ b/app/locale/pt_BR/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-15 00:38-0300\n" -"PO-Revision-Date: 2025-02-15 00:39-0300\n" +"POT-Creation-Date: 2025-02-16 00:03-0300\n" +"PO-Revision-Date: 2025-02-16 00:04-0300\n" "Last-Translator: Herculino Trotta\n" "Language-Team: \n" "Language: pt_BR\n" @@ -86,7 +86,7 @@ msgstr "Categoria" #: apps/transactions/forms.py:315 apps/transactions/forms.py:471 #: apps/transactions/forms.py:716 apps/transactions/models.py:209 #: apps/transactions/models.py:380 apps/transactions/models.py:562 -#: templates/includes/navbar.html:105 templates/tags/fragments/list.html:5 +#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5 #: templates/tags/pages/index.html:4 msgid "Tags" msgstr "Tags" @@ -115,7 +115,7 @@ msgstr "Grupo da Conta" #: apps/accounts/models.py:13 templates/account_groups/fragments/list.html:5 #: templates/account_groups/pages/index.html:4 -#: templates/includes/navbar.html:115 +#: templates/includes/navbar.html:118 msgid "Account Groups" msgstr "Grupos da Conta" @@ -166,8 +166,8 @@ msgstr "Conta" #: apps/accounts/models.py:60 apps/transactions/filters.py:53 #: templates/accounts/fragments/list.html:5 -#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:111 -#: templates/includes/navbar.html:113 +#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114 +#: templates/includes/navbar.html:116 #: templates/monthly_overview/pages/overview.html:94 #: templates/transactions/fragments/summary.html:12 #: templates/transactions/pages/transactions.html:72 @@ -336,6 +336,7 @@ msgid "Cache cleared successfully" msgstr "Cache limpo com sucesso" #: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186 +#: apps/common/widgets/datepicker.py:244 msgid "Today" msgstr "Hoje" @@ -390,8 +391,8 @@ msgstr "Casas Decimais" #: apps/currencies/models.py:40 apps/transactions/filters.py:60 #: templates/currencies/fragments/list.html:5 -#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 -#: templates/includes/navbar.html:121 +#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122 +#: templates/includes/navbar.html:124 #: templates/monthly_overview/pages/overview.html:81 #: templates/transactions/fragments/summary.html:8 #: templates/transactions/pages/transactions.html:59 @@ -420,7 +421,7 @@ msgstr "Data e Tempo" #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6 #: templates/exchange_rates/pages/index.html:4 -#: templates/includes/navbar.html:123 +#: templates/includes/navbar.html:126 msgid "Exchange Rates" msgstr "Taxas de Câmbio" @@ -690,7 +691,7 @@ msgstr "Selecione um arquivo" #: apps/import_app/forms.py:61 #: templates/import_app/fragments/profiles/list.html:62 -#: templates/includes/navbar.html:131 +#: templates/includes/navbar.html:134 msgid "Import" msgstr "Importar" @@ -758,6 +759,15 @@ msgstr "Importação adicionada à fila com sucesso" msgid "Run deleted successfully" msgstr "Importação apagada com sucesso" +#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154 +msgid "Uncategorized" +msgstr "Sem categoria" + +#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119 +#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235 +msgid "Saved" +msgstr "Salvo" + #: apps/rules/forms.py:20 msgid "Run on creation" msgstr "Rodar na criação" @@ -774,7 +784,7 @@ msgstr "Se..." msgid "Set field" msgstr "Definir campo" -#: apps/rules/forms.py:65 +#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84 msgid "To" msgstr "Para" @@ -815,7 +825,7 @@ msgstr "Data de Referência" #: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29 #: apps/rules/models.py:256 apps/transactions/models.py:192 -#: apps/transactions/models.py:551 +#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85 msgid "Amount" msgstr "Quantia" @@ -842,7 +852,7 @@ msgstr "ID Interna" #: apps/transactions/forms.py:731 apps/transactions/models.py:161 #: apps/transactions/models.py:214 apps/transactions/models.py:383 #: apps/transactions/models.py:565 templates/entities/fragments/list.html:5 -#: templates/entities/pages/index.html:4 templates/includes/navbar.html:107 +#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110 msgid "Entities" msgstr "Entidades" @@ -998,7 +1008,7 @@ msgid "Transaction Type" msgstr "Tipo de Transação" #: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5 -#: templates/categories/pages/index.html:4 templates/includes/navbar.html:103 +#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106 msgid "Categories" msgstr "Categorias" @@ -1140,8 +1150,8 @@ msgstr "Apagado Em" msgid "Transaction" msgstr "Transação" -#: apps/transactions/models.py:256 templates/includes/navbar.html:54 -#: templates/includes/navbar.html:101 +#: apps/transactions/models.py:256 templates/includes/navbar.html:57 +#: templates/includes/navbar.html:104 #: templates/recurring_transactions/fragments/list_transactions.html:5 #: templates/recurring_transactions/fragments/table.html:37 #: templates/transactions/pages/transactions.html:5 @@ -1205,7 +1215,7 @@ msgstr "Recorrência" msgid "Installment Amount" msgstr "Valor da Parcela" -#: apps/transactions/models.py:391 templates/includes/navbar.html:69 +#: apps/transactions/models.py:391 templates/includes/navbar.html:72 #: templates/installment_plans/fragments/list.html:5 #: templates/installment_plans/pages/index.html:4 msgid "Installment Plans" @@ -1248,7 +1258,7 @@ msgstr "Última data gerada" msgid "Last Generated Reference Date" msgstr "Última data de referência gerada" -#: apps/transactions/models.py:592 templates/includes/navbar.html:71 +#: apps/transactions/models.py:592 templates/includes/navbar.html:74 #: templates/recurring_transactions/fragments/list.html:5 #: templates/recurring_transactions/pages/index.html:4 msgid "Recurring Transactions" @@ -2092,7 +2102,7 @@ msgid "Edit exchange rate" msgstr "Editar taxa de câmbio" #: templates/exchange_rates/fragments/list.html:25 -#: templates/includes/navbar.html:58 +#: templates/includes/navbar.html:61 #: templates/installment_plans/fragments/list.html:21 #: templates/yearly_overview/pages/overview_by_account.html:92 #: templates/yearly_overview/pages/overview_by_currency.html:94 @@ -2122,7 +2132,7 @@ msgstr "Navegação por página" #: templates/exchange_rates_services/fragments/list.html:6 #: templates/exchange_rates_services/pages/index.html:4 -#: templates/includes/navbar.html:133 +#: templates/includes/navbar.html:136 msgid "Automatic Exchange Rates" msgstr "Taxas de Câmbio Automáticas" @@ -2261,52 +2271,56 @@ msgstr "Patrimônio" msgid "Current" msgstr "Atual" -#: templates/includes/navbar.html:63 +#: templates/includes/navbar.html:50 +msgid "Insights" +msgstr "Insights" + +#: templates/includes/navbar.html:66 msgid "Trash Can" msgstr "Lixeira" -#: templates/includes/navbar.html:79 +#: templates/includes/navbar.html:82 msgid "Tools" msgstr "Ferramentas" -#: templates/includes/navbar.html:83 +#: templates/includes/navbar.html:86 msgid "Dollar Cost Average Tracker" msgstr "Rastreador de Custo Médio Ponderado" -#: templates/includes/navbar.html:86 +#: templates/includes/navbar.html:89 #: templates/mini_tools/unit_price_calculator.html:5 #: templates/mini_tools/unit_price_calculator.html:10 msgid "Unit Price Calculator" msgstr "Calculadora de preço unitário" -#: templates/includes/navbar.html:89 +#: templates/includes/navbar.html:92 #: templates/mini_tools/currency_converter/currency_converter.html:8 #: templates/mini_tools/currency_converter/currency_converter.html:15 msgid "Currency Converter" msgstr "Conversor de Moeda" -#: templates/includes/navbar.html:98 +#: templates/includes/navbar.html:101 msgid "Management" msgstr "Gerenciar" -#: templates/includes/navbar.html:127 +#: templates/includes/navbar.html:130 msgid "Automation" msgstr "Automação" -#: templates/includes/navbar.html:129 templates/rules/fragments/list.html:5 +#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5 #: templates/rules/pages/index.html:4 msgid "Rules" msgstr "Regras" -#: templates/includes/navbar.html:143 +#: templates/includes/navbar.html:146 msgid "Only use this if you know what you're doing" msgstr "Só use isso se você souber o que está fazendo" -#: templates/includes/navbar.html:144 +#: templates/includes/navbar.html:147 msgid "Django Admin" msgstr "Django Admin" -#: templates/includes/navbar.html:153 +#: templates/includes/navbar.html:156 msgid "Calculator" msgstr "Calculadora" @@ -2339,6 +2353,44 @@ msgstr "Cancelar" msgid "Confirm" msgstr "Confirmar" +#: templates/insights/fragments/sankey.html:83 +msgid "From" +msgstr "De" + +#: templates/insights/fragments/sankey.html:86 +msgid "Percentage" +msgstr "Porcentagem" + +#: templates/insights/pages/index.html:33 +msgid "Month" +msgstr "Mês" + +#: templates/insights/pages/index.html:36 +#: templates/yearly_overview/pages/overview_by_account.html:61 +#: templates/yearly_overview/pages/overview_by_currency.html:63 +msgid "Year" +msgstr "Ano" + +#: templates/insights/pages/index.html:39 +msgid "Month Range" +msgstr "Intervalo de Mês" + +#: templates/insights/pages/index.html:42 +msgid "Year Range" +msgstr "Intervalo de Ano" + +#: templates/insights/pages/index.html:45 +msgid "Date Range" +msgstr "Intervalo de Data" + +#: templates/insights/pages/index.html:74 +msgid "Account Flow" +msgstr "Fluxo de Conta" + +#: templates/insights/pages/index.html:81 +msgid "Currency Flow" +msgstr "Fluxo de Moeda" + #: templates/installment_plans/fragments/add.html:5 msgid "Add installment plan" msgstr "Adicionar parcelamento" @@ -2709,11 +2761,6 @@ msgstr "Mostrar valores" msgid "Yearly Overview" msgstr "Visão Anual" -#: templates/yearly_overview/pages/overview_by_account.html:61 -#: templates/yearly_overview/pages/overview_by_currency.html:63 -msgid "Year" -msgstr "Ano" - #, fuzzy #~| msgid "Tags" #~ msgid "No Tags" @@ -2913,9 +2960,6 @@ msgstr "Ano" #~ msgid "Is an asset account?" #~ msgstr "É uma conta de ativos?" -#~ msgid "Month" -#~ msgstr "Mês" - #~ msgid "" #~ "This transaction is part of a Installment Plan, you can't delete it " #~ "directly." diff --git a/app/templates/includes/navbar.html b/app/templates/includes/navbar.html index c8e4c72..53c06c0 100644 --- a/app/templates/includes/navbar.html +++ b/app/templates/includes/navbar.html @@ -46,8 +46,11 @@ href="{% url 'net_worth_projected' %}">{% translate 'Projected' %} +