Compare commits

...

55 Commits

Author SHA1 Message Date
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
Herculino Trotta
7926e081ef locale: update locales 2025-02-19 13:50:45 -03:00
Herculino Trotta
ceefe7075f locale: update locales 2025-02-19 13:48:54 -03:00
Herculino Trotta
ad3230fd83 Merge pull request #179 from eitchtee/export
feat: export and restore
2025-02-19 13:41:53 -03:00
Herculino Trotta
c89b07ed93 Merge branch 'main' into export 2025-02-19 13:41:04 -03:00
Herculino Trotta
201ccea842 feat: export (WIP) 2025-02-19 13:38:00 -03:00
Herculino Trotta
32ada488b4 Merge pull request #178
feat(transactions:actions): select all only selects displayed transactions
2025-02-19 09:08:06 -03:00
Herculino Trotta
794d11a355 feat(transactions:actions): select all only selects displayed transactions 2025-02-19 09:07:49 -03:00
Herculino Trotta
67f8f5fe89 Merge pull request #177
fix(transactions:actions): sum considers everything an expense
2025-02-19 09:00:02 -03:00
Herculino Trotta
9ac69fd92a fix(transactions:actions): sum considers everything an expense 2025-02-19 08:59:30 -03:00
Herculino Trotta
069f1b450c feat: export (WIP) 2025-02-19 08:51:33 -03:00
Herculino Trotta
2f388af928 Merge pull request #176
feat(insights): make sidebar sticky
2025-02-18 21:04:36 -03:00
Herculino Trotta
beeb0579ce feat(insights): make sidebar sticky 2025-02-18 21:04:09 -03:00
Herculino Trotta
a8666da57b Merge pull request #175
feat(insights:category-explorer): separate current and projected totals
2025-02-18 20:46:28 -03:00
Herculino Trotta
835316d0f3 feat(insights:category-explorer): separate current and projected totals 2025-02-18 20:46:06 -03:00
Herculino Trotta
f5feeb9617 Merge pull request #174
feat(insights:category-explorer): allow for uncategorized totals
2025-02-18 20:45:24 -03:00
Herculino Trotta
09e380a480 feat(insights:category-explorer): allow for uncategorized totals 2025-02-18 20:45:07 -03:00
Herculino Trotta
3080df9b66 feat: export (WIP) 2025-02-18 19:55:12 -03:00
Herculino Trotta
ebc41a8049 Merge pull request #173 from eitchtee/insights
fix(insights): error if filter is empty
2025-02-17 21:49:00 -03:00
Herculino Trotta
635628e30e fix(insights): error if filter is empty 2025-02-17 21:48:33 -03:00
Herculino Trotta
819a58ac06 Merge pull request #172
feat(datepicker): disable input and fix toggling dates
2025-02-17 21:37:16 -03:00
Herculino Trotta
d433375522 feat(datepicker): disable input and fix toggling dates 2025-02-17 21:36:11 -03:00
Herculino Trotta
c0150f71a8 Merge pull request #171 from eitchtee/insights
fix(insights:category-explorer): silent categories can't be displayed
2025-02-17 10:43:12 -03:00
Herculino Trotta
6119698d38 fix(insights:category-explorer): silent categories can't be displayed 2025-02-17 10:42:38 -03:00
Herculino Trotta
f5ae231601 Merge pull request #170
feat(insights:category-explorer): add empty message when there's no data or no category selected
2025-02-17 10:28:55 -03:00
Herculino Trotta
972d23abbd feat(insights:category-explorer): add empty message when there's no data or no category selected 2025-02-17 10:28:37 -03:00
Herculino Trotta
9a514a8a69 Merge pull request #169
refactor(insights:flows): improve readability when there's a lot of nodes
2025-02-17 10:21:36 -03:00
Herculino Trotta
7325231548 refactor(insights:flows): improve readability when there's a lot of nodes 2025-02-17 10:21:18 -03:00
Herculino Trotta
570657371a Merge pull request #168
fix(insights:category-explorer): use currency name instead of code
2025-02-16 19:34:15 -03:00
Herculino Trotta
67da60b5b0 fix(insights:category-explorer): use currency name instead of code 2025-02-16 19:33:58 -03:00
Herculino Trotta
84c047c5ab Merge pull request #167 from eitchtee/insights
insights
2025-02-16 13:06:03 -03:00
Herculino Trotta
23f5d09bec locale: update locales 2025-02-16 13:05:35 -03:00
Herculino Trotta
2a19075e23 Merge pull request #166
feat(insights): category explorer
2025-02-16 13:03:20 -03:00
Herculino Trotta
7f231175b2 feat(insights): category explorer 2025-02-16 13:03:02 -03:00
Herculino Trotta
062e84f864 Merge pull request #165
fix(insights): sankey diagrams nodes too far from destination
2025-02-16 02:25:45 -03:00
Herculino Trotta
5521eb20bf fix(insights): sankey diagrams nodes too far from destination 2025-02-16 02:25:29 -03:00
54 changed files with 2636 additions and 671 deletions

View File

@@ -55,6 +55,7 @@ INSTALLED_APPS = [
"hijack",
"hijack.contrib.admin",
"django_filters",
"import_export",
"apps.users.apps.UsersConfig",
"procrastinate.contrib.django",
"apps.transactions.apps.TransactionsConfig",
@@ -63,6 +64,7 @@ INSTALLED_APPS = [
"apps.common.apps.CommonConfig",
"apps.net_worth.apps.NetWorthConfig",
"apps.import_app.apps.ImportConfig",
"apps.export_app.apps.ExportConfig",
"apps.api.apps.ApiConfig",
"cachalot",
"rest_framework",

View File

@@ -49,5 +49,6 @@ urlpatterns = [
path("", include("apps.dca.urls")),
path("", include("apps.mini_tools.urls")),
path("", include("apps.import_app.urls")),
path("", include("apps.export_app.urls")),
path("", include("apps.insights.urls")),
]

View File

@@ -19,6 +19,8 @@ class AirDatePickerInput(widgets.DateInput):
format=None,
clear_button=True,
auto_close=True,
read_only=True,
toggle_selected=None,
*args,
**kwargs,
):
@@ -26,6 +28,10 @@ class AirDatePickerInput(widgets.DateInput):
super().__init__(attrs=attrs, format=format, *args, **kwargs)
self.clear_button = clear_button
self.auto_close = auto_close
self.read_only = read_only
self.toggle_selected = (
toggle_selected if isinstance(toggle_selected, bool) else self.clear_button
)
@staticmethod
def _get_current_language():
@@ -47,9 +53,13 @@ class AirDatePickerInput(widgets.DateInput):
attrs["data-now-button-txt"] = _("Today")
attrs["data-auto-close"] = str(self.auto_close).lower()
attrs["data-clear-button"] = str(self.clear_button).lower()
attrs["data-toggle-selected"] = str(self.toggle_selected).lower()
attrs["data-language"] = self._get_current_language()
attrs["data-date-format"] = django_to_airdatepicker_datetime(self._get_format())
if self.read_only:
attrs["readonly"] = True
return attrs
def format_value(self, value):
@@ -89,6 +99,8 @@ class AirDateTimePickerInput(widgets.DateTimeInput):
timepicker=True,
clear_button=True,
auto_close=True,
read_only=True,
toggle_selected=None,
*args,
**kwargs,
):
@@ -97,6 +109,10 @@ class AirDateTimePickerInput(widgets.DateTimeInput):
self.timepicker = timepicker
self.clear_button = clear_button
self.auto_close = auto_close
self.read_only = read_only
self.toggle_selected = (
toggle_selected if isinstance(toggle_selected, bool) else self.clear_button
)
@staticmethod
def _get_current_language():
@@ -123,11 +139,15 @@ class AirDateTimePickerInput(widgets.DateTimeInput):
attrs["data-now-button-txt"] = _("Now")
attrs["data-timepicker"] = str(self.timepicker).lower()
attrs["data-auto-close"] = str(self.auto_close).lower()
attrs["data-toggle-selected"] = str(self.toggle_selected).lower()
attrs["data-clear-button"] = str(self.clear_button).lower()
attrs["data-language"] = self._get_current_language()
attrs["data-date-format"] = date_format
attrs["data-time-format"] = time_format
if self.read_only:
attrs["readonly"] = True
return attrs
def format_value(self, value):

View File

View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class ExportConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.export_app"

View File

@@ -0,0 +1,189 @@
from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, HTML
from django import forms
from django.utils.translation import gettext_lazy as _
from apps.common.widgets.crispy.submit import NoClassSubmit
class ExportForm(forms.Form):
accounts = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Accounts"),
initial=True,
)
currencies = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Currencies"),
initial=True,
)
transactions = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Transactions"),
initial=True,
)
categories = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Categories"),
initial=True,
)
tags = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Tags"),
initial=False,
)
entities = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Entities"),
initial=False,
)
recurring_transactions = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Recurring Transactions"),
initial=True,
)
installment_plans = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Installment Plans"),
initial=True,
)
exchange_rates = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Exchange Rates"),
initial=False,
)
exchange_rates_services = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Automatic Exchange Rates"),
initial=False,
)
rules = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Rules"),
initial=True,
)
dca = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("DCA"),
initial=False,
)
import_profiles = forms.BooleanField(
required=False,
widget=forms.CheckboxInput(),
label=_("Import Profiles"),
initial=True,
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = "post"
self.helper.layout = Layout(
"accounts",
"currencies",
"transactions",
"categories",
"entities",
"tags",
"installment_plans",
"recurring_transactions",
"exchange_rates_services",
"exchange_rates",
"rules",
"dca",
"import_profiles",
FormActions(
NoClassSubmit(
"submit", _("Export"), css_class="btn btn-outline-primary w-100"
),
),
)
class RestoreForm(forms.Form):
zip_file = forms.FileField(
required=False,
help_text=_("Import a ZIP file exported from WYGIWYH"),
label=_("ZIP File"),
)
accounts = forms.FileField(required=False, label=_("Accounts"))
currencies = forms.FileField(required=False, label=_("Currencies"))
transactions_categories = forms.FileField(required=False, label=_("Categories"))
transactions_tags = forms.FileField(required=False, label=_("Tags"))
transactions_entities = forms.FileField(required=False, label=_("Entities"))
transactions = forms.FileField(required=False, label=_("Transactions"))
installment_plans = forms.FileField(required=False, label=_("Installment Plans"))
recurring_transactions = forms.FileField(
required=False, label=_("Recurring Transactions")
)
automatic_exchange_rates = forms.FileField(
required=False, label=_("Automatic Exchange Rates")
)
exchange_rates = forms.FileField(required=False, label=_("Exchange Rates"))
transaction_rules = forms.FileField(required=False, label=_("Transaction rules"))
transaction_rules_actions = forms.FileField(
required=False, label=_("Edit transaction action")
)
transaction_rules_update_or_create = forms.FileField(
required=False, label=_("Update or create transaction actions")
)
dca_strategies = forms.FileField(required=False, label=_("DCA Strategies"))
dca_entries = forms.FileField(required=False, label=_("DCA Entries"))
import_profiles = forms.FileField(required=False, label=_("Import Profiles"))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = "post"
self.helper.layout = Layout(
"zip_file",
HTML("<hr />"),
"accounts",
"currencies",
"transactions",
"transactions_categories",
"transactions_entities",
"transactions_tags",
"installment_plans",
"recurring_transactions",
"automatic_exchange_rates",
"exchange_rates",
"transaction_rules",
"transaction_rules_actions",
"transaction_rules_update_or_create",
"dca_strategies",
"dca_entries",
"import_profiles",
FormActions(
NoClassSubmit(
"submit", _("Restore"), css_class="btn btn-outline-primary w-100"
),
),
)
def clean(self):
cleaned_data = super().clean()
if not cleaned_data.get("zip_file") and not any(
cleaned_data.get(field) for field in self.fields if field != "zip_file"
):
raise forms.ValidationError(
_("Please upload either a ZIP file or at least one CSV file")
)
return cleaned_data

View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@@ -0,0 +1,26 @@
from import_export import fields, resources, widgets
from apps.accounts.models import Account, AccountGroup
from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget
from apps.currencies.models import Currency
class AccountResource(resources.ModelResource):
group = fields.Field(
attribute="group",
column_name="group",
widget=AutoCreateForeignKeyWidget(AccountGroup, "name"),
)
currency = fields.Field(
attribute="currency",
column_name="currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
)
exchange_currency = fields.Field(
attribute="exchange_currency",
column_name="exchange_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
)
class Meta:
model = Account

View File

@@ -0,0 +1,52 @@
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=SkipMissingForeignKeyWidget(Currency, "name"),
)
class Meta:
model = Currency
class ExchangeRateResource(resources.ModelResource):
from_currency = fields.Field(
attribute="from_currency",
column_name="from_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
)
to_currency = fields.Field(
attribute="to_currency",
column_name="to_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
)
rate = fields.Field(
attribute="rate", column_name="rate", widget=UniversalDecimalWidget()
)
class Meta:
model = ExchangeRate
class ExchangeRateServiceResource(resources.ModelResource):
target_currencies = fields.Field(
attribute="target_currencies",
column_name="target_currencies",
widget=widgets.ManyToManyWidget(Currency, field="name"),
)
target_accounts = fields.Field(
attribute="target_accounts",
column_name="target_accounts",
widget=widgets.ManyToManyWidget(Account, field="name"),
)
class Meta:
model = ExchangeRateService

View File

@@ -0,0 +1,38 @@
from import_export import fields, resources
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):
target_currency = fields.Field(
attribute="target_currency",
column_name="target_currency",
widget=ForeignKeyWidget(Currency, "name"),
)
payment_currency = fields.Field(
attribute="payment_currency",
column_name="payment_currency",
widget=ForeignKeyWidget(Currency, "name"),
)
class Meta:
model = DCAStrategy
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

View File

@@ -0,0 +1,8 @@
from import_export import resources
from apps.import_app.models import ImportProfile
class ImportProfileResource(resources.ModelResource):
class Meta:
model = ImportProfile

View File

@@ -0,0 +1,25 @@
from import_export import fields, resources
from import_export.widgets import ForeignKeyWidget
from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget
from apps.export_app.widgets.many_to_many import AutoCreateManyToManyWidget
from apps.rules.models import (
TransactionRule,
TransactionRuleAction,
UpdateOrCreateTransactionRuleAction,
)
class TransactionRuleResource(resources.ModelResource):
class Meta:
model = TransactionRule
class TransactionRuleActionResource(resources.ModelResource):
class Meta:
model = TransactionRuleAction
class UpdateOrCreateTransactionRuleResource(resources.ModelResource):
class Meta:
model = UpdateOrCreateTransactionRuleAction

View File

@@ -0,0 +1,143 @@
from import_export import fields, resources
from import_export.widgets import ForeignKeyWidget
from apps.accounts.models import Account
from apps.export_app.widgets.foreign_key import AutoCreateForeignKeyWidget
from apps.export_app.widgets.many_to_many import AutoCreateManyToManyWidget
from apps.export_app.widgets.string import EmptyStringToNoneField
from apps.transactions.models import (
Transaction,
TransactionCategory,
TransactionTag,
TransactionEntity,
RecurringTransaction,
InstallmentPlan,
)
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class TransactionResource(resources.ModelResource):
account = fields.Field(
attribute="account",
column_name="account",
widget=ForeignKeyWidget(Account, "name"),
)
category = fields.Field(
attribute="category",
column_name="category",
widget=AutoCreateForeignKeyWidget(TransactionCategory, "name"),
)
tags = fields.Field(
attribute="tags",
column_name="tags",
widget=AutoCreateManyToManyWidget(TransactionTag, field="name"),
)
entities = fields.Field(
attribute="entities",
column_name="entities",
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
)
internal_id = EmptyStringToNoneField(
column_name="internal_id", attribute="internal_id"
)
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = Transaction
def get_queryset(self):
return Transaction.all_objects.all()
class TransactionTagResource(resources.ModelResource):
class Meta:
model = TransactionTag
class TransactionEntityResource(resources.ModelResource):
class Meta:
model = TransactionEntity
class TransactionCategoyResource(resources.ModelResource):
class Meta:
model = TransactionCategory
class RecurringTransactionResource(resources.ModelResource):
account = fields.Field(
attribute="account",
column_name="account",
widget=ForeignKeyWidget(Account, "name"),
)
category = fields.Field(
attribute="category",
column_name="category",
widget=AutoCreateForeignKeyWidget(TransactionCategory, "name"),
)
tags = fields.Field(
attribute="tags",
column_name="tags",
widget=AutoCreateManyToManyWidget(TransactionTag, field="name"),
)
entities = fields.Field(
attribute="entities",
column_name="entities",
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
)
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = RecurringTransaction
class InstallmentPlanResource(resources.ModelResource):
account = fields.Field(
attribute="account",
column_name="account",
widget=ForeignKeyWidget(Account, "name"),
)
category = fields.Field(
attribute="category",
column_name="category",
widget=AutoCreateForeignKeyWidget(TransactionCategory, "name"),
)
tags = fields.Field(
attribute="tags",
column_name="tags",
widget=AutoCreateManyToManyWidget(TransactionTag, field="name"),
)
entities = fields.Field(
attribute="entities",
column_name="entities",
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
)
installment_amount = fields.Field(
attribute="installment_amount",
column_name="installment_amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = InstallmentPlan

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1,8 @@
from django.urls import path
import apps.export_app.views as views
urlpatterns = [
path("export/", views.export_index, name="export_index"),
path("export/form/", views.export_form, name="export_form"),
path("export/restore/", views.import_form, name="restore_form"),
]

View File

@@ -0,0 +1,284 @@
import logging
import zipfile
from io import BytesIO, TextIOWrapper
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.http import HttpResponse
from django.shortcuts import render
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_http_methods
from tablib import Dataset
from apps.export_app.forms import ExportForm, RestoreForm
from apps.export_app.resources.accounts import AccountResource
from apps.export_app.resources.transactions import (
TransactionResource,
TransactionTagResource,
TransactionEntityResource,
TransactionCategoyResource,
InstallmentPlanResource,
RecurringTransactionResource,
)
from apps.export_app.resources.currencies import (
CurrencyResource,
ExchangeRateResource,
ExchangeRateServiceResource,
)
from apps.export_app.resources.rules import (
TransactionRuleResource,
TransactionRuleActionResource,
UpdateOrCreateTransactionRuleResource,
)
from apps.export_app.resources.dca import (
DCAStrategyResource,
DCAEntryResource,
)
from apps.export_app.resources.import_app import (
ImportProfileResource,
)
from apps.common.decorators.htmx import only_htmx
logger = logging.getLogger()
@login_required
@require_http_methods(["GET"])
def export_index(request):
return render(request, "export_app/pages/index.html")
@login_required
@require_http_methods(["GET", "POST"])
def export_form(request):
timestamp = timezone.localtime(timezone.now()).strftime("%Y-%m-%dT%H-%M-%S")
if request.method == "POST":
form = ExportForm(request.POST)
if form.is_valid():
zip_buffer = BytesIO()
export_accounts = form.cleaned_data.get("accounts", False)
export_currencies = form.cleaned_data.get("currencies", False)
export_transactions = form.cleaned_data.get("transactions", False)
export_categories = form.cleaned_data.get("categories", False)
export_tags = form.cleaned_data.get("tags", False)
export_entities = form.cleaned_data.get("entities", False)
export_installment_plans = form.cleaned_data.get("installment_plans", False)
export_recurring_transactions = form.cleaned_data.get(
"recurring_transactions", False
)
export_exchange_rates_services = form.cleaned_data.get(
"exchange_rates_services", False
)
export_exchange_rates = form.cleaned_data.get("exchange_rates", False)
export_rules = form.cleaned_data.get("rules", False)
export_dca = form.cleaned_data.get("dca", False)
export_import_profiles = form.cleaned_data.get("import_profiles", False)
exports = []
if export_accounts:
exports.append((AccountResource().export(), "accounts"))
if export_currencies:
exports.append((CurrencyResource().export(), "currencies"))
if export_transactions:
exports.append((TransactionResource().export(), "transactions"))
if export_categories:
exports.append(
(TransactionCategoyResource().export(), "transactions_categories")
)
if export_tags:
exports.append((TransactionTagResource().export(), "transactions_tags"))
if export_entities:
exports.append(
(TransactionEntityResource().export(), "transactions_entities")
)
if export_installment_plans:
exports.append(
(InstallmentPlanResource().export(), "installment_plans")
)
if export_recurring_transactions:
exports.append(
(RecurringTransactionResource().export(), "recurring_transactions")
)
if export_exchange_rates_services:
exports.append(
(ExchangeRateServiceResource().export(), "automatic_exchange_rates")
)
if export_exchange_rates:
exports.append((ExchangeRateResource().export(), "exchange_rates"))
if export_rules:
exports.append(
(TransactionRuleResource().export(), "transaction_rules")
)
exports.append(
(
TransactionRuleActionResource().export(),
"transaction_rules_actions",
)
)
exports.append(
(
UpdateOrCreateTransactionRuleResource().export(),
"transaction_rules_update_or_create",
)
)
if export_dca:
exports.append((DCAStrategyResource().export(), "dca_strategies"))
exports.append(
(
DCAEntryResource().export(),
"dca_entries",
)
)
if export_import_profiles:
exports.append((ImportProfileResource().export(), "import_profiles"))
if len(exports) >= 2:
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
for dataset, name in exports:
zip_file.writestr(f"{name}.csv", dataset.csv)
response = HttpResponse(
zip_buffer.getvalue(),
content_type="application/zip",
headers={
"HX-Trigger": "hide_offcanvas, updated",
"Content-Disposition": f'attachment; filename="{timestamp}_WYGIWYH_export.zip"',
},
)
return response
elif len(exports) == 1:
dataset, name = exports[0]
response = HttpResponse(
dataset.csv,
content_type="text/csv",
headers={
"HX-Trigger": "hide_offcanvas, updated",
"Content-Disposition": f'attachment; filename="{timestamp}_WYGIWYH_export_{name}.csv"',
},
)
return response
else:
return HttpResponse(
_("You have to select at least one export"),
)
else:
form = ExportForm()
return render(request, "export_app/fragments/export.html", context={"form": form})
@only_htmx
@login_required
@require_http_methods(["GET", "POST"])
def import_form(request):
if request.method == "POST":
form = RestoreForm(request.POST, request.FILES)
if form.is_valid():
try:
process_imports(request, form.cleaned_data)
messages.success(request, _("Data restored successfully"))
return HttpResponse(
status=204,
headers={
"HX-Trigger": "hide_offcanvas, updated",
},
)
except Exception as e:
logger.error("Error importing", exc_info=e)
messages.error(
request,
_(
"There was an error restoring your data. Check the logs for more details."
),
)
else:
form = RestoreForm()
response = render(request, "export_app/fragments/restore.html", {"form": form})
response["HX-Trigger"] = "updated"
return response
def process_imports(request, cleaned_data):
# Define import order to handle dependencies
import_order = [
("currencies", CurrencyResource),
(
"currencies",
CurrencyResource,
), # We do a double pass because exchange_currency may not exist when currency is initially created
("accounts", AccountResource),
("transactions_categories", TransactionCategoyResource),
("transactions_tags", TransactionTagResource),
("transactions_entities", TransactionEntityResource),
("automatic_exchange_rates", ExchangeRateServiceResource),
("exchange_rates", ExchangeRateResource),
("installment_plans", InstallmentPlanResource),
("recurring_transactions", RecurringTransactionResource),
("transactions", TransactionResource),
("dca_strategies", DCAStrategyResource),
("dca_entries", DCAEntryResource),
("import_profiles", ImportProfileResource),
("transaction_rules", TransactionRuleResource),
("transaction_rules_actions", TransactionRuleActionResource),
("transaction_rules_update_or_create", UpdateOrCreateTransactionRuleResource),
]
def import_dataset(content, resource_class, field_name):
try:
# Create a new resource instance
resource = resource_class()
# Create dataset from CSV content
dataset = Dataset()
dataset.load(content, format="csv")
# Perform the import
result = resource.import_data(
dataset,
dry_run=False,
raise_errors=True,
collect_failed_rows=True,
use_transactions=False,
skip_unchanged=True,
)
if result.has_errors():
raise ImportError(f"Failed rows: {result.failed_dataset}")
return result
except Exception as e:
logger.error(f"Error importing {field_name}: {str(e)}")
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:
for filename in z.namelist():
name = filename.replace(".csv", "")
with z.open(filename) as f:
content = f.read().decode("utf-8")
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:
if csv_file := cleaned_data.get(field_name):
content = csv_file.read().decode("utf-8")
import_dataset(content, resource_class, field_name)

View File

View File

@@ -0,0 +1,22 @@
from import_export.widgets import ForeignKeyWidget
class AutoCreateForeignKeyWidget(ForeignKeyWidget):
def clean(self, value, row=None, *args, **kwargs):
if value:
try:
return super().clean(value, row, **kwargs)
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

View File

@@ -0,0 +1,21 @@
from import_export.widgets import ManyToManyWidget
class AutoCreateManyToManyWidget(ManyToManyWidget):
def clean(self, value, row=None, *args, **kwargs):
if not value:
return []
values = value.split(self.separator)
cleaned_values = []
for val in values:
val = val.strip()
if val:
try:
obj = self.model.objects.get(**{self.field: val})
except self.model.DoesNotExist:
obj = self.model.objects.create(name=val)
cleaned_values.append(obj)
return cleaned_values

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

@@ -0,0 +1,7 @@
from import_export import fields
class EmptyStringToNoneField(fields.Field):
def clean(self, data, **kwargs):
value = super().clean(data)
return None if value == "" else value

View File

@@ -8,11 +8,13 @@ from apps.common.widgets.datepicker import (
AirYearPickerInput,
AirDatePickerInput,
)
from apps.transactions.models import TransactionCategory
from apps.common.widgets.tom_select import TomSelect
class SingleMonthForm(forms.Form):
month = forms.DateField(
widget=AirMonthYearPickerInput(clear_button=False), label="", required=False
widget=AirMonthYearPickerInput(clear_button=False), label="", required=True
)
def __init__(self, *args, **kwargs):
@@ -27,7 +29,7 @@ class SingleMonthForm(forms.Form):
class SingleYearForm(forms.Form):
year = forms.DateField(
widget=AirYearPickerInput(clear_button=False), label="", required=False
widget=AirYearPickerInput(clear_button=False), label="", required=True
)
def __init__(self, *args, **kwargs):
@@ -42,10 +44,10 @@ class SingleYearForm(forms.Form):
class MonthRangeForm(forms.Form):
month_from = forms.DateField(
widget=AirMonthYearPickerInput(clear_button=False), label="", required=False
widget=AirMonthYearPickerInput(clear_button=False), label="", required=True
)
month_to = forms.DateField(
widget=AirMonthYearPickerInput(clear_button=False), label="", required=False
widget=AirMonthYearPickerInput(clear_button=False), label="", required=True
)
def __init__(self, *args, **kwargs):
@@ -65,10 +67,10 @@ class MonthRangeForm(forms.Form):
class YearRangeForm(forms.Form):
year_from = forms.DateField(
widget=AirYearPickerInput(clear_button=False), label="", required=False
widget=AirYearPickerInput(clear_button=False), label="", required=True
)
year_to = forms.DateField(
widget=AirYearPickerInput(clear_button=False), label="", required=False
widget=AirYearPickerInput(clear_button=False), label="", required=True
)
def __init__(self, *args, **kwargs):
@@ -88,10 +90,10 @@ class YearRangeForm(forms.Form):
class DateRangeForm(forms.Form):
date_from = forms.DateField(
widget=AirDatePickerInput(clear_button=False), label="", required=False
widget=AirDatePickerInput(clear_button=False), label="", required=True
)
date_to = forms.DateField(
widget=AirDatePickerInput(clear_button=False), label="", required=False
widget=AirDatePickerInput(clear_button=False), label="", required=True
)
def __init__(self, *args, **kwargs):
@@ -108,3 +110,22 @@ class DateRangeForm(forms.Form):
css_class="mb-0",
),
)
class CategoryForm(forms.Form):
category = forms.ModelChoiceField(
required=False,
label=_("Category"),
empty_label=_("Uncategorized"),
queryset=TransactionCategory.objects.filter(active=True),
widget=TomSelect(clear_button=True),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.disable_csrf = True
self.helper.layout = Layout("category")

View File

@@ -14,4 +14,29 @@ urlpatterns = [
views.sankey_by_currency,
name="insights_sankey_by_currency",
),
path(
"insights/category-explorer/",
views.category_explorer_index,
name="category_explorer_index",
),
path(
"insights/category-explorer/account/",
views.category_sum_by_account,
name="category_sum_by_account",
),
path(
"insights/category-explorer/currency/",
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",
),
]

View File

@@ -0,0 +1,161 @@
from django.db.models import Sum, Case, When, F, DecimalField, Value
from django.db.models.functions import Coalesce
from django.utils.translation import gettext_lazy as _
def get_category_sums_by_account(queryset, category=None):
"""
Returns income/expense sums per account for a specific category.
"""
sums = (
queryset.filter(category=category)
.values("account__name")
.annotate(
current_income=Coalesce(
Sum(
Case(
When(type="IN", is_paid=True, then="amount"),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
current_expense=Coalesce(
Sum(
Case(
When(type="EX", is_paid=True, then=-F("amount")),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
projected_income=Coalesce(
Sum(
Case(
When(type="IN", is_paid=False, then="amount"),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
projected_expense=Coalesce(
Sum(
Case(
When(type="EX", is_paid=False, then=-F("amount")),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
)
.order_by("account__name")
)
return {
"labels": [item["account__name"] for item in sums],
"datasets": [
{
"label": _("Current Income"),
"data": [float(item["current_income"]) for item in sums],
},
{
"label": _("Current Expenses"),
"data": [float(item["current_expense"]) for item in sums],
},
{
"label": _("Projected Income"),
"data": [float(item["projected_income"]) for item in sums],
},
{
"label": _("Projected Expenses"),
"data": [float(item["projected_expense"]) for item in sums],
},
],
}
def get_category_sums_by_currency(queryset, category=None):
"""
Returns income/expense sums per currency for a specific category.
"""
sums = (
queryset.filter(category=category)
.values("account__currency__name")
.annotate(
current_income=Coalesce(
Sum(
Case(
When(type="IN", is_paid=True, then="amount"),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
current_expense=Coalesce(
Sum(
Case(
When(type="EX", is_paid=True, then=-F("amount")),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
projected_income=Coalesce(
Sum(
Case(
When(type="IN", is_paid=False, then="amount"),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
projected_expense=Coalesce(
Sum(
Case(
When(type="EX", is_paid=False, then=-F("amount")),
default=Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
)
),
Value(0),
output_field=DecimalField(max_digits=42, decimal_places=30),
),
)
.order_by("account__currency__name")
)
return {
"labels": [item["account__currency__name"] for item in sums],
"datasets": [
{
"label": _("Current Income"),
"data": [float(item["current_income"]) for item in sums],
},
{
"label": _("Current Expenses"),
"data": [float(item["current_expense"]) for item in sums],
},
{
"label": _("Projected Income"),
"data": [float(item["projected_income"]) for item in sums],
},
{
"label": _("Projected Expenses"),
"data": [float(item["projected_expense"]) for item in sums],
},
],
}

View File

@@ -52,13 +52,29 @@ def generate_sankey_data_by_account(transactions_queryset):
total_volume_by_currency.get(currency, Decimal("0")) + amount
)
unique_accounts = {
account_id: idx
for idx, account_id in enumerate(
transactions_queryset.values_list("account", flat=True).distinct()
)
}
def get_node_priority(node_id: str) -> int:
"""Get priority based on the account ID embedded in the node ID."""
account_id = int(node_id.split("_")[-1])
return unique_accounts[account_id]
def get_node_id(node_type: str, name: str, account_id: int) -> str:
"""Generate unique node ID."""
return f"{node_type}_{name}_{account_id}".lower().replace(" ", "_")
def add_node(node_id: str, display_name: str) -> None:
"""Add node with both ID and display name."""
nodes[node_id] = {"id": node_id, "name": display_name}
"""Add node with ID, display name and priority."""
nodes[node_id] = {
"id": node_id,
"name": display_name,
"priority": get_node_priority(node_id),
}
def add_flow(
from_node_id: str, to_node_id: str, amount: Decimal, currency, is_income: bool
@@ -167,13 +183,29 @@ def generate_sankey_data_by_currency(transactions_queryset):
total_volume_by_currency.get(currency, Decimal("0")) + amount
)
unique_currencies = {
currency_id: idx
for idx, currency_id in enumerate(
transactions_queryset.values_list("account__currency", flat=True).distinct()
)
}
def get_node_priority(node_id: str) -> int:
"""Get priority based on the currency ID embedded in the node ID."""
currency_id = int(node_id.split("_")[-1])
return unique_currencies[currency_id]
def get_node_id(node_type: str, name: str, currency_id: int) -> str:
"""Generate unique node ID including currency information."""
return f"{node_type}_{name}_{currency_id}".lower().replace(" ", "_")
def add_node(node_id: str, display_name: str) -> None:
"""Add node with both ID and display name."""
nodes[node_id] = {"id": node_id, "name": display_name}
"""Add node with ID, display name and priority."""
nodes[node_id] = {
"id": node_id,
"name": display_name,
"priority": get_node_priority(node_id),
}
def add_flow(
from_node_id: str, to_node_id: str, amount: Decimal, currency, is_income: bool

View File

@@ -1,24 +1,28 @@
from dateutil.relativedelta import relativedelta
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from dateutil.relativedelta import relativedelta
from apps.transactions.models import Transaction
from apps.insights.utils.sankey import (
generate_sankey_data_by_account,
generate_sankey_data_by_currency,
)
from apps.common.decorators.htmx import only_htmx
from apps.insights.forms import (
SingleMonthForm,
SingleYearForm,
MonthRangeForm,
YearRangeForm,
DateRangeForm,
CategoryForm,
)
from apps.insights.utils.category_explorer import (
get_category_sums_by_account,
get_category_sums_by_currency,
)
from apps.insights.utils.sankey import (
generate_sankey_data_by_account,
generate_sankey_data_by_currency,
)
from apps.common.decorators.htmx import only_htmx
from apps.insights.utils.transactions import get_transactions
from apps.transactions.models import TransactionCategory, Transaction
@login_required
@@ -61,7 +65,7 @@ def index(request):
@only_htmx
@login_required
@require_http_methods(["GET", "POST"])
@require_http_methods(["GET"])
def sankey_by_account(request):
# Get filtered transactions
@@ -79,7 +83,7 @@ def sankey_by_account(request):
@only_htmx
@login_required
@require_http_methods(["GET", "POST"])
@require_http_methods(["GET"])
def sankey_by_currency(request):
# Get filtered transactions
transactions = get_transactions(request)
@@ -92,3 +96,94 @@ def sankey_by_currency(request):
"insights/fragments/sankey.html",
{"sankey_data": sankey_data, "type": "currency"},
)
@only_htmx
@login_required
@require_http_methods(["GET"])
def category_explorer_index(request):
category_form = CategoryForm()
return render(
request,
"insights/fragments/category_explorer/index.html",
{"category_form": category_form},
)
@only_htmx
@login_required
@require_http_methods(["GET"])
def category_sum_by_account(request):
# Get filtered transactions
transactions = get_transactions(request, include_silent=True)
category = request.GET.get("category")
if category:
category = TransactionCategory.objects.get(id=category)
# Generate data
account_data = get_category_sums_by_account(transactions, category)
else:
account_data = get_category_sums_by_account(transactions, category=None)
return render(
request,
"insights/fragments/category_explorer/charts/account.html",
{"account_data": account_data},
)
@only_htmx
@login_required
@require_http_methods(["GET"])
def category_sum_by_currency(request):
# Get filtered transactions
transactions = get_transactions(request, include_silent=True)
category = request.GET.get("category")
if category:
category = TransactionCategory.objects.get(id=category)
# Generate data
currency_data = get_category_sums_by_currency(transactions, category)
else:
currency_data = get_category_sums_by_currency(transactions, category=None)
return render(
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},
)

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.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},
)

View File

@@ -63,7 +63,9 @@ class TransactionForm(forms.ModelForm):
date = forms.DateField(label=_("Date"))
reference_date = forms.DateField(
widget=AirMonthYearPickerInput(), label=_("Reference Date"), required=False
widget=AirMonthYearPickerInput(),
label=_("Reference Date"),
required=False,
)
class Meta:
@@ -176,7 +178,6 @@ class TransactionForm(forms.ModelForm):
),
)
self.fields["reference_date"].required = False
self.fields["date"].widget = AirDatePickerInput(clear_button=False)
if self.instance and self.instance.pk:

View File

@@ -2,13 +2,13 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-16 00:03-0300\n"
"POT-Creation-Date: 2025-02-19 23:05-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -26,10 +26,10 @@ msgstr ""
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:142 apps/dca/forms.py:49 apps/dca/forms.py:224
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/rules/forms.py:359 apps/transactions/forms.py:190
#: apps/transactions/forms.py:257 apps/transactions/forms.py:581
#: apps/transactions/forms.py:624 apps/transactions/forms.py:656
#: apps/transactions/forms.py:691 apps/transactions/forms.py:827
#: apps/rules/forms.py:359 apps/transactions/forms.py:191
#: apps/transactions/forms.py:258 apps/transactions/forms.py:582
#: apps/transactions/forms.py:625 apps/transactions/forms.py:657
#: apps/transactions/forms.py:692 apps/transactions/forms.py:828
msgid "Update"
msgstr ""
@@ -38,10 +38,10 @@ msgstr ""
#: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:57 apps/dca/forms.py:232 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/rules/forms.py:367
#: apps/transactions/forms.py:174 apps/transactions/forms.py:199
#: apps/transactions/forms.py:589 apps/transactions/forms.py:632
#: apps/transactions/forms.py:664 apps/transactions/forms.py:699
#: apps/transactions/forms.py:835
#: apps/transactions/forms.py:176 apps/transactions/forms.py:200
#: apps/transactions/forms.py:590 apps/transactions/forms.py:633
#: apps/transactions/forms.py:665 apps/transactions/forms.py:700
#: apps/transactions/forms.py:836
#: templates/account_groups/fragments/list.html:9
#: templates/accounts/fragments/list.html:9
#: templates/categories/fragments/list.html:9
@@ -69,21 +69,22 @@ msgid "New balance"
msgstr ""
#: apps/accounts/forms.py:119 apps/dca/forms.py:85 apps/dca/forms.py:92
#: apps/rules/forms.py:168 apps/rules/forms.py:183 apps/rules/models.py:32
#: apps/rules/models.py:280 apps/transactions/forms.py:39
#: apps/transactions/forms.py:291 apps/transactions/forms.py:298
#: apps/transactions/forms.py:478 apps/transactions/forms.py:723
#: apps/transactions/models.py:203 apps/transactions/models.py:378
#: apps/transactions/models.py:558
#: apps/insights/forms.py:118 apps/rules/forms.py:168 apps/rules/forms.py:183
#: apps/rules/models.py:32 apps/rules/models.py:280
#: apps/transactions/forms.py:39 apps/transactions/forms.py:292
#: apps/transactions/forms.py:299 apps/transactions/forms.py:479
#: apps/transactions/forms.py:724 apps/transactions/models.py:203
#: apps/transactions/models.py:378 apps/transactions/models.py:558
msgid "Category"
msgstr ""
#: apps/accounts/forms.py:126 apps/dca/forms.py:101 apps/dca/forms.py:109
#: apps/export_app/forms.py:38 apps/export_app/forms.py:127
#: apps/rules/forms.py:171 apps/rules/forms.py:180 apps/rules/models.py:33
#: apps/rules/models.py:284 apps/transactions/filters.py:74
#: apps/transactions/forms.py:47 apps/transactions/forms.py:307
#: apps/transactions/forms.py:315 apps/transactions/forms.py:471
#: apps/transactions/forms.py:716 apps/transactions/models.py:209
#: apps/transactions/forms.py:47 apps/transactions/forms.py:308
#: apps/transactions/forms.py:316 apps/transactions/forms.py:472
#: apps/transactions/forms.py:717 apps/transactions/models.py:209
#: apps/transactions/models.py:380 apps/transactions/models.py:562
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
#: templates/tags/pages/index.html:4
@@ -154,13 +155,14 @@ msgstr ""
#: apps/accounts/models.py:59 apps/rules/forms.py:160 apps/rules/forms.py:173
#: apps/rules/models.py:24 apps/rules/models.py:236
#: apps/transactions/forms.py:59 apps/transactions/forms.py:463
#: apps/transactions/forms.py:708 apps/transactions/models.py:176
#: apps/transactions/forms.py:59 apps/transactions/forms.py:464
#: apps/transactions/forms.py:709 apps/transactions/models.py:176
#: apps/transactions/models.py:338 apps/transactions/models.py:540
msgid "Account"
msgstr ""
#: apps/accounts/models.py:60 apps/transactions/filters.py:53
#: apps/accounts/models.py:60 apps/export_app/forms.py:14
#: apps/export_app/forms.py:124 apps/transactions/filters.py:53
#: templates/accounts/fragments/list.html:5
#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114
#: templates/includes/navbar.html:116
@@ -331,12 +333,12 @@ msgstr ""
msgid "Cache cleared successfully"
msgstr ""
#: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186
#: apps/common/widgets/datepicker.py:244
#: apps/common/widgets/datepicker.py:53 apps/common/widgets/datepicker.py:206
#: apps/common/widgets/datepicker.py:264
msgid "Today"
msgstr ""
#: apps/common/widgets/datepicker.py:123
#: apps/common/widgets/datepicker.py:139
msgid "Now"
msgstr ""
@@ -365,7 +367,7 @@ msgstr ""
#: apps/currencies/forms.py:69 apps/dca/models.py:156 apps/rules/forms.py:163
#: apps/rules/forms.py:176 apps/rules/models.py:27 apps/rules/models.py:248
#: apps/transactions/forms.py:63 apps/transactions/forms.py:319
#: apps/transactions/forms.py:63 apps/transactions/forms.py:320
#: apps/transactions/models.py:186
#: templates/dca/fragments/strategy/details.html:52
#: templates/exchange_rates/fragments/table.html:10
@@ -385,7 +387,8 @@ msgstr ""
msgid "Decimal Places"
msgstr ""
#: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: apps/currencies/models.py:40 apps/export_app/forms.py:20
#: apps/export_app/forms.py:125 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122
#: templates/includes/navbar.html:124
@@ -415,7 +418,8 @@ msgstr ""
msgid "Date and Time"
msgstr ""
#: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: apps/currencies/models.py:74 apps/export_app/forms.py:62
#: apps/export_app/forms.py:137 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:126
msgid "Exchange Rates"
@@ -566,11 +570,11 @@ msgstr ""
msgid "Create transaction"
msgstr ""
#: apps/dca/forms.py:70 apps/transactions/forms.py:266
#: apps/dca/forms.py:70 apps/transactions/forms.py:267
msgid "From Account"
msgstr ""
#: apps/dca/forms.py:76 apps/transactions/forms.py:271
#: apps/dca/forms.py:76 apps/transactions/forms.py:272
msgid "To Account"
msgstr ""
@@ -595,7 +599,7 @@ msgstr ""
msgid "You must provide an account."
msgstr ""
#: apps/dca/forms.py:294 apps/transactions/forms.py:413
#: apps/dca/forms.py:294 apps/transactions/forms.py:414
msgid "From and To accounts must be different."
msgstr ""
@@ -614,7 +618,7 @@ msgstr ""
#: apps/dca/models.py:27 apps/dca/models.py:179 apps/rules/forms.py:167
#: apps/rules/forms.py:182 apps/rules/models.py:31 apps/rules/models.py:264
#: apps/transactions/forms.py:333 apps/transactions/models.py:199
#: apps/transactions/forms.py:334 apps/transactions/models.py:199
#: apps/transactions/models.py:387 apps/transactions/models.py:568
msgid "Notes"
msgstr ""
@@ -623,7 +627,7 @@ msgstr ""
msgid "DCA Strategy"
msgstr ""
#: apps/dca/models.py:33
#: apps/dca/models.py:33 apps/export_app/forms.py:145
msgid "DCA Strategies"
msgstr ""
@@ -643,7 +647,7 @@ msgstr ""
msgid "DCA Entry"
msgstr ""
#: apps/dca/models.py:185
#: apps/dca/models.py:185 apps/export_app/forms.py:146
msgid "DCA Entries"
msgstr ""
@@ -671,6 +675,117 @@ msgstr ""
msgid "Entry deleted successfully"
msgstr ""
#: apps/export_app/forms.py:26 apps/export_app/forms.py:129
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr ""
#: apps/export_app/forms.py:32 apps/export_app/forms.py:126
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr ""
#: apps/export_app/forms.py:44 apps/export_app/forms.py:128
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:487
#: apps/transactions/forms.py:732 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr ""
#: apps/export_app/forms.py:50 apps/export_app/forms.py:132
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr ""
#: apps/export_app/forms.py:56 apps/export_app/forms.py:130
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr ""
#: apps/export_app/forms.py:68 apps/export_app/forms.py:135
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:138
msgid "Automatic Exchange Rates"
msgstr ""
#: apps/export_app/forms.py:74 templates/includes/navbar.html:132
#: templates/rules/fragments/list.html:5 templates/rules/pages/index.html:4
msgid "Rules"
msgstr ""
#: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr ""
#: apps/export_app/forms.py:86 apps/export_app/forms.py:147
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr ""
#: apps/export_app/forms.py:112 templates/export_app/fragments/export.html:5
#: templates/export_app/pages/index.html:15
msgid "Export"
msgstr ""
#: apps/export_app/forms.py:121
msgid "Import a ZIP file exported from WYGIWYH"
msgstr ""
#: apps/export_app/forms.py:122
msgid "ZIP File"
msgstr ""
#: apps/export_app/forms.py:138 apps/rules/models.py:16
msgid "Transaction rules"
msgstr ""
#: apps/export_app/forms.py:140 apps/rules/models.py:53
msgid "Edit transaction action"
msgstr ""
#: apps/export_app/forms.py:143 apps/rules/models.py:290
msgid "Update or create transaction actions"
msgstr ""
#: apps/export_app/forms.py:176 templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
#: templates/export_app/fragments/restore.html:5
#: templates/export_app/pages/index.html:24
msgid "Restore"
msgstr ""
#: apps/export_app/forms.py:187
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr ""
#: apps/export_app/views.py:168
msgid "You have to select at least one export"
msgstr ""
#: apps/export_app/views.py:186
msgid "Data restored successfully"
msgstr ""
#: apps/export_app/views.py:198
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
#: apps/import_app/forms.py:49
msgid "Select a file"
msgstr ""
@@ -745,12 +860,49 @@ msgstr ""
msgid "Run deleted successfully"
msgstr ""
#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
#: apps/insights/utils/sankey.py:167
msgid "Uncategorized"
msgstr ""
#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119
#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235
#: 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:72
#: templates/insights/fragments/category_explorer/charts/currency.html:72
msgid "Current Income"
msgstr ""
#: 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
#: templates/insights/fragments/category_explorer/charts/currency.html:66
msgid "Current Expenses"
msgstr ""
#: 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:78
#: templates/insights/fragments/category_explorer/charts/currency.html:78
msgid "Projected Income"
msgstr ""
#: 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:60
#: templates/insights/fragments/category_explorer/charts/currency.html:60
msgid "Projected Expenses"
msgstr ""
#: apps/insights/utils/sankey.py:133 apps/insights/utils/sankey.py:134
#: apps/insights/utils/sankey.py:263 apps/insights/utils/sankey.py:264
msgid "Saved"
msgstr ""
@@ -770,7 +922,7 @@ msgstr ""
msgid "Set field"
msgstr ""
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:94
msgid "To"
msgstr ""
@@ -802,8 +954,8 @@ msgid "Paid"
msgstr ""
#: apps/rules/forms.py:164 apps/rules/forms.py:177 apps/rules/models.py:28
#: apps/rules/models.py:252 apps/transactions/forms.py:66
#: apps/transactions/forms.py:322 apps/transactions/forms.py:492
#: apps/rules/models.py:252 apps/transactions/forms.py:67
#: apps/transactions/forms.py:323 apps/transactions/forms.py:493
#: apps/transactions/models.py:187 apps/transactions/models.py:361
#: apps/transactions/models.py:570
msgid "Reference Date"
@@ -811,13 +963,13 @@ msgstr ""
#: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29
#: apps/rules/models.py:256 apps/transactions/models.py:192
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:95
msgid "Amount"
msgstr ""
#: apps/rules/forms.py:166 apps/rules/forms.py:179 apps/rules/models.py:11
#: apps/rules/models.py:30 apps/rules/models.py:260
#: apps/transactions/forms.py:325 apps/transactions/models.py:197
#: apps/transactions/forms.py:326 apps/transactions/models.py:197
#: apps/transactions/models.py:345 apps/transactions/models.py:554
msgid "Description"
msgstr ""
@@ -832,16 +984,6 @@ msgstr ""
msgid "Internal ID"
msgstr ""
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:486
#: apps/transactions/forms.py:731 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr ""
#: apps/rules/forms.py:199
msgid "Search Criteria"
msgstr ""
@@ -858,10 +1000,6 @@ msgstr ""
msgid "Transaction rule"
msgstr ""
#: apps/rules/models.py:16
msgid "Transaction rules"
msgstr ""
#: apps/rules/models.py:40 apps/rules/models.py:78
msgid "Rule"
msgstr ""
@@ -874,10 +1012,6 @@ msgstr ""
msgid "Value"
msgstr ""
#: apps/rules/models.py:53
msgid "Edit transaction action"
msgstr ""
#: apps/rules/models.py:54
msgid "Edit transaction actions"
msgstr ""
@@ -932,10 +1066,6 @@ msgstr ""
msgid "Update or create transaction action"
msgstr ""
#: apps/rules/models.py:290
msgid "Update or create transaction actions"
msgstr ""
#: apps/rules/views.py:52
msgid "Rule deactivated successfully"
msgstr ""
@@ -991,11 +1121,6 @@ msgstr ""
msgid "Transaction Type"
msgstr ""
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr ""
#: apps/transactions/filters.py:91
msgid "Date from"
msgstr ""
@@ -1016,40 +1141,40 @@ msgstr ""
msgid "Amount max"
msgstr ""
#: apps/transactions/forms.py:158
#: apps/transactions/forms.py:160
msgid "More"
msgstr ""
#: apps/transactions/forms.py:278
#: apps/transactions/forms.py:279
msgid "From Amount"
msgstr ""
#: apps/transactions/forms.py:283
#: apps/transactions/forms.py:284
msgid "To Amount"
msgstr ""
#: apps/transactions/forms.py:398
#: apps/transactions/forms.py:399
#: templates/cotton/ui/quick_transactions_buttons.html:40
msgid "Transfer"
msgstr ""
#: apps/transactions/forms.py:610
#: apps/transactions/forms.py:611
msgid "Tag name"
msgstr ""
#: apps/transactions/forms.py:642
#: apps/transactions/forms.py:643
msgid "Entity name"
msgstr ""
#: apps/transactions/forms.py:674
#: apps/transactions/forms.py:675
msgid "Category name"
msgstr ""
#: apps/transactions/forms.py:676
#: apps/transactions/forms.py:677
msgid "Muted categories won't count towards your monthly total"
msgstr ""
#: apps/transactions/forms.py:846
#: apps/transactions/forms.py:847
msgid "End date should be after the start date"
msgstr ""
@@ -1129,14 +1254,6 @@ msgstr ""
msgid "Transaction"
msgstr ""
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr ""
#: apps/transactions/models.py:323 templates/tags/fragments/table.html:53
msgid "No tags"
msgstr ""
@@ -1194,12 +1311,6 @@ msgstr ""
msgid "Installment Amount"
msgstr ""
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr ""
#: apps/transactions/models.py:533
msgid "day(s)"
msgstr ""
@@ -1237,12 +1348,6 @@ msgstr ""
msgid "Last Generated Reference Date"
msgstr ""
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr ""
#: apps/transactions/validators.py:8
#, python-format
msgid "%(value)s has too many decimal places. Maximum is 30."
@@ -1771,20 +1876,11 @@ msgstr ""
msgid "Select"
msgstr ""
#: templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr ""
#: templates/cotton/transaction/item.html:137
#: templates/cotton/ui/transactions_action_bar.html:78
msgid "Duplicate"
msgstr ""
#: templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
msgid "Restore"
msgstr ""
#: templates/cotton/ui/account_card.html:15
#: templates/cotton/ui/currency_card.html:10
msgid "projected income"
@@ -1888,26 +1984,6 @@ msgstr ""
msgid "Count"
msgstr ""
#: templates/cotton/ui/percentage_distribution.html:3
#: templates/cotton/ui/percentage_distribution.html:7
msgid "Projected Income"
msgstr ""
#: templates/cotton/ui/percentage_distribution.html:10
#: templates/cotton/ui/percentage_distribution.html:14
msgid "Current Income"
msgstr ""
#: templates/cotton/ui/percentage_distribution.html:17
#: templates/cotton/ui/percentage_distribution.html:21
msgid "Projected Expenses"
msgstr ""
#: templates/cotton/ui/percentage_distribution.html:24
#: templates/cotton/ui/percentage_distribution.html:28
msgid "Current Expenses"
msgstr ""
#: templates/cotton/ui/quick_transactions_buttons.html:25
msgid "Installment"
msgstr ""
@@ -2108,12 +2184,6 @@ msgstr ""
msgid "Page navigation"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:136
msgid "Automatic Exchange Rates"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:21
msgid "Fetch all"
msgstr ""
@@ -2142,6 +2212,10 @@ msgstr ""
msgid "No services configured"
msgstr ""
#: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136
msgid "Export and Restore"
msgstr ""
#: templates/import_app/fragments/profiles/add.html:6
msgid "Add new import profile"
msgstr ""
@@ -2154,11 +2228,6 @@ msgstr ""
msgid "Edit import profile"
msgstr ""
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr ""
#: templates/import_app/fragments/profiles/list.html:17
msgid "New"
msgstr ""
@@ -2283,20 +2352,15 @@ msgstr ""
msgid "Automation"
msgstr ""
#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5
#: templates/rules/pages/index.html:4
msgid "Rules"
msgstr ""
#: templates/includes/navbar.html:146
#: templates/includes/navbar.html:148
msgid "Only use this if you know what you're doing"
msgstr ""
#: templates/includes/navbar.html:147
#: templates/includes/navbar.html:149
msgid "Django Admin"
msgstr ""
#: templates/includes/navbar.html:156
#: templates/includes/navbar.html:158
msgid "Calculator"
msgstr ""
@@ -2328,44 +2392,89 @@ msgstr ""
msgid "Confirm"
msgstr ""
#: templates/insights/fragments/sankey.html:83
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr ""
#: templates/insights/fragments/category_explorer/index.html:14
msgid "Income/Expense by Account"
msgstr ""
#: templates/insights/fragments/category_explorer/index.html:26
msgid "Income/Expense by Currency"
msgstr ""
#: templates/insights/fragments/late_transactions.html:15
msgid "All good!"
msgstr ""
#: templates/insights/fragments/late_transactions.html:16
msgid "No late transactions"
msgstr ""
#: templates/insights/fragments/latest_transactions.html:14
msgid "No recent transactions"
msgstr ""
#: templates/insights/fragments/sankey.html:93
msgid "From"
msgstr ""
#: templates/insights/fragments/sankey.html:86
#: templates/insights/fragments/sankey.html:96
msgid "Percentage"
msgstr ""
#: templates/insights/pages/index.html:33
#: templates/insights/pages/index.html:35
msgid "Month"
msgstr ""
#: templates/insights/pages/index.html:36
#: templates/insights/pages/index.html:38
#: templates/yearly_overview/pages/overview_by_account.html:61
#: templates/yearly_overview/pages/overview_by_currency.html:63
msgid "Year"
msgstr ""
#: templates/insights/pages/index.html:39
#: templates/insights/pages/index.html:43
msgid "Month Range"
msgstr ""
#: templates/insights/pages/index.html:42
#: templates/insights/pages/index.html:48
msgid "Year Range"
msgstr ""
#: templates/insights/pages/index.html:45
#: templates/insights/pages/index.html:53
msgid "Date Range"
msgstr ""
#: templates/insights/pages/index.html:74
#: templates/insights/pages/index.html:81
msgid "Account Flow"
msgstr ""
#: templates/insights/pages/index.html:81
#: templates/insights/pages/index.html:88
msgid "Currency Flow"
msgstr ""
#: templates/insights/pages/index.html:95
msgid "Category Explorer"
msgstr ""
#: templates/insights/pages/index.html:102
msgid "Late Transactions"
msgstr ""
#: templates/insights/pages/index.html:108
msgid "Latest Transactions"
msgstr ""
#: templates/installment_plans/fragments/add.html:5
msgid "Add installment plan"
msgstr ""
@@ -2433,17 +2542,6 @@ msgstr ""
msgid "No transactions this month"
msgstr ""
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr ""
#: templates/monthly_overview/fragments/monthly_summary.html:6
msgid "Daily Spending Allowance"
msgstr ""

View File

@@ -2,14 +2,14 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-16 00:03-0300\n"
"PO-Revision-Date: 2025-02-12 06:58+0100\n"
"POT-Creation-Date: 2025-02-19 23:05-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"
@@ -27,10 +27,10 @@ msgstr "Groepsnaam"
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:142 apps/dca/forms.py:49 apps/dca/forms.py:224
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/rules/forms.py:359 apps/transactions/forms.py:190
#: apps/transactions/forms.py:257 apps/transactions/forms.py:581
#: apps/transactions/forms.py:624 apps/transactions/forms.py:656
#: apps/transactions/forms.py:691 apps/transactions/forms.py:827
#: apps/rules/forms.py:359 apps/transactions/forms.py:191
#: apps/transactions/forms.py:258 apps/transactions/forms.py:582
#: apps/transactions/forms.py:625 apps/transactions/forms.py:657
#: apps/transactions/forms.py:692 apps/transactions/forms.py:828
msgid "Update"
msgstr "Bijwerken"
@@ -39,10 +39,10 @@ msgstr "Bijwerken"
#: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:57 apps/dca/forms.py:232 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/rules/forms.py:367
#: apps/transactions/forms.py:174 apps/transactions/forms.py:199
#: apps/transactions/forms.py:589 apps/transactions/forms.py:632
#: apps/transactions/forms.py:664 apps/transactions/forms.py:699
#: apps/transactions/forms.py:835
#: apps/transactions/forms.py:176 apps/transactions/forms.py:200
#: apps/transactions/forms.py:590 apps/transactions/forms.py:633
#: apps/transactions/forms.py:665 apps/transactions/forms.py:700
#: apps/transactions/forms.py:836
#: templates/account_groups/fragments/list.html:9
#: templates/accounts/fragments/list.html:9
#: templates/categories/fragments/list.html:9
@@ -70,21 +70,22 @@ msgid "New balance"
msgstr "Nieuw saldo"
#: apps/accounts/forms.py:119 apps/dca/forms.py:85 apps/dca/forms.py:92
#: apps/rules/forms.py:168 apps/rules/forms.py:183 apps/rules/models.py:32
#: apps/rules/models.py:280 apps/transactions/forms.py:39
#: apps/transactions/forms.py:291 apps/transactions/forms.py:298
#: apps/transactions/forms.py:478 apps/transactions/forms.py:723
#: apps/transactions/models.py:203 apps/transactions/models.py:378
#: apps/transactions/models.py:558
#: apps/insights/forms.py:118 apps/rules/forms.py:168 apps/rules/forms.py:183
#: apps/rules/models.py:32 apps/rules/models.py:280
#: apps/transactions/forms.py:39 apps/transactions/forms.py:292
#: apps/transactions/forms.py:299 apps/transactions/forms.py:479
#: apps/transactions/forms.py:724 apps/transactions/models.py:203
#: apps/transactions/models.py:378 apps/transactions/models.py:558
msgid "Category"
msgstr "Categorie"
#: apps/accounts/forms.py:126 apps/dca/forms.py:101 apps/dca/forms.py:109
#: apps/export_app/forms.py:38 apps/export_app/forms.py:127
#: apps/rules/forms.py:171 apps/rules/forms.py:180 apps/rules/models.py:33
#: apps/rules/models.py:284 apps/transactions/filters.py:74
#: apps/transactions/forms.py:47 apps/transactions/forms.py:307
#: apps/transactions/forms.py:315 apps/transactions/forms.py:471
#: apps/transactions/forms.py:716 apps/transactions/models.py:209
#: apps/transactions/forms.py:47 apps/transactions/forms.py:308
#: apps/transactions/forms.py:316 apps/transactions/forms.py:472
#: apps/transactions/forms.py:717 apps/transactions/models.py:209
#: apps/transactions/models.py:380 apps/transactions/models.py:562
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
#: templates/tags/pages/index.html:4
@@ -159,13 +160,14 @@ msgstr ""
#: apps/accounts/models.py:59 apps/rules/forms.py:160 apps/rules/forms.py:173
#: apps/rules/models.py:24 apps/rules/models.py:236
#: apps/transactions/forms.py:59 apps/transactions/forms.py:463
#: apps/transactions/forms.py:708 apps/transactions/models.py:176
#: apps/transactions/forms.py:59 apps/transactions/forms.py:464
#: apps/transactions/forms.py:709 apps/transactions/models.py:176
#: apps/transactions/models.py:338 apps/transactions/models.py:540
msgid "Account"
msgstr "Rekening"
#: apps/accounts/models.py:60 apps/transactions/filters.py:53
#: apps/accounts/models.py:60 apps/export_app/forms.py:14
#: apps/export_app/forms.py:124 apps/transactions/filters.py:53
#: templates/accounts/fragments/list.html:5
#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114
#: templates/includes/navbar.html:116
@@ -337,12 +339,12 @@ msgstr "Info"
msgid "Cache cleared successfully"
msgstr "Categorie succesvol bijgewerkt"
#: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186
#: apps/common/widgets/datepicker.py:244
#: apps/common/widgets/datepicker.py:53 apps/common/widgets/datepicker.py:206
#: apps/common/widgets/datepicker.py:264
msgid "Today"
msgstr "Vandaag"
#: apps/common/widgets/datepicker.py:123
#: apps/common/widgets/datepicker.py:139
msgid "Now"
msgstr "Nu"
@@ -371,7 +373,7 @@ msgstr "Achtervoegsel"
#: apps/currencies/forms.py:69 apps/dca/models.py:156 apps/rules/forms.py:163
#: apps/rules/forms.py:176 apps/rules/models.py:27 apps/rules/models.py:248
#: apps/transactions/forms.py:63 apps/transactions/forms.py:319
#: apps/transactions/forms.py:63 apps/transactions/forms.py:320
#: apps/transactions/models.py:186
#: templates/dca/fragments/strategy/details.html:52
#: templates/exchange_rates/fragments/table.html:10
@@ -391,7 +393,8 @@ msgstr "Munteenheids Naam"
msgid "Decimal Places"
msgstr "Cijfers na de komma"
#: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: apps/currencies/models.py:40 apps/export_app/forms.py:20
#: apps/export_app/forms.py:125 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122
#: templates/includes/navbar.html:124
@@ -421,7 +424,8 @@ msgstr "Wisselkoers"
msgid "Date and Time"
msgstr "Datum en Tijd"
#: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: apps/currencies/models.py:74 apps/export_app/forms.py:62
#: apps/export_app/forms.py:137 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:126
msgid "Exchange Rates"
@@ -578,16 +582,14 @@ 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:266
#: apps/dca/forms.py:70 apps/transactions/forms.py:267
msgid "From Account"
msgstr "Van rekening"
#: apps/dca/forms.py:76 apps/transactions/forms.py:271
#: apps/dca/forms.py:76 apps/transactions/forms.py:272
msgid "To Account"
msgstr "Naar rekening"
@@ -598,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:413
#: 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"
@@ -634,7 +634,7 @@ msgstr "Betaal Munteenheid"
#: apps/dca/models.py:27 apps/dca/models.py:179 apps/rules/forms.py:167
#: apps/rules/forms.py:182 apps/rules/models.py:31 apps/rules/models.py:264
#: apps/transactions/forms.py:333 apps/transactions/models.py:199
#: apps/transactions/forms.py:334 apps/transactions/models.py:199
#: apps/transactions/models.py:387 apps/transactions/models.py:568
msgid "Notes"
msgstr "Opmerkingen"
@@ -643,7 +643,7 @@ msgstr "Opmerkingen"
msgid "DCA Strategy"
msgstr "DCA Strategie"
#: apps/dca/models.py:33
#: apps/dca/models.py:33 apps/export_app/forms.py:145
msgid "DCA Strategies"
msgstr "DCA Strategieën"
@@ -663,7 +663,7 @@ msgstr "Ontvangen bedrag"
msgid "DCA Entry"
msgstr "DCA Instap"
#: apps/dca/models.py:185
#: apps/dca/models.py:185 apps/export_app/forms.py:146
msgid "DCA Entries"
msgstr "DCA Idems"
@@ -691,6 +691,119 @@ msgstr "Item succesvol bijgewerkt"
msgid "Entry deleted successfully"
msgstr "Item succesvol verwijderd"
#: apps/export_app/forms.py:26 apps/export_app/forms.py:129
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr "Verrichtingen"
#: apps/export_app/forms.py:32 apps/export_app/forms.py:126
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr "Categorieën"
#: apps/export_app/forms.py:44 apps/export_app/forms.py:128
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:487
#: apps/transactions/forms.py:732 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr "Bedrijven"
#: apps/export_app/forms.py:50 apps/export_app/forms.py:132
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr "Terugkerende Verrichtingen"
#: apps/export_app/forms.py:56 apps/export_app/forms.py:130
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr "Afbetalingsplannen"
#: apps/export_app/forms.py:68 apps/export_app/forms.py:135
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:138
msgid "Automatic Exchange Rates"
msgstr "Automatische Wisselkoersen"
#: apps/export_app/forms.py:74 templates/includes/navbar.html:132
#: templates/rules/fragments/list.html:5 templates/rules/pages/index.html:4
msgid "Rules"
msgstr "Regels"
#: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr "DCA"
#: apps/export_app/forms.py:86 apps/export_app/forms.py:147
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr "Profielen importeren"
#: apps/export_app/forms.py:112 templates/export_app/fragments/export.html:5
#: templates/export_app/pages/index.html:15
msgid "Export"
msgstr "Exporteer"
#: apps/export_app/forms.py:121
msgid "Import a ZIP file exported from WYGIWYH"
msgstr "Importeer een ZIP-bestand geëxporteerd vanuit WYGIWYH"
#: apps/export_app/forms.py:122
msgid "ZIP File"
msgstr "ZIP-bestand"
#: apps/export_app/forms.py:138 apps/rules/models.py:16
msgid "Transaction rules"
msgstr "Verrichtingsregels"
#: apps/export_app/forms.py:140 apps/rules/models.py:53
msgid "Edit transaction action"
msgstr "Bewerk verrichtingsregel actie"
#: apps/export_app/forms.py:143 apps/rules/models.py:290
msgid "Update or create transaction actions"
msgstr "Bewerk of maak verrichtingsregel acties"
#: apps/export_app/forms.py:176 templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
#: templates/export_app/fragments/restore.html:5
#: templates/export_app/pages/index.html:24
msgid "Restore"
msgstr "Herstel"
#: apps/export_app/forms.py:187
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "Upload een ZIP-bestand of ten minste één CSV-bestand"
#: apps/export_app/views.py:168
msgid "You have to select at least one export"
msgstr "U moet ten minste één export selecteren"
#: apps/export_app/views.py:186
msgid "Data restored successfully"
msgstr "Gegevens succesvol hersteld"
#: 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"
msgstr "Selecteer een bestand"
@@ -765,18 +878,51 @@ msgstr "Importrun met succes in de wachtrij geplaatst"
msgid "Run deleted successfully"
msgstr "Run met succes verwijderd"
#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154
#, fuzzy
#| msgid "Categories"
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
#: apps/insights/utils/sankey.py:167
msgid "Uncategorized"
msgstr "Categorieën"
msgstr "Ongecategoriseerd"
#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119
#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235
#, fuzzy
#| msgid "Save"
#: 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:72
#: templates/insights/fragments/category_explorer/charts/currency.html:72
msgid "Current Income"
msgstr "Huidige inkomsten"
#: 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
#: templates/insights/fragments/category_explorer/charts/currency.html:66
msgid "Current Expenses"
msgstr "Huidige uitgaven"
#: 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:78
#: templates/insights/fragments/category_explorer/charts/currency.html:78
msgid "Projected Income"
msgstr "Verwachte inkomsten"
#: 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: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
msgid "Saved"
msgstr "Opslaan"
msgstr "Opgeslagen"
#: apps/rules/forms.py:20
msgid "Run on creation"
@@ -794,7 +940,7 @@ msgstr "Als..."
msgid "Set field"
msgstr "Veld instellen"
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:94
msgid "To"
msgstr "Naar"
@@ -826,8 +972,8 @@ msgid "Paid"
msgstr "Betaald"
#: apps/rules/forms.py:164 apps/rules/forms.py:177 apps/rules/models.py:28
#: apps/rules/models.py:252 apps/transactions/forms.py:66
#: apps/transactions/forms.py:322 apps/transactions/forms.py:492
#: apps/rules/models.py:252 apps/transactions/forms.py:67
#: apps/transactions/forms.py:323 apps/transactions/forms.py:493
#: apps/transactions/models.py:187 apps/transactions/models.py:361
#: apps/transactions/models.py:570
msgid "Reference Date"
@@ -835,13 +981,13 @@ msgstr "Referentiedatum"
#: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29
#: apps/rules/models.py:256 apps/transactions/models.py:192
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:95
msgid "Amount"
msgstr "Bedrag"
#: apps/rules/forms.py:166 apps/rules/forms.py:179 apps/rules/models.py:11
#: apps/rules/models.py:30 apps/rules/models.py:260
#: apps/transactions/forms.py:325 apps/transactions/models.py:197
#: apps/transactions/forms.py:326 apps/transactions/models.py:197
#: apps/transactions/models.py:345 apps/transactions/models.py:554
msgid "Description"
msgstr "Beschrijving"
@@ -856,16 +1002,6 @@ msgstr "Interne opmerking"
msgid "Internal ID"
msgstr "Interne ID"
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:486
#: apps/transactions/forms.py:731 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr "Bedrijven"
#: apps/rules/forms.py:199
msgid "Search Criteria"
msgstr "Zoek Vereisten"
@@ -882,10 +1018,6 @@ msgstr "Trigger"
msgid "Transaction rule"
msgstr "Verrichtingsregel"
#: apps/rules/models.py:16
msgid "Transaction rules"
msgstr "Verrichtingsregels"
#: apps/rules/models.py:40 apps/rules/models.py:78
msgid "Rule"
msgstr "Regel"
@@ -898,10 +1030,6 @@ msgstr "Veld"
msgid "Value"
msgstr "Waarde"
#: apps/rules/models.py:53
msgid "Edit transaction action"
msgstr "Bewerk verrichtingsregel actie"
#: apps/rules/models.py:54
msgid "Edit transaction actions"
msgstr "Bewerk verrichtingsregel acties"
@@ -947,22 +1075,17 @@ 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"
msgstr "Bewerk of maak verrichtingsregel actie"
#: apps/rules/models.py:290
msgid "Update or create transaction actions"
msgstr "Bewerk of maak verrichtingsregel acties"
#: apps/rules/views.py:52
msgid "Rule deactivated successfully"
msgstr "Regel succesvol uitgeschakeld"
@@ -1018,11 +1141,6 @@ msgstr "Inhoud"
msgid "Transaction Type"
msgstr "Soort transactie"
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr "Categorieën"
#: apps/transactions/filters.py:91
msgid "Date from"
msgstr "Datum vanaf"
@@ -1043,40 +1161,40 @@ msgstr "Minimum bedrag"
msgid "Amount max"
msgstr "Maximaal bedrag"
#: apps/transactions/forms.py:158
#: apps/transactions/forms.py:160
msgid "More"
msgstr "Meer"
#: apps/transactions/forms.py:278
#: apps/transactions/forms.py:279
msgid "From Amount"
msgstr "Van Bedrag"
#: apps/transactions/forms.py:283
#: apps/transactions/forms.py:284
msgid "To Amount"
msgstr "Naar Bedrag"
#: apps/transactions/forms.py:398
#: apps/transactions/forms.py:399
#: templates/cotton/ui/quick_transactions_buttons.html:40
msgid "Transfer"
msgstr "Overschrijving"
#: apps/transactions/forms.py:610
#: apps/transactions/forms.py:611
msgid "Tag name"
msgstr "Labelnaam"
#: apps/transactions/forms.py:642
#: apps/transactions/forms.py:643
msgid "Entity name"
msgstr "Naam van bedrijf"
#: apps/transactions/forms.py:674
#: apps/transactions/forms.py:675
msgid "Category name"
msgstr "Naam van categorie"
#: apps/transactions/forms.py:676
#: apps/transactions/forms.py:677
msgid "Muted categories won't count towards your monthly total"
msgstr "Gedempte categorieën tellen niet mee voor je maandtotaal"
#: apps/transactions/forms.py:846
#: apps/transactions/forms.py:847
msgid "End date should be after the start date"
msgstr "De einddatum moet na de begindatum vallen"
@@ -1162,29 +1280,17 @@ msgstr "Verwijderd Op"
msgid "Transaction"
msgstr "Verrichting"
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr "Verrichtingen"
#: apps/transactions/models.py:323 templates/tags/fragments/table.html:53
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"
@@ -1231,12 +1337,6 @@ msgstr "Terugkeerpatroon"
msgid "Installment Amount"
msgstr "Termijnbedrag"
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr "Afbetalingsplannen"
#: apps/transactions/models.py:533
msgid "day(s)"
msgstr "dag(en)"
@@ -1274,12 +1374,6 @@ msgstr "Laatste Gegenereerde Datum"
msgid "Last Generated Reference Date"
msgstr "Laatste Gegenereerde Referentiedatum"
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr "Terugkerende Verrichtingen"
#: apps/transactions/validators.py:8
#, python-format
msgid "%(value)s has too many decimal places. Maximum is 30."
@@ -1808,20 +1902,11 @@ msgstr "Zoeken"
msgid "Select"
msgstr "Selecteer"
#: templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr ""
#: templates/cotton/transaction/item.html:137
#: templates/cotton/ui/transactions_action_bar.html:78
msgid "Duplicate"
msgstr "Dupliceren"
#: templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
msgid "Restore"
msgstr "Herstel"
#: templates/cotton/ui/account_card.html:15
#: templates/cotton/ui/currency_card.html:10
msgid "projected income"
@@ -1925,26 +2010,6 @@ msgstr "Minimaal"
msgid "Count"
msgstr "Rekenen"
#: templates/cotton/ui/percentage_distribution.html:3
#: templates/cotton/ui/percentage_distribution.html:7
msgid "Projected Income"
msgstr "Verwachte inkomsten"
#: templates/cotton/ui/percentage_distribution.html:10
#: templates/cotton/ui/percentage_distribution.html:14
msgid "Current Income"
msgstr "Huidige inkomsten"
#: templates/cotton/ui/percentage_distribution.html:17
#: templates/cotton/ui/percentage_distribution.html:21
msgid "Projected Expenses"
msgstr "Verwachte uitgaven"
#: templates/cotton/ui/percentage_distribution.html:24
#: templates/cotton/ui/percentage_distribution.html:28
msgid "Current Expenses"
msgstr "Huidige uitgaven"
#: templates/cotton/ui/quick_transactions_buttons.html:25
msgid "Installment"
msgstr "Afbetaling"
@@ -2145,12 +2210,6 @@ msgstr "Geen wisselkoersen"
msgid "Page navigation"
msgstr "Paginanavigatie"
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:136
msgid "Automatic Exchange Rates"
msgstr "Automatische Wisselkoersen"
#: templates/exchange_rates_services/fragments/list.html:21
msgid "Fetch all"
msgstr "Alles Ophalen"
@@ -2179,6 +2238,10 @@ msgstr "rekeningen"
msgid "No services configured"
msgstr "Geen diensten ingesteld"
#: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136
msgid "Export and Restore"
msgstr "Exporteren en Herstellen"
#: templates/import_app/fragments/profiles/add.html:6
msgid "Add new import profile"
msgstr "Nieuw importprofiel toevoegen"
@@ -2191,11 +2254,6 @@ msgstr "Een bericht van de auteur"
msgid "Edit import profile"
msgstr "Importprofiel bewerken"
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr "Profielen importeren"
#: templates/import_app/fragments/profiles/list.html:17
msgid "New"
msgstr "Nieuw"
@@ -2287,7 +2345,7 @@ msgstr "Huidige"
#: templates/includes/navbar.html:50
msgid "Insights"
msgstr ""
msgstr "Inzichten"
#: templates/includes/navbar.html:66
msgid "Trash Can"
@@ -2321,20 +2379,15 @@ msgstr "Beheer"
msgid "Automation"
msgstr "Automatisatie"
#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5
#: templates/rules/pages/index.html:4
msgid "Rules"
msgstr "Regels"
#: templates/includes/navbar.html:146
#: templates/includes/navbar.html:148
msgid "Only use this if you know what you're doing"
msgstr "Gebruik dit alleen als je weet wat je doet"
#: templates/includes/navbar.html:147
#: templates/includes/navbar.html:149
msgid "Django Admin"
msgstr "Django Beheerder"
#: templates/includes/navbar.html:156
#: templates/includes/navbar.html:158
msgid "Calculator"
msgstr "Rekenmachine"
@@ -2368,53 +2421,88 @@ msgstr "Annuleer"
msgid "Confirm"
msgstr "Bevestig"
#: templates/insights/fragments/sankey.html:83
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr "Geen informatie om weer te geven"
#: templates/insights/fragments/category_explorer/index.html:14
msgid "Income/Expense by Account"
msgstr "Inkomsten/uitgaven per rekening"
#: templates/insights/fragments/category_explorer/index.html:26
msgid "Income/Expense by Currency"
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:86
#: templates/insights/fragments/sankey.html:96
msgid "Percentage"
msgstr ""
msgstr "Percentage"
#: templates/insights/pages/index.html:33
#, fuzzy
#| msgid "Monthly"
#: templates/insights/pages/index.html:35
msgid "Month"
msgstr "Maandelijks"
msgstr "Maand"
#: templates/insights/pages/index.html:36
#: templates/insights/pages/index.html:38
#: templates/yearly_overview/pages/overview_by_account.html:61
#: templates/yearly_overview/pages/overview_by_currency.html:63
msgid "Year"
msgstr "Jaar"
#: templates/insights/pages/index.html:39
#, fuzzy
#| msgid "Unchanged"
#: templates/insights/pages/index.html:43
msgid "Month Range"
msgstr "Ongewijzigd"
msgstr "Maand Bereik"
#: templates/insights/pages/index.html:42
#: templates/insights/pages/index.html:48
msgid "Year Range"
msgstr ""
msgstr "Jaar Bereik"
#: templates/insights/pages/index.html:45
#, fuzzy
#| msgid "Date and Time"
#: templates/insights/pages/index.html:53
msgid "Date Range"
msgstr "Datum en Tijd"
#: templates/insights/pages/index.html:74
#, fuzzy
#| msgid "Account"
msgid "Account Flow"
msgstr "Rekening"
msgstr "Datum Bereik"
#: templates/insights/pages/index.html:81
#, fuzzy
#| msgid "Currency Code"
msgid "Account Flow"
msgstr "Rekeningstroom"
#: templates/insights/pages/index.html:88
msgid "Currency Flow"
msgstr "Munteenheids Code"
msgstr "Geldstroom"
#: templates/insights/pages/index.html:95
msgid "Category Explorer"
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"
@@ -2485,17 +2573,6 @@ msgstr "Artikel"
msgid "No transactions this month"
msgstr "Geen verrichtingen deze maand"
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr "Geen informatie om weer te geven"
#: templates/monthly_overview/fragments/monthly_summary.html:6
msgid "Daily Spending Allowance"
msgstr "Dagelijks Toegestane Besteding"
@@ -2789,6 +2866,11 @@ msgstr "Bedragen tonen"
msgid "Yearly Overview"
msgstr "Jaaroverzicht"
#, fuzzy
#~| msgid "Installment Plans"
#~ msgid "Installment Planss"
#~ msgstr "Afbetalingsplannen"
#, fuzzy
#~| msgid "Start Date"
#~ msgid "Search Date"
@@ -2879,11 +2961,6 @@ msgstr "Jaaroverzicht"
#~ msgid "Search Category"
#~ msgstr "Categorie"
#, fuzzy
#~| msgid "Category name"
#~ msgid "Category Operator"
#~ msgstr "Naam van categorie"
#, fuzzy
#~| msgid "Search"
#~ msgid "Search Tags"

View File

@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-16 00:03-0300\n"
"PO-Revision-Date: 2025-02-16 00:04-0300\n"
"POT-Creation-Date: 2025-02-19 23:05-0300\n"
"PO-Revision-Date: 2025-02-19 23:06-0300\n"
"Last-Translator: Herculino Trotta\n"
"Language-Team: \n"
"Language: pt_BR\n"
@@ -27,10 +27,10 @@ msgstr "Nome do grupo"
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:142 apps/dca/forms.py:49 apps/dca/forms.py:224
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/rules/forms.py:359 apps/transactions/forms.py:190
#: apps/transactions/forms.py:257 apps/transactions/forms.py:581
#: apps/transactions/forms.py:624 apps/transactions/forms.py:656
#: apps/transactions/forms.py:691 apps/transactions/forms.py:827
#: apps/rules/forms.py:359 apps/transactions/forms.py:191
#: apps/transactions/forms.py:258 apps/transactions/forms.py:582
#: apps/transactions/forms.py:625 apps/transactions/forms.py:657
#: apps/transactions/forms.py:692 apps/transactions/forms.py:828
msgid "Update"
msgstr "Atualizar"
@@ -39,10 +39,10 @@ msgstr "Atualizar"
#: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:57 apps/dca/forms.py:232 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/rules/forms.py:367
#: apps/transactions/forms.py:174 apps/transactions/forms.py:199
#: apps/transactions/forms.py:589 apps/transactions/forms.py:632
#: apps/transactions/forms.py:664 apps/transactions/forms.py:699
#: apps/transactions/forms.py:835
#: apps/transactions/forms.py:176 apps/transactions/forms.py:200
#: apps/transactions/forms.py:590 apps/transactions/forms.py:633
#: apps/transactions/forms.py:665 apps/transactions/forms.py:700
#: apps/transactions/forms.py:836
#: templates/account_groups/fragments/list.html:9
#: templates/accounts/fragments/list.html:9
#: templates/categories/fragments/list.html:9
@@ -70,21 +70,22 @@ msgid "New balance"
msgstr "Novo saldo"
#: apps/accounts/forms.py:119 apps/dca/forms.py:85 apps/dca/forms.py:92
#: apps/rules/forms.py:168 apps/rules/forms.py:183 apps/rules/models.py:32
#: apps/rules/models.py:280 apps/transactions/forms.py:39
#: apps/transactions/forms.py:291 apps/transactions/forms.py:298
#: apps/transactions/forms.py:478 apps/transactions/forms.py:723
#: apps/transactions/models.py:203 apps/transactions/models.py:378
#: apps/transactions/models.py:558
#: apps/insights/forms.py:118 apps/rules/forms.py:168 apps/rules/forms.py:183
#: apps/rules/models.py:32 apps/rules/models.py:280
#: apps/transactions/forms.py:39 apps/transactions/forms.py:292
#: apps/transactions/forms.py:299 apps/transactions/forms.py:479
#: apps/transactions/forms.py:724 apps/transactions/models.py:203
#: apps/transactions/models.py:378 apps/transactions/models.py:558
msgid "Category"
msgstr "Categoria"
#: apps/accounts/forms.py:126 apps/dca/forms.py:101 apps/dca/forms.py:109
#: apps/export_app/forms.py:38 apps/export_app/forms.py:127
#: apps/rules/forms.py:171 apps/rules/forms.py:180 apps/rules/models.py:33
#: apps/rules/models.py:284 apps/transactions/filters.py:74
#: apps/transactions/forms.py:47 apps/transactions/forms.py:307
#: apps/transactions/forms.py:315 apps/transactions/forms.py:471
#: apps/transactions/forms.py:716 apps/transactions/models.py:209
#: apps/transactions/forms.py:47 apps/transactions/forms.py:308
#: apps/transactions/forms.py:316 apps/transactions/forms.py:472
#: apps/transactions/forms.py:717 apps/transactions/models.py:209
#: apps/transactions/models.py:380 apps/transactions/models.py:562
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
#: templates/tags/pages/index.html:4
@@ -158,13 +159,14 @@ msgstr ""
#: apps/accounts/models.py:59 apps/rules/forms.py:160 apps/rules/forms.py:173
#: apps/rules/models.py:24 apps/rules/models.py:236
#: apps/transactions/forms.py:59 apps/transactions/forms.py:463
#: apps/transactions/forms.py:708 apps/transactions/models.py:176
#: apps/transactions/forms.py:59 apps/transactions/forms.py:464
#: apps/transactions/forms.py:709 apps/transactions/models.py:176
#: apps/transactions/models.py:338 apps/transactions/models.py:540
msgid "Account"
msgstr "Conta"
#: apps/accounts/models.py:60 apps/transactions/filters.py:53
#: apps/accounts/models.py:60 apps/export_app/forms.py:14
#: apps/export_app/forms.py:124 apps/transactions/filters.py:53
#: templates/accounts/fragments/list.html:5
#: templates/accounts/pages/index.html:4 templates/includes/navbar.html:114
#: templates/includes/navbar.html:116
@@ -335,12 +337,12 @@ msgstr "Informação"
msgid "Cache cleared successfully"
msgstr "Cache limpo com sucesso"
#: apps/common/widgets/datepicker.py:47 apps/common/widgets/datepicker.py:186
#: apps/common/widgets/datepicker.py:244
#: apps/common/widgets/datepicker.py:53 apps/common/widgets/datepicker.py:206
#: apps/common/widgets/datepicker.py:264
msgid "Today"
msgstr "Hoje"
#: apps/common/widgets/datepicker.py:123
#: apps/common/widgets/datepicker.py:139
msgid "Now"
msgstr "Agora"
@@ -369,7 +371,7 @@ msgstr "Sufixo"
#: apps/currencies/forms.py:69 apps/dca/models.py:156 apps/rules/forms.py:163
#: apps/rules/forms.py:176 apps/rules/models.py:27 apps/rules/models.py:248
#: apps/transactions/forms.py:63 apps/transactions/forms.py:319
#: apps/transactions/forms.py:63 apps/transactions/forms.py:320
#: apps/transactions/models.py:186
#: templates/dca/fragments/strategy/details.html:52
#: templates/exchange_rates/fragments/table.html:10
@@ -389,7 +391,8 @@ msgstr "Nome da Moeda"
msgid "Decimal Places"
msgstr "Casas Decimais"
#: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: apps/currencies/models.py:40 apps/export_app/forms.py:20
#: apps/export_app/forms.py:125 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:122
#: templates/includes/navbar.html:124
@@ -419,7 +422,8 @@ msgstr "Taxa de Câmbio"
msgid "Date and Time"
msgstr "Data e Tempo"
#: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: apps/currencies/models.py:74 apps/export_app/forms.py:62
#: apps/export_app/forms.py:137 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:126
msgid "Exchange Rates"
@@ -580,11 +584,11 @@ msgstr "Serviços marcados para execução com sucesso"
msgid "Create transaction"
msgstr "Criar transação"
#: apps/dca/forms.py:70 apps/transactions/forms.py:266
#: apps/dca/forms.py:70 apps/transactions/forms.py:267
msgid "From Account"
msgstr "Conta de origem"
#: apps/dca/forms.py:76 apps/transactions/forms.py:271
#: apps/dca/forms.py:76 apps/transactions/forms.py:272
msgid "To Account"
msgstr "Conta de destino"
@@ -609,7 +613,7 @@ msgstr "Conectar transação"
msgid "You must provide an account."
msgstr "Você deve informar uma conta."
#: apps/dca/forms.py:294 apps/transactions/forms.py:413
#: apps/dca/forms.py:294 apps/transactions/forms.py:414
msgid "From and To accounts must be different."
msgstr "As contas De e Para devem ser diferentes."
@@ -628,7 +632,7 @@ msgstr "Moeda de pagamento"
#: apps/dca/models.py:27 apps/dca/models.py:179 apps/rules/forms.py:167
#: apps/rules/forms.py:182 apps/rules/models.py:31 apps/rules/models.py:264
#: apps/transactions/forms.py:333 apps/transactions/models.py:199
#: apps/transactions/forms.py:334 apps/transactions/models.py:199
#: apps/transactions/models.py:387 apps/transactions/models.py:568
msgid "Notes"
msgstr "Notas"
@@ -637,7 +641,7 @@ msgstr "Notas"
msgid "DCA Strategy"
msgstr "Estratégia CMP"
#: apps/dca/models.py:33
#: apps/dca/models.py:33 apps/export_app/forms.py:145
msgid "DCA Strategies"
msgstr "Estratégias CMP"
@@ -657,7 +661,7 @@ msgstr "Quantia recebida"
msgid "DCA Entry"
msgstr "Entrada CMP"
#: apps/dca/models.py:185
#: apps/dca/models.py:185 apps/export_app/forms.py:146
msgid "DCA Entries"
msgstr "Entradas CMP"
@@ -685,6 +689,119 @@ msgstr "Entrada atualizada com sucesso"
msgid "Entry deleted successfully"
msgstr "Entrada apagada com sucesso"
#: apps/export_app/forms.py:26 apps/export_app/forms.py:129
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr "Transações"
#: apps/export_app/forms.py:32 apps/export_app/forms.py:126
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr "Categorias"
#: apps/export_app/forms.py:44 apps/export_app/forms.py:128
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:487
#: apps/transactions/forms.py:732 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr "Entidades"
#: apps/export_app/forms.py:50 apps/export_app/forms.py:132
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr "Transações Recorrentes"
#: apps/export_app/forms.py:56 apps/export_app/forms.py:130
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr "Parcelamentos"
#: apps/export_app/forms.py:68 apps/export_app/forms.py:135
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:138
msgid "Automatic Exchange Rates"
msgstr "Taxas de Câmbio Automáticas"
#: apps/export_app/forms.py:74 templates/includes/navbar.html:132
#: templates/rules/fragments/list.html:5 templates/rules/pages/index.html:4
msgid "Rules"
msgstr "Regras"
#: apps/export_app/forms.py:80 templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr "CMP"
#: apps/export_app/forms.py:86 apps/export_app/forms.py:147
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr "Perfis de Importação"
#: apps/export_app/forms.py:112 templates/export_app/fragments/export.html:5
#: templates/export_app/pages/index.html:15
msgid "Export"
msgstr "Exportar"
#: apps/export_app/forms.py:121
msgid "Import a ZIP file exported from WYGIWYH"
msgstr "Importe um arquivo ZIP exportado do WYGIWYH"
#: apps/export_app/forms.py:122
msgid "ZIP File"
msgstr "Arquivo ZIP"
#: apps/export_app/forms.py:138 apps/rules/models.py:16
msgid "Transaction rules"
msgstr "Regra da transação"
#: apps/export_app/forms.py:140 apps/rules/models.py:53
msgid "Edit transaction action"
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"
#: apps/export_app/forms.py:176 templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
#: templates/export_app/fragments/restore.html:5
#: templates/export_app/pages/index.html:24
msgid "Restore"
msgstr "Restaurar"
#: apps/export_app/forms.py:187
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:168
msgid "You have to select at least one export"
msgstr "É necessário selecionar pelo menos uma exportação"
#: apps/export_app/views.py:186
msgid "Data restored successfully"
msgstr "Dados restaurados com sucesso"
#: apps/export_app/views.py:198
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
"Ocorreu um erro ao restaurar seus dados. Verifique o log para obter mais "
"detalhes."
#: apps/import_app/forms.py:49
msgid "Select a file"
msgstr "Selecione um arquivo"
@@ -759,12 +876,49 @@ msgstr "Importação adicionada à fila com sucesso"
msgid "Run deleted successfully"
msgstr "Importação apagada com sucesso"
#: apps/insights/utils/sankey.py:37 apps/insights/utils/sankey.py:154
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
#: apps/insights/utils/sankey.py:167
msgid "Uncategorized"
msgstr "Sem categoria"
#: apps/insights/utils/sankey.py:118 apps/insights/utils/sankey.py:119
#: apps/insights/utils/sankey.py:234 apps/insights/utils/sankey.py:235
#: 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:72
#: templates/insights/fragments/category_explorer/charts/currency.html:72
msgid "Current Income"
msgstr "Renda Atual"
#: 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
#: templates/insights/fragments/category_explorer/charts/currency.html:66
msgid "Current Expenses"
msgstr "Despesas Atuais"
#: 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:78
#: templates/insights/fragments/category_explorer/charts/currency.html:78
msgid "Projected Income"
msgstr "Renda Prevista"
#: 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:60
#: templates/insights/fragments/category_explorer/charts/currency.html:60
msgid "Projected Expenses"
msgstr "Despesas Previstas"
#: apps/insights/utils/sankey.py:133 apps/insights/utils/sankey.py:134
#: apps/insights/utils/sankey.py:263 apps/insights/utils/sankey.py:264
msgid "Saved"
msgstr "Salvo"
@@ -784,7 +938,7 @@ msgstr "Se..."
msgid "Set field"
msgstr "Definir campo"
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:84
#: apps/rules/forms.py:65 templates/insights/fragments/sankey.html:94
msgid "To"
msgstr "Para"
@@ -816,8 +970,8 @@ msgid "Paid"
msgstr "Pago"
#: apps/rules/forms.py:164 apps/rules/forms.py:177 apps/rules/models.py:28
#: apps/rules/models.py:252 apps/transactions/forms.py:66
#: apps/transactions/forms.py:322 apps/transactions/forms.py:492
#: apps/rules/models.py:252 apps/transactions/forms.py:67
#: apps/transactions/forms.py:323 apps/transactions/forms.py:493
#: apps/transactions/models.py:187 apps/transactions/models.py:361
#: apps/transactions/models.py:570
msgid "Reference Date"
@@ -825,13 +979,13 @@ msgstr "Data de Referência"
#: apps/rules/forms.py:165 apps/rules/forms.py:178 apps/rules/models.py:29
#: apps/rules/models.py:256 apps/transactions/models.py:192
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:85
#: apps/transactions/models.py:551 templates/insights/fragments/sankey.html:95
msgid "Amount"
msgstr "Quantia"
#: apps/rules/forms.py:166 apps/rules/forms.py:179 apps/rules/models.py:11
#: apps/rules/models.py:30 apps/rules/models.py:260
#: apps/transactions/forms.py:325 apps/transactions/models.py:197
#: apps/transactions/forms.py:326 apps/transactions/models.py:197
#: apps/transactions/models.py:345 apps/transactions/models.py:554
msgid "Description"
msgstr "Descrição"
@@ -846,16 +1000,6 @@ msgstr "Nota Interna"
msgid "Internal ID"
msgstr "ID Interna"
#: apps/rules/forms.py:172 apps/rules/forms.py:181 apps/rules/models.py:34
#: apps/rules/models.py:276 apps/transactions/filters.py:81
#: apps/transactions/forms.py:55 apps/transactions/forms.py:486
#: apps/transactions/forms.py:731 apps/transactions/models.py:161
#: apps/transactions/models.py:214 apps/transactions/models.py:383
#: apps/transactions/models.py:565 templates/entities/fragments/list.html:5
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
msgid "Entities"
msgstr "Entidades"
#: apps/rules/forms.py:199
msgid "Search Criteria"
msgstr "Critério de Busca"
@@ -872,10 +1016,6 @@ msgstr "Gatilho"
msgid "Transaction rule"
msgstr "Regra da transação"
#: apps/rules/models.py:16
msgid "Transaction rules"
msgstr "Regra da transação"
#: apps/rules/models.py:40 apps/rules/models.py:78
msgid "Rule"
msgstr "Regra"
@@ -888,13 +1028,9 @@ msgstr "Campo"
msgid "Value"
msgstr "Valor"
#: apps/rules/models.py:53
msgid "Edit transaction action"
msgstr "Editar ação de transação"
#: apps/rules/models.py:54
msgid "Edit transaction actions"
msgstr "Editar ações de transação"
msgstr "Ações de editar de transação"
#: apps/rules/models.py:64
msgid "is exactly"
@@ -946,11 +1082,7 @@ msgstr ""
#: apps/rules/models.py:289
msgid "Update or create transaction action"
msgstr "Atualizar ou criar transação ação"
#: apps/rules/models.py:290
msgid "Update or create transaction actions"
msgstr "Atualizar ou criar transação ações"
msgstr "Ação de atualizar ou criar transação"
#: apps/rules/views.py:52
msgid "Rule deactivated successfully"
@@ -1007,11 +1139,6 @@ msgstr "Conteúdo"
msgid "Transaction Type"
msgstr "Tipo de Transação"
#: apps/transactions/filters.py:67 templates/categories/fragments/list.html:5
#: templates/categories/pages/index.html:4 templates/includes/navbar.html:106
msgid "Categories"
msgstr "Categorias"
#: apps/transactions/filters.py:91
msgid "Date from"
msgstr "Data de"
@@ -1032,40 +1159,40 @@ msgstr "Quantia miníma"
msgid "Amount max"
msgstr "Quantia máxima"
#: apps/transactions/forms.py:158
#: apps/transactions/forms.py:160
msgid "More"
msgstr "Mais"
#: apps/transactions/forms.py:278
#: apps/transactions/forms.py:279
msgid "From Amount"
msgstr "Quantia de origem"
#: apps/transactions/forms.py:283
#: apps/transactions/forms.py:284
msgid "To Amount"
msgstr "Quantia de destino"
#: apps/transactions/forms.py:398
#: apps/transactions/forms.py:399
#: templates/cotton/ui/quick_transactions_buttons.html:40
msgid "Transfer"
msgstr "Transferir"
#: apps/transactions/forms.py:610
#: apps/transactions/forms.py:611
msgid "Tag name"
msgstr "Nome da Tag"
#: apps/transactions/forms.py:642
#: apps/transactions/forms.py:643
msgid "Entity name"
msgstr "Nome da entidade"
#: apps/transactions/forms.py:674
#: apps/transactions/forms.py:675
msgid "Category name"
msgstr "Nome da Categoria"
#: apps/transactions/forms.py:676
#: apps/transactions/forms.py:677
msgid "Muted categories won't count towards your monthly total"
msgstr "As categorias silenciadas não serão contabilizadas em seu total mensal"
#: apps/transactions/forms.py:846
#: apps/transactions/forms.py:847
msgid "End date should be after the start date"
msgstr "Data final deve ser após data inicial"
@@ -1150,14 +1277,6 @@ msgstr "Apagado Em"
msgid "Transaction"
msgstr "Transação"
#: apps/transactions/models.py:256 templates/includes/navbar.html:57
#: templates/includes/navbar.html:104
#: templates/recurring_transactions/fragments/list_transactions.html:5
#: templates/recurring_transactions/fragments/table.html:37
#: templates/transactions/pages/transactions.html:5
msgid "Transactions"
msgstr "Transações"
#: apps/transactions/models.py:323 templates/tags/fragments/table.html:53
msgid "No tags"
msgstr "Nenhuma tag"
@@ -1215,12 +1334,6 @@ msgstr "Recorrência"
msgid "Installment Amount"
msgstr "Valor da Parcela"
#: apps/transactions/models.py:391 templates/includes/navbar.html:72
#: templates/installment_plans/fragments/list.html:5
#: templates/installment_plans/pages/index.html:4
msgid "Installment Plans"
msgstr "Parcelamentos"
#: apps/transactions/models.py:533
msgid "day(s)"
msgstr "dia(s)"
@@ -1258,12 +1371,6 @@ msgstr "Última data gerada"
msgid "Last Generated Reference Date"
msgstr "Última data de referência gerada"
#: apps/transactions/models.py:592 templates/includes/navbar.html:74
#: templates/recurring_transactions/fragments/list.html:5
#: templates/recurring_transactions/pages/index.html:4
msgid "Recurring Transactions"
msgstr "Transações Recorrentes"
#: apps/transactions/validators.py:8
#, python-format
msgid "%(value)s has too many decimal places. Maximum is 30."
@@ -1792,20 +1899,11 @@ msgstr "Buscar"
msgid "Select"
msgstr "Selecionar"
#: templates/cotton/transaction/item.html:56
msgid "DCA"
msgstr "CMP"
#: templates/cotton/transaction/item.html:137
#: templates/cotton/ui/transactions_action_bar.html:78
msgid "Duplicate"
msgstr "Duplicar"
#: templates/cotton/transaction/item.html:158
#: templates/cotton/ui/deleted_transactions_action_bar.html:47
msgid "Restore"
msgstr "Restaurar"
#: templates/cotton/ui/account_card.html:15
#: templates/cotton/ui/currency_card.html:10
msgid "projected income"
@@ -1909,26 +2007,6 @@ msgstr "Minímo"
msgid "Count"
msgstr "Contagem"
#: templates/cotton/ui/percentage_distribution.html:3
#: templates/cotton/ui/percentage_distribution.html:7
msgid "Projected Income"
msgstr "Renda Prevista"
#: templates/cotton/ui/percentage_distribution.html:10
#: templates/cotton/ui/percentage_distribution.html:14
msgid "Current Income"
msgstr "Renda Atual"
#: templates/cotton/ui/percentage_distribution.html:17
#: templates/cotton/ui/percentage_distribution.html:21
msgid "Projected Expenses"
msgstr "Despesas Previstas"
#: templates/cotton/ui/percentage_distribution.html:24
#: templates/cotton/ui/percentage_distribution.html:28
msgid "Current Expenses"
msgstr "Despesas Atuais"
#: templates/cotton/ui/quick_transactions_buttons.html:25
msgid "Installment"
msgstr "Parcelamento"
@@ -2130,12 +2208,6 @@ msgstr "Nenhuma taxa de câmbio"
msgid "Page navigation"
msgstr "Navegação por página"
#: templates/exchange_rates_services/fragments/list.html:6
#: templates/exchange_rates_services/pages/index.html:4
#: templates/includes/navbar.html:136
msgid "Automatic Exchange Rates"
msgstr "Taxas de Câmbio Automáticas"
#: templates/exchange_rates_services/fragments/list.html:21
msgid "Fetch all"
msgstr "Executar todos"
@@ -2164,6 +2236,10 @@ msgstr "contas"
msgid "No services configured"
msgstr "Nenhum serviço configurado"
#: templates/export_app/pages/index.html:4 templates/includes/navbar.html:136
msgid "Export and Restore"
msgstr "Exportar e Restaurar"
#: templates/import_app/fragments/profiles/add.html:6
msgid "Add new import profile"
msgstr "Adicionar novo perfil de importação"
@@ -2176,11 +2252,6 @@ msgstr "Uma mensagem do autor"
msgid "Edit import profile"
msgstr "Editar perfil de importação"
#: templates/import_app/fragments/profiles/list.html:5
#: templates/import_app/pages/profiles_index.html:4
msgid "Import Profiles"
msgstr "Perfis de Importação"
#: templates/import_app/fragments/profiles/list.html:17
msgid "New"
msgstr "Novo"
@@ -2307,20 +2378,15 @@ msgstr "Gerenciar"
msgid "Automation"
msgstr "Automação"
#: templates/includes/navbar.html:132 templates/rules/fragments/list.html:5
#: templates/rules/pages/index.html:4
msgid "Rules"
msgstr "Regras"
#: templates/includes/navbar.html:146
#: templates/includes/navbar.html:148
msgid "Only use this if you know what you're doing"
msgstr "Só use isso se você souber o que está fazendo"
#: templates/includes/navbar.html:147
#: templates/includes/navbar.html:149
msgid "Django Admin"
msgstr "Django Admin"
#: templates/includes/navbar.html:156
#: templates/includes/navbar.html:158
msgid "Calculator"
msgstr "Calculadora"
@@ -2353,44 +2419,89 @@ msgstr "Cancelar"
msgid "Confirm"
msgstr "Confirmar"
#: templates/insights/fragments/sankey.html:83
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr "Não há informação para mostrar"
#: templates/insights/fragments/category_explorer/index.html:14
msgid "Income/Expense by Account"
msgstr "Gasto/Despesa por Conta"
#: templates/insights/fragments/category_explorer/index.html:26
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"
#: templates/insights/fragments/sankey.html:86
#: templates/insights/fragments/sankey.html:96
msgid "Percentage"
msgstr "Porcentagem"
#: templates/insights/pages/index.html:33
#: templates/insights/pages/index.html:35
msgid "Month"
msgstr "Mês"
#: templates/insights/pages/index.html:36
#: templates/insights/pages/index.html:38
#: templates/yearly_overview/pages/overview_by_account.html:61
#: templates/yearly_overview/pages/overview_by_currency.html:63
msgid "Year"
msgstr "Ano"
#: templates/insights/pages/index.html:39
#: templates/insights/pages/index.html:43
msgid "Month Range"
msgstr "Intervalo de Mês"
#: templates/insights/pages/index.html:42
#: templates/insights/pages/index.html:48
msgid "Year Range"
msgstr "Intervalo de Ano"
#: templates/insights/pages/index.html:45
#: templates/insights/pages/index.html:53
msgid "Date Range"
msgstr "Intervalo de Data"
#: templates/insights/pages/index.html:74
#: templates/insights/pages/index.html:81
msgid "Account Flow"
msgstr "Fluxo de Conta"
#: templates/insights/pages/index.html:81
#: templates/insights/pages/index.html:88
msgid "Currency Flow"
msgstr "Fluxo de Moeda"
#: 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"
@@ -2460,17 +2571,6 @@ msgstr "Item"
msgid "No transactions this month"
msgstr "Nenhuma transação neste mês"
#: 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
#: templates/transactions/fragments/all_currency_summary.html:13
#: templates/transactions/fragments/summary.html:27
#: templates/transactions/fragments/summary.html:42
#: templates/yearly_overview/fragments/account_data.html:12
#: templates/yearly_overview/fragments/currency_data.html:12
msgid "No information to display"
msgstr "Não há informação para mostrar"
#: templates/monthly_overview/fragments/monthly_summary.html:6
msgid "Daily Spending Allowance"
msgstr "Gasto Diário"
@@ -2761,6 +2861,11 @@ msgstr "Mostrar valores"
msgid "Yearly Overview"
msgstr "Visão Anual"
#, fuzzy
#~| msgid "Installment Plans"
#~ msgid "Installment Planss"
#~ msgstr "Parcelamentos"
#, fuzzy
#~| msgid "Tags"
#~ msgid "No Tags"
@@ -2856,11 +2961,6 @@ msgstr "Visão Anual"
#~ msgid "Search Category"
#~ msgstr "Categoria"
#, fuzzy
#~| msgid "Category name"
#~ msgid "Category Operator"
#~ msgstr "Nome da Categoria"
#, fuzzy
#~| msgid "Search"
#~ msgid "Search Tags"

View File

@@ -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>

View File

@@ -1,7 +1,7 @@
{% load markdown %}
{% load i18n %}
<div class="transaction">
<div class="d-flex my-1 {% if transaction.type == "EX" %}expense{% else %}income{% endif %}">
<div class="transaction {% if transaction.type == "EX" %}expense{% else %}income{% endif %}">
<div class="d-flex my-1">
{% if not disable_selection %}
<label class="px-3 d-flex align-items-center justify-content-center">
<input class="form-check-input" type="checkbox" name="transactions" value="{{ transaction.id }}"
@@ -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"

View File

@@ -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>

View File

@@ -27,7 +27,7 @@
<ul class="dropdown-menu">
<li>
<div class="dropdown-item px-3 tw-cursor-pointer"
_="on click set <#transactions-list input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
_="on click set <#transactions-list .transaction:not([style*='display: none']) input[type='checkbox']/>'s checked to true then call me.blur() then trigger change">
<i class="fa-regular fa-square-check tw-text-green-400 me-3"></i>{% translate 'Select All' %}
</div>
</li>

View File

@@ -0,0 +1,13 @@
{% extends "extends/offcanvas.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block title %}{% translate 'Export' %}{% endblock %}
{% block body %}
<div class="container p-3">
<form method="post" action="{% url 'export_form' %}" id="export-form" class="show-loading px-1" _="on submit trigger hide_offcanvas" target="_blank">
{% crispy form %}
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends "extends/offcanvas.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block title %}{% translate 'Restore' %}{% endblock %}
{% block body %}
<div class="container p-3">
<form hx-post="{% url 'restore_form' %}"
hx-target="#generic-offcanvas"
id="restore-form"
enctype="multipart/form-data"
class="show-loading px-1">
{% crispy form %}
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,29 @@
{% extends "layouts/base.html" %}
{% load i18n %}
{% block title %}{% translate 'Export and Restore' %}{% endblock %}
{% block content %}
<div class="container">
<div class="row d-flex flex-row align-items-center justify-content-center my-5">
<div class="text-center w-auto mb-3">
<button class="btn btn-outline-success d-flex flex-column align-items-center justify-content-center p-3"
style="width: 100px; height: 100px;"
hx-get="{% url 'export_form' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-download mb-1"></i>
<span>{% trans 'Export' %}</span>
</button>
</div>
<div class="text-center w-auto mb-3">
<button class="btn btn-outline-primary d-flex flex-column align-items-center justify-content-center p-3"
style="width: 100px; height: 100px;"
hx-get="{% url 'restore_form' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-upload mb-1"></i>
<span>{% trans 'Restore' %}</span>
</button>
</div>
</div>
</div>
{% endblock %}

View File

@@ -94,7 +94,7 @@
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index' %}"
<a class="nav-link dropdown-toggle {% active_link views='tags_index||entities_index||categories_index||accounts_index||account_groups_index||currencies_index||exchange_rates_index||rules_index||import_profiles_index||automatic_exchange_rates_index||export_index' %}"
href="#" role="button"
data-bs-toggle="dropdown"
aria-expanded="false">
@@ -132,6 +132,8 @@
href="{% url 'rules_index' %}">{% translate 'Rules' %}</a></li>
<li><a class="dropdown-item {% active_link views='import_profiles_index' %}"
href="{% url 'import_profiles_index' %}">{% translate 'Import' %} <span class="badge text-bg-primary">beta</span></a></li>
<li><a class="dropdown-item {% active_link views='export_index' %}"
href="{% url 'export_index' %}">{% translate 'Export and Restore' %}</a></li>
<li><a class="dropdown-item {% active_link views='automatic_exchange_rates_index' %}"
href="{% url 'automatic_exchange_rates_index' %}">{% translate 'Automatic Exchange Rates' %}</a></li>
<li>

View File

@@ -0,0 +1,101 @@
{% load i18n %}
{% if account_data.labels %}
<div class="chart-container" style="position: relative; height:400px; width:100%"
_="init call setupAccountChart() end">
<canvas id="accountChart"></canvas>
</div>
<script>
// Get the data from your Django view (passed as JSON)
var accountData = {{ account_data|safe }};
function setupAccountChart() {
var chartOptions = {
indexAxis: 'y', // This makes the chart horizontal
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true, // Enable stacking on the x-axis
title: {
display: false,
},
},
y: {
stacked: true, // Enable stacking on the y-axis
title: {
display: false,
},
}
},
plugins: {
legend: {
display: false,
},
tooltip: {
callbacks: {
label: function (context) {
if (context.parsed.x !== null) {
return `${context.dataset.label}: ${new Intl.NumberFormat(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 30,
roundingMode: 'trunc'
}).format(Math.abs(context.parsed.x))}`;
}
return "";
},
}
}
}
};
new Chart(
document.getElementById('accountChart'),
{
type: 'bar',
data: {
labels: accountData.labels,
datasets: [
{
label: "{% trans 'Projected Expenses' %}",
data: accountData.datasets[3].data,
backgroundColor: '#f8717180', // Added transparency
stack: 'stack0'
},
{
label: "{% trans 'Current Expenses' %}",
data: accountData.datasets[1].data,
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'
},
]
},
options: {
...chartOptions,
plugins: {
...chartOptions.plugins,
title: {
display: false,
}
}
}
}
);
}
</script>
{% else %}
<c-msg.empty title="{% translate "No information to display" %}"></c-msg.empty>
{% endif %}

View File

@@ -0,0 +1,93 @@
{% load i18n %}
{% if currency_data.labels %}
<div class="chart-container" style="position: relative; height:400px; width:100%"
_="init call setupCurrencyChart() end">
<canvas id="currencyChart"></canvas>
</div>
<script>
// Get the data from your Django view (passed as JSON)
var currencyData = {{ currency_data|safe }};
function setupCurrencyChart() {
var chartOptions = {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true,
title: {
display: false,
},
},
y: {
stacked: true,
title: {
display: false,
},
}
},
plugins: {
legend: {
display: false,
},
tooltip: {
callbacks: {
label: function (context) {
if (context.parsed.x !== null) {
return `${context.dataset.label}: ${new Intl.NumberFormat(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 30,
roundingMode: 'trunc'
}).format(Math.abs(context.parsed.x))}`;
}
return "";
},
}
}
}
};
new Chart(
document.getElementById('currencyChart'),
{
type: 'bar',
data: {
labels: currencyData.labels,
datasets: [
{
label: "{% trans 'Projected Expenses' %}",
data: currencyData.datasets[3].data,
backgroundColor: '#f8717180', // Added transparency
stack: 'stack0'
},
{
label: "{% trans 'Current Expenses' %}",
data: currencyData.datasets[1].data,
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'
},
]
},
options: chartOptions
}
);
}
</script>
{% else %}
<c-msg.empty title="{% translate "No information to display" %}"></c-msg.empty>
{% endif %}

View File

@@ -0,0 +1,37 @@
{% load i18n %}
{% load crispy_forms_tags %}
<form _="install init_tom_select
on change trigger updated
init trigger updated" id="category-form">
{% crispy category_form %}
</form>
<div class="row row-cols-1 row-cols-lg-2 gx-3 gy-3">
<div class="col">
<div class="card h-100">
<div class="card-header">
{% trans "Income/Expense by Account" %}
</div>
<div class="card-body">
<div id="account-card" class="show-loading" hx-get="{% url 'category_sum_by_account' %}"
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
</div>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-header">
{% trans "Income/Expense by Currency" %}
</div>
<div class="card-body">
<div id="currency-card" class="show-loading" hx-get="{% url 'category_sum_by_currency' %}"
hx-trigger="updated from:window" hx-include="#category-form, #picker-form, #picker-type">
</div>
</div>
</div>
</div>
</div>

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

@@ -1,15 +1,17 @@
{% load i18n %}
{% if type == 'account' %}
<div class="show-loading" hx-get="{% url 'insights_sankey_by_account' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
<div class="show-loading" hx-get="{% url 'insights_sankey_by_account' %}" hx-trigger="updated from:window"
hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
{% else %}
<div class="show-loading" hx-get="{% url 'insights_sankey_by_currency' %}" hx-trigger="updated from:window" hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
<div class="show-loading" hx-get="{% url 'insights_sankey_by_currency' %}" hx-trigger="updated from:window"
hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
{% endif %}
<div class="chart-container position-relative tw-min-h-[60vh] tw-max-h-[60vh] tw-h-full tw-w-full"
id="sankeyContainer"
_="init call setupSankeyChart() end">
<canvas id="sankeyChart"></canvas>
</div>
<div class="chart-container position-relative tw-min-h-[85vh] tw-max-h-[85vh] tw-h-full tw-w-full"
id="sankeyContainer"
_="init call setupSankeyChart() end">
<canvas id="sankeyChart"></canvas>
</div>
</div>
<script>
@@ -61,7 +63,12 @@
colorMode: 'gradient',
alpha: 0.5,
size: 'max',
color: "white"
color: "white",
nodePadding: 30,
priority: data.nodes.reduce((acc, node) => {
acc[node.id] = node.priority;
return acc;
}, {}),
}]
};
@@ -71,6 +78,9 @@
options: {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: 20
},
plugins: {
tooltip: {
callbacks: {
@@ -98,23 +108,10 @@
}
};
// Destroy existing chart if it exists
const existingChart = Chart.getChart(chartId);
if (existingChart) {
existingChart.destroy();
}
// Create new chart
var chart = new Chart(
new Chart(
document.getElementById(chartId),
config
);
window.addEventListener('resize', () => {
chart.resize();
});
document.addEventListener('fullscreenchange', function () {
console.log('oi');
chart.resize();
});
}
</script>

View File

@@ -4,11 +4,12 @@
{% block content %}
<div class="container-fluid">
<div class="row my-3">
<div class="row my-3 h-100">
<div class="col-lg-2 col-md-3 mb-3 mb-md-0">
<div class="">
<div class="mb-2 w-100 d-lg-inline-flex d-grid gap-2 flex-wrap justify-content-lg-center" role="group"
_="on change
<div class="position-sticky tw-top-3">
<div class="">
<div class="mb-2 w-100 d-lg-inline-flex d-grid gap-2 flex-wrap justify-content-lg-center" role="group"
_="on change
set type to event.target.value
add .tw-hidden to <#picker-form > div:not(.tw-hidden)/>
@@ -28,58 +29,85 @@
remove .tw-hidden from #date-range-form
end
then trigger updated"
id="picker-type">
<input type="radio" class="btn-check" name="type" value="month" id="monthradio" autocomplete="off" checked>
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="monthradio">{% translate 'Month' %}</label>
id="picker-type">
<input type="radio" class="btn-check" name="type" value="month" id="monthradio" autocomplete="off"
checked>
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="monthradio">{% translate 'Month' %}</label>
<input type="radio" class="btn-check" name="type" value="year" id="yearradio" autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="yearradio">{% translate 'Year' %}</label>
<input type="radio" class="btn-check" name="type" value="year" id="yearradio" autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="yearradio">{% translate 'Year' %}</label>
<input type="radio" class="btn-check" name="type" value="month-range" id="monthrangeradio" autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="monthrangeradio">{% translate 'Month Range' %}</label>
<input type="radio" class="btn-check" name="type" value="month-range" id="monthrangeradio"
autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1"
for="monthrangeradio">{% translate 'Month Range' %}</label>
<input type="radio" class="btn-check" name="type" value="year-range" id="yearrangeradio" autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="yearrangeradio">{% translate 'Year Range' %}</label>
<input type="radio" class="btn-check" name="type" value="year-range" id="yearrangeradio"
autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1"
for="yearrangeradio">{% translate 'Year Range' %}</label>
<input type="radio" class="btn-check" name="type" value="date-range" id="daterangeradio" autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1" for="daterangeradio">{% translate 'Date Range' %}</label>
</div>
<form id="picker-form"
_="install init_datepicker
<input type="radio" class="btn-check" name="type" value="date-range" id="daterangeradio"
autocomplete="off">
<label class="btn btn-sm btn-outline-primary flex-grow-1"
for="daterangeradio">{% translate 'Date Range' %}</label>
</div>
<form id="picker-form"
_="install init_datepicker
on change trigger updated">
<div id="month-form" class="">
{% crispy month_form %}
</div>
<div id="year-form" class="tw-hidden">
{% crispy year_form %}
</div>
<div id="month-range-form" class="tw-hidden">
{% crispy month_range_form %}
</div>
<div id="year-range-form" class="tw-hidden">
{% crispy year_range_form %}
</div>
<div id="date-range-form" class="tw-hidden">
{% crispy date_range_form %}
</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"
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
hx-get="{% url 'insights_sankey_by_account' %}" hx-include="#picker-form, #picker-type"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Account Flow' %}
</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_sankey_by_currency' %}"
hx-include="#picker-form, #picker-type"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Currency Flow' %}
</button>
<div id="month-form" class="">
{% crispy month_form %}
</div>
<div id="year-form" class="tw-hidden">
{% crispy year_form %}
</div>
<div id="month-range-form" class="tw-hidden">
{% crispy month_range_form %}
</div>
<div id="year-range-form" class="tw-hidden">
{% crispy year_range_form %}
</div>
<div id="date-range-form" class="tw-hidden">
{% crispy date_range_form %}
</div>
</form>
</div>
<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"
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
hx-get="{% url 'insights_sankey_by_account' %}" hx-include="#picker-form, #picker-type"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Account Flow' %}
</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_sankey_by_currency' %}"
hx-include="#picker-form, #picker-type"
hx-indicator="#tab-content"
hx-target="#tab-content">{% trans 'Currency Flow' %}
</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 'category_explorer_index' %}"
hx-include="#picker-form, #picker-type"
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>
<div class="col-md-9 col-lg-10">

View File

@@ -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 %}

View File

@@ -40,6 +40,7 @@ window.DatePicker = function createDynamicDatePicker(element) {
dateFormat: element.dataset.dateFormat,
timeFormat: element.dataset.timeFormat,
timepicker: element.dataset.timepicker === 'true',
toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language],
@@ -96,7 +97,6 @@ window.DatePicker = function createDynamicDatePicker(element) {
return new AirDatepicker(element, opts);
};
window.MonthYearPicker = function createDynamicDatePicker(element) {
let todayButton = {
content: element.dataset.nowButtonTxt,
@@ -114,6 +114,7 @@ window.MonthYearPicker = function createDynamicDatePicker(element) {
view: 'months',
minView: 'months',
dateFormat: 'MMMM yyyy',
toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language],
@@ -163,8 +164,8 @@ window.MonthYearPicker = function createDynamicDatePicker(element) {
let opts = {...baseOpts, ...positionConfig};
if (element.dataset.value) {
opts["selectedDates"] = [new Date(element.dataset.value + "T00:00:00")];
opts["startDate"] = [new Date(element.dataset.value + "T00:00:00")];
opts["selectedDates"] = [new Date(element.dataset.value + "T00:00:00")];
opts["startDate"] = [new Date(element.dataset.value + "T00:00:00")];
}
return new AirDatepicker(element, opts);
};
@@ -186,6 +187,7 @@ window.YearPicker = function createDynamicDatePicker(element) {
view: 'years',
minView: 'years',
dateFormat: 'yyyy',
toggleSelected: element.dataset.toggleSelected === 'true',
autoClose: element.dataset.autoClose === 'true',
buttons: element.dataset.clearButton === 'true' ? ['clear', todayButton] : [todayButton],
locale: locales[element.dataset.language],
@@ -235,8 +237,8 @@ window.YearPicker = function createDynamicDatePicker(element) {
let opts = {...baseOpts, ...positionConfig};
if (element.dataset.value) {
opts["selectedDates"] = [new Date(element.dataset.value + "T00:00:00")];
opts["startDate"] = [new Date(element.dataset.value + "T00:00:00")];
opts["selectedDates"] = [new Date(element.dataset.value + "T00:00:00")];
opts["startDate"] = [new Date(element.dataset.value + "T00:00:00")];
}
return new AirDatepicker(element, opts);
};

View File

@@ -12,6 +12,7 @@ django-cotton~=1.2.1
django-pwa~=2.0.1
djangorestframework~=3.15.2
drf-spectacular~=0.27.2
django-import-export~=4.3.5
gunicorn==22.0.0
whitenoise[brotli]==6.6.0