mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-08-25 21:04:07 +02:00
@@ -1,3 +1,82 @@
|
||||
from django.test import TestCase
|
||||
import json
|
||||
import tempfile
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
# Create your tests here.
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.accounts.models import Account
|
||||
from apps.currencies.models import Currency, ExchangeRate
|
||||
from apps.transactions.models import Transaction
|
||||
|
||||
|
||||
@override_settings(
|
||||
STATIC_ROOT=tempfile.gettempdir(),
|
||||
STORAGES={
|
||||
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
},
|
||||
},
|
||||
)
|
||||
class NetWorthCurrencyChartTests(TestCase):
|
||||
def test_consolidated_currency_is_a_selectable_dashed_matching_color_line(self):
|
||||
user = get_user_model().objects.create_user(
|
||||
email="chart@example.com", password="password"
|
||||
)
|
||||
usd = Currency.objects.create(code="USD", name="US Dollar", prefix="$ ")
|
||||
eur = Currency.objects.create(
|
||||
code="EUR", name="Euro", prefix="€ ", exchange_currency=usd
|
||||
)
|
||||
usd_account = Account.all_objects.create(
|
||||
name="USD account", currency=usd, owner=user
|
||||
)
|
||||
eur_account = Account.all_objects.create(
|
||||
name="EUR account", currency=eur, owner=user
|
||||
)
|
||||
ExchangeRate.objects.create(
|
||||
from_currency=eur,
|
||||
to_currency=usd,
|
||||
rate=Decimal("1.234567"),
|
||||
date=timezone.now(),
|
||||
)
|
||||
for account, amount in ((usd_account, "100"), (eur_account, "50")):
|
||||
Transaction.userless_all_objects.create(
|
||||
account=account,
|
||||
owner=user,
|
||||
type=Transaction.Type.INCOME,
|
||||
amount=Decimal(amount),
|
||||
date=date(2026, 1, 15),
|
||||
reference_date=date(2026, 1, 1),
|
||||
is_paid=True,
|
||||
)
|
||||
|
||||
self.client.force_login(user)
|
||||
response = self.client.get(reverse("net_worth"))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
chart_data = json.loads(response.context["chart_data_currency_json"])
|
||||
datasets = {dataset["label"]: dataset for dataset in chart_data["datasets"]}
|
||||
self.assertIn("US Dollar Consolidated", datasets)
|
||||
regular = datasets["US Dollar"]
|
||||
consolidated = datasets["US Dollar Consolidated"]
|
||||
self.assertEqual(consolidated["data"], [161.73])
|
||||
self.assertNotIn("borderColor", regular)
|
||||
self.assertNotIn("borderColor", consolidated)
|
||||
self.assertEqual(consolidated["colorSource"], "US Dollar")
|
||||
self.assertEqual(consolidated["borderDash"], [12, 6])
|
||||
self.assertEqual(consolidated["pointRadius"], 0)
|
||||
self.assertEqual(consolidated["pointHitRadius"], 8)
|
||||
self.assertContains(
|
||||
response,
|
||||
"showOnlyCurrencyDataset('US Dollar Consolidated', 'US Dollar')",
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<span class="text-start shrink">Consolidated</span>',
|
||||
html=False,
|
||||
)
|
||||
|
||||
@@ -3,8 +3,11 @@ import json
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from apps.currencies.models import Currency
|
||||
from apps.currencies.utils.convert import convert
|
||||
from apps.net_worth.utils.calculate_net_worth import (
|
||||
calculate_historical_currency_net_worth,
|
||||
calculate_historical_account_balance,
|
||||
@@ -78,6 +81,17 @@ def net_worth(request):
|
||||
)
|
||||
|
||||
datasets = []
|
||||
currency_models = {
|
||||
currency.name: currency
|
||||
for currency in Currency.objects.filter(name__in=currencies).select_related(
|
||||
"exchange_currency"
|
||||
)
|
||||
}
|
||||
consolidated_currencies = {
|
||||
data["currency"]["name"]
|
||||
for data in currency_net_worth.values()
|
||||
if data["consolidated"]["total_final"] != data["total_final"]
|
||||
}
|
||||
for i, currency in enumerate(currencies):
|
||||
data = [
|
||||
float(month_data[currency])
|
||||
@@ -93,6 +107,45 @@ def net_worth(request):
|
||||
}
|
||||
)
|
||||
|
||||
if currency in consolidated_currencies:
|
||||
target = currency_models[currency]
|
||||
sources = [
|
||||
source
|
||||
for source in currency_models.values()
|
||||
if source.exchange_currency_id == target.id
|
||||
]
|
||||
rates = {}
|
||||
for source in sources:
|
||||
converted, _, _, _ = convert(1, source, target)
|
||||
if converted is not None:
|
||||
rates[source.name] = converted
|
||||
|
||||
consolidated_data = [
|
||||
float(
|
||||
round(
|
||||
month_data[currency]
|
||||
+ sum(
|
||||
month_data[source] * rate for source, rate in rates.items()
|
||||
),
|
||||
target.decimal_places,
|
||||
)
|
||||
)
|
||||
for month_data in historical_currency_net_worth.values()
|
||||
]
|
||||
datasets.append(
|
||||
{
|
||||
"label": f"{currency} {gettext('Consolidated')}",
|
||||
"data": consolidated_data,
|
||||
"yAxisID": f"y{i}",
|
||||
"fill": False,
|
||||
"tension": 0.1,
|
||||
"colorSource": currency,
|
||||
"borderDash": [12, 6],
|
||||
"pointRadius": 0,
|
||||
"pointHitRadius": 8,
|
||||
}
|
||||
)
|
||||
|
||||
chart_data_currency = {"labels": labels, "datasets": datasets}
|
||||
|
||||
chart_data_currency_json = json.dumps(chart_data_currency, cls=DjangoJSONEncoder)
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<li>
|
||||
{% if currency.consolidated and currency.consolidated.total_final != currency.total_final %}
|
||||
<a class="cursor-pointer select-auto flex justify-between items-center w-full"
|
||||
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
|
||||
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}', '{{ currency.currency.name }}')">
|
||||
<span
|
||||
class="currency-name text-start font-mono shrink text-ellipsis">{{ currency.currency.name }}</span>
|
||||
<span class="text-end shrink-0">
|
||||
@@ -80,7 +80,8 @@
|
||||
</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a class="text-base-content/60 select-auto flex justify-between items-center w-full">
|
||||
<a class="cursor-pointer text-base-content/60 select-auto flex justify-between items-center w-full"
|
||||
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }} {% trans "Consolidated" %}', '{{ currency.currency.name }}')">
|
||||
<span class="text-start shrink">{% trans "Consolidated" %}</span>
|
||||
<span class="text-end shrink-0">
|
||||
<c-amount.display :amount="currency.consolidated.total_final"
|
||||
@@ -95,7 +96,7 @@
|
||||
</ul>
|
||||
{% else %}
|
||||
<a class="cursor-pointer select-auto flex justify-between items-center w-full"
|
||||
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}')">
|
||||
_="on click showOnlyCurrencyDataset('{{ currency.currency.name }}', '{{ currency.currency.name }}')">
|
||||
<span class="currency-name text-start font-mono shrink">{{ currency.currency.name }}</span>
|
||||
<span class="text-end shrink-0">
|
||||
<div>
|
||||
@@ -302,6 +303,16 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const dataset of currencyChart.data.datasets) {
|
||||
if (!dataset.colorSource) continue;
|
||||
const source = currencyChart.data.datasets.find(
|
||||
candidate => candidate.label === dataset.colorSource
|
||||
);
|
||||
dataset.borderColor = source.borderColor;
|
||||
dataset.backgroundColor = source.backgroundColor;
|
||||
}
|
||||
currencyChart.update('none');
|
||||
}
|
||||
</script>
|
||||
<script id="accountBalanceChartScript">
|
||||
@@ -448,7 +459,7 @@
|
||||
call accountChart.update()
|
||||
end
|
||||
|
||||
def showOnlyCurrencyDataset(datasetName)
|
||||
def showOnlyCurrencyDataset(datasetName, differenceDatasetName)
|
||||
for dataset in currencyChart.data.datasets
|
||||
set isMatch to dataset.label is datasetName
|
||||
call currencyChart.setDatasetVisibility(currencyChart.data.datasets.indexOf(dataset), isMatch)
|
||||
@@ -456,7 +467,7 @@
|
||||
call currencyChart.update()
|
||||
|
||||
for dataset in monthlyDifferenceChart.data.datasets
|
||||
set isMatch to dataset.label is datasetName
|
||||
set isMatch to dataset.label is differenceDatasetName
|
||||
call monthlyDifferenceChart.setDatasetVisibility(monthlyDifferenceChart.data.datasets.indexOf(dataset), isMatch)
|
||||
end
|
||||
call monthlyDifferenceChart.update()
|
||||
|
||||
Reference in New Issue
Block a user