mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-11-13 12:23:44 +01:00
Investments are accounts flagged as investments; performance is derived from their transactions. Linked transfers are contributions and withdrawals (average cost, realized gains), unlinked transactions are gains or losses, and income comes from the accounts' income entities. - Unit-priced (exchange currency) or value-tracked accounts - Money-weighted return (XIRR), annualized after a year - Totals converted along each currency's exchange chain, with currency effect - Investments list and detail pages; buy/sell/income use the transfer and transaction forms - GET /api/accounts/<id>/performance/
99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
from drf_spectacular.utils import extend_schema, extend_schema_view
|
|
from rest_framework import viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
|
|
from apps.accounts.models import AccountGroup, Account
|
|
from apps.accounts.services import get_account_balance
|
|
from apps.api.permissions import SHARED_OBJECT_PERMISSIONS
|
|
from apps.api.serializers import (
|
|
AccountGroupSerializer,
|
|
AccountSerializer,
|
|
AccountBalanceSerializer,
|
|
InvestmentPerformanceSerializer,
|
|
)
|
|
from apps.investments.services import get_holding_performance
|
|
|
|
|
|
class AccountGroupViewSet(viewsets.ModelViewSet):
|
|
"""ViewSet for managing account groups."""
|
|
|
|
permission_classes = SHARED_OBJECT_PERMISSIONS
|
|
queryset = AccountGroup.objects.all()
|
|
serializer_class = AccountGroupSerializer
|
|
filterset_fields = {
|
|
"name": ["exact", "icontains"],
|
|
"owner": ["exact"],
|
|
}
|
|
search_fields = ["name"]
|
|
ordering_fields = "__all__"
|
|
ordering = ["id"]
|
|
|
|
def get_queryset(self):
|
|
return AccountGroup.objects.all()
|
|
|
|
|
|
@extend_schema_view(
|
|
balance=extend_schema(
|
|
summary="Get account balance",
|
|
description="Returns the current and projected balance for the account, along with currency data.",
|
|
responses={200: AccountBalanceSerializer},
|
|
),
|
|
performance=extend_schema(
|
|
summary="Get investment performance",
|
|
description="Returns quantity, cost basis, market value, realized/unrealized gains, income and total return, in the account's exchange currency (or its own currency when it has none).",
|
|
responses={200: InvestmentPerformanceSerializer},
|
|
),
|
|
)
|
|
class AccountViewSet(viewsets.ModelViewSet):
|
|
"""ViewSet for managing accounts."""
|
|
|
|
permission_classes = SHARED_OBJECT_PERMISSIONS
|
|
queryset = Account.objects.all()
|
|
serializer_class = AccountSerializer
|
|
filterset_fields = {
|
|
"name": ["exact", "icontains"],
|
|
"group": ["exact", "isnull"],
|
|
"currency": ["exact"],
|
|
"exchange_currency": ["exact", "isnull"],
|
|
"is_asset": ["exact"],
|
|
"is_investment": ["exact"],
|
|
"is_archived": ["exact"],
|
|
"owner": ["exact"],
|
|
}
|
|
search_fields = ["name"]
|
|
ordering_fields = "__all__"
|
|
ordering = ["id"]
|
|
|
|
def get_queryset(self):
|
|
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)
|
|
|
|
@action(detail=True, methods=["get"], permission_classes=[IsAuthenticated])
|
|
def performance(self, request, pk=None):
|
|
"""Get investment performance (cost basis, value, returns) for an account."""
|
|
account = self.get_object()
|
|
return Response(
|
|
InvestmentPerformanceSerializer(get_holding_performance(account)).data
|
|
)
|