agdar/finance/serializers.py
2025-11-02 14:35:35 +03:00

203 lines
7.0 KiB
Python

"""
DRF Serializers for Finance app.
"""
from rest_framework import serializers
from .models import Invoice, InvoiceLineItem, Payment, Service, Package, PackagePurchase, Payer
from core.serializers import PatientListSerializer
class ServiceSerializer(serializers.ModelSerializer):
"""Serializer for Service model."""
clinic_name = serializers.CharField(source='clinic.name_en', read_only=True)
class Meta:
model = Service
fields = [
'id', 'code', 'name_en', 'name_ar',
'clinic', 'clinic_name', 'base_price',
'duration_minutes', 'is_active'
]
read_only_fields = ['id']
class PackageSerializer(serializers.ModelSerializer):
"""Serializer for Package model."""
services_display = serializers.SerializerMethodField()
class Meta:
model = Package
fields = [
'id', 'name_en', 'name_ar', 'services', 'services_display',
'total_sessions', 'price', 'validity_days', 'is_active'
]
read_only_fields = ['id']
def get_services_display(self, obj):
"""Return list of service names."""
return [service.name_en for service in obj.services.all()]
class PayerSerializer(serializers.ModelSerializer):
"""Serializer for Payer model."""
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
type_display = serializers.CharField(source='get_type_display', read_only=True)
class Meta:
model = Payer
fields = [
'id', 'patient', 'patient_name', 'name',
'type', 'type_display', 'policy_number',
'coverage_percentage', 'is_active'
]
read_only_fields = ['id']
class InvoiceLineItemSerializer(serializers.ModelSerializer):
"""Serializer for InvoiceLineItem model."""
service_name = serializers.CharField(source='service.name_en', read_only=True)
package_name = serializers.CharField(source='package.name_en', read_only=True)
class Meta:
model = InvoiceLineItem
fields = [
'id', 'service', 'service_name', 'package', 'package_name',
'description', 'quantity', 'unit_price', 'total'
]
read_only_fields = ['id', 'total']
def validate(self, data):
"""Calculate total."""
quantity = data.get('quantity', 1)
unit_price = data.get('unit_price', 0)
data['total'] = quantity * unit_price
return data
class InvoiceListSerializer(serializers.ModelSerializer):
"""Lightweight serializer for invoice lists."""
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
status_display = serializers.CharField(source='get_status_display', read_only=True)
class Meta:
model = Invoice
fields = [
'id', 'invoice_number', 'patient', 'patient_name',
'issue_date', 'due_date', 'total',
'status', 'status_display'
]
read_only_fields = ['id', 'invoice_number']
class InvoiceDetailSerializer(serializers.ModelSerializer):
"""Detailed serializer for invoice detail views."""
patient = PatientListSerializer(read_only=True)
line_items = InvoiceLineItemSerializer(many=True, read_only=True)
status_display = serializers.CharField(source='get_status_display', read_only=True)
amount_paid = serializers.SerializerMethodField()
amount_due = serializers.SerializerMethodField()
class Meta:
model = Invoice
fields = [
'id', 'invoice_number', 'patient', 'appointment',
'issue_date', 'due_date',
'subtotal', 'tax', 'discount', 'total',
'status', 'status_display',
'amount_paid', 'amount_due',
'line_items', 'notes',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'invoice_number', 'created_at', 'updated_at']
def get_amount_paid(self, obj):
"""Calculate total amount paid."""
return sum(payment.amount for payment in obj.payments.filter(status='COMPLETED'))
def get_amount_due(self, obj):
"""Calculate amount due."""
amount_paid = self.get_amount_paid(obj)
return obj.total - amount_paid
class InvoiceCreateSerializer(serializers.ModelSerializer):
"""Serializer for creating invoices."""
line_items = InvoiceLineItemSerializer(many=True)
class Meta:
model = Invoice
fields = [
'patient', 'appointment', 'issue_date', 'due_date',
'subtotal', 'tax', 'discount', 'notes', 'line_items'
]
def create(self, validated_data):
"""Create invoice with line items."""
line_items_data = validated_data.pop('line_items')
# Calculate total
subtotal = validated_data.get('subtotal', 0)
tax = validated_data.get('tax', 0)
discount = validated_data.get('discount', 0)
total = subtotal + tax - discount
validated_data['total'] = total
validated_data['status'] = 'DRAFT'
invoice = Invoice.objects.create(**validated_data)
# Create line items
for item_data in line_items_data:
InvoiceLineItem.objects.create(invoice=invoice, **item_data)
return invoice
class PaymentSerializer(serializers.ModelSerializer):
"""Serializer for Payment model."""
invoice_number = serializers.CharField(source='invoice.invoice_number', read_only=True)
patient_name = serializers.CharField(source='invoice.patient.get_full_name', read_only=True)
method_display = serializers.CharField(source='get_method_display', read_only=True)
status_display = serializers.CharField(source='get_status_display', read_only=True)
processed_by_name = serializers.CharField(source='processed_by.get_full_name', read_only=True)
class Meta:
model = Payment
fields = [
'id', 'invoice', 'invoice_number', 'patient_name',
'payment_date', 'amount',
'method', 'method_display',
'transaction_id', 'reference',
'status', 'status_display',
'processed_by', 'processed_by_name',
'created_at'
]
read_only_fields = ['id', 'created_at']
class PackagePurchaseSerializer(serializers.ModelSerializer):
"""Serializer for PackagePurchase model."""
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
package_name = serializers.CharField(source='package.name_en', read_only=True)
invoice_number = serializers.CharField(source='invoice.invoice_number', read_only=True)
class Meta:
model = PackagePurchase
fields = [
'id', 'patient', 'patient_name',
'package', 'package_name',
'invoice', 'invoice_number',
'purchase_date', 'expiry_date',
'total_sessions', 'used_sessions', 'remaining_sessions',
'is_active'
]
read_only_fields = ['id', 'remaining_sessions']