diff --git a/app/apps/api/__init__.py b/app/apps/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/apps/api/apps.py b/app/apps/api/apps.py new file mode 100644 index 0000000..a79077a --- /dev/null +++ b/app/apps/api/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.api" diff --git a/app/apps/api/migrations/__init__.py b/app/apps/api/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/apps/api/serializers/__init__.py b/app/apps/api/serializers/__init__.py new file mode 100644 index 0000000..11c1f3c --- /dev/null +++ b/app/apps/api/serializers/__init__.py @@ -0,0 +1,3 @@ +from .transactions import * +from .accounts import * +from .currencies import * diff --git a/app/apps/api/serializers/accounts.py b/app/apps/api/serializers/accounts.py new file mode 100644 index 0000000..880c03c --- /dev/null +++ b/app/apps/api/serializers/accounts.py @@ -0,0 +1,55 @@ +from rest_framework import serializers + +from apps.api.serializers.currencies import CurrencySerializer +from apps.accounts.models import AccountGroup, Account +from apps.currencies.models import Currency + + +class AccountGroupSerializer(serializers.ModelSerializer): + class Meta: + model = AccountGroup + fields = "__all__" + + +class AccountSerializer(serializers.ModelSerializer): + group = AccountGroupSerializer(read_only=True) + group_id = serializers.PrimaryKeyRelatedField( + queryset=AccountGroup.objects.all(), + source="group", + write_only=True, + allow_null=True, + ) + currency = CurrencySerializer(read_only=True) + currency_id = serializers.PrimaryKeyRelatedField( + queryset=Currency.objects.all(), source="currency", write_only=True + ) + exchange_currency = CurrencySerializer(read_only=True) + exchange_currency_id = serializers.PrimaryKeyRelatedField( + queryset=Currency.objects.all(), + source="exchange_currency", + write_only=True, + allow_null=True, + ) + + class Meta: + model = Account + fields = [ + "id", + "name", + "group", + "group_id", + "currency", + "currency_id", + "exchange_currency", + "exchange_currency_id", + "is_asset", + ] + + def create(self, validated_data): + return Account.objects.create(**validated_data) + + def update(self, instance, validated_data): + for attr, value in validated_data.items(): + setattr(instance, attr, value) + instance.save() + return instance diff --git a/app/apps/api/serializers/currencies.py b/app/apps/api/serializers/currencies.py new file mode 100644 index 0000000..990f7b8 --- /dev/null +++ b/app/apps/api/serializers/currencies.py @@ -0,0 +1,29 @@ +from rest_framework import serializers +from apps.currencies.models import Currency, ExchangeRate + + +class CurrencySerializer(serializers.ModelSerializer): + class Meta: + model = Currency + fields = "__all__" + + +class ExchangeRateSerializer(serializers.ModelSerializer): + # For read operations (GET) + from_currency = CurrencySerializer(read_only=True) + + # For write operations (POST, PUT, PATCH) + from_currency_id = serializers.PrimaryKeyRelatedField( + queryset=Currency.objects.all(), source="from_currency", write_only=True + ) + + to_currency = CurrencySerializer(read_only=True) + + # For write operations (POST, PUT, PATCH) + to_currency_id = serializers.PrimaryKeyRelatedField( + queryset=Currency.objects.all(), source="from_currency", write_only=True + ) + + class Meta: + model = ExchangeRate + fields = "__all__" diff --git a/app/apps/api/serializers/transactions.py b/app/apps/api/serializers/transactions.py new file mode 100644 index 0000000..24c7504 --- /dev/null +++ b/app/apps/api/serializers/transactions.py @@ -0,0 +1,60 @@ +from rest_framework import serializers +from rest_framework.permissions import IsAuthenticated + +from apps.accounts.models import Account +from apps.api.serializers.accounts import AccountSerializer +from apps.transactions.models import ( + Transaction, + TransactionCategory, + TransactionTag, + InstallmentPlan, +) + + +# Create serializers for other related models as needed +class TransactionCategorySerializer(serializers.ModelSerializer): + permission_classes = [IsAuthenticated] + + class Meta: + model = TransactionCategory + fields = "__all__" + + +class TransactionTagSerializer(serializers.ModelSerializer): + permission_classes = [IsAuthenticated] + + class Meta: + model = TransactionTag + fields = "__all__" + + +class InstallmentPlanSerializer(serializers.ModelSerializer): + permission_classes = [IsAuthenticated] + + class Meta: + model = InstallmentPlan + fields = "__all__" + + +class TransactionSerializer(serializers.ModelSerializer): + category_name = serializers.CharField(source="category.name", read_only=True) + tags = TransactionTagSerializer(many=True, read_only=True) + exchanged_amount = serializers.SerializerMethodField() + + # For read operations (GET) + account = AccountSerializer(read_only=True) + + # For write operations (POST, PUT, PATCH) + account_id = serializers.PrimaryKeyRelatedField( + queryset=Account.objects.all(), source="account", write_only=True + ) + + permission_classes = [IsAuthenticated] + + class Meta: + model = Transaction + fields = "__all__" + + @staticmethod + def get_exchanged_amount(obj): + return obj.exchanged_amount() diff --git a/app/apps/api/urls.py b/app/apps/api/urls.py new file mode 100644 index 0000000..071f487 --- /dev/null +++ b/app/apps/api/urls.py @@ -0,0 +1,18 @@ +from django.urls import path, include +from rest_framework import routers + +from apps.api import views + +router = routers.DefaultRouter() +router.register(r"transactions", views.TransactionViewSet) +router.register(r"categories", views.TransactionCategoryViewSet) +router.register(r"tags", views.TransactionTagViewSet) +router.register(r"installment-plans", views.InstallmentPlanViewSet) +router.register(r"account-groups", views.AccountGroupViewSet) +router.register(r"accounts", views.AccountViewSet) +router.register(r"currencies", views.CurrencyViewSet) +router.register(r"exchange-rates", views.ExchangeRateViewSet) + +urlpatterns = [ + path("", include(router.urls)), +] diff --git a/app/apps/api/views/__init__.py b/app/apps/api/views/__init__.py new file mode 100644 index 0000000..11c1f3c --- /dev/null +++ b/app/apps/api/views/__init__.py @@ -0,0 +1,3 @@ +from .transactions import * +from .accounts import * +from .currencies import * diff --git a/app/apps/api/views/accounts.py b/app/apps/api/views/accounts.py new file mode 100644 index 0000000..de5b29c --- /dev/null +++ b/app/apps/api/views/accounts.py @@ -0,0 +1,17 @@ +from rest_framework import viewsets +from apps.accounts.models import AccountGroup, Account +from apps.api.serializers import AccountGroupSerializer, AccountSerializer + + +class AccountGroupViewSet(viewsets.ModelViewSet): + queryset = AccountGroup.objects.all() + serializer_class = AccountGroupSerializer + + +class AccountViewSet(viewsets.ModelViewSet): + queryset = Account.objects.all() + serializer_class = AccountSerializer + + def get_queryset(self): + queryset = super().get_queryset() + return queryset.select_related("group", "currency", "exchange_currency") diff --git a/app/apps/api/views/currencies.py b/app/apps/api/views/currencies.py new file mode 100644 index 0000000..56a2622 --- /dev/null +++ b/app/apps/api/views/currencies.py @@ -0,0 +1,16 @@ +from rest_framework import viewsets + +from apps.api.serializers import ExchangeRateSerializer +from apps.api.serializers import CurrencySerializer +from apps.currencies.models import Currency +from apps.currencies.models import ExchangeRate + + +class CurrencyViewSet(viewsets.ModelViewSet): + queryset = Currency.objects.all() + serializer_class = CurrencySerializer + + +class ExchangeRateViewSet(viewsets.ModelViewSet): + queryset = ExchangeRate.objects.all() + serializer_class = ExchangeRateSerializer diff --git a/app/apps/api/views/transactions.py b/app/apps/api/views/transactions.py new file mode 100644 index 0000000..ad79cd8 --- /dev/null +++ b/app/apps/api/views/transactions.py @@ -0,0 +1,34 @@ +from rest_framework import permissions, viewsets + +from apps.api.serializers import ( + TransactionSerializer, + TransactionCategorySerializer, + TransactionTagSerializer, + InstallmentPlanSerializer, +) +from apps.transactions.models import ( + Transaction, + TransactionCategory, + TransactionTag, + InstallmentPlan, +) + + +class TransactionViewSet(viewsets.ModelViewSet): + queryset = Transaction.objects.all() + serializer_class = TransactionSerializer + + +class TransactionCategoryViewSet(viewsets.ModelViewSet): + queryset = TransactionCategory.objects.all() + serializer_class = TransactionCategorySerializer + + +class TransactionTagViewSet(viewsets.ModelViewSet): + queryset = TransactionTag.objects.all() + serializer_class = TransactionTagSerializer + + +class InstallmentPlanViewSet(viewsets.ModelViewSet): + queryset = InstallmentPlan.objects.all() + serializer_class = InstallmentPlanSerializer diff --git a/requirements.txt b/requirements.txt index 04a10fe..cd46ca9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,9 @@ django-filter==24.3 django-anymail[sendinblue]==10.2 django-debug-toolbar==4.3.0 django-cachalot~=2.6.3 + djangorestframework~=3.15.2 +drf-spectacular~=0.27.2 gunicorn==21.2.0 whitenoise[brotli]==6.6.0