mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-07-15 17:22:41 +02:00
feat(api): make category and tags create or get
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from apps.transactions.models import TransactionCategory, TransactionTag
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(
|
||||||
|
{
|
||||||
|
"oneOf": [{"type": "string"}, {"type": "integer"}],
|
||||||
|
"description": "TransactionCategory ID or name. If the name doesn't exist, a new one will be created",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
class TransactionCategoryField(serializers.Field):
|
||||||
|
def to_representation(self, value):
|
||||||
|
return {"id": value.id, "name": value.name}
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
if isinstance(data, int):
|
||||||
|
try:
|
||||||
|
return TransactionCategory.objects.get(pk=data)
|
||||||
|
except TransactionCategory.DoesNotExist:
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
"Category with this ID does not exist."
|
||||||
|
)
|
||||||
|
elif isinstance(data, str):
|
||||||
|
category, created = TransactionCategory.objects.get_or_create(name=data)
|
||||||
|
return category
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
"Invalid category data. Provide an ID or name."
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_schema():
|
||||||
|
return {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string", "description": "TransactionTag ID or name"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_field(
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
|
||||||
|
"description": "TransactionTag ID or name. If the name doesn't exist, a new one will be created",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
class TransactionTagField(serializers.Field):
|
||||||
|
def to_representation(self, value):
|
||||||
|
return [{"id": tag.id, "name": tag.name} for tag in value.all()]
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
tags = []
|
||||||
|
for item in data:
|
||||||
|
if isinstance(item, int):
|
||||||
|
try:
|
||||||
|
tag = TransactionTag.objects.get(pk=item)
|
||||||
|
except TransactionTag.DoesNotExist:
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
f"Tag with ID {item} does not exist."
|
||||||
|
)
|
||||||
|
elif isinstance(item, str):
|
||||||
|
tag, created = TransactionTag.objects.get_or_create(name=item)
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
"Invalid tag data. Provide an ID or name."
|
||||||
|
)
|
||||||
|
tags.append(tag)
|
||||||
|
return tags
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from apps.accounts.models import Account
|
from apps.accounts.models import Account
|
||||||
|
from apps.api.fields.transactions import TransactionTagField, TransactionCategoryField
|
||||||
from apps.api.serializers.accounts import AccountSerializer
|
from apps.api.serializers.accounts import AccountSerializer
|
||||||
from apps.transactions.models import (
|
from apps.transactions.models import (
|
||||||
Transaction,
|
Transaction,
|
||||||
@@ -37,8 +40,9 @@ class InstallmentPlanSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class TransactionSerializer(serializers.ModelSerializer):
|
class TransactionSerializer(serializers.ModelSerializer):
|
||||||
category_name = serializers.CharField(source="category.name", read_only=True)
|
category = TransactionCategoryField(required=False)
|
||||||
tags = TransactionTagSerializer(many=True, read_only=True)
|
tags = TransactionTagField(required=False)
|
||||||
|
|
||||||
exchanged_amount = serializers.SerializerMethodField()
|
exchanged_amount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
# For read operations (GET)
|
# For read operations (GET)
|
||||||
@@ -49,11 +53,45 @@ class TransactionSerializer(serializers.ModelSerializer):
|
|||||||
queryset=Account.objects.all(), source="account", write_only=True
|
queryset=Account.objects.all(), source="account", write_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
reference_date = serializers.DateField(required=False)
|
||||||
|
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Transaction
|
model = Transaction
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
|
"installment_plan",
|
||||||
|
"recurring_transaction",
|
||||||
|
"installment_id",
|
||||||
|
]
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
if "date" in data and "reference_date" not in data:
|
||||||
|
data["reference_date"] = data["date"].replace(day=1)
|
||||||
|
elif "reference_date" in data:
|
||||||
|
data["reference_date"] = data["reference_date"].replace(day=1)
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
_("Either 'date' or 'reference_date' must be provided.")
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
tags = validated_data.pop("tags", [])
|
||||||
|
transaction = Transaction.objects.create(**validated_data)
|
||||||
|
transaction.tags.set(tags)
|
||||||
|
return transaction
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
tags = validated_data.pop("tags", None)
|
||||||
|
for attr, value in validated_data.items():
|
||||||
|
setattr(instance, attr, value)
|
||||||
|
instance.save()
|
||||||
|
if tags is not None:
|
||||||
|
instance.tags.set(tags)
|
||||||
|
return instance
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_exchanged_amount(obj):
|
def get_exchanged_amount(obj):
|
||||||
|
|||||||
@@ -62,19 +62,6 @@ class TransactionForm(forms.ModelForm):
|
|||||||
"notes": forms.Textarea(attrs={"rows": 3}),
|
"notes": forms.Textarea(attrs={"rows": 3}),
|
||||||
"account": TomSelect(),
|
"account": TomSelect(),
|
||||||
}
|
}
|
||||||
# labels = {
|
|
||||||
# "tags": mark_safe('<i class="fa-solid fa-hashtag me-1"></i>' + _("Tags")),
|
|
||||||
# "category": mark_safe(
|
|
||||||
# '<i class="fa-solid fa-icons me-1"></i>' + _("Category")
|
|
||||||
# ),
|
|
||||||
# "notes": mark_safe(
|
|
||||||
# '<i class="fa-solid fa-align-justify me-1"></i>' + _("Notes")
|
|
||||||
# ),
|
|
||||||
# "amount": mark_safe('<i class="fa-solid fa-coins me-1"></i>' + _("Amount")),
|
|
||||||
# "description": mark_safe(
|
|
||||||
# '<i class="fa-solid fa-quote-left me-1"></i>' + _("Name")
|
|
||||||
# ),
|
|
||||||
# }
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|||||||
@@ -103,7 +103,12 @@ class Transaction(models.Model):
|
|||||||
self.amount = truncate_decimal(
|
self.amount = truncate_decimal(
|
||||||
value=self.amount, decimal_places=self.account.currency.decimal_places
|
value=self.amount, decimal_places=self.account.currency.decimal_places
|
||||||
)
|
)
|
||||||
self.reference_date = self.reference_date.replace(day=1)
|
|
||||||
|
if self.reference_date:
|
||||||
|
self.reference_date = self.reference_date.replace(day=1)
|
||||||
|
elif not self.reference_date and self.date:
|
||||||
|
self.reference_date = self.date.replace(day=1)
|
||||||
|
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user