mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-25 08:54:52 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a461a33dc2 | ||
|
|
1213ffebeb | ||
|
|
c5a352cf4d | ||
|
|
cfcca54aa6 | ||
|
|
234f8cd669 |
@@ -32,7 +32,7 @@ def net_worth_current(request):
|
||||
)
|
||||
|
||||
currency_net_worth = calculate_currency_totals(
|
||||
transactions_queryset=transactions_currency_queryset
|
||||
transactions_queryset=transactions_currency_queryset, deep_search=True
|
||||
)
|
||||
account_net_worth = calculate_account_totals(
|
||||
transactions_queryset=transactions_account_queryset
|
||||
@@ -137,7 +137,7 @@ def net_worth_projected(request):
|
||||
)
|
||||
|
||||
currency_net_worth = calculate_currency_totals(
|
||||
transactions_queryset=transactions_currency_queryset
|
||||
transactions_queryset=transactions_currency_queryset, deep_search=True
|
||||
)
|
||||
account_net_worth = calculate_account_totals(
|
||||
transactions_queryset=transactions_account_queryset
|
||||
|
||||
@@ -9,9 +9,11 @@ from apps.currencies.utils.convert import convert
|
||||
from apps.currencies.models import Currency
|
||||
|
||||
|
||||
def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
def calculate_currency_totals(
|
||||
transactions_queryset, ignore_empty=False, deep_search=False
|
||||
):
|
||||
# Prepare the aggregation expressions
|
||||
currency_totals = (
|
||||
currency_totals_from_transactions = (
|
||||
transactions_queryset.values(
|
||||
"account__currency",
|
||||
"account__currency__code",
|
||||
@@ -19,7 +21,14 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
"account__currency__decimal_places",
|
||||
"account__currency__prefix",
|
||||
"account__currency__suffix",
|
||||
"account__currency__exchange_currency",
|
||||
"account__currency__exchange_currency", # ID of the exchange currency for the account's currency
|
||||
# Fields for the exchange currency itself (if account.currency.exchange_currency is set)
|
||||
# These might be null if not set, so handle appropriately.
|
||||
"account__currency__exchange_currency__code",
|
||||
"account__currency__exchange_currency__name",
|
||||
"account__currency__exchange_currency__decimal_places",
|
||||
"account__currency__exchange_currency__prefix",
|
||||
"account__currency__exchange_currency__suffix",
|
||||
)
|
||||
.annotate(
|
||||
expense_current=Coalesce(
|
||||
@@ -72,36 +81,55 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
.order_by()
|
||||
)
|
||||
|
||||
# First pass: Process basic totals and store all currency data
|
||||
result = {}
|
||||
currencies_using_exchange = (
|
||||
{}
|
||||
) # Track which currencies use which exchange currencies
|
||||
# currencies_using_exchange maps:
|
||||
# exchange_currency_id -> list of [
|
||||
# { "currency_id": original_currency_id, (the currency that was exchanged FROM)
|
||||
# "exchanged": { field: amount_in_exchange_currency, ... } (the values of original_currency_id converted TO exchange_currency_id)
|
||||
# }
|
||||
# ]
|
||||
currencies_using_exchange = {}
|
||||
|
||||
for total in currency_totals:
|
||||
# Skip empty currencies if ignore_empty is True
|
||||
if ignore_empty and all(
|
||||
total[field] == Decimal("0")
|
||||
for field in [
|
||||
"expense_current",
|
||||
"expense_projected",
|
||||
"income_current",
|
||||
"income_projected",
|
||||
]
|
||||
# --- First Pass: Process transactions from the queryset ---
|
||||
for total in currency_totals_from_transactions:
|
||||
if (
|
||||
ignore_empty
|
||||
and not deep_search
|
||||
and all(
|
||||
total[field] == Decimal("0")
|
||||
for field in [
|
||||
"expense_current",
|
||||
"expense_projected",
|
||||
"income_current",
|
||||
"income_projected",
|
||||
]
|
||||
)
|
||||
):
|
||||
continue
|
||||
|
||||
# Calculate derived totals
|
||||
currency_id = total["account__currency"]
|
||||
try:
|
||||
from_currency_obj = Currency.objects.get(id=currency_id)
|
||||
except Currency.DoesNotExist:
|
||||
# This should ideally not happen if database is consistent
|
||||
continue
|
||||
|
||||
exchange_currency_for_this_total_id = total[
|
||||
"account__currency__exchange_currency"
|
||||
]
|
||||
exchange_currency_obj_for_this_total = None
|
||||
if exchange_currency_for_this_total_id:
|
||||
try:
|
||||
# Use pre-fetched values if available, otherwise query
|
||||
exchange_currency_obj_for_this_total = Currency.objects.get(
|
||||
id=exchange_currency_for_this_total_id
|
||||
)
|
||||
except Currency.DoesNotExist:
|
||||
pass # Exchange currency might not exist or be set
|
||||
|
||||
total_current = total["income_current"] - total["expense_current"]
|
||||
total_projected = total["income_projected"] - total["expense_projected"]
|
||||
total_final = total_current + total_projected
|
||||
currency_id = total["account__currency"]
|
||||
from_currency = Currency.objects.get(id=currency_id)
|
||||
exchange_currency = (
|
||||
Currency.objects.get(id=total["account__currency__exchange_currency"])
|
||||
if total["account__currency__exchange_currency"]
|
||||
else None
|
||||
)
|
||||
|
||||
currency_data = {
|
||||
"currency": {
|
||||
@@ -120,9 +148,16 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
"total_final": total_final,
|
||||
}
|
||||
|
||||
# Add exchanged values if exchange_currency exists
|
||||
if exchange_currency:
|
||||
exchanged = {}
|
||||
if exchange_currency_obj_for_this_total:
|
||||
exchanged_details = {
|
||||
"currency": {
|
||||
"code": exchange_currency_obj_for_this_total.code,
|
||||
"name": exchange_currency_obj_for_this_total.name,
|
||||
"decimal_places": exchange_currency_obj_for_this_total.decimal_places,
|
||||
"prefix": exchange_currency_obj_for_this_total.prefix,
|
||||
"suffix": exchange_currency_obj_for_this_total.suffix,
|
||||
}
|
||||
}
|
||||
for field in [
|
||||
"expense_current",
|
||||
"expense_projected",
|
||||
@@ -132,50 +167,142 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
"total_projected",
|
||||
"total_final",
|
||||
]:
|
||||
amount, prefix, suffix, decimal_places = convert(
|
||||
amount=currency_data[field],
|
||||
from_currency=from_currency,
|
||||
to_currency=exchange_currency,
|
||||
amount_to_convert = currency_data[field]
|
||||
converted_val, _, _, _ = convert(
|
||||
amount=amount_to_convert,
|
||||
from_currency=from_currency_obj,
|
||||
to_currency=exchange_currency_obj_for_this_total,
|
||||
)
|
||||
exchanged_details[field] = (
|
||||
converted_val if converted_val is not None else Decimal("0")
|
||||
)
|
||||
if amount is not None:
|
||||
exchanged[field] = amount
|
||||
if "currency" not in exchanged:
|
||||
exchanged["currency"] = {
|
||||
"prefix": prefix,
|
||||
"suffix": suffix,
|
||||
"decimal_places": decimal_places,
|
||||
"code": exchange_currency.code,
|
||||
"name": exchange_currency.name,
|
||||
}
|
||||
|
||||
if exchanged:
|
||||
currency_data["exchanged"] = exchanged
|
||||
# Track which currencies are using which exchange currencies
|
||||
if exchange_currency.id not in currencies_using_exchange:
|
||||
currencies_using_exchange[exchange_currency.id] = []
|
||||
currencies_using_exchange[exchange_currency.id].append(
|
||||
{"currency_id": currency_id, "exchanged": exchanged}
|
||||
)
|
||||
currency_data["exchanged"] = exchanged_details
|
||||
|
||||
if exchange_currency_obj_for_this_total.id not in currencies_using_exchange:
|
||||
currencies_using_exchange[exchange_currency_obj_for_this_total.id] = []
|
||||
currencies_using_exchange[exchange_currency_obj_for_this_total.id].append(
|
||||
{"currency_id": currency_id, "exchanged": exchanged_details}
|
||||
)
|
||||
|
||||
result[currency_id] = currency_data
|
||||
|
||||
# Second pass: Add consolidated totals for currencies that are used as exchange currencies
|
||||
for currency_id, currency_data in result.items():
|
||||
if currency_id in currencies_using_exchange:
|
||||
consolidated = {
|
||||
"currency": currency_data["currency"].copy(),
|
||||
"expense_current": currency_data["expense_current"],
|
||||
"expense_projected": currency_data["expense_projected"],
|
||||
"income_current": currency_data["income_current"],
|
||||
"income_projected": currency_data["income_projected"],
|
||||
"total_current": currency_data["total_current"],
|
||||
"total_projected": currency_data["total_projected"],
|
||||
"total_final": currency_data["total_final"],
|
||||
}
|
||||
# --- Deep Search: Add transaction-less currencies that are exchange targets ---
|
||||
if deep_search:
|
||||
# Iteratively add exchange targets that might not have had direct transactions
|
||||
# Start with known exchange targets from the first pass
|
||||
queue = list(currencies_using_exchange.keys())
|
||||
processed_for_deep_add = set(
|
||||
result.keys()
|
||||
) # Track currencies already in result or added by this deep search step
|
||||
|
||||
# Add exchanged values from all currencies using this as exchange currency
|
||||
for using_currency in currencies_using_exchange[currency_id]:
|
||||
exchanged = using_currency["exchanged"]
|
||||
while queue:
|
||||
target_id = queue.pop(0)
|
||||
if target_id in processed_for_deep_add:
|
||||
continue
|
||||
processed_for_deep_add.add(target_id)
|
||||
|
||||
if (
|
||||
target_id not in result
|
||||
): # If this exchange target had no direct transactions
|
||||
try:
|
||||
db_currency = Currency.objects.get(id=target_id)
|
||||
except Currency.DoesNotExist:
|
||||
continue
|
||||
|
||||
# Initialize data for this transaction-less exchange target currency
|
||||
currency_data_for_db_currency = {
|
||||
"currency": {
|
||||
"code": db_currency.code,
|
||||
"name": db_currency.name,
|
||||
"decimal_places": db_currency.decimal_places,
|
||||
"prefix": db_currency.prefix,
|
||||
"suffix": db_currency.suffix,
|
||||
},
|
||||
"expense_current": Decimal("0"),
|
||||
"expense_projected": Decimal("0"),
|
||||
"income_current": Decimal("0"),
|
||||
"income_projected": Decimal("0"),
|
||||
"total_current": Decimal("0"),
|
||||
"total_projected": Decimal("0"),
|
||||
"total_final": Decimal("0"),
|
||||
}
|
||||
|
||||
# If this newly added transaction-less currency ALSO has an exchange_currency set for itself
|
||||
if db_currency.exchange_currency:
|
||||
exchanged_details_for_db_currency = {
|
||||
"currency": {
|
||||
"code": db_currency.exchange_currency.code,
|
||||
"name": db_currency.exchange_currency.name,
|
||||
"decimal_places": db_currency.exchange_currency.decimal_places,
|
||||
"prefix": db_currency.exchange_currency.prefix,
|
||||
"suffix": db_currency.exchange_currency.suffix,
|
||||
}
|
||||
}
|
||||
for field in [
|
||||
"expense_current",
|
||||
"expense_projected",
|
||||
"income_current",
|
||||
"income_projected",
|
||||
"total_current",
|
||||
"total_projected",
|
||||
"total_final",
|
||||
]:
|
||||
converted_val, _, _, _ = convert(
|
||||
Decimal("0"), db_currency, db_currency.exchange_currency
|
||||
)
|
||||
exchanged_details_for_db_currency[field] = (
|
||||
converted_val if converted_val is not None else Decimal("0")
|
||||
)
|
||||
|
||||
currency_data_for_db_currency["exchanged"] = (
|
||||
exchanged_details_for_db_currency
|
||||
)
|
||||
|
||||
# Ensure its own exchange_currency is registered in currencies_using_exchange
|
||||
# and add it to the queue if it hasn't been processed yet for deep add.
|
||||
target_id_for_this_db_curr = db_currency.exchange_currency.id
|
||||
if target_id_for_this_db_curr not in currencies_using_exchange:
|
||||
currencies_using_exchange[target_id_for_this_db_curr] = []
|
||||
|
||||
# Avoid adding duplicate entries
|
||||
already_present_in_cue = any(
|
||||
entry["currency_id"] == db_currency.id
|
||||
for entry in currencies_using_exchange[
|
||||
target_id_for_this_db_curr
|
||||
]
|
||||
)
|
||||
if not already_present_in_cue:
|
||||
currencies_using_exchange[target_id_for_this_db_curr].append(
|
||||
{
|
||||
"currency_id": db_currency.id,
|
||||
"exchanged": exchanged_details_for_db_currency,
|
||||
}
|
||||
)
|
||||
|
||||
if target_id_for_this_db_curr not in processed_for_deep_add:
|
||||
queue.append(target_id_for_this_db_curr)
|
||||
|
||||
result[db_currency.id] = currency_data_for_db_currency
|
||||
|
||||
# --- Second Pass: Calculate consolidated totals for all currencies in result ---
|
||||
for currency_id_consolidated, data_consolidated_currency in result.items():
|
||||
consolidated_data = {
|
||||
"currency": data_consolidated_currency["currency"].copy(),
|
||||
"expense_current": data_consolidated_currency["expense_current"],
|
||||
"expense_projected": data_consolidated_currency["expense_projected"],
|
||||
"income_current": data_consolidated_currency["income_current"],
|
||||
"income_projected": data_consolidated_currency["income_projected"],
|
||||
"total_current": data_consolidated_currency["total_current"],
|
||||
"total_projected": data_consolidated_currency["total_projected"],
|
||||
"total_final": data_consolidated_currency["total_final"],
|
||||
}
|
||||
|
||||
if currency_id_consolidated in currencies_using_exchange:
|
||||
for original_currency_info in currencies_using_exchange[
|
||||
currency_id_consolidated
|
||||
]:
|
||||
exchanged_values_from_original = original_currency_info["exchanged"]
|
||||
for field in [
|
||||
"expense_current",
|
||||
"expense_projected",
|
||||
@@ -185,10 +312,25 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
||||
"total_projected",
|
||||
"total_final",
|
||||
]:
|
||||
if field in exchanged:
|
||||
consolidated[field] += exchanged[field]
|
||||
if field in exchanged_values_from_original:
|
||||
consolidated_data[field] += exchanged_values_from_original[
|
||||
field
|
||||
]
|
||||
|
||||
result[currency_id]["consolidated"] = consolidated
|
||||
result[currency_id_consolidated]["consolidated"] = consolidated_data
|
||||
|
||||
# Sort currencies by their final_total or consolidated final_total, descending
|
||||
result = {
|
||||
k: v
|
||||
for k, v in sorted(
|
||||
result.items(),
|
||||
reverse=True,
|
||||
key=lambda item: max(
|
||||
item[1].get("total_final", Decimal("0")),
|
||||
item[1].get("consolidated", {}).get("total_final", Decimal("0")),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -8,19 +8,21 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-05-11 15:47+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"PO-Revision-Date: 2025-05-12 14:16+0000\n"
|
||||
"Last-Translator: Felix <xnovaua@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <https://translations.herculino.com/projects/"
|
||||
"wygiwyh/app/uk/>\n"
|
||||
"Language: uk\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.11.3\n"
|
||||
|
||||
#: apps/accounts/forms.py:24
|
||||
msgid "Group name"
|
||||
msgstr ""
|
||||
msgstr "Назва групи"
|
||||
|
||||
#: apps/accounts/forms.py:40 apps/accounts/forms.py:98
|
||||
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91
|
||||
@@ -32,7 +34,7 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:751 apps/transactions/forms.py:903
|
||||
#: apps/users/forms.py:210 apps/users/forms.py:372
|
||||
msgid "Update"
|
||||
msgstr ""
|
||||
msgstr "Оновлення"
|
||||
|
||||
#: apps/accounts/forms.py:48 apps/accounts/forms.py:106
|
||||
#: apps/common/widgets/tom_select.py:13 apps/currencies/forms.py:61
|
||||
@@ -60,15 +62,15 @@ msgstr ""
|
||||
#: templates/rules/fragments/list.html:9 templates/tags/fragments/list.html:9
|
||||
#: templates/users/fragments/list.html:10
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
msgstr "Додати"
|
||||
|
||||
#: apps/accounts/forms.py:57 templates/accounts/fragments/list.html:26
|
||||
msgid "Group"
|
||||
msgstr ""
|
||||
msgstr "Група"
|
||||
|
||||
#: apps/accounts/forms.py:115
|
||||
msgid "New balance"
|
||||
msgstr ""
|
||||
msgstr "Новий баланс"
|
||||
|
||||
#: apps/accounts/forms.py:121 apps/dca/forms.py:85 apps/dca/forms.py:92
|
||||
#: apps/insights/forms.py:118 apps/rules/forms.py:174 apps/rules/forms.py:189
|
||||
@@ -80,7 +82,7 @@ msgstr ""
|
||||
#: templates/insights/fragments/category_overview/index.html:63
|
||||
#: templates/insights/fragments/category_overview/index.html:420
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
msgstr "Категорія"
|
||||
|
||||
#: apps/accounts/forms.py:128 apps/dca/forms.py:101 apps/dca/forms.py:109
|
||||
#: apps/export_app/forms.py:44 apps/export_app/forms.py:135
|
||||
@@ -94,7 +96,7 @@ msgstr ""
|
||||
#: templates/insights/fragments/category_overview/index.html:35
|
||||
#: templates/tags/fragments/list.html:5 templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
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
|
||||
@@ -113,51 +115,54 @@ msgstr ""
|
||||
#: templates/tags/fragments/table.html:16
|
||||
#: templates/users/fragments/list.html:29
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
msgstr "Ім'я"
|
||||
|
||||
#: apps/accounts/models.py:18 apps/accounts/models.py:33
|
||||
msgid "Account Group"
|
||||
msgstr ""
|
||||
msgstr "Група рахунків"
|
||||
|
||||
#: apps/accounts/models.py:19 templates/account_groups/fragments/list.html:5
|
||||
#: templates/account_groups/pages/index.html:4
|
||||
#: templates/includes/navbar.html:118
|
||||
msgid "Account Groups"
|
||||
msgstr ""
|
||||
msgstr "Групи рахунків"
|
||||
|
||||
#: apps/accounts/models.py:39 apps/currencies/models.py:39
|
||||
#: templates/accounts/fragments/list.html:27
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
msgstr "Валюта"
|
||||
|
||||
#: apps/accounts/models.py:45 apps/currencies/models.py:27
|
||||
#: templates/accounts/fragments/list.html:28
|
||||
msgid "Exchange Currency"
|
||||
msgstr ""
|
||||
msgstr "Валюта обміну"
|
||||
|
||||
#: apps/accounts/models.py:50 apps/currencies/models.py:32
|
||||
msgid "Default currency for exchange calculations"
|
||||
msgstr ""
|
||||
msgstr "Валюта за замовчуванням для обмінних розрахунків"
|
||||
|
||||
#: apps/accounts/models.py:55
|
||||
msgid "Asset account"
|
||||
msgstr ""
|
||||
msgstr "Рахунок активів"
|
||||
|
||||
#: apps/accounts/models.py:57
|
||||
msgid ""
|
||||
"Asset accounts count towards your Net Worth, but not towards your month."
|
||||
msgstr ""
|
||||
"Рахунки активів враховуються у вашій чистій вартості, але не у вашому місяці."
|
||||
|
||||
#: apps/accounts/models.py:62 templates/accounts/fragments/list.html:30
|
||||
#: templates/categories/fragments/list.html:24
|
||||
#: templates/entities/fragments/list.html:24
|
||||
#: templates/tags/fragments/list.html:24
|
||||
msgid "Archived"
|
||||
msgstr ""
|
||||
msgstr "Архівовано"
|
||||
|
||||
#: apps/accounts/models.py:63
|
||||
msgid "Archived accounts don't show up nor count towards your net worth"
|
||||
msgstr ""
|
||||
"Заархівовані рахунки не відображаються і не враховуються у вашій чистій "
|
||||
"вартості"
|
||||
|
||||
#: apps/accounts/models.py:70 apps/rules/forms.py:166 apps/rules/forms.py:179
|
||||
#: apps/rules/models.py:30 apps/rules/models.py:242
|
||||
@@ -165,7 +170,7 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:768 apps/transactions/models.py:285
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:677
|
||||
msgid "Account"
|
||||
msgstr ""
|
||||
msgstr "Рахунок"
|
||||
|
||||
#: apps/accounts/models.py:71 apps/export_app/forms.py:20
|
||||
#: apps/export_app/forms.py:132 apps/transactions/filters.py:53
|
||||
@@ -176,15 +181,15 @@ msgstr ""
|
||||
#: templates/transactions/fragments/summary.html:12
|
||||
#: templates/transactions/pages/transactions.html:72
|
||||
msgid "Accounts"
|
||||
msgstr ""
|
||||
msgstr "Рахунки"
|
||||
|
||||
#: apps/accounts/models.py:84
|
||||
msgid "Exchange currency cannot be the same as the account's main currency."
|
||||
msgstr ""
|
||||
msgstr "Валюта обміну не може збігатися з основною валютою рахунку."
|
||||
|
||||
#: apps/accounts/views/account_groups.py:44
|
||||
msgid "Account Group added successfully"
|
||||
msgstr ""
|
||||
msgstr "Групу рахунків успішно додано"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:69
|
||||
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
|
||||
@@ -196,188 +201,196 @@ msgstr ""
|
||||
#: apps/transactions/views/entities.py:171 apps/transactions/views/tags.py:91
|
||||
#: apps/transactions/views/tags.py:171
|
||||
msgid "Only the owner can edit this"
|
||||
msgstr ""
|
||||
msgstr "Тільки власник може редагувати його"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:82
|
||||
msgid "Account Group updated successfully"
|
||||
msgstr ""
|
||||
msgstr "Групу рахунків успішно оновлено"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:111
|
||||
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
|
||||
#: apps/rules/views.py:162 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"
|
||||
msgstr ""
|
||||
msgstr "Елемент більше не доступний для вас"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:114
|
||||
msgid "Account Group deleted successfully"
|
||||
msgstr ""
|
||||
msgstr "Групу рахунків успішно видалено"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:135
|
||||
#: apps/accounts/views/accounts.py:169 apps/dca/views.py:129
|
||||
#: apps/rules/views.py:187 apps/transactions/views/categories.py:192
|
||||
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
|
||||
msgid "Ownership taken successfully"
|
||||
msgstr ""
|
||||
msgstr "Успішно прийнято право власності"
|
||||
|
||||
#: apps/accounts/views/account_groups.py:165
|
||||
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
|
||||
#: apps/rules/views.py:218 apps/transactions/views/categories.py:142
|
||||
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
|
||||
msgid "Configuration saved successfully"
|
||||
msgstr ""
|
||||
msgstr "Конфігурацію успішно збережено"
|
||||
|
||||
#: apps/accounts/views/accounts.py:44
|
||||
msgid "Account added successfully"
|
||||
msgstr ""
|
||||
msgstr "Рахунок додано успішно"
|
||||
|
||||
#: apps/accounts/views/accounts.py:81
|
||||
msgid "Account updated successfully"
|
||||
msgstr ""
|
||||
msgstr "Рахунок успішно оновлено"
|
||||
|
||||
#: apps/accounts/views/accounts.py:148
|
||||
msgid "Account deleted successfully"
|
||||
msgstr ""
|
||||
msgstr "Рахунок успішно видалено"
|
||||
|
||||
#: apps/accounts/views/balance.py:77
|
||||
msgid "Balance reconciliation"
|
||||
msgstr ""
|
||||
msgstr "Звірка балансу"
|
||||
|
||||
#: apps/accounts/views/balance.py:85
|
||||
msgid "Account balances have been reconciled successfully"
|
||||
msgstr ""
|
||||
msgstr "Баланси рахунків успішно звірені"
|
||||
|
||||
#: apps/api/fields/transactions.py:27
|
||||
msgid "Category with this ID does not exist."
|
||||
msgstr ""
|
||||
msgstr "Категорії з таким ідентифікатором не існує."
|
||||
|
||||
#: apps/api/fields/transactions.py:37
|
||||
msgid "Invalid category data. Provide an ID or name."
|
||||
msgstr ""
|
||||
msgstr "Невірні дані категорії. Вкажіть ідентифікатор або ім'я."
|
||||
|
||||
#: apps/api/fields/transactions.py:70
|
||||
msgid "Tag with this ID does not exist."
|
||||
msgstr ""
|
||||
msgstr "Мітки з таким ідентифікатором не існує."
|
||||
|
||||
#: apps/api/fields/transactions.py:80
|
||||
msgid "Invalid tag data. Provide an ID or name."
|
||||
msgstr ""
|
||||
msgstr "Неправильні дані мітки. Вкажіть ідентифікатор або ім'я."
|
||||
|
||||
#: apps/api/fields/transactions.py:105
|
||||
msgid "Entity with this ID does not exist."
|
||||
msgstr ""
|
||||
msgstr "Об'єкт з таким ідентифікатором не існує."
|
||||
|
||||
#: apps/api/fields/transactions.py:115
|
||||
msgid "Invalid entity data. Provide an ID or name."
|
||||
msgstr ""
|
||||
msgstr "Невірні дані про об'єкт. Вкажіть ідентифікатор або ім'я."
|
||||
|
||||
#: apps/api/serializers/transactions.py:191
|
||||
msgid "Either 'date' or 'reference_date' must be provided."
|
||||
msgstr ""
|
||||
msgstr "Необхідно вказати або 'date', або 'reference_date'."
|
||||
|
||||
#: apps/common/fields/forms/dynamic_select.py:71
|
||||
#: apps/common/fields/forms/dynamic_select.py:143
|
||||
msgid "Error creating new instance"
|
||||
msgstr ""
|
||||
msgstr "Помилка створення нового екземпляра"
|
||||
|
||||
#: apps/common/fields/forms/grouped_select.py:24
|
||||
#: apps/common/widgets/tom_select.py:92 apps/common/widgets/tom_select.py:95
|
||||
msgid "Ungrouped"
|
||||
msgstr ""
|
||||
msgstr "Не згруповані"
|
||||
|
||||
#: apps/common/fields/month_year.py:30
|
||||
msgid "Invalid date format. Use YYYY-MM or YYYY-MM-DD."
|
||||
msgstr ""
|
||||
msgstr "Неправильний формат дати. Використовуйте YYYY-MM або YYYY-MM-DD."
|
||||
|
||||
#: apps/common/fields/month_year.py:59
|
||||
msgid "Invalid date format. Use YYYY-MM."
|
||||
msgstr ""
|
||||
msgstr "Неправильний формат дати. Використовуйте YYYY-MM."
|
||||
|
||||
#: apps/common/forms.py:25
|
||||
msgid "Owner"
|
||||
msgstr ""
|
||||
msgstr "Власник"
|
||||
|
||||
#: apps/common/forms.py:28
|
||||
msgid ""
|
||||
"The owner of this object, if empty all users can see, edit and take "
|
||||
"ownership."
|
||||
msgstr ""
|
||||
"Власник цього об'єкта, якщо він порожній, всі користувачі можуть бачити, "
|
||||
"редагувати і набувати права власності."
|
||||
|
||||
#: apps/common/forms.py:35
|
||||
msgid "Shared with users"
|
||||
msgstr ""
|
||||
msgstr "Поділитися з користувачами"
|
||||
|
||||
#: apps/common/forms.py:36
|
||||
msgid "Select users to share this object with"
|
||||
msgstr ""
|
||||
msgstr "Виберіть користувачів, яким буде надано доступ до цього об'єкта"
|
||||
|
||||
#: apps/common/forms.py:41
|
||||
msgid "Visibility"
|
||||
msgstr ""
|
||||
msgstr "Видимість"
|
||||
|
||||
#: apps/common/forms.py:43
|
||||
msgid ""
|
||||
"Private: Only shown for the owner and shared users. Only editable by the "
|
||||
"owner.<br/>Public: Shown for all users. Only editable by the owner."
|
||||
msgstr ""
|
||||
"Private: Відображається лише для власника та користувачів із загальним "
|
||||
"доступом. Редагувати може лише власник.<br/> Public: Відображається для всіх "
|
||||
"користувачів. Редагувати може лише власник."
|
||||
|
||||
#: apps/common/forms.py:80 apps/users/forms.py:135
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
msgstr "Зберегти"
|
||||
|
||||
#: apps/common/forms.py:95
|
||||
msgid "You cannot share this item with its owner."
|
||||
msgstr ""
|
||||
msgstr "Ви не можете поділитися цією річчю з її власником."
|
||||
|
||||
#: apps/common/models.py:29
|
||||
msgid "Private"
|
||||
msgstr ""
|
||||
msgstr "Private"
|
||||
|
||||
#: apps/common/models.py:30
|
||||
msgid "Public"
|
||||
msgstr ""
|
||||
msgstr "Public"
|
||||
|
||||
#: apps/common/templatetags/natural.py:20
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:9
|
||||
msgid "today"
|
||||
msgstr ""
|
||||
msgstr "сьогодні"
|
||||
|
||||
#: apps/common/templatetags/natural.py:22
|
||||
msgid "tomorrow"
|
||||
msgstr ""
|
||||
msgstr "завтра"
|
||||
|
||||
#: apps/common/templatetags/natural.py:24
|
||||
msgid "yesterday"
|
||||
msgstr ""
|
||||
msgstr "вчора"
|
||||
|
||||
#: apps/common/templatetags/natural.py:26
|
||||
msgid "last 7 days"
|
||||
msgstr ""
|
||||
msgstr "останні 7 днів"
|
||||
|
||||
#: apps/common/templatetags/natural.py:28
|
||||
msgid "in the next 7 days"
|
||||
msgstr ""
|
||||
msgstr "у наступні 7 днів"
|
||||
|
||||
#: apps/common/templatetags/natural.py:31
|
||||
#, python-format
|
||||
msgid "%(years)s year ago"
|
||||
msgid_plural "%(years)s years ago"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%(years)s рік тому"
|
||||
msgstr[1] "%(years)s роки тому"
|
||||
msgstr[2] "%(years)s років тому"
|
||||
|
||||
#: apps/common/templatetags/natural.py:37
|
||||
#, python-format
|
||||
msgid "%(months)s month ago"
|
||||
msgid_plural "%(months)s months ago"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%(months)s місяць тому"
|
||||
msgstr[1] "%(months)s місяці тому"
|
||||
msgstr[2] "%(months)s місяців тому"
|
||||
|
||||
#: apps/common/templatetags/natural.py:41
|
||||
#, python-format
|
||||
msgid "%(weeks)s week ago"
|
||||
msgid_plural "%(weeks)s weeks ago"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%(weeks)s тиждень тому"
|
||||
msgstr[1] "%(weeks)s тижня тому"
|
||||
msgstr[2] "%(weeks)s тижнів тому"
|
||||
|
||||
#: apps/common/templatetags/natural.py:46
|
||||
#, python-format
|
||||
@@ -385,6 +398,7 @@ msgid "in %(years)s year"
|
||||
msgid_plural "in %(years)s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: apps/common/templatetags/natural.py:51
|
||||
#, python-format
|
||||
@@ -402,55 +416,55 @@ msgstr[1] ""
|
||||
|
||||
#: apps/common/templatetags/toast_bg.py:34
|
||||
msgid "Success"
|
||||
msgstr ""
|
||||
msgstr "Успіх"
|
||||
|
||||
#: apps/common/templatetags/toast_bg.py:36
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
msgstr "Попередження"
|
||||
|
||||
#: apps/common/templatetags/toast_bg.py:38
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
msgstr "Помилка"
|
||||
|
||||
#: apps/common/templatetags/toast_bg.py:40
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
msgstr "Info"
|
||||
|
||||
#: apps/common/views.py:111
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr ""
|
||||
msgstr "Кеш успішно очищено"
|
||||
|
||||
#: apps/common/widgets/datepicker.py:53 apps/common/widgets/datepicker.py:206
|
||||
#: apps/common/widgets/datepicker.py:264
|
||||
msgid "Today"
|
||||
msgstr ""
|
||||
msgstr "Сьогодні"
|
||||
|
||||
#: apps/common/widgets/datepicker.py:139
|
||||
msgid "Now"
|
||||
msgstr ""
|
||||
msgstr "Зараз"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:11
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
msgstr "Видалити"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:15
|
||||
#: templates/mini_tools/unit_price_calculator.html:174
|
||||
#: templates/monthly_overview/pages/overview.html:172
|
||||
#: templates/transactions/pages/transactions.html:17
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
msgstr "Чисто"
|
||||
|
||||
#: apps/common/widgets/tom_select.py:16
|
||||
msgid "No results..."
|
||||
msgstr ""
|
||||
msgstr "Жодних результатів..."
|
||||
|
||||
#: apps/currencies/forms.py:17 apps/currencies/models.py:22
|
||||
msgid "Prefix"
|
||||
msgstr ""
|
||||
msgstr "Префікс"
|
||||
|
||||
#: apps/currencies/forms.py:18 apps/currencies/models.py:23
|
||||
msgid "Suffix"
|
||||
msgstr ""
|
||||
msgstr "Суфікс"
|
||||
|
||||
#: apps/currencies/forms.py:69 apps/dca/models.py:158 apps/rules/forms.py:169
|
||||
#: apps/rules/forms.py:182 apps/rules/models.py:33 apps/rules/models.py:254
|
||||
@@ -460,19 +474,19 @@ msgstr ""
|
||||
#: templates/exchange_rates/fragments/table.html:10
|
||||
#: templates/exchange_rates_services/fragments/table.html:10
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
msgstr "Дата"
|
||||
|
||||
#: apps/currencies/models.py:14
|
||||
msgid "Currency Code"
|
||||
msgstr ""
|
||||
msgstr "Код валюти"
|
||||
|
||||
#: apps/currencies/models.py:16
|
||||
msgid "Currency Name"
|
||||
msgstr ""
|
||||
msgstr "Назва валюти"
|
||||
|
||||
#: apps/currencies/models.py:20
|
||||
msgid "Decimal Places"
|
||||
msgstr ""
|
||||
msgstr "Десяткові знаки"
|
||||
|
||||
#: apps/currencies/models.py:40 apps/export_app/forms.py:26
|
||||
#: apps/export_app/forms.py:133 apps/transactions/filters.py:60
|
||||
@@ -483,58 +497,58 @@ msgstr ""
|
||||
#: templates/transactions/fragments/summary.html:8
|
||||
#: templates/transactions/pages/transactions.html:59
|
||||
msgid "Currencies"
|
||||
msgstr ""
|
||||
msgstr "Валюти"
|
||||
|
||||
#: apps/currencies/models.py:49
|
||||
msgid "Currency cannot have itself as exchange currency."
|
||||
msgstr ""
|
||||
msgstr "Валюта не може бути валютою обміну."
|
||||
|
||||
#: apps/currencies/models.py:60
|
||||
msgid "From Currency"
|
||||
msgstr ""
|
||||
msgstr "З валюти"
|
||||
|
||||
#: apps/currencies/models.py:66
|
||||
msgid "To Currency"
|
||||
msgstr ""
|
||||
msgstr "У валюту"
|
||||
|
||||
#: apps/currencies/models.py:69 apps/currencies/models.py:74
|
||||
msgid "Exchange Rate"
|
||||
msgstr ""
|
||||
msgstr "Обмінний курс"
|
||||
|
||||
#: apps/currencies/models.py:71
|
||||
msgid "Date and Time"
|
||||
msgstr ""
|
||||
msgstr "Дата і час"
|
||||
|
||||
#: apps/currencies/models.py:75 apps/export_app/forms.py:68
|
||||
#: apps/export_app/forms.py:145 templates/exchange_rates/fragments/list.html:6
|
||||
#: templates/exchange_rates/pages/index.html:4
|
||||
#: templates/includes/navbar.html:126
|
||||
msgid "Exchange Rates"
|
||||
msgstr ""
|
||||
msgstr "Обмінні курси"
|
||||
|
||||
#: apps/currencies/models.py:87
|
||||
msgid "From and To currencies cannot be the same."
|
||||
msgstr ""
|
||||
msgstr "Валюти «Від» і «До» не можуть бути однаковими."
|
||||
|
||||
#: apps/currencies/models.py:102
|
||||
msgid "On"
|
||||
msgstr ""
|
||||
msgstr "On"
|
||||
|
||||
#: apps/currencies/models.py:103
|
||||
msgid "Every X hours"
|
||||
msgstr ""
|
||||
msgstr "Кожні Х годин"
|
||||
|
||||
#: apps/currencies/models.py:104
|
||||
msgid "Not on"
|
||||
msgstr ""
|
||||
msgstr "Not on"
|
||||
|
||||
#: apps/currencies/models.py:106
|
||||
msgid "Service Name"
|
||||
msgstr ""
|
||||
msgstr "Назва сервісу"
|
||||
|
||||
#: apps/currencies/models.py:108
|
||||
msgid "Service Type"
|
||||
msgstr ""
|
||||
msgstr "Тип сервісу"
|
||||
|
||||
#: apps/currencies/models.py:110 apps/transactions/models.py:209
|
||||
#: apps/transactions/models.py:233 apps/transactions/models.py:257
|
||||
@@ -543,27 +557,27 @@ msgstr ""
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21 templates/users/fragments/list.html:28
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
msgstr "Активний"
|
||||
|
||||
#: apps/currencies/models.py:115
|
||||
msgid "API Key"
|
||||
msgstr ""
|
||||
msgstr "Ключ API"
|
||||
|
||||
#: apps/currencies/models.py:116
|
||||
msgid "API key for the service (if required)"
|
||||
msgstr ""
|
||||
msgstr "API-ключ для сервісу (якщо потрібно)"
|
||||
|
||||
#: apps/currencies/models.py:121
|
||||
msgid "Interval Type"
|
||||
msgstr ""
|
||||
msgstr "Тип інтервалу"
|
||||
|
||||
#: apps/currencies/models.py:125
|
||||
msgid "Interval"
|
||||
msgstr ""
|
||||
msgstr "Інтервал"
|
||||
|
||||
#: apps/currencies/models.py:128
|
||||
msgid "Last Successful Fetch"
|
||||
msgstr ""
|
||||
msgstr "Остання успішна вибірка"
|
||||
|
||||
#: apps/currencies/models.py:133
|
||||
msgid "Target Currencies"
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
color="grey"></c-amount.display>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if currency.consolidated %}
|
||||
{% if currency.consolidated and currency.consolidated.total_final != currency.total_final %}
|
||||
<div class="d-flex align-items-baseline w-100">
|
||||
<div class="account-name text-start font-monospace tw-text-gray-300">
|
||||
<span class="hierarchy-line-icon"></span>{% trans 'Consolidated' %}</div>
|
||||
@@ -57,7 +57,7 @@
|
||||
:prefix="currency.consolidated.currency.prefix"
|
||||
:suffix="currency.consolidated.currency.suffix"
|
||||
:decimal_places="currency.consolidated.currency.decimal_places"
|
||||
color="{% if currency.total_final > 0 %}green{% elif currency.total_final < 0 %}red{% endif %}"
|
||||
color="{% if currency.consolidated.total_final > 0 %}green{% elif currency.consolidated.total_final < 0 %}red{% endif %}"
|
||||
text-end></c-amount.display>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user