mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-25 00:44:52 +01:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91904e959b | ||
|
|
a6a85ae3a2 | ||
|
|
b0f53f45f9 | ||
|
|
0f60f8d486 | ||
|
|
efb207a109 | ||
|
|
95b1481dd5 | ||
|
|
8de340b68b | ||
|
|
ef15b85386 | ||
|
|
45d939237d | ||
|
|
6bf262e514 | ||
|
|
f9d9137336 | ||
|
|
b532521f27 | ||
|
|
1e06e2d34d | ||
|
|
a33fa5e184 | ||
|
|
a2453695d8 | ||
|
|
3e929d0433 | ||
|
|
185fc464a5 | ||
|
|
647c009525 | ||
|
|
ba75492dcc | ||
|
|
8312baaf45 | ||
|
|
4d346dc278 | ||
|
|
70ff7fab38 | ||
|
|
6947c6affd | ||
|
|
dcab83f936 | ||
|
|
b228e4ec26 | ||
|
|
4071a1301f | ||
|
|
5c9db10710 | ||
|
|
19c92e0014 | ||
|
|
6459f2eb46 |
@@ -163,6 +163,7 @@ AUTH_USER_MODEL = "users.User"
|
||||
|
||||
LANGUAGE_CODE = "en"
|
||||
LANGUAGES = (
|
||||
("de", "Deutsch"),
|
||||
("en", "English"),
|
||||
("nl", "Nederlands"),
|
||||
("pt-br", "Português (Brasil)"),
|
||||
|
||||
@@ -2,13 +2,15 @@ from import_export import fields, resources, widgets
|
||||
|
||||
from apps.accounts.models import Account
|
||||
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):
|
||||
exchange_currency = fields.Field(
|
||||
attribute="exchange_currency",
|
||||
column_name="exchange_currency",
|
||||
widget=widgets.ForeignKeyWidget(Currency, "name"),
|
||||
widget=SkipMissingForeignKeyWidget(Currency, "name"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -26,6 +28,9 @@ class ExchangeRateResource(resources.ModelResource):
|
||||
column_name="to_currency",
|
||||
widget=widgets.ForeignKeyWidget(Currency, "name"),
|
||||
)
|
||||
rate = fields.Field(
|
||||
attribute="rate", column_name="rate", widget=UniversalDecimalWidget()
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = ExchangeRate
|
||||
|
||||
@@ -3,6 +3,7 @@ from import_export.widgets import ForeignKeyWidget
|
||||
|
||||
from apps.dca.models import DCAStrategy, DCAEntry
|
||||
from apps.currencies.models import Currency
|
||||
from apps.export_app.widgets.numbers import UniversalDecimalWidget
|
||||
|
||||
|
||||
class DCAStrategyResource(resources.ModelResource):
|
||||
@@ -22,5 +23,16 @@ class DCAStrategyResource(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:
|
||||
model = DCAEntry
|
||||
|
||||
@@ -13,6 +13,7 @@ from apps.transactions.models import (
|
||||
RecurringTransaction,
|
||||
InstallmentPlan,
|
||||
)
|
||||
from apps.export_app.widgets.numbers import UniversalDecimalWidget
|
||||
|
||||
|
||||
class TransactionResource(resources.ModelResource):
|
||||
@@ -44,6 +45,12 @@ class TransactionResource(resources.ModelResource):
|
||||
column_name="internal_id", attribute="internal_id"
|
||||
)
|
||||
|
||||
amount = fields.Field(
|
||||
attribute="amount",
|
||||
column_name="amount",
|
||||
widget=UniversalDecimalWidget(),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Transaction
|
||||
|
||||
@@ -91,6 +98,12 @@ class RecurringTransactionResource(resources.ModelResource):
|
||||
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
|
||||
)
|
||||
|
||||
amount = fields.Field(
|
||||
attribute="amount",
|
||||
column_name="amount",
|
||||
widget=UniversalDecimalWidget(),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = RecurringTransaction
|
||||
|
||||
@@ -120,5 +133,11 @@ class InstallmentPlanResource(resources.ModelResource):
|
||||
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
|
||||
)
|
||||
|
||||
installment_amount = fields.Field(
|
||||
attribute="installment_amount",
|
||||
column_name="installment_amount",
|
||||
widget=UniversalDecimalWidget(),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = InstallmentPlan
|
||||
|
||||
@@ -50,7 +50,6 @@ def export_index(request):
|
||||
return render(request, "export_app/pages/index.html")
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def export_form(request):
|
||||
@@ -241,11 +240,6 @@ def process_imports(request, cleaned_data):
|
||||
dataset = Dataset()
|
||||
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
|
||||
result = resource.import_data(
|
||||
dataset,
|
||||
@@ -266,6 +260,8 @@ def process_imports(request, cleaned_data):
|
||||
raise ImportError(f"Error importing {field_name}: {str(e)}")
|
||||
|
||||
with transaction.atomic():
|
||||
files = {}
|
||||
|
||||
if zip_file := cleaned_data.get("zip_file"):
|
||||
# Process ZIP file
|
||||
with zipfile.ZipFile(zip_file) as z:
|
||||
@@ -274,10 +270,12 @@ def process_imports(request, cleaned_data):
|
||||
with z.open(filename) as f:
|
||||
content = f.read().decode("utf-8")
|
||||
|
||||
for field_name, resource_class in import_order:
|
||||
if name == field_name:
|
||||
import_dataset(content, resource_class, field_name)
|
||||
break
|
||||
files[name] = content
|
||||
|
||||
for field_name, resource_class in import_order:
|
||||
if field_name in files.keys():
|
||||
content = files[field_name]
|
||||
import_dataset(content, resource_class, field_name)
|
||||
else:
|
||||
# Process individual files
|
||||
for field_name, resource_class in import_order:
|
||||
|
||||
@@ -9,3 +9,14 @@ class AutoCreateForeignKeyWidget(ForeignKeyWidget):
|
||||
except self.model.DoesNotExist:
|
||||
return self.model.objects.create(name=value)
|
||||
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
|
||||
|
||||
18
app/apps/export_app/widgets/numbers.py
Normal file
18
app/apps/export_app/widgets/numbers.py
Normal 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(",", ".")
|
||||
@@ -29,4 +29,14 @@ urlpatterns = [
|
||||
views.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",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -14,8 +14,7 @@ def get_category_sums_by_account(queryset, category=None):
|
||||
current_income=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="IN", then="amount"),
|
||||
When(is_paid=True, then="amount"),
|
||||
When(type="IN", is_paid=True, then="amount"),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="EX", then=-F("amount")),
|
||||
When(is_paid=True, then="amount"),
|
||||
When(type="EX", is_paid=True, then=-F("amount")),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="IN", then="amount"),
|
||||
When(is_paid=False, then="amount"),
|
||||
When(type="IN", is_paid=False, then="amount"),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="EX", then=-F("amount")),
|
||||
When(is_paid=False, then="amount"),
|
||||
When(type="EX", is_paid=False, then=-F("amount")),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="IN", then="amount"),
|
||||
When(is_paid=True, then="amount"),
|
||||
When(type="IN", is_paid=True, then="amount"),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="EX", then=-F("amount")),
|
||||
When(is_paid=True, then="amount"),
|
||||
When(type="EX", is_paid=True, then=-F("amount")),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="IN", then="amount"),
|
||||
When(is_paid=False, then="amount"),
|
||||
When(type="IN", is_paid=False, then="amount"),
|
||||
default=Value(0),
|
||||
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(
|
||||
Sum(
|
||||
Case(
|
||||
When(type="EX", then=-F("amount")),
|
||||
When(is_paid=False, then="amount"),
|
||||
When(type="EX", is_paid=False, then=-F("amount")),
|
||||
default=Value(0),
|
||||
output_field=DecimalField(max_digits=42, decimal_places=30),
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ from apps.insights.utils.sankey import (
|
||||
generate_sankey_data_by_currency,
|
||||
)
|
||||
from apps.insights.utils.transactions import get_transactions
|
||||
from apps.transactions.models import TransactionCategory
|
||||
from apps.transactions.models import TransactionCategory, Transaction
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -157,3 +157,33 @@ def category_sum_by_currency(request):
|
||||
"insights/fragments/category_explorer/charts/currency.html",
|
||||
{"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},
|
||||
)
|
||||
|
||||
0
app/apps/mini_tools/utils/__init__.py
Normal file
0
app/apps/mini_tools/utils/__init__.py
Normal file
85
app/apps/mini_tools/utils/exchange_rate_map.py
Normal file
85
app/apps/mini_tools/utils/exchange_rate_map.py
Normal 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
|
||||
@@ -5,6 +5,7 @@ from apps.common.widgets.decimal import convert_to_decimal
|
||||
from apps.currencies.models import Currency
|
||||
from apps.currencies.utils.convert import convert
|
||||
from apps.mini_tools.forms import CurrencyConverterForm
|
||||
from apps.mini_tools.utils.exchange_rate_map import get_currency_exchange_map
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -14,11 +15,13 @@ def unit_price_calculator(request):
|
||||
|
||||
@login_required
|
||||
def currency_converter(request):
|
||||
rate_map = get_currency_exchange_map()
|
||||
|
||||
form = CurrencyConverterForm()
|
||||
return render(
|
||||
request,
|
||||
"mini_tools/currency_converter/currency_converter.html",
|
||||
context={"form": form},
|
||||
context={"form": form, "rate_map": rate_map},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -297,10 +297,8 @@ class UpdateOrCreateTransactionRuleAction(models.Model):
|
||||
search_query = Q()
|
||||
|
||||
def add_to_query(field_name, value, operator):
|
||||
if isinstance(value, (int, str)):
|
||||
lookup = f"{field_name}__{operator}"
|
||||
return Q(**{lookup: value})
|
||||
return Q()
|
||||
lookup = f"{field_name}__{operator}"
|
||||
return Q(**{lookup: value})
|
||||
|
||||
if self.search_account:
|
||||
value = simple.eval(self.search_account)
|
||||
|
||||
@@ -131,14 +131,16 @@ def _process_update_or_create_transaction_action(action, simple_eval):
|
||||
|
||||
# Build search query using the helper method
|
||||
search_query = action.build_search_query(simple_eval)
|
||||
logger.info("Searching transactions using: %s", search_query)
|
||||
|
||||
# Find latest matching transaction or create new
|
||||
if search_query:
|
||||
transaction = (
|
||||
Transaction.objects.filter(search_query).order_by("-date", "-id").first()
|
||||
)
|
||||
transactions = Transaction.objects.filter(search_query).order_by("-date", "-id")
|
||||
transaction = transactions.first()
|
||||
logger.info("Found at least one matching transaction, using latest")
|
||||
else:
|
||||
transaction = None
|
||||
logger.info("No matching transaction found, creating a new transaction")
|
||||
|
||||
if not transaction:
|
||||
transaction = Transaction()
|
||||
|
||||
@@ -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
2831
app/locale/en/LC_MESSAGES/django.po
Normal file
2831
app/locale/en/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-19 13:44-0300\n"
|
||||
"PO-Revision-Date: 2025-02-12 06:58+0100\n"
|
||||
"POT-Creation-Date: 2025-02-24 16:30-0300\n"
|
||||
"PO-Revision-Date: 2025-02-22 15:03+0100\n"
|
||||
"Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: nl\n"
|
||||
@@ -582,10 +582,8 @@ msgid "Services queued successfully"
|
||||
msgstr "Diensten succesvol in de wachtrij geplaatst"
|
||||
|
||||
#: apps/dca/forms.py:65 apps/dca/forms.py:164
|
||||
#, fuzzy
|
||||
#| msgid "Deleted transactions"
|
||||
msgid "Create transaction"
|
||||
msgstr "Verwijderde verrichtingen"
|
||||
msgstr "Maak verrichtingen"
|
||||
|
||||
#: apps/dca/forms.py:70 apps/transactions/forms.py:267
|
||||
msgid "From Account"
|
||||
@@ -602,31 +600,29 @@ msgstr "Uitgave Transactie"
|
||||
#: apps/dca/forms.py:120 apps/dca/forms.py:130
|
||||
msgid "Type to search for a transaction to link to this entry"
|
||||
msgstr ""
|
||||
"Type om een transactie te zoeken die aan dit item moet worden gekoppeld"
|
||||
|
||||
#: apps/dca/forms.py:126 apps/dca/models.py:177
|
||||
msgid "Income Transaction"
|
||||
msgstr "Ontvangsten Transactie"
|
||||
|
||||
#: apps/dca/forms.py:210
|
||||
#, fuzzy
|
||||
#| msgid "Edit 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:289
|
||||
msgid "You must provide an account."
|
||||
msgstr ""
|
||||
msgstr "Je moet een account opgeven."
|
||||
|
||||
#: apps/dca/forms.py:294 apps/transactions/forms.py:414
|
||||
msgid "From and To accounts must be different."
|
||||
msgstr "Van en Naar rekening moeten verschillend zijn."
|
||||
|
||||
#: apps/dca/forms.py:308
|
||||
#, fuzzy, python-format
|
||||
#| msgid "DCA Strategies"
|
||||
#, python-format
|
||||
msgid "DCA for %(strategy_name)s"
|
||||
msgstr "DCA Strategieën"
|
||||
msgstr "DCA voor %(strategy_name)s"
|
||||
|
||||
#: apps/dca/models.py:17
|
||||
msgid "Target Currency"
|
||||
@@ -749,7 +745,7 @@ msgstr "Regels"
|
||||
|
||||
#: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56
|
||||
msgid "DCA"
|
||||
msgstr ""
|
||||
msgstr "DCA"
|
||||
|
||||
#: apps/export_app/forms.py:86 apps/export_app/forms.py:147
|
||||
#: 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
|
||||
#: templates/export_app/pages/index.html:15
|
||||
#, fuzzy
|
||||
#| msgid "Import"
|
||||
msgid "Export"
|
||||
msgstr "Importeer"
|
||||
msgstr "Exporteer"
|
||||
|
||||
#: apps/export_app/forms.py:121
|
||||
msgid "Import a ZIP file exported from WYGIWYH"
|
||||
msgstr ""
|
||||
msgstr "Importeer een ZIP-bestand geëxporteerd vanuit WYGIWYH"
|
||||
|
||||
#: apps/export_app/forms.py:122
|
||||
msgid "ZIP File"
|
||||
msgstr ""
|
||||
msgstr "ZIP-bestand"
|
||||
|
||||
#: apps/export_app/forms.py:138 apps/rules/models.py:16
|
||||
msgid "Transaction rules"
|
||||
@@ -793,22 +787,22 @@ msgstr "Herstel"
|
||||
|
||||
#: apps/export_app/forms.py:187
|
||||
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"
|
||||
msgstr ""
|
||||
msgstr "U moet ten minste één export selecteren"
|
||||
|
||||
#: apps/export_app/views.py:187
|
||||
#, fuzzy
|
||||
#| msgid "Tag updated successfully"
|
||||
#: apps/export_app/views.py:186
|
||||
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 ""
|
||||
"There was an error restoring your data. Check the logs for more details."
|
||||
msgstr ""
|
||||
"Er is een fout opgetreden bij het herstellen van uw gegevens. Controleer de "
|
||||
"logboeken voor meer details."
|
||||
|
||||
#: apps/import_app/forms.py:49
|
||||
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/utils/sankey.py:167
|
||||
#, fuzzy
|
||||
#| msgid "Categories"
|
||||
msgid "Uncategorized"
|
||||
msgstr "Categorieën"
|
||||
msgstr "Ongecategoriseerd"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:70
|
||||
#: apps/insights/utils/category_explorer.py:153
|
||||
#: apps/insights/utils/category_explorer.py:66
|
||||
#: apps/insights/utils/category_explorer.py:145
|
||||
#: templates/cotton/ui/percentage_distribution.html:10
|
||||
#: templates/cotton/ui/percentage_distribution.html:14
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:72
|
||||
msgid "Current Income"
|
||||
msgstr "Huidige inkomsten"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:74
|
||||
#: apps/insights/utils/category_explorer.py:157
|
||||
#: apps/insights/utils/category_explorer.py:70
|
||||
#: apps/insights/utils/category_explorer.py:149
|
||||
#: templates/cotton/ui/percentage_distribution.html:24
|
||||
#: templates/cotton/ui/percentage_distribution.html:28
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:66
|
||||
@@ -909,30 +901,28 @@ msgstr "Huidige inkomsten"
|
||||
msgid "Current Expenses"
|
||||
msgstr "Huidige uitgaven"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:78
|
||||
#: apps/insights/utils/category_explorer.py:161
|
||||
#: apps/insights/utils/category_explorer.py:74
|
||||
#: apps/insights/utils/category_explorer.py:153
|
||||
#: templates/cotton/ui/percentage_distribution.html:3
|
||||
#: templates/cotton/ui/percentage_distribution.html:7
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:78
|
||||
msgid "Projected Income"
|
||||
msgstr "Verwachte inkomsten"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:82
|
||||
#: apps/insights/utils/category_explorer.py:165
|
||||
#: apps/insights/utils/category_explorer.py:78
|
||||
#: apps/insights/utils/category_explorer.py:157
|
||||
#: templates/cotton/ui/percentage_distribution.html:17
|
||||
#: templates/cotton/ui/percentage_distribution.html:21
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:60
|
||||
msgid "Projected Expenses"
|
||||
msgstr "Verwachte uitgaven"
|
||||
|
||||
#: apps/insights/utils/sankey.py:133 apps/insights/utils/sankey.py:134
|
||||
#: apps/insights/utils/sankey.py:263 apps/insights/utils/sankey.py:264
|
||||
#, fuzzy
|
||||
#| msgid "Save"
|
||||
msgid "Saved"
|
||||
msgstr "Opslaan"
|
||||
msgstr "Opgeslagen"
|
||||
|
||||
#: apps/rules/forms.py:20
|
||||
msgid "Run on creation"
|
||||
@@ -1085,13 +1075,12 @@ msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
#: apps/rules/models.py:85
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Generic expression to enable or disable execution. Should evaluate to True "
|
||||
"or False"
|
||||
msgstr ""
|
||||
"Generieke expressie om uitvoering in of uit te schakelen. Moet evalueren "
|
||||
"naar True of False"
|
||||
"naar Waar of Onwaar"
|
||||
|
||||
#: apps/rules/models.py:289
|
||||
msgid "Update or create transaction action"
|
||||
@@ -1296,16 +1285,12 @@ msgid "No tags"
|
||||
msgstr "Geen labels"
|
||||
|
||||
#: apps/transactions/models.py:324
|
||||
#, fuzzy
|
||||
#| msgid "No categories"
|
||||
msgid "No category"
|
||||
msgstr "Geen categorieën"
|
||||
msgstr "Geen categorie"
|
||||
|
||||
#: apps/transactions/models.py:326
|
||||
#, fuzzy
|
||||
#| msgid "Description"
|
||||
msgid "No description"
|
||||
msgstr "Beschrijving"
|
||||
msgstr "Geen Beschrijving"
|
||||
|
||||
#: apps/transactions/models.py:332
|
||||
msgid "Yearly"
|
||||
@@ -1910,6 +1895,7 @@ msgstr "Sluiten"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:177
|
||||
msgid "Search"
|
||||
msgstr "Zoeken"
|
||||
|
||||
@@ -2255,7 +2241,7 @@ msgstr "Geen diensten ingesteld"
|
||||
|
||||
#: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136
|
||||
msgid "Export and Restore"
|
||||
msgstr ""
|
||||
msgstr "Exporteren en Herstellen"
|
||||
|
||||
#: templates/import_app/fragments/profiles/add.html:6
|
||||
msgid "Add new import profile"
|
||||
@@ -2360,7 +2346,7 @@ msgstr "Huidige"
|
||||
|
||||
#: templates/includes/navbar.html:50
|
||||
msgid "Insights"
|
||||
msgstr ""
|
||||
msgstr "Inzichten"
|
||||
|
||||
#: templates/includes/navbar.html:66
|
||||
msgid "Trash Can"
|
||||
@@ -2436,8 +2422,8 @@ msgstr "Annuleer"
|
||||
msgid "Confirm"
|
||||
msgstr "Bevestig"
|
||||
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:99
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:91
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:100
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:92
|
||||
#: templates/monthly_overview/fragments/monthly_account_summary.html:14
|
||||
#: templates/monthly_overview/fragments/monthly_currency_summary.html:13
|
||||
#: 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
|
||||
msgid "Income/Expense by Account"
|
||||
msgstr ""
|
||||
msgstr "Inkomsten/uitgaven per rekening"
|
||||
|
||||
#: templates/insights/fragments/category_explorer/index.html:26
|
||||
#, fuzzy
|
||||
#| msgid "Exchange 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
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
msgstr "Van"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:96
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
msgstr "Percentage"
|
||||
|
||||
#: templates/insights/pages/index.html:35
|
||||
#, fuzzy
|
||||
#| msgid "Monthly"
|
||||
msgid "Month"
|
||||
msgstr "Maandelijks"
|
||||
msgstr "Maand"
|
||||
|
||||
#: templates/insights/pages/index.html:38
|
||||
#: templates/yearly_overview/pages/overview_by_account.html:61
|
||||
@@ -2480,38 +2474,36 @@ msgid "Year"
|
||||
msgstr "Jaar"
|
||||
|
||||
#: templates/insights/pages/index.html:43
|
||||
#, fuzzy
|
||||
#| msgid "Unchanged"
|
||||
msgid "Month Range"
|
||||
msgstr "Ongewijzigd"
|
||||
msgstr "Maand Bereik"
|
||||
|
||||
#: templates/insights/pages/index.html:48
|
||||
msgid "Year Range"
|
||||
msgstr ""
|
||||
msgstr "Jaar Bereik"
|
||||
|
||||
#: templates/insights/pages/index.html:53
|
||||
#, fuzzy
|
||||
#| msgid "Date and Time"
|
||||
msgid "Date Range"
|
||||
msgstr "Datum en Tijd"
|
||||
msgstr "Datum Bereik"
|
||||
|
||||
#: templates/insights/pages/index.html:82
|
||||
#, fuzzy
|
||||
#| msgid "Account"
|
||||
#: templates/insights/pages/index.html:81
|
||||
msgid "Account Flow"
|
||||
msgstr "Rekening"
|
||||
msgstr "Rekeningstroom"
|
||||
|
||||
#: templates/insights/pages/index.html:89
|
||||
#, fuzzy
|
||||
#| msgid "Currency Code"
|
||||
#: templates/insights/pages/index.html:88
|
||||
msgid "Currency Flow"
|
||||
msgstr "Munteenheids Code"
|
||||
msgstr "Geldstroom"
|
||||
|
||||
#: templates/insights/pages/index.html:96
|
||||
#, fuzzy
|
||||
#| msgid "Category name"
|
||||
#: templates/insights/pages/index.html:95
|
||||
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
|
||||
msgid "Add installment plan"
|
||||
@@ -2875,6 +2867,26 @@ msgstr "Bedragen tonen"
|
||||
msgid "Yearly Overview"
|
||||
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
|
||||
#~| msgid "Installment Plans"
|
||||
#~ msgid "Installment Planss"
|
||||
@@ -2935,11 +2947,6 @@ msgstr "Jaaroverzicht"
|
||||
#~ msgid "Reference Date Operator"
|
||||
#~ msgstr "Referentiedatum vanaf"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "From Amount"
|
||||
#~ msgid "Search Amount"
|
||||
#~ msgstr "Van Bedrag"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Amount max"
|
||||
#~ msgid "Amount Operator"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-19 13:44-0300\n"
|
||||
"PO-Revision-Date: 2025-02-19 13:50-0300\n"
|
||||
"POT-Creation-Date: 2025-02-24 16:30-0300\n"
|
||||
"PO-Revision-Date: 2025-02-19 23:06-0300\n"
|
||||
"Last-Translator: Herculino Trotta\n"
|
||||
"Language-Team: \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
|
||||
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
|
||||
#: 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"
|
||||
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"
|
||||
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"
|
||||
msgstr "Dados restaurados com sucesso"
|
||||
|
||||
#: apps/export_app/views.py:199
|
||||
#: apps/export_app/views.py:198
|
||||
msgid ""
|
||||
"There was an error restoring your data. Check the logs for more details."
|
||||
msgstr ""
|
||||
@@ -881,17 +881,17 @@ msgstr "Importação apagada com sucesso"
|
||||
msgid "Uncategorized"
|
||||
msgstr "Sem categoria"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:70
|
||||
#: apps/insights/utils/category_explorer.py:153
|
||||
#: apps/insights/utils/category_explorer.py:66
|
||||
#: apps/insights/utils/category_explorer.py:145
|
||||
#: templates/cotton/ui/percentage_distribution.html:10
|
||||
#: templates/cotton/ui/percentage_distribution.html:14
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:72
|
||||
msgid "Current Income"
|
||||
msgstr "Renda Atual"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:74
|
||||
#: apps/insights/utils/category_explorer.py:157
|
||||
#: apps/insights/utils/category_explorer.py:70
|
||||
#: apps/insights/utils/category_explorer.py:149
|
||||
#: templates/cotton/ui/percentage_distribution.html:24
|
||||
#: templates/cotton/ui/percentage_distribution.html:28
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:66
|
||||
@@ -899,21 +899,21 @@ msgstr "Renda Atual"
|
||||
msgid "Current Expenses"
|
||||
msgstr "Despesas Atuais"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:78
|
||||
#: apps/insights/utils/category_explorer.py:161
|
||||
#: apps/insights/utils/category_explorer.py:74
|
||||
#: apps/insights/utils/category_explorer.py:153
|
||||
#: templates/cotton/ui/percentage_distribution.html:3
|
||||
#: templates/cotton/ui/percentage_distribution.html:7
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:72
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:78
|
||||
msgid "Projected Income"
|
||||
msgstr "Renda Prevista"
|
||||
|
||||
#: apps/insights/utils/category_explorer.py:82
|
||||
#: apps/insights/utils/category_explorer.py:165
|
||||
#: apps/insights/utils/category_explorer.py:78
|
||||
#: apps/insights/utils/category_explorer.py:157
|
||||
#: templates/cotton/ui/percentage_distribution.html:17
|
||||
#: templates/cotton/ui/percentage_distribution.html:21
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:78
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:60
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:60
|
||||
msgid "Projected Expenses"
|
||||
msgstr "Despesas Previstas"
|
||||
|
||||
@@ -1082,7 +1082,7 @@ msgstr ""
|
||||
|
||||
#: apps/rules/models.py:289
|
||||
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
|
||||
msgid "Rule deactivated successfully"
|
||||
@@ -1892,6 +1892,7 @@ msgstr "Fechar"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:177
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
@@ -2419,8 +2420,8 @@ msgstr "Cancelar"
|
||||
msgid "Confirm"
|
||||
msgstr "Confirmar"
|
||||
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:99
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:91
|
||||
#: templates/insights/fragments/category_explorer/charts/account.html:100
|
||||
#: templates/insights/fragments/category_explorer/charts/currency.html:92
|
||||
#: templates/monthly_overview/fragments/monthly_account_summary.html:14
|
||||
#: templates/monthly_overview/fragments/monthly_currency_summary.html:13
|
||||
#: templates/transactions/fragments/all_account_summary.html:14
|
||||
@@ -2440,6 +2441,18 @@ msgstr "Gasto/Despesa por Conta"
|
||||
msgid "Income/Expense by Currency"
|
||||
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
|
||||
msgid "From"
|
||||
msgstr "De"
|
||||
@@ -2470,18 +2483,26 @@ msgstr "Intervalo de Ano"
|
||||
msgid "Date Range"
|
||||
msgstr "Intervalo de Data"
|
||||
|
||||
#: templates/insights/pages/index.html:82
|
||||
#: templates/insights/pages/index.html:81
|
||||
msgid "Account Flow"
|
||||
msgstr "Fluxo de Conta"
|
||||
|
||||
#: templates/insights/pages/index.html:89
|
||||
#: templates/insights/pages/index.html:88
|
||||
msgid "Currency Flow"
|
||||
msgstr "Fluxo de Moeda"
|
||||
|
||||
#: templates/insights/pages/index.html:96
|
||||
#: templates/insights/pages/index.html:95
|
||||
msgid "Category Explorer"
|
||||
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
|
||||
msgid "Add installment plan"
|
||||
msgstr "Adicionar parcelamento"
|
||||
@@ -2841,6 +2862,26 @@ msgstr "Mostrar valores"
|
||||
msgid "Yearly Overview"
|
||||
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
|
||||
#~| msgid "Installment Plans"
|
||||
#~ msgid "Installment Planss"
|
||||
@@ -2906,11 +2947,6 @@ msgstr "Visão Anual"
|
||||
#~ msgid "Reference Date Operator"
|
||||
#~ msgstr "Data de Referência de"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "From Amount"
|
||||
#~ msgid "Search Amount"
|
||||
#~ msgstr "Quantia de origem"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Amount max"
|
||||
#~ msgid "Amount Operator"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="row {% if not remove_padding %}p-5{% endif %}">
|
||||
<div class="col {% if not remove_padding %}p-5{% endif %}">
|
||||
<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="tw-text-gray-500">{{ subtitle }}</p>
|
||||
</div>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
_="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">
|
||||
<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 %}
|
||||
<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 %}"
|
||||
role="button"
|
||||
hx-get="{% url 'transaction_pay' transaction_id=transaction.id %}"
|
||||
@@ -27,14 +27,14 @@
|
||||
class="fa-regular fa-circle"></i>{% endif %}
|
||||
</a>
|
||||
{% 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 %}">
|
||||
{% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
|
||||
class="fa-regular fa-circle"></i>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-lg-8 col-12">
|
||||
<div class="col-lg col-12">
|
||||
{# Date#}
|
||||
<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>
|
||||
@@ -92,7 +92,7 @@
|
||||
{% endwith %}
|
||||
</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">
|
||||
<c-amount.display
|
||||
:amount="transaction.amount"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<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">
|
||||
<i class="{{ icon }}"></i>
|
||||
{% if icon %}<i class="{{ icon }}"></i>{% else %}<span class="fw-bold">{{ title.0 }}</span>{% endif %}
|
||||
</div>
|
||||
<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>
|
||||
{{ slot }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
labels: accountData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "{% trans 'Current Income' %}",
|
||||
data: accountData.datasets[0].data,
|
||||
backgroundColor: '#4dde80',
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: accountData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
@@ -68,18 +68,19 @@
|
||||
backgroundColor: '#f87171',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Current Income' %}",
|
||||
data: accountData.datasets[0].data,
|
||||
backgroundColor: '#4dde80',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Projected Income' %}",
|
||||
data: accountData.datasets[2].data,
|
||||
backgroundColor: '#4dde8080', // Added transparency
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: accountData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
stack: 'stack0'
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
options: {
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
labels: currencyData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "{% trans 'Current Income' %}",
|
||||
data: currencyData.datasets[0].data,
|
||||
backgroundColor: '#4dde80',
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: currencyData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
@@ -68,18 +68,19 @@
|
||||
backgroundColor: '#f87171',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Current Income' %}",
|
||||
data: currencyData.datasets[0].data,
|
||||
backgroundColor: '#4dde80',
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Projected Income' %}",
|
||||
data: currencyData.datasets[2].data,
|
||||
backgroundColor: '#4dde8080', // Added transparency
|
||||
stack: 'stack0'
|
||||
},
|
||||
{
|
||||
label: "{% trans 'Projected Expenses' %}",
|
||||
data: currencyData.datasets[3].data,
|
||||
backgroundColor: '#f8717180', // Added transparency
|
||||
stack: 'stack0'
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
options: chartOptions
|
||||
|
||||
18
app/templates/insights/fragments/late_transactions.html
Normal file
18
app/templates/insights/fragments/late_transactions.html
Normal 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>
|
||||
16
app/templates/insights/fragments/latest_transactions.html
Normal file
16
app/templates/insights/fragments/latest_transactions.html
Normal 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>
|
||||
@@ -72,7 +72,6 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<hr class="mt-0">
|
||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist"
|
||||
aria-orientation="vertical">
|
||||
<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-target="#tab-content">{% trans 'Category Explorer' %}
|
||||
</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>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="tw-cursor-pointer text-primary text-end"
|
||||
<div class="tw-cursor-pointer text-primary text-end"
|
||||
_="on click
|
||||
set from_value to #id_from_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>
|
||||
</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>
|
||||
{% endblock %}
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
</div>
|
||||
<div id="search" class="my-3">
|
||||
<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
|
||||
if my value is empty
|
||||
trigger toggle on <.transactions-divider-collapse/>
|
||||
|
||||
@@ -2,12 +2,14 @@ import AirDatepicker from 'air-datepicker';
|
||||
import en from 'air-datepicker/locale/en';
|
||||
import ptBr from 'air-datepicker/locale/pt-BR';
|
||||
import nl from 'air-datepicker/locale/nl';
|
||||
import de from 'air-datepicker/locale/de';
|
||||
import {createPopper} from '@popperjs/core';
|
||||
|
||||
const locales = {
|
||||
'pt': ptBr,
|
||||
'en': en,
|
||||
'nl': nl
|
||||
'nl': nl,
|
||||
'de': de
|
||||
};
|
||||
|
||||
function isMobileDevice() {
|
||||
@@ -43,7 +45,7 @@ window.DatePicker = function createDynamicDatePicker(element) {
|
||||
toggleSelected: element.dataset.toggleSelected === 'true',
|
||||
autoClose: element.dataset.autoClose === 'true',
|
||||
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
|
||||
locale: locales[element.dataset.language],
|
||||
locale: locales[element.dataset.language] || locales['en'],
|
||||
onSelect: ({date, formattedDate, datepicker}) => {
|
||||
const _event = new CustomEvent("change", {
|
||||
bubbles: true,
|
||||
@@ -117,7 +119,7 @@ window.MonthYearPicker = function createDynamicDatePicker(element) {
|
||||
toggleSelected: element.dataset.toggleSelected === 'true',
|
||||
autoClose: element.dataset.autoClose === 'true',
|
||||
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
|
||||
locale: locales[element.dataset.language],
|
||||
locale: locales[element.dataset.language] || locales['en'],
|
||||
onSelect: ({date, formattedDate, datepicker}) => {
|
||||
const _event = new CustomEvent("change", {
|
||||
bubbles: true,
|
||||
@@ -190,7 +192,7 @@ window.YearPicker = function createDynamicDatePicker(element) {
|
||||
toggleSelected: element.dataset.toggleSelected === 'true',
|
||||
autoClose: element.dataset.autoClose === 'true',
|
||||
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
|
||||
locale: locales[element.dataset.language],
|
||||
locale: locales[element.dataset.language] || locales['en'],
|
||||
onSelect: ({date, formattedDate, datepicker}) => {
|
||||
const _event = new CustomEvent("change", {
|
||||
bubbles: true,
|
||||
|
||||
Reference in New Issue
Block a user