from rest_framework import serializers from django.db import transaction from .models import ( Device, DeviceSerial, DeviceIP, MaintenanceRecord, DeviceAttachment ) from loguru import logger class DeviceSerialSerializer(serializers.ModelSerializer): class Meta: model = DeviceSerial fields = ['id', 'serial_number', 'serial_type', 'is_primary', 'remark'] class DeviceIPSerializer(serializers.ModelSerializer): class Meta: model = DeviceIP fields = ['id', 'ip_address', 'ip_type', 'is_primary', 'subnet_mask', 'gateway', 'vlan_id'] class MaintenanceRecordSerializer(serializers.ModelSerializer): class Meta: model = MaintenanceRecord fields = ['id', 'maintenance_date', 'fault_description', 'repair_content', 'replaced_parts', 'maintenance_by', 'cost', 'remark'] class DeviceAttachmentSerializer(serializers.ModelSerializer): class Meta: model = DeviceAttachment fields = ['id', 'file', 'file_name', 'file_type', 'uploaded_at'] read_only_fields = ['uploaded_at'] class DeviceSerializer(serializers.ModelSerializer): serials = DeviceSerialSerializer(many=True, required=False) ips = DeviceIPSerializer(many=True, required=False) maintenance_records = MaintenanceRecordSerializer(many=True, read_only=True) attachments = DeviceAttachmentSerializer(many=True, read_only=True) service_duration_days = serializers.IntegerField(read_only=True) is_warranty_expired = serializers.BooleanField(read_only=True) primary_serial = serializers.SerializerMethodField() primary_ip = serializers.SerializerMethodField() latest_maintenance = serializers.SerializerMethodField() class Meta: model = Device fields = ['id', 'location', 'building', 'floor', 'cabinet', 'device_name', 'model', 'brand', 'mac_address', 'enable_date', 'last_inspection_date', 'thumbnail', 'status', 'responsible_person', 'warranty_expire', 'service_duration_days', 'is_warranty_expired', 'primary_serial', 'primary_ip', 'latest_maintenance', 'serials', 'ips', 'maintenance_records', 'attachments', 'created_at', 'updated_at'] read_only_fields = ['created_at', 'updated_at'] def get_primary_serial(self, obj): primary = obj.serials.filter(is_primary=True).first() if primary: return DeviceSerialSerializer(primary).data return None def get_primary_ip(self, obj): primary = obj.ips.filter(is_primary=True).first() if primary: return DeviceIPSerializer(primary).data return None def get_latest_maintenance(self, obj): latest = obj.maintenance_records.first() if latest: return MaintenanceRecordSerializer(latest).data return None @transaction.atomic def create(self, validated_data): serials_data = validated_data.pop('serials', []) ips_data = validated_data.pop('ips', []) device = Device.objects.create(**validated_data) for serial_data in serials_data: DeviceSerial.objects.create(device=device, **serial_data) for ip_data in ips_data: DeviceIP.objects.create(device=device, **ip_data) logger.info(f'Created device: {device.id} - {device.device_name}') return device @transaction.atomic def update(self, instance, validated_data): serials_data = validated_data.pop('serials', None) ips_data = validated_data.pop('ips', None) for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() if serials_data is not None: instance.serials.all().delete() for serial_data in serials_data: DeviceSerial.objects.create(device=instance, **serial_data) if ips_data is not None: instance.ips.all().delete() for ip_data in ips_data: DeviceIP.objects.create(device=instance, **ip_data) logger.info(f'Updated device: {instance.id}') return instance class DeviceListSerializer(serializers.ModelSerializer): primary_serial_number = serializers.SerializerMethodField() primary_ip_address = serializers.SerializerMethodField() latest_maintenance_summary = serializers.SerializerMethodField() service_duration_days = serializers.IntegerField(read_only=True) class Meta: model = Device fields = ['id', 'location', 'building', 'device_name', 'model', 'brand', 'status', 'responsible_person', 'enable_date', 'thumbnail', 'primary_serial_number', 'primary_ip_address', 'latest_maintenance_summary', 'service_duration_days'] def get_primary_serial_number(self, obj): primary = obj.serials.filter(is_primary=True).first() return primary.serial_number if primary else None def get_primary_ip_address(self, obj): primary = obj.ips.filter(is_primary=True).first() return primary.ip_address if primary else None def get_latest_maintenance_summary(self, obj): latest = obj.maintenance_records.first() if latest: return f"{latest.maintenance_date}: {latest.fault_description[:50]}..." if latest.fault_description else str(latest.maintenance_date) return None