""" Accounts serializers """ from django.contrib.auth import get_user_model from rest_framework import serializers from .models import ( AcknowledgementCategory, AcknowledgementChecklistItem, AcknowledgementContent, Role, UserAcknowledgement, ) User = get_user_model() class UserSerializer(serializers.ModelSerializer): """User serializer""" roles = serializers.SerializerMethodField() hospital_name = serializers.CharField(source="hospital.name", read_only=True) department_name = serializers.CharField(source="department.name", read_only=True) class Meta: model = User fields = [ "id", "username", "email", "first_name", "last_name", "phone", "employee_id", "hospital", "hospital_name", "department", "department_name", "avatar", "bio", "language", "is_active", "roles", "date_joined", "created_at", "updated_at", ] read_only_fields = ["id", "date_joined", "created_at", "updated_at"] def get_roles(self, obj): """Get user roles""" return obj.get_role_names() class UserCreateSerializer(serializers.ModelSerializer): """User creation serializer with password""" password = serializers.CharField(write_only=True, required=True, style={"input_type": "password"}) password_confirm = serializers.CharField(write_only=True, required=True, style={"input_type": "password"}) class Meta: model = User fields = [ "username", "email", "password", "password_confirm", "first_name", "last_name", "phone", "employee_id", "hospital", "department", "language", ] def validate(self, attrs): """Validate passwords match""" if attrs["password"] != attrs["password_confirm"]: raise serializers.ValidationError({"password": "Passwords do not match."}) return attrs def create(self, validated_data): """Create user with hashed password""" validated_data.pop("password_confirm") password = validated_data.pop("password") user = User.objects.create(**validated_data) user.set_password(password) user.save() return user class UserUpdateSerializer(serializers.ModelSerializer): """User update serializer (without password)""" class Meta: model = User fields = [ "first_name", "last_name", "phone", "employee_id", "hospital", "department", "avatar", "bio", "language", "is_active", ] class ChangePasswordSerializer(serializers.Serializer): """Change password serializer""" old_password = serializers.CharField(required=True, write_only=True) new_password = serializers.CharField(required=True, write_only=True) new_password_confirm = serializers.CharField(required=True, write_only=True) def validate(self, attrs): """Validate passwords""" if attrs["new_password"] != attrs["new_password_confirm"]: raise serializers.ValidationError({"new_password": "Passwords do not match."}) return attrs def validate_old_password(self, value): """Validate old password""" user = self.context["request"].user if not user.check_password(value): raise serializers.ValidationError("Old password is incorrect.") return value class RoleSerializer(serializers.ModelSerializer): """Role serializer""" group_name = serializers.CharField(source="group.name", read_only=True) class Meta: model = Role fields = [ "id", "name", "display_name", "description", "group", "group_name", "level", "permissions", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] # ==================== Onboarding Serializers ==================== class ProvisionalUserSerializer(serializers.ModelSerializer): """Serializer for creating provisional users""" roles = serializers.ListField( child=serializers.CharField(), write_only=True, required=False, default=list, help_text="List of role names to assign", ) class Meta: model = User fields = [ "email", "first_name", "last_name", "phone", "employee_id", "hospital", "department", "language", "roles", ] def create(self, validated_data): """Create provisional user""" roles = validated_data.pop("roles", []) user = User(**validated_data) user.is_provisional = True user.set_unusable_password() user.save() # Assign roles for role_name in roles: from .models import Role as RoleModel try: role = RoleModel.objects.get(name=role_name) user.groups.add(role.group) except RoleModel.DoesNotExist: pass return user class AcknowledgementCategorySerializer(serializers.ModelSerializer): item_count = serializers.SerializerMethodField() class Meta: model = AcknowledgementCategory fields = [ "id", "name_en", "name_ar", "code", "description", "icon", "color", "order", "is_active", "is_default", "item_count", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] def get_item_count(self, obj): return obj.checklist_items.filter(is_active=True).count() class AcknowledgementContentSerializer(serializers.ModelSerializer): category_name_en = serializers.CharField(source="category.name_en", read_only=True) category_name_ar = serializers.CharField(source="category.name_ar", read_only=True) class Meta: model = AcknowledgementContent fields = [ "id", "category", "category_name_en", "category_name_ar", "code", "title_en", "title_ar", "description_en", "description_ar", "content_en", "content_ar", "icon", "color", "order", "is_active", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] class AcknowledgementChecklistItemSerializer(serializers.ModelSerializer): category_name_en = serializers.CharField(source="category.name_en", read_only=True) category_name_ar = serializers.CharField(source="category.name_ar", read_only=True) content_title_en = serializers.CharField(source="content.title_en", read_only=True) content_title_ar = serializers.CharField(source="content.title_ar", read_only=True) class Meta: model = AcknowledgementChecklistItem fields = [ "id", "category", "category_name_en", "category_name_ar", "content", "content_title_en", "content_title_ar", "code", "text_en", "text_ar", "description_en", "description_ar", "is_required", "order", "is_active", "created_at", "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] class UserAcknowledgementSerializer(serializers.ModelSerializer): """Serializer for user acknowledgements""" user_email = serializers.CharField(source="user.email", read_only=True) user_name = serializers.CharField(source="user.get_full_name", read_only=True) checklist_item_text_en = serializers.CharField(source="checklist_item.text_en", read_only=True) checklist_item_text_ar = serializers.CharField(source="checklist_item.text_ar", read_only=True) checklist_item_code = serializers.CharField(source="checklist_item.code", read_only=True) pdf_download_url = serializers.SerializerMethodField() class Meta: model = UserAcknowledgement fields = [ "id", "user", "user_email", "user_name", "checklist_item", "checklist_item_text_en", "checklist_item_text_ar", "checklist_item_code", "is_acknowledged", "acknowledged_at", "signature", "signature_ip", "signature_user_agent", "pdf_file", "pdf_download_url", "metadata", "created_at", "updated_at", ] read_only_fields = ["id", "user", "acknowledged_at", "pdf_file", "created_at", "updated_at"] def get_pdf_download_url(self, obj): """Get PDF download URL if available""" if obj.pdf_file: request = self.context.get("request") if request: return request.build_absolute_uri(f"/api/accounts/user-acknowledgements/{obj.id}/download_pdf/") return None class WizardProgressSerializer(serializers.Serializer): """Serializer for wizard progress""" current_step = serializers.IntegerField() completed_steps = serializers.ListField(child=serializers.IntegerField()) progress_percentage = serializers.FloatField() total_required_items = serializers.IntegerField() acknowledged_items = serializers.IntegerField() class AcknowledgeItemSerializer(serializers.Serializer): """Serializer for acknowledging checklist items""" checklist_item_id = serializers.UUIDField(required=True) signature = serializers.CharField(required=False, allow_blank=True) class AccountActivationSerializer(serializers.Serializer): """Serializer for account activation""" username = serializers.CharField(required=True, min_length=3, max_length=150, help_text="Desired username") password = serializers.CharField(required=True, min_length=8, write_only=True, style={"input_type": "password"}) password_confirm = serializers.CharField(required=True, write_only=True, style={"input_type": "password"}) signature = serializers.CharField(required=True, help_text="Digital signature data (base64 encoded)") def validate(self, attrs): """Validate passwords match""" if attrs["password"] != attrs["password_confirm"]: raise serializers.ValidationError({"password": "Passwords do not match."}) # Check if username is available if User.objects.filter(username=attrs["username"]).exists(): raise serializers.ValidationError({"username": "Username already taken."}) return attrs class ResendInvitationSerializer(serializers.Serializer): """Serializer for resending invitation""" user_id = serializers.UUIDField(required=True)