import os import math from django.conf import settings from rest_framework import serializers from django.utils import timezone from datetime import datetime from module_iam.models import IAmPrincipal from ..models import ( PrincipalHealthData, Intolerance, Symptoms, PastTreatment, ChronicCondition, Medicine, Medication, Bowel, SymptomTypeAfterMeal, SymptomTypeBeforeMeal, MealSymptomRecord, FoodIngredientRecord, FoodRecord, BeverageRecord, MealRecord, ) class IAmPrincipalSerializer(serializers.ModelSerializer): class Meta: model = IAmPrincipal fields = [ "profile_photo", "first_name", "date_of_birth", "gender", "phone_no", ] class PrincipalHealthDataSerializer(serializers.ModelSerializer): class Meta: model = PrincipalHealthData fields = [ "ethenicity", "weight", "height", "gastrointestinal_health", "exercise_frequency", "sleep_duration", "eat_frequency", ] class PrincipalAndHealthSerializer(serializers.ModelSerializer): ethenicity = serializers.CharField(read_only=True) weight = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True) height = serializers.DecimalField(max_digits=6, decimal_places=2, read_only=True) gastrointestinal_health = serializers.CharField(read_only=True) exercise_frequency = serializers.CharField(read_only=True) sleep_duration = serializers.CharField(read_only=True) eat_frequency = serializers.CharField(read_only=True) profile_complete = serializers.IntegerField(read_only=True) class Meta: model = IAmPrincipal fields = [ "profile_photo", "first_name", "email", "date_of_birth", "gender", "phone_no", # "phone_verified", # "email_verified", "ethenicity", "weight", "height", "gastrointestinal_health", "exercise_frequency", "sleep_duration", "eat_frequency", "profile_complete" ] def calculate_profile_completion(self, user): """ Calculates the profile completion percentage for a user based on the required fields. """ fields = self.fields try: # Retrieve the user profile from the database profile = IAmPrincipal.objects.get(id=user) try: # Retrieve the user's health data from the database health_data = PrincipalHealthData.objects.get(principal=profile) except PrincipalHealthData.DoesNotExist: # If health data doesn't exist, set health_data to None health_data = None # Initialize a counter for completed fields completed_fields = sum( 1 for field in fields if ( # If the field is in the user profile and the field value is not None, not an empty string, and not an instance of datetime.date (field in vars(profile) and vars(profile).get(field, '') and vars(profile).get(field) != datetime.date) or # If health data exists, the field is in the user's health data, and the field value is not None, not an empty string, and not an instance of datetime.date (health_data and field in vars(health_data) and vars(health_data).get(field, '') and vars(health_data).get(field) != datetime.date) ) ) except IAmPrincipal.DoesNotExist: # If the user profile doesn't exist, return 0 return 0 # Calculate the total number of fields total_fields = len(fields) - 1 # Exclude profile_complete field # Calculate the profile completion percentage completion_percentage = math.floor((completed_fields / total_fields) * 100) # Return the profile completion percentage return completion_percentage def get_image_url(self, obj, field_name, request): image_field = getattr(obj, field_name) if image_field: return request.build_absolute_uri(image_field.url) else: # Return the URL of the default image from the static path default_image_path = os.path.join( settings.STATIC_URL, "img/default_profile.jpg" ) return request.build_absolute_uri(default_image_path) def to_representation(self, instance): data = super().to_representation(instance) request = self.context.get("request") data["profile_photo"] = self.get_image_url(instance, "profile_photo", request) data["profile_complete"] = self.calculate_profile_completion(request.user.id) if ( hasattr(instance, "health_data_principal") and instance.health_data_principal ): health_data = instance.health_data_principal data["ethenicity"] = health_data.ethenicity data["weight"] = health_data.weight data["height"] = health_data.height data["gastrointestinal_health"] = health_data.gastrointestinal_health data["exercise_frequency"] = health_data.exercise_frequency data["sleep_duration"] = health_data.sleep_duration data["eat_frequency"] = health_data.eat_frequency else: # If health_data_principal doesn't exist or is empty, set empty strings for all attributes data["ethenicity"] = "" data["weight"] = 0.00 data["height"] = 0.00 data["gastrointestinal_health"] = "" data["exercise_frequency"] = "" data["sleep_duration"] = "" data["eat_frequency"] = "" return data class IntoleranceSerializer(serializers.ModelSerializer): class Meta: model = Intolerance fields = ["id", "name", "duration"] class SymptomsSerializer(serializers.ModelSerializer): class Meta: model = Symptoms fields = ["id", "name", "duration"] class PastTreatmentSerializer(serializers.ModelSerializer): class Meta: model = PastTreatment fields = ["id", "name", "duration"] class ChronicConditionSerializer(serializers.ModelSerializer): class Meta: model = ChronicCondition fields = ["id", "name", "duration"] class FoodIngredientRecordSerializer(serializers.ModelSerializer): class Meta: model = FoodIngredientRecord fields = ["name"] class FoodRecordSerializer(serializers.ModelSerializer): class Meta: model = FoodRecord fields = ["name", "quantity"] class BeverageRecordSerializer(serializers.ModelSerializer): class Meta: model = BeverageRecord fields = [ "beverage_type", "glass_type", "glass_count", "quantity", "quantity_measure", ] class MealRecordSerializer(serializers.ModelSerializer): food_records = FoodRecordSerializer(many=True) beverage_records = BeverageRecordSerializer(many=True) food_ingredient_records = FoodIngredientRecordSerializer(many=True) class Meta: model = MealRecord fields = [ "id", "date", "time", "meal_type", "food_records", "food_ingredient_records", "beverage_records", ] def create(self, validated_data): food_record_data = validated_data.pop("food_records", []) beverage_record_data = validated_data.pop("beverage_records", []) food_ingredient_record_data = validated_data.pop("food_ingredient_records", []) meal_record = self.Meta.model.objects.create(**validated_data) food_record_list = [] for data in food_record_data: obj, _ = FoodRecord.objects.get_or_create(**data) food_record_list.append(obj) food_ingredient_list = [] for data in food_ingredient_record_data: obj, _ = FoodIngredientRecord.objects.get_or_create(**data) food_ingredient_list.append(obj) beverage_record_list = [] for data in beverage_record_data: obj, _ = BeverageRecord.objects.get_or_create(**data) beverage_record_list.append(obj) meal_record.food_records.set(food_record_list) meal_record.food_ingredient_records.set(food_ingredient_list) meal_record.beverage_records.set(beverage_record_list) return meal_record def update(self, instance, validated_data): instance.date = validated_data.get("date", instance.date) instance.time = validated_data.get("time", instance.time) instance.meal_type = validated_data.get("meal_type", instance.meal_type) instance.save() food_record_data = validated_data.pop("food_records", []) beverage_record_data = validated_data.pop("beverage_records", []) food_ingredient_record_data = validated_data.pop("food_ingredient_records", []) food_record_list = [] for data in food_record_data: obj, _ = FoodRecord.objects.get_or_create(**data) food_record_list.append(obj) food_ingredient_list = [] for data in food_ingredient_record_data: obj, _ = FoodIngredientRecord.objects.get_or_create(**data) food_ingredient_list.append(obj) beverage_record_list = [] for data in beverage_record_data: obj, _ = BeverageRecord.objects.get_or_create(**data) beverage_record_list.append(obj) instance.food_records.set(food_record_list) instance.food_ingredient_records.set(food_ingredient_list) instance.beverage_records.set(beverage_record_list) instance.save() return instance class MedicineSerializer(serializers.ModelSerializer): class Meta: model = Medicine fields = ["name", "quantity", "type"] class MedicationSerializer(serializers.ModelSerializer): medicines = MedicineSerializer(many=True) class Meta: model = Medication fields = ["id", "date", "time", "medicines"] def create(self, validated_data): medicines_data = validated_data.pop("medicines") medication = self.Meta.model.objects.create(**validated_data) for medicine_data in medicines_data: medicine = Medicine.objects.create(**medicine_data) medication.medicines.add(medicine) return medication def update(self, instance, validated_data): instance.date = validated_data.get("date", instance.date) instance.time = validated_data.get("time", instance.time) instance.save() medicines_data = validated_data.get("medicines", []) instance.medicines.clear() for medicine_data in medicines_data: medicine = Medicine.objects.create(**medicine_data) instance.medicines.add(medicine) return instance class BowelSerializer(serializers.ModelSerializer): class Meta: model = Bowel fields = [ "id", "date", "time", "stool_type", "stool_name", "duration", "completeness_of_evacuation", "urgency", "smellness", "pain_level", "volume", "color", "excessive_flatulence", ] class SymptomTypeBeforeMealSerializer(serializers.ModelSerializer): class Meta: model = SymptomTypeBeforeMeal fields = ["name"] class SymptomTypeAfterMealSerializer(serializers.ModelSerializer): class Meta: model = SymptomTypeAfterMeal fields = ["name"] class MealSymptomRecordSerializer(serializers.ModelSerializer): symptoms_before_meal = SymptomTypeBeforeMealSerializer(many=True) symptoms_after_meal = SymptomTypeAfterMealSerializer(many=True) class Meta: model = MealSymptomRecord fields = [ "id", "date", "time", "symptoms_description", "interval", "symptoms_before_meal", "symptoms_after_meal", ] def create(self, validated_data): before_meal_data = validated_data.pop("symptoms_before_meal") after_meal_data = validated_data.pop("symptoms_after_meal") meal_symptom_record = MealSymptomRecord.objects.create(**validated_data) before_meal_list = [] for data in before_meal_data: obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data) before_meal_list.append(obj) after_meal_list = [] for data in after_meal_data: obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data) after_meal_list.append(obj) meal_symptom_record.symptoms_before_meal.set(before_meal_list) meal_symptom_record.symptoms_after_meal.set(after_meal_list) return meal_symptom_record def update(self, instance, validated_data): instance.date = validated_data.get("date", instance.date) instance.time = validated_data.get("time", instance.time) instance.symptoms_description = validated_data.get( "symptoms_description", instance.symptoms_description ) instance.interval = validated_data.get("interval", instance.interval) before_meal_data = validated_data.pop("symptoms_before_meal", []) after_meal_data = validated_data.pop("symptoms_after_meal", []) before_meal_instances = [] for data in before_meal_data: obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data) before_meal_instances.append(obj) after_meal_instances = [] for data in after_meal_data: obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data) after_meal_instances.append(obj) instance.symptoms_before_meal.set(before_meal_instances) instance.symptoms_after_meal.set(after_meal_instances) instance.save() return instance