mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-01-11 20:00:26 +01:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e4d7c6b1f | ||
|
|
63868514f9 | ||
|
|
9055a24327 | ||
|
|
9dc963ed7b | ||
|
|
49cac0588e | ||
|
|
3b2b6d6473 | ||
|
|
db30bcbeb7 | ||
|
|
a122733a47 | ||
|
|
37f3e4d99a | ||
|
|
d756286135 | ||
|
|
06a7378fd8 | ||
|
|
ab4075c500 | ||
|
|
96318f003d | ||
|
|
1a0412264a | ||
|
|
2588404876 | ||
|
|
fdc273103b | ||
|
|
c015b78cd6 | ||
|
|
50e5492ea1 | ||
|
|
796089cdb3 | ||
|
|
c83b1bf2d6 | ||
|
|
b074ef7929 | ||
|
|
ec7e33b3b0 | ||
|
|
72fedea0db | ||
|
|
0a03745ce6 | ||
|
|
ff4bd79634 | ||
|
|
383b42e26d | ||
|
|
48e43ac031 | ||
|
|
21c60c4059 | ||
|
|
dd6a390e6b | ||
|
|
0c961a8250 | ||
|
|
e28c651973 | ||
|
|
7687ff81c3 | ||
|
|
b2d78c9190 | ||
|
|
b0815e00c7 | ||
|
|
fbe9726338 | ||
|
|
0df3a57a33 | ||
|
|
f86613b17a | ||
|
|
ffa4644e1b | ||
|
|
6611559696 | ||
|
|
b455a0251a | ||
|
|
9d7c3212f1 | ||
|
|
0da3185996 | ||
|
|
6c90e1bb7f | ||
|
|
c6543c0841 | ||
|
|
d4740b8406 | ||
|
|
5a51795e6a | ||
|
|
64d7765357 | ||
|
|
070e11ca77 | ||
|
|
39f66b620a | ||
|
|
ad164866e0 | ||
|
|
05c465cb34 | ||
|
|
92cf526b76 | ||
|
|
639236b890 | ||
|
|
519a85d256 | ||
|
|
700d35b5d5 | ||
|
|
10e51971db | ||
|
|
ec0d5fc121 | ||
|
|
01f91352d6 | ||
|
|
63ce57a315 | ||
|
|
eadeb649a1 | ||
|
|
a2871d5289 | ||
|
|
f2a362bc0f | ||
|
|
2076903740 | ||
|
|
c752c0b16e | ||
|
|
1674766253 | ||
|
|
7ea9d56132 | ||
|
|
3699c6c671 | ||
|
|
d7c255aa14 | ||
|
|
d17b9d5736 | ||
|
|
c7ff6db0bf | ||
|
|
a4c7753f69 | ||
|
|
7e08028557 | ||
|
|
5eaf5086d2 | ||
|
|
c949c6cea0 | ||
|
|
71c0e9a271 | ||
|
|
bc65980511 | ||
|
|
ecdb1a52cc | ||
|
|
afc06582b4 |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__/
|
||||
15
.github/workflows/translations.yml
vendored
15
.github/workflows/translations.yml
vendored
@@ -32,15 +32,16 @@ jobs:
|
||||
token: ${{ secrets.PAT }}
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
enable-cache: true
|
||||
|
||||
- name: Set up Python 3.11
|
||||
run: uv python install 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
run: uv sync --frozen --no-dev
|
||||
|
||||
- name: Install gettext
|
||||
run: sudo apt-get install -y gettext
|
||||
@@ -48,7 +49,7 @@ jobs:
|
||||
- name: Run makemessages
|
||||
run: |
|
||||
cd app
|
||||
python manage.py makemessages -a
|
||||
uv run python manage.py makemessages -a
|
||||
|
||||
- name: Check for changes
|
||||
id: check_changes
|
||||
|
||||
@@ -70,6 +70,7 @@ INSTALLED_APPS = [
|
||||
"apps.api.apps.ApiConfig",
|
||||
"cachalot",
|
||||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
"drf_spectacular",
|
||||
"django_cotton",
|
||||
"apps.rules.apps.RulesConfig",
|
||||
@@ -433,8 +434,16 @@ REST_FRAMEWORK = {
|
||||
"apps.api.permissions.NotInDemoMode",
|
||||
"rest_framework.permissions.DjangoModelPermissions",
|
||||
],
|
||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
||||
"PAGE_SIZE": 10,
|
||||
'DEFAULT_FILTER_BACKENDS': [
|
||||
'django_filters.rest_framework.DjangoFilterBackend',
|
||||
'rest_framework.filters.OrderingFilter',
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
],
|
||||
"DEFAULT_PAGINATION_CLASS": "apps.api.custom.pagination.CustomPageNumberPagination",
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def account_groups_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def account_groups_list(request):
|
||||
account_groups = AccountGroup.objects.all().order_by("id")
|
||||
account_groups = AccountGroup.objects.all().order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"account_groups/fragments/list.html",
|
||||
|
||||
@@ -25,7 +25,7 @@ def accounts_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def accounts_list(request):
|
||||
accounts = Account.objects.all().order_by("id")
|
||||
accounts = Account.objects.all().order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"accounts/fragments/list.html",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Import all test classes for Django test discovery
|
||||
from .test_imports import *
|
||||
from .test_accounts import *
|
||||
|
||||
from .test_data_isolation import *
|
||||
from .test_shared_access import *
|
||||
|
||||
719
app/apps/api/tests/test_data_isolation.py
Normal file
719
app/apps/api/tests/test_data_isolation.py
Normal file
@@ -0,0 +1,719 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, override_settings
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.accounts.models import Account, AccountGroup
|
||||
from apps.currencies.models import Currency
|
||||
from apps.dca.models import DCAStrategy, DCAEntry
|
||||
from apps.transactions.models import (
|
||||
Transaction,
|
||||
TransactionCategory,
|
||||
TransactionTag,
|
||||
TransactionEntity,
|
||||
InstallmentPlan,
|
||||
RecurringTransaction,
|
||||
)
|
||||
|
||||
|
||||
ACCESS_DENIED_CODES = [status.HTTP_403_FORBIDDEN, status.HTTP_404_NOT_FOUND]
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class AccountDataIsolationTests(TestCase):
|
||||
"""Tests to ensure users cannot access other users' accounts."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with two distinct users."""
|
||||
User = get_user_model()
|
||||
|
||||
# User 1 - the requester
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
# User 2 - owner of data that user1 should NOT access
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
# Shared currency
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's account
|
||||
self.user1_account_group = AccountGroup.all_objects.create(
|
||||
name="User1 Group", owner=self.user1
|
||||
)
|
||||
self.user1_account = Account.all_objects.create(
|
||||
name="User1 Account",
|
||||
group=self.user1_account_group,
|
||||
currency=self.currency,
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
# User 2's account (private, should be invisible to user1)
|
||||
self.user2_account_group = AccountGroup.all_objects.create(
|
||||
name="User2 Group", owner=self.user2
|
||||
)
|
||||
self.user2_account = Account.all_objects.create(
|
||||
name="User2 Account",
|
||||
group=self.user2_account_group,
|
||||
currency=self.currency,
|
||||
owner=self.user2,
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_accounts_in_list(self):
|
||||
"""GET /api/accounts/ should only return user's own accounts."""
|
||||
response = self.client1.get("/api/accounts/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# User1 should only see their own account
|
||||
account_ids = [acc["id"] for acc in response.data["results"]]
|
||||
self.assertIn(self.user1_account.id, account_ids)
|
||||
self.assertNotIn(self.user2_account.id, account_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_account_detail(self):
|
||||
"""GET /api/accounts/{id}/ should deny access to other user's account."""
|
||||
response = self.client1.get(f"/api/accounts/{self.user2_account.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_account(self):
|
||||
"""PATCH on other user's account should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/accounts/{self.user2_account.id}/",
|
||||
{"name": "Hacked Account"},
|
||||
)
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
# Verify account name wasn't changed
|
||||
self.user2_account.refresh_from_db()
|
||||
self.assertEqual(self.user2_account.name, "User2 Account")
|
||||
|
||||
def test_user_cannot_delete_other_users_account(self):
|
||||
"""DELETE on other user's account should deny access."""
|
||||
response = self.client1.delete(f"/api/accounts/{self.user2_account.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
# Verify account still exists
|
||||
self.assertTrue(Account.all_objects.filter(id=self.user2_account.id).exists())
|
||||
|
||||
def test_user_cannot_get_balance_of_other_users_account(self):
|
||||
"""Balance action on other user's account should deny access."""
|
||||
response = self.client1.get(f"/api/accounts/{self.user2_account.id}/balance/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_can_access_own_account(self):
|
||||
"""User can access their own account normally."""
|
||||
response = self.client1.get(f"/api/accounts/{self.user1_account.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "User1 Account")
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class AccountGroupDataIsolationTests(TestCase):
|
||||
"""Tests to ensure users cannot access other users' account groups."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with two distinct users."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
|
||||
# User 1's account group
|
||||
self.user1_group = AccountGroup.all_objects.create(
|
||||
name="User1 Group", owner=self.user1
|
||||
)
|
||||
|
||||
# User 2's account group
|
||||
self.user2_group = AccountGroup.all_objects.create(
|
||||
name="User2 Group", owner=self.user2
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_account_groups(self):
|
||||
"""GET /api/account-groups/ should only return user's own groups."""
|
||||
response = self.client1.get("/api/account-groups/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
group_ids = [grp["id"] for grp in response.data["results"]]
|
||||
self.assertIn(self.user1_group.id, group_ids)
|
||||
self.assertNotIn(self.user2_group.id, group_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_account_group_detail(self):
|
||||
"""GET /api/account-groups/{id}/ should deny access to other user's group."""
|
||||
response = self.client1.get(f"/api/account-groups/{self.user2_group.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_account_group(self):
|
||||
"""PATCH on other user's account group should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/account-groups/{self.user2_group.id}/",
|
||||
{"name": "Hacked Group"},
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.user2_group.refresh_from_db()
|
||||
self.assertEqual(self.user2_group.name, "User2 Group")
|
||||
|
||||
def test_user_cannot_delete_other_users_account_group(self):
|
||||
"""DELETE on other user's account group should deny access."""
|
||||
response = self.client1.delete(f"/api/account-groups/{self.user2_group.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.assertTrue(
|
||||
AccountGroup.all_objects.filter(id=self.user2_group.id).exists()
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class TransactionDataIsolationTests(TestCase):
|
||||
"""Tests to ensure users cannot access other users' transactions."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with transactions for two distinct users."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's account and transaction
|
||||
self.user1_account = Account.all_objects.create(
|
||||
name="User1 Account", currency=self.currency, owner=self.user1
|
||||
)
|
||||
self.user1_transaction = Transaction.userless_all_objects.create(
|
||||
account=self.user1_account,
|
||||
type=Transaction.Type.INCOME,
|
||||
amount=Decimal("100.00"),
|
||||
is_paid=True,
|
||||
date=date(2025, 1, 1),
|
||||
description="User1 Income",
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
# User 2's account and transaction
|
||||
self.user2_account = Account.all_objects.create(
|
||||
name="User2 Account", currency=self.currency, owner=self.user2
|
||||
)
|
||||
self.user2_transaction = Transaction.userless_all_objects.create(
|
||||
account=self.user2_account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
amount=Decimal("50.00"),
|
||||
is_paid=True,
|
||||
date=date(2025, 1, 1),
|
||||
description="User2 Expense",
|
||||
owner=self.user2,
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_transactions_in_list(self):
|
||||
"""GET /api/transactions/ should only return user's own transactions."""
|
||||
response = self.client1.get("/api/transactions/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
transaction_ids = [t["id"] for t in response.data["results"]]
|
||||
self.assertIn(self.user1_transaction.id, transaction_ids)
|
||||
self.assertNotIn(self.user2_transaction.id, transaction_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_transaction_detail(self):
|
||||
"""GET /api/transactions/{id}/ should deny access to other user's transaction."""
|
||||
response = self.client1.get(f"/api/transactions/{self.user2_transaction.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_transaction(self):
|
||||
"""PATCH on other user's transaction should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/transactions/{self.user2_transaction.id}/",
|
||||
{"description": "Hacked Transaction"},
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.user2_transaction.refresh_from_db()
|
||||
self.assertEqual(self.user2_transaction.description, "User2 Expense")
|
||||
|
||||
def test_user_cannot_delete_other_users_transaction(self):
|
||||
"""DELETE on other user's transaction should deny access."""
|
||||
response = self.client1.delete(
|
||||
f"/api/transactions/{self.user2_transaction.id}/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.assertTrue(
|
||||
Transaction.userless_all_objects.filter(
|
||||
id=self.user2_transaction.id
|
||||
).exists()
|
||||
)
|
||||
|
||||
def test_user_cannot_create_transaction_in_other_users_account(self):
|
||||
"""POST /api/transactions/ with other user's account should fail."""
|
||||
response = self.client1.post(
|
||||
"/api/transactions/",
|
||||
{
|
||||
"account": self.user2_account.id,
|
||||
"type": "IN",
|
||||
"amount": "100.00",
|
||||
"date": "2025-01-15",
|
||||
"description": "Sneaky transaction",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
# Should deny access - 400 (validation error), 403, or 404
|
||||
self.assertIn(
|
||||
response.status_code,
|
||||
ACCESS_DENIED_CODES + [status.HTTP_400_BAD_REQUEST],
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class CategoryTagEntityIsolationTests(TestCase):
|
||||
"""Tests for isolation of categories, tags, and entities between users."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
|
||||
# User 1's categories, tags, entities
|
||||
self.user1_category = TransactionCategory.all_objects.create(
|
||||
name="User1 Category", owner=self.user1
|
||||
)
|
||||
self.user1_tag = TransactionTag.all_objects.create(
|
||||
name="User1 Tag", owner=self.user1
|
||||
)
|
||||
self.user1_entity = TransactionEntity.all_objects.create(
|
||||
name="User1 Entity", owner=self.user1
|
||||
)
|
||||
|
||||
# User 2's categories, tags, entities
|
||||
self.user2_category = TransactionCategory.all_objects.create(
|
||||
name="User2 Category", owner=self.user2
|
||||
)
|
||||
self.user2_tag = TransactionTag.all_objects.create(
|
||||
name="User2 Tag", owner=self.user2
|
||||
)
|
||||
self.user2_entity = TransactionEntity.all_objects.create(
|
||||
name="User2 Entity", owner=self.user2
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_categories(self):
|
||||
"""GET /api/categories/ should only return user's own categories."""
|
||||
response = self.client1.get("/api/categories/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
category_ids = [c["id"] for c in response.data["results"]]
|
||||
self.assertIn(self.user1_category.id, category_ids)
|
||||
self.assertNotIn(self.user2_category.id, category_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_category_detail(self):
|
||||
"""GET /api/categories/{id}/ should deny access to other user's category."""
|
||||
response = self.client1.get(f"/api/categories/{self.user2_category.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_see_other_users_tags(self):
|
||||
"""GET /api/tags/ should only return user's own tags."""
|
||||
response = self.client1.get("/api/tags/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
tag_ids = [t["id"] for t in response.data["results"]]
|
||||
self.assertIn(self.user1_tag.id, tag_ids)
|
||||
self.assertNotIn(self.user2_tag.id, tag_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_tag_detail(self):
|
||||
"""GET /api/tags/{id}/ should deny access to other user's tag."""
|
||||
response = self.client1.get(f"/api/tags/{self.user2_tag.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_see_other_users_entities(self):
|
||||
"""GET /api/entities/ should only return user's own entities."""
|
||||
response = self.client1.get("/api/entities/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
entity_ids = [e["id"] for e in response.data["results"]]
|
||||
self.assertIn(self.user1_entity.id, entity_ids)
|
||||
self.assertNotIn(self.user2_entity.id, entity_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_entity_detail(self):
|
||||
"""GET /api/entities/{id}/ should deny access to other user's entity."""
|
||||
response = self.client1.get(f"/api/entities/{self.user2_entity.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_category(self):
|
||||
"""PATCH on other user's category should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/categories/{self.user2_category.id}/",
|
||||
{"name": "Hacked Category"},
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_delete_other_users_tag(self):
|
||||
"""DELETE on other user's tag should deny access."""
|
||||
response = self.client1.delete(f"/api/tags/{self.user2_tag.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.assertTrue(
|
||||
TransactionTag.all_objects.filter(id=self.user2_tag.id).exists()
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class DCADataIsolationTests(TestCase):
|
||||
"""Tests to ensure users cannot access other users' DCA strategies and entries."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
|
||||
self.currency1 = Currency.objects.create(
|
||||
code="BTC", name="Bitcoin", decimal_places=8, prefix=""
|
||||
)
|
||||
self.currency2 = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's DCA strategy and entry
|
||||
self.user1_strategy = DCAStrategy.all_objects.create(
|
||||
name="User1 BTC Strategy",
|
||||
target_currency=self.currency1,
|
||||
payment_currency=self.currency2,
|
||||
owner=self.user1,
|
||||
)
|
||||
self.user1_entry = DCAEntry.objects.create(
|
||||
strategy=self.user1_strategy,
|
||||
date=date(2025, 1, 1),
|
||||
amount_paid=Decimal("100.00"),
|
||||
amount_received=Decimal("0.001"),
|
||||
)
|
||||
|
||||
# User 2's DCA strategy and entry
|
||||
self.user2_strategy = DCAStrategy.all_objects.create(
|
||||
name="User2 BTC Strategy",
|
||||
target_currency=self.currency1,
|
||||
payment_currency=self.currency2,
|
||||
owner=self.user2,
|
||||
)
|
||||
self.user2_entry = DCAEntry.objects.create(
|
||||
strategy=self.user2_strategy,
|
||||
date=date(2025, 1, 1),
|
||||
amount_paid=Decimal("200.00"),
|
||||
amount_received=Decimal("0.002"),
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_dca_strategies(self):
|
||||
"""GET /api/dca/strategies/ should only return user's own strategies."""
|
||||
response = self.client1.get("/api/dca/strategies/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
strategy_ids = [s["id"] for s in response.data["results"]]
|
||||
self.assertIn(self.user1_strategy.id, strategy_ids)
|
||||
self.assertNotIn(self.user2_strategy.id, strategy_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_dca_strategy_detail(self):
|
||||
"""GET /api/dca/strategies/{id}/ should deny access to other user's strategy."""
|
||||
response = self.client1.get(f"/api/dca/strategies/{self.user2_strategy.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_access_other_users_dca_entries(self):
|
||||
"""GET /api/dca/entries/ filtered by other user's strategy should return empty."""
|
||||
response = self.client1.get(
|
||||
f"/api/dca/entries/?strategy={self.user2_strategy.id}"
|
||||
)
|
||||
|
||||
# Either OK with empty results or error
|
||||
if response.status_code == status.HTTP_200_OK:
|
||||
entry_ids = [e["id"] for e in response.data["results"]]
|
||||
self.assertNotIn(self.user2_entry.id, entry_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_dca_entry_detail(self):
|
||||
"""GET /api/dca/entries/{id}/ should deny access to other user's entry."""
|
||||
response = self.client1.get(f"/api/dca/entries/{self.user2_entry.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_access_other_users_strategy_investment_frequency(self):
|
||||
"""investment_frequency action on other user's strategy should deny access."""
|
||||
response = self.client1.get(
|
||||
f"/api/dca/strategies/{self.user2_strategy.id}/investment_frequency/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_access_other_users_strategy_price_comparison(self):
|
||||
"""price_comparison action on other user's strategy should deny access."""
|
||||
response = self.client1.get(
|
||||
f"/api/dca/strategies/{self.user2_strategy.id}/price_comparison/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_access_other_users_strategy_current_price(self):
|
||||
"""current_price action on other user's strategy should deny access."""
|
||||
response = self.client1.get(
|
||||
f"/api/dca/strategies/{self.user2_strategy.id}/current_price/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_dca_strategy(self):
|
||||
"""PATCH on other user's DCA strategy should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/dca/strategies/{self.user2_strategy.id}/",
|
||||
{"name": "Hacked Strategy"},
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_delete_other_users_dca_entry(self):
|
||||
"""DELETE on other user's DCA entry should deny access."""
|
||||
response = self.client1.delete(f"/api/dca/entries/{self.user2_entry.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.assertTrue(DCAEntry.objects.filter(id=self.user2_entry.id).exists())
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class InstallmentRecurringIsolationTests(TestCase):
|
||||
"""Tests for isolation of installment plans and recurring transactions."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's account
|
||||
self.user1_account = Account.all_objects.create(
|
||||
name="User1 Account", currency=self.currency, owner=self.user1
|
||||
)
|
||||
|
||||
# User 2's account
|
||||
self.user2_account = Account.all_objects.create(
|
||||
name="User2 Account", currency=self.currency, owner=self.user2
|
||||
)
|
||||
|
||||
# User 1's installment plan
|
||||
self.user1_installment = InstallmentPlan.all_objects.create(
|
||||
account=self.user1_account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
description="User1 Installment",
|
||||
number_of_installments=12,
|
||||
start_date=date(2025, 1, 1),
|
||||
installment_amount=Decimal("100.00"),
|
||||
)
|
||||
|
||||
# User 2's installment plan
|
||||
self.user2_installment = InstallmentPlan.all_objects.create(
|
||||
account=self.user2_account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
description="User2 Installment",
|
||||
number_of_installments=6,
|
||||
start_date=date(2025, 1, 1),
|
||||
installment_amount=Decimal("200.00"),
|
||||
)
|
||||
|
||||
# User 1's recurring transaction
|
||||
self.user1_recurring = RecurringTransaction.all_objects.create(
|
||||
account=self.user1_account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
amount=Decimal("50.00"),
|
||||
description="User1 Recurring",
|
||||
start_date=date(2025, 1, 1),
|
||||
recurrence_type=RecurringTransaction.RecurrenceType.MONTH,
|
||||
recurrence_interval=1,
|
||||
)
|
||||
|
||||
# User 2's recurring transaction
|
||||
self.user2_recurring = RecurringTransaction.all_objects.create(
|
||||
account=self.user2_account,
|
||||
type=Transaction.Type.INCOME,
|
||||
amount=Decimal("1000.00"),
|
||||
description="User2 Recurring",
|
||||
start_date=date(2025, 1, 1),
|
||||
recurrence_type=RecurringTransaction.RecurrenceType.MONTH,
|
||||
recurrence_interval=1,
|
||||
)
|
||||
|
||||
def test_user_cannot_see_other_users_installment_plans(self):
|
||||
"""GET /api/installment-plans/ should only return user's own plans."""
|
||||
response = self.client1.get("/api/installment-plans/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
plan_ids = [p["id"] for p in response.data["results"]]
|
||||
self.assertIn(self.user1_installment.id, plan_ids)
|
||||
self.assertNotIn(self.user2_installment.id, plan_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_installment_plan_detail(self):
|
||||
"""GET /api/installment-plans/{id}/ should deny access to other user's plan."""
|
||||
response = self.client1.get(
|
||||
f"/api/installment-plans/{self.user2_installment.id}/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_see_other_users_recurring_transactions(self):
|
||||
"""GET /api/recurring-transactions/ should only return user's own recurring."""
|
||||
response = self.client1.get("/api/recurring-transactions/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
recurring_ids = [r["id"] for r in response.data["results"]]
|
||||
self.assertIn(self.user1_recurring.id, recurring_ids)
|
||||
self.assertNotIn(self.user2_recurring.id, recurring_ids)
|
||||
|
||||
def test_user_cannot_access_other_users_recurring_transaction_detail(self):
|
||||
"""GET /api/recurring-transactions/{id}/ should deny access to other user's recurring."""
|
||||
response = self.client1.get(
|
||||
f"/api/recurring-transactions/{self.user2_recurring.id}/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_modify_other_users_installment_plan(self):
|
||||
"""PATCH on other user's installment plan should deny access."""
|
||||
response = self.client1.patch(
|
||||
f"/api/installment-plans/{self.user2_installment.id}/",
|
||||
{"description": "Hacked Installment"},
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_cannot_delete_other_users_recurring_transaction(self):
|
||||
"""DELETE on other user's recurring transaction should deny access."""
|
||||
response = self.client1.delete(
|
||||
f"/api/recurring-transactions/{self.user2_recurring.id}/"
|
||||
)
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
self.assertTrue(
|
||||
RecurringTransaction.all_objects.filter(id=self.user2_recurring.id).exists()
|
||||
)
|
||||
587
app/apps/api/tests/test_shared_access.py
Normal file
587
app/apps/api/tests/test_shared_access.py
Normal file
@@ -0,0 +1,587 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, override_settings
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.accounts.models import Account, AccountGroup
|
||||
from apps.currencies.models import Currency
|
||||
from apps.dca.models import DCAStrategy, DCAEntry
|
||||
from apps.transactions.models import (
|
||||
Transaction,
|
||||
TransactionCategory,
|
||||
TransactionTag,
|
||||
TransactionEntity,
|
||||
)
|
||||
|
||||
|
||||
ACCESS_DENIED_CODES = [status.HTTP_403_FORBIDDEN, status.HTTP_404_NOT_FOUND]
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class SharedAccountAccessTests(TestCase):
|
||||
"""Tests for shared account access via shared_with field."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with shared accounts."""
|
||||
User = get_user_model()
|
||||
|
||||
# User 1 - owner
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
# User 2 - will have shared access
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
# User 3 - no shared access
|
||||
self.user3 = User.objects.create_user(
|
||||
email="user3@test.com", password="testpass123"
|
||||
)
|
||||
self.client3 = APIClient()
|
||||
self.client3.force_authenticate(user=self.user3)
|
||||
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's account shared with user 2
|
||||
self.shared_account = Account.all_objects.create(
|
||||
name="Shared Account",
|
||||
currency=self.currency,
|
||||
owner=self.user1,
|
||||
visibility="private",
|
||||
)
|
||||
self.shared_account.shared_with.add(self.user2)
|
||||
|
||||
# User 1's private account (not shared)
|
||||
self.private_account = Account.all_objects.create(
|
||||
name="Private Account",
|
||||
currency=self.currency,
|
||||
owner=self.user1,
|
||||
visibility="private",
|
||||
)
|
||||
|
||||
# Transaction in shared account
|
||||
self.shared_transaction = Transaction.userless_all_objects.create(
|
||||
account=self.shared_account,
|
||||
type=Transaction.Type.INCOME,
|
||||
amount=Decimal("100.00"),
|
||||
is_paid=True,
|
||||
date=date(2025, 1, 1),
|
||||
description="Shared Transaction",
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
# Transaction in private account
|
||||
self.private_transaction = Transaction.userless_all_objects.create(
|
||||
account=self.private_account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
amount=Decimal("50.00"),
|
||||
is_paid=True,
|
||||
date=date(2025, 1, 1),
|
||||
description="Private Transaction",
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
def test_user_can_see_accounts_shared_with_them(self):
|
||||
"""User2 should see the account shared with them."""
|
||||
response = self.client2.get("/api/accounts/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
account_ids = [acc["id"] for acc in response.data["results"]]
|
||||
self.assertIn(self.shared_account.id, account_ids)
|
||||
|
||||
def test_user_cannot_see_accounts_not_shared_with_them(self):
|
||||
"""User2 should NOT see user1's private (non-shared) account."""
|
||||
response = self.client2.get("/api/accounts/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
account_ids = [acc["id"] for acc in response.data["results"]]
|
||||
self.assertNotIn(self.private_account.id, account_ids)
|
||||
|
||||
def test_user_can_access_shared_account_detail(self):
|
||||
"""User2 should be able to access shared account details."""
|
||||
response = self.client2.get(f"/api/accounts/{self.shared_account.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared Account")
|
||||
|
||||
def test_user_without_share_cannot_access_shared_account(self):
|
||||
"""User3 should NOT be able to access the shared account."""
|
||||
response = self.client3.get(f"/api/accounts/{self.shared_account.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_can_see_transactions_in_shared_account(self):
|
||||
"""User2 should see transactions in the shared account."""
|
||||
response = self.client2.get("/api/transactions/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
transaction_ids = [t["id"] for t in response.data["results"]]
|
||||
self.assertIn(self.shared_transaction.id, transaction_ids)
|
||||
self.assertNotIn(self.private_transaction.id, transaction_ids)
|
||||
|
||||
def test_user_can_access_transaction_in_shared_account(self):
|
||||
"""User2 should be able to access transaction details in shared account."""
|
||||
response = self.client2.get(f"/api/transactions/{self.shared_transaction.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["description"], "Shared Transaction")
|
||||
|
||||
def test_user_cannot_access_transaction_in_non_shared_account(self):
|
||||
"""User2 should NOT access transactions in user1's private account."""
|
||||
response = self.client2.get(f"/api/transactions/{self.private_transaction.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
|
||||
def test_user_can_get_balance_of_shared_account(self):
|
||||
"""User2 should be able to get balance of shared account."""
|
||||
response = self.client2.get(f"/api/accounts/{self.shared_account.id}/balance/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn("current_balance", response.data)
|
||||
|
||||
def test_sharing_works_with_multiple_users(self):
|
||||
"""Account shared with multiple users should be accessible by all."""
|
||||
# Add user3 to shared_with
|
||||
self.shared_account.shared_with.add(self.user3)
|
||||
|
||||
# User2 still has access
|
||||
response2 = self.client2.get(f"/api/accounts/{self.shared_account.id}/")
|
||||
self.assertEqual(response2.status_code, status.HTTP_200_OK)
|
||||
|
||||
# User3 now has access
|
||||
response3 = self.client3.get(f"/api/accounts/{self.shared_account.id}/")
|
||||
self.assertEqual(response3.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class PublicVisibilityTests(TestCase):
|
||||
"""Tests for public visibility access."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with public accounts."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's public account
|
||||
self.public_account = Account.all_objects.create(
|
||||
name="Public Account",
|
||||
currency=self.currency,
|
||||
owner=self.user1,
|
||||
visibility="public",
|
||||
)
|
||||
|
||||
# User 1's private account
|
||||
self.private_account = Account.all_objects.create(
|
||||
name="Private Account",
|
||||
currency=self.currency,
|
||||
owner=self.user1,
|
||||
visibility="private",
|
||||
)
|
||||
|
||||
# Transaction in public account
|
||||
self.public_transaction = Transaction.userless_all_objects.create(
|
||||
account=self.public_account,
|
||||
type=Transaction.Type.INCOME,
|
||||
amount=Decimal("100.00"),
|
||||
is_paid=True,
|
||||
date=date(2025, 1, 1),
|
||||
description="Public Transaction",
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
def test_user_can_see_public_accounts(self):
|
||||
"""User2 should see user1's public account."""
|
||||
response = self.client2.get("/api/accounts/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
account_ids = [acc["id"] for acc in response.data["results"]]
|
||||
self.assertIn(self.public_account.id, account_ids)
|
||||
self.assertNotIn(self.private_account.id, account_ids)
|
||||
|
||||
def test_user_can_access_public_account_detail(self):
|
||||
"""User2 should be able to access public account details."""
|
||||
response = self.client2.get(f"/api/accounts/{self.public_account.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Public Account")
|
||||
|
||||
def test_user_can_see_transactions_in_public_accounts(self):
|
||||
"""User2 should see transactions in public accounts."""
|
||||
response = self.client2.get("/api/transactions/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
transaction_ids = [t["id"] for t in response.data["results"]]
|
||||
self.assertIn(self.public_transaction.id, transaction_ids)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class SharedCategoryTagEntityTests(TestCase):
|
||||
"""Tests for shared categories, tags, and entities."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with shared categories/tags/entities."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
self.user3 = User.objects.create_user(
|
||||
email="user3@test.com", password="testpass123"
|
||||
)
|
||||
self.client3 = APIClient()
|
||||
self.client3.force_authenticate(user=self.user3)
|
||||
|
||||
# User 1's category shared with user 2
|
||||
self.shared_category = TransactionCategory.all_objects.create(
|
||||
name="Shared Category", owner=self.user1
|
||||
)
|
||||
self.shared_category.shared_with.add(self.user2)
|
||||
|
||||
# User 1's private category
|
||||
self.private_category = TransactionCategory.all_objects.create(
|
||||
name="Private Category", owner=self.user1
|
||||
)
|
||||
|
||||
# User 1's public category
|
||||
self.public_category = TransactionCategory.all_objects.create(
|
||||
name="Public Category", owner=self.user1, visibility="public"
|
||||
)
|
||||
|
||||
# User 1's tag shared with user 2
|
||||
self.shared_tag = TransactionTag.all_objects.create(
|
||||
name="Shared Tag", owner=self.user1
|
||||
)
|
||||
self.shared_tag.shared_with.add(self.user2)
|
||||
|
||||
# User 1's entity shared with user 2
|
||||
self.shared_entity = TransactionEntity.all_objects.create(
|
||||
name="Shared Entity", owner=self.user1
|
||||
)
|
||||
self.shared_entity.shared_with.add(self.user2)
|
||||
|
||||
def test_user_can_see_shared_categories(self):
|
||||
"""User2 should see categories shared with them."""
|
||||
response = self.client2.get("/api/categories/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
category_ids = [c["id"] for c in response.data["results"]]
|
||||
self.assertIn(self.shared_category.id, category_ids)
|
||||
self.assertNotIn(self.private_category.id, category_ids)
|
||||
|
||||
def test_user_can_access_shared_category_detail(self):
|
||||
"""User2 should be able to access shared category details."""
|
||||
response = self.client2.get(f"/api/categories/{self.shared_category.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared Category")
|
||||
|
||||
def test_user_can_see_public_categories(self):
|
||||
"""User3 should see public categories."""
|
||||
response = self.client3.get("/api/categories/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
category_ids = [c["id"] for c in response.data["results"]]
|
||||
self.assertIn(self.public_category.id, category_ids)
|
||||
|
||||
def test_user_without_share_cannot_see_shared_category(self):
|
||||
"""User3 should NOT see category shared only with user2."""
|
||||
response = self.client3.get("/api/categories/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
category_ids = [c["id"] for c in response.data["results"]]
|
||||
self.assertNotIn(self.shared_category.id, category_ids)
|
||||
|
||||
def test_user_can_see_shared_tags(self):
|
||||
"""User2 should see tags shared with them."""
|
||||
response = self.client2.get("/api/tags/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
tag_ids = [t["id"] for t in response.data["results"]]
|
||||
self.assertIn(self.shared_tag.id, tag_ids)
|
||||
|
||||
def test_user_can_access_shared_tag_detail(self):
|
||||
"""User2 should be able to access shared tag details."""
|
||||
response = self.client2.get(f"/api/tags/{self.shared_tag.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared Tag")
|
||||
|
||||
def test_user_can_see_shared_entities(self):
|
||||
"""User2 should see entities shared with them."""
|
||||
response = self.client2.get("/api/entities/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
entity_ids = [e["id"] for e in response.data["results"]]
|
||||
self.assertIn(self.shared_entity.id, entity_ids)
|
||||
|
||||
def test_user_can_access_shared_entity_detail(self):
|
||||
"""User2 should be able to access shared entity details."""
|
||||
response = self.client2.get(f"/api/entities/{self.shared_entity.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared Entity")
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class SharedDCAAccessTests(TestCase):
|
||||
"""Tests for shared DCA strategy access."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with shared DCA strategies."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
self.user3 = User.objects.create_user(
|
||||
email="user3@test.com", password="testpass123"
|
||||
)
|
||||
self.client3 = APIClient()
|
||||
self.client3.force_authenticate(user=self.user3)
|
||||
|
||||
self.currency1 = Currency.objects.create(
|
||||
code="BTC", name="Bitcoin", decimal_places=8, prefix=""
|
||||
)
|
||||
self.currency2 = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
|
||||
# User 1's DCA strategy shared with user 2
|
||||
self.shared_strategy = DCAStrategy.all_objects.create(
|
||||
name="Shared BTC Strategy",
|
||||
target_currency=self.currency1,
|
||||
payment_currency=self.currency2,
|
||||
owner=self.user1,
|
||||
)
|
||||
self.shared_strategy.shared_with.add(self.user2)
|
||||
|
||||
# Entry in shared strategy
|
||||
self.shared_entry = DCAEntry.objects.create(
|
||||
strategy=self.shared_strategy,
|
||||
date=date(2025, 1, 1),
|
||||
amount_paid=Decimal("100.00"),
|
||||
amount_received=Decimal("0.001"),
|
||||
)
|
||||
|
||||
# User 1's private strategy
|
||||
self.private_strategy = DCAStrategy.all_objects.create(
|
||||
name="Private BTC Strategy",
|
||||
target_currency=self.currency1,
|
||||
payment_currency=self.currency2,
|
||||
owner=self.user1,
|
||||
)
|
||||
|
||||
def test_user_can_see_shared_dca_strategies(self):
|
||||
"""User2 should see DCA strategies shared with them."""
|
||||
response = self.client2.get("/api/dca/strategies/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
strategy_ids = [s["id"] for s in response.data["results"]]
|
||||
self.assertIn(self.shared_strategy.id, strategy_ids)
|
||||
self.assertNotIn(self.private_strategy.id, strategy_ids)
|
||||
|
||||
def test_user_can_access_shared_dca_strategy_detail(self):
|
||||
"""User2 should be able to access shared strategy details."""
|
||||
response = self.client2.get(f"/api/dca/strategies/{self.shared_strategy.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared BTC Strategy")
|
||||
|
||||
def test_user_without_share_cannot_see_shared_strategy(self):
|
||||
"""User3 should NOT see strategy shared only with user2."""
|
||||
response = self.client3.get("/api/dca/strategies/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
strategy_ids = [s["id"] for s in response.data["results"]]
|
||||
self.assertNotIn(self.shared_strategy.id, strategy_ids)
|
||||
|
||||
def test_user_can_access_shared_strategy_actions(self):
|
||||
"""User2 should be able to access actions on shared strategy."""
|
||||
# investment_frequency
|
||||
response1 = self.client2.get(
|
||||
f"/api/dca/strategies/{self.shared_strategy.id}/investment_frequency/"
|
||||
)
|
||||
self.assertEqual(response1.status_code, status.HTTP_200_OK)
|
||||
|
||||
# price_comparison
|
||||
response2 = self.client2.get(
|
||||
f"/api/dca/strategies/{self.shared_strategy.id}/price_comparison/"
|
||||
)
|
||||
self.assertEqual(response2.status_code, status.HTTP_200_OK)
|
||||
|
||||
# current_price
|
||||
response3 = self.client2.get(
|
||||
f"/api/dca/strategies/{self.shared_strategy.id}/current_price/"
|
||||
)
|
||||
self.assertEqual(response3.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class SharedAccountGroupTests(TestCase):
|
||||
"""Tests for shared account group access."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data with shared account groups."""
|
||||
User = get_user_model()
|
||||
|
||||
self.user1 = User.objects.create_user(
|
||||
email="user1@test.com", password="testpass123"
|
||||
)
|
||||
self.client1 = APIClient()
|
||||
self.client1.force_authenticate(user=self.user1)
|
||||
|
||||
self.user2 = User.objects.create_user(
|
||||
email="user2@test.com", password="testpass123"
|
||||
)
|
||||
self.client2 = APIClient()
|
||||
self.client2.force_authenticate(user=self.user2)
|
||||
|
||||
self.user3 = User.objects.create_user(
|
||||
email="user3@test.com", password="testpass123"
|
||||
)
|
||||
self.client3 = APIClient()
|
||||
self.client3.force_authenticate(user=self.user3)
|
||||
|
||||
# User 1's account group shared with user 2
|
||||
self.shared_group = AccountGroup.all_objects.create(
|
||||
name="Shared Group", owner=self.user1
|
||||
)
|
||||
self.shared_group.shared_with.add(self.user2)
|
||||
|
||||
# User 1's private account group
|
||||
self.private_group = AccountGroup.all_objects.create(
|
||||
name="Private Group", owner=self.user1
|
||||
)
|
||||
|
||||
# User 1's public account group
|
||||
self.public_group = AccountGroup.all_objects.create(
|
||||
name="Public Group", owner=self.user1, visibility="public"
|
||||
)
|
||||
|
||||
def test_user_can_see_shared_account_groups(self):
|
||||
"""User2 should see account groups shared with them."""
|
||||
response = self.client2.get("/api/account-groups/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
group_ids = [g["id"] for g in response.data["results"]]
|
||||
self.assertIn(self.shared_group.id, group_ids)
|
||||
self.assertNotIn(self.private_group.id, group_ids)
|
||||
|
||||
def test_user_can_access_shared_account_group_detail(self):
|
||||
"""User2 should be able to access shared account group details."""
|
||||
response = self.client2.get(f"/api/account-groups/{self.shared_group.id}/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["name"], "Shared Group")
|
||||
|
||||
def test_user_can_see_public_account_groups(self):
|
||||
"""User3 should see public account groups."""
|
||||
response = self.client3.get("/api/account-groups/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
group_ids = [g["id"] for g in response.data["results"]]
|
||||
self.assertIn(self.public_group.id, group_ids)
|
||||
|
||||
def test_user_without_share_cannot_access_shared_group(self):
|
||||
"""User3 should NOT be able to access shared account group."""
|
||||
response = self.client3.get(f"/api/account-groups/{self.shared_group.id}/")
|
||||
|
||||
self.assertIn(response.status_code, ACCESS_DENIED_CODES)
|
||||
@@ -6,8 +6,11 @@ from rest_framework.response import Response
|
||||
|
||||
from apps.accounts.models import AccountGroup, Account
|
||||
from apps.accounts.services import get_account_balance
|
||||
from apps.api.custom.pagination import CustomPageNumberPagination
|
||||
from apps.api.serializers import AccountGroupSerializer, AccountSerializer, AccountBalanceSerializer
|
||||
from apps.api.serializers import (
|
||||
AccountGroupSerializer,
|
||||
AccountSerializer,
|
||||
AccountBalanceSerializer,
|
||||
)
|
||||
|
||||
|
||||
class AccountGroupViewSet(viewsets.ModelViewSet):
|
||||
@@ -15,10 +18,16 @@ class AccountGroupViewSet(viewsets.ModelViewSet):
|
||||
|
||||
queryset = AccountGroup.objects.all()
|
||||
serializer_class = AccountGroupSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return AccountGroup.objects.all().order_by("id")
|
||||
return AccountGroup.objects.all()
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
@@ -33,28 +42,38 @@ class AccountViewSet(viewsets.ModelViewSet):
|
||||
|
||||
queryset = Account.objects.all()
|
||||
serializer_class = AccountSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"group": ["exact", "isnull"],
|
||||
"currency": ["exact"],
|
||||
"exchange_currency": ["exact", "isnull"],
|
||||
"is_asset": ["exact"],
|
||||
"is_archived": ["exact"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
Account.objects.all()
|
||||
.order_by("id")
|
||||
.select_related("group", "currency", "exchange_currency")
|
||||
return Account.objects.all().select_related(
|
||||
"group", "currency", "exchange_currency"
|
||||
)
|
||||
|
||||
@action(detail=True, methods=["get"], permission_classes=[IsAuthenticated])
|
||||
def balance(self, request, pk=None):
|
||||
"""Get current and projected balance for an account."""
|
||||
account = self.get_object()
|
||||
|
||||
|
||||
current_balance = get_account_balance(account, paid_only=True)
|
||||
projected_balance = get_account_balance(account, paid_only=False)
|
||||
|
||||
serializer = AccountBalanceSerializer({
|
||||
"current_balance": current_balance,
|
||||
"projected_balance": projected_balance,
|
||||
"currency": account.currency,
|
||||
})
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
serializer = AccountBalanceSerializer(
|
||||
{
|
||||
"current_balance": current_balance,
|
||||
"projected_balance": projected_balance,
|
||||
"currency": account.currency,
|
||||
}
|
||||
)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
@@ -9,8 +9,28 @@ from apps.currencies.models import ExchangeRate
|
||||
class CurrencyViewSet(viewsets.ModelViewSet):
|
||||
queryset = Currency.objects.all()
|
||||
serializer_class = CurrencySerializer
|
||||
filterset_fields = {
|
||||
'name': ['exact', 'icontains'],
|
||||
'code': ['exact', 'icontains'],
|
||||
'decimal_places': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'prefix': ['exact', 'icontains'],
|
||||
'suffix': ['exact', 'icontains'],
|
||||
'exchange_currency': ['exact'],
|
||||
'is_archived': ['exact'],
|
||||
}
|
||||
search_fields = '__all__'
|
||||
ordering_fields = '__all__'
|
||||
|
||||
|
||||
class ExchangeRateViewSet(viewsets.ModelViewSet):
|
||||
queryset = ExchangeRate.objects.all()
|
||||
serializer_class = ExchangeRateSerializer
|
||||
filterset_fields = {
|
||||
'from_currency': ['exact'],
|
||||
'to_currency': ['exact'],
|
||||
'rate': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'date': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'automatic': ['exact'],
|
||||
}
|
||||
search_fields = '__all__'
|
||||
ordering_fields = '__all__'
|
||||
|
||||
@@ -8,6 +8,19 @@ from apps.api.serializers import DCAStrategySerializer, DCAEntrySerializer
|
||||
class DCAStrategyViewSet(viewsets.ModelViewSet):
|
||||
queryset = DCAStrategy.objects.all()
|
||||
serializer_class = DCAStrategySerializer
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"target_currency": ["exact"],
|
||||
"payment_currency": ["exact"],
|
||||
"notes": ["exact", "icontains"],
|
||||
"created_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"updated_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
}
|
||||
search_fields = ["name", "notes"]
|
||||
ordering_fields = "__all__"
|
||||
|
||||
def get_queryset(self):
|
||||
return DCAStrategy.objects.all()
|
||||
|
||||
@action(detail=True, methods=["get"])
|
||||
def investment_frequency(self, request, pk=None):
|
||||
@@ -32,10 +45,22 @@ class DCAStrategyViewSet(viewsets.ModelViewSet):
|
||||
class DCAEntryViewSet(viewsets.ModelViewSet):
|
||||
queryset = DCAEntry.objects.all()
|
||||
serializer_class = DCAEntrySerializer
|
||||
filterset_fields = {
|
||||
"strategy": ["exact"],
|
||||
"date": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"amount_paid": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"amount_received": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"expense_transaction": ["exact", "isnull"],
|
||||
"income_transaction": ["exact", "isnull"],
|
||||
"notes": ["exact", "icontains"],
|
||||
"created_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"updated_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
}
|
||||
search_fields = ["notes"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["-date"]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = DCAEntry.objects.all()
|
||||
strategy_id = self.request.query_params.get("strategy", None)
|
||||
if strategy_id is not None:
|
||||
queryset = queryset.filter(strategy_id=strategy_id)
|
||||
return queryset
|
||||
# Filter entries by strategies the user has access to
|
||||
accessible_strategies = DCAStrategy.objects.all()
|
||||
return DCAEntry.objects.filter(strategy__in=accessible_strategies)
|
||||
|
||||
@@ -28,6 +28,14 @@ class ImportProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = ImportProfile.objects.all()
|
||||
serializer_class = ImportProfileSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = {
|
||||
'name': ['exact', 'icontains'],
|
||||
'yaml_config': ['exact', 'icontains'],
|
||||
'version': ['exact'],
|
||||
}
|
||||
search_fields = ['name', 'yaml_config']
|
||||
ordering_fields = '__all__'
|
||||
ordering = ['name']
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
@@ -55,6 +63,22 @@ class ImportRunViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = ImportRun.objects.all().order_by("-id")
|
||||
serializer_class = ImportRunSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = {
|
||||
'status': ['exact'],
|
||||
'profile': ['exact'],
|
||||
'file_name': ['exact', 'icontains'],
|
||||
'logs': ['exact', 'icontains'],
|
||||
'processed_rows': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'total_rows': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'successful_rows': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'skipped_rows': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'failed_rows': ['exact', 'gte', 'lte', 'gt', 'lt'],
|
||||
'started_at': ['exact', 'gte', 'lte', 'gt', 'lt', 'isnull'],
|
||||
'finished_at': ['exact', 'gte', 'lte', 'gt', 'lt', 'isnull'],
|
||||
}
|
||||
search_fields = ['file_name', 'logs']
|
||||
ordering_fields = '__all__'
|
||||
ordering = ['-id']
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
|
||||
@@ -2,7 +2,6 @@ from copy import deepcopy
|
||||
|
||||
from rest_framework import viewsets
|
||||
|
||||
from apps.api.custom.pagination import CustomPageNumberPagination
|
||||
from apps.api.serializers import (
|
||||
TransactionSerializer,
|
||||
TransactionCategorySerializer,
|
||||
@@ -25,7 +24,34 @@ from apps.rules.signals import transaction_updated, transaction_created
|
||||
class TransactionViewSet(viewsets.ModelViewSet):
|
||||
queryset = Transaction.objects.all()
|
||||
serializer_class = TransactionSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"account": ["exact"],
|
||||
"type": ["exact"],
|
||||
"is_paid": ["exact"],
|
||||
"date": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"reference_date": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"mute": ["exact"],
|
||||
"amount": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"description": ["exact", "icontains"],
|
||||
"notes": ["exact", "icontains"],
|
||||
"category": ["exact", "isnull"],
|
||||
"installment_plan": ["exact", "isnull"],
|
||||
"installment_id": ["exact", "gte", "lte"],
|
||||
"recurring_transaction": ["exact", "isnull"],
|
||||
"internal_note": ["exact", "icontains"],
|
||||
"internal_id": ["exact"],
|
||||
"deleted": ["exact"],
|
||||
"created_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"updated_at": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"deleted_at": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["description", "notes", "internal_note"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["-id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return Transaction.objects.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
instance = serializer.save()
|
||||
@@ -40,50 +66,109 @@ class TransactionViewSet(viewsets.ModelViewSet):
|
||||
kwargs["partial"] = True
|
||||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return Transaction.objects.all().order_by("-id")
|
||||
|
||||
|
||||
class TransactionCategoryViewSet(viewsets.ModelViewSet):
|
||||
queryset = TransactionCategory.objects.all()
|
||||
serializer_class = TransactionCategorySerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"mute": ["exact"],
|
||||
"active": ["exact"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return TransactionCategory.objects.all().order_by("id")
|
||||
return TransactionCategory.objects.all()
|
||||
|
||||
|
||||
class TransactionTagViewSet(viewsets.ModelViewSet):
|
||||
queryset = TransactionTag.objects.all()
|
||||
serializer_class = TransactionTagSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"active": ["exact"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return TransactionTag.objects.all().order_by("id")
|
||||
return TransactionTag.objects.all()
|
||||
|
||||
|
||||
class TransactionEntityViewSet(viewsets.ModelViewSet):
|
||||
queryset = TransactionEntity.objects.all()
|
||||
serializer_class = TransactionEntitySerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"name": ["exact", "icontains"],
|
||||
"active": ["exact"],
|
||||
"owner": ["exact"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return TransactionEntity.objects.all().order_by("id")
|
||||
return TransactionEntity.objects.all()
|
||||
|
||||
|
||||
class InstallmentPlanViewSet(viewsets.ModelViewSet):
|
||||
queryset = InstallmentPlan.objects.all()
|
||||
serializer_class = InstallmentPlanSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"account": ["exact"],
|
||||
"type": ["exact"],
|
||||
"description": ["exact", "icontains"],
|
||||
"number_of_installments": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"installment_start": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"installment_total_number": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"start_date": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"reference_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"end_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"recurrence": ["exact"],
|
||||
"installment_amount": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"category": ["exact", "isnull"],
|
||||
"notes": ["exact", "icontains"],
|
||||
"add_description_to_transaction": ["exact"],
|
||||
"add_notes_to_transaction": ["exact"],
|
||||
}
|
||||
search_fields = ["description", "notes"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["-id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return InstallmentPlan.objects.all().order_by("-id")
|
||||
return InstallmentPlan.objects.all()
|
||||
|
||||
|
||||
class RecurringTransactionViewSet(viewsets.ModelViewSet):
|
||||
queryset = RecurringTransaction.objects.all()
|
||||
serializer_class = RecurringTransactionSerializer
|
||||
pagination_class = CustomPageNumberPagination
|
||||
filterset_fields = {
|
||||
"is_paused": ["exact"],
|
||||
"account": ["exact"],
|
||||
"type": ["exact"],
|
||||
"amount": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"description": ["exact", "icontains"],
|
||||
"category": ["exact", "isnull"],
|
||||
"notes": ["exact", "icontains"],
|
||||
"reference_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"start_date": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"end_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"recurrence_type": ["exact"],
|
||||
"recurrence_interval": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"keep_at_most": ["exact", "gte", "lte", "gt", "lt"],
|
||||
"last_generated_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"last_generated_reference_date": ["exact", "gte", "lte", "gt", "lt", "isnull"],
|
||||
"add_description_to_transaction": ["exact"],
|
||||
"add_notes_to_transaction": ["exact"],
|
||||
}
|
||||
search_fields = ["description", "notes"]
|
||||
ordering_fields = "__all__"
|
||||
ordering = ["-id"]
|
||||
|
||||
def get_queryset(self):
|
||||
return RecurringTransaction.objects.all().order_by("-id")
|
||||
return RecurringTransaction.objects.all()
|
||||
|
||||
@@ -23,3 +23,6 @@ class CommonConfig(AppConfig):
|
||||
# Delete the cache for update checks to prevent false-positives when the app is restarted
|
||||
# this will be recreated by the check_for_updates task
|
||||
cache.delete("update_check")
|
||||
|
||||
# Register system checks for required environment variables
|
||||
from apps.common import checks # noqa: F401
|
||||
|
||||
103
app/apps/common/checks.py
Normal file
103
app/apps/common/checks.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
Django System Checks for required environment variables.
|
||||
|
||||
This module validates that required environment variables (those without defaults)
|
||||
are present before the application starts.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.checks import Error, register
|
||||
|
||||
|
||||
# List of environment variables that are required (no default values)
|
||||
# Based on the README.md documentation
|
||||
REQUIRED_ENV_VARS = [
|
||||
("SECRET_KEY", "This is used to provide cryptographic signing."),
|
||||
("SQL_DATABASE", "The name of your postgres database."),
|
||||
]
|
||||
|
||||
# List of environment variables that must be valid integers if set
|
||||
INT_ENV_VARS = [
|
||||
("TASK_WORKERS", "How many workers to have for async tasks."),
|
||||
("SESSION_EXPIRY_TIME", "The age of session cookies, in seconds."),
|
||||
("INTERNAL_PORT", "The port on which the app listens on."),
|
||||
("DJANGO_VITE_DEV_SERVER_PORT", "The port where Vite's dev server is running"),
|
||||
]
|
||||
|
||||
|
||||
@register()
|
||||
def check_required_env_vars(app_configs, **kwargs):
|
||||
"""
|
||||
Check that all required environment variables are set.
|
||||
|
||||
Returns a list of Error objects for any missing required variables.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for var_name, description in REQUIRED_ENV_VARS:
|
||||
value = os.getenv(var_name)
|
||||
if not value:
|
||||
errors.append(
|
||||
Error(
|
||||
f"Required environment variable '{var_name}' is not set.",
|
||||
hint=f"{description} Please set this variable in your .env file or environment.",
|
||||
id="wygiwyh.E001",
|
||||
)
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@register()
|
||||
def check_int_env_vars(app_configs, **kwargs):
|
||||
"""
|
||||
Check that environment variables that should be integers are valid.
|
||||
|
||||
Returns a list of Error objects for any invalid integer variables.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for var_name, description in INT_ENV_VARS:
|
||||
value = os.getenv(var_name)
|
||||
if value is not None:
|
||||
try:
|
||||
int(value)
|
||||
except ValueError:
|
||||
errors.append(
|
||||
Error(
|
||||
f"Environment variable '{var_name}' must be a valid integer, got '{value}'.",
|
||||
hint=f"{description}",
|
||||
id="wygiwyh.E002",
|
||||
)
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@register()
|
||||
def check_soft_delete_config(app_configs, **kwargs):
|
||||
"""
|
||||
Check that KEEP_DELETED_TRANSACTIONS_FOR is a valid integer when ENABLE_SOFT_DELETE is enabled.
|
||||
|
||||
Returns a list of Error objects if the configuration is invalid.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
enable_soft_delete = os.getenv("ENABLE_SOFT_DELETE", "false").lower() == "true"
|
||||
|
||||
if enable_soft_delete:
|
||||
keep_deleted_for = os.getenv("KEEP_DELETED_TRANSACTIONS_FOR")
|
||||
if keep_deleted_for is not None:
|
||||
try:
|
||||
int(keep_deleted_for)
|
||||
except ValueError:
|
||||
errors.append(
|
||||
Error(
|
||||
f"Environment variable 'KEEP_DELETED_TRANSACTIONS_FOR' must be a valid integer when ENABLE_SOFT_DELETE is enabled, got '{keep_deleted_for}'.",
|
||||
hint="Time in days to keep soft deleted transactions for. Set to 0 to keep all transactions indefinitely.",
|
||||
id="wygiwyh.E003",
|
||||
)
|
||||
)
|
||||
|
||||
return errors
|
||||
@@ -1,5 +1,4 @@
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from django.db.models import QuerySet
|
||||
from django.utils import timezone
|
||||
@@ -258,7 +257,10 @@ class ExchangeRateFetcher:
|
||||
processed_pairs.add((from_currency.id, to_currency.id))
|
||||
|
||||
service.last_fetch = timezone.now()
|
||||
service.failure_count = 0
|
||||
service.save()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching rates for {service.name}: {e}")
|
||||
service.failure_count += 1
|
||||
service.save()
|
||||
|
||||
18
app/apps/currencies/migrations/0023_add_failure_count.py
Normal file
18
app/apps/currencies/migrations/0023_add_failure_count.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-10 06:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('currencies', '0022_currency_is_archived'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='exchangerateservice',
|
||||
name='failure_count',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
]
|
||||
@@ -136,6 +136,8 @@ class ExchangeRateService(models.Model):
|
||||
null=True, blank=True, verbose_name=_("Last Successful Fetch")
|
||||
)
|
||||
|
||||
failure_count = models.PositiveIntegerField(default=0)
|
||||
|
||||
target_currencies = models.ManyToManyField(
|
||||
Currency,
|
||||
verbose_name=_("Target Currencies"),
|
||||
@@ -237,7 +239,7 @@ class ExchangeRateService(models.Model):
|
||||
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:
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
{
|
||||
"fetch_interval": _(
|
||||
@@ -248,7 +250,7 @@ class ExchangeRateService(models.Model):
|
||||
)
|
||||
except ValidationError:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
raise ValidationError(
|
||||
{
|
||||
"fetch_interval": _(
|
||||
|
||||
1
app/apps/currencies/tests/__init__.py
Normal file
1
app/apps/currencies/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests package for currencies app
|
||||
109
app/apps/currencies/tests/test_automatic_exchange_rates.py
Normal file
109
app/apps/currencies/tests/test_automatic_exchange_rates.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from decimal import Decimal
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.currencies.models import Currency, ExchangeRateService
|
||||
from apps.currencies.exchange_rates.fetcher import ExchangeRateFetcher
|
||||
|
||||
|
||||
class ExchangeRateServiceFailureTrackingTests(TestCase):
|
||||
"""Tests for the failure count tracking functionality."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data."""
|
||||
self.usd = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
self.eur = Currency.objects.create(
|
||||
code="EUR", name="Euro", decimal_places=2, prefix="€ "
|
||||
)
|
||||
self.eur.exchange_currency = self.usd
|
||||
self.eur.save()
|
||||
|
||||
self.service = ExchangeRateService.objects.create(
|
||||
name="Test Service",
|
||||
service_type=ExchangeRateService.ServiceType.FRANKFURTER,
|
||||
is_active=True,
|
||||
)
|
||||
self.service.target_currencies.add(self.eur)
|
||||
|
||||
def test_failure_count_increments_on_provider_error(self):
|
||||
"""Test that failure_count increments when provider raises an exception."""
|
||||
self.assertEqual(self.service.failure_count, 0)
|
||||
|
||||
with patch.object(
|
||||
self.service, "get_provider", side_effect=Exception("API Error")
|
||||
):
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
|
||||
self.service.refresh_from_db()
|
||||
self.assertEqual(self.service.failure_count, 1)
|
||||
|
||||
def test_failure_count_resets_on_success(self):
|
||||
"""Test that failure_count resets to 0 on successful fetch."""
|
||||
# Set initial failure count
|
||||
self.service.failure_count = 5
|
||||
self.service.save()
|
||||
|
||||
# Mock a successful provider
|
||||
mock_provider = MagicMock()
|
||||
mock_provider.requires_api_key.return_value = False
|
||||
mock_provider.get_rates.return_value = [(self.usd, self.eur, Decimal("0.85"))]
|
||||
mock_provider.rates_inverted = False
|
||||
|
||||
with patch.object(self.service, "get_provider", return_value=mock_provider):
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
|
||||
self.service.refresh_from_db()
|
||||
self.assertEqual(self.service.failure_count, 0)
|
||||
|
||||
def test_failure_count_accumulates_across_fetches(self):
|
||||
"""Test that failure_count accumulates with consecutive failures."""
|
||||
self.assertEqual(self.service.failure_count, 0)
|
||||
|
||||
with patch.object(
|
||||
self.service, "get_provider", side_effect=Exception("API Error")
|
||||
):
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
self.service.refresh_from_db()
|
||||
self.assertEqual(self.service.failure_count, 1)
|
||||
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
self.service.refresh_from_db()
|
||||
self.assertEqual(self.service.failure_count, 2)
|
||||
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
self.service.refresh_from_db()
|
||||
self.assertEqual(self.service.failure_count, 3)
|
||||
|
||||
def test_last_fetch_not_updated_on_failure(self):
|
||||
"""Test that last_fetch is NOT updated when a failure occurs."""
|
||||
original_last_fetch = self.service.last_fetch
|
||||
self.assertIsNone(original_last_fetch)
|
||||
|
||||
with patch.object(
|
||||
self.service, "get_provider", side_effect=Exception("API Error")
|
||||
):
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
|
||||
self.service.refresh_from_db()
|
||||
self.assertIsNone(self.service.last_fetch)
|
||||
self.assertEqual(self.service.failure_count, 1)
|
||||
|
||||
def test_last_fetch_updated_on_success(self):
|
||||
"""Test that last_fetch IS updated when fetch succeeds."""
|
||||
self.assertIsNone(self.service.last_fetch)
|
||||
|
||||
mock_provider = MagicMock()
|
||||
mock_provider.requires_api_key.return_value = False
|
||||
mock_provider.get_rates.return_value = [(self.usd, self.eur, Decimal("0.85"))]
|
||||
mock_provider.rates_inverted = False
|
||||
|
||||
with patch.object(self.service, "get_provider", return_value=mock_provider):
|
||||
ExchangeRateFetcher._fetch_service_rates(self.service)
|
||||
|
||||
self.service.refresh_from_db()
|
||||
self.assertIsNotNone(self.service.last_fetch)
|
||||
self.assertEqual(self.service.failure_count, 0)
|
||||
@@ -23,7 +23,7 @@ def currencies_index(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def currencies_list(request):
|
||||
currencies = Currency.objects.all().order_by("id")
|
||||
currencies = Currency.objects.all().order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"currencies/fragments/list.html",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# apps/dca_tracker/views.py
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Sum, Avg
|
||||
@@ -23,7 +22,7 @@ def strategy_index(request):
|
||||
@only_htmx
|
||||
@login_required
|
||||
def strategy_list(request):
|
||||
strategies = DCAStrategy.objects.all().order_by("created_at")
|
||||
strategies = DCAStrategy.objects.all().order_by("name")
|
||||
return render(
|
||||
request, "dca/fragments/strategy/list.html", {"strategies": strategies}
|
||||
)
|
||||
@@ -234,7 +233,7 @@ def strategy_entry_add(request, strategy_id):
|
||||
if request.method == "POST":
|
||||
form = DCAEntryForm(request.POST, strategy=strategy)
|
||||
if form.is_valid():
|
||||
entry = form.save()
|
||||
form.save()
|
||||
messages.success(request, _("Entry added successfully"))
|
||||
|
||||
return HttpResponse(
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
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.foreign_key import (
|
||||
AllObjectsForeignKeyWidget,
|
||||
AutoCreateForeignKeyWidget,
|
||||
)
|
||||
from apps.export_app.widgets.many_to_many import AutoCreateManyToManyWidget
|
||||
from apps.export_app.widgets.string import EmptyStringToNoneField
|
||||
from apps.transactions.models import (
|
||||
@@ -20,7 +22,7 @@ class TransactionResource(resources.ModelResource):
|
||||
account = fields.Field(
|
||||
attribute="account",
|
||||
column_name="account",
|
||||
widget=ForeignKeyWidget(Account, "name"),
|
||||
widget=AllObjectsForeignKeyWidget(Account, "name"),
|
||||
)
|
||||
|
||||
category = fields.Field(
|
||||
@@ -86,7 +88,7 @@ class RecurringTransactionResource(resources.ModelResource):
|
||||
account = fields.Field(
|
||||
attribute="account",
|
||||
column_name="account",
|
||||
widget=ForeignKeyWidget(Account, "name"),
|
||||
widget=AllObjectsForeignKeyWidget(Account, "name"),
|
||||
)
|
||||
|
||||
category = fields.Field(
|
||||
@@ -119,12 +121,16 @@ class RecurringTransactionResource(resources.ModelResource):
|
||||
def get_queryset(self):
|
||||
return RecurringTransaction.all_objects.all()
|
||||
|
||||
def dehydrate_account_owner(self, obj):
|
||||
"""Export the account's owner ID for proper import matching."""
|
||||
return obj.account.owner_id if obj.account else None
|
||||
|
||||
|
||||
class InstallmentPlanResource(resources.ModelResource):
|
||||
account = fields.Field(
|
||||
attribute="account",
|
||||
column_name="account",
|
||||
widget=ForeignKeyWidget(Account, "name"),
|
||||
widget=AllObjectsForeignKeyWidget(Account, "name"),
|
||||
)
|
||||
|
||||
category = fields.Field(
|
||||
@@ -156,3 +162,7 @@ class InstallmentPlanResource(resources.ModelResource):
|
||||
|
||||
def get_queryset(self):
|
||||
return InstallmentPlan.all_objects.all()
|
||||
|
||||
def dehydrate_account_owner(self, obj):
|
||||
"""Export the account's owner ID for proper import matching."""
|
||||
return obj.account.owner_id if obj.account else None
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
from import_export.widgets import ForeignKeyWidget
|
||||
|
||||
|
||||
class AllObjectsForeignKeyWidget(ForeignKeyWidget):
|
||||
"""
|
||||
ForeignKeyWidget that uses 'all_objects' manager for lookups,
|
||||
bypassing user-filtered managers like SharedObjectManager.
|
||||
Also filters by owner if available in the row data.
|
||||
"""
|
||||
|
||||
def get_queryset(self, value, row, *args, **kwargs):
|
||||
# Use all_objects manager if available, otherwise fall back to default
|
||||
if hasattr(self.model, "all_objects"):
|
||||
qs = self.model.all_objects.all()
|
||||
# Filter by owner if the row has an owner field and the model has owner
|
||||
if row:
|
||||
# Check for direct owner field first
|
||||
owner_id = row.get("owner") if "owner" in row else None
|
||||
# Fall back to account_owner for models like InstallmentPlan
|
||||
if not owner_id and "account_owner" in row:
|
||||
owner_id = row.get("account_owner")
|
||||
# If still no owner, try to get it from the existing record's account
|
||||
# This handles backward compatibility with older exports
|
||||
if not owner_id and "id" in row and row.get("id"):
|
||||
try:
|
||||
# Try to find the existing record and get owner from its account
|
||||
from apps.transactions.models import (
|
||||
InstallmentPlan,
|
||||
RecurringTransaction,
|
||||
)
|
||||
|
||||
record_id = row.get("id")
|
||||
# Try to find the existing InstallmentPlan or RecurringTransaction
|
||||
for model_class in [InstallmentPlan, RecurringTransaction]:
|
||||
try:
|
||||
existing = model_class.all_objects.get(id=record_id)
|
||||
if existing.account:
|
||||
owner_id = existing.account.owner_id
|
||||
break
|
||||
except model_class.DoesNotExist:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
# Final fallback: use the current logged-in user
|
||||
# This handles restoring to a fresh database with older exports
|
||||
if not owner_id:
|
||||
from apps.common.middleware.thread_local import get_current_user
|
||||
|
||||
user = get_current_user()
|
||||
if user and user.is_authenticated:
|
||||
owner_id = user.id
|
||||
if owner_id:
|
||||
qs = qs.filter(owner_id=owner_id)
|
||||
return qs
|
||||
return super().get_queryset(value, row, *args, **kwargs)
|
||||
|
||||
|
||||
class AutoCreateForeignKeyWidget(ForeignKeyWidget):
|
||||
def clean(self, value, row=None, *args, **kwargs):
|
||||
if value:
|
||||
|
||||
@@ -8,7 +8,6 @@ is only used for string fields (not dates, decimals, etc.).
|
||||
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
@@ -49,4 +49,14 @@ urlpatterns = [
|
||||
views.emergency_fund,
|
||||
name="insights_emergency_fund",
|
||||
),
|
||||
path(
|
||||
"insights/year-by-year/",
|
||||
views.year_by_year,
|
||||
name="insights_year_by_year",
|
||||
),
|
||||
path(
|
||||
"insights/month-by-month/",
|
||||
views.month_by_month,
|
||||
name="insights_month_by_month",
|
||||
),
|
||||
]
|
||||
|
||||
316
app/apps/insights/utils/month_by_month.py
Normal file
316
app/apps/insights/utils/month_by_month.py
Normal file
@@ -0,0 +1,316 @@
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Sum, Case, When, Value
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.currencies.models import Currency
|
||||
from apps.currencies.utils.convert import convert
|
||||
from apps.transactions.models import Transaction
|
||||
|
||||
|
||||
def get_month_by_month_data(year=None, group_by="categories"):
|
||||
"""
|
||||
Aggregate transaction totals by month for a specific year, grouped by categories, tags, or entities.
|
||||
|
||||
Args:
|
||||
year: The year to filter transactions (defaults to current year)
|
||||
group_by: One of "categories", "tags", or "entities"
|
||||
|
||||
Returns:
|
||||
{
|
||||
"year": 2025,
|
||||
"available_years": [2025, 2024, ...],
|
||||
"months": [1, 2, 3, ..., 12],
|
||||
"items": {
|
||||
item_id: {
|
||||
"name": "Item Name",
|
||||
"month_totals": {
|
||||
1: {"currencies": {...}},
|
||||
...
|
||||
},
|
||||
"total": {"currencies": {...}}
|
||||
},
|
||||
...
|
||||
},
|
||||
"month_totals": {...},
|
||||
"grand_total": {"currencies": {...}}
|
||||
}
|
||||
"""
|
||||
if year is None:
|
||||
year = timezone.localdate(timezone.now()).year
|
||||
|
||||
# Base queryset - all paid transactions, non-muted
|
||||
transactions = Transaction.objects.filter(
|
||||
is_paid=True,
|
||||
account__is_archived=False,
|
||||
).exclude(account__currency__is_archived=True)
|
||||
|
||||
# Get available years for the selector
|
||||
available_years = list(
|
||||
transactions.values_list("reference_date__year", flat=True)
|
||||
.distinct()
|
||||
.order_by("-reference_date__year")
|
||||
)
|
||||
|
||||
# Filter by the selected year
|
||||
transactions = transactions.filter(reference_date__year=year)
|
||||
|
||||
# Define grouping fields based on group_by parameter
|
||||
if group_by == "tags":
|
||||
group_field = "tags"
|
||||
name_field = "tags__name"
|
||||
elif group_by == "entities":
|
||||
group_field = "entities"
|
||||
name_field = "entities__name"
|
||||
else: # Default to categories
|
||||
group_field = "category"
|
||||
name_field = "category__name"
|
||||
|
||||
# Months 1-12
|
||||
months = list(range(1, 13))
|
||||
|
||||
if not available_years:
|
||||
return {
|
||||
"year": year,
|
||||
"available_years": [],
|
||||
"months": months,
|
||||
"items": {},
|
||||
"month_totals": {},
|
||||
"grand_total": {"currencies": {}},
|
||||
}
|
||||
|
||||
# Aggregate by group, month, and currency
|
||||
metrics = (
|
||||
transactions.values(
|
||||
group_field,
|
||||
name_field,
|
||||
"reference_date__month",
|
||||
"account__currency",
|
||||
"account__currency__code",
|
||||
"account__currency__name",
|
||||
"account__currency__decimal_places",
|
||||
"account__currency__prefix",
|
||||
"account__currency__suffix",
|
||||
"account__currency__exchange_currency",
|
||||
)
|
||||
.annotate(
|
||||
expense_total=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(type=Transaction.Type.EXPENSE, then="amount"),
|
||||
default=Value(0),
|
||||
output_field=models.DecimalField(),
|
||||
)
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
income_total=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(type=Transaction.Type.INCOME, then="amount"),
|
||||
default=Value(0),
|
||||
output_field=models.DecimalField(),
|
||||
)
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
)
|
||||
.order_by(name_field, "reference_date__month")
|
||||
)
|
||||
|
||||
# Build result structure
|
||||
result = {
|
||||
"year": year,
|
||||
"available_years": available_years,
|
||||
"months": months,
|
||||
"items": OrderedDict(),
|
||||
"month_totals": {},
|
||||
"grand_total": {"currencies": {}},
|
||||
}
|
||||
|
||||
# Store currency info for later use in totals
|
||||
currency_info = {}
|
||||
|
||||
for metric in metrics:
|
||||
item_id = metric[group_field]
|
||||
item_name = metric[name_field]
|
||||
month = metric["reference_date__month"]
|
||||
currency_id = metric["account__currency"]
|
||||
|
||||
# Use a consistent key for None (uncategorized/untagged/no entity)
|
||||
item_key = item_id if item_id is not None else "__none__"
|
||||
|
||||
if item_key not in result["items"]:
|
||||
result["items"][item_key] = {
|
||||
"name": item_name,
|
||||
"month_totals": {},
|
||||
"total": {"currencies": {}},
|
||||
}
|
||||
|
||||
if month not in result["items"][item_key]["month_totals"]:
|
||||
result["items"][item_key]["month_totals"][month] = {"currencies": {}}
|
||||
|
||||
# Calculate final total (income - expense)
|
||||
final_total = metric["income_total"] - metric["expense_total"]
|
||||
|
||||
# Store currency info for totals calculation
|
||||
if currency_id not in currency_info:
|
||||
currency_info[currency_id] = {
|
||||
"code": metric["account__currency__code"],
|
||||
"name": metric["account__currency__name"],
|
||||
"decimal_places": metric["account__currency__decimal_places"],
|
||||
"prefix": metric["account__currency__prefix"],
|
||||
"suffix": metric["account__currency__suffix"],
|
||||
"exchange_currency_id": metric["account__currency__exchange_currency"],
|
||||
}
|
||||
|
||||
currency_data = {
|
||||
"currency": {
|
||||
"code": metric["account__currency__code"],
|
||||
"name": metric["account__currency__name"],
|
||||
"decimal_places": metric["account__currency__decimal_places"],
|
||||
"prefix": metric["account__currency__prefix"],
|
||||
"suffix": metric["account__currency__suffix"],
|
||||
},
|
||||
"final_total": final_total,
|
||||
"income_total": metric["income_total"],
|
||||
"expense_total": metric["expense_total"],
|
||||
}
|
||||
|
||||
# Handle currency conversion if exchange currency is set
|
||||
if metric["account__currency__exchange_currency"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=metric["account__currency__exchange_currency"]
|
||||
)
|
||||
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=final_total,
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
|
||||
if converted_amount is not None:
|
||||
currency_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
result["items"][item_key]["month_totals"][month]["currencies"][currency_id] = (
|
||||
currency_data
|
||||
)
|
||||
|
||||
# Accumulate item total (across all months for this item)
|
||||
if currency_id not in result["items"][item_key]["total"]["currencies"]:
|
||||
result["items"][item_key]["total"]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["items"][item_key]["total"]["currencies"][currency_id][
|
||||
"final_total"
|
||||
] += final_total
|
||||
|
||||
# Accumulate month total (across all items for this month)
|
||||
if month not in result["month_totals"]:
|
||||
result["month_totals"][month] = {"currencies": {}}
|
||||
if currency_id not in result["month_totals"][month]["currencies"]:
|
||||
result["month_totals"][month]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["month_totals"][month]["currencies"][currency_id]["final_total"] += (
|
||||
final_total
|
||||
)
|
||||
|
||||
# Accumulate grand total
|
||||
if currency_id not in result["grand_total"]["currencies"]:
|
||||
result["grand_total"]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["grand_total"]["currencies"][currency_id]["final_total"] += final_total
|
||||
|
||||
# Add currency conversion for item totals
|
||||
for item_key, item_data in result["items"].items():
|
||||
for currency_id, total_data in item_data["total"]["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
# Add currency conversion for month totals
|
||||
for month, month_data in result["month_totals"].items():
|
||||
for currency_id, total_data in month_data["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
# Add currency conversion for grand total
|
||||
for currency_id, total_data in result["grand_total"]["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
return result
|
||||
303
app/apps/insights/utils/year_by_year.py
Normal file
303
app/apps/insights/utils/year_by_year.py
Normal file
@@ -0,0 +1,303 @@
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Sum, Case, When, Value
|
||||
from django.db.models.functions import Coalesce
|
||||
|
||||
from apps.currencies.models import Currency
|
||||
from apps.currencies.utils.convert import convert
|
||||
from apps.transactions.models import Transaction
|
||||
|
||||
|
||||
def get_year_by_year_data(group_by="categories"):
|
||||
"""
|
||||
Aggregate transaction totals by year for categories, tags, or entities.
|
||||
|
||||
Args:
|
||||
group_by: One of "categories", "tags", or "entities"
|
||||
|
||||
Returns:
|
||||
{
|
||||
"years": [2025, 2024, ...], # Sorted descending
|
||||
"items": {
|
||||
item_id: {
|
||||
"name": "Item Name",
|
||||
"year_totals": {
|
||||
2025: {"currencies": {...}},
|
||||
...
|
||||
},
|
||||
"total": {"currencies": {...}} # Sum across all years
|
||||
},
|
||||
...
|
||||
},
|
||||
"year_totals": { # Sum across all items for each year
|
||||
2025: {"currencies": {...}},
|
||||
...
|
||||
},
|
||||
"grand_total": {"currencies": {...}} # Sum of everything
|
||||
}
|
||||
"""
|
||||
# Base queryset - all paid transactions, non-muted
|
||||
transactions = Transaction.objects.filter(
|
||||
is_paid=True,
|
||||
account__is_archived=False,
|
||||
).exclude(account__currency__is_archived=True)
|
||||
|
||||
# Define grouping fields based on group_by parameter
|
||||
if group_by == "tags":
|
||||
group_field = "tags"
|
||||
name_field = "tags__name"
|
||||
elif group_by == "entities":
|
||||
group_field = "entities"
|
||||
name_field = "entities__name"
|
||||
else: # Default to categories
|
||||
group_field = "category"
|
||||
name_field = "category__name"
|
||||
|
||||
# Get all unique years with transactions
|
||||
years = (
|
||||
transactions.values_list("reference_date__year", flat=True)
|
||||
.distinct()
|
||||
.order_by("-reference_date__year")
|
||||
)
|
||||
years = list(years)
|
||||
|
||||
if not years:
|
||||
return {
|
||||
"years": [],
|
||||
"items": {},
|
||||
"year_totals": {},
|
||||
"grand_total": {"currencies": {}},
|
||||
}
|
||||
|
||||
# Aggregate by group, year, and currency
|
||||
metrics = (
|
||||
transactions.values(
|
||||
group_field,
|
||||
name_field,
|
||||
"reference_date__year",
|
||||
"account__currency",
|
||||
"account__currency__code",
|
||||
"account__currency__name",
|
||||
"account__currency__decimal_places",
|
||||
"account__currency__prefix",
|
||||
"account__currency__suffix",
|
||||
"account__currency__exchange_currency",
|
||||
)
|
||||
.annotate(
|
||||
expense_total=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(type=Transaction.Type.EXPENSE, then="amount"),
|
||||
default=Value(0),
|
||||
output_field=models.DecimalField(),
|
||||
)
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
income_total=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(type=Transaction.Type.INCOME, then="amount"),
|
||||
default=Value(0),
|
||||
output_field=models.DecimalField(),
|
||||
)
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
)
|
||||
.order_by(name_field, "-reference_date__year")
|
||||
)
|
||||
|
||||
# Build result structure
|
||||
result = {
|
||||
"years": years,
|
||||
"items": OrderedDict(),
|
||||
"year_totals": {}, # Totals per year across all items
|
||||
"grand_total": {"currencies": {}}, # Grand total across everything
|
||||
}
|
||||
|
||||
# Store currency info for later use in totals
|
||||
currency_info = {}
|
||||
|
||||
for metric in metrics:
|
||||
item_id = metric[group_field]
|
||||
item_name = metric[name_field]
|
||||
year = metric["reference_date__year"]
|
||||
currency_id = metric["account__currency"]
|
||||
|
||||
# Use a consistent key for None (uncategorized/untagged/no entity)
|
||||
item_key = item_id if item_id is not None else "__none__"
|
||||
|
||||
if item_key not in result["items"]:
|
||||
result["items"][item_key] = {
|
||||
"name": item_name,
|
||||
"year_totals": {},
|
||||
"total": {"currencies": {}}, # Total for this item across all years
|
||||
}
|
||||
|
||||
if year not in result["items"][item_key]["year_totals"]:
|
||||
result["items"][item_key]["year_totals"][year] = {"currencies": {}}
|
||||
|
||||
# Calculate final total (income - expense)
|
||||
final_total = metric["income_total"] - metric["expense_total"]
|
||||
|
||||
# Store currency info for totals calculation
|
||||
if currency_id not in currency_info:
|
||||
currency_info[currency_id] = {
|
||||
"code": metric["account__currency__code"],
|
||||
"name": metric["account__currency__name"],
|
||||
"decimal_places": metric["account__currency__decimal_places"],
|
||||
"prefix": metric["account__currency__prefix"],
|
||||
"suffix": metric["account__currency__suffix"],
|
||||
"exchange_currency_id": metric["account__currency__exchange_currency"],
|
||||
}
|
||||
|
||||
currency_data = {
|
||||
"currency": {
|
||||
"code": metric["account__currency__code"],
|
||||
"name": metric["account__currency__name"],
|
||||
"decimal_places": metric["account__currency__decimal_places"],
|
||||
"prefix": metric["account__currency__prefix"],
|
||||
"suffix": metric["account__currency__suffix"],
|
||||
},
|
||||
"final_total": final_total,
|
||||
"income_total": metric["income_total"],
|
||||
"expense_total": metric["expense_total"],
|
||||
}
|
||||
|
||||
# Handle currency conversion if exchange currency is set
|
||||
if metric["account__currency__exchange_currency"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=metric["account__currency__exchange_currency"]
|
||||
)
|
||||
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=final_total,
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
|
||||
if converted_amount is not None:
|
||||
currency_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
result["items"][item_key]["year_totals"][year]["currencies"][currency_id] = (
|
||||
currency_data
|
||||
)
|
||||
|
||||
# Accumulate item total (across all years for this item)
|
||||
if currency_id not in result["items"][item_key]["total"]["currencies"]:
|
||||
result["items"][item_key]["total"]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["items"][item_key]["total"]["currencies"][currency_id][
|
||||
"final_total"
|
||||
] += final_total
|
||||
|
||||
# Accumulate year total (across all items for this year)
|
||||
if year not in result["year_totals"]:
|
||||
result["year_totals"][year] = {"currencies": {}}
|
||||
if currency_id not in result["year_totals"][year]["currencies"]:
|
||||
result["year_totals"][year]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["year_totals"][year]["currencies"][currency_id]["final_total"] += (
|
||||
final_total
|
||||
)
|
||||
|
||||
# Accumulate grand total
|
||||
if currency_id not in result["grand_total"]["currencies"]:
|
||||
result["grand_total"]["currencies"][currency_id] = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"final_total": Decimal("0"),
|
||||
}
|
||||
result["grand_total"]["currencies"][currency_id]["final_total"] += final_total
|
||||
|
||||
# Add currency conversion for item totals
|
||||
for item_key, item_data in result["items"].items():
|
||||
for currency_id, total_data in item_data["total"]["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
# Add currency conversion for year totals
|
||||
for year, year_data in result["year_totals"].items():
|
||||
for currency_id, total_data in year_data["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
# Add currency conversion for grand total
|
||||
for currency_id, total_data in result["grand_total"]["currencies"].items():
|
||||
if currency_info[currency_id]["exchange_currency_id"]:
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = Currency.objects.get(
|
||||
id=currency_info[currency_id]["exchange_currency_id"]
|
||||
)
|
||||
converted_amount, prefix, suffix, decimal_places = convert(
|
||||
amount=total_data["final_total"],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
)
|
||||
if converted_amount is not None:
|
||||
total_data["exchanged"] = {
|
||||
"final_total": converted_amount,
|
||||
"currency": {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
},
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -26,6 +26,8 @@ from apps.insights.utils.sankey import (
|
||||
generate_sankey_data_by_currency,
|
||||
)
|
||||
from apps.insights.utils.transactions import get_transactions
|
||||
from apps.insights.utils.year_by_year import get_year_by_year_data
|
||||
from apps.insights.utils.month_by_month import get_month_by_month_data
|
||||
from apps.transactions.models import TransactionCategory, Transaction
|
||||
from apps.transactions.utils.calculations import calculate_currency_totals
|
||||
|
||||
@@ -306,3 +308,71 @@ def emergency_fund(request):
|
||||
"insights/fragments/emergency_fund.html",
|
||||
{"data": currency_net_worth},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def year_by_year(request):
|
||||
if "group_by" in request.GET:
|
||||
group_by = request.GET["group_by"]
|
||||
request.session["insights_year_by_year_group_by"] = group_by
|
||||
else:
|
||||
group_by = request.session.get("insights_year_by_year_group_by", "categories")
|
||||
|
||||
# Validate group_by value
|
||||
if group_by not in ("categories", "tags", "entities"):
|
||||
group_by = "categories"
|
||||
|
||||
data = get_year_by_year_data(group_by=group_by)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"insights/fragments/year_by_year.html",
|
||||
{
|
||||
"data": data,
|
||||
"group_by": group_by,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def month_by_month(request):
|
||||
# Handle year selection
|
||||
if "year" in request.GET:
|
||||
try:
|
||||
year = int(request.GET["year"])
|
||||
request.session["insights_month_by_month_year"] = year
|
||||
except (ValueError, TypeError):
|
||||
year = request.session.get(
|
||||
"insights_month_by_month_year", timezone.localdate(timezone.now()).year
|
||||
)
|
||||
else:
|
||||
year = request.session.get(
|
||||
"insights_month_by_month_year", timezone.localdate(timezone.now()).year
|
||||
)
|
||||
|
||||
# Handle group_by selection
|
||||
if "group_by" in request.GET:
|
||||
group_by = request.GET["group_by"]
|
||||
request.session["insights_month_by_month_group_by"] = group_by
|
||||
else:
|
||||
group_by = request.session.get("insights_month_by_month_group_by", "categories")
|
||||
|
||||
# Validate group_by value
|
||||
if group_by not in ("categories", "tags", "entities"):
|
||||
group_by = "categories"
|
||||
|
||||
data = get_month_by_month_data(year=year, group_by=group_by)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"insights/fragments/month_by_month.html",
|
||||
{
|
||||
"data": data,
|
||||
"group_by": group_by,
|
||||
"selected_year": year,
|
||||
},
|
||||
)
|
||||
|
||||
0
app/apps/monthly_overview/tests/__init__.py
Normal file
0
app/apps/monthly_overview/tests/__init__.py
Normal file
331
app/apps/monthly_overview/tests/test_summary.py
Normal file
331
app/apps/monthly_overview/tests/test_summary.py
Normal file
@@ -0,0 +1,331 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from apps.accounts.models import Account, AccountGroup
|
||||
from apps.currencies.models import Currency
|
||||
from apps.transactions.models import (
|
||||
Transaction,
|
||||
TransactionCategory,
|
||||
TransactionTag,
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
WHITENOISE_AUTOREFRESH=True,
|
||||
)
|
||||
class MonthlySummaryFilterBehaviorTests(TestCase):
|
||||
"""Tests for monthly summary views filter behavior.
|
||||
|
||||
These tests verify that:
|
||||
1. Views work correctly without any filters
|
||||
2. Views work correctly with filters applied
|
||||
3. The filter detection logic properly uses different querysets
|
||||
4. Calculated values reflect the applied filters
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test data"""
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(
|
||||
email="testuser@test.com", password="testpass123"
|
||||
)
|
||||
self.client.login(username="testuser@test.com", password="testpass123")
|
||||
|
||||
self.currency = Currency.objects.create(
|
||||
code="USD", name="US Dollar", decimal_places=2, prefix="$ "
|
||||
)
|
||||
self.account_group = AccountGroup.objects.create(name="Test Group")
|
||||
self.account = Account.objects.create(
|
||||
name="Test Account",
|
||||
group=self.account_group,
|
||||
currency=self.currency,
|
||||
is_asset=False,
|
||||
)
|
||||
self.category = TransactionCategory.objects.create(
|
||||
name="Test Category", owner=self.user
|
||||
)
|
||||
self.tag = TransactionTag.objects.create(name="TestTag", owner=self.user)
|
||||
|
||||
# Create test transactions for December 2025
|
||||
# Income: 1000 (paid)
|
||||
self.income_transaction = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.INCOME,
|
||||
is_paid=True,
|
||||
date=date(2025, 12, 10),
|
||||
reference_date=date(2025, 12, 1),
|
||||
amount=Decimal("1000.00"),
|
||||
description="December Income",
|
||||
owner=self.user,
|
||||
)
|
||||
|
||||
# Expense: 200 (paid)
|
||||
self.expense_transaction = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
is_paid=True,
|
||||
date=date(2025, 12, 15),
|
||||
reference_date=date(2025, 12, 1),
|
||||
amount=Decimal("200.00"),
|
||||
description="December Expense",
|
||||
category=self.category,
|
||||
owner=self.user,
|
||||
)
|
||||
self.expense_transaction.tags.add(self.tag)
|
||||
|
||||
# Expense: 150 (projected/unpaid)
|
||||
self.projected_expense = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
is_paid=False,
|
||||
date=date(2025, 12, 20),
|
||||
reference_date=date(2025, 12, 1),
|
||||
amount=Decimal("150.00"),
|
||||
description="Projected Expense",
|
||||
owner=self.user,
|
||||
)
|
||||
|
||||
def _get_currency_data(self, context_dict):
|
||||
"""Helper to extract data for our test currency from context dict.
|
||||
|
||||
The context dict is keyed by currency ID, so we need to find
|
||||
the entry for our currency.
|
||||
"""
|
||||
if not context_dict:
|
||||
return None
|
||||
for currency_id, data in context_dict.items():
|
||||
if data.get("currency", {}).get("code") == "USD":
|
||||
return data
|
||||
return None
|
||||
|
||||
# --- monthly_summary view tests ---
|
||||
|
||||
def test_monthly_summary_no_filter_returns_200(self):
|
||||
"""Test that monthly_summary returns 200 without filters"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_monthly_summary_no_filter_includes_all_transactions(self):
|
||||
"""Without filters, summary should include all transactions"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# income_current should have the income: 1000
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["income_current"], Decimal("1000.00"))
|
||||
|
||||
# expense_current should have paid expense: 200
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_current"], Decimal("200.00"))
|
||||
|
||||
# expense_projected should have unpaid expense: 150
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_projected"], Decimal("150.00"))
|
||||
|
||||
def test_monthly_summary_type_filter_only_income(self):
|
||||
"""With type=IN filter, summary should only include income"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?type=IN",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# income_current should still have 1000
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["income_current"], Decimal("1000.00"))
|
||||
|
||||
# expense_current should be empty/zero (filtered out)
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("expense_current", 0), Decimal("0"))
|
||||
|
||||
# expense_projected should be empty/zero (filtered out)
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("expense_projected", 0), Decimal("0"))
|
||||
|
||||
def test_monthly_summary_type_filter_only_expenses(self):
|
||||
"""With type=EX filter, summary should only include expenses"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?type=EX",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# income_current should be empty/zero (filtered out)
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("income_current", 0), Decimal("0"))
|
||||
|
||||
# expense_current should have 200
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_current"], Decimal("200.00"))
|
||||
|
||||
# expense_projected should have 150
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_projected"], Decimal("150.00"))
|
||||
|
||||
def test_monthly_summary_is_paid_filter_only_paid(self):
|
||||
"""With is_paid=1 filter, summary should only include paid transactions"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?is_paid=1",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# income_current should have 1000 (paid)
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["income_current"], Decimal("1000.00"))
|
||||
|
||||
# expense_current should have 200 (paid)
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_current"], Decimal("200.00"))
|
||||
|
||||
# expense_projected should be empty/zero (filtered out - unpaid)
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("expense_projected", 0), Decimal("0"))
|
||||
|
||||
def test_monthly_summary_is_paid_filter_only_unpaid(self):
|
||||
"""With is_paid=0 filter, summary should only include unpaid transactions"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?is_paid=0",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# income_current should be empty/zero (filtered out - paid)
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("income_current", 0), Decimal("0"))
|
||||
|
||||
# expense_current should be empty/zero (filtered out - paid)
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("expense_current", 0), Decimal("0"))
|
||||
|
||||
# expense_projected should have 150 (unpaid)
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_projected"], Decimal("150.00"))
|
||||
|
||||
def test_monthly_summary_description_filter(self):
|
||||
"""With description filter, summary should only include matching transactions"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?description=Income",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# Only income matches "Income" description
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["income_current"], Decimal("1000.00"))
|
||||
|
||||
# Expenses should be filtered out
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("expense_current", 0), Decimal("0"))
|
||||
|
||||
def test_monthly_summary_amount_filter(self):
|
||||
"""With amount filter, summary should only include transactions in range"""
|
||||
# Filter to only get transactions between 100 and 250 (should get 200 and 150)
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/?from_amount=100&to_amount=250",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
context = response.context
|
||||
|
||||
# Income (1000) should be filtered out
|
||||
income_current = context.get("income_current", {})
|
||||
usd_data = self._get_currency_data(income_current)
|
||||
if usd_data:
|
||||
self.assertEqual(usd_data.get("income_current", 0), Decimal("0"))
|
||||
|
||||
# expense_current should have 200
|
||||
expense_current = context.get("expense_current", {})
|
||||
usd_data = self._get_currency_data(expense_current)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_current"], Decimal("200.00"))
|
||||
|
||||
# expense_projected should have 150
|
||||
expense_projected = context.get("expense_projected", {})
|
||||
usd_data = self._get_currency_data(expense_projected)
|
||||
self.assertIsNotNone(usd_data)
|
||||
self.assertEqual(usd_data["expense_projected"], Decimal("150.00"))
|
||||
|
||||
# --- monthly_account_summary view tests ---
|
||||
|
||||
def test_monthly_account_summary_no_filter_returns_200(self):
|
||||
"""Test that monthly_account_summary returns 200 without filters"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/accounts/",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_monthly_account_summary_with_filter_returns_200(self):
|
||||
"""Test that monthly_account_summary returns 200 with filter"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/accounts/?type=IN",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# --- monthly_currency_summary view tests ---
|
||||
|
||||
def test_monthly_currency_summary_no_filter_returns_200(self):
|
||||
"""Test that monthly_currency_summary returns 200 without filters"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/currencies/",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_monthly_currency_summary_with_filter_returns_200(self):
|
||||
"""Test that monthly_currency_summary returns 200 with filter"""
|
||||
response = self.client.get(
|
||||
"/monthly/12/2025/summary/currencies/?type=EX",
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -2,7 +2,8 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import (
|
||||
Q,
|
||||
)
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, Http404
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_http_methods
|
||||
@@ -36,8 +37,6 @@ def monthly_overview(request, month: int, year: int):
|
||||
summary_tab = request.session.get("monthly_summary_tab", "summary")
|
||||
|
||||
if month < 1 or month > 12:
|
||||
from django.http import Http404
|
||||
|
||||
raise Http404("Month is out of range")
|
||||
|
||||
next_month = 1 if month == 12 else month + 1
|
||||
@@ -76,6 +75,8 @@ def transactions_list(request, month: int, year: int):
|
||||
if order != request.session.get("monthly_transactions_order", "default"):
|
||||
request.session["monthly_transactions_order"] = order
|
||||
|
||||
today = timezone.localdate(timezone.now())
|
||||
|
||||
f = TransactionsFilter(request.GET)
|
||||
transactions_filtered = f.qs.filter(
|
||||
reference_date__year=year,
|
||||
@@ -93,12 +94,28 @@ def transactions_list(request, month: int, year: int):
|
||||
"dca_income_entries",
|
||||
)
|
||||
|
||||
# Late transactions: date < today and is_paid = False (only shown for default ordering)
|
||||
late_transactions = None
|
||||
if order == "default":
|
||||
late_transactions = transactions_filtered.filter(
|
||||
date__lt=today,
|
||||
is_paid=False,
|
||||
).order_by("date", "id")
|
||||
# Exclude late transactions from the main list
|
||||
transactions_filtered = transactions_filtered.exclude(
|
||||
date__lt=today,
|
||||
is_paid=False,
|
||||
)
|
||||
|
||||
transactions_filtered = default_order(transactions_filtered, order=order)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"monthly_overview/fragments/list.html",
|
||||
context={"transactions": transactions_filtered},
|
||||
context={
|
||||
"transactions": transactions_filtered,
|
||||
"late_transactions": late_transactions,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -107,17 +124,48 @@ def transactions_list(request, month: int, year: int):
|
||||
@require_http_methods(["GET"])
|
||||
def monthly_summary(request, month: int, year: int):
|
||||
# Base queryset with all required filters
|
||||
base_queryset = (
|
||||
Transaction.objects.filter(
|
||||
reference_date__year=year,
|
||||
reference_date__month=month,
|
||||
account__is_asset=False,
|
||||
)
|
||||
.exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||
.exclude(account__in=request.user.untracked_accounts.all())
|
||||
base_queryset = Transaction.objects.filter(
|
||||
reference_date__year=year,
|
||||
reference_date__month=month,
|
||||
)
|
||||
|
||||
data = calculate_currency_totals(base_queryset, ignore_empty=True)
|
||||
# Apply filters and check if any are active
|
||||
f = TransactionsFilter(request.GET, queryset=base_queryset)
|
||||
|
||||
# Check if any filter has a non-default value
|
||||
# Default values are: type=['IN', 'EX'], is_paid=['1', '0'], everything else empty
|
||||
has_active_filter = False
|
||||
if f.form.is_valid():
|
||||
for name, value in f.form.cleaned_data.items():
|
||||
# Skip fields with default/empty values
|
||||
if not value:
|
||||
continue
|
||||
# Skip type if it has both default values
|
||||
if name == "type" and set(value) == {"IN", "EX"}:
|
||||
continue
|
||||
# Skip is_paid if it has both default values (values are strings)
|
||||
if name == "is_paid" and set(value) == {"1", "0"}:
|
||||
continue
|
||||
# Skip mute_status if it has both default values
|
||||
if name == "mute_status" and set(value) == {"active", "muted"}:
|
||||
continue
|
||||
# If we get here, there's an active filter
|
||||
has_active_filter = True
|
||||
break
|
||||
|
||||
if has_active_filter:
|
||||
queryset = f.qs
|
||||
else:
|
||||
queryset = (
|
||||
base_queryset.exclude(
|
||||
Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)
|
||||
)
|
||||
.exclude(account__in=request.user.untracked_accounts.all())
|
||||
.exclude(account__is_asset=True)
|
||||
)
|
||||
|
||||
data = calculate_currency_totals(queryset, ignore_empty=True)
|
||||
|
||||
percentages = calculate_percentage_distribution(data)
|
||||
|
||||
context = {
|
||||
@@ -132,6 +180,7 @@ def monthly_summary(request, month: int, year: int):
|
||||
currency_totals=data, month=month, year=year
|
||||
),
|
||||
"percentages": percentages,
|
||||
"has_active_filter": has_active_filter,
|
||||
}
|
||||
|
||||
return render(
|
||||
@@ -149,9 +198,38 @@ def monthly_account_summary(request, month: int, year: int):
|
||||
base_queryset = Transaction.objects.filter(
|
||||
reference_date__year=year,
|
||||
reference_date__month=month,
|
||||
).exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||
)
|
||||
|
||||
account_data = calculate_account_totals(transactions_queryset=base_queryset.all())
|
||||
# Apply filters and check if any are active
|
||||
f = TransactionsFilter(request.GET, queryset=base_queryset)
|
||||
|
||||
# Check if any filter has a non-default value
|
||||
has_active_filter = False
|
||||
if f.form.is_valid():
|
||||
for name, value in f.form.cleaned_data.items():
|
||||
if not value:
|
||||
continue
|
||||
if name == "type" and set(value) == {"IN", "EX"}:
|
||||
continue
|
||||
if name == "is_paid" and set(value) == {"1", "0"}:
|
||||
continue
|
||||
if name == "mute_status" and set(value) == {"active", "muted"}:
|
||||
continue
|
||||
has_active_filter = True
|
||||
break
|
||||
|
||||
if has_active_filter:
|
||||
queryset = f.qs
|
||||
else:
|
||||
queryset = (
|
||||
base_queryset.exclude(
|
||||
Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)
|
||||
)
|
||||
.exclude(account__in=request.user.untracked_accounts.all())
|
||||
.exclude(account__is_asset=True)
|
||||
)
|
||||
|
||||
account_data = calculate_account_totals(transactions_queryset=queryset.all())
|
||||
account_percentages = calculate_percentage_distribution(account_data)
|
||||
|
||||
context = {
|
||||
@@ -171,16 +249,41 @@ def monthly_account_summary(request, month: int, year: int):
|
||||
@require_http_methods(["GET"])
|
||||
def monthly_currency_summary(request, month: int, year: int):
|
||||
# Base queryset with all required filters
|
||||
base_queryset = (
|
||||
Transaction.objects.filter(
|
||||
reference_date__year=year,
|
||||
reference_date__month=month,
|
||||
)
|
||||
.exclude(Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True))
|
||||
.exclude(account__in=request.user.untracked_accounts.all())
|
||||
base_queryset = Transaction.objects.filter(
|
||||
reference_date__year=year,
|
||||
reference_date__month=month,
|
||||
)
|
||||
|
||||
currency_data = calculate_currency_totals(base_queryset.all(), ignore_empty=True)
|
||||
# Apply filters and check if any are active
|
||||
f = TransactionsFilter(request.GET, queryset=base_queryset)
|
||||
|
||||
# Check if any filter has a non-default value
|
||||
has_active_filter = False
|
||||
if f.form.is_valid():
|
||||
for name, value in f.form.cleaned_data.items():
|
||||
if not value:
|
||||
continue
|
||||
if name == "type" and set(value) == {"IN", "EX"}:
|
||||
continue
|
||||
if name == "is_paid" and set(value) == {"1", "0"}:
|
||||
continue
|
||||
if name == "mute_status" and set(value) == {"active", "muted"}:
|
||||
continue
|
||||
has_active_filter = True
|
||||
break
|
||||
|
||||
if has_active_filter:
|
||||
queryset = f.qs
|
||||
else:
|
||||
queryset = (
|
||||
base_queryset.exclude(
|
||||
Q(Q(category__mute=True) & ~Q(category=None)) | Q(mute=True)
|
||||
)
|
||||
.exclude(account__in=request.user.untracked_accounts.all())
|
||||
.exclude(account__is_asset=True)
|
||||
)
|
||||
|
||||
currency_data = calculate_currency_totals(queryset.all(), ignore_empty=True)
|
||||
currency_percentages = calculate_percentage_distribution(currency_data)
|
||||
|
||||
context = {
|
||||
|
||||
@@ -23,6 +23,11 @@ SITUACAO_CHOICES = (
|
||||
("0", _("Projected")),
|
||||
)
|
||||
|
||||
MUTE_STATUS_CHOICES = (
|
||||
("active", _("Active")),
|
||||
("muted", _("Muted")),
|
||||
)
|
||||
|
||||
|
||||
def content_filter(queryset, name, value):
|
||||
queryset = queryset.filter(
|
||||
@@ -78,6 +83,11 @@ class TransactionsFilter(django_filters.FilterSet):
|
||||
choices=SITUACAO_CHOICES,
|
||||
field_name="is_paid",
|
||||
)
|
||||
mute_status = django_filters.MultipleChoiceFilter(
|
||||
choices=MUTE_STATUS_CHOICES,
|
||||
method="filter_mute_status",
|
||||
label=_("Mute Status"),
|
||||
)
|
||||
date_start = django_filters.DateFilter(
|
||||
field_name="date",
|
||||
lookup_expr="gte",
|
||||
@@ -140,6 +150,9 @@ class TransactionsFilter(django_filters.FilterSet):
|
||||
if data.get("is_paid") is None:
|
||||
data.setlist("is_paid", ["1", "0"])
|
||||
|
||||
if data.get("mute_status") is None:
|
||||
data.setlist("mute_status", ["active", "muted"])
|
||||
|
||||
super().__init__(data, *args, **kwargs)
|
||||
|
||||
self.form.helper = FormHelper()
|
||||
@@ -155,6 +168,10 @@ class TransactionsFilter(django_filters.FilterSet):
|
||||
"is_paid",
|
||||
template="transactions/widgets/transaction_type_filter_buttons.html",
|
||||
),
|
||||
Field(
|
||||
"mute_status",
|
||||
template="transactions/widgets/transaction_type_filter_buttons.html",
|
||||
),
|
||||
Field("description"),
|
||||
Row(Column("date_start"), Column("date_end")),
|
||||
Row(
|
||||
@@ -268,3 +285,36 @@ class TransactionsFilter(django_filters.FilterSet):
|
||||
return queryset.filter(q).distinct()
|
||||
|
||||
return queryset
|
||||
|
||||
@staticmethod
|
||||
def filter_mute_status(queryset, name, value):
|
||||
from apps.common.middleware.thread_local import get_current_user
|
||||
|
||||
if not value:
|
||||
return queryset
|
||||
|
||||
value = list(value)
|
||||
|
||||
# If both are selected, return all
|
||||
if "active" in value and "muted" in value:
|
||||
return queryset
|
||||
|
||||
user = get_current_user()
|
||||
|
||||
# Only Active selected: exclude muted transactions
|
||||
if "active" in value:
|
||||
return (
|
||||
queryset.exclude(account__untracked_by=user)
|
||||
.filter(
|
||||
mute=False,
|
||||
)
|
||||
.filter(Q(category__mute=False) | Q(category__isnull=True))
|
||||
)
|
||||
|
||||
# Only Muted selected: include only muted transactions
|
||||
if "muted" in value:
|
||||
return queryset.filter(
|
||||
Q(account__untracked_by=user) | Q(category__mute=True) | Q(mute=True)
|
||||
)
|
||||
|
||||
return queryset
|
||||
|
||||
@@ -383,6 +383,10 @@ class Transaction(OwnedObject):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
# Convert empty internal_id to None to allow multiple "empty" values with unique constraint
|
||||
if self.internal_id == "":
|
||||
self.internal_id = None
|
||||
|
||||
# Only process amount and reference_date if account exists
|
||||
# If account is missing, Django's required field validation will handle it
|
||||
try:
|
||||
|
||||
@@ -125,6 +125,70 @@ class TransactionTests(TestCase):
|
||||
datetime.datetime(day=1, month=2, year=2000).date(),
|
||||
)
|
||||
|
||||
def test_empty_internal_id_converts_to_none(self):
|
||||
"""Test that empty string internal_id is converted to None"""
|
||||
transaction = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction",
|
||||
internal_id="", # Empty string should become None
|
||||
)
|
||||
self.assertIsNone(transaction.internal_id)
|
||||
|
||||
def test_unique_internal_id_works(self):
|
||||
"""Test that unique non-empty internal_id values work correctly"""
|
||||
transaction1 = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction 1",
|
||||
internal_id="unique-id-123",
|
||||
)
|
||||
transaction2 = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction 2",
|
||||
internal_id="unique-id-456",
|
||||
)
|
||||
self.assertEqual(transaction1.internal_id, "unique-id-123")
|
||||
self.assertEqual(transaction2.internal_id, "unique-id-456")
|
||||
|
||||
def test_multiple_transactions_with_empty_internal_id(self):
|
||||
"""Test that multiple transactions can have empty/None internal_id"""
|
||||
transaction1 = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction 1",
|
||||
internal_id="",
|
||||
)
|
||||
transaction2 = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction 2",
|
||||
internal_id="",
|
||||
)
|
||||
transaction3 = Transaction.objects.create(
|
||||
account=self.account,
|
||||
type=Transaction.Type.EXPENSE,
|
||||
date=timezone.now().date(),
|
||||
amount=Decimal("100.00"),
|
||||
description="Test transaction 3",
|
||||
internal_id=None,
|
||||
)
|
||||
# All should be saved successfully with None internal_id
|
||||
self.assertIsNone(transaction1.internal_id)
|
||||
self.assertIsNone(transaction2.internal_id)
|
||||
self.assertIsNone(transaction3.internal_id)
|
||||
|
||||
|
||||
class InstallmentPlanTests(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -35,7 +35,7 @@ def categories_list(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def categories_table_active(request):
|
||||
categories = TransactionCategory.objects.filter(active=True).order_by("id")
|
||||
categories = TransactionCategory.objects.filter(active=True).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"categories/fragments/table.html",
|
||||
@@ -47,7 +47,7 @@ def categories_table_active(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def categories_table_archived(request):
|
||||
categories = TransactionCategory.objects.filter(active=False).order_by("id")
|
||||
categories = TransactionCategory.objects.filter(active=False).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"categories/fragments/table.html",
|
||||
|
||||
@@ -35,7 +35,7 @@ def entities_list(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def entities_table_active(request):
|
||||
entities = TransactionEntity.objects.filter(active=True).order_by("id")
|
||||
entities = TransactionEntity.objects.filter(active=True).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"entities/fragments/table.html",
|
||||
@@ -47,7 +47,7 @@ def entities_table_active(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def entities_table_archived(request):
|
||||
entities = TransactionEntity.objects.filter(active=False).order_by("id")
|
||||
entities = TransactionEntity.objects.filter(active=False).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"entities/fragments/table.html",
|
||||
|
||||
@@ -35,7 +35,7 @@ def tags_list(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def tags_table_active(request):
|
||||
tags = TransactionTag.objects.filter(active=True).order_by("id")
|
||||
tags = TransactionTag.objects.filter(active=True).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"tags/fragments/table.html",
|
||||
@@ -47,7 +47,7 @@ def tags_table_active(request):
|
||||
@login_required
|
||||
@require_http_methods(["GET"])
|
||||
def tags_table_archived(request):
|
||||
tags = TransactionTag.objects.filter(active=False).order_by("id")
|
||||
tags = TransactionTag.objects.filter(active=False).order_by("name")
|
||||
return render(
|
||||
request,
|
||||
"tags/fragments/table.html",
|
||||
|
||||
@@ -152,7 +152,9 @@ def transaction_simple_add(request):
|
||||
date_param = request.GET.get("date")
|
||||
if date_param:
|
||||
try:
|
||||
initial_data["date"] = datetime.datetime.strptime(date_param, "%Y-%m-%d").date()
|
||||
initial_data["date"] = datetime.datetime.strptime(
|
||||
date_param, "%Y-%m-%d"
|
||||
).date()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@@ -160,7 +162,9 @@ def transaction_simple_add(request):
|
||||
reference_date_param = request.GET.get("reference_date")
|
||||
if reference_date_param:
|
||||
try:
|
||||
initial_data["reference_date"] = datetime.datetime.strptime(reference_date_param, "%Y-%m-%d").date()
|
||||
initial_data["reference_date"] = datetime.datetime.strptime(
|
||||
reference_date_param, "%Y-%m-%d"
|
||||
).date()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@@ -172,7 +176,10 @@ def transaction_simple_add(request):
|
||||
except (ValueError, TypeError):
|
||||
# Try to find by name
|
||||
from apps.accounts.models import Account
|
||||
account = Account.objects.filter(name__iexact=account_param, is_archived=False).first()
|
||||
|
||||
account = Account.objects.filter(
|
||||
name__iexact=account_param, is_archived=False
|
||||
).first()
|
||||
if account:
|
||||
initial_data["account"] = account.pk
|
||||
|
||||
@@ -207,7 +214,10 @@ def transaction_simple_add(request):
|
||||
except (ValueError, TypeError):
|
||||
# Try to find by name
|
||||
from apps.transactions.models import TransactionCategory
|
||||
category = TransactionCategory.objects.filter(name__iexact=category_param, active=True).first()
|
||||
|
||||
category = TransactionCategory.objects.filter(
|
||||
name__iexact=category_param, active=True
|
||||
).first()
|
||||
if category:
|
||||
initial_data["category"] = category.pk
|
||||
|
||||
@@ -457,7 +467,7 @@ def transaction_pay(request, transaction_id):
|
||||
context={"transaction": transaction, **request.GET},
|
||||
)
|
||||
response.headers["HX-Trigger"] = (
|
||||
f'{"paid" if new_is_paid else "unpaid"}, selective_update'
|
||||
f"{'paid' if new_is_paid else 'unpaid'}, selective_update"
|
||||
)
|
||||
return response
|
||||
|
||||
@@ -552,6 +562,8 @@ def transaction_all_list(request):
|
||||
if order != request.session.get("all_transactions_order", "default"):
|
||||
request.session["all_transactions_order"] = order
|
||||
|
||||
today = timezone.localdate(timezone.now())
|
||||
|
||||
transactions = Transaction.objects.prefetch_related(
|
||||
"account",
|
||||
"account__group",
|
||||
@@ -565,12 +577,27 @@ def transaction_all_list(request):
|
||||
"dca_income_entries",
|
||||
).all()
|
||||
|
||||
transactions = default_order(transactions, order=order)
|
||||
|
||||
f = TransactionsFilter(request.GET, queryset=transactions)
|
||||
|
||||
# Late transactions: date < today and is_paid = False (only shown for default ordering on first page)
|
||||
late_transactions = None
|
||||
page_number = request.GET.get("page", 1)
|
||||
paginator = Paginator(f.qs, 100)
|
||||
if order == "default" and str(page_number) == "1":
|
||||
late_transactions = f.qs.filter(
|
||||
date__lt=today,
|
||||
is_paid=False,
|
||||
).order_by("date", "id")
|
||||
# Exclude late transactions from the main paginated list
|
||||
main_transactions = f.qs.exclude(
|
||||
date__lt=today,
|
||||
is_paid=False,
|
||||
)
|
||||
else:
|
||||
main_transactions = f.qs
|
||||
|
||||
main_transactions = default_order(main_transactions, order=order)
|
||||
|
||||
paginator = Paginator(main_transactions, 100)
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
return render(
|
||||
@@ -579,6 +606,7 @@ def transaction_all_list(request):
|
||||
{
|
||||
"page_obj": page_obj,
|
||||
"paginator": paginator,
|
||||
"late_transactions": late_transactions,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\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"
|
||||
@@ -66,24 +66,30 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
@@ -91,7 +97,7 @@ msgstr ""
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -160,8 +166,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -170,11 +176,11 @@ msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr ""
|
||||
@@ -189,8 +195,8 @@ msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -204,7 +210,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -215,14 +221,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -355,7 +361,7 @@ msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr ""
|
||||
|
||||
@@ -453,10 +459,10 @@ msgstr ""
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
|
||||
@@ -495,11 +501,11 @@ msgid "Decimal Places"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr ""
|
||||
@@ -560,9 +566,9 @@ msgstr ""
|
||||
msgid "Service Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -590,57 +596,57 @@ msgstr ""
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
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:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -739,8 +745,8 @@ msgstr ""
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
@@ -772,27 +778,27 @@ msgstr ""
|
||||
msgid "DCA Entries"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -812,34 +818,42 @@ msgid "Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -991,10 +1005,12 @@ msgid "Run deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1087,15 +1103,15 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1106,14 +1122,14 @@ msgstr ""
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1124,27 +1140,27 @@ msgstr ""
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr ""
|
||||
|
||||
@@ -1300,53 +1316,65 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
msgid "Until"
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Reference date from"
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr ""
|
||||
|
||||
@@ -1434,10 +1462,12 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1445,11 +1475,11 @@ msgstr ""
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1460,11 +1490,11 @@ msgstr ""
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1476,113 +1506,113 @@ msgstr ""
|
||||
msgid "Deleted At"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1591,7 +1621,7 @@ msgstr ""
|
||||
msgid "Quick Transaction"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1697,7 +1727,7 @@ msgstr ""
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1737,30 +1767,30 @@ msgstr ""
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1802,10 +1832,10 @@ msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
@@ -2225,10 +2255,6 @@ msgstr ""
|
||||
msgid "Edit category"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2247,9 +2273,9 @@ msgstr ""
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
@@ -2477,8 +2503,8 @@ msgid "No entries for this DCA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr ""
|
||||
|
||||
@@ -2603,7 +2629,7 @@ msgstr ""
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr ""
|
||||
|
||||
@@ -2623,15 +2649,22 @@ msgstr ""
|
||||
msgid "Last fetch"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr ""
|
||||
|
||||
@@ -2881,7 +2914,11 @@ msgid "Final total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
@@ -2925,6 +2962,63 @@ msgstr ""
|
||||
msgid "No recent transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
@@ -2933,6 +3027,10 @@ msgstr ""
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
@@ -2982,6 +3080,14 @@ msgstr ""
|
||||
msgid "Emergency Fund"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr ""
|
||||
@@ -3053,35 +3159,40 @@ msgstr ""
|
||||
msgid "Item"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
@@ -3089,27 +3200,27 @@ msgstr ""
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
@@ -3350,7 +3461,7 @@ msgstr ""
|
||||
msgid "transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-12-16 05:24+0000\n"
|
||||
"Last-Translator: BRodolfo <simplysmartbydesign@gmail.com>\n"
|
||||
"Language-Team: Spanish <https://translations.herculino.com/projects/wygiwyh/"
|
||||
@@ -67,24 +67,30 @@ msgstr "Nuevo balance"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Categoría"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Etiquetas"
|
||||
@@ -92,7 +98,7 @@ msgstr "Etiquetas"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -162,8 +168,8 @@ msgstr "Las cuentas archivadas no aparecen ni cuentan para su patrimonio neto"
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -172,11 +178,11 @@ msgid "Account"
|
||||
msgstr "Cuenta"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "Cuentas"
|
||||
@@ -193,8 +199,8 @@ msgstr "Grupo de Cuenta añadido exitosamente"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -208,7 +214,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "Grupo de Cuenta actualizado exitosamente"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -219,14 +225,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "Grupo de Cuenta eliminado exitosamente"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "Propiedad tomada exitosamete"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -364,7 +370,7 @@ msgid "Public"
|
||||
msgstr "Público"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "hoy"
|
||||
|
||||
@@ -462,10 +468,10 @@ msgstr "Remover"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "Limpiar"
|
||||
|
||||
@@ -504,11 +510,11 @@ msgid "Decimal Places"
|
||||
msgstr "Cantidad de decimales"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "Monedas"
|
||||
@@ -569,9 +575,9 @@ msgstr "Nombre del Servicio"
|
||||
msgid "Service Type"
|
||||
msgstr "Tipo de Servicio"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -599,11 +605,11 @@ msgstr "Intervalo"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "Última Sincronización Exitosa"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "Monedas de Destino"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
@@ -612,11 +618,11 @@ msgstr ""
|
||||
"tasas se consultarán para cada moneda en relación con su moneda de "
|
||||
"referencia establecida."
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "Cuentas de Destino"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
@@ -625,33 +631,33 @@ msgstr ""
|
||||
"tasas se consultarán para la moneda de cada cuenta en relación con su moneda "
|
||||
"de referencia establecida."
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr "Tasa de cambio única"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
"Crea una única tasa de cambio y mantenla actualizada. Evita la acumulación "
|
||||
"de datos en la base de datos."
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "Servicio de Tasas de Cambio"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "Servicios de Tasas de Cambio"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr "El tipo de intervalo 'Cada X horas' requiere un entero positivo."
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "El tipo de intervalo 'Cada X horas' debe ser ente 1 y 24."
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -659,7 +665,7 @@ msgstr ""
|
||||
"Formato de hora no válido. Usa horas separadas por coma (0-23) y/o rangos "
|
||||
"(p. ej., \"1-5,8,10-12\")."
|
||||
|
||||
#: apps/currencies/models.py:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -760,8 +766,8 @@ msgstr "Moneda de pago"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "Notas"
|
||||
|
||||
@@ -793,27 +799,27 @@ msgstr "Entrada DCA"
|
||||
msgid "DCA Entries"
|
||||
msgstr "Entradas DCA"
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr "Estrategia DCA agregada con éxito"
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr "Estrategia DCA actualizada con éxito"
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr "Estrategia DCA eliminada con éxito"
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "Entrada agregada con éxito"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "Entrada actualizada con éxito"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "Entrada eliminada con éxito"
|
||||
|
||||
@@ -833,34 +839,42 @@ msgid "Transactions"
|
||||
msgstr "Transacciones"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "Categorías"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr "Entidades"
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "Transacciones Recurrentes"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -1013,10 +1027,12 @@ msgid "Run deleted successfully"
|
||||
msgstr "Tarea de importación eliminada con éxito"
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr "Sin categoría"
|
||||
|
||||
@@ -1109,15 +1125,15 @@ msgstr "Operador"
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1128,14 +1144,14 @@ msgstr "Pagado"
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr "Fecha de Referencia"
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1146,27 +1162,27 @@ msgstr "Monto"
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr "Nota Interna"
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr "ID Interno"
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr "Silenciar"
|
||||
|
||||
@@ -1324,53 +1340,67 @@ msgstr "Acción de Actualizar o Crear Transacción eliminada con éxito"
|
||||
msgid "Projected"
|
||||
msgstr "Proyectado"
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Silenciado"
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr "Contenido"
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr "Tipo de Transacción"
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
#: apps/transactions/filters.py:89
|
||||
#, fuzzy
|
||||
#| msgid "Status"
|
||||
msgid "Mute Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Date from"
|
||||
msgstr "Desde la fecha"
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr "Hasta"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr "Desde la fecha de referencia"
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr "Monto mínimo"
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr "Monto máximo"
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr "Con Categoría"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr "Etiquetado"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr "Sin etiqueta"
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr "Cualquier entidad"
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr "Ninguna entidad"
|
||||
|
||||
@@ -1466,10 +1496,12 @@ msgstr ""
|
||||
"transacciones"
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr "Entidad"
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1477,11 +1509,11 @@ msgstr "Entidad"
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr "Ingreso"
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1492,11 +1524,11 @@ msgstr "Ingreso"
|
||||
msgid "Expense"
|
||||
msgstr "Gasto"
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr "Plan de Cuotas"
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Transacción Recurrente"
|
||||
|
||||
@@ -1508,113 +1540,113 @@ msgstr "Eliminado"
|
||||
msgid "Deleted At"
|
||||
msgstr "Eliminado en"
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr "Sin etiquetas"
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr "Sin categoría"
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr "Sin descripción"
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr "Anual"
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr "Mensual"
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr "Semanal"
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr "Diario"
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr "Cantidad de cuotas"
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr "Cuota de Inicio"
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "El número de la cuota desde la cual comenzar a contar"
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr "Fecha de Inicio"
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr "Fecha de Fin"
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr "Recurrencia"
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr "Monto de la Cuota"
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Agregar descripción a las transacciones"
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Agregar notas a las transacciones"
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr "día(s)"
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr "semana(s)"
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr "mes(es)"
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr "año(s)"
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr "Pausado"
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Tipo de Recurrencia"
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Intervalo de Recurrencia"
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr "Mantener como máximo"
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Última Fecha Generada"
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Última Fecha de Referencia Generada"
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1623,7 +1655,7 @@ msgstr "Última Fecha de Referencia Generada"
|
||||
msgid "Quick Transaction"
|
||||
msgstr "Transacción Rápida"
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1729,7 +1761,7 @@ msgstr "Ítem eliminado con éxito"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr "Transacción añadida exitosamente"
|
||||
|
||||
@@ -1769,30 +1801,30 @@ msgstr "Etiqueta actualizada con éxito"
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "Etiqueta eliminada con éxito"
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr "Transacción actualizada con éxito"
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] "%(count)s transacción actualizada exitosamente"
|
||||
msgstr[1] "%(count)s transacciones actualizadas exitosamente"
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr "Transacción duplicada exitosamente"
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr "Transacción borrada exitosamente"
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr "Transacción restaurada exitosamente"
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr "Transferencia añadida exitosamente"
|
||||
|
||||
@@ -1834,10 +1866,10 @@ msgid "This account is deactivated"
|
||||
msgstr "Esta cuenta está desactivada"
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr "Por Defecto"
|
||||
|
||||
@@ -2265,10 +2297,6 @@ msgstr "Agregar categoría"
|
||||
msgid "Edit category"
|
||||
msgstr "Editar categoría"
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Silenciado"
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2287,9 +2315,9 @@ msgstr "Cerrar"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
@@ -2517,8 +2545,8 @@ msgid "No entries for this DCA"
|
||||
msgstr "Sin entradas para este DCA"
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr "Prueba agregar una"
|
||||
|
||||
@@ -2644,7 +2672,7 @@ msgstr "No hay tasas de cambio"
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr "Navegación entre páginas"
|
||||
|
||||
@@ -2664,15 +2692,22 @@ msgstr "Dirigido a"
|
||||
msgid "Last fetch"
|
||||
msgstr "Última sincronización"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr "monedas"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr "cuentas"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr "No hay servicios configurados"
|
||||
|
||||
@@ -2927,7 +2962,11 @@ msgid "Final total"
|
||||
msgstr "Total final"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
@@ -2971,6 +3010,75 @@ msgstr "No hay transacciones atrasadas"
|
||||
msgid "No recent transactions"
|
||||
msgstr "No hay transacciones recientes"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
#, fuzzy
|
||||
#| msgid "Tags"
|
||||
msgid "Tag"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "Mar"
|
||||
msgstr "Máximo"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "May"
|
||||
msgstr "Máximo"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
#, fuzzy
|
||||
#| msgid "Set"
|
||||
msgid "Sep"
|
||||
msgstr "Establecer"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
#, fuzzy
|
||||
#| msgid "Now"
|
||||
msgid "Nov"
|
||||
msgstr "Ahora"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
#, fuzzy
|
||||
#| msgid "No transactions on this date"
|
||||
msgid "No transactions for this year"
|
||||
msgstr "No hay transacciones en esta fecha"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr "Desde"
|
||||
@@ -2979,6 +3087,12 @@ msgstr "Desde"
|
||||
msgid "Percentage"
|
||||
msgstr "Porcentaje"
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
#, fuzzy
|
||||
#| msgid "transactions"
|
||||
msgid "No transactions"
|
||||
msgstr "transacciones"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr "Mes"
|
||||
@@ -3028,6 +3142,16 @@ msgstr "Últimas Transacciones"
|
||||
msgid "Emergency Fund"
|
||||
msgstr "Fondo de Emergencia"
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
#, fuzzy
|
||||
#| msgid "Yearly by account"
|
||||
msgid "Year by Year"
|
||||
msgstr "Anual por cuenta"
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr "Agregar plan de cuotas"
|
||||
@@ -3101,35 +3225,40 @@ msgstr "Precio unitario"
|
||||
msgid "Item"
|
||||
msgstr "Ítem"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr "Sin transacciones este mes"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr "Asignación de gastos diarios"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr "Este es el total final dividido por los días restantes del mes"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr "actual"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr "proyectado"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr "Gastos"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr "Distribución"
|
||||
|
||||
@@ -3137,27 +3266,27 @@ msgstr "Distribución"
|
||||
msgid "Summary"
|
||||
msgstr "Resumen"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr "Lo más antiguo primero"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr "Lo más nuevo primero"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr "Filtrar transacciones"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr "Ordenar por"
|
||||
|
||||
@@ -3402,7 +3531,7 @@ msgstr "Edición"
|
||||
msgid "transactions"
|
||||
msgstr "transacciones"
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr "No se encontraron transacciones"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-10-07 20:17+0000\n"
|
||||
"Last-Translator: Erwan Colin <zephone@protonmail.com>\n"
|
||||
"Language-Team: French <https://translations.herculino.com/projects/wygiwyh/"
|
||||
@@ -67,24 +67,30 @@ msgstr "Nouveau solde"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Catégorie"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Etiquettes"
|
||||
@@ -92,7 +98,7 @@ msgstr "Etiquettes"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -164,8 +170,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -174,11 +180,11 @@ msgid "Account"
|
||||
msgstr "Compte"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "Comptes"
|
||||
@@ -195,8 +201,8 @@ msgstr "Groupe de compte ajouté avec succès"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -210,7 +216,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "Groupe de compte mis à jour avec succès"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -221,14 +227,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "Groupe de compte supprimé avec succès"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "Propriété acquise avec succès"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -366,7 +372,7 @@ msgid "Public"
|
||||
msgstr "Publique"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "aujourd'hui"
|
||||
|
||||
@@ -464,10 +470,10 @@ msgstr "Enlever"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "Vider"
|
||||
|
||||
@@ -506,11 +512,11 @@ msgid "Decimal Places"
|
||||
msgstr "Décimales"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "Devises"
|
||||
@@ -571,9 +577,9 @@ msgstr "Nom du Service"
|
||||
msgid "Service Type"
|
||||
msgstr "Type de Service"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -601,11 +607,11 @@ msgstr "Intervalle"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "Dernière récupération avec succès"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "Devises cibles"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
@@ -613,11 +619,11 @@ msgstr ""
|
||||
"Sélectionnez les devises pour récupérer leur taux de changes. Les taux "
|
||||
"seront récupérés pour chaque devises par rapport à leur devise d'échange."
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "Comptes cibles"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
@@ -625,33 +631,33 @@ msgstr ""
|
||||
"Sélectionnez les comptes pour récupérer leur taux de change. Les taux seront "
|
||||
"récupérés pour chaque compte par rapport à leur devise d'échange."
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr "Taux de change unique"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
"Ne créer qu'un seul taux de change et le mettre à jour. Evite d'engorger la "
|
||||
"base de donnée."
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "Service de taux de change"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "Services de taux de change"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr "'Toutes les X heures' l'intervalle requiert un entier positif."
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "'Toutes les X heures' l'intervalle doit être compris entre 1 et 24."
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -659,7 +665,7 @@ msgstr ""
|
||||
"Format d'heure invalide. Utilisez les heures séparé par virgule (0-23) et/ou "
|
||||
"une plage (ex : '1-5,8,10-12')."
|
||||
|
||||
#: apps/currencies/models.py:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -761,8 +767,8 @@ msgstr "Devise de paiement"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "Notes"
|
||||
|
||||
@@ -794,27 +800,27 @@ msgstr "Entrée DCA"
|
||||
msgid "DCA Entries"
|
||||
msgstr "Entrées DCA"
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr "Stratégie DCA ajouté avec succès"
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr "Stratégie DCA mise à jour avec succès"
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr "Stratégie DCA supprimé avec succès"
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "Entrée ajoutée avec succès"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "Entrée mise à jour avec succès"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "Entrée supprimée avec succès"
|
||||
|
||||
@@ -834,34 +840,42 @@ msgid "Transactions"
|
||||
msgstr "Transactions"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "Catégories"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr "Entités"
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "Transactions récurrentes"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -1015,10 +1029,12 @@ msgid "Run deleted successfully"
|
||||
msgstr "Exécution supprimé avec succès"
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr "Sans catégorie"
|
||||
|
||||
@@ -1111,15 +1127,15 @@ msgstr "Opérateur"
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1130,14 +1146,14 @@ msgstr "Payé"
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr "Date de référence"
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1148,27 +1164,27 @@ msgstr "Montant"
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr "Note interne"
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr "ID interne"
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr "Silencieux"
|
||||
|
||||
@@ -1328,53 +1344,67 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr "Projeté"
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Muet"
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr "Contenu"
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr "Type de transaction"
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
#: apps/transactions/filters.py:89
|
||||
#, fuzzy
|
||||
#| msgid "Status"
|
||||
msgid "Mute Status"
|
||||
msgstr "Statut"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Date from"
|
||||
msgstr "Date de départ"
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr "Jusqu'au"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr "Référencer une date de"
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr "Montant min"
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr "Montant max"
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr "Catégorisé"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr "Avec étiquettes"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr "Sans étiquettes"
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr "N'importe quelle entité"
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr "Pas d'entité"
|
||||
|
||||
@@ -1470,10 +1500,12 @@ msgstr ""
|
||||
"créations de nouvelles transactions"
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr "Entité"
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1481,11 +1513,11 @@ msgstr "Entité"
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr "Revenus"
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1496,11 +1528,11 @@ msgstr "Revenus"
|
||||
msgid "Expense"
|
||||
msgstr "Dépense"
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr "Plan d'aménagement"
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Transaction récurrente"
|
||||
|
||||
@@ -1512,113 +1544,113 @@ msgstr "Supprimé"
|
||||
msgid "Deleted At"
|
||||
msgstr "Supprimé à"
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr "Aucunes étiquettes"
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr "Pas de catégorie"
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr "Pas de description"
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr "Annuel"
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr "Mensuel"
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr "Hebdomadaire"
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr "Quotidien"
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr "Nombre d'écheances"
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr "Commencer à l'échéance"
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "L'échéance à partir de laquelle compter"
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr "Date de début"
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr "Date de fin"
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr "Récurrence"
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr "Montant des échéances"
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Rajouter une description à la transaction"
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Ajouter des notes aux transactions"
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr "jour(s)"
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr "semaine(s)"
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr "mois"
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr "année(s)"
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr "Interrompu"
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Type de récurrence"
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Interval de récurrence"
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr "Répéter un maximum de"
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Dernière date générée"
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Dernière date de référence générée"
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1627,7 +1659,7 @@ msgstr "Dernière date de référence générée"
|
||||
msgid "Quick Transaction"
|
||||
msgstr "Transaction rapide"
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1733,7 +1765,7 @@ msgstr "Item supprimée avec succès"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr "Transaction ajoutée avec succès"
|
||||
|
||||
@@ -1773,30 +1805,30 @@ msgstr "Etiquette mise à jour avec succès"
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "Etiquette supprimée avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr "Transaction mise à jour avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] "%(count)s transaction mise à jour avec succès"
|
||||
msgstr[1] "%(count)s transactions mises à jour avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr "Transaction dupliquée avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr "Transaction supprimée avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr "Transaction restaurée avec succès"
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr "Virement ajouté avec succès"
|
||||
|
||||
@@ -1838,10 +1870,10 @@ msgid "This account is deactivated"
|
||||
msgstr "Ce compte est désactivé"
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr "Par défaut"
|
||||
|
||||
@@ -2274,10 +2306,6 @@ msgstr "Ajouter une catégorie"
|
||||
msgid "Edit category"
|
||||
msgstr "Modifier la catégorie"
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Muet"
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2296,9 +2324,9 @@ msgstr "Fermer"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr "Rechercher"
|
||||
|
||||
@@ -2532,8 +2560,8 @@ msgid "No entries for this DCA"
|
||||
msgstr "Pas d'entrées pour ce DCA"
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr "Essayer d'en ajouter une"
|
||||
|
||||
@@ -2659,7 +2687,7 @@ msgstr "Pas de taux de change"
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr "Navigation dans les pages"
|
||||
|
||||
@@ -2679,15 +2707,22 @@ msgstr "Ciblage"
|
||||
msgid "Last fetch"
|
||||
msgstr "Dernière récupération"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr "devises"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr "Comptes"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr "Pas de services configurés"
|
||||
|
||||
@@ -2946,7 +2981,11 @@ msgid "Final total"
|
||||
msgstr "Total final"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
@@ -2990,6 +3029,75 @@ msgstr "Aucunes transactions en retard"
|
||||
msgid "No recent transactions"
|
||||
msgstr "Aucunes transactions récentes"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
#, fuzzy
|
||||
#| msgid "Tags"
|
||||
msgid "Tag"
|
||||
msgstr "Etiquettes"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "Mar"
|
||||
msgstr "Max"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "May"
|
||||
msgstr "Max"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
#, fuzzy
|
||||
#| msgid "Set"
|
||||
msgid "Sep"
|
||||
msgstr "Définir"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
#, fuzzy
|
||||
#| msgid "Now"
|
||||
msgid "Nov"
|
||||
msgstr "Maintenant"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
#, fuzzy
|
||||
#| msgid "No transactions on this date"
|
||||
msgid "No transactions for this year"
|
||||
msgstr "Aucunes transactions à cette date"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr "De"
|
||||
@@ -2998,6 +3106,12 @@ msgstr "De"
|
||||
msgid "Percentage"
|
||||
msgstr "Pourcentage"
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
#, fuzzy
|
||||
#| msgid "transactions"
|
||||
msgid "No transactions"
|
||||
msgstr "transactions"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr "Mois"
|
||||
@@ -3047,6 +3161,16 @@ msgstr "Transactions récentes"
|
||||
msgid "Emergency Fund"
|
||||
msgstr "Fonds de secours"
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
#, fuzzy
|
||||
#| msgid "Yearly by account"
|
||||
msgid "Year by Year"
|
||||
msgstr "Annuel par comptes"
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr "Ajouter un paiement en plusieurs fois"
|
||||
@@ -3122,35 +3246,40 @@ msgstr "Prix unitaire"
|
||||
msgid "Item"
|
||||
msgstr "Eléments"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr "Aucunes transactions ce mois-ci"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr "Montant disponible pour les dépenses quotidiennes"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr "Total final divisé par le nombre de jour restant dans le mois"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr "A date"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr "Prévisionnel"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr "Dépenses"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr "Répartition"
|
||||
|
||||
@@ -3158,27 +3287,27 @@ msgstr "Répartition"
|
||||
msgid "Summary"
|
||||
msgstr "Résumé"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr "Plus ancien en premier"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr "Plus récent en premier"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr "Filtrer les transactions"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr "Trier par"
|
||||
|
||||
@@ -3428,7 +3557,7 @@ msgstr "Modification en cours"
|
||||
msgid "transactions"
|
||||
msgstr "transactions"
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr "Aucunes transactions trouvées"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
@@ -65,24 +65,30 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
@@ -90,7 +96,7 @@ msgstr ""
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -159,8 +165,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -169,11 +175,11 @@ msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr ""
|
||||
@@ -188,8 +194,8 @@ msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -203,7 +209,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -214,14 +220,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -354,7 +360,7 @@ msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr ""
|
||||
|
||||
@@ -452,10 +458,10 @@ msgstr ""
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
|
||||
@@ -494,11 +500,11 @@ msgid "Decimal Places"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr ""
|
||||
@@ -559,9 +565,9 @@ msgstr ""
|
||||
msgid "Service Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -589,57 +595,57 @@ msgstr ""
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
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:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -738,8 +744,8 @@ msgstr ""
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
@@ -771,27 +777,27 @@ msgstr ""
|
||||
msgid "DCA Entries"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -811,34 +817,42 @@ msgid "Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -990,10 +1004,12 @@ msgid "Run deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1086,15 +1102,15 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1105,14 +1121,14 @@ msgstr ""
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1123,27 +1139,27 @@ msgstr ""
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr ""
|
||||
|
||||
@@ -1299,53 +1315,65 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
msgid "Until"
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Reference date from"
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr ""
|
||||
|
||||
@@ -1433,10 +1461,12 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1444,11 +1474,11 @@ msgstr ""
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1459,11 +1489,11 @@ msgstr ""
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1475,113 +1505,113 @@ msgstr ""
|
||||
msgid "Deleted At"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1590,7 +1620,7 @@ msgstr ""
|
||||
msgid "Quick Transaction"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1696,7 +1726,7 @@ msgstr ""
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1736,30 +1766,30 @@ msgstr ""
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1801,10 +1831,10 @@ msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
@@ -2224,10 +2254,6 @@ msgstr ""
|
||||
msgid "Edit category"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2246,9 +2272,9 @@ msgstr ""
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
@@ -2476,8 +2502,8 @@ msgid "No entries for this DCA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr ""
|
||||
|
||||
@@ -2602,7 +2628,7 @@ msgstr ""
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr ""
|
||||
|
||||
@@ -2622,15 +2648,21 @@ msgstr ""
|
||||
msgid "Last fetch"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr ""
|
||||
|
||||
@@ -2880,7 +2912,11 @@ msgid "Final total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
@@ -2924,6 +2960,63 @@ msgstr ""
|
||||
msgid "No recent transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
@@ -2932,6 +3025,10 @@ msgstr ""
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
@@ -2981,6 +3078,14 @@ msgstr ""
|
||||
msgid "Emergency Fund"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr ""
|
||||
@@ -3052,35 +3157,40 @@ msgstr ""
|
||||
msgid "Item"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
@@ -3088,27 +3198,27 @@ msgstr ""
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
@@ -3349,7 +3459,7 @@ msgstr ""
|
||||
msgid "transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr ""
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"PO-Revision-Date: 2025-12-15 05:24+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2026-01-11 13:24+0000\n"
|
||||
"Last-Translator: Dimitri Decrock <dj.flashpower@gmail.com>\n"
|
||||
"Language-Team: Dutch <https://translations.herculino.com/projects/wygiwyh/"
|
||||
"app/nl/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.14.3\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
#: apps/accounts/forms.py:24
|
||||
msgid "Group name"
|
||||
@@ -67,24 +67,30 @@ msgstr "Nieuw saldo"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Categorie"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Labels"
|
||||
@@ -92,7 +98,7 @@ msgstr "Labels"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -165,8 +171,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -175,11 +181,11 @@ msgid "Account"
|
||||
msgstr "Rekening"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "Rekeningen"
|
||||
@@ -195,8 +201,8 @@ msgstr "Rekeninggroep succesvol toegevoegd"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -210,7 +216,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "Rekeninggroep succesvol bijgewerkt"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -221,14 +227,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "Rekeninggroep succesvol verwijderd"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "Eigendom succesvol genomen"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -366,7 +372,7 @@ msgid "Public"
|
||||
msgstr "Openbaar"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "vandaag"
|
||||
|
||||
@@ -464,10 +470,10 @@ msgstr "Verwijder"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "Leegmaken"
|
||||
|
||||
@@ -506,11 +512,11 @@ msgid "Decimal Places"
|
||||
msgstr "Cijfers na de komma"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "Munteenheden"
|
||||
@@ -571,9 +577,9 @@ msgstr "Dienstnaam"
|
||||
msgid "Service Type"
|
||||
msgstr "Soort Dienst"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -601,11 +607,11 @@ msgstr "Interval"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "Laatste Succesvolle Ophaling"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "Doel Munteenheden"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
@@ -613,11 +619,11 @@ msgstr ""
|
||||
"Selecteer munteenheden om wisselkoersen voor op te halen. De koersen worden "
|
||||
"voor elke munteenheid opgehaald ten opzichte van de ingestelde wisselkoers."
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "Naar rekeningen"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
@@ -626,33 +632,33 @@ msgstr ""
|
||||
"opgehaald voor de munteenheid van elke rekening ten opzichte van de "
|
||||
"ingestelde wisselkoers."
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr "Enkele Wisselkoers"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
"Maak één wisselkoers aan en houd deze bijgewerkt. Voorkomt een overvolle "
|
||||
"database."
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "Wisselkoersdienst"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "Wisselkoersdiensten"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr "Voor het intervaltype ‘Elke X uur’ is een positief geheel getal nodig."
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "Het interval ‘Elke X uur’ moet tussen 1 en 24 liggen."
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -660,7 +666,7 @@ msgstr ""
|
||||
"Ongeldige urennotatie. Gebruik door komma's gescheiden uren (0-23) en/of "
|
||||
"reeksen (bijv. ‘1-5,8,10-12’)."
|
||||
|
||||
#: apps/currencies/models.py:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -762,8 +768,8 @@ msgstr "Betaal Munteenheid"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "Opmerkingen"
|
||||
|
||||
@@ -795,27 +801,27 @@ msgstr "DCA Instap"
|
||||
msgid "DCA Entries"
|
||||
msgstr "DCA Idems"
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr "Strategie voor DCA succesvol toegevoegd"
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr "Strategie voor DCA succesvol bijgewerkt"
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr "Strategie voor DCA succesvol verwijderd"
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "Item succesvol toegevoegd"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "Invoer succesvol bijgewerkt"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "Invoer succesvol verwijderd"
|
||||
|
||||
@@ -835,34 +841,42 @@ msgid "Transactions"
|
||||
msgstr "Verrichtingen"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "Categorieën"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr "Bedrijven"
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "Terugkerende Verrichtingen"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -1016,10 +1030,12 @@ msgid "Run deleted successfully"
|
||||
msgstr "Run met succes verwijderd"
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr "Ongecategoriseerd"
|
||||
|
||||
@@ -1112,15 +1128,15 @@ msgstr "Operator"
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr "Soort"
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1131,14 +1147,14 @@ msgstr "Betaald"
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr "Referentiedatum"
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1149,27 +1165,27 @@ msgstr "Bedrag"
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr "Beschrijving"
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr "Interne opmerking"
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr "Interne ID"
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr "Dempen"
|
||||
|
||||
@@ -1327,53 +1343,65 @@ msgstr "Verrichting Bijwerken Of Maken succesvol verwijderd"
|
||||
msgid "Projected"
|
||||
msgstr "Ingepland"
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Gedempt"
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr "Inhoud"
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr "Soort transactie"
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr "Demp Status"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Date from"
|
||||
msgstr "Datum vanaf"
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr "Tot"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr "Referentiedatum vanaf"
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr "Minimum bedrag"
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr "Maximaal bedrag"
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr "Gecategoriseerd"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr "Gelabeld"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr "Niet gelabeld"
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr "Elk bedrijf"
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr "Geen bedrijf"
|
||||
|
||||
@@ -1467,10 +1495,12 @@ msgstr ""
|
||||
"nieuwe verrichtingen"
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr "Bedrijf"
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1478,11 +1508,11 @@ msgstr "Bedrijf"
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr "Ontvangsten Transactie"
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1493,11 +1523,11 @@ msgstr "Ontvangsten Transactie"
|
||||
msgid "Expense"
|
||||
msgstr "Uitgave"
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr "Afbetalingsplan"
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Terugkerende verrichting"
|
||||
|
||||
@@ -1509,113 +1539,113 @@ msgstr "Verwijderd"
|
||||
msgid "Deleted At"
|
||||
msgstr "Verwijderd Op"
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr "Geen labels"
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr "Geen categorie"
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr "Geen Beschrijving"
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr "Jaarlijks"
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr "Maandelijks"
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr "Wekelijks"
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr "Dagelijks"
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr "Aantal aflossingen"
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr "Begin afbetaling"
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "Het nummer van de aflevering om mee te beginnen"
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr "Einddatum"
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr "Terugkeerpatroon"
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr "Termijnbedrag"
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Beschrijving toevoegen aan verrichting"
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Notities toevoegen aan verrichting"
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr "dag(en)"
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr "we(e)k(en)"
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr "maand(en)"
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr "ja(a)r(en)"
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr "Gepauzeerd"
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Type Terugkeerpatroon"
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Terugkeer Interval"
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr "Bewaar maximaal"
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Laatste Gegenereerde Datum"
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Laatste Gegenereerde Referentiedatum"
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1624,7 +1654,7 @@ msgstr "Laatste Gegenereerde Referentiedatum"
|
||||
msgid "Quick Transaction"
|
||||
msgstr "Snelle verrichting"
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1730,7 +1760,7 @@ msgstr "Item succesvol verwijderd"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr "Verrichting succesvol toegevoegd"
|
||||
|
||||
@@ -1770,30 +1800,30 @@ msgstr "Label succesvol bijgewerkt"
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "Label succesvol verwijderd"
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr "Verrichting succesvol bijgewerkt"
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] "%(count)s verrichting succesvol bijgewerkt"
|
||||
msgstr[1] "%(count)s verrichtingen succesvol bijgewerkt"
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr "Verrichting succesvol gedupliceerd"
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr "Verrichting succesvol verwijderd"
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr "Verrichting succesvol hersteld"
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr "Transactie succesvol toegevoegd"
|
||||
|
||||
@@ -1835,10 +1865,10 @@ msgid "This account is deactivated"
|
||||
msgstr "Deze gebruiker is gedeactiveerd"
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr "Standaard"
|
||||
|
||||
@@ -2265,10 +2295,6 @@ msgstr "Categorie toevoegen"
|
||||
msgid "Edit category"
|
||||
msgstr "Categorie bewerken"
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Gedempt"
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2287,9 +2313,9 @@ msgstr "Sluiten"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr "Zoeken"
|
||||
|
||||
@@ -2517,8 +2543,8 @@ msgid "No entries for this DCA"
|
||||
msgstr "Geen idems in deze DCA"
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr "Probeer er een toe te voegen"
|
||||
|
||||
@@ -2643,7 +2669,7 @@ msgstr "Geen wisselkoersen"
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr "Paginanavigatie"
|
||||
|
||||
@@ -2663,15 +2689,22 @@ msgstr "Gericht op"
|
||||
msgid "Last fetch"
|
||||
msgstr "Laatst opgehaald"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] "%(counter)s opeenvolgende mislukking"
|
||||
msgstr[1] "%(counter)s opeenvolgende mislukkingen"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr "munteenheden"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr "rekeningen"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr "Geen diensten ingesteld"
|
||||
|
||||
@@ -2928,7 +2961,11 @@ msgid "Final total"
|
||||
msgstr "Eindtotaal"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Totaal"
|
||||
|
||||
@@ -2972,6 +3009,63 @@ msgstr "Geen betalingsachterstanden"
|
||||
msgid "No recent transactions"
|
||||
msgstr "Geen recente betalingen"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
msgid "Tag"
|
||||
msgstr "Label"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr "Jan"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr "Feb"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr "Mrt"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr "Apr"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr "Mei"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr "Jun"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr "Jul"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr "Aug"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr "Sep"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr "Okt"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr "Nov"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr "Dec"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr "Geen verrichtingen voor dit jaar"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr "Van"
|
||||
@@ -2980,6 +3074,10 @@ msgstr "Van"
|
||||
msgid "Percentage"
|
||||
msgstr "Percentage"
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr "Geen verrichtingen"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr "Maand"
|
||||
@@ -3029,6 +3127,14 @@ msgstr "Laatste Verrichtingen"
|
||||
msgid "Emergency Fund"
|
||||
msgstr "Noodfonds"
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr "Jaar bij Jaar"
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr "Maand bij Maand"
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr "Afbetalingsplan toevoegen"
|
||||
@@ -3103,35 +3209,40 @@ msgstr "Eenheidsprijs"
|
||||
msgid "Item"
|
||||
msgstr "Artikel"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr "laat"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr "Geen verrichtingen deze maand"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr "Dagelijks Toegestane Besteding"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr "Dit is het eindtotaal gedeeld door de resterende dagen in de maand"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr "actueel"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr "verwacht"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr "Uitgaven"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr "Verdeling"
|
||||
|
||||
@@ -3139,27 +3250,27 @@ msgstr "Verdeling"
|
||||
msgid "Summary"
|
||||
msgstr "Samenvatting"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr "Oudste eerst"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr "Nieuwste eerst"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr "Filter verrichtingen"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr "Sorteer op"
|
||||
|
||||
@@ -3406,7 +3517,7 @@ msgstr "Bewerking"
|
||||
msgid "transactions"
|
||||
msgstr "verrichtingen"
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr "Geen Verrichtingen gevonden"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-11-08 12:20+0000\n"
|
||||
"Last-Translator: Marcin Kisielewski <kisielewski.mar@gmail.com>\n"
|
||||
"Language-Team: Polish <https://translations.herculino.com/projects/wygiwyh/"
|
||||
@@ -68,24 +68,30 @@ msgstr "Nowe saldo"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Kategoria"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Tagi"
|
||||
@@ -93,7 +99,7 @@ msgstr "Tagi"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -162,8 +168,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -172,11 +178,11 @@ msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr ""
|
||||
@@ -191,8 +197,8 @@ msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -206,7 +212,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -217,14 +223,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -357,7 +363,7 @@ msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr ""
|
||||
|
||||
@@ -455,10 +461,10 @@ msgstr ""
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
|
||||
@@ -497,11 +503,11 @@ msgid "Decimal Places"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr ""
|
||||
@@ -562,9 +568,9 @@ msgstr ""
|
||||
msgid "Service Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -592,57 +598,57 @@ msgstr ""
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
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:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -741,8 +747,8 @@ msgstr ""
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
@@ -774,27 +780,27 @@ msgstr ""
|
||||
msgid "DCA Entries"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -814,34 +820,42 @@ msgid "Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -993,10 +1007,12 @@ msgid "Run deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1089,15 +1105,15 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1108,14 +1124,14 @@ msgstr ""
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1126,27 +1142,27 @@ msgstr ""
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr ""
|
||||
|
||||
@@ -1302,53 +1318,65 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
msgid "Until"
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Reference date from"
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr ""
|
||||
|
||||
@@ -1436,10 +1464,12 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1447,11 +1477,11 @@ msgstr ""
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1462,11 +1492,11 @@ msgstr ""
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1478,113 +1508,113 @@ msgstr ""
|
||||
msgid "Deleted At"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1593,7 +1623,7 @@ msgstr ""
|
||||
msgid "Quick Transaction"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1699,7 +1729,7 @@ msgstr ""
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1739,30 +1769,30 @@ msgstr ""
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1804,10 +1834,10 @@ msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
@@ -2227,10 +2257,6 @@ msgstr ""
|
||||
msgid "Edit category"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2249,9 +2275,9 @@ msgstr ""
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
@@ -2479,8 +2505,8 @@ msgid "No entries for this DCA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr ""
|
||||
|
||||
@@ -2605,7 +2631,7 @@ msgstr ""
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr ""
|
||||
|
||||
@@ -2625,15 +2651,23 @@ msgstr ""
|
||||
msgid "Last fetch"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr ""
|
||||
|
||||
@@ -2883,7 +2917,11 @@ msgid "Final total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
@@ -2927,6 +2965,65 @@ msgstr ""
|
||||
msgid "No recent transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
#, fuzzy
|
||||
#| msgid "Tags"
|
||||
msgid "Tag"
|
||||
msgstr "Tagi"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
@@ -2935,6 +3032,10 @@ msgstr ""
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
@@ -2984,6 +3085,14 @@ msgstr ""
|
||||
msgid "Emergency Fund"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr ""
|
||||
@@ -3055,35 +3164,40 @@ msgstr ""
|
||||
msgid "Item"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
@@ -3091,27 +3205,27 @@ msgstr ""
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
@@ -3352,7 +3466,7 @@ msgstr ""
|
||||
msgid "transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"PO-Revision-Date: 2025-12-14 15:07+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2026-01-11 16:55+0000\n"
|
||||
"Last-Translator: Herculino Trotta <netotrotta@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) <https://translations.herculino.com/"
|
||||
"projects/wygiwyh/app/pt_BR/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.14.3\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
#: apps/accounts/forms.py:24
|
||||
msgid "Group name"
|
||||
@@ -67,24 +67,30 @@ msgstr "Novo saldo"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Categoria"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
@@ -92,7 +98,7 @@ msgstr "Tags"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -164,8 +170,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -174,11 +180,11 @@ msgid "Account"
|
||||
msgstr "Conta"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "Contas"
|
||||
@@ -193,8 +199,8 @@ msgstr "Grupo de Conta adicionado com sucesso"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -208,7 +214,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "Grupo de Conta atualizado com sucesso"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -219,14 +225,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "Grupo de Conta apagado com sucesso"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "Propriedade assumida com sucesso"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -364,7 +370,7 @@ msgid "Public"
|
||||
msgstr "Público"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "hoje"
|
||||
|
||||
@@ -462,10 +468,10 @@ msgstr "Remover"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "Limpar"
|
||||
|
||||
@@ -504,11 +510,11 @@ msgid "Decimal Places"
|
||||
msgstr "Casas Decimais"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "Moedas"
|
||||
@@ -569,9 +575,9 @@ msgstr "Nome do Serviço"
|
||||
msgid "Service Type"
|
||||
msgstr "Tipo de Serviço"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -599,11 +605,11 @@ msgstr "Intervalo"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "Última execução bem-sucedida"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "Moedas-alvo"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
@@ -611,11 +617,11 @@ msgstr ""
|
||||
"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."
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "Contas-alvo"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
@@ -624,34 +630,34 @@ msgstr ""
|
||||
"serão obtidas para a moeda de cada conta em relação à moeda de câmbio "
|
||||
"definida."
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr "Taxa de câmbio única"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
"Cria uma taxa de câmbio e mantenha-a atualizada. Evita a poluição do banco "
|
||||
"de dados."
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "Serviço de Taxa de Câmbio"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "Serviços de Taxa de Câmbio"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
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:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "Intervalo do tipo 'A cada X horas' requerer um número entre 1 e 24."
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -659,7 +665,7 @@ 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:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -760,8 +766,8 @@ msgstr "Moeda de pagamento"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "Notas"
|
||||
|
||||
@@ -793,27 +799,27 @@ msgstr "Entrada CMP"
|
||||
msgid "DCA Entries"
|
||||
msgstr "Entradas CMP"
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr "Estratégia CMP adicionada com sucesso"
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr "Estratégia CMP atualizada com sucesso"
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr "Estratégia CMP apagada com sucesso"
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "Entrada adicionada com sucesso"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "Entrada atualizada com sucesso"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "Entrada apagada com sucesso"
|
||||
|
||||
@@ -833,34 +839,42 @@ msgid "Transactions"
|
||||
msgstr "Transações"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "Categorias"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr "Entidades"
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "Transações Recorrentes"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -1014,10 +1028,12 @@ msgid "Run deleted successfully"
|
||||
msgstr "Importação apagada com sucesso"
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr "Sem categoria"
|
||||
|
||||
@@ -1110,15 +1126,15 @@ msgstr "Operador"
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1129,14 +1145,14 @@ msgstr "Pago"
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr "Data de Referência"
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1147,27 +1163,27 @@ msgstr "Quantia"
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr "Descrição"
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr "Nota Interna"
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr "ID Interna"
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr "Silenciada"
|
||||
|
||||
@@ -1325,53 +1341,65 @@ msgstr "Ação Atualizar ou Criar Transação apagada com sucesso"
|
||||
msgid "Projected"
|
||||
msgstr "Previsto"
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Silenciada"
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr "Conteúdo"
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr "Tipo de Transação"
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr "Status de silenciamento"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Date from"
|
||||
msgstr "Data de"
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr "Até"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr "Data de Referência de"
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr "Quantia miníma"
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr "Quantia máxima"
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr "Categorizada"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr "Com tag"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr "Sem tag"
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr "Qualquer entidade"
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr "Sem entidade"
|
||||
|
||||
@@ -1464,10 +1492,12 @@ msgstr ""
|
||||
"transações"
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr "Entidade"
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1475,11 +1505,11 @@ msgstr "Entidade"
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr "Renda"
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1490,11 +1520,11 @@ msgstr "Renda"
|
||||
msgid "Expense"
|
||||
msgstr "Despesa"
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr "Parcelamento"
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Transação Recorrente"
|
||||
|
||||
@@ -1506,113 +1536,113 @@ msgstr "Apagado"
|
||||
msgid "Deleted At"
|
||||
msgstr "Apagado Em"
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr "Nenhuma tag"
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr "Sem categoria"
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr "Sem descrição"
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr "Anual"
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr "Mensal"
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr "Semanal"
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr "Diária"
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr "Número de Parcelas"
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr "Parcela inicial"
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "O número da parcela a partir do qual se inicia a contagem"
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr "Data de Início"
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr "Data Final"
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr "Recorrência"
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr "Valor da Parcela"
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Adicionar descrição às transações"
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Adicionar notas às transações"
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr "dia(s)"
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr "semana(s)"
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr "mês(es)"
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr "ano(s)"
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr "Pausado"
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Tipo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Intervalo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr "Manter no máximo"
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Última data gerada"
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Última data de referência gerada"
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1621,7 +1651,7 @@ msgstr "Última data de referência gerada"
|
||||
msgid "Quick Transaction"
|
||||
msgstr "Transação Rápida"
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1727,7 +1757,7 @@ msgstr "Item apagado com sucesso"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr "Transação adicionada com sucesso"
|
||||
|
||||
@@ -1767,30 +1797,30 @@ msgstr "Tag atualizada com sucesso"
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "Tag apagada com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr "Transação atualizada com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] "%(count)s transação atualizada com sucesso"
|
||||
msgstr[1] "%(count)s transações atualizadas com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr "Transação duplicada com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr "Transação apagada com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr "Transação restaurada com sucesso"
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr "Transferência adicionada com sucesso"
|
||||
|
||||
@@ -1832,10 +1862,10 @@ msgid "This account is deactivated"
|
||||
msgstr "Essa conta está desativada"
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr "Padrão"
|
||||
|
||||
@@ -2264,10 +2294,6 @@ msgstr "Adicionar categoria"
|
||||
msgid "Edit category"
|
||||
msgstr "Editar categoria"
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "Silenciada"
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2286,9 +2312,9 @@ msgstr "Fechar"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
@@ -2516,8 +2542,8 @@ msgid "No entries for this DCA"
|
||||
msgstr "Nenhuma entrada neste CMP"
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr "Tente adicionar uma"
|
||||
|
||||
@@ -2643,7 +2669,7 @@ msgstr "Nenhuma taxa de câmbio"
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr "Navegação por página"
|
||||
|
||||
@@ -2663,15 +2689,22 @@ msgstr "Alvos"
|
||||
msgid "Last fetch"
|
||||
msgstr "Última execução"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] "%(counter)s falha consecutiva"
|
||||
msgstr[1] "%(counter)s falhas consecutivas"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr "moedas"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr "contas"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr "Nenhum serviço configurado"
|
||||
|
||||
@@ -2927,7 +2960,11 @@ msgid "Final total"
|
||||
msgstr "Total final"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
@@ -2971,6 +3008,63 @@ msgstr "Nenhuma transação atrasada"
|
||||
msgid "No recent transactions"
|
||||
msgstr "Nenhuma transação recente"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
msgid "Tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr "Jan"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr "Fev"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr "Mar"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr "Abr"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr "Mai"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr "Jun"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr "Jul"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr "Ago"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr "Set"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr "Out"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr "Nov"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr "Dez"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr "Nenhuma transação neste ano"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr "De"
|
||||
@@ -2979,6 +3073,10 @@ msgstr "De"
|
||||
msgid "Percentage"
|
||||
msgstr "Porcentagem"
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr "Sem transações"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr "Mês"
|
||||
@@ -3028,6 +3126,14 @@ msgstr "Últimas Transações"
|
||||
msgid "Emergency Fund"
|
||||
msgstr "Reserva de Emergência"
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr "Ano a ano"
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr "Mês a Mês"
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr "Adicionar parcelamento"
|
||||
@@ -3102,35 +3208,40 @@ msgstr "Preço unitário"
|
||||
msgid "Item"
|
||||
msgstr "Item"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr "atrasado"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr "Nenhuma transação neste mês"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr "Gasto Diário"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr "Esse é o total final dividido pelos dias restantes do mês"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr "atual"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr "previsto"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr "Despesas"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr "Distribuição"
|
||||
|
||||
@@ -3138,27 +3249,27 @@ msgstr "Distribuição"
|
||||
msgid "Summary"
|
||||
msgstr "Resumo"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr "Mais antigas primeiro"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr "Mais novas primeiro"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr "Filtrar transações"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr "Ordernar por"
|
||||
|
||||
@@ -3402,7 +3513,7 @@ msgstr "Editando"
|
||||
msgid "transactions"
|
||||
msgstr "transações"
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr "Nenhuma transação encontrada"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-04-14 06:16+0000\n"
|
||||
"Last-Translator: Emil <emil.bjorkroth@gmail.com>\n"
|
||||
"Language-Team: Swedish <https://translations.herculino.com/projects/wygiwyh/"
|
||||
@@ -67,24 +67,30 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
@@ -92,7 +98,7 @@ msgstr ""
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -161,8 +167,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -171,11 +177,11 @@ msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr ""
|
||||
@@ -190,8 +196,8 @@ msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -205,7 +211,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -216,14 +222,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -356,7 +362,7 @@ msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr ""
|
||||
|
||||
@@ -454,10 +460,10 @@ msgstr ""
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
|
||||
@@ -496,11 +502,11 @@ msgid "Decimal Places"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr ""
|
||||
@@ -561,9 +567,9 @@ msgstr ""
|
||||
msgid "Service Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -591,57 +597,57 @@ msgstr ""
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr ""
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
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:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -740,8 +746,8 @@ msgstr ""
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
@@ -773,27 +779,27 @@ msgstr ""
|
||||
msgid "DCA Entries"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -813,34 +819,42 @@ msgid "Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -992,10 +1006,12 @@ msgid "Run deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1088,15 +1104,15 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1107,14 +1123,14 @@ msgstr ""
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1125,27 +1141,27 @@ msgstr ""
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr ""
|
||||
|
||||
@@ -1301,53 +1317,65 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
msgid "Until"
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Reference date from"
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr ""
|
||||
|
||||
@@ -1435,10 +1463,12 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1446,11 +1476,11 @@ msgstr ""
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1461,11 +1491,11 @@ msgstr ""
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1477,113 +1507,113 @@ msgstr ""
|
||||
msgid "Deleted At"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1592,7 +1622,7 @@ msgstr ""
|
||||
msgid "Quick Transaction"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1698,7 +1728,7 @@ msgstr ""
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1738,30 +1768,30 @@ msgstr ""
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1803,10 +1833,10 @@ msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
@@ -2226,10 +2256,6 @@ msgstr ""
|
||||
msgid "Edit category"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2248,9 +2274,9 @@ msgstr ""
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
@@ -2478,8 +2504,8 @@ msgid "No entries for this DCA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr ""
|
||||
|
||||
@@ -2604,7 +2630,7 @@ msgstr ""
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr ""
|
||||
|
||||
@@ -2624,15 +2650,22 @@ msgstr ""
|
||||
msgid "Last fetch"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr ""
|
||||
|
||||
@@ -2882,7 +2915,11 @@ msgid "Final total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
@@ -2926,6 +2963,63 @@ msgstr ""
|
||||
msgid "No recent transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
msgid "No transactions for this year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
@@ -2934,6 +3028,10 @@ msgstr ""
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
msgid "No transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
@@ -2983,6 +3081,14 @@ msgstr ""
|
||||
msgid "Emergency Fund"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr ""
|
||||
@@ -3054,35 +3160,40 @@ msgstr ""
|
||||
msgid "Item"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
@@ -3090,27 +3201,27 @@ msgstr ""
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
@@ -3351,7 +3462,7 @@ msgstr ""
|
||||
msgid "transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-11-01 01:17+0000\n"
|
||||
"Last-Translator: mlystopad <mlystopadt@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <https://translations.herculino.com/projects/"
|
||||
@@ -68,24 +68,30 @@ msgstr "Новий баланс"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "Категорія"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "Мітки"
|
||||
@@ -93,7 +99,7 @@ msgstr "Мітки"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -166,8 +172,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -176,11 +182,11 @@ msgid "Account"
|
||||
msgstr "Рахунок"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "Рахунки"
|
||||
@@ -195,8 +201,8 @@ msgstr "Групу рахунків успішно додано"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -210,7 +216,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "Групу рахунків успішно оновлено"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -221,14 +227,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "Групу рахунків успішно видалено"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "Успішно прийнято право власності"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -368,7 +374,7 @@ msgid "Public"
|
||||
msgstr "Public"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "сьогодні"
|
||||
|
||||
@@ -472,10 +478,10 @@ msgstr "Видалити"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "Чисто"
|
||||
|
||||
@@ -514,11 +520,11 @@ msgid "Decimal Places"
|
||||
msgstr "Десяткові знаки"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "Валюти"
|
||||
@@ -579,9 +585,9 @@ msgstr "Назва сервісу"
|
||||
msgid "Service Type"
|
||||
msgstr "Тип сервісу"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -609,11 +615,11 @@ msgstr "Інтервал"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "Остання успішна вибірка"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "Цільові валюти"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
@@ -621,11 +627,11 @@ msgstr ""
|
||||
"Оберіть валюти для завантаження курсів обміну. Курси будуть завантажені для "
|
||||
"кожної валюти відносно встановленої валюти обміну."
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "Цільові Рахунки"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
@@ -633,35 +639,35 @@ msgstr ""
|
||||
"Оберіть рахунки для завантаження курсів обміну. Курси будуть завантажені для "
|
||||
"валюти кожного рахунку відносно встановленої валюти обміну."
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
#, fuzzy
|
||||
#| msgid "Exchange Rate"
|
||||
msgid "Single exchange rate"
|
||||
msgstr "Обмінний курс"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr ""
|
||||
"Створіть один курс обміну та оновлюйте його постійно. Це запобігає "
|
||||
"засміченню бази даних."
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "Сервіс Курсів Обміну"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "Сервіси Курсів Обміну"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr "Інтервал типу «Кожні X годин» потребує додатнього цілого числа."
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "Інтервал типу «Кожні X годин» повинен бути між 1 та 24."
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -669,7 +675,7 @@ msgstr ""
|
||||
"Неправильний формат годин. Використовуйте години, розділені комами (0–23) та/"
|
||||
"або діапазони (наприклад, '1-5,8,10-12')."
|
||||
|
||||
#: apps/currencies/models.py:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -770,8 +776,8 @@ msgstr "Валюта платежу"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "Примітки"
|
||||
|
||||
@@ -803,27 +809,27 @@ msgstr ""
|
||||
msgid "DCA Entries"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "Запис успішно додано"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "Запис успішно оновлено"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "Запис успішно видалено"
|
||||
|
||||
@@ -843,34 +849,42 @@ msgid "Transactions"
|
||||
msgstr "Транзакції"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "Категорії"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "Регулярні транзакції"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -1024,10 +1038,12 @@ msgid "Run deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1120,15 +1136,15 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1139,14 +1155,14 @@ msgstr ""
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1157,27 +1173,27 @@ msgstr ""
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr ""
|
||||
|
||||
@@ -1333,55 +1349,67 @@ msgstr ""
|
||||
msgid "Projected"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
msgid "Until"
|
||||
#: apps/transactions/filters.py:89
|
||||
msgid "Mute Status"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Reference date from"
|
||||
msgid "Date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
#, fuzzy
|
||||
#| msgid "Category"
|
||||
msgid "Categorized"
|
||||
msgstr "Категорія"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr ""
|
||||
|
||||
@@ -1469,10 +1497,12 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1480,11 +1510,11 @@ msgstr ""
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1495,11 +1525,11 @@ msgstr ""
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1511,113 +1541,113 @@ msgstr ""
|
||||
msgid "Deleted At"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1626,7 +1656,7 @@ msgstr ""
|
||||
msgid "Quick Transaction"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1734,7 +1764,7 @@ msgstr "Рахунок успішно видалено"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1774,30 +1804,30 @@ msgstr ""
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -1839,10 +1869,10 @@ msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
@@ -2262,10 +2292,6 @@ msgstr ""
|
||||
msgid "Edit category"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2284,9 +2310,9 @@ msgstr ""
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
@@ -2514,8 +2540,8 @@ msgid "No entries for this DCA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr ""
|
||||
|
||||
@@ -2640,7 +2666,7 @@ msgstr ""
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr ""
|
||||
|
||||
@@ -2660,15 +2686,23 @@ msgstr ""
|
||||
msgid "Last fetch"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr ""
|
||||
|
||||
@@ -2918,7 +2952,11 @@ msgid "Final total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
@@ -2962,6 +3000,69 @@ msgstr ""
|
||||
msgid "No recent transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
#, fuzzy
|
||||
#| msgid "Tags"
|
||||
msgid "Tag"
|
||||
msgstr "Мітки"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
#, fuzzy
|
||||
#| msgid "Now"
|
||||
msgid "Nov"
|
||||
msgstr "Зараз"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
#, fuzzy
|
||||
#| msgid "Transactions"
|
||||
msgid "No transactions for this year"
|
||||
msgstr "Транзакції"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr ""
|
||||
@@ -2970,6 +3071,12 @@ msgstr ""
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
#, fuzzy
|
||||
#| msgid "Transactions"
|
||||
msgid "No transactions"
|
||||
msgstr "Транзакції"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
@@ -3019,6 +3126,14 @@ msgstr ""
|
||||
msgid "Emergency Fund"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
msgid "Year by Year"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr ""
|
||||
@@ -3090,35 +3205,40 @@ msgstr ""
|
||||
msgid "Item"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
@@ -3126,27 +3246,27 @@ msgstr ""
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
@@ -3387,7 +3507,7 @@ msgstr ""
|
||||
msgid "transactions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-12-20 02:59+0000\n"
|
||||
"POT-Creation-Date: 2026-01-10 20:50+0000\n"
|
||||
"PO-Revision-Date: 2025-10-08 16:17+0000\n"
|
||||
"Last-Translator: doody <doodykimo@gmail.com>\n"
|
||||
"Language-Team: Chinese (Traditional Han script) <https://translations."
|
||||
@@ -67,24 +67,30 @@ msgstr "新的餘額"
|
||||
#: apps/transactions/forms.py:419 apps/transactions/forms.py:516
|
||||
#: apps/transactions/forms.py:523 apps/transactions/forms.py:707
|
||||
#: apps/transactions/forms.py:948 apps/transactions/models.py:322
|
||||
#: apps/transactions/models.py:574 apps/transactions/models.py:774
|
||||
#: apps/transactions/models.py:1022
|
||||
#: apps/transactions/models.py:578 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1026
|
||||
#: templates/insights/fragments/category_overview/index.html:86
|
||||
#: templates/insights/fragments/category_overview/index.html:542
|
||||
#: templates/insights/fragments/month_by_month.html:84
|
||||
#: templates/insights/fragments/year_by_year.html:52
|
||||
msgid "Category"
|
||||
msgstr "分類"
|
||||
|
||||
#: apps/accounts/forms.py:132 apps/dca/forms.py:95 apps/dca/forms.py:103
|
||||
#: apps/export_app/forms.py:43 apps/export_app/forms.py:132
|
||||
#: apps/rules/forms.py:184 apps/rules/forms.py:194 apps/rules/models.py:45
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:68
|
||||
#: apps/rules/models.py:315 apps/transactions/filters.py:73
|
||||
#: apps/transactions/forms.py:51 apps/transactions/forms.py:259
|
||||
#: apps/transactions/forms.py:427 apps/transactions/forms.py:532
|
||||
#: apps/transactions/forms.py:540 apps/transactions/forms.py:700
|
||||
#: apps/transactions/forms.py:941 apps/transactions/models.py:328
|
||||
#: apps/transactions/models.py:576 apps/transactions/models.py:778
|
||||
#: apps/transactions/models.py:1028 templates/includes/sidebar.html:150
|
||||
#: apps/transactions/models.py:580 apps/transactions/models.py:782
|
||||
#: apps/transactions/models.py:1032 templates/includes/sidebar.html:150
|
||||
#: templates/insights/fragments/category_overview/index.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:29
|
||||
#: templates/insights/fragments/month_by_month.html:32
|
||||
#: templates/insights/fragments/year_by_year.html:24
|
||||
#: templates/insights/fragments/year_by_year.html:27
|
||||
#: templates/tags/fragments/list.html:9 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr "標籤"
|
||||
@@ -92,7 +98,7 @@ msgstr "標籤"
|
||||
#: apps/accounts/models.py:12 apps/accounts/models.py:29 apps/dca/models.py:13
|
||||
#: apps/import_app/models.py:14 apps/rules/models.py:13
|
||||
#: apps/transactions/models.py:214 apps/transactions/models.py:239
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:990
|
||||
#: apps/transactions/models.py:263 apps/transactions/models.py:994
|
||||
#: templates/account_groups/fragments/list.html:22
|
||||
#: templates/accounts/fragments/list.html:22
|
||||
#: templates/categories/fragments/table.html:17
|
||||
@@ -161,8 +167,8 @@ msgstr "封存的帳戶不會在淨資產中被計算或顯示"
|
||||
#: apps/transactions/forms.py:63 apps/transactions/forms.py:271
|
||||
#: apps/transactions/forms.py:386 apps/transactions/forms.py:692
|
||||
#: apps/transactions/forms.py:933 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:534 apps/transactions/models.py:756
|
||||
#: apps/transactions/models.py:996
|
||||
#: apps/transactions/models.py:538 apps/transactions/models.py:760
|
||||
#: apps/transactions/models.py:1000
|
||||
#: templates/installment_plans/fragments/table.html:17
|
||||
#: templates/quick_transactions/fragments/list.html:14
|
||||
#: templates/recurring_transactions/fragments/table.html:19
|
||||
@@ -171,11 +177,11 @@ msgid "Account"
|
||||
msgstr "帳戶"
|
||||
|
||||
#: apps/accounts/models.py:76 apps/export_app/forms.py:19
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:52
|
||||
#: apps/export_app/forms.py:129 apps/transactions/filters.py:57
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/accounts/pages/index.html:4 templates/includes/sidebar.html:162
|
||||
#: templates/includes/sidebar.html:164
|
||||
#: templates/monthly_overview/pages/overview.html:75
|
||||
#: templates/monthly_overview/pages/overview.html:77
|
||||
#: templates/transactions/pages/transactions.html:26
|
||||
msgid "Accounts"
|
||||
msgstr "帳戶"
|
||||
@@ -190,8 +196,8 @@ msgstr "成功新增帳戶組"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
|
||||
#: apps/dca/views.py:146 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:62
|
||||
#: apps/dca/views.py:145 apps/rules/views.py:118 apps/rules/views.py:228
|
||||
#: apps/transactions/views/categories.py:91
|
||||
#: apps/transactions/views/categories.py:129
|
||||
#: apps/transactions/views/entities.py:91
|
||||
@@ -205,7 +211,7 @@ msgid "Account Group updated successfully"
|
||||
msgstr "成功更新帳戶組"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:104
|
||||
#: apps/rules/views.py:185 apps/transactions/views/categories.py:168
|
||||
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
|
||||
msgid "Item no longer shared with you"
|
||||
@@ -216,14 +222,14 @@ msgid "Account Group deleted successfully"
|
||||
msgstr "成功刪除帳戶組"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:129
|
||||
#: apps/accounts/views/accounts.py:189 apps/dca/views.py:128
|
||||
#: apps/rules/views.py:210 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr "成功取得所有權"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:158
|
||||
#: apps/rules/views.py:241 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
@@ -360,7 +366,7 @@ msgid "Public"
|
||||
msgstr "公開"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:10
|
||||
msgid "today"
|
||||
msgstr "今天"
|
||||
|
||||
@@ -452,10 +458,10 @@ msgstr "移除"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:180
|
||||
#: templates/monthly_overview/pages/overview.html:171
|
||||
#: templates/monthly_overview/pages/overview.html:183
|
||||
#: templates/transactions/pages/transactions.html:124
|
||||
#: templates/transactions/pages/transactions.html:136
|
||||
#: templates/monthly_overview/pages/overview.html:275
|
||||
#: templates/monthly_overview/pages/overview.html:287
|
||||
#: templates/transactions/pages/transactions.html:225
|
||||
#: templates/transactions/pages/transactions.html:237
|
||||
msgid "Clear"
|
||||
msgstr "清除"
|
||||
|
||||
@@ -494,11 +500,11 @@ msgid "Decimal Places"
|
||||
msgstr "小數點後位數"
|
||||
|
||||
#: apps/currencies/models.py:45 apps/export_app/forms.py:25
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:59
|
||||
#: apps/export_app/forms.py:130 apps/transactions/filters.py:64
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
#: templates/currencies/pages/index.html:4 templates/includes/sidebar.html:176
|
||||
#: templates/includes/sidebar.html:178
|
||||
#: templates/monthly_overview/pages/overview.html:62
|
||||
#: templates/monthly_overview/pages/overview.html:63
|
||||
#: templates/transactions/pages/transactions.html:12
|
||||
msgid "Currencies"
|
||||
msgstr "貨幣"
|
||||
@@ -559,9 +565,9 @@ msgstr "服務名稱"
|
||||
msgid "Service Type"
|
||||
msgstr "服務類型"
|
||||
|
||||
#: apps/currencies/models.py:118 apps/transactions/models.py:218
|
||||
#: apps/transactions/models.py:242 apps/transactions/models.py:266
|
||||
#: templates/categories/fragments/list.html:16
|
||||
#: apps/currencies/models.py:118 apps/transactions/filters.py:27
|
||||
#: apps/transactions/models.py:218 apps/transactions/models.py:242
|
||||
#: apps/transactions/models.py:266 templates/categories/fragments/list.html:16
|
||||
#: templates/entities/fragments/list.html:16
|
||||
#: templates/installment_plans/fragments/list.html:16
|
||||
#: templates/recurring_transactions/fragments/list.html:16
|
||||
@@ -589,51 +595,51 @@ msgstr "間隔"
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr "最後更新時間"
|
||||
|
||||
#: apps/currencies/models.py:141
|
||||
#: apps/currencies/models.py:143
|
||||
msgid "Target Currencies"
|
||||
msgstr "目標貨幣"
|
||||
|
||||
#: apps/currencies/models.py:143
|
||||
#: apps/currencies/models.py:145
|
||||
msgid ""
|
||||
"Select currencies to fetch exchange rates for. Rates will be fetched for "
|
||||
"each currency against their set exchange currency."
|
||||
msgstr "選擇要自動擷取匯率的貨幣,貨幣會根據設定的目標貨幣自動取得匯率資訊。"
|
||||
|
||||
#: apps/currencies/models.py:151
|
||||
#: apps/currencies/models.py:153
|
||||
msgid "Target Accounts"
|
||||
msgstr "目標帳戶"
|
||||
|
||||
#: apps/currencies/models.py:153
|
||||
#: apps/currencies/models.py:155
|
||||
msgid ""
|
||||
"Select accounts to fetch exchange rates for. Rates will be fetched for each "
|
||||
"account's currency against their set exchange currency."
|
||||
msgstr "選擇自動擷取匯率的帳戶,帳戶會根據設定的匯兌貨幣取得匯率資訊。"
|
||||
|
||||
#: apps/currencies/models.py:160
|
||||
#: apps/currencies/models.py:162
|
||||
msgid "Single exchange rate"
|
||||
msgstr "保留單一匯率資訊"
|
||||
|
||||
#: apps/currencies/models.py:163
|
||||
#: apps/currencies/models.py:165
|
||||
msgid "Create one exchange rate and keep updating it. Avoids database clutter."
|
||||
msgstr "只建立一筆匯率資訊並且持續更新,防止資料庫無限擴張。"
|
||||
|
||||
#: apps/currencies/models.py:168
|
||||
#: apps/currencies/models.py:170
|
||||
msgid "Exchange Rate Service"
|
||||
msgstr "匯率資訊服務"
|
||||
|
||||
#: apps/currencies/models.py:169
|
||||
#: apps/currencies/models.py:171
|
||||
msgid "Exchange Rate Services"
|
||||
msgstr "匯率資訊服務"
|
||||
|
||||
#: apps/currencies/models.py:221
|
||||
#: apps/currencies/models.py:223
|
||||
msgid "'Every X hours' interval type requires a positive integer."
|
||||
msgstr "「每X小時」需要提供正整數。"
|
||||
|
||||
#: apps/currencies/models.py:230
|
||||
#: apps/currencies/models.py:232
|
||||
msgid "'Every X hours' interval must be between 1 and 24."
|
||||
msgstr "「每X小時」需要介於1到24之間。"
|
||||
|
||||
#: apps/currencies/models.py:244
|
||||
#: apps/currencies/models.py:246
|
||||
msgid ""
|
||||
"Invalid hour format. Use comma-separated hours (0-23) and/or ranges (e.g., "
|
||||
"'1-5,8,10-12')."
|
||||
@@ -641,7 +647,7 @@ msgstr ""
|
||||
"錯誤的小時格式,請使用逗號設定多個小時(0~23)或著設定範圍(例"
|
||||
"如:'1-5,10-12')。"
|
||||
|
||||
#: apps/currencies/models.py:255
|
||||
#: apps/currencies/models.py:257
|
||||
msgid ""
|
||||
"Invalid format. Please check the requirements for your selected interval "
|
||||
"type."
|
||||
@@ -740,8 +746,8 @@ msgstr "交易貨幣"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:180
|
||||
#: apps/rules/forms.py:196 apps/rules/models.py:43 apps/rules/models.py:295
|
||||
#: apps/transactions/forms.py:413 apps/transactions/forms.py:560
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:784 apps/transactions/models.py:1018
|
||||
#: apps/transactions/models.py:318 apps/transactions/models.py:587
|
||||
#: apps/transactions/models.py:788 apps/transactions/models.py:1022
|
||||
msgid "Notes"
|
||||
msgstr "備註"
|
||||
|
||||
@@ -773,27 +779,27 @@ msgstr "定期定額投入"
|
||||
msgid "DCA Entries"
|
||||
msgstr "定期定額投入"
|
||||
|
||||
#: apps/dca/views.py:39
|
||||
#: apps/dca/views.py:38
|
||||
msgid "DCA Strategy added successfully"
|
||||
msgstr "成功新增定期定額策略"
|
||||
|
||||
#: apps/dca/views.py:76
|
||||
#: apps/dca/views.py:75
|
||||
msgid "DCA Strategy updated successfully"
|
||||
msgstr "成功更新定期定額策略"
|
||||
|
||||
#: apps/dca/views.py:108
|
||||
#: apps/dca/views.py:107
|
||||
msgid "DCA strategy deleted successfully"
|
||||
msgstr "成功刪除定期定額策略"
|
||||
|
||||
#: apps/dca/views.py:238
|
||||
#: apps/dca/views.py:237
|
||||
msgid "Entry added successfully"
|
||||
msgstr "成功新增投入"
|
||||
|
||||
#: apps/dca/views.py:265
|
||||
#: apps/dca/views.py:264
|
||||
msgid "Entry updated successfully"
|
||||
msgstr "成功更新投入"
|
||||
|
||||
#: apps/dca/views.py:291
|
||||
#: apps/dca/views.py:290
|
||||
msgid "Entry deleted successfully"
|
||||
msgstr "成功刪除投入"
|
||||
|
||||
@@ -813,34 +819,42 @@ msgid "Transactions"
|
||||
msgstr "交易"
|
||||
|
||||
#: apps/export_app/forms.py:37 apps/export_app/forms.py:131
|
||||
#: apps/transactions/filters.py:63 templates/categories/fragments/list.html:9
|
||||
#: apps/transactions/filters.py:68 templates/categories/fragments/list.html:9
|
||||
#: templates/categories/pages/index.html:4 templates/includes/sidebar.html:144
|
||||
#: templates/insights/fragments/month_by_month.html:18
|
||||
#: templates/insights/fragments/month_by_month.html:21
|
||||
#: templates/insights/fragments/year_by_year.html:13
|
||||
#: templates/insights/fragments/year_by_year.html:16
|
||||
msgid "Categories"
|
||||
msgstr "類別"
|
||||
|
||||
#: apps/export_app/forms.py:49 apps/export_app/forms.py:133
|
||||
#: apps/rules/forms.py:185 apps/rules/forms.py:195 apps/rules/models.py:46
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:73
|
||||
#: apps/rules/models.py:307 apps/transactions/filters.py:78
|
||||
#: apps/transactions/forms.py:59 apps/transactions/forms.py:267
|
||||
#: apps/transactions/forms.py:435 apps/transactions/forms.py:715
|
||||
#: apps/transactions/forms.py:956 apps/transactions/models.py:277
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:579
|
||||
#: apps/transactions/models.py:781 apps/transactions/models.py:1033
|
||||
#: apps/transactions/models.py:333 apps/transactions/models.py:583
|
||||
#: apps/transactions/models.py:785 apps/transactions/models.py:1037
|
||||
#: templates/entities/fragments/list.html:9
|
||||
#: templates/entities/pages/index.html:4 templates/includes/sidebar.html:156
|
||||
#: templates/insights/fragments/category_overview/index.html:54
|
||||
#: templates/insights/fragments/month_by_month.html:40
|
||||
#: templates/insights/fragments/month_by_month.html:43
|
||||
#: templates/insights/fragments/year_by_year.html:35
|
||||
#: templates/insights/fragments/year_by_year.html:38
|
||||
msgid "Entities"
|
||||
msgstr "實體"
|
||||
|
||||
#: apps/export_app/forms.py:55 apps/export_app/forms.py:137
|
||||
#: apps/transactions/models.py:821 templates/includes/sidebar.html:110
|
||||
#: apps/transactions/models.py:825 templates/includes/sidebar.html:110
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
msgstr "定期扣款交易"
|
||||
|
||||
#: apps/export_app/forms.py:61 apps/export_app/forms.py:135
|
||||
#: apps/transactions/models.py:597 templates/includes/sidebar.html:104
|
||||
#: apps/transactions/models.py:601 templates/includes/sidebar.html:104
|
||||
#: templates/installment_plans/fragments/list.html:9
|
||||
#: templates/installment_plans/pages/index.html:4
|
||||
msgid "Installment Plans"
|
||||
@@ -992,10 +1006,12 @@ msgid "Run deleted successfully"
|
||||
msgstr "成功刪除匯入任務"
|
||||
|
||||
#: apps/insights/forms.py:118 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:186
|
||||
#: apps/insights/utils/sankey.py:167 apps/transactions/filters.py:203
|
||||
#: templates/insights/fragments/category_overview/index.html:96
|
||||
#: templates/insights/fragments/category_overview/index.html:407
|
||||
#: templates/insights/fragments/category_overview/index.html:436
|
||||
#: templates/insights/fragments/month_by_month.html:119
|
||||
#: templates/insights/fragments/year_by_year.html:73
|
||||
msgid "Uncategorized"
|
||||
msgstr "未分類"
|
||||
|
||||
@@ -1088,15 +1104,15 @@ msgstr "運算子"
|
||||
|
||||
#: apps/rules/forms.py:174 apps/rules/forms.py:188 apps/rules/models.py:36
|
||||
#: apps/rules/models.py:271 apps/transactions/forms.py:377
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:539
|
||||
#: apps/transactions/models.py:762 apps/transactions/models.py:1003
|
||||
#: apps/transactions/models.py:301 apps/transactions/models.py:543
|
||||
#: apps/transactions/models.py:766 apps/transactions/models.py:1007
|
||||
msgid "Type"
|
||||
msgstr "種類"
|
||||
|
||||
#: apps/rules/forms.py:175 apps/rules/forms.py:189 apps/rules/models.py:37
|
||||
#: apps/rules/models.py:275 apps/transactions/filters.py:22
|
||||
#: apps/transactions/forms.py:381 apps/transactions/models.py:303
|
||||
#: apps/transactions/models.py:1005 templates/cotton/transaction/item.html:20
|
||||
#: apps/transactions/models.py:1009 templates/cotton/transaction/item.html:20
|
||||
#: templates/cotton/transaction/item.html:31
|
||||
#: templates/transactions/widgets/paid_toggle_button.html:10
|
||||
#: templates/transactions/widgets/unselectable_paid_toggle_button.html:13
|
||||
@@ -1107,14 +1123,14 @@ msgstr "已支付"
|
||||
#: apps/rules/models.py:283 apps/transactions/forms.py:71
|
||||
#: apps/transactions/forms.py:397 apps/transactions/forms.py:547
|
||||
#: apps/transactions/forms.py:721 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:557 apps/transactions/models.py:786
|
||||
#: apps/transactions/models.py:561 apps/transactions/models.py:790
|
||||
msgid "Reference Date"
|
||||
msgstr "起算日"
|
||||
|
||||
#: apps/rules/forms.py:178 apps/rules/forms.py:192 apps/rules/models.py:41
|
||||
#: apps/rules/models.py:287 apps/transactions/forms.py:404
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:767
|
||||
#: apps/transactions/models.py:1011
|
||||
#: apps/transactions/models.py:311 apps/transactions/models.py:771
|
||||
#: apps/transactions/models.py:1015
|
||||
#: templates/insights/fragments/sankey.html:102
|
||||
#: templates/installment_plans/fragments/table.html:18
|
||||
#: templates/quick_transactions/fragments/list.html:15
|
||||
@@ -1125,27 +1141,27 @@ msgstr "金額"
|
||||
#: apps/rules/forms.py:179 apps/rules/forms.py:193 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:42 apps/rules/models.py:291
|
||||
#: apps/transactions/forms.py:408 apps/transactions/forms.py:551
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:541
|
||||
#: apps/transactions/models.py:770 apps/transactions/models.py:1016
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:545
|
||||
#: apps/transactions/models.py:774 apps/transactions/models.py:1020
|
||||
msgid "Description"
|
||||
msgstr "描述"
|
||||
|
||||
#: apps/rules/forms.py:182 apps/rules/forms.py:198 apps/rules/models.py:47
|
||||
#: apps/rules/models.py:299 apps/transactions/models.py:355
|
||||
#: apps/transactions/models.py:1038
|
||||
#: apps/transactions/models.py:1042
|
||||
msgid "Internal Note"
|
||||
msgstr "內部註記"
|
||||
|
||||
#: apps/rules/forms.py:183 apps/rules/forms.py:199 apps/rules/models.py:48
|
||||
#: apps/rules/models.py:303 apps/transactions/models.py:357
|
||||
#: apps/transactions/models.py:1040
|
||||
#: apps/transactions/models.py:1044
|
||||
msgid "Internal ID"
|
||||
msgstr "內部ID"
|
||||
|
||||
#: apps/rules/forms.py:186 apps/rules/forms.py:200 apps/rules/models.py:40
|
||||
#: apps/rules/models.py:319 apps/transactions/forms.py:564
|
||||
#: apps/transactions/models.py:215 apps/transactions/models.py:306
|
||||
#: apps/transactions/models.py:1006
|
||||
#: apps/transactions/models.py:1010
|
||||
msgid "Mute"
|
||||
msgstr "靜音"
|
||||
|
||||
@@ -1301,53 +1317,67 @@ msgstr "成功刪除「更新或建立交易行為」"
|
||||
msgid "Projected"
|
||||
msgstr "預期"
|
||||
|
||||
#: apps/transactions/filters.py:40
|
||||
#: apps/transactions/filters.py:28 templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "已靜音"
|
||||
|
||||
#: apps/transactions/filters.py:45
|
||||
msgid "Content"
|
||||
msgstr "內容"
|
||||
|
||||
#: apps/transactions/filters.py:46
|
||||
#: apps/transactions/filters.py:51
|
||||
msgid "Transaction Type"
|
||||
msgstr "交易種類"
|
||||
|
||||
#: apps/transactions/filters.py:84
|
||||
#: apps/transactions/filters.py:89
|
||||
#, fuzzy
|
||||
#| msgid "Status"
|
||||
msgid "Mute Status"
|
||||
msgstr "狀態"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
msgid "Date from"
|
||||
msgstr "起始日期"
|
||||
|
||||
#: apps/transactions/filters.py:89 apps/transactions/filters.py:99
|
||||
#: apps/transactions/filters.py:99 apps/transactions/filters.py:109
|
||||
msgid "Until"
|
||||
msgstr "直到"
|
||||
|
||||
#: apps/transactions/filters.py:94
|
||||
#: apps/transactions/filters.py:104
|
||||
msgid "Reference date from"
|
||||
msgstr "起算日日期"
|
||||
|
||||
#: apps/transactions/filters.py:104
|
||||
#: apps/transactions/filters.py:114
|
||||
msgid "Amount min"
|
||||
msgstr "最小金額"
|
||||
|
||||
#: apps/transactions/filters.py:109
|
||||
#: apps/transactions/filters.py:119
|
||||
msgid "Amount max"
|
||||
msgstr "最大金額"
|
||||
|
||||
#: apps/transactions/filters.py:185
|
||||
#: apps/transactions/filters.py:202
|
||||
msgid "Categorized"
|
||||
msgstr "已分類"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
msgid "Tagged"
|
||||
msgstr "已標籤"
|
||||
|
||||
#: apps/transactions/filters.py:192
|
||||
#: apps/transactions/filters.py:209
|
||||
#: templates/insights/fragments/category_overview/index.html:189
|
||||
#: templates/insights/fragments/month_by_month.html:121
|
||||
#: templates/insights/fragments/year_by_year.html:75
|
||||
msgid "Untagged"
|
||||
msgstr "未標籤"
|
||||
|
||||
#: apps/transactions/filters.py:198
|
||||
#: apps/transactions/filters.py:215
|
||||
msgid "Any entity"
|
||||
msgstr "任何實體"
|
||||
|
||||
#: apps/transactions/filters.py:199
|
||||
#: apps/transactions/filters.py:216
|
||||
#: templates/insights/fragments/category_overview/index.html:282
|
||||
#: templates/insights/fragments/month_by_month.html:123
|
||||
#: templates/insights/fragments/year_by_year.html:77
|
||||
msgid "No entity"
|
||||
msgstr "無實體"
|
||||
|
||||
@@ -1435,10 +1465,12 @@ msgid ""
|
||||
msgstr "新增交易的時候無法選擇停用的實體"
|
||||
|
||||
#: apps/transactions/models.py:276
|
||||
#: templates/insights/fragments/month_by_month.html:88
|
||||
#: templates/insights/fragments/year_by_year.html:56
|
||||
msgid "Entity"
|
||||
msgstr "實體"
|
||||
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:983
|
||||
#: apps/transactions/models.py:288 apps/transactions/models.py:987
|
||||
#: templates/calendar_view/fragments/list.html:42
|
||||
#: templates/calendar_view/fragments/list.html:44
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
@@ -1446,11 +1478,11 @@ msgstr "實體"
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/cotton/ui/transactions_fab.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:41
|
||||
msgid "Income"
|
||||
msgstr "收入"
|
||||
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:984
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:988
|
||||
#: templates/calendar_view/fragments/list.html:46
|
||||
#: templates/calendar_view/fragments/list.html:48
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
@@ -1461,11 +1493,11 @@ msgstr "收入"
|
||||
msgid "Expense"
|
||||
msgstr "支出"
|
||||
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:596
|
||||
#: apps/transactions/models.py:344 apps/transactions/models.py:600
|
||||
msgid "Installment Plan"
|
||||
msgstr "分期付款計劃"
|
||||
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:820
|
||||
#: apps/transactions/models.py:353 apps/transactions/models.py:824
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "定期扣款交易"
|
||||
|
||||
@@ -1477,113 +1509,113 @@ msgstr "已刪除"
|
||||
msgid "Deleted At"
|
||||
msgstr "刪除時間"
|
||||
|
||||
#: apps/transactions/models.py:476 templates/tags/fragments/table.html:69
|
||||
#: apps/transactions/models.py:480 templates/tags/fragments/table.html:69
|
||||
msgid "No tags"
|
||||
msgstr "沒有標籤"
|
||||
|
||||
#: apps/transactions/models.py:478
|
||||
#: apps/transactions/models.py:482
|
||||
msgid "No category"
|
||||
msgstr "沒有分類"
|
||||
|
||||
#: apps/transactions/models.py:480
|
||||
#: apps/transactions/models.py:484
|
||||
msgid "No description"
|
||||
msgstr "沒有描述"
|
||||
|
||||
#: apps/transactions/models.py:528 templates/includes/sidebar.html:57
|
||||
#: apps/transactions/models.py:532 templates/includes/sidebar.html:57
|
||||
msgid "Yearly"
|
||||
msgstr "年"
|
||||
|
||||
#: apps/transactions/models.py:529 apps/users/models.py:464
|
||||
#: apps/transactions/models.py:533 apps/users/models.py:464
|
||||
#: templates/includes/sidebar.html:51
|
||||
msgid "Monthly"
|
||||
msgstr "月"
|
||||
|
||||
#: apps/transactions/models.py:530
|
||||
#: apps/transactions/models.py:534
|
||||
msgid "Weekly"
|
||||
msgstr "週"
|
||||
|
||||
#: apps/transactions/models.py:531
|
||||
#: apps/transactions/models.py:535
|
||||
msgid "Daily"
|
||||
msgstr "日"
|
||||
|
||||
#: apps/transactions/models.py:544
|
||||
#: apps/transactions/models.py:548
|
||||
msgid "Number of Installments"
|
||||
msgstr "期數"
|
||||
|
||||
#: apps/transactions/models.py:549
|
||||
#: apps/transactions/models.py:553
|
||||
msgid "Installment Start"
|
||||
msgstr "分期付款起始日"
|
||||
|
||||
#: apps/transactions/models.py:550
|
||||
#: apps/transactions/models.py:554
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "開始計算的期數"
|
||||
|
||||
#: apps/transactions/models.py:555 apps/transactions/models.py:790
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:794
|
||||
msgid "Start Date"
|
||||
msgstr "起始日期"
|
||||
|
||||
#: apps/transactions/models.py:559 apps/transactions/models.py:791
|
||||
#: apps/transactions/models.py:563 apps/transactions/models.py:795
|
||||
msgid "End Date"
|
||||
msgstr "結束日期"
|
||||
|
||||
#: apps/transactions/models.py:564
|
||||
#: apps/transactions/models.py:568
|
||||
msgid "Recurrence"
|
||||
msgstr "頻率"
|
||||
|
||||
#: apps/transactions/models.py:567
|
||||
#: apps/transactions/models.py:571
|
||||
msgid "Installment Amount"
|
||||
msgstr "分期付款金額"
|
||||
|
||||
#: apps/transactions/models.py:586 apps/transactions/models.py:810
|
||||
#: apps/transactions/models.py:590 apps/transactions/models.py:814
|
||||
msgid "Add description to transactions"
|
||||
msgstr "為交易增加描述"
|
||||
|
||||
#: apps/transactions/models.py:589 apps/transactions/models.py:813
|
||||
#: apps/transactions/models.py:593 apps/transactions/models.py:817
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "為交易新增註記"
|
||||
|
||||
#: apps/transactions/models.py:749
|
||||
#: apps/transactions/models.py:753
|
||||
msgid "day(s)"
|
||||
msgstr "天"
|
||||
|
||||
#: apps/transactions/models.py:750
|
||||
#: apps/transactions/models.py:754
|
||||
msgid "week(s)"
|
||||
msgstr "週"
|
||||
|
||||
#: apps/transactions/models.py:751
|
||||
#: apps/transactions/models.py:755
|
||||
msgid "month(s)"
|
||||
msgstr "月"
|
||||
|
||||
#: apps/transactions/models.py:752
|
||||
#: apps/transactions/models.py:756
|
||||
msgid "year(s)"
|
||||
msgstr "年"
|
||||
|
||||
#: apps/transactions/models.py:754
|
||||
#: apps/transactions/models.py:758
|
||||
#: templates/recurring_transactions/fragments/list.html:18
|
||||
msgid "Paused"
|
||||
msgstr "已暫停"
|
||||
|
||||
#: apps/transactions/models.py:793
|
||||
#: apps/transactions/models.py:797
|
||||
msgid "Recurrence Type"
|
||||
msgstr "頻率"
|
||||
|
||||
#: apps/transactions/models.py:796
|
||||
#: apps/transactions/models.py:800
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "頻率間隔"
|
||||
|
||||
#: apps/transactions/models.py:799
|
||||
#: apps/transactions/models.py:803
|
||||
msgid "Keep at most"
|
||||
msgstr "持續最多"
|
||||
|
||||
#: apps/transactions/models.py:803
|
||||
#: apps/transactions/models.py:807
|
||||
msgid "Last Generated Date"
|
||||
msgstr "最後產生的日期"
|
||||
|
||||
#: apps/transactions/models.py:806
|
||||
#: apps/transactions/models.py:810
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "最後產生的起算日"
|
||||
|
||||
#: apps/transactions/models.py:1050
|
||||
#: apps/transactions/models.py:1054
|
||||
#: apps/transactions/views/quick_transactions.py:178
|
||||
#: apps/transactions/views/quick_transactions.py:187
|
||||
#: apps/transactions/views/quick_transactions.py:189
|
||||
@@ -1592,7 +1624,7 @@ msgstr "最後產生的起算日"
|
||||
msgid "Quick Transaction"
|
||||
msgstr "快速交易"
|
||||
|
||||
#: apps/transactions/models.py:1051 templates/includes/sidebar.html:98
|
||||
#: apps/transactions/models.py:1055 templates/includes/sidebar.html:98
|
||||
#: templates/quick_transactions/pages/index.html:5
|
||||
#: templates/quick_transactions/pages/index.html:15
|
||||
msgid "Quick Transactions"
|
||||
@@ -1693,7 +1725,7 @@ msgstr "成功刪除項目"
|
||||
|
||||
#: apps/transactions/views/quick_transactions.py:156
|
||||
#: apps/transactions/views/transactions.py:53
|
||||
#: apps/transactions/views/transactions.py:228
|
||||
#: apps/transactions/views/transactions.py:238
|
||||
msgid "Transaction added successfully"
|
||||
msgstr "成功新增交易"
|
||||
|
||||
@@ -1733,29 +1765,29 @@ msgstr "成功更新標籤"
|
||||
msgid "Tag deleted successfully"
|
||||
msgstr "成功刪除標籤"
|
||||
|
||||
#: apps/transactions/views/transactions.py:252
|
||||
#: apps/transactions/views/transactions.py:262
|
||||
msgid "Transaction updated successfully"
|
||||
msgstr "成功更新交易"
|
||||
|
||||
#: apps/transactions/views/transactions.py:303
|
||||
#: apps/transactions/views/transactions.py:313
|
||||
#, python-format
|
||||
msgid "%(count)s transaction updated successfully"
|
||||
msgid_plural "%(count)s transactions updated successfully"
|
||||
msgstr[0] "成功更新%(count)s筆交易"
|
||||
|
||||
#: apps/transactions/views/transactions.py:339
|
||||
#: apps/transactions/views/transactions.py:349
|
||||
msgid "Transaction duplicated successfully"
|
||||
msgstr "成功複製交易"
|
||||
|
||||
#: apps/transactions/views/transactions.py:381
|
||||
#: apps/transactions/views/transactions.py:391
|
||||
msgid "Transaction deleted successfully"
|
||||
msgstr "成功刪除交易"
|
||||
|
||||
#: apps/transactions/views/transactions.py:399
|
||||
#: apps/transactions/views/transactions.py:409
|
||||
msgid "Transaction restored successfully"
|
||||
msgstr "成功復原交易"
|
||||
|
||||
#: apps/transactions/views/transactions.py:425
|
||||
#: apps/transactions/views/transactions.py:435
|
||||
msgid "Transfer added successfully"
|
||||
msgstr "成功新增轉帳"
|
||||
|
||||
@@ -1797,10 +1829,10 @@ msgid "This account is deactivated"
|
||||
msgstr "這個帳號已經被停用"
|
||||
|
||||
#: apps/users/forms.py:62 apps/users/forms.py:75 apps/users/forms.py:97
|
||||
#: templates/monthly_overview/pages/overview.html:95
|
||||
#: templates/monthly_overview/pages/overview.html:141
|
||||
#: templates/monthly_overview/pages/overview.html:98
|
||||
#: templates/monthly_overview/pages/overview.html:245
|
||||
#: templates/transactions/pages/transactions.html:47
|
||||
#: templates/transactions/pages/transactions.html:94
|
||||
#: templates/transactions/pages/transactions.html:195
|
||||
msgid "Default"
|
||||
msgstr "預設"
|
||||
|
||||
@@ -2222,10 +2254,6 @@ msgstr "新增分類"
|
||||
msgid "Edit category"
|
||||
msgstr "編輯分類"
|
||||
|
||||
#: templates/categories/fragments/table.html:18
|
||||
msgid "Muted"
|
||||
msgstr "已靜音"
|
||||
|
||||
#: templates/categories/fragments/table.html:73
|
||||
#: templates/insights/fragments/category_overview/index.html:552
|
||||
msgid "No categories"
|
||||
@@ -2244,9 +2272,9 @@ msgstr "關閉"
|
||||
|
||||
#: templates/cotton/config/search.html:6
|
||||
#: templates/import_app/fragments/profiles/list_presets.html:13
|
||||
#: templates/monthly_overview/pages/overview.html:115
|
||||
#: templates/monthly_overview/pages/overview.html:219
|
||||
#: templates/rules/fragments/transaction_rule/dry_run/visual.html:57
|
||||
#: templates/transactions/pages/transactions.html:67
|
||||
#: templates/transactions/pages/transactions.html:168
|
||||
msgid "Search"
|
||||
msgstr "搜尋"
|
||||
|
||||
@@ -2480,8 +2508,8 @@ msgid "No entries for this DCA"
|
||||
msgstr "這個定期定額沒有投入"
|
||||
|
||||
#: templates/dca/fragments/strategy/details.html:120
|
||||
#: templates/monthly_overview/fragments/list.html:33
|
||||
#: templates/transactions/fragments/list_all.html:33
|
||||
#: templates/monthly_overview/fragments/list.html:59
|
||||
#: templates/transactions/fragments/list_all.html:59
|
||||
msgid "Try adding one"
|
||||
msgstr "試著增加一個"
|
||||
|
||||
@@ -2606,7 +2634,7 @@ msgstr "沒有匯率"
|
||||
|
||||
#: templates/exchange_rates/fragments/table.html:56
|
||||
#: templates/exchange_rates_services/fragments/table.html:57
|
||||
#: templates/transactions/fragments/list_all.html:43
|
||||
#: templates/transactions/fragments/list_all.html:70
|
||||
msgid "Page navigation"
|
||||
msgstr "頁面導覽"
|
||||
|
||||
@@ -2626,15 +2654,21 @@ msgstr "目標"
|
||||
msgid "Last fetch"
|
||||
msgstr "最後更新"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:62
|
||||
#, python-format
|
||||
msgid "%(counter)s consecutive failure"
|
||||
msgid_plural "%(counter)s consecutive failures"
|
||||
msgstr[0] ""
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "currencies"
|
||||
msgstr "貨幣"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:61
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
msgid "accounts"
|
||||
msgstr "帳戶"
|
||||
|
||||
#: templates/exchange_rates_services/fragments/list.html:69
|
||||
#: templates/exchange_rates_services/fragments/list.html:77
|
||||
msgid "No services configured"
|
||||
msgstr "沒有設定任何服務"
|
||||
|
||||
@@ -2884,7 +2918,11 @@ msgid "Final total"
|
||||
msgstr "最終總額"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:89
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:165
|
||||
#: templates/insights/fragments/month_by_month.html:91
|
||||
#: templates/insights/fragments/month_by_month.html:186
|
||||
#: templates/insights/fragments/year_by_year.html:59
|
||||
#: templates/insights/fragments/year_by_year.html:140
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "總額"
|
||||
|
||||
@@ -2928,6 +2966,75 @@ msgstr "沒有逾期交易"
|
||||
msgid "No recent transactions"
|
||||
msgstr "沒有近期交易"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:86
|
||||
#: templates/insights/fragments/year_by_year.html:54
|
||||
#, fuzzy
|
||||
#| msgid "Tags"
|
||||
msgid "Tag"
|
||||
msgstr "標籤"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:94
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:95
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:96
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "Mar"
|
||||
msgstr "最大值"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:97
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:98
|
||||
#, fuzzy
|
||||
#| msgid "Max"
|
||||
msgid "May"
|
||||
msgstr "最大值"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:99
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:100
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:101
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:102
|
||||
#, fuzzy
|
||||
#| msgid "Set"
|
||||
msgid "Sep"
|
||||
msgstr "設定"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:103
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:104
|
||||
#, fuzzy
|
||||
#| msgid "Now"
|
||||
msgid "Nov"
|
||||
msgstr "現在"
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:105
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/month_by_month.html:248
|
||||
#, fuzzy
|
||||
#| msgid "No transactions on this date"
|
||||
msgid "No transactions for this year"
|
||||
msgstr "本日沒有交易"
|
||||
|
||||
#: templates/insights/fragments/sankey.html:100
|
||||
msgid "From"
|
||||
msgstr "從"
|
||||
@@ -2936,6 +3043,12 @@ msgstr "從"
|
||||
msgid "Percentage"
|
||||
msgstr "百分比"
|
||||
|
||||
#: templates/insights/fragments/year_by_year.html:202
|
||||
#, fuzzy
|
||||
#| msgid "transactions"
|
||||
msgid "No transactions"
|
||||
msgstr "交易"
|
||||
|
||||
#: templates/insights/pages/index.html:37
|
||||
msgid "Month"
|
||||
msgstr "月"
|
||||
@@ -2985,6 +3098,16 @@ msgstr "最新的交易"
|
||||
msgid "Emergency Fund"
|
||||
msgstr "緊急資金"
|
||||
|
||||
#: templates/insights/pages/index.html:127
|
||||
#, fuzzy
|
||||
#| msgid "Yearly by account"
|
||||
msgid "Year by Year"
|
||||
msgstr "以帳戶為主的年報"
|
||||
|
||||
#: templates/insights/pages/index.html:132
|
||||
msgid "Month by Month"
|
||||
msgstr ""
|
||||
|
||||
#: templates/installment_plans/fragments/add.html:5
|
||||
msgid "Add installment plan"
|
||||
msgstr "新增分期付款計劃"
|
||||
@@ -3056,35 +3179,40 @@ msgstr "單位價格"
|
||||
msgid "Item"
|
||||
msgstr "項目"
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:32
|
||||
#: templates/monthly_overview/fragments/list.html:15
|
||||
#: templates/transactions/fragments/list_all.html:15
|
||||
msgid "late"
|
||||
msgstr ""
|
||||
|
||||
#: templates/monthly_overview/fragments/list.html:58
|
||||
msgid "No transactions this month"
|
||||
msgstr "這個月沒有交易"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "Daily Spending Allowance"
|
||||
msgstr "每日支出上限"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:6
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:7
|
||||
msgid "This is the final total divided by the remaining days in the month"
|
||||
msgstr "這是最終總額除以這個月的剩餘天數所計算"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:42
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:105
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:168
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:44
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:107
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:170
|
||||
msgid "current"
|
||||
msgstr "目前"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:71
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:134
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:197
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:73
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:136
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:199
|
||||
msgid "projected"
|
||||
msgstr "預期的"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:102
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:104
|
||||
msgid "Expenses"
|
||||
msgstr "支出"
|
||||
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:255
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:257
|
||||
msgid "Distribution"
|
||||
msgstr "分佈"
|
||||
|
||||
@@ -3092,27 +3220,27 @@ msgstr "分佈"
|
||||
msgid "Summary"
|
||||
msgstr "總結"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:96
|
||||
#: templates/monthly_overview/pages/overview.html:150
|
||||
#: templates/monthly_overview/pages/overview.html:99
|
||||
#: templates/monthly_overview/pages/overview.html:254
|
||||
#: templates/transactions/pages/transactions.html:48
|
||||
#: templates/transactions/pages/transactions.html:103
|
||||
#: templates/transactions/pages/transactions.html:204
|
||||
msgid "Oldest first"
|
||||
msgstr "最舊的優先"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:97
|
||||
#: templates/monthly_overview/pages/overview.html:159
|
||||
#: templates/monthly_overview/pages/overview.html:100
|
||||
#: templates/monthly_overview/pages/overview.html:263
|
||||
#: templates/transactions/pages/transactions.html:49
|
||||
#: templates/transactions/pages/transactions.html:112
|
||||
#: templates/transactions/pages/transactions.html:213
|
||||
msgid "Newest first"
|
||||
msgstr "新的優先"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:106
|
||||
#: templates/monthly_overview/pages/overview.html:109
|
||||
#: templates/transactions/pages/transactions.html:58
|
||||
msgid "Filter transactions"
|
||||
msgstr "過濾交易"
|
||||
|
||||
#: templates/monthly_overview/pages/overview.html:131
|
||||
#: templates/transactions/pages/transactions.html:84
|
||||
#: templates/monthly_overview/pages/overview.html:235
|
||||
#: templates/transactions/pages/transactions.html:185
|
||||
msgid "Order by"
|
||||
msgstr "排序方式"
|
||||
|
||||
@@ -3355,7 +3483,7 @@ msgstr "編輯"
|
||||
msgid "transactions"
|
||||
msgstr "交易"
|
||||
|
||||
#: templates/transactions/fragments/list_all.html:32
|
||||
#: templates/transactions/fragments/list_all.html:58
|
||||
msgid "No transactions found"
|
||||
msgstr "沒有發現交易"
|
||||
|
||||
|
||||
@@ -56,7 +56,15 @@
|
||||
</td>
|
||||
<td class="table-col-auto">{% if service.is_active %}<i class="fa-solid fa-circle text-success"></i>{% else %}
|
||||
<i class="fa-solid fa-circle text-error"></i>{% endif %}</td>
|
||||
<td class="table-col-auto">{{ service.name }}</td>
|
||||
<td>
|
||||
{{ service.name }}
|
||||
{% if service.failure_count > 0 %}
|
||||
<span class="badge badge-error gap-1" data-tippy-content="{% blocktrans count counter=service.failure_count %}{{ counter }} consecutive failure{% plural %}{{ counter }} consecutive failures{% endblocktrans %}">
|
||||
<i class="fa-solid fa-triangle-exclamation fa-fw"></i>
|
||||
{{ service.failure_count }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ service.get_service_type_display }}</td>
|
||||
<td>{{ service.target_currencies.count }} {% trans 'currencies' %}, {{ service.target_accounts.count }} {% trans 'accounts' %}</td>
|
||||
<td>{{ service.last_fetch|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
|
||||
250
app/templates/insights/fragments/month_by_month.html
Normal file
250
app/templates/insights/fragments/month_by_month.html
Normal file
@@ -0,0 +1,250 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div hx-get="{% url 'insights_month_by_month' %}" hx-trigger="updated from:window" class="show-loading"
|
||||
hx-swap="outerHTML" hx-include="#year-selector, #group-by-selector-month">
|
||||
|
||||
{# Hidden input to hold the year value #}
|
||||
<input type="hidden" name="year" id="year-selector" value="{{ selected_year }}" _="on change trigger updated">
|
||||
|
||||
{# Tabs for Categories/Tags/Entities #}
|
||||
<div class="h-full text-center mb-4">
|
||||
<div class="tabs tabs-box mx-auto w-fit" role="group" id="group-by-selector-month" _="on change trigger updated">
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="categories-view-month"
|
||||
autocomplete="off"
|
||||
value="categories"
|
||||
aria-label="{% trans 'Categories' %}"
|
||||
{% if group_by == "categories" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-icons fa-fw me-2"></i>
|
||||
{% trans 'Categories' %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="tags-view-month"
|
||||
autocomplete="off"
|
||||
value="tags"
|
||||
aria-label="{% trans 'Tags' %}"
|
||||
{% if group_by == "tags" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-hashtag fa-fw me-2"></i>
|
||||
{% trans 'Tags' %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="entities-view-month"
|
||||
autocomplete="off"
|
||||
value="entities"
|
||||
aria-label="{% trans 'Entities' %}"
|
||||
{% if group_by == "entities" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-user-group fa-fw me-2"></i>
|
||||
{% trans 'Entities' %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if data.items %}
|
||||
<div class="card bg-base-100 card-border">
|
||||
<div class="card-body">
|
||||
{# Year dropdown - left aligned #}
|
||||
{% if data.available_years %}
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
<button class="btn btn-ghost" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa-solid fa-calendar fa-fw me-1"></i>
|
||||
{{ selected_year }}
|
||||
<i class="fa-solid fa-chevron-down fa-fw ms-1"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu menu">
|
||||
{% for year in data.available_years %}
|
||||
<li>
|
||||
<button class="{% if year == selected_year %}menu-active{% endif %}" type="button"
|
||||
_="on click remove .menu-active from <li > button/> in the closest <ul/>
|
||||
then add .menu-active to me
|
||||
then set the value of #year-selector to '{{ year }}'
|
||||
then trigger change on #year-selector">
|
||||
{{ year }}
|
||||
</button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="overflow-x-auto">
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="sticky left-0 bg-base-100 z-10">
|
||||
{% if group_by == "categories" %}
|
||||
{% trans 'Category' %}
|
||||
{% elif group_by == "tags" %}
|
||||
{% trans 'Tag' %}
|
||||
{% else %}
|
||||
{% trans 'Entity' %}
|
||||
{% endif %}
|
||||
</th>
|
||||
<th scope="col" class="font-bold">{% trans 'Total' %}</th>
|
||||
{% for month in data.months %}
|
||||
<th scope="col">
|
||||
{% if month == 1 %}{% trans 'Jan' %}
|
||||
{% elif month == 2 %}{% trans 'Feb' %}
|
||||
{% elif month == 3 %}{% trans 'Mar' %}
|
||||
{% elif month == 4 %}{% trans 'Apr' %}
|
||||
{% elif month == 5 %}{% trans 'May' %}
|
||||
{% elif month == 6 %}{% trans 'Jun' %}
|
||||
{% elif month == 7 %}{% trans 'Jul' %}
|
||||
{% elif month == 8 %}{% trans 'Aug' %}
|
||||
{% elif month == 9 %}{% trans 'Sep' %}
|
||||
{% elif month == 10 %}{% trans 'Oct' %}
|
||||
{% elif month == 11 %}{% trans 'Nov' %}
|
||||
{% elif month == 12 %}{% trans 'Dec' %}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item_id, item in data.items.items %}
|
||||
<tr>
|
||||
<th class="text-nowrap sticky left-0 bg-base-100 z-10">
|
||||
{% if item.name %}
|
||||
{{ item.name }}
|
||||
{% else %}
|
||||
{% if group_by == "categories" %}
|
||||
{% trans 'Uncategorized' %}
|
||||
{% elif group_by == "tags" %}
|
||||
{% trans 'Untagged' %}
|
||||
{% else %}
|
||||
{% trans 'No entity' %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</th>
|
||||
{# Total column for this item #}
|
||||
<td class="text-nowrap font-semibold bg-base-200">
|
||||
{% for currency_id, currency_data in item.total.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# Month columns #}
|
||||
{% for month in data.months %}
|
||||
<td class="text-nowrap">
|
||||
{% with month_data=item.month_totals %}
|
||||
{% for m, m_data in month_data.items %}
|
||||
{% if m == month %}
|
||||
{% for currency_id, currency_data in m_data.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="font-bold bg-base-200">
|
||||
<th class="sticky left-0 bg-base-200 z-10">{% trans 'Total' %}</th>
|
||||
{# Grand total #}
|
||||
<td class="text-nowrap bg-base-300">
|
||||
{% for currency_id, currency_data in data.grand_total.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# Month totals #}
|
||||
{% for month in data.months %}
|
||||
<td class="text-nowrap">
|
||||
{% with month_total=data.month_totals %}
|
||||
{% for m, m_data in month_total.items %}
|
||||
{% if m == month %}
|
||||
{% for currency_id, currency_data in m_data.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate 'No transactions for this year' %}"></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
204
app/templates/insights/fragments/year_by_year.html
Normal file
204
app/templates/insights/fragments/year_by_year.html
Normal file
@@ -0,0 +1,204 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div hx-get="{% url 'insights_year_by_year' %}" hx-trigger="updated from:window" class="show-loading"
|
||||
hx-swap="outerHTML" hx-include="#group-by-selector">
|
||||
<div class="h-full text-center mb-4">
|
||||
<div class="tabs tabs-box mx-auto w-fit" role="group" id="group-by-selector" _="on change trigger updated">
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="categories-view"
|
||||
autocomplete="off"
|
||||
value="categories"
|
||||
aria-label="{% trans 'Categories' %}"
|
||||
{% if group_by == "categories" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-icons fa-fw me-2"></i>
|
||||
{% trans 'Categories' %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="tags-view"
|
||||
autocomplete="off"
|
||||
value="tags"
|
||||
aria-label="{% trans 'Tags' %}"
|
||||
{% if group_by == "tags" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-hashtag fa-fw me-2"></i>
|
||||
{% trans 'Tags' %}
|
||||
</label>
|
||||
<label class="tab">
|
||||
<input type="radio"
|
||||
name="group_by"
|
||||
id="entities-view"
|
||||
autocomplete="off"
|
||||
value="entities"
|
||||
aria-label="{% trans 'Entities' %}"
|
||||
{% if group_by == "entities" %}checked{% endif %}>
|
||||
<i class="fa-solid fa-user-group fa-fw me-2"></i>
|
||||
{% trans 'Entities' %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if data.years %}
|
||||
<div class="card bg-base-100 card-border">
|
||||
<div class="card-body">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="sticky left-0 bg-base-100 z-10">
|
||||
{% if group_by == "categories" %}
|
||||
{% trans 'Category' %}
|
||||
{% elif group_by == "tags" %}
|
||||
{% trans 'Tag' %}
|
||||
{% else %}
|
||||
{% trans 'Entity' %}
|
||||
{% endif %}
|
||||
</th>
|
||||
<th scope="col" class="font-bold">{% trans 'Total' %}</th>
|
||||
{% for year in data.years %}
|
||||
<th scope="col">{{ year }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item_id, item in data.items.items %}
|
||||
<tr>
|
||||
<th class="text-nowrap sticky left-0 bg-base-100 z-10">
|
||||
{% if item.name %}
|
||||
{{ item.name }}
|
||||
{% else %}
|
||||
{% if group_by == "categories" %}
|
||||
{% trans 'Uncategorized' %}
|
||||
{% elif group_by == "tags" %}
|
||||
{% trans 'Untagged' %}
|
||||
{% else %}
|
||||
{% trans 'No entity' %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</th>
|
||||
{# Total column for this item #}
|
||||
<td class="text-nowrap font-semibold bg-base-200">
|
||||
{% for currency_id, currency_data in item.total.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# Year columns #}
|
||||
{% for year in data.years %}
|
||||
<td class="text-nowrap">
|
||||
{% with year_data=item.year_totals %}
|
||||
{% for y, y_data in year_data.items %}
|
||||
{% if y == year %}
|
||||
{% for currency_id, currency_data in y_data.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="font-bold bg-base-200">
|
||||
<th class="sticky left-0 bg-base-200 z-10">{% trans 'Total' %}</th>
|
||||
{# Grand total #}
|
||||
<td class="text-nowrap bg-base-300">
|
||||
{% for currency_id, currency_data in data.grand_total.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# Year totals #}
|
||||
{% for year in data.years %}
|
||||
<td class="text-nowrap">
|
||||
{% with year_total=data.year_totals %}
|
||||
{% for y, y_data in year_total.items %}
|
||||
{% if y == year %}
|
||||
{% for currency_id, currency_data in y_data.currencies.items %}
|
||||
<c-amount.display
|
||||
:amount="currency_data.final_total"
|
||||
:prefix="currency_data.currency.prefix"
|
||||
:suffix="currency_data.currency.suffix"
|
||||
:decimal_places="currency_data.currency.decimal_places"
|
||||
color="{% if currency_data.final_total < 0 %}red{% elif currency_data.final_total > 0 %}green{% endif %}"></c-amount.display>
|
||||
{% if currency_data.exchanged %}
|
||||
<div class="text-xs text-base-content/60">
|
||||
<c-amount.display
|
||||
:amount="currency_data.exchanged.final_total"
|
||||
:prefix="currency_data.exchanged.currency.prefix"
|
||||
:suffix="currency_data.exchanged.currency.suffix"
|
||||
:decimal_places="currency_data.exchanged.currency.decimal_places"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
-
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate 'No transactions' %}"></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -121,6 +121,16 @@
|
||||
hx-get="{% url 'insights_emergency_fund' %}">
|
||||
{% trans 'Emergency Fund' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-free justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_year_by_year' %}">
|
||||
{% trans 'Year by Year' %}
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-free justify-start text-start" data-bs-target="#v-pills-content"
|
||||
type="button" role="tab" aria-controls="v-pills-content" aria-selected="false"
|
||||
hx-get="{% url 'insights_month_by_month' %}">
|
||||
{% trans 'Month by Month' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
{% regroup transactions by date|customnaturaldate as transactions_by_date %}
|
||||
|
||||
<div id="transactions-list">
|
||||
{% if late_transactions %}
|
||||
<div id="late-transactions" class="transactions-divider"
|
||||
x-data="{ open: sessionStorage.getItem('late-transactions') !== 'false' }"
|
||||
x-init="if (sessionStorage.getItem('late-transactions') === null) sessionStorage.setItem('late-transactions', 'true')">
|
||||
<div class="mt-3 mb-1 w-full border-b border-b-error/50 transactions-divider-title cursor-pointer">
|
||||
<a class="no-underline inline-block w-full text-error font-semibold"
|
||||
role="button"
|
||||
@click="open = !open; sessionStorage.setItem('late-transactions', open)"
|
||||
:aria-expanded="open">
|
||||
<i class="fa-solid fa-circle-exclamation me-1"></i>{% translate "late" %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="transactions-divider-collapse overflow-visible isolation-auto"
|
||||
x-show="open"
|
||||
x-collapse>
|
||||
<div class="flex flex-col">
|
||||
{% for transaction in late_transactions %}
|
||||
<c-transaction.item
|
||||
:transaction="transaction"></c-transaction.item>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for x in transactions_by_date %}
|
||||
<div id="{{ x.grouper|slugify }}" class="transactions-divider"
|
||||
x-data="{ open: sessionStorage.getItem('{{ x.grouper|slugify }}') !== 'false' }"
|
||||
@@ -28,10 +53,13 @@
|
||||
</div>
|
||||
|
||||
{% empty %}
|
||||
{% if not late_transactions %}
|
||||
<c-msg.empty
|
||||
title="{% translate 'No transactions this month' %}"
|
||||
subtitle="{% translate "Try adding one" %}"></c-msg.empty>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{# Floating bar #}
|
||||
<c-ui.transactions-action-bar></c-ui.transactions-action-bar>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% load currency_display %}
|
||||
<div class="grid grid-cols-1 gap-4 mt-1 mb-3">
|
||||
{% if not has_active_filter %}
|
||||
{# Daily Spending#}
|
||||
<div>
|
||||
<c-ui.info-card color="yellow" icon="fa-solid fa-calendar-day" title="{% trans 'Daily Spending Allowance' %}" help_text={% trans "This is the final total divided by the remaining days in the month" %}>
|
||||
@@ -34,6 +35,7 @@
|
||||
</div>
|
||||
</c-ui.info-card>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# Income#}
|
||||
<div>
|
||||
<c-ui.info-card color="green" icon="fa-solid fa-arrow-right-to-bracket" title="{% trans 'Income' %}">
|
||||
|
||||
@@ -50,12 +50,13 @@
|
||||
role="tab"
|
||||
{% if summary_tab == 'summary' or not summary_tab %}checked="checked"{% endif %}
|
||||
_="on click fetch {% url 'monthly_summary_select' selected='summary' %}"
|
||||
aria-controls="summary-tab-pane" />
|
||||
aria-controls="summary-tab-pane"/>
|
||||
<div class="tab-content" id="summary-tab-pane" role="tabpanel">
|
||||
<div id="summary"
|
||||
hx-get="{% url 'monthly_summary' month=month year=year %}"
|
||||
class="show-loading"
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m">
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m"
|
||||
hx-include="#filter">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -68,7 +69,8 @@
|
||||
<div id="currency-summary"
|
||||
hx-get="{% url 'monthly_currency_summary' month=month year=year %}"
|
||||
class="show-loading"
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m">
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m"
|
||||
hx-include="#filter">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,7 +83,8 @@
|
||||
<div id="account-summary"
|
||||
hx-get="{% url 'monthly_account_summary' month=month year=year %}"
|
||||
class="show-loading"
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m">
|
||||
hx-trigger="load, updated from:window, selective_update from:window, every 10m"
|
||||
hx-include="#filter">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,11 +103,112 @@
|
||||
{# Main control bar with filter, search, and ordering #}
|
||||
<div class="join w-full">
|
||||
|
||||
<button class="btn btn-secondary join-item relative" type="button"
|
||||
<button class="btn btn-secondary join-item relative z-1" type="button"
|
||||
@click="filterOpen = !filterOpen"
|
||||
:aria-expanded="filterOpen" id="filter-button"
|
||||
title="{% translate 'Filter transactions' %}">
|
||||
title="{% translate 'Filter transactions' %}"
|
||||
_="on load or change from #filter
|
||||
-- Check if any filter has a non-default value
|
||||
set hasActiveFilter to false
|
||||
|
||||
-- Check type (default is both IN and EX checked)
|
||||
set typeInputs to <input[name='type']:checked/> in #filter
|
||||
if typeInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check is_paid (default is both 1 and 0 checked)
|
||||
set isPaidInputs to <input[name='is_paid']:checked/> in #filter
|
||||
if isPaidInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check mute_status (default is both active and muted checked)
|
||||
set muteStatusInputs to <input[name='mute_status']:checked/> in #filter
|
||||
if muteStatusInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check description
|
||||
set descInput to #id_description
|
||||
if descInput exists and descInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check date_start
|
||||
set dateStartInput to #id_date_start
|
||||
if dateStartInput exists and dateStartInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check date_end
|
||||
set dateEndInput to #id_date_end
|
||||
if dateEndInput exists and dateEndInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check reference_date_start
|
||||
set refDateStartInput to #id_reference_date_start
|
||||
if refDateStartInput exists and refDateStartInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check reference_date_end
|
||||
set refDateEndInput to #id_reference_date_end
|
||||
if refDateEndInput exists and refDateEndInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check from_amount
|
||||
set fromAmountInput to #id_from_amount
|
||||
if fromAmountInput exists and fromAmountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check to_amount
|
||||
set toAmountInput to #id_to_amount
|
||||
if toAmountInput exists and toAmountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check account (TomSelect stores values differently)
|
||||
set accountInput to #id_account
|
||||
if accountInput exists and accountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check currency
|
||||
set currencyInput to #id_currency
|
||||
if currencyInput exists and currencyInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check category
|
||||
set categoryInput to #id_category
|
||||
if categoryInput exists and categoryInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check tags
|
||||
set tagsInput to #id_tags
|
||||
if tagsInput exists and tagsInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check entities
|
||||
set entitiesInput to #id_entities
|
||||
if entitiesInput exists and entitiesInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Show or hide the indicator
|
||||
if hasActiveFilter
|
||||
remove .hidden from #filter-active-indicator
|
||||
else
|
||||
add .hidden to #filter-active-indicator
|
||||
end">
|
||||
<i class="fa-solid fa-filter fa-fw"></i>
|
||||
<span id="filter-active-indicator" class="absolute -top-1 -right-1 w-3 h-3 bg-error rounded-full hidden z-10"></span>
|
||||
</button>
|
||||
|
||||
{# Search box #}
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
{% regroup page_obj by date|customnaturaldate as transactions_by_date %}
|
||||
|
||||
<div id="transactions-list" class="show-loading">
|
||||
{% if late_transactions %}
|
||||
<div id="late-transactions" class="transactions-divider"
|
||||
x-data="{ open: sessionStorage.getItem('late-transactions') !== 'false' }"
|
||||
x-init="if (sessionStorage.getItem('late-transactions') === null) sessionStorage.setItem('late-transactions', 'true')">
|
||||
<div class="mt-3 mb-1 w-full border-b border-b-error/50 transactions-divider-title cursor-pointer">
|
||||
<a class="no-underline inline-block w-full text-error font-semibold"
|
||||
role="button"
|
||||
@click="open = !open; sessionStorage.setItem('late-transactions', open)"
|
||||
:aria-expanded="open">
|
||||
<i class="fa-solid fa-circle-exclamation me-1"></i>{% translate "late" %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="transactions-divider-collapse overflow-visible isolation-auto"
|
||||
x-show="open"
|
||||
x-collapse>
|
||||
<div class="flex flex-col">
|
||||
{% for transaction in late_transactions %}
|
||||
<c-transaction.item
|
||||
:transaction="transaction"></c-transaction.item>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for x in transactions_by_date %}
|
||||
<div id="{{ x.grouper|slugify }}" class="transactions-divider"
|
||||
x-data="{ open: sessionStorage.getItem('{{ x.grouper|slugify }}') !== 'false' }"
|
||||
@@ -28,9 +53,11 @@
|
||||
</div>
|
||||
|
||||
{% empty %}
|
||||
{% if not late_transactions %}
|
||||
<c-msg.empty
|
||||
title="{% translate "No transactions found" %}"
|
||||
subtitle="{% translate "Try adding one" %}"></c-msg.empty>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# Floating bar #}
|
||||
|
||||
@@ -52,11 +52,112 @@
|
||||
{# Main control bar with filter, search, and ordering #}
|
||||
<div class="join w-full">
|
||||
|
||||
<button class="btn btn-secondary join-item relative" type="button"
|
||||
<button class="btn btn-secondary join-item relative z-1" type="button"
|
||||
@click="filterOpen = !filterOpen"
|
||||
:aria-expanded="filterOpen" id="filter-button"
|
||||
title="{% translate 'Filter transactions' %}">
|
||||
title="{% translate 'Filter transactions' %}"
|
||||
_="on load or change from #filter
|
||||
-- Check if any filter has a non-default value
|
||||
set hasActiveFilter to false
|
||||
|
||||
-- Check type (default is both IN and EX checked)
|
||||
set typeInputs to <input[name='type']:checked/> in #filter
|
||||
if typeInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check is_paid (default is both 1 and 0 checked)
|
||||
set isPaidInputs to <input[name='is_paid']:checked/> in #filter
|
||||
if isPaidInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check mute_status (default is both active and muted checked)
|
||||
set muteStatusInputs to <input[name='mute_status']:checked/> in #filter
|
||||
if muteStatusInputs.length is not 2
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check description
|
||||
set descInput to #id_description
|
||||
if descInput exists and descInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check date_start
|
||||
set dateStartInput to #id_date_start
|
||||
if dateStartInput exists and dateStartInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check date_end
|
||||
set dateEndInput to #id_date_end
|
||||
if dateEndInput exists and dateEndInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check reference_date_start
|
||||
set refDateStartInput to #id_reference_date_start
|
||||
if refDateStartInput exists and refDateStartInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check reference_date_end
|
||||
set refDateEndInput to #id_reference_date_end
|
||||
if refDateEndInput exists and refDateEndInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check from_amount
|
||||
set fromAmountInput to #id_from_amount
|
||||
if fromAmountInput exists and fromAmountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check to_amount
|
||||
set toAmountInput to #id_to_amount
|
||||
if toAmountInput exists and toAmountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check account (TomSelect stores values differently)
|
||||
set accountInput to #id_account
|
||||
if accountInput exists and accountInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check currency
|
||||
set currencyInput to #id_currency
|
||||
if currencyInput exists and currencyInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check category
|
||||
set categoryInput to #id_category
|
||||
if categoryInput exists and categoryInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check tags
|
||||
set tagsInput to #id_tags
|
||||
if tagsInput exists and tagsInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Check entities
|
||||
set entitiesInput to #id_entities
|
||||
if entitiesInput exists and entitiesInput.value is not ''
|
||||
set hasActiveFilter to true
|
||||
end
|
||||
|
||||
-- Show or hide the indicator
|
||||
if hasActiveFilter
|
||||
remove .hidden from #filter-active-indicator
|
||||
else
|
||||
add .hidden to #filter-active-indicator
|
||||
end">
|
||||
<i class="fa-solid fa-filter fa-fw"></i>
|
||||
<span id="filter-active-indicator" class="absolute -top-1 -right-1 w-3 h-3 bg-error rounded-full hidden z-10"></span>
|
||||
</button>
|
||||
|
||||
{# Search box #}
|
||||
|
||||
@@ -2,6 +2,7 @@ volumes:
|
||||
wygiwyh_dev_postgres_data: {}
|
||||
wygiwyh_temp:
|
||||
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
FROM python:3.11-slim-bookworm AS python-build-stage
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY ../requirements.txt .
|
||||
RUN pip wheel --wheel-dir /usr/src/app/wheels -r requirements.txt
|
||||
|
||||
FROM python:3.11-slim-bookworm AS python-run-stage
|
||||
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim
|
||||
|
||||
ARG VERSION=dev
|
||||
ENV APP_VERSION=$VERSION
|
||||
@@ -16,16 +6,17 @@ ENV APP_VERSION=$VERSION
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
COPY --from=python-build-stage /usr/src/app/wheels /wheels/
|
||||
PYTHONUNBUFFERED=1 \
|
||||
UV_COMPILE_BYTECODE=1 \
|
||||
UV_LINK_MODE=copy \
|
||||
UV_PROJECT_ENVIRONMENT=/opt/venv
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -y gettext supervisor && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
pip install --upgrade pip && \
|
||||
pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* && \
|
||||
rm -rf /wheels/ ~/.cache/pip/*
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY pyproject.toml uv.lock ./
|
||||
RUN uv sync --frozen --no-install-project --no-dev
|
||||
|
||||
COPY ./docker/dev/django/start /start
|
||||
COPY ./docker/dev/procrastinate/start /start-procrastinate
|
||||
@@ -40,6 +31,8 @@ RUN sed -i 's/\r$//g' /start && \
|
||||
sed -i 's/\r$//g' /start-supervisor && \
|
||||
chmod +x /start-supervisor
|
||||
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
COPY ./app .
|
||||
|
||||
CMD ["/start-supervisor"]
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
FROM python:3.11-slim-bookworm AS python-build-stage
|
||||
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim AS python-build-stage
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV UV_COMPILE_BYTECODE=1 \
|
||||
UV_LINK_MODE=copy
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install uv for faster package resolution
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||
COPY uv.lock pyproject.toml ./
|
||||
|
||||
COPY ./requirements.txt .
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip install --system --compile-bytecode -r requirements.txt
|
||||
uv sync --frozen --no-install-project --no-dev
|
||||
|
||||
FROM node:lts-alpine AS vite_build
|
||||
WORKDIR /usr/src/frontend
|
||||
@@ -33,9 +35,8 @@ ENV APP_VERSION=$VERSION
|
||||
|
||||
COPY --from=vite_build /usr/src/frontend/build /usr/src/frontend/build
|
||||
|
||||
# Copy Python packages from build stage
|
||||
COPY --from=python-build-stage /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
|
||||
COPY --from=python-build-stage /usr/local/bin /usr/local/bin
|
||||
# Copy virtual environment from build stage
|
||||
COPY --from=python-build-stage /app/.venv /app/.venv
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
@@ -43,7 +44,8 @@ RUN addgroup --system app && \
|
||||
adduser --system --ingroup app app
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/app/.venv/bin:$PATH"
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN --mount=type=cache,target=/root/.cache/apt \
|
||||
|
||||
40
pyproject.toml
Normal file
40
pyproject.toml
Normal file
@@ -0,0 +1,40 @@
|
||||
[project]
|
||||
name = "wygiwyh"
|
||||
dynamic = ["version"]
|
||||
description = "An opinionated and powerful finance tracker."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"crispy-bootstrap5==2025.6",
|
||||
"django~=5.2.9",
|
||||
"django-allauth[socialaccount]~=65.13.1",
|
||||
"django-browser-reload==1.21.0",
|
||||
"django-cachalot~=2.8.0",
|
||||
"django-cotton<2.3.0",
|
||||
"django-crispy-forms==2.5",
|
||||
"django-debug-toolbar==6.1.0",
|
||||
"django-filter==25.2",
|
||||
"django-hijack==3.7.4",
|
||||
"django-import-export~=4.3.9",
|
||||
"django-pwa~=2.0.1",
|
||||
"django-vite==3.1.0",
|
||||
"djangorestframework~=3.16.0",
|
||||
"drf-spectacular~=0.29.0",
|
||||
"gunicorn==23.0.0",
|
||||
"mistune~=3.1.3",
|
||||
"openpyxl~=3.1.5",
|
||||
"procrastinate[django]~=3.5.3",
|
||||
"psycopg[binary,pool]==3.2.9",
|
||||
"pydantic~=2.12.3",
|
||||
"python-dateutil~=2.9.0.post0",
|
||||
"pytz>=2025.2",
|
||||
"pyyaml~=6.0.2",
|
||||
"requests~=2.32.5",
|
||||
"simpleeval~=1.0.3",
|
||||
"watchfiles==1.1.1",
|
||||
"whitenoise[brotli]==6.11.0",
|
||||
"xlrd~=2.0.1",
|
||||
]
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["app"]
|
||||
@@ -1,33 +0,0 @@
|
||||
Django~=5.2.9
|
||||
psycopg[binary,pool]==3.2.9
|
||||
django-vite==3.1.0
|
||||
django-crispy-forms==2.5
|
||||
crispy-bootstrap5==2025.6
|
||||
django-browser-reload==1.21.0
|
||||
django-hijack==3.7.4
|
||||
django-filter==25.2
|
||||
django-debug-toolbar==6.1.0
|
||||
django-cachalot~=2.8.0
|
||||
django-cotton<2.3.0
|
||||
django-pwa~=2.0.1
|
||||
djangorestframework~=3.16.0
|
||||
drf-spectacular~=0.29.0
|
||||
django-import-export~=4.3.9
|
||||
|
||||
gunicorn==23.0.0
|
||||
whitenoise[brotli]==6.11.0
|
||||
|
||||
watchfiles==1.1.1
|
||||
procrastinate[django]~=3.5.3
|
||||
|
||||
requests~=2.32.5
|
||||
django-allauth[socialaccount]~=65.13.1
|
||||
|
||||
pytz
|
||||
python-dateutil~=2.9.0.post0
|
||||
simpleeval~=1.0.3
|
||||
pydantic~=2.12.3
|
||||
PyYAML~=6.0.2
|
||||
mistune~=3.1.3
|
||||
openpyxl~=3.1.5
|
||||
xlrd~=2.0.1
|
||||
Reference in New Issue
Block a user