Compare commits

..

23 Commits

Author SHA1 Message Date
Herculino Trotta
8de340b68b Merge pull request #190
locale(de): enable Deutsch
2025-02-24 16:34:50 -03:00
Herculino Trotta
ef15b85386 fix(locale): transactions quick search placeholder is not translatable 2025-02-24 16:34:05 -03:00
Herculino Trotta
45d939237d locale(de): enable Deutsch 2025-02-24 16:33:14 -03:00
Herculino Trotta
6bf262e514 Merge pull request #189
style(transactions): improve look on wider columns
2025-02-22 23:21:45 -03:00
Herculino Trotta
f9d9137336 style(transactions): improve look on wider columns 2025-02-22 23:21:28 -03:00
Herculino Trotta
b532521f27 Merge pull request #188 from DragonHeart69/main
update dutch to V0.11.3
2025-02-22 23:17:11 -03:00
Dimitri Decrock
1e06e2d34d update dutch to V0.11.3 2025-02-22 15:04:47 +01:00
Herculino Trotta
a33fa5e184 Merge pull request #187 from eitchtee/dev
style(transactions): improve look on wider columns
2025-02-22 01:41:27 -03:00
Herculino Trotta
a2453695d8 style(transactions): improve look on wider columns 2025-02-22 01:41:02 -03:00
Herculino Trotta
3e929d0433 Merge pull request #186
style(transactions): improve look on wider columns
2025-02-22 01:18:35 -03:00
Herculino Trotta
185fc464a5 style(transactions): improve look on wider columns 2025-02-22 01:18:20 -03:00
Herculino Trotta
647c009525 Merge pull request #185
fix(insights:latest-transactions): order transactions from newest to oldest
2025-02-22 01:02:56 -03:00
Herculino Trotta
ba75492dcc fix(insights:latest-transactions): order transactions from newest to oldest 2025-02-22 01:02:35 -03:00
Herculino Trotta
8312baaf45 Merge pull request #184
feat(tools:currency-converter): show 1:1 rates for all available currencies
2025-02-20 23:48:32 -03:00
Herculino Trotta
4d346dc278 feat(tools:currency-converter): show 1:1 rates for all available currencies 2025-02-20 23:48:08 -03:00
Herculino Trotta
70ff7fab38 Merge pull request #183 from eitchtee/dev
feat(insights): add late and recent transactions
2025-02-19 23:07:51 -03:00
Herculino Trotta
6947c6affd feat(insights): add late and recent transactions 2025-02-19 23:07:28 -03:00
Herculino Trotta
dcab83f936 Merge pull request #182
fix(insights:category-explorer): wrong sums
2025-02-19 16:02:14 -03:00
Herculino Trotta
b228e4ec26 fix(insights:category-explorer): wrong sums 2025-02-19 16:01:53 -03:00
Herculino Trotta
4071a1301f Merge pull request #181 from eitchtee/dev
fix(export): unable to import decimals
2025-02-19 15:44:50 -03:00
Herculino Trotta
5c9db10710 fix(export): unable to import decimals 2025-02-19 15:44:18 -03:00
Herculino Trotta
19c92e0014 Merge pull request #180
fix(export): 403 when exporting
2025-02-19 14:02:52 -03:00
Herculino Trotta
6459f2eb46 fix(export): 403 when exporting 2025-02-19 14:02:31 -03:00
28 changed files with 1237 additions and 745 deletions

View File

@@ -163,6 +163,7 @@ AUTH_USER_MODEL = "users.User"
LANGUAGE_CODE = "en" LANGUAGE_CODE = "en"
LANGUAGES = ( LANGUAGES = (
("de", "Deutsch"),
("en", "English"), ("en", "English"),
("nl", "Nederlands"), ("nl", "Nederlands"),
("pt-br", "Português (Brasil)"), ("pt-br", "Português (Brasil)"),

View File

@@ -2,13 +2,15 @@ from import_export import fields, resources, widgets
from apps.accounts.models import Account from apps.accounts.models import Account
from apps.currencies.models import Currency, ExchangeRate, ExchangeRateService from apps.currencies.models import Currency, ExchangeRate, ExchangeRateService
from apps.export_app.widgets.foreign_key import SkipMissingForeignKeyWidget
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class CurrencyResource(resources.ModelResource): class CurrencyResource(resources.ModelResource):
exchange_currency = fields.Field( exchange_currency = fields.Field(
attribute="exchange_currency", attribute="exchange_currency",
column_name="exchange_currency", column_name="exchange_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"), widget=SkipMissingForeignKeyWidget(Currency, "name"),
) )
class Meta: class Meta:
@@ -26,6 +28,9 @@ class ExchangeRateResource(resources.ModelResource):
column_name="to_currency", column_name="to_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"), widget=widgets.ForeignKeyWidget(Currency, "name"),
) )
rate = fields.Field(
attribute="rate", column_name="rate", widget=UniversalDecimalWidget()
)
class Meta: class Meta:
model = ExchangeRate model = ExchangeRate

View File

@@ -3,6 +3,7 @@ from import_export.widgets import ForeignKeyWidget
from apps.dca.models import DCAStrategy, DCAEntry from apps.dca.models import DCAStrategy, DCAEntry
from apps.currencies.models import Currency from apps.currencies.models import Currency
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class DCAStrategyResource(resources.ModelResource): class DCAStrategyResource(resources.ModelResource):
@@ -22,5 +23,16 @@ class DCAStrategyResource(resources.ModelResource):
class DCAEntryResource(resources.ModelResource): class DCAEntryResource(resources.ModelResource):
amount_paid = fields.Field(
attribute="amount_paid",
column_name="amount_paid",
widget=UniversalDecimalWidget(),
)
amount_received = fields.Field(
attribute="amount_received",
column_name="amount_received",
widget=UniversalDecimalWidget(),
)
class Meta: class Meta:
model = DCAEntry model = DCAEntry

View File

@@ -13,6 +13,7 @@ from apps.transactions.models import (
RecurringTransaction, RecurringTransaction,
InstallmentPlan, InstallmentPlan,
) )
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class TransactionResource(resources.ModelResource): class TransactionResource(resources.ModelResource):
@@ -44,6 +45,12 @@ class TransactionResource(resources.ModelResource):
column_name="internal_id", attribute="internal_id" column_name="internal_id", attribute="internal_id"
) )
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta: class Meta:
model = Transaction model = Transaction
@@ -91,6 +98,12 @@ class RecurringTransactionResource(resources.ModelResource):
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"), widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
) )
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta: class Meta:
model = RecurringTransaction model = RecurringTransaction
@@ -120,5 +133,11 @@ class InstallmentPlanResource(resources.ModelResource):
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"), widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
) )
installment_amount = fields.Field(
attribute="installment_amount",
column_name="installment_amount",
widget=UniversalDecimalWidget(),
)
class Meta: class Meta:
model = InstallmentPlan model = InstallmentPlan

View File

@@ -50,7 +50,6 @@ def export_index(request):
return render(request, "export_app/pages/index.html") return render(request, "export_app/pages/index.html")
@only_htmx
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def export_form(request): def export_form(request):
@@ -241,11 +240,6 @@ def process_imports(request, cleaned_data):
dataset = Dataset() dataset = Dataset()
dataset.load(content, format="csv") dataset.load(content, format="csv")
# Debug logging
logger.debug(f"Importing {field_name}")
logger.debug(f"Headers: {dataset.headers}")
logger.debug(f"First row: {dataset[0] if len(dataset) > 0 else 'No data'}")
# Perform the import # Perform the import
result = resource.import_data( result = resource.import_data(
dataset, dataset,
@@ -266,6 +260,8 @@ def process_imports(request, cleaned_data):
raise ImportError(f"Error importing {field_name}: {str(e)}") raise ImportError(f"Error importing {field_name}: {str(e)}")
with transaction.atomic(): with transaction.atomic():
files = {}
if zip_file := cleaned_data.get("zip_file"): if zip_file := cleaned_data.get("zip_file"):
# Process ZIP file # Process ZIP file
with zipfile.ZipFile(zip_file) as z: with zipfile.ZipFile(zip_file) as z:
@@ -274,10 +270,12 @@ def process_imports(request, cleaned_data):
with z.open(filename) as f: with z.open(filename) as f:
content = f.read().decode("utf-8") content = f.read().decode("utf-8")
for field_name, resource_class in import_order: files[name] = content
if name == field_name:
import_dataset(content, resource_class, field_name) for field_name, resource_class in import_order:
break if field_name in files.keys():
content = files[field_name]
import_dataset(content, resource_class, field_name)
else: else:
# Process individual files # Process individual files
for field_name, resource_class in import_order: for field_name, resource_class in import_order:

View File

@@ -9,3 +9,14 @@ class AutoCreateForeignKeyWidget(ForeignKeyWidget):
except self.model.DoesNotExist: except self.model.DoesNotExist:
return self.model.objects.create(name=value) return self.model.objects.create(name=value)
return None return None
class SkipMissingForeignKeyWidget(ForeignKeyWidget):
def clean(self, value, row=None, *args, **kwargs):
if not value:
return None
try:
return super().clean(value, row, *args, **kwargs)
except self.model.DoesNotExist:
return None

View File

@@ -0,0 +1,18 @@
from decimal import Decimal
from import_export.widgets import NumberWidget
class UniversalDecimalWidget(NumberWidget):
def clean(self, value, row=None, *args, **kwargs):
if self.is_empty(value):
return None
# Replace comma with dot if present
if isinstance(value, str):
value = value.replace(",", ".")
return Decimal(str(value))
def render(self, value, obj=None, **kwargs):
if value is None:
return ""
return str(value).replace(",", ".")

View File

@@ -29,4 +29,14 @@ urlpatterns = [
views.category_sum_by_currency, views.category_sum_by_currency,
name="category_sum_by_currency", name="category_sum_by_currency",
), ),
path(
"insights/late-transactions/",
views.late_transactions,
name="insights_late_transactions",
),
path(
"insights/latest-transactions/",
views.latest_transactions,
name="insights_latest_transactions",
),
] ]

View File

@@ -14,8 +14,7 @@ def get_category_sums_by_account(queryset, category=None):
current_income=Coalesce( current_income=Coalesce(
Sum( Sum(
Case( Case(
When(type="IN", then="amount"), When(type="IN", is_paid=True, then="amount"),
When(is_paid=True, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -26,8 +25,7 @@ def get_category_sums_by_account(queryset, category=None):
current_expense=Coalesce( current_expense=Coalesce(
Sum( Sum(
Case( Case(
When(type="EX", then=-F("amount")), When(type="EX", is_paid=True, then=-F("amount")),
When(is_paid=True, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -38,8 +36,7 @@ def get_category_sums_by_account(queryset, category=None):
projected_income=Coalesce( projected_income=Coalesce(
Sum( Sum(
Case( Case(
When(type="IN", then="amount"), When(type="IN", is_paid=False, then="amount"),
When(is_paid=False, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -50,8 +47,7 @@ def get_category_sums_by_account(queryset, category=None):
projected_expense=Coalesce( projected_expense=Coalesce(
Sum( Sum(
Case( Case(
When(type="EX", then=-F("amount")), When(type="EX", is_paid=False, then=-F("amount")),
When(is_paid=False, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -97,8 +93,7 @@ def get_category_sums_by_currency(queryset, category=None):
current_income=Coalesce( current_income=Coalesce(
Sum( Sum(
Case( Case(
When(type="IN", then="amount"), When(type="IN", is_paid=True, then="amount"),
When(is_paid=True, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -109,8 +104,7 @@ def get_category_sums_by_currency(queryset, category=None):
current_expense=Coalesce( current_expense=Coalesce(
Sum( Sum(
Case( Case(
When(type="EX", then=-F("amount")), When(type="EX", is_paid=True, then=-F("amount")),
When(is_paid=True, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -121,8 +115,7 @@ def get_category_sums_by_currency(queryset, category=None):
projected_income=Coalesce( projected_income=Coalesce(
Sum( Sum(
Case( Case(
When(type="IN", then="amount"), When(type="IN", is_paid=False, then="amount"),
When(is_paid=False, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )
@@ -133,8 +126,7 @@ def get_category_sums_by_currency(queryset, category=None):
projected_expense=Coalesce( projected_expense=Coalesce(
Sum( Sum(
Case( Case(
When(type="EX", then=-F("amount")), When(type="EX", is_paid=False, then=-F("amount")),
When(is_paid=False, then="amount"),
default=Value(0), default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30), output_field=DecimalField(max_digits=42, decimal_places=30),
) )

View File

@@ -22,7 +22,7 @@ from apps.insights.utils.sankey import (
generate_sankey_data_by_currency, generate_sankey_data_by_currency,
) )
from apps.insights.utils.transactions import get_transactions from apps.insights.utils.transactions import get_transactions
from apps.transactions.models import TransactionCategory from apps.transactions.models import TransactionCategory, Transaction
@login_required @login_required
@@ -157,3 +157,33 @@ def category_sum_by_currency(request):
"insights/fragments/category_explorer/charts/currency.html", "insights/fragments/category_explorer/charts/currency.html",
{"currency_data": currency_data}, {"currency_data": currency_data},
) )
@only_htmx
@login_required
@require_http_methods(["GET"])
def latest_transactions(request):
limit = timezone.now() - relativedelta(days=3)
transactions = Transaction.objects.filter(created_at__gte=limit).order_by("-id")[
:30
]
return render(
request,
"insights/fragments/latest_transactions.html",
{"transactions": transactions},
)
@only_htmx
@login_required
@require_http_methods(["GET"])
def late_transactions(request):
now = timezone.localdate(timezone.now())
transactions = Transaction.objects.filter(is_paid=False, date__lt=now)
return render(
request,
"insights/fragments/late_transactions.html",
{"transactions": transactions},
)

View File

View File

@@ -0,0 +1,85 @@
from typing import Dict
from django.db.models import Func, F, Value
from django.db.models.functions import Extract
from django.utils import timezone
from apps.currencies.models import ExchangeRate
def get_currency_exchange_map(date=None) -> Dict[str, dict]:
"""
Creates a nested dictionary of exchange rates and currency information.
Returns:
{
'BTC': {
'decimal_places': 8,
'prefix': '',
'suffix': '',
'rates': {'USD': Decimal('34000.00'), 'EUR': Decimal('31000.00')}
},
'USD': {
'decimal_places': 2,
'prefix': '$',
'suffix': '',
'rates': {'BTC': Decimal('0.0000294'), 'EUR': Decimal('0.91')}
},
...
}
"""
if date is None:
date = timezone.localtime(timezone.now())
# Get all exchange rates for the closest date
exchange_rates = (
ExchangeRate.objects.select_related(
"from_currency", "to_currency"
) # Optimize currency queries
.annotate(
date_diff=Func(Extract(F("date") - Value(date), "epoch"), function="ABS"),
effective_rate=F("rate"),
)
.order_by("from_currency", "to_currency", "date_diff")
.distinct("from_currency", "to_currency")
)
# Initialize the result dictionary
rate_map = {}
# Build the exchange rate mapping with currency info
for rate in exchange_rates:
# Add from_currency info if not exists
if rate.from_currency.name not in rate_map:
rate_map[rate.from_currency.name] = {
"decimal_places": rate.from_currency.decimal_places,
"prefix": rate.from_currency.prefix,
"suffix": rate.from_currency.suffix,
"rates": {},
}
# Add to_currency info if not exists
if rate.to_currency.name not in rate_map:
rate_map[rate.to_currency.name] = {
"decimal_places": rate.to_currency.decimal_places,
"prefix": rate.to_currency.prefix,
"suffix": rate.to_currency.suffix,
"rates": {},
}
# Add direct rate
rate_map[rate.from_currency.name]["rates"][rate.to_currency.name] = {
"rate": rate.rate,
"decimal_places": rate.to_currency.decimal_places,
"prefix": rate.to_currency.prefix,
"suffix": rate.to_currency.suffix,
}
# Add inverse rate
rate_map[rate.to_currency.name]["rates"][rate.from_currency.name] = {
"rate": 1 / rate.rate,
"decimal_places": rate.from_currency.decimal_places,
"prefix": rate.from_currency.prefix,
"suffix": rate.from_currency.suffix,
}
return rate_map

View File

@@ -5,6 +5,7 @@ from apps.common.widgets.decimal import convert_to_decimal
from apps.currencies.models import Currency from apps.currencies.models import Currency
from apps.currencies.utils.convert import convert from apps.currencies.utils.convert import convert
from apps.mini_tools.forms import CurrencyConverterForm from apps.mini_tools.forms import CurrencyConverterForm
from apps.mini_tools.utils.exchange_rate_map import get_currency_exchange_map
@login_required @login_required
@@ -14,11 +15,13 @@ def unit_price_calculator(request):
@login_required @login_required
def currency_converter(request): def currency_converter(request):
rate_map = get_currency_exchange_map()
form = CurrencyConverterForm() form = CurrencyConverterForm()
return render( return render(
request, request,
"mini_tools/currency_converter/currency_converter.html", "mini_tools/currency_converter/currency_converter.html",
context={"form": form}, context={"form": form, "rate_map": rate_map},
) )

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.6 on 2025-02-24 19:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0018_alter_usersettings_start_page'),
]
operations = [
migrations.AlterField(
model_name='usersettings',
name='language',
field=models.CharField(choices=[('auto', 'Auto'), ('de', 'Deutsch'), ('en', 'English'), ('nl', 'Nederlands'), ('pt-br', 'Português (Brasil)')], default='auto', max_length=10, verbose_name='Language'),
),
]

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-19 13:44-0300\n" "POT-Creation-Date: 2025-02-24 16:30-0300\n"
"PO-Revision-Date: 2025-02-12 06:58+0100\n" "PO-Revision-Date: 2025-02-22 15:03+0100\n"
"Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n" "Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
@@ -582,10 +582,8 @@ msgid "Services queued successfully"
msgstr "Diensten succesvol in de wachtrij geplaatst" msgstr "Diensten succesvol in de wachtrij geplaatst"
#: apps/dca/forms.py:65 apps/dca/forms.py:164 #: apps/dca/forms.py:65 apps/dca/forms.py:164
#, fuzzy
#| msgid "Deleted transactions"
msgid "Create transaction" msgid "Create transaction"
msgstr "Verwijderde verrichtingen" msgstr "Maak verrichtingen"
#: apps/dca/forms.py:70 apps/transactions/forms.py:267 #: apps/dca/forms.py:70 apps/transactions/forms.py:267
msgid "From Account" msgid "From Account"
@@ -602,31 +600,29 @@ msgstr "Uitgave Transactie"
#: apps/dca/forms.py:120 apps/dca/forms.py:130 #: apps/dca/forms.py:120 apps/dca/forms.py:130
msgid "Type to search for a transaction to link to this entry" msgid "Type to search for a transaction to link to this entry"
msgstr "" msgstr ""
"Type om een transactie te zoeken die aan dit item moet worden gekoppeld"
#: apps/dca/forms.py:126 apps/dca/models.py:177 #: apps/dca/forms.py:126 apps/dca/models.py:177
msgid "Income Transaction" msgid "Income Transaction"
msgstr "Ontvangsten Transactie" msgstr "Ontvangsten Transactie"
#: apps/dca/forms.py:210 #: apps/dca/forms.py:210
#, fuzzy
#| msgid "Edit transaction"
msgid "Link transaction" msgid "Link transaction"
msgstr "Bewerk verrichting" msgstr "Koppel verrichting"
#: apps/dca/forms.py:279 apps/dca/forms.py:280 apps/dca/forms.py:285 #: apps/dca/forms.py:279 apps/dca/forms.py:280 apps/dca/forms.py:285
#: apps/dca/forms.py:289 #: apps/dca/forms.py:289
msgid "You must provide an account." msgid "You must provide an account."
msgstr "" msgstr "Je moet een account opgeven."
#: apps/dca/forms.py:294 apps/transactions/forms.py:414 #: apps/dca/forms.py:294 apps/transactions/forms.py:414
msgid "From and To accounts must be different." msgid "From and To accounts must be different."
msgstr "Van en Naar rekening moeten verschillend zijn." msgstr "Van en Naar rekening moeten verschillend zijn."
#: apps/dca/forms.py:308 #: apps/dca/forms.py:308
#, fuzzy, python-format #, python-format
#| msgid "DCA Strategies"
msgid "DCA for %(strategy_name)s" msgid "DCA for %(strategy_name)s"
msgstr "DCA Strategieën" msgstr "DCA voor %(strategy_name)s"
#: apps/dca/models.py:17 #: apps/dca/models.py:17
msgid "Target Currency" msgid "Target Currency"
@@ -749,7 +745,7 @@ msgstr "Regels"
#: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56 #: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56
msgid "DCA" msgid "DCA"
msgstr "" msgstr "DCA"
#: apps/export_app/forms.py:86 apps/export_app/forms.py:147 #: apps/export_app/forms.py:86 apps/export_app/forms.py:147
#: templates/import_app/fragments/profiles/list.html:5 #: templates/import_app/fragments/profiles/list.html:5
@@ -759,18 +755,16 @@ msgstr "Profielen importeren"
#: apps/export_app/forms.py:112 templates/export_app/fragments/export.html:5 #: apps/export_app/forms.py:112 templates/export_app/fragments/export.html:5
#: templates/export_app/pages/index.html:15 #: templates/export_app/pages/index.html:15
#, fuzzy
#| msgid "Import"
msgid "Export" msgid "Export"
msgstr "Importeer" msgstr "Exporteer"
#: apps/export_app/forms.py:121 #: apps/export_app/forms.py:121
msgid "Import a ZIP file exported from WYGIWYH" msgid "Import a ZIP file exported from WYGIWYH"
msgstr "" msgstr "Importeer een ZIP-bestand geëxporteerd vanuit WYGIWYH"
#: apps/export_app/forms.py:122 #: apps/export_app/forms.py:122
msgid "ZIP File" msgid "ZIP File"
msgstr "" msgstr "ZIP-bestand"
#: apps/export_app/forms.py:138 apps/rules/models.py:16 #: apps/export_app/forms.py:138 apps/rules/models.py:16
msgid "Transaction rules" msgid "Transaction rules"
@@ -793,22 +787,22 @@ msgstr "Herstel"
#: apps/export_app/forms.py:187 #: apps/export_app/forms.py:187
msgid "Please upload either a ZIP file or at least one CSV file" msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "" msgstr "Upload een ZIP-bestand of ten minste één CSV-bestand"
#: apps/export_app/views.py:169 #: apps/export_app/views.py:168
msgid "You have to select at least one export" msgid "You have to select at least one export"
msgstr "" msgstr "U moet ten minste één export selecteren"
#: apps/export_app/views.py:187 #: apps/export_app/views.py:186
#, fuzzy
#| msgid "Tag updated successfully"
msgid "Data restored successfully" msgid "Data restored successfully"
msgstr "Label succesvol bijgewerkt" msgstr "Gegevens succesvol hersteld"
#: apps/export_app/views.py:199 #: apps/export_app/views.py:198
msgid "" msgid ""
"There was an error restoring your data. Check the logs for more details." "There was an error restoring your data. Check the logs for more details."
msgstr "" msgstr ""
"Er is een fout opgetreden bij het herstellen van uw gegevens. Controleer de "
"logboeken voor meer details."
#: apps/import_app/forms.py:49 #: apps/import_app/forms.py:49
msgid "Select a file" msgid "Select a file"
@@ -886,22 +880,20 @@ msgstr "Run met succes verwijderd"
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36 #: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
#: apps/insights/utils/sankey.py:167 #: apps/insights/utils/sankey.py:167
#, fuzzy
#| msgid "Categories"
msgid "Uncategorized" msgid "Uncategorized"
msgstr "Categorieën" msgstr "Ongecategoriseerd"
#: apps/insights/utils/category_explorer.py:70 #: apps/insights/utils/category_explorer.py:66
#: apps/insights/utils/category_explorer.py:153 #: apps/insights/utils/category_explorer.py:145
#: templates/cotton/ui/percentage_distribution.html:10 #: templates/cotton/ui/percentage_distribution.html:10
#: templates/cotton/ui/percentage_distribution.html:14 #: templates/cotton/ui/percentage_distribution.html:14
#: templates/insights/fragments/category_explorer/charts/account.html:60 #: templates/insights/fragments/category_explorer/charts/account.html:72
#: templates/insights/fragments/category_explorer/charts/currency.html:60 #: templates/insights/fragments/category_explorer/charts/currency.html:72
msgid "Current Income" msgid "Current Income"
msgstr "Huidige inkomsten" msgstr "Huidige inkomsten"
#: apps/insights/utils/category_explorer.py:74 #: apps/insights/utils/category_explorer.py:70
#: apps/insights/utils/category_explorer.py:157 #: apps/insights/utils/category_explorer.py:149
#: templates/cotton/ui/percentage_distribution.html:24 #: templates/cotton/ui/percentage_distribution.html:24
#: templates/cotton/ui/percentage_distribution.html:28 #: templates/cotton/ui/percentage_distribution.html:28
#: templates/insights/fragments/category_explorer/charts/account.html:66 #: templates/insights/fragments/category_explorer/charts/account.html:66
@@ -909,30 +901,28 @@ msgstr "Huidige inkomsten"
msgid "Current Expenses" msgid "Current Expenses"
msgstr "Huidige uitgaven" msgstr "Huidige uitgaven"
#: apps/insights/utils/category_explorer.py:78 #: apps/insights/utils/category_explorer.py:74
#: apps/insights/utils/category_explorer.py:161 #: apps/insights/utils/category_explorer.py:153
#: templates/cotton/ui/percentage_distribution.html:3 #: templates/cotton/ui/percentage_distribution.html:3
#: templates/cotton/ui/percentage_distribution.html:7 #: templates/cotton/ui/percentage_distribution.html:7
#: templates/insights/fragments/category_explorer/charts/account.html:72 #: templates/insights/fragments/category_explorer/charts/account.html:78
#: templates/insights/fragments/category_explorer/charts/currency.html:72 #: templates/insights/fragments/category_explorer/charts/currency.html:78
msgid "Projected Income" msgid "Projected Income"
msgstr "Verwachte inkomsten" msgstr "Verwachte inkomsten"
#: apps/insights/utils/category_explorer.py:82 #: apps/insights/utils/category_explorer.py:78
#: apps/insights/utils/category_explorer.py:165 #: apps/insights/utils/category_explorer.py:157
#: templates/cotton/ui/percentage_distribution.html:17 #: templates/cotton/ui/percentage_distribution.html:17
#: templates/cotton/ui/percentage_distribution.html:21 #: templates/cotton/ui/percentage_distribution.html:21
#: templates/insights/fragments/category_explorer/charts/account.html:78 #: templates/insights/fragments/category_explorer/charts/account.html:60
#: templates/insights/fragments/category_explorer/charts/currency.html:78 #: templates/insights/fragments/category_explorer/charts/currency.html:60
msgid "Projected Expenses" msgid "Projected Expenses"
msgstr "Verwachte uitgaven" msgstr "Verwachte uitgaven"
#: apps/insights/utils/sankey.py:133 apps/insights/utils/sankey.py:134 #: apps/insights/utils/sankey.py:133 apps/insights/utils/sankey.py:134
#: apps/insights/utils/sankey.py:263 apps/insights/utils/sankey.py:264 #: apps/insights/utils/sankey.py:263 apps/insights/utils/sankey.py:264
#, fuzzy
#| msgid "Save"
msgid "Saved" msgid "Saved"
msgstr "Opslaan" msgstr "Opgeslagen"
#: apps/rules/forms.py:20 #: apps/rules/forms.py:20
msgid "Run on creation" msgid "Run on creation"
@@ -1085,13 +1075,12 @@ msgid "Filter"
msgstr "Filter" msgstr "Filter"
#: apps/rules/models.py:85 #: apps/rules/models.py:85
#, fuzzy
msgid "" msgid ""
"Generic expression to enable or disable execution. Should evaluate to True " "Generic expression to enable or disable execution. Should evaluate to True "
"or False" "or False"
msgstr "" msgstr ""
"Generieke expressie om uitvoering in of uit te schakelen. Moet evalueren " "Generieke expressie om uitvoering in of uit te schakelen. Moet evalueren "
"naar True of False" "naar Waar of Onwaar"
#: apps/rules/models.py:289 #: apps/rules/models.py:289
msgid "Update or create transaction action" msgid "Update or create transaction action"
@@ -1296,16 +1285,12 @@ msgid "No tags"
msgstr "Geen labels" msgstr "Geen labels"
#: apps/transactions/models.py:324 #: apps/transactions/models.py:324
#, fuzzy
#| msgid "No categories"
msgid "No category" msgid "No category"
msgstr "Geen categorieën" msgstr "Geen categorie"
#: apps/transactions/models.py:326 #: apps/transactions/models.py:326
#, fuzzy
#| msgid "Description"
msgid "No description" msgid "No description"
msgstr "Beschrijving" msgstr "Geen Beschrijving"
#: apps/transactions/models.py:332 #: apps/transactions/models.py:332
msgid "Yearly" msgid "Yearly"
@@ -1910,6 +1895,7 @@ msgstr "Sluiten"
#: templates/cotton/config/search.html:6 #: templates/cotton/config/search.html:6
#: templates/import_app/fragments/profiles/list_presets.html:13 #: templates/import_app/fragments/profiles/list_presets.html:13
#: templates/monthly_overview/pages/overview.html:177
msgid "Search" msgid "Search"
msgstr "Zoeken" msgstr "Zoeken"
@@ -2255,7 +2241,7 @@ msgstr "Geen diensten ingesteld"
#: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136 #: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136
msgid "Export and Restore" msgid "Export and Restore"
msgstr "" msgstr "Exporteren en Herstellen"
#: templates/import_app/fragments/profiles/add.html:6 #: templates/import_app/fragments/profiles/add.html:6
msgid "Add new import profile" msgid "Add new import profile"
@@ -2360,7 +2346,7 @@ msgstr "Huidige"
#: templates/includes/navbar.html:50 #: templates/includes/navbar.html:50
msgid "Insights" msgid "Insights"
msgstr "" msgstr "Inzichten"
#: templates/includes/navbar.html:66 #: templates/includes/navbar.html:66
msgid "Trash Can" msgid "Trash Can"
@@ -2436,8 +2422,8 @@ msgstr "Annuleer"
msgid "Confirm" msgid "Confirm"
msgstr "Bevestig" msgstr "Bevestig"
#: templates/insights/fragments/category_explorer/charts/account.html:99 #: templates/insights/fragments/category_explorer/charts/account.html:100
#: templates/insights/fragments/category_explorer/charts/currency.html:91 #: templates/insights/fragments/category_explorer/charts/currency.html:92
#: templates/monthly_overview/fragments/monthly_account_summary.html:14 #: templates/monthly_overview/fragments/monthly_account_summary.html:14
#: templates/monthly_overview/fragments/monthly_currency_summary.html:13 #: templates/monthly_overview/fragments/monthly_currency_summary.html:13
#: templates/transactions/fragments/all_account_summary.html:14 #: templates/transactions/fragments/all_account_summary.html:14
@@ -2451,27 +2437,35 @@ msgstr "Geen informatie om weer te geven"
#: templates/insights/fragments/category_explorer/index.html:14 #: templates/insights/fragments/category_explorer/index.html:14
msgid "Income/Expense by Account" msgid "Income/Expense by Account"
msgstr "" msgstr "Inkomsten/uitgaven per rekening"
#: templates/insights/fragments/category_explorer/index.html:26 #: templates/insights/fragments/category_explorer/index.html:26
#, fuzzy
#| msgid "Exchange Currency"
msgid "Income/Expense by Currency" msgid "Income/Expense by Currency"
msgstr "Eenheid Wisselgeld" msgstr "Inkomsten/uitgaven per Munteenheid"
#: templates/insights/fragments/late_transactions.html:15
msgid "All good!"
msgstr "Allemaal goed!"
#: templates/insights/fragments/late_transactions.html:16
msgid "No late transactions"
msgstr "Geen betalingsachterstanden"
#: templates/insights/fragments/latest_transactions.html:14
msgid "No recent transactions"
msgstr "Geen recente betalingen"
#: templates/insights/fragments/sankey.html:93 #: templates/insights/fragments/sankey.html:93
msgid "From" msgid "From"
msgstr "" msgstr "Van"
#: templates/insights/fragments/sankey.html:96 #: templates/insights/fragments/sankey.html:96
msgid "Percentage" msgid "Percentage"
msgstr "" msgstr "Percentage"
#: templates/insights/pages/index.html:35 #: templates/insights/pages/index.html:35
#, fuzzy
#| msgid "Monthly"
msgid "Month" msgid "Month"
msgstr "Maandelijks" msgstr "Maand"
#: templates/insights/pages/index.html:38 #: templates/insights/pages/index.html:38
#: templates/yearly_overview/pages/overview_by_account.html:61 #: templates/yearly_overview/pages/overview_by_account.html:61
@@ -2480,38 +2474,36 @@ msgid "Year"
msgstr "Jaar" msgstr "Jaar"
#: templates/insights/pages/index.html:43 #: templates/insights/pages/index.html:43
#, fuzzy
#| msgid "Unchanged"
msgid "Month Range" msgid "Month Range"
msgstr "Ongewijzigd" msgstr "Maand Bereik"
#: templates/insights/pages/index.html:48 #: templates/insights/pages/index.html:48
msgid "Year Range" msgid "Year Range"
msgstr "" msgstr "Jaar Bereik"
#: templates/insights/pages/index.html:53 #: templates/insights/pages/index.html:53
#, fuzzy
#| msgid "Date and Time"
msgid "Date Range" msgid "Date Range"
msgstr "Datum en Tijd" msgstr "Datum Bereik"
#: templates/insights/pages/index.html:82 #: templates/insights/pages/index.html:81
#, fuzzy
#| msgid "Account"
msgid "Account Flow" msgid "Account Flow"
msgstr "Rekening" msgstr "Rekeningstroom"
#: templates/insights/pages/index.html:89 #: templates/insights/pages/index.html:88
#, fuzzy
#| msgid "Currency Code"
msgid "Currency Flow" msgid "Currency Flow"
msgstr "Munteenheids Code" msgstr "Geldstroom"
#: templates/insights/pages/index.html:96 #: templates/insights/pages/index.html:95
#, fuzzy
#| msgid "Category name"
msgid "Category Explorer" msgid "Category Explorer"
msgstr "Naam van categorie" msgstr "Categorie Verkenner"
#: templates/insights/pages/index.html:102
msgid "Late Transactions"
msgstr "Betalingsachterstanden"
#: templates/insights/pages/index.html:108
msgid "Latest Transactions"
msgstr "Laatste Verrichtingen"
#: templates/installment_plans/fragments/add.html:5 #: templates/installment_plans/fragments/add.html:5
msgid "Add installment plan" msgid "Add installment plan"
@@ -2875,6 +2867,26 @@ msgstr "Bedragen tonen"
msgid "Yearly Overview" msgid "Yearly Overview"
msgstr "Jaaroverzicht" msgstr "Jaaroverzicht"
#, fuzzy
#~| msgid "From Amount"
#~ msgid "Principal Amount"
#~ msgstr "Van Bedrag"
#, fuzzy
#~| msgid "Interval"
#~ msgid "Interest"
#~ msgstr "Interval"
#, fuzzy
#~| msgid "Management"
#~ msgid "Loan Payment"
#~ msgstr "Beheer"
#, fuzzy
#~| msgid "Management"
#~ msgid "Loan Payments"
#~ msgstr "Beheer"
#, fuzzy #, fuzzy
#~| msgid "Installment Plans" #~| msgid "Installment Plans"
#~ msgid "Installment Planss" #~ msgid "Installment Planss"
@@ -2935,11 +2947,6 @@ msgstr "Jaaroverzicht"
#~ msgid "Reference Date Operator" #~ msgid "Reference Date Operator"
#~ msgstr "Referentiedatum vanaf" #~ msgstr "Referentiedatum vanaf"
#, fuzzy
#~| msgid "From Amount"
#~ msgid "Search Amount"
#~ msgstr "Van Bedrag"
#, fuzzy #, fuzzy
#~| msgid "Amount max" #~| msgid "Amount max"
#~ msgid "Amount Operator" #~ msgid "Amount Operator"

View File

@@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-19 13:44-0300\n" "POT-Creation-Date: 2025-02-24 16:30-0300\n"
"PO-Revision-Date: 2025-02-19 13:50-0300\n" "PO-Revision-Date: 2025-02-19 23:06-0300\n"
"Last-Translator: Herculino Trotta\n" "Last-Translator: Herculino Trotta\n"
"Language-Team: \n" "Language-Team: \n"
"Language: pt_BR\n" "Language: pt_BR\n"
@@ -774,7 +774,7 @@ msgstr "Ação de editar de transação"
#: apps/export_app/forms.py:143 apps/rules/models.py:290 #: apps/export_app/forms.py:143 apps/rules/models.py:290
msgid "Update or create transaction actions" msgid "Update or create transaction actions"
msgstr "Ações de atualizar ou criar transação " msgstr "Ações de atualizar ou criar transação"
#: apps/export_app/forms.py:176 templates/cotton/transaction/item.html:158 #: apps/export_app/forms.py:176 templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47 #: templates/cotton/ui/deleted_transactions_action_bar.html:47
@@ -787,15 +787,15 @@ msgstr "Restaurar"
msgid "Please upload either a ZIP file or at least one CSV file" msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "Carregue um arquivo ZIP ou pelo menos um arquivo CSV" msgstr "Carregue um arquivo ZIP ou pelo menos um arquivo CSV"
#: apps/export_app/views.py:169 #: apps/export_app/views.py:168
msgid "You have to select at least one export" msgid "You have to select at least one export"
msgstr "É necessário selecionar pelo menos uma exportação" msgstr "É necessário selecionar pelo menos uma exportação"
#: apps/export_app/views.py:187 #: apps/export_app/views.py:186
msgid "Data restored successfully" msgid "Data restored successfully"
msgstr "Dados restaurados com sucesso" msgstr "Dados restaurados com sucesso"
#: apps/export_app/views.py:199 #: apps/export_app/views.py:198
msgid "" msgid ""
"There was an error restoring your data. Check the logs for more details." "There was an error restoring your data. Check the logs for more details."
msgstr "" msgstr ""
@@ -881,17 +881,17 @@ msgstr "Importação apagada com sucesso"
msgid "Uncategorized" msgid "Uncategorized"
msgstr "Sem categoria" msgstr "Sem categoria"
#: apps/insights/utils/category_explorer.py:70 #: apps/insights/utils/category_explorer.py:66
#: apps/insights/utils/category_explorer.py:153 #: apps/insights/utils/category_explorer.py:145
#: templates/cotton/ui/percentage_distribution.html:10 #: templates/cotton/ui/percentage_distribution.html:10
#: templates/cotton/ui/percentage_distribution.html:14 #: templates/cotton/ui/percentage_distribution.html:14
#: templates/insights/fragments/category_explorer/charts/account.html:60 #: templates/insights/fragments/category_explorer/charts/account.html:72
#: templates/insights/fragments/category_explorer/charts/currency.html:60 #: templates/insights/fragments/category_explorer/charts/currency.html:72
msgid "Current Income" msgid "Current Income"
msgstr "Renda Atual" msgstr "Renda Atual"
#: apps/insights/utils/category_explorer.py:74 #: apps/insights/utils/category_explorer.py:70
#: apps/insights/utils/category_explorer.py:157 #: apps/insights/utils/category_explorer.py:149
#: templates/cotton/ui/percentage_distribution.html:24 #: templates/cotton/ui/percentage_distribution.html:24
#: templates/cotton/ui/percentage_distribution.html:28 #: templates/cotton/ui/percentage_distribution.html:28
#: templates/insights/fragments/category_explorer/charts/account.html:66 #: templates/insights/fragments/category_explorer/charts/account.html:66
@@ -899,21 +899,21 @@ msgstr "Renda Atual"
msgid "Current Expenses" msgid "Current Expenses"
msgstr "Despesas Atuais" msgstr "Despesas Atuais"
#: apps/insights/utils/category_explorer.py:78 #: apps/insights/utils/category_explorer.py:74
#: apps/insights/utils/category_explorer.py:161 #: apps/insights/utils/category_explorer.py:153
#: templates/cotton/ui/percentage_distribution.html:3 #: templates/cotton/ui/percentage_distribution.html:3
#: templates/cotton/ui/percentage_distribution.html:7 #: templates/cotton/ui/percentage_distribution.html:7
#: templates/insights/fragments/category_explorer/charts/account.html:72 #: templates/insights/fragments/category_explorer/charts/account.html:78
#: templates/insights/fragments/category_explorer/charts/currency.html:72 #: templates/insights/fragments/category_explorer/charts/currency.html:78
msgid "Projected Income" msgid "Projected Income"
msgstr "Renda Prevista" msgstr "Renda Prevista"
#: apps/insights/utils/category_explorer.py:82 #: apps/insights/utils/category_explorer.py:78
#: apps/insights/utils/category_explorer.py:165 #: apps/insights/utils/category_explorer.py:157
#: templates/cotton/ui/percentage_distribution.html:17 #: templates/cotton/ui/percentage_distribution.html:17
#: templates/cotton/ui/percentage_distribution.html:21 #: templates/cotton/ui/percentage_distribution.html:21
#: templates/insights/fragments/category_explorer/charts/account.html:78 #: templates/insights/fragments/category_explorer/charts/account.html:60
#: templates/insights/fragments/category_explorer/charts/currency.html:78 #: templates/insights/fragments/category_explorer/charts/currency.html:60
msgid "Projected Expenses" msgid "Projected Expenses"
msgstr "Despesas Previstas" msgstr "Despesas Previstas"
@@ -1082,7 +1082,7 @@ msgstr ""
#: apps/rules/models.py:289 #: apps/rules/models.py:289
msgid "Update or create transaction action" msgid "Update or create transaction action"
msgstr " Ação de atualizar ou criar transação" msgstr "Ação de atualizar ou criar transação"
#: apps/rules/views.py:52 #: apps/rules/views.py:52
msgid "Rule deactivated successfully" msgid "Rule deactivated successfully"
@@ -1892,6 +1892,7 @@ msgstr "Fechar"
#: templates/cotton/config/search.html:6 #: templates/cotton/config/search.html:6
#: templates/import_app/fragments/profiles/list_presets.html:13 #: templates/import_app/fragments/profiles/list_presets.html:13
#: templates/monthly_overview/pages/overview.html:177
msgid "Search" msgid "Search"
msgstr "Buscar" msgstr "Buscar"
@@ -2419,8 +2420,8 @@ msgstr "Cancelar"
msgid "Confirm" msgid "Confirm"
msgstr "Confirmar" msgstr "Confirmar"
#: templates/insights/fragments/category_explorer/charts/account.html:99 #: templates/insights/fragments/category_explorer/charts/account.html:100
#: templates/insights/fragments/category_explorer/charts/currency.html:91 #: templates/insights/fragments/category_explorer/charts/currency.html:92
#: templates/monthly_overview/fragments/monthly_account_summary.html:14 #: templates/monthly_overview/fragments/monthly_account_summary.html:14
#: templates/monthly_overview/fragments/monthly_currency_summary.html:13 #: templates/monthly_overview/fragments/monthly_currency_summary.html:13
#: templates/transactions/fragments/all_account_summary.html:14 #: templates/transactions/fragments/all_account_summary.html:14
@@ -2440,6 +2441,18 @@ msgstr "Gasto/Despesa por Conta"
msgid "Income/Expense by Currency" msgid "Income/Expense by Currency"
msgstr "Gasto/Despesa por Moeda" msgstr "Gasto/Despesa por Moeda"
#: templates/insights/fragments/late_transactions.html:15
msgid "All good!"
msgstr "Tudo certo!"
#: templates/insights/fragments/late_transactions.html:16
msgid "No late transactions"
msgstr "Nenhuma transação atrasada"
#: templates/insights/fragments/latest_transactions.html:14
msgid "No recent transactions"
msgstr "Nenhuma transação recente"
#: templates/insights/fragments/sankey.html:93 #: templates/insights/fragments/sankey.html:93
msgid "From" msgid "From"
msgstr "De" msgstr "De"
@@ -2470,18 +2483,26 @@ msgstr "Intervalo de Ano"
msgid "Date Range" msgid "Date Range"
msgstr "Intervalo de Data" msgstr "Intervalo de Data"
#: templates/insights/pages/index.html:82 #: templates/insights/pages/index.html:81
msgid "Account Flow" msgid "Account Flow"
msgstr "Fluxo de Conta" msgstr "Fluxo de Conta"
#: templates/insights/pages/index.html:89 #: templates/insights/pages/index.html:88
msgid "Currency Flow" msgid "Currency Flow"
msgstr "Fluxo de Moeda" msgstr "Fluxo de Moeda"
#: templates/insights/pages/index.html:96 #: templates/insights/pages/index.html:95
msgid "Category Explorer" msgid "Category Explorer"
msgstr "Explorador de Categoria" msgstr "Explorador de Categoria"
#: templates/insights/pages/index.html:102
msgid "Late Transactions"
msgstr "Transações Atrasadas"
#: templates/insights/pages/index.html:108
msgid "Latest Transactions"
msgstr "Últimas Transações"
#: templates/installment_plans/fragments/add.html:5 #: templates/installment_plans/fragments/add.html:5
msgid "Add installment plan" msgid "Add installment plan"
msgstr "Adicionar parcelamento" msgstr "Adicionar parcelamento"
@@ -2841,6 +2862,26 @@ msgstr "Mostrar valores"
msgid "Yearly Overview" msgid "Yearly Overview"
msgstr "Visão Anual" msgstr "Visão Anual"
#, fuzzy
#~| msgid "From Amount"
#~ msgid "Principal Amount"
#~ msgstr "Quantia de origem"
#, fuzzy
#~| msgid "Interval"
#~ msgid "Interest"
#~ msgstr "Intervalo"
#, fuzzy
#~| msgid "Management"
#~ msgid "Loan Payment"
#~ msgstr "Gerenciar"
#, fuzzy
#~| msgid "Management"
#~ msgid "Loan Payments"
#~ msgstr "Gerenciar"
#, fuzzy #, fuzzy
#~| msgid "Installment Plans" #~| msgid "Installment Plans"
#~ msgid "Installment Planss" #~ msgid "Installment Planss"
@@ -2906,11 +2947,6 @@ msgstr "Visão Anual"
#~ msgid "Reference Date Operator" #~ msgid "Reference Date Operator"
#~ msgstr "Data de Referência de" #~ msgstr "Data de Referência de"
#, fuzzy
#~| msgid "From Amount"
#~ msgid "Search Amount"
#~ msgstr "Quantia de origem"
#, fuzzy #, fuzzy
#~| msgid "Amount max" #~| msgid "Amount max"
#~ msgid "Amount Operator" #~ msgid "Amount Operator"

View File

@@ -1,7 +1,7 @@
<div class="row {% if not remove_padding %}p-5{% endif %}"> <div class="row {% if not remove_padding %}p-5{% endif %}">
<div class="col {% if not remove_padding %}p-5{% endif %}"> <div class="col {% if not remove_padding %}p-5{% endif %}">
<div class="text-center"> <div class="text-center">
<i class="fa-solid fa-circle-xmark tw-text-6xl"></i> <i class="{% if icon %}{{ icon }}{% else %}fa-solid fa-circle-xmark{% endif %} tw-text-6xl"></i>
<p class="lead mt-4 mb-0">{{ title }}</p> <p class="lead mt-4 mb-0">{{ title }}</p>
<p class="tw-text-gray-500">{{ subtitle }}</p> <p class="tw-text-gray-500">{{ subtitle }}</p>
</div> </div>

View File

@@ -15,9 +15,9 @@
_="on mouseover remove .tw-invisible from the first .transaction-actions in me end _="on mouseover remove .tw-invisible from the first .transaction-actions in me end
on mouseout add .tw-invisible to the first .transaction-actions in me end"> on mouseout add .tw-invisible to the first .transaction-actions in me end">
<div class="row font-monospace tw-text-sm align-items-center"> <div class="row font-monospace tw-text-sm align-items-center">
<div class="col-lg-1 col-12 d-flex align-items-center tw-text-2xl lg:tw-text-xl text-lg-center text-center"> <div class="col-lg-auto col-12 d-flex align-items-center tw-text-2xl lg:tw-text-xl text-lg-center text-center p-0 ps-1">
{% if not transaction.deleted %} {% if not transaction.deleted %}
<a class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500" <a class="text-decoration-none p-3 tw-text-gray-500"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}" title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"
role="button" role="button"
hx-get="{% url 'transaction_pay' transaction_id=transaction.id %}" hx-get="{% url 'transaction_pay' transaction_id=transaction.id %}"
@@ -27,14 +27,14 @@
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
</a> </a>
{% else %} {% else %}
<div class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500" <div class="text-decoration-none p-3 tw-text-gray-500"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"> title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}">
{% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i {% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="col-lg-8 col-12"> <div class="col-lg col-12">
{# Date#} {# Date#}
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> <div class="row mb-2 mb-lg-1 tw-text-gray-400">
<div class="col-auto pe-1"><i class="fa-solid fa-calendar fa-fw me-1 fa-xs"></i></div> <div class="col-auto pe-1"><i class="fa-solid fa-calendar fa-fw me-1 fa-xs"></i></div>
@@ -92,7 +92,7 @@
{% endwith %} {% endwith %}
</div> </div>
</div> </div>
<div class="col-lg-3 col-12 text-lg-end align-self-end"> <div class="col-lg-auto col-12 text-lg-end align-self-end">
<div class="main-amount mb-2 mb-lg-0"> <div class="main-amount mb-2 mb-lg-0">
<c-amount.display <c-amount.display
:amount="transaction.amount" :amount="transaction.amount"

View File

@@ -1,9 +1,9 @@
<div class="card tw-relative h-100 shadow"> <div class="card tw-relative h-100 shadow">
<div class="tw-absolute tw-h-8 tw-w-8 tw-right-2 tw-top-2 tw-bg-{{ color }}-300 tw-text-{{ color }}-800 text-center align-items-center d-flex justify-content-center rounded-2"> <div class="tw-absolute tw-h-8 tw-w-8 tw-right-2 tw-top-2 tw-bg-{{ color }}-300 tw-text-{{ color }}-800 text-center align-items-center d-flex justify-content-center rounded-2">
<i class="{{ icon }}"></i> {% if icon %}<i class="{{ icon }}"></i>{% else %}<span class="fw-bold">{{ title.0 }}</span>{% endif %}
</div> </div>
<div class="card-body"> <div class="card-body">
<h5 class="tw-text-{{ color }}-400 fw-bold tw-mr-[50px]" {{ attrs }}>{{ title }}{% if help_text %}{% include 'includes/help_icon.html' with content=help_text %}{% endif %}</h5> <h5 class="tw-text-{{ color }}-400 fw-bold tw-mr-[50px]" {{ attrs }}>{{ title }}{% if help_text %}{% include 'includes/help_icon.html' with content=help_text %}{% endif %}</h5>
{{ slot }} {{ slot }}
</div> </div>
</div> </div>

View File

@@ -57,9 +57,9 @@
labels: accountData.labels, labels: accountData.labels,
datasets: [ datasets: [
{ {
label: "{% trans 'Current Income' %}", label: "{% trans 'Projected Expenses' %}",
data: accountData.datasets[0].data, data: accountData.datasets[3].data,
backgroundColor: '#4dde80', backgroundColor: '#f8717180', // Added transparency
stack: 'stack0' stack: 'stack0'
}, },
{ {
@@ -68,18 +68,19 @@
backgroundColor: '#f87171', backgroundColor: '#f87171',
stack: 'stack0' stack: 'stack0'
}, },
{
label: "{% trans 'Current Income' %}",
data: accountData.datasets[0].data,
backgroundColor: '#4dde80',
stack: 'stack0'
},
{ {
label: "{% trans 'Projected Income' %}", label: "{% trans 'Projected Income' %}",
data: accountData.datasets[2].data, data: accountData.datasets[2].data,
backgroundColor: '#4dde8080', // Added transparency backgroundColor: '#4dde8080', // Added transparency
stack: 'stack0' stack: 'stack0'
}, },
{
label: "{% trans 'Projected Expenses' %}",
data: accountData.datasets[3].data,
backgroundColor: '#f8717180', // Added transparency
stack: 'stack0'
}
] ]
}, },
options: { options: {

View File

@@ -57,9 +57,9 @@
labels: currencyData.labels, labels: currencyData.labels,
datasets: [ datasets: [
{ {
label: "{% trans 'Current Income' %}", label: "{% trans 'Projected Expenses' %}",
data: currencyData.datasets[0].data, data: currencyData.datasets[3].data,
backgroundColor: '#4dde80', backgroundColor: '#f8717180', // Added transparency
stack: 'stack0' stack: 'stack0'
}, },
{ {
@@ -68,18 +68,19 @@
backgroundColor: '#f87171', backgroundColor: '#f87171',
stack: 'stack0' stack: 'stack0'
}, },
{
label: "{% trans 'Current Income' %}",
data: currencyData.datasets[0].data,
backgroundColor: '#4dde80',
stack: 'stack0'
},
{ {
label: "{% trans 'Projected Income' %}", label: "{% trans 'Projected Income' %}",
data: currencyData.datasets[2].data, data: currencyData.datasets[2].data,
backgroundColor: '#4dde8080', // Added transparency backgroundColor: '#4dde8080', // Added transparency
stack: 'stack0' stack: 'stack0'
}, },
{
label: "{% trans 'Projected Expenses' %}",
data: currencyData.datasets[3].data,
backgroundColor: '#f8717180', // Added transparency
stack: 'stack0'
}
] ]
}, },
options: chartOptions options: chartOptions

View File

@@ -0,0 +1,18 @@
{% load i18n %}
<div hx-get="{% url 'insights_late_transactions' %}" hx-trigger="updated from:window" class="show-loading"
id="transactions-list" hx-swap="outerHTML">
{% if transactions %}
{% for transaction in transactions %}
<c-transaction.item :transaction="transaction"></c-transaction.item>
{% endfor %}
{# Floating bar #}
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
{% else %}
<c-msg.empty
icon="fa-regular fa-hourglass"
title="{% translate 'All good!' %}"
subtitle="{% translate "No late transactions" %}"></c-msg.empty>
{% endif %}
</div>

View File

@@ -0,0 +1,16 @@
{% load i18n %}
<div hx-get="{% url 'insights_late_transactions' %}" hx-trigger="updated from:window" class="show-loading"
id="transactions-list" hx-swap="outerHTML">
{% if transactions %}
{% for transaction in transactions %}
<c-transaction.item :transaction="transaction"></c-transaction.item>
{% endfor %}
{# Floating bar #}
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
{% else %}
<c-msg.empty
title="{% translate 'No recent transactions' %}"></c-msg.empty>
{% endif %}
</div>

View File

@@ -72,7 +72,6 @@
</div> </div>
</form> </form>
</div> </div>
<hr class="mt-0">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist"
aria-orientation="vertical"> aria-orientation="vertical">
<button class="nav-link" id="v-pills-tab" data-bs-toggle="pill" data-bs-target="#v-pills-content" <button class="nav-link" id="v-pills-tab" data-bs-toggle="pill" data-bs-target="#v-pills-content"
@@ -95,6 +94,19 @@
hx-indicator="#tab-content" hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Category Explorer' %} hx-target="#tab-content">{% trans 'Category Explorer' %}
</button> </button>
<hr>
<button class="nav-link" id="v-pills-tab" data-bs-toggle="pill" data-bs-target="#v-pills-content"
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
hx-get="{% url 'insights_late_transactions' %}"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Late Transactions' %}
</button>
<button class="nav-link" id="v-pills-tab" data-bs-toggle="pill" data-bs-target="#v-pills-content"
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
hx-get="{% url 'insights_latest_transactions' %}"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Latest Transactions' %}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -45,7 +45,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="tw-cursor-pointer text-primary text-end" <div class="tw-cursor-pointer text-primary text-end"
_="on click _="on click
set from_value to #id_from_currency's value set from_value to #id_from_currency's value
set to_value to #id_to_currency's value set to_value to #id_to_currency's value
@@ -58,5 +58,39 @@
<i class="fa-solid fa-rotate me-2"></i><span>{% trans 'Invert' %}</span> <i class="fa-solid fa-rotate me-2"></i><span>{% trans 'Invert' %}</span>
</div> </div>
</div> </div>
<hr>
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
{% for currency, data in rate_map.items %}
<div class="col">
<c-ui.info-card color="yellow" title="{{ currency }}">
{% for rate in data.rates.values %}
<div class="d-flex justify-content-between align-items-baseline mt-2">
<div class="text-end font-monospace">
<div class="tw-text-gray-400">
{# <c-amount.display#}
{# :amount="1"#}
{# :prefix="data.prefix"#}
{# :suffix="data.suffix"#}
{# :decimal_places="data.decimal_places"></c-amount.display>#}
</div>
</div>
<div class="dotted-line flex-grow-1"></div>
{% if currency.income_projected != 0 %}
<div class="text-end font-monospace tw-text-green-400">
<c-amount.display
:amount="rate.rate"
:prefix="rate.prefix"
:suffix="rate.suffix"
:decimal_places="rate.decimal_places"></c-amount.display>
</div>
{% else %}
<div class="text-end font-monospace">-</div>
{% endif %}
</div>
{% endfor %}
</c-ui.info-card>
</div>
{% endfor %}
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -174,7 +174,7 @@
</div> </div>
<div id="search" class="my-3"> <div id="search" class="my-3">
<label class="w-100"> <label class="w-100">
<input type="search" class="form-control" placeholder="Buscar" hx-preserve id="quick-search" <input type="search" class="form-control" placeholder="{% translate 'Search' %}" hx-preserve id="quick-search"
_="on input or search or htmx:afterSwap from window _="on input or search or htmx:afterSwap from window
if my value is empty if my value is empty
trigger toggle on <.transactions-divider-collapse/> trigger toggle on <.transactions-divider-collapse/>

View File

@@ -2,12 +2,14 @@ import AirDatepicker from 'air-datepicker';
import en from 'air-datepicker/locale/en'; import en from 'air-datepicker/locale/en';
import ptBr from 'air-datepicker/locale/pt-BR'; import ptBr from 'air-datepicker/locale/pt-BR';
import nl from 'air-datepicker/locale/nl'; import nl from 'air-datepicker/locale/nl';
import de from 'air-datepicker/locale/de';
import {createPopper} from '@popperjs/core'; import {createPopper} from '@popperjs/core';
const locales = { const locales = {
'pt': ptBr, 'pt': ptBr,
'en': en, 'en': en,
'nl': nl 'nl': nl,
'de': de
}; };
function isMobileDevice() { function isMobileDevice() {
@@ -43,7 +45,7 @@ window.DatePicker = function createDynamicDatePicker(element) {
toggleSelected: element.dataset.toggleSelected === 'true', toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true', autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton], buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language], locale: locales[element.dataset.language] || locales['en'],
onSelect: ({date, formattedDate, datepicker}) => { onSelect: ({date, formattedDate, datepicker}) => {
const _event = new CustomEvent("change", { const _event = new CustomEvent("change", {
bubbles: true, bubbles: true,
@@ -117,7 +119,7 @@ window.MonthYearPicker = function createDynamicDatePicker(element) {
toggleSelected: element.dataset.toggleSelected === 'true', toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true', autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton], buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language], locale: locales[element.dataset.language] || locales['en'],
onSelect: ({date, formattedDate, datepicker}) => { onSelect: ({date, formattedDate, datepicker}) => {
const _event = new CustomEvent("change", { const _event = new CustomEvent("change", {
bubbles: true, bubbles: true,
@@ -190,7 +192,7 @@ window.YearPicker = function createDynamicDatePicker(element) {
toggleSelected: element.dataset.toggleSelected === 'true', toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true', autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton], buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language], locale: locales[element.dataset.language] || locales['en'],
onSelect: ({date, formattedDate, datepicker}) => { onSelect: ({date, formattedDate, datepicker}) => {
const _event = new CustomEvent("change", { const _event = new CustomEvent("change", {
bubbles: true, bubbles: true,