Merge pull request #140

automatic exchange rates
This commit is contained in:
Herculino Trotta
2025-02-07 11:49:25 -03:00
committed by GitHub
9 changed files with 455 additions and 187 deletions

View File

@@ -17,7 +17,8 @@ class ExchangeRateServiceAdmin(admin.ModelAdmin):
"name", "name",
"service_type", "service_type",
"is_active", "is_active",
"fetch_interval_hours", "interval_type",
"fetch_interval",
"last_fetch", "last_fetch",
] ]
list_filter = ["is_active", "service_type"] list_filter = ["is_active", "service_type"]

View File

@@ -23,17 +23,67 @@ PROVIDER_MAPPING = {
class ExchangeRateFetcher: class ExchangeRateFetcher:
def _should_fetch_at_hour(service: ExchangeRateService, current_hour: int) -> bool:
"""Check if service should fetch rates at given hour based on interval type."""
try:
if service.interval_type == ExchangeRateService.IntervalType.NOT_ON:
blocked_hours = ExchangeRateService._parse_hour_ranges(
service.fetch_interval
)
should_fetch = current_hour not in blocked_hours
logger.debug(
f"NOT_ON check for {service.name}: "
f"current_hour={current_hour}, "
f"blocked_hours={blocked_hours}, "
f"should_fetch={should_fetch}"
)
return should_fetch
if service.interval_type == ExchangeRateService.IntervalType.ON:
allowed_hours = ExchangeRateService._parse_hour_ranges(
service.fetch_interval
)
return current_hour in allowed_hours
if service.interval_type == ExchangeRateService.IntervalType.EVERY:
try:
interval_hours = int(service.fetch_interval)
if service.last_fetch is None:
return True
hours_since_last = (
timezone.now() - service.last_fetch
).total_seconds() / 3600
should_fetch = hours_since_last >= interval_hours
logger.debug(
f"EVERY check for {service.name}: "
f"hours_since_last={hours_since_last:.1f}, "
f"interval={interval_hours}, "
f"should_fetch={should_fetch}"
)
return should_fetch
except ValueError:
logger.error(
f"Invalid EVERY interval format for {service.name}: "
f"expected single number, got '{service.fetch_interval}'"
)
return False
return False
except ValueError as e:
logger.error(f"Error parsing fetch_interval for {service.name}: {e}")
return False
@staticmethod @staticmethod
def fetch_due_rates(force: bool = False) -> None: def fetch_due_rates(force: bool = False) -> None:
""" """
Fetch rates for all services that are due for update. Fetch rates for all services that are due for update.
Args: Args:
force (bool): If True, fetches all active services regardless of their last fetch time. force (bool): If True, fetches all active services regardless of their schedule.
If False, only fetches services that are due according to their interval.
""" """
services = ExchangeRateService.objects.filter(is_active=True) services = ExchangeRateService.objects.filter(is_active=True)
current_time = timezone.now().replace(minute=0, second=0, microsecond=0) current_time = timezone.now().astimezone()
current_hour = current_time.hour
for service in services: for service in services:
try: try:
@@ -42,29 +92,21 @@ class ExchangeRateFetcher:
ExchangeRateFetcher._fetch_service_rates(service) ExchangeRateFetcher._fetch_service_rates(service)
continue continue
# Regular schedule-based fetching # Check if service should fetch based on interval type
if service.last_fetch is None: if ExchangeRateFetcher._should_fetch_at_hour(service, current_hour):
logger.info(f"First fetch for service: {service.name}")
ExchangeRateFetcher._fetch_service_rates(service)
continue
# Calculate when the next fetch should occur
next_fetch_due = (
service.last_fetch + timedelta(hours=service.fetch_interval_hours)
).replace(minute=0, second=0, microsecond=0)
# Check if it's time for the next fetch
if current_time >= next_fetch_due:
logger.info( logger.info(
f"Fetching rates for {service.name}. " f"Fetching rates for {service.name}. "
f"Last fetch: {service.last_fetch}, " f"Last fetch: {service.last_fetch}, "
f"Interval: {service.fetch_interval_hours}h" f"Interval type: {service.interval_type}, "
f"Current hour: {current_hour}"
) )
ExchangeRateFetcher._fetch_service_rates(service) ExchangeRateFetcher._fetch_service_rates(service)
else: else:
logger.debug( logger.debug(
f"Skipping {service.name}. " f"Skipping {service.name}. "
f"Next fetch due at: {next_fetch_due}" f"Current hour: {current_hour}, "
f"Interval type: {service.interval_type}, "
f"Fetch interval: {service.fetch_interval}"
) )
except Exception as e: except Exception as e:

View File

@@ -1,7 +1,7 @@
from crispy_bootstrap5.bootstrap5 import Switch from crispy_bootstrap5.bootstrap5 import Switch
from crispy_forms.bootstrap import FormActions from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout from crispy_forms.layout import Layout, Row, Column
from django import forms from django import forms
from django.forms import CharField from django.forms import CharField
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -110,7 +110,8 @@ class ExchangeRateServiceForm(forms.ModelForm):
"service_type", "service_type",
"is_active", "is_active",
"api_key", "api_key",
"fetch_interval_hours", "interval_type",
"fetch_interval",
"target_currencies", "target_currencies",
"target_accounts", "target_accounts",
] ]
@@ -126,7 +127,10 @@ class ExchangeRateServiceForm(forms.ModelForm):
"service_type", "service_type",
Switch("is_active"), Switch("is_active"),
"api_key", "api_key",
"fetch_interval_hours", Row(
Column("interval_type", css_class="form-group col-md-6"),
Column("fetch_interval", css_class="form-group col-md-6"),
),
"target_currencies", "target_currencies",
"target_accounts", "target_accounts",
) )

View File

@@ -0,0 +1,32 @@
# Generated by Django 5.1.5 on 2025-02-07 02:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('currencies', '0010_alter_currency_code'),
]
operations = [
migrations.RemoveField(
model_name='exchangerateservice',
name='fetch_interval_hours',
),
migrations.AddField(
model_name='exchangerateservice',
name='fetch_interval',
field=models.CharField(default='24', max_length=1000, verbose_name='Interval'),
),
migrations.AddField(
model_name='exchangerateservice',
name='interval_type',
field=models.CharField(choices=[('on', 'On'), ('every', 'Every X hours'), ('not_on', 'Not on')], default='every', max_length=255, verbose_name='Interval Type'),
),
migrations.AlterField(
model_name='exchangerateservice',
name='service_type',
field=models.CharField(choices=[('synth_finance', 'Synth Finance'), ('coingecko_free', 'CoinGecko (Demo/Free)'), ('coingecko_pro', 'CoinGecko (Pro)')], max_length=255, verbose_name='Service Type'),
),
]

View File

@@ -1,4 +1,5 @@
import logging import logging
from typing import Set
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
@@ -94,6 +95,11 @@ class ExchangeRateService(models.Model):
COINGECKO_FREE = "coingecko_free", "CoinGecko (Demo/Free)" COINGECKO_FREE = "coingecko_free", "CoinGecko (Demo/Free)"
COINGECKO_PRO = "coingecko_pro", "CoinGecko (Pro)" COINGECKO_PRO = "coingecko_pro", "CoinGecko (Pro)"
class IntervalType(models.TextChoices):
ON = "on", _("On")
EVERY = "every", _("Every X hours")
NOT_ON = "not_on", _("Not on")
name = models.CharField(max_length=255, unique=True, verbose_name=_("Service Name")) name = models.CharField(max_length=255, unique=True, verbose_name=_("Service Name"))
service_type = models.CharField( service_type = models.CharField(
max_length=255, choices=ServiceType.choices, verbose_name=_("Service Type") max_length=255, choices=ServiceType.choices, verbose_name=_("Service Type")
@@ -106,10 +112,14 @@ class ExchangeRateService(models.Model):
verbose_name=_("API Key"), verbose_name=_("API Key"),
help_text=_("API key for the service (if required)"), help_text=_("API key for the service (if required)"),
) )
fetch_interval_hours = models.PositiveIntegerField( interval_type = models.CharField(
default=24, max_length=255,
validators=[MinValueValidator(1)], choices=IntervalType.choices,
verbose_name=_("Fetch Interval (hours)"), verbose_name=_("Interval Type"),
default=IntervalType.EVERY,
)
fetch_interval = models.CharField(
max_length=1000, verbose_name=_("Interval"), default="24"
) )
last_fetch = models.DateTimeField( last_fetch = models.DateTimeField(
null=True, blank=True, verbose_name=_("Last Successful Fetch") null=True, blank=True, verbose_name=_("Last Successful Fetch")
@@ -148,3 +158,82 @@ class ExchangeRateService(models.Model):
provider_class = PROVIDER_MAPPING[self.service_type] provider_class = PROVIDER_MAPPING[self.service_type]
return provider_class(self.api_key) return provider_class(self.api_key)
@staticmethod
def _parse_hour_ranges(interval_str: str) -> Set[int]:
"""
Parse hour ranges and individual hours from string.
Valid formats:
- Single hours: "1,5,9"
- Ranges: "1-5"
- Mixed: "1-5,8,10-12"
Returns set of hours.
"""
hours = set()
for part in interval_str.strip().split(","):
part = part.strip()
if "-" in part:
start, end = part.split("-")
start, end = int(start), int(end)
if not (0 <= start <= 23 and 0 <= end <= 23):
raise ValueError("Hours must be between 0 and 23")
if start > end:
raise ValueError(f"Invalid range: {start}-{end}")
hours.update(range(start, end + 1))
else:
hour = int(part)
if not 0 <= hour <= 23:
raise ValueError("Hours must be between 0 and 23")
hours.add(hour)
return hours
def clean(self):
super().clean()
try:
if self.interval_type == self.IntervalType.EVERY:
if not self.fetch_interval.isdigit():
raise ValidationError(
{
"fetch_interval": _(
"'Every X hours' interval type requires a positive integer."
)
}
)
hours = int(self.fetch_interval)
if hours < 0 or hours > 23:
raise ValidationError(
{
"fetch_interval": _(
"'Every X hours' interval must be between 0 and 23."
)
}
)
else:
try:
# Parse and validate hour ranges
hours = self._parse_hour_ranges(self.fetch_interval)
# Store in normalized format (optional)
self.fetch_interval = ",".join(str(h) for h in sorted(hours))
except ValueError as e:
raise ValidationError(
{
"fetch_interval": _(
"Invalid hour format. Use comma-separated hours (0-23) "
"and/or ranges (e.g., '1-5,8,10-12')."
)
}
)
except ValidationError:
raise
except Exception as e:
raise ValidationError(
{
"fetch_interval": _(
"Invalid format. Please check the requirements for your selected interval type."
)
}
)

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-04 03:20+0000\n" "POT-Creation-Date: 2025-02-07 11:45-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,7 +24,7 @@ msgstr ""
#: apps/accounts/forms.py:40 apps/accounts/forms.py:96 #: apps/accounts/forms.py:40 apps/accounts/forms.py:96
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91 #: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:138 apps/dca/forms.py:41 apps/dca/forms.py:93 #: apps/currencies/forms.py:142 apps/dca/forms.py:41 apps/dca/forms.py:93
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87 #: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/transactions/forms.py:190 apps/transactions/forms.py:257 #: apps/transactions/forms.py:190 apps/transactions/forms.py:257
#: apps/transactions/forms.py:581 apps/transactions/forms.py:624 #: apps/transactions/forms.py:581 apps/transactions/forms.py:624
@@ -35,7 +35,7 @@ msgstr ""
#: apps/accounts/forms.py:48 apps/accounts/forms.py:104 #: apps/accounts/forms.py:48 apps/accounts/forms.py:104
#: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61 #: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61
#: apps/currencies/forms.py:99 apps/currencies/forms.py:146 #: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42 #: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174 #: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174
#: apps/transactions/forms.py:199 apps/transactions/forms.py:589 #: apps/transactions/forms.py:199 apps/transactions/forms.py:589
@@ -113,17 +113,17 @@ msgstr ""
msgid "Account Groups" msgid "Account Groups"
msgstr "" msgstr ""
#: apps/accounts/models.py:31 apps/currencies/models.py:38 #: apps/accounts/models.py:31 apps/currencies/models.py:39
#: templates/accounts/fragments/list.html:27 #: templates/accounts/fragments/list.html:27
msgid "Currency" msgid "Currency"
msgstr "" msgstr ""
#: apps/accounts/models.py:37 apps/currencies/models.py:26 #: apps/accounts/models.py:37 apps/currencies/models.py:27
#: templates/accounts/fragments/list.html:28 #: templates/accounts/fragments/list.html:28
msgid "Exchange Currency" msgid "Exchange Currency"
msgstr "" msgstr ""
#: apps/accounts/models.py:42 apps/currencies/models.py:31 #: apps/accounts/models.py:42 apps/currencies/models.py:32
msgid "Default currency for exchange calculations" msgid "Default currency for exchange calculations"
msgstr "" msgstr ""
@@ -348,11 +348,11 @@ msgstr ""
msgid "No results..." msgid "No results..."
msgstr "" msgstr ""
#: apps/currencies/forms.py:17 apps/currencies/models.py:21 #: apps/currencies/forms.py:17 apps/currencies/models.py:22
msgid "Prefix" msgid "Prefix"
msgstr "" msgstr ""
#: apps/currencies/forms.py:18 apps/currencies/models.py:22 #: apps/currencies/forms.py:18 apps/currencies/models.py:23
msgid "Suffix" msgid "Suffix"
msgstr "" msgstr ""
@@ -365,19 +365,19 @@ msgstr ""
msgid "Date" msgid "Date"
msgstr "" msgstr ""
#: apps/currencies/models.py:13 #: apps/currencies/models.py:14
msgid "Currency Code" msgid "Currency Code"
msgstr "" msgstr ""
#: apps/currencies/models.py:15 #: apps/currencies/models.py:16
msgid "Currency Name" msgid "Currency Name"
msgstr "" msgstr ""
#: apps/currencies/models.py:19 #: apps/currencies/models.py:20
msgid "Decimal Places" msgid "Decimal Places"
msgstr "" msgstr ""
#: apps/currencies/models.py:39 apps/transactions/filters.py:60 #: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5 #: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 #: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119
#: templates/includes/navbar.html:121 #: templates/includes/navbar.html:121
@@ -387,45 +387,57 @@ msgstr ""
msgid "Currencies" msgid "Currencies"
msgstr "" msgstr ""
#: apps/currencies/models.py:47 #: apps/currencies/models.py:48
msgid "Currency cannot have itself as exchange currency." msgid "Currency cannot have itself as exchange currency."
msgstr "" msgstr ""
#: apps/currencies/models.py:58 #: apps/currencies/models.py:59
msgid "From Currency" msgid "From Currency"
msgstr "" msgstr ""
#: apps/currencies/models.py:64 #: apps/currencies/models.py:65
msgid "To Currency" msgid "To Currency"
msgstr "" msgstr ""
#: apps/currencies/models.py:67 apps/currencies/models.py:72 #: apps/currencies/models.py:68 apps/currencies/models.py:73
msgid "Exchange Rate" msgid "Exchange Rate"
msgstr "" msgstr ""
#: apps/currencies/models.py:69 #: apps/currencies/models.py:70
msgid "Date and Time" msgid "Date and Time"
msgstr "" msgstr ""
#: apps/currencies/models.py:73 templates/exchange_rates/fragments/list.html:6 #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4 #: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:123 #: templates/includes/navbar.html:123
msgid "Exchange Rates" msgid "Exchange Rates"
msgstr "" msgstr ""
#: apps/currencies/models.py:85 #: apps/currencies/models.py:86
msgid "From and To currencies cannot be the same." msgid "From and To currencies cannot be the same."
msgstr "" msgstr ""
#: apps/currencies/models.py:97 #: apps/currencies/models.py:99
msgid "On"
msgstr ""
#: apps/currencies/models.py:100
msgid "Every X hours"
msgstr ""
#: apps/currencies/models.py:101
msgid "Not on"
msgstr ""
#: apps/currencies/models.py:103
msgid "Service Name" msgid "Service Name"
msgstr "" msgstr ""
#: apps/currencies/models.py:99 #: apps/currencies/models.py:105
msgid "Service Type" msgid "Service Type"
msgstr "" msgstr ""
#: apps/currencies/models.py:101 apps/transactions/models.py:71 #: apps/currencies/models.py:107 apps/transactions/models.py:71
#: apps/transactions/models.py:90 apps/transactions/models.py:109 #: apps/transactions/models.py:90 apps/transactions/models.py:109
#: templates/categories/fragments/list.html:21 #: templates/categories/fragments/list.html:21
#: templates/entities/fragments/list.html:21 #: templates/entities/fragments/list.html:21
@@ -434,50 +446,74 @@ msgstr ""
msgid "Active" msgid "Active"
msgstr "" msgstr ""
#: apps/currencies/models.py:106 #: apps/currencies/models.py:112
msgid "API Key" msgid "API Key"
msgstr "" msgstr ""
#: apps/currencies/models.py:107 #: apps/currencies/models.py:113
msgid "API key for the service (if required)" msgid "API key for the service (if required)"
msgstr "" msgstr ""
#: apps/currencies/models.py:112 #: apps/currencies/models.py:118
msgid "Fetch Interval (hours)" msgid "Interval Type"
msgstr ""
#: apps/currencies/models.py:115
msgid "Last Successful Fetch"
msgstr ""
#: apps/currencies/models.py:120
msgid "Target Currencies"
msgstr "" msgstr ""
#: apps/currencies/models.py:122 #: apps/currencies/models.py:122
msgid "Interval"
msgstr ""
#: apps/currencies/models.py:125
msgid "Last Successful Fetch"
msgstr ""
#: apps/currencies/models.py:130
msgid "Target Currencies"
msgstr ""
#: apps/currencies/models.py:132
msgid "" msgid ""
"Select currencies to fetch exchange rates for. Rates will be fetched for " "Select currencies to fetch exchange rates for. Rates will be fetched for "
"each currency against their set exchange currency." "each currency against their set exchange currency."
msgstr "" msgstr ""
#: apps/currencies/models.py:130 #: apps/currencies/models.py:140
msgid "Target Accounts" msgid "Target Accounts"
msgstr "" msgstr ""
#: apps/currencies/models.py:132 #: apps/currencies/models.py:142
msgid "" msgid ""
"Select accounts to fetch exchange rates for. Rates will be fetched for each " "Select accounts to fetch exchange rates for. Rates will be fetched for each "
"account's currency against their set exchange currency." "account's currency against their set exchange currency."
msgstr "" msgstr ""
#: apps/currencies/models.py:139 #: apps/currencies/models.py:149
msgid "Exchange Rate Service" msgid "Exchange Rate Service"
msgstr "" msgstr ""
#: apps/currencies/models.py:140 #: apps/currencies/models.py:150
msgid "Exchange Rate Services" msgid "Exchange Rate Services"
msgstr "" msgstr ""
#: apps/currencies/models.py:202
msgid "'Every X hours' interval type requires a positive integer."
msgstr ""
#: apps/currencies/models.py:211
msgid "'Every X hours' interval must be between 0 and 23."
msgstr ""
#: apps/currencies/models.py:225
msgid ""
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
"'1-5,8,10-12')."
msgstr ""
#: apps/currencies/models.py:236
msgid ""
"Invalid format. Please check the requirements for your selected interval "
"type."
msgstr ""
#: apps/currencies/views/currencies.py:42 #: apps/currencies/views/currencies.py:42
msgid "Currency added successfully" msgid "Currency added successfully"
msgstr "" msgstr ""
@@ -1335,7 +1371,7 @@ msgstr ""
#: templates/dca/fragments/strategy/details.html:63 #: templates/dca/fragments/strategy/details.html:63
#: templates/entities/fragments/table.html:23 #: templates/entities/fragments/table.html:23
#: templates/exchange_rates/fragments/table.html:19 #: templates/exchange_rates/fragments/table.html:19
#: templates/exchange_rates_services/fragments/list.html:43 #: templates/exchange_rates_services/fragments/list.html:42
#: templates/exchange_rates_services/fragments/table.html:19 #: templates/exchange_rates_services/fragments/table.html:19
#: templates/import_app/fragments/profiles/list.html:44 #: templates/import_app/fragments/profiles/list.html:44
#: templates/installment_plans/fragments/table.html:23 #: templates/installment_plans/fragments/table.html:23
@@ -1355,7 +1391,7 @@ msgstr ""
#: templates/dca/fragments/strategy/list.html:34 #: templates/dca/fragments/strategy/list.html:34
#: templates/entities/fragments/table.html:28 #: templates/entities/fragments/table.html:28
#: templates/exchange_rates/fragments/table.html:23 #: templates/exchange_rates/fragments/table.html:23
#: templates/exchange_rates_services/fragments/list.html:47 #: templates/exchange_rates_services/fragments/list.html:46
#: templates/exchange_rates_services/fragments/table.html:23 #: templates/exchange_rates_services/fragments/table.html:23
#: templates/import_app/fragments/profiles/list.html:48 #: templates/import_app/fragments/profiles/list.html:48
#: templates/installment_plans/fragments/table.html:27 #: templates/installment_plans/fragments/table.html:27
@@ -1378,7 +1414,7 @@ msgstr ""
#: templates/dca/fragments/strategy/list.html:42 #: templates/dca/fragments/strategy/list.html:42
#: templates/entities/fragments/table.html:36 #: templates/entities/fragments/table.html:36
#: templates/exchange_rates/fragments/table.html:31 #: templates/exchange_rates/fragments/table.html:31
#: templates/exchange_rates_services/fragments/list.html:54 #: templates/exchange_rates_services/fragments/list.html:53
#: templates/exchange_rates_services/fragments/table.html:31 #: templates/exchange_rates_services/fragments/table.html:31
#: templates/import_app/fragments/profiles/list.html:69 #: templates/import_app/fragments/profiles/list.html:69
#: templates/import_app/fragments/runs/list.html:102 #: templates/import_app/fragments/runs/list.html:102
@@ -1403,7 +1439,7 @@ msgstr ""
#: templates/dca/fragments/strategy/list.html:46 #: templates/dca/fragments/strategy/list.html:46
#: templates/entities/fragments/table.html:40 #: templates/entities/fragments/table.html:40
#: templates/exchange_rates/fragments/table.html:36 #: templates/exchange_rates/fragments/table.html:36
#: templates/exchange_rates_services/fragments/list.html:58 #: templates/exchange_rates_services/fragments/list.html:57
#: templates/exchange_rates_services/fragments/table.html:36 #: templates/exchange_rates_services/fragments/table.html:36
#: templates/import_app/fragments/profiles/list.html:73 #: templates/import_app/fragments/profiles/list.html:73
#: templates/import_app/fragments/runs/list.html:106 #: templates/import_app/fragments/runs/list.html:106
@@ -1431,7 +1467,7 @@ msgstr ""
#: templates/dca/fragments/strategy/list.html:47 #: templates/dca/fragments/strategy/list.html:47
#: templates/entities/fragments/table.html:41 #: templates/entities/fragments/table.html:41
#: templates/exchange_rates/fragments/table.html:37 #: templates/exchange_rates/fragments/table.html:37
#: templates/exchange_rates_services/fragments/list.html:59 #: templates/exchange_rates_services/fragments/list.html:58
#: templates/exchange_rates_services/fragments/table.html:37 #: templates/exchange_rates_services/fragments/table.html:37
#: templates/import_app/fragments/profiles/list.html:74 #: templates/import_app/fragments/profiles/list.html:74
#: templates/rules/fragments/list.html:49 #: templates/rules/fragments/list.html:49
@@ -1450,7 +1486,7 @@ msgstr ""
#: templates/dca/fragments/strategy/list.html:48 #: templates/dca/fragments/strategy/list.html:48
#: templates/entities/fragments/table.html:42 #: templates/entities/fragments/table.html:42
#: templates/exchange_rates/fragments/table.html:38 #: templates/exchange_rates/fragments/table.html:38
#: templates/exchange_rates_services/fragments/list.html:60 #: templates/exchange_rates_services/fragments/list.html:59
#: templates/exchange_rates_services/fragments/table.html:38 #: templates/exchange_rates_services/fragments/table.html:38
#: templates/import_app/fragments/profiles/list.html:75 #: templates/import_app/fragments/profiles/list.html:75
#: templates/import_app/fragments/runs/list.html:108 #: templates/import_app/fragments/runs/list.html:108
@@ -1924,26 +1960,18 @@ msgid "Targeting"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:35 #: templates/exchange_rates_services/fragments/list.html:35
msgid "Fetch every"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:36
msgid "Last fetch" msgid "Last fetch"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
msgid "currencies" msgid "currencies"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
msgid "accounts" msgid "accounts"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:69 #: templates/exchange_rates_services/fragments/list.html:75
msgid "hours"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:77
msgid "No services configured" msgid "No services configured"
msgstr "" msgstr ""

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-04 03:20+0000\n" "POT-Creation-Date: 2025-02-07 11:45-0300\n"
"PO-Revision-Date: 2025-01-29 06:12+0100\n" "PO-Revision-Date: 2025-01-29 06:12+0100\n"
"Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n" "Last-Translator: Dimitri Decrock <dimitri@fam-decrock.eu>\n"
"Language-Team: \n" "Language-Team: \n"
@@ -25,7 +25,7 @@ msgstr "Groepsnaam"
#: apps/accounts/forms.py:40 apps/accounts/forms.py:96 #: apps/accounts/forms.py:40 apps/accounts/forms.py:96
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91 #: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:138 apps/dca/forms.py:41 apps/dca/forms.py:93 #: apps/currencies/forms.py:142 apps/dca/forms.py:41 apps/dca/forms.py:93
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87 #: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/transactions/forms.py:190 apps/transactions/forms.py:257 #: apps/transactions/forms.py:190 apps/transactions/forms.py:257
#: apps/transactions/forms.py:581 apps/transactions/forms.py:624 #: apps/transactions/forms.py:581 apps/transactions/forms.py:624
@@ -36,7 +36,7 @@ msgstr "Bijwerken"
#: apps/accounts/forms.py:48 apps/accounts/forms.py:104 #: apps/accounts/forms.py:48 apps/accounts/forms.py:104
#: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61 #: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61
#: apps/currencies/forms.py:99 apps/currencies/forms.py:146 #: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42 #: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174 #: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174
#: apps/transactions/forms.py:199 apps/transactions/forms.py:589 #: apps/transactions/forms.py:199 apps/transactions/forms.py:589
@@ -114,17 +114,17 @@ msgstr "Accountgroep"
msgid "Account Groups" msgid "Account Groups"
msgstr "Accountgroepen" msgstr "Accountgroepen"
#: apps/accounts/models.py:31 apps/currencies/models.py:38 #: apps/accounts/models.py:31 apps/currencies/models.py:39
#: templates/accounts/fragments/list.html:27 #: templates/accounts/fragments/list.html:27
msgid "Currency" msgid "Currency"
msgstr "Munteenheid" msgstr "Munteenheid"
#: apps/accounts/models.py:37 apps/currencies/models.py:26 #: apps/accounts/models.py:37 apps/currencies/models.py:27
#: templates/accounts/fragments/list.html:28 #: templates/accounts/fragments/list.html:28
msgid "Exchange Currency" msgid "Exchange Currency"
msgstr "Eenheid Wisselgeld" msgstr "Eenheid Wisselgeld"
#: apps/accounts/models.py:42 apps/currencies/models.py:31 #: apps/accounts/models.py:42 apps/currencies/models.py:32
msgid "Default currency for exchange calculations" msgid "Default currency for exchange calculations"
msgstr "Standaard munteenheid voor wisselberekeningen" msgstr "Standaard munteenheid voor wisselberekeningen"
@@ -354,11 +354,11 @@ msgstr "Leegmaken"
msgid "No results..." msgid "No results..."
msgstr "Geen resultaten..." msgstr "Geen resultaten..."
#: apps/currencies/forms.py:17 apps/currencies/models.py:21 #: apps/currencies/forms.py:17 apps/currencies/models.py:22
msgid "Prefix" msgid "Prefix"
msgstr "Voorvoegsel" msgstr "Voorvoegsel"
#: apps/currencies/forms.py:18 apps/currencies/models.py:22 #: apps/currencies/forms.py:18 apps/currencies/models.py:23
msgid "Suffix" msgid "Suffix"
msgstr "Achtervoegsel" msgstr "Achtervoegsel"
@@ -371,19 +371,19 @@ msgstr "Achtervoegsel"
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
#: apps/currencies/models.py:13 #: apps/currencies/models.py:14
msgid "Currency Code" msgid "Currency Code"
msgstr "Munteenheids Code" msgstr "Munteenheids Code"
#: apps/currencies/models.py:15 #: apps/currencies/models.py:16
msgid "Currency Name" msgid "Currency Name"
msgstr "Munteenheids Naam" msgstr "Munteenheids Naam"
#: apps/currencies/models.py:19 #: apps/currencies/models.py:20
msgid "Decimal Places" msgid "Decimal Places"
msgstr "Cijfers na de komma" msgstr "Cijfers na de komma"
#: apps/currencies/models.py:39 apps/transactions/filters.py:60 #: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5 #: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 #: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119
#: templates/includes/navbar.html:121 #: templates/includes/navbar.html:121
@@ -393,47 +393,59 @@ msgstr "Cijfers na de komma"
msgid "Currencies" msgid "Currencies"
msgstr "Munteenheden" msgstr "Munteenheden"
#: apps/currencies/models.py:47 #: apps/currencies/models.py:48
msgid "Currency cannot have itself as exchange currency." msgid "Currency cannot have itself as exchange currency."
msgstr "Munteenheid kan zichzelf niet als ruilmiddel hebben." msgstr "Munteenheid kan zichzelf niet als ruilmiddel hebben."
#: apps/currencies/models.py:58 #: apps/currencies/models.py:59
msgid "From Currency" msgid "From Currency"
msgstr "Van Munteenheid" msgstr "Van Munteenheid"
#: apps/currencies/models.py:64 #: apps/currencies/models.py:65
msgid "To Currency" msgid "To Currency"
msgstr "Naar Munteenheid" msgstr "Naar Munteenheid"
#: apps/currencies/models.py:67 apps/currencies/models.py:72 #: apps/currencies/models.py:68 apps/currencies/models.py:73
msgid "Exchange Rate" msgid "Exchange Rate"
msgstr "Wisselkoers" msgstr "Wisselkoers"
#: apps/currencies/models.py:69 #: apps/currencies/models.py:70
msgid "Date and Time" msgid "Date and Time"
msgstr "Datum en Tijd" msgstr "Datum en Tijd"
#: apps/currencies/models.py:73 templates/exchange_rates/fragments/list.html:6 #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4 #: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:123 #: templates/includes/navbar.html:123
msgid "Exchange Rates" msgid "Exchange Rates"
msgstr "Wisselkoersen" msgstr "Wisselkoersen"
#: apps/currencies/models.py:85 #: apps/currencies/models.py:86
msgid "From and To currencies cannot be the same." msgid "From and To currencies cannot be the same."
msgstr "Van en Naar munteenheid kunnen niet dezelfde zijn." msgstr "Van en Naar munteenheid kunnen niet dezelfde zijn."
#: apps/currencies/models.py:97 #: apps/currencies/models.py:99
msgid "On"
msgstr ""
#: apps/currencies/models.py:100
msgid "Every X hours"
msgstr ""
#: apps/currencies/models.py:101
msgid "Not on"
msgstr ""
#: apps/currencies/models.py:103
msgid "Service Name" msgid "Service Name"
msgstr "" msgstr ""
#: apps/currencies/models.py:99 #: apps/currencies/models.py:105
#, fuzzy #, fuzzy
#| msgid "Recurrence Type" #| msgid "Recurrence Type"
msgid "Service Type" msgid "Service Type"
msgstr "Type Terugkeerpatroon" msgstr "Type Terugkeerpatroon"
#: apps/currencies/models.py:101 apps/transactions/models.py:71 #: apps/currencies/models.py:107 apps/transactions/models.py:71
#: apps/transactions/models.py:90 apps/transactions/models.py:109 #: apps/transactions/models.py:90 apps/transactions/models.py:109
#: templates/categories/fragments/list.html:21 #: templates/categories/fragments/list.html:21
#: templates/entities/fragments/list.html:21 #: templates/entities/fragments/list.html:21
@@ -442,60 +454,88 @@ msgstr "Type Terugkeerpatroon"
msgid "Active" msgid "Active"
msgstr "Actief" msgstr "Actief"
#: apps/currencies/models.py:106 #: apps/currencies/models.py:112
msgid "API Key" msgid "API Key"
msgstr "" msgstr ""
#: apps/currencies/models.py:107 #: apps/currencies/models.py:113
msgid "API key for the service (if required)" msgid "API key for the service (if required)"
msgstr "" msgstr ""
#: apps/currencies/models.py:112 #: apps/currencies/models.py:118
msgid "Fetch Interval (hours)" #, fuzzy
msgstr "" #| msgid "Internal Note"
msgid "Interval Type"
msgstr "Interne opmerking"
#: apps/currencies/models.py:115 #: apps/currencies/models.py:122
#, fuzzy
#| msgid "Internal ID"
msgid "Interval"
msgstr "Interne ID"
#: apps/currencies/models.py:125
#, fuzzy #, fuzzy
#| msgid "Successful Items" #| msgid "Successful Items"
msgid "Last Successful Fetch" msgid "Last Successful Fetch"
msgstr "Succesvolle Artikelen" msgstr "Succesvolle Artikelen"
#: apps/currencies/models.py:120 #: apps/currencies/models.py:130
#, fuzzy #, fuzzy
#| msgid "Target Currency" #| msgid "Target Currency"
msgid "Target Currencies" msgid "Target Currencies"
msgstr "Doel Munteenheid" msgstr "Doel Munteenheid"
#: apps/currencies/models.py:122 #: apps/currencies/models.py:132
msgid "" msgid ""
"Select currencies to fetch exchange rates for. Rates will be fetched for " "Select currencies to fetch exchange rates for. Rates will be fetched for "
"each currency against their set exchange currency." "each currency against their set exchange currency."
msgstr "" msgstr ""
#: apps/currencies/models.py:130 #: apps/currencies/models.py:140
#, fuzzy #, fuzzy
#| msgid "To Account" #| msgid "To Account"
msgid "Target Accounts" msgid "Target Accounts"
msgstr "Naar rekening" msgstr "Naar rekening"
#: apps/currencies/models.py:132 #: apps/currencies/models.py:142
msgid "" msgid ""
"Select accounts to fetch exchange rates for. Rates will be fetched for each " "Select accounts to fetch exchange rates for. Rates will be fetched for each "
"account's currency against their set exchange currency." "account's currency against their set exchange currency."
msgstr "" msgstr ""
#: apps/currencies/models.py:139 #: apps/currencies/models.py:149
#, fuzzy #, fuzzy
#| msgid "Exchange Rate" #| msgid "Exchange Rate"
msgid "Exchange Rate Service" msgid "Exchange Rate Service"
msgstr "Wisselkoers" msgstr "Wisselkoers"
#: apps/currencies/models.py:140 #: apps/currencies/models.py:150
#, fuzzy #, fuzzy
#| msgid "Exchange Rates" #| msgid "Exchange Rates"
msgid "Exchange Rate Services" msgid "Exchange Rate Services"
msgstr "Wisselkoersen" msgstr "Wisselkoersen"
#: apps/currencies/models.py:202
msgid "'Every X hours' interval type requires a positive integer."
msgstr ""
#: apps/currencies/models.py:211
msgid "'Every X hours' interval must be between 0 and 23."
msgstr ""
#: apps/currencies/models.py:225
msgid ""
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
"'1-5,8,10-12')."
msgstr ""
#: apps/currencies/models.py:236
msgid ""
"Invalid format. Please check the requirements for your selected interval "
"type."
msgstr ""
#: apps/currencies/views/currencies.py:42 #: apps/currencies/views/currencies.py:42
msgid "Currency added successfully" msgid "Currency added successfully"
msgstr "Munteenheid succesvol toegevoegd" msgstr "Munteenheid succesvol toegevoegd"
@@ -1371,7 +1411,7 @@ msgstr "Rekeningsgroep bewerken"
#: templates/dca/fragments/strategy/details.html:63 #: templates/dca/fragments/strategy/details.html:63
#: templates/entities/fragments/table.html:23 #: templates/entities/fragments/table.html:23
#: templates/exchange_rates/fragments/table.html:19 #: templates/exchange_rates/fragments/table.html:19
#: templates/exchange_rates_services/fragments/list.html:43 #: templates/exchange_rates_services/fragments/list.html:42
#: templates/exchange_rates_services/fragments/table.html:19 #: templates/exchange_rates_services/fragments/table.html:19
#: templates/import_app/fragments/profiles/list.html:44 #: templates/import_app/fragments/profiles/list.html:44
#: templates/installment_plans/fragments/table.html:23 #: templates/installment_plans/fragments/table.html:23
@@ -1391,7 +1431,7 @@ msgstr "Acties"
#: templates/dca/fragments/strategy/list.html:34 #: templates/dca/fragments/strategy/list.html:34
#: templates/entities/fragments/table.html:28 #: templates/entities/fragments/table.html:28
#: templates/exchange_rates/fragments/table.html:23 #: templates/exchange_rates/fragments/table.html:23
#: templates/exchange_rates_services/fragments/list.html:47 #: templates/exchange_rates_services/fragments/list.html:46
#: templates/exchange_rates_services/fragments/table.html:23 #: templates/exchange_rates_services/fragments/table.html:23
#: templates/import_app/fragments/profiles/list.html:48 #: templates/import_app/fragments/profiles/list.html:48
#: templates/installment_plans/fragments/table.html:27 #: templates/installment_plans/fragments/table.html:27
@@ -1414,7 +1454,7 @@ msgstr "Bijwerken"
#: templates/dca/fragments/strategy/list.html:42 #: templates/dca/fragments/strategy/list.html:42
#: templates/entities/fragments/table.html:36 #: templates/entities/fragments/table.html:36
#: templates/exchange_rates/fragments/table.html:31 #: templates/exchange_rates/fragments/table.html:31
#: templates/exchange_rates_services/fragments/list.html:54 #: templates/exchange_rates_services/fragments/list.html:53
#: templates/exchange_rates_services/fragments/table.html:31 #: templates/exchange_rates_services/fragments/table.html:31
#: templates/import_app/fragments/profiles/list.html:69 #: templates/import_app/fragments/profiles/list.html:69
#: templates/import_app/fragments/runs/list.html:102 #: templates/import_app/fragments/runs/list.html:102
@@ -1439,7 +1479,7 @@ msgstr "Verwijderen"
#: templates/dca/fragments/strategy/list.html:46 #: templates/dca/fragments/strategy/list.html:46
#: templates/entities/fragments/table.html:40 #: templates/entities/fragments/table.html:40
#: templates/exchange_rates/fragments/table.html:36 #: templates/exchange_rates/fragments/table.html:36
#: templates/exchange_rates_services/fragments/list.html:58 #: templates/exchange_rates_services/fragments/list.html:57
#: templates/exchange_rates_services/fragments/table.html:36 #: templates/exchange_rates_services/fragments/table.html:36
#: templates/import_app/fragments/profiles/list.html:73 #: templates/import_app/fragments/profiles/list.html:73
#: templates/import_app/fragments/runs/list.html:106 #: templates/import_app/fragments/runs/list.html:106
@@ -1467,7 +1507,7 @@ msgstr "Weet je het zeker?"
#: templates/dca/fragments/strategy/list.html:47 #: templates/dca/fragments/strategy/list.html:47
#: templates/entities/fragments/table.html:41 #: templates/entities/fragments/table.html:41
#: templates/exchange_rates/fragments/table.html:37 #: templates/exchange_rates/fragments/table.html:37
#: templates/exchange_rates_services/fragments/list.html:59 #: templates/exchange_rates_services/fragments/list.html:58
#: templates/exchange_rates_services/fragments/table.html:37 #: templates/exchange_rates_services/fragments/table.html:37
#: templates/import_app/fragments/profiles/list.html:74 #: templates/import_app/fragments/profiles/list.html:74
#: templates/rules/fragments/list.html:49 #: templates/rules/fragments/list.html:49
@@ -1486,7 +1526,7 @@ msgstr "Je kunt dit niet meer terugdraaien!"
#: templates/dca/fragments/strategy/list.html:48 #: templates/dca/fragments/strategy/list.html:48
#: templates/entities/fragments/table.html:42 #: templates/entities/fragments/table.html:42
#: templates/exchange_rates/fragments/table.html:38 #: templates/exchange_rates/fragments/table.html:38
#: templates/exchange_rates_services/fragments/list.html:60 #: templates/exchange_rates_services/fragments/list.html:59
#: templates/exchange_rates_services/fragments/table.html:38 #: templates/exchange_rates_services/fragments/table.html:38
#: templates/import_app/fragments/profiles/list.html:75 #: templates/import_app/fragments/profiles/list.html:75
#: templates/import_app/fragments/runs/list.html:108 #: templates/import_app/fragments/runs/list.html:108
@@ -1964,30 +2004,22 @@ msgid "Targeting"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:35 #: templates/exchange_rates_services/fragments/list.html:35
msgid "Fetch every"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:36
msgid "Last fetch" msgid "Last fetch"
msgstr "" msgstr ""
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
#, fuzzy #, fuzzy
#| msgid "Currencies" #| msgid "Currencies"
msgid "currencies" msgid "currencies"
msgstr "Munteenheden" msgstr "Munteenheden"
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
#, fuzzy #, fuzzy
#| msgid "Accounts" #| msgid "Accounts"
msgid "accounts" msgid "accounts"
msgstr "Rekeningen" msgstr "Rekeningen"
#: templates/exchange_rates_services/fragments/list.html:69 #: templates/exchange_rates_services/fragments/list.html:75
msgid "hours"
msgstr ""
#: templates/exchange_rates_services/fragments/list.html:77
msgid "No services configured" msgid "No services configured"
msgstr "" msgstr ""

View File

@@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-04 03:20+0000\n" "POT-Creation-Date: 2025-02-07 11:45-0300\n"
"PO-Revision-Date: 2025-02-04 00:22-0300\n" "PO-Revision-Date: 2025-02-07 11:46-0300\n"
"Last-Translator: Herculino Trotta\n" "Last-Translator: Herculino Trotta\n"
"Language-Team: \n" "Language-Team: \n"
"Language: pt_BR\n" "Language: pt_BR\n"
@@ -25,7 +25,7 @@ msgstr "Nome do grupo"
#: apps/accounts/forms.py:40 apps/accounts/forms.py:96 #: apps/accounts/forms.py:40 apps/accounts/forms.py:96
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91 #: apps/currencies/forms.py:53 apps/currencies/forms.py:91
#: apps/currencies/forms.py:138 apps/dca/forms.py:41 apps/dca/forms.py:93 #: apps/currencies/forms.py:142 apps/dca/forms.py:41 apps/dca/forms.py:93
#: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87 #: apps/import_app/forms.py:34 apps/rules/forms.py:45 apps/rules/forms.py:87
#: apps/transactions/forms.py:190 apps/transactions/forms.py:257 #: apps/transactions/forms.py:190 apps/transactions/forms.py:257
#: apps/transactions/forms.py:581 apps/transactions/forms.py:624 #: apps/transactions/forms.py:581 apps/transactions/forms.py:624
@@ -36,7 +36,7 @@ msgstr "Atualizar"
#: apps/accounts/forms.py:48 apps/accounts/forms.py:104 #: apps/accounts/forms.py:48 apps/accounts/forms.py:104
#: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61 #: apps/common/widgets/tom_select.py:12 apps/currencies/forms.py:61
#: apps/currencies/forms.py:99 apps/currencies/forms.py:146 #: apps/currencies/forms.py:99 apps/currencies/forms.py:150
#: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42 #: apps/dca/forms.py:49 apps/dca/forms.py:102 apps/import_app/forms.py:42
#: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174 #: apps/rules/forms.py:53 apps/rules/forms.py:95 apps/transactions/forms.py:174
#: apps/transactions/forms.py:199 apps/transactions/forms.py:589 #: apps/transactions/forms.py:199 apps/transactions/forms.py:589
@@ -114,17 +114,17 @@ msgstr "Grupo da Conta"
msgid "Account Groups" msgid "Account Groups"
msgstr "Grupos da Conta" msgstr "Grupos da Conta"
#: apps/accounts/models.py:31 apps/currencies/models.py:38 #: apps/accounts/models.py:31 apps/currencies/models.py:39
#: templates/accounts/fragments/list.html:27 #: templates/accounts/fragments/list.html:27
msgid "Currency" msgid "Currency"
msgstr "Moeda" msgstr "Moeda"
#: apps/accounts/models.py:37 apps/currencies/models.py:26 #: apps/accounts/models.py:37 apps/currencies/models.py:27
#: templates/accounts/fragments/list.html:28 #: templates/accounts/fragments/list.html:28
msgid "Exchange Currency" msgid "Exchange Currency"
msgstr "Moeda de Câmbio" msgstr "Moeda de Câmbio"
#: apps/accounts/models.py:42 apps/currencies/models.py:31 #: apps/accounts/models.py:42 apps/currencies/models.py:32
msgid "Default currency for exchange calculations" msgid "Default currency for exchange calculations"
msgstr "Moeda padrão para os cálculos de câmbio" msgstr "Moeda padrão para os cálculos de câmbio"
@@ -352,11 +352,11 @@ msgstr "Limpar"
msgid "No results..." msgid "No results..."
msgstr "Sem resultados..." msgstr "Sem resultados..."
#: apps/currencies/forms.py:17 apps/currencies/models.py:21 #: apps/currencies/forms.py:17 apps/currencies/models.py:22
msgid "Prefix" msgid "Prefix"
msgstr "Prefixo" msgstr "Prefixo"
#: apps/currencies/forms.py:18 apps/currencies/models.py:22 #: apps/currencies/forms.py:18 apps/currencies/models.py:23
msgid "Suffix" msgid "Suffix"
msgstr "Sufixo" msgstr "Sufixo"
@@ -369,19 +369,19 @@ msgstr "Sufixo"
msgid "Date" msgid "Date"
msgstr "Data" msgstr "Data"
#: apps/currencies/models.py:13 #: apps/currencies/models.py:14
msgid "Currency Code" msgid "Currency Code"
msgstr "Código da Moeda" msgstr "Código da Moeda"
#: apps/currencies/models.py:15 #: apps/currencies/models.py:16
msgid "Currency Name" msgid "Currency Name"
msgstr "Nome da Moeda" msgstr "Nome da Moeda"
#: apps/currencies/models.py:19 #: apps/currencies/models.py:20
msgid "Decimal Places" msgid "Decimal Places"
msgstr "Casas Decimais" msgstr "Casas Decimais"
#: apps/currencies/models.py:39 apps/transactions/filters.py:60 #: apps/currencies/models.py:40 apps/transactions/filters.py:60
#: templates/currencies/fragments/list.html:5 #: templates/currencies/fragments/list.html:5
#: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119 #: templates/currencies/pages/index.html:4 templates/includes/navbar.html:119
#: templates/includes/navbar.html:121 #: templates/includes/navbar.html:121
@@ -391,45 +391,57 @@ msgstr "Casas Decimais"
msgid "Currencies" msgid "Currencies"
msgstr "Moedas" msgstr "Moedas"
#: apps/currencies/models.py:47 #: apps/currencies/models.py:48
msgid "Currency cannot have itself as exchange currency." msgid "Currency cannot have itself as exchange currency."
msgstr "A moeda não pode ter a si mesma como moeda de câmbio." msgstr "A moeda não pode ter a si mesma como moeda de câmbio."
#: apps/currencies/models.py:58 #: apps/currencies/models.py:59
msgid "From Currency" msgid "From Currency"
msgstr "Moeda de origem" msgstr "Moeda de origem"
#: apps/currencies/models.py:64 #: apps/currencies/models.py:65
msgid "To Currency" msgid "To Currency"
msgstr "Moeda de destino" msgstr "Moeda de destino"
#: apps/currencies/models.py:67 apps/currencies/models.py:72 #: apps/currencies/models.py:68 apps/currencies/models.py:73
msgid "Exchange Rate" msgid "Exchange Rate"
msgstr "Taxa de Câmbio" msgstr "Taxa de Câmbio"
#: apps/currencies/models.py:69 #: apps/currencies/models.py:70
msgid "Date and Time" msgid "Date and Time"
msgstr "Data e Tempo" msgstr "Data e Tempo"
#: apps/currencies/models.py:73 templates/exchange_rates/fragments/list.html:6 #: apps/currencies/models.py:74 templates/exchange_rates/fragments/list.html:6
#: templates/exchange_rates/pages/index.html:4 #: templates/exchange_rates/pages/index.html:4
#: templates/includes/navbar.html:123 #: templates/includes/navbar.html:123
msgid "Exchange Rates" msgid "Exchange Rates"
msgstr "Taxas de Câmbio" msgstr "Taxas de Câmbio"
#: apps/currencies/models.py:85 #: apps/currencies/models.py:86
msgid "From and To currencies cannot be the same." msgid "From and To currencies cannot be the same."
msgstr "As moedas De e Para não podem ser as mesmas." msgstr "As moedas De e Para não podem ser as mesmas."
#: apps/currencies/models.py:97 #: apps/currencies/models.py:99
msgid "On"
msgstr "Em"
#: apps/currencies/models.py:100
msgid "Every X hours"
msgstr "A cada X horas"
#: apps/currencies/models.py:101
msgid "Not on"
msgstr "Não em"
#: apps/currencies/models.py:103
msgid "Service Name" msgid "Service Name"
msgstr "Nome do Serviço" msgstr "Nome do Serviço"
#: apps/currencies/models.py:99 #: apps/currencies/models.py:105
msgid "Service Type" msgid "Service Type"
msgstr "Tipo de Serviço" msgstr "Tipo de Serviço"
#: apps/currencies/models.py:101 apps/transactions/models.py:71 #: apps/currencies/models.py:107 apps/transactions/models.py:71
#: apps/transactions/models.py:90 apps/transactions/models.py:109 #: apps/transactions/models.py:90 apps/transactions/models.py:109
#: templates/categories/fragments/list.html:21 #: templates/categories/fragments/list.html:21
#: templates/entities/fragments/list.html:21 #: templates/entities/fragments/list.html:21
@@ -438,27 +450,31 @@ msgstr "Tipo de Serviço"
msgid "Active" msgid "Active"
msgstr "Ativo" msgstr "Ativo"
#: apps/currencies/models.py:106 #: apps/currencies/models.py:112
msgid "API Key" msgid "API Key"
msgstr "Chave de API" msgstr "Chave de API"
#: apps/currencies/models.py:107 #: apps/currencies/models.py:113
msgid "API key for the service (if required)" msgid "API key for the service (if required)"
msgstr "Chave de API para o serviço (se necessário)" msgstr "Chave de API para o serviço (se necessário)"
#: apps/currencies/models.py:112 #: apps/currencies/models.py:118
msgid "Fetch Interval (hours)" msgid "Interval Type"
msgstr "Intervalo de busca (horas)" msgstr "Tipo de Intervalo"
#: apps/currencies/models.py:115 #: apps/currencies/models.py:122
msgid "Interval"
msgstr "Intervalo"
#: apps/currencies/models.py:125
msgid "Last Successful Fetch" msgid "Last Successful Fetch"
msgstr "Última execução bem-sucedida" msgstr "Última execução bem-sucedida"
#: apps/currencies/models.py:120 #: apps/currencies/models.py:130
msgid "Target Currencies" msgid "Target Currencies"
msgstr "Moedas-alvo" msgstr "Moedas-alvo"
#: apps/currencies/models.py:122 #: apps/currencies/models.py:132
msgid "" msgid ""
"Select currencies to fetch exchange rates for. Rates will be fetched for " "Select currencies to fetch exchange rates for. Rates will be fetched for "
"each currency against their set exchange currency." "each currency against their set exchange currency."
@@ -466,11 +482,11 @@ msgstr ""
"Selecione as moedas para as quais deseja obter as taxas de câmbio. As taxas " "Selecione as moedas para as quais deseja obter as taxas de câmbio. As taxas "
"serão obtidas para cada moeda em relação à moeda de câmbio definida." "serão obtidas para cada moeda em relação à moeda de câmbio definida."
#: apps/currencies/models.py:130 #: apps/currencies/models.py:140
msgid "Target Accounts" msgid "Target Accounts"
msgstr "Contas-alvo" msgstr "Contas-alvo"
#: apps/currencies/models.py:132 #: apps/currencies/models.py:142
msgid "" msgid ""
"Select accounts to fetch exchange rates for. Rates will be fetched for each " "Select accounts to fetch exchange rates for. Rates will be fetched for each "
"account's currency against their set exchange currency." "account's currency against their set exchange currency."
@@ -479,14 +495,39 @@ msgstr ""
"serão obtidas para a moeda de cada conta em relação à moeda de câmbio " "serão obtidas para a moeda de cada conta em relação à moeda de câmbio "
"definida." "definida."
#: apps/currencies/models.py:139 #: apps/currencies/models.py:149
msgid "Exchange Rate Service" msgid "Exchange Rate Service"
msgstr "Serviço de Taxa de Câmbio" msgstr "Serviço de Taxa de Câmbio"
#: apps/currencies/models.py:140 #: apps/currencies/models.py:150
msgid "Exchange Rate Services" msgid "Exchange Rate Services"
msgstr "Serviços de Taxa de Câmbio" msgstr "Serviços de Taxa de Câmbio"
#: apps/currencies/models.py:202
msgid "'Every X hours' interval type requires a positive integer."
msgstr ""
"Intervalo do tipo 'A cada X horas' requerer um número inteiro positivo."
#: apps/currencies/models.py:211
msgid "'Every X hours' interval must be between 0 and 23."
msgstr "Intervalo do tipo 'A cada X horas' requerer um número entre 0 e 23."
#: apps/currencies/models.py:225
msgid ""
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
"'1-5,8,10-12')."
msgstr ""
"Formato inválido de hora. Use uma lista de horas separada por vírgulas "
"(0-23) e/ou uma faixa (ex.: '1-5,8,10-12')"
#: apps/currencies/models.py:236
msgid ""
"Invalid format. Please check the requirements for your selected interval "
"type."
msgstr ""
"Formato inválido. Por favor cheque os requisitos para o seu tipo de "
"intervalo."
#: apps/currencies/views/currencies.py:42 #: apps/currencies/views/currencies.py:42
msgid "Currency added successfully" msgid "Currency added successfully"
msgstr "Moeda adicionada com sucesso" msgstr "Moeda adicionada com sucesso"
@@ -1349,7 +1390,7 @@ msgstr "Editar grupo de conta"
#: templates/dca/fragments/strategy/details.html:63 #: templates/dca/fragments/strategy/details.html:63
#: templates/entities/fragments/table.html:23 #: templates/entities/fragments/table.html:23
#: templates/exchange_rates/fragments/table.html:19 #: templates/exchange_rates/fragments/table.html:19
#: templates/exchange_rates_services/fragments/list.html:43 #: templates/exchange_rates_services/fragments/list.html:42
#: templates/exchange_rates_services/fragments/table.html:19 #: templates/exchange_rates_services/fragments/table.html:19
#: templates/import_app/fragments/profiles/list.html:44 #: templates/import_app/fragments/profiles/list.html:44
#: templates/installment_plans/fragments/table.html:23 #: templates/installment_plans/fragments/table.html:23
@@ -1369,7 +1410,7 @@ msgstr "Ações"
#: templates/dca/fragments/strategy/list.html:34 #: templates/dca/fragments/strategy/list.html:34
#: templates/entities/fragments/table.html:28 #: templates/entities/fragments/table.html:28
#: templates/exchange_rates/fragments/table.html:23 #: templates/exchange_rates/fragments/table.html:23
#: templates/exchange_rates_services/fragments/list.html:47 #: templates/exchange_rates_services/fragments/list.html:46
#: templates/exchange_rates_services/fragments/table.html:23 #: templates/exchange_rates_services/fragments/table.html:23
#: templates/import_app/fragments/profiles/list.html:48 #: templates/import_app/fragments/profiles/list.html:48
#: templates/installment_plans/fragments/table.html:27 #: templates/installment_plans/fragments/table.html:27
@@ -1392,7 +1433,7 @@ msgstr "Editar"
#: templates/dca/fragments/strategy/list.html:42 #: templates/dca/fragments/strategy/list.html:42
#: templates/entities/fragments/table.html:36 #: templates/entities/fragments/table.html:36
#: templates/exchange_rates/fragments/table.html:31 #: templates/exchange_rates/fragments/table.html:31
#: templates/exchange_rates_services/fragments/list.html:54 #: templates/exchange_rates_services/fragments/list.html:53
#: templates/exchange_rates_services/fragments/table.html:31 #: templates/exchange_rates_services/fragments/table.html:31
#: templates/import_app/fragments/profiles/list.html:69 #: templates/import_app/fragments/profiles/list.html:69
#: templates/import_app/fragments/runs/list.html:102 #: templates/import_app/fragments/runs/list.html:102
@@ -1417,7 +1458,7 @@ msgstr "Apagar"
#: templates/dca/fragments/strategy/list.html:46 #: templates/dca/fragments/strategy/list.html:46
#: templates/entities/fragments/table.html:40 #: templates/entities/fragments/table.html:40
#: templates/exchange_rates/fragments/table.html:36 #: templates/exchange_rates/fragments/table.html:36
#: templates/exchange_rates_services/fragments/list.html:58 #: templates/exchange_rates_services/fragments/list.html:57
#: templates/exchange_rates_services/fragments/table.html:36 #: templates/exchange_rates_services/fragments/table.html:36
#: templates/import_app/fragments/profiles/list.html:73 #: templates/import_app/fragments/profiles/list.html:73
#: templates/import_app/fragments/runs/list.html:106 #: templates/import_app/fragments/runs/list.html:106
@@ -1445,7 +1486,7 @@ msgstr "Tem certeza?"
#: templates/dca/fragments/strategy/list.html:47 #: templates/dca/fragments/strategy/list.html:47
#: templates/entities/fragments/table.html:41 #: templates/entities/fragments/table.html:41
#: templates/exchange_rates/fragments/table.html:37 #: templates/exchange_rates/fragments/table.html:37
#: templates/exchange_rates_services/fragments/list.html:59 #: templates/exchange_rates_services/fragments/list.html:58
#: templates/exchange_rates_services/fragments/table.html:37 #: templates/exchange_rates_services/fragments/table.html:37
#: templates/import_app/fragments/profiles/list.html:74 #: templates/import_app/fragments/profiles/list.html:74
#: templates/rules/fragments/list.html:49 #: templates/rules/fragments/list.html:49
@@ -1464,7 +1505,7 @@ msgstr "Você não será capaz de reverter isso!"
#: templates/dca/fragments/strategy/list.html:48 #: templates/dca/fragments/strategy/list.html:48
#: templates/entities/fragments/table.html:42 #: templates/entities/fragments/table.html:42
#: templates/exchange_rates/fragments/table.html:38 #: templates/exchange_rates/fragments/table.html:38
#: templates/exchange_rates_services/fragments/list.html:60 #: templates/exchange_rates_services/fragments/list.html:59
#: templates/exchange_rates_services/fragments/table.html:38 #: templates/exchange_rates_services/fragments/table.html:38
#: templates/import_app/fragments/profiles/list.html:75 #: templates/import_app/fragments/profiles/list.html:75
#: templates/import_app/fragments/runs/list.html:108 #: templates/import_app/fragments/runs/list.html:108
@@ -1939,26 +1980,18 @@ msgid "Targeting"
msgstr "Alvos" msgstr "Alvos"
#: templates/exchange_rates_services/fragments/list.html:35 #: templates/exchange_rates_services/fragments/list.html:35
msgid "Fetch every"
msgstr "Buscar a cada"
#: templates/exchange_rates_services/fragments/list.html:36
msgid "Last fetch" msgid "Last fetch"
msgstr "Última execução" msgstr "Última execução"
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
msgid "currencies" msgid "currencies"
msgstr "moedas" msgstr "moedas"
#: templates/exchange_rates_services/fragments/list.html:68 #: templates/exchange_rates_services/fragments/list.html:67
msgid "accounts" msgid "accounts"
msgstr "contas" msgstr "contas"
#: templates/exchange_rates_services/fragments/list.html:69 #: templates/exchange_rates_services/fragments/list.html:75
msgid "hours"
msgstr "horas"
#: templates/exchange_rates_services/fragments/list.html:77
msgid "No services configured" msgid "No services configured"
msgstr "Nenhum serviço configurado" msgstr "Nenhum serviço configurado"
@@ -2511,6 +2544,15 @@ msgstr "Visão Anual"
msgid "Year" msgid "Year"
msgstr "Ano" msgstr "Ano"
#~ msgid "Fetch Interval (hours)"
#~ msgstr "Intervalo de busca (horas)"
#~ msgid "Fetch every"
#~ msgstr "Buscar a cada"
#~ msgid "hours"
#~ msgstr "horas"
#, fuzzy #, fuzzy
#~ msgid "Exchange rates queued to be fetched successfully" #~ msgid "Exchange rates queued to be fetched successfully"
#~ msgstr "Taxas de câmbio com sucesso" #~ msgstr "Taxas de câmbio com sucesso"

View File

@@ -32,7 +32,6 @@
<th scope="col" class="col-auto">{% translate 'Name' %}</th> <th scope="col" class="col-auto">{% translate 'Name' %}</th>
<th scope="col" class="col">{% translate 'Service' %}</th> <th scope="col" class="col">{% translate 'Service' %}</th>
<th scope="col" class="col">{% translate 'Targeting' %}</th> <th scope="col" class="col">{% translate 'Targeting' %}</th>
<th scope="col" class="col">{% translate 'Fetch every' %}</th>
<th scope="col" class="col">{% translate 'Last fetch' %}</th> <th scope="col" class="col">{% translate 'Last fetch' %}</th>
</tr> </tr>
</thead> </thead>
@@ -66,7 +65,6 @@
<td class="col-auto">{{ service.name }}</td> <td class="col-auto">{{ service.name }}</td>
<td class="col">{{ service.get_service_type_display }}</td> <td class="col">{{ service.get_service_type_display }}</td>
<td class="col">{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td> <td class="col">{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td>
<td class="col">{{ service.fetch_interval_hours }} {% trans 'hours' %}</td>
<td class="col">{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td> <td class="col">{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td>
</tr> </tr>
{% endfor %} {% endfor %}