from rest_framework import serializers from django.contrib.auth import get_user_model from django.contrib.auth.password_validation import validate_password from django.utils import timezone from .models import Product, Transaction, Budget, Ad, Notification, SupportTicket User = get_user_model() class UserSerializer(serializers.ModelSerializer): """Serializer pour le profil utilisateur""" class Meta: model = User fields = [ 'id', 'email', 'first_name', 'last_name', 'phone_number', 'avatar', 'account_type', 'is_premium', 'initial_balance', 'business_name', 'sector', 'location', 'ifu', 'business_logo', 'currency', 'language', 'dark_mode', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] class RegisterSerializer(serializers.ModelSerializer): """Serializer pour l'inscription""" password = serializers.CharField( write_only=True, required=True, validators=[validate_password] ) password2 = serializers.CharField(write_only=True, required=True) agreed = serializers.BooleanField(write_only=True, required=True) businessAgreed = serializers.BooleanField(write_only=True, required=False) class Meta: model = User fields = [ 'email', 'password', 'password2', 'first_name', 'last_name', 'phone_number', 'account_type', 'business_name', 'sector', 'location', 'ifu', 'agreed', 'businessAgreed' ] def validate(self, attrs): if attrs['password'] != attrs['password2']: raise serializers.ValidationError({ "password": "Les mots de passe ne correspondent pas." }) # Validation IFU pour les comptes business if attrs.get('account_type') == 'business': if not attrs.get('ifu'): raise serializers.ValidationError({ "ifu": "Ce champ est obligatoire pour les comptes professionnels." }) if not attrs.get('businessAgreed'): raise serializers.ValidationError({ "businessAgreed": "Vous devez accepter les conditions professionnelles." }) if not attrs.get('agreed'): raise serializers.ValidationError({ "agreed": "Vous devez accepter les conditions générales." }) return attrs def create(self, validated_data): validated_data.pop('password2') validated_data.pop('agreed') business_agreed = validated_data.pop('businessAgreed', False) password = validated_data.pop('password') user = User.objects.create_user(password=password, **validated_data) user.agreed_terms = True if business_agreed: user.business_agreed = True user.business_agreed_at = timezone.now() user.save() return user class ChangePasswordSerializer(serializers.Serializer): """Serializer pour le changement de mot de passe""" old_password = serializers.CharField(required=True) new_password = serializers.CharField( required=True, validators=[validate_password] ) new_password2 = serializers.CharField(required=True) def validate(self, attrs): if attrs['new_password'] != attrs['new_password2']: raise serializers.ValidationError({ "new_password": "Les mots de passe ne correspondent pas." }) return attrs class ProductSerializer(serializers.ModelSerializer): """Serializer pour les produits""" class Meta: model = Product fields = [ 'id', 'name', 'description', 'price', 'unit', 'image', 'category', 'stock_status', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def create(self, validated_data): validated_data['user'] = self.context['request'].user return super().create(validated_data) class TransactionSerializer(serializers.ModelSerializer): """Serializer pour les transactions""" class Meta: model = Transaction fields = [ 'id', 'name', 'amount', 'type', 'category', 'date', 'currency', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def create(self, validated_data): validated_data['user'] = self.context['request'].user return super().create(validated_data) class TransactionSummarySerializer(serializers.Serializer): """Serializer pour le résumé des transactions (dashboard)""" balance = serializers.DecimalField(max_digits=15, decimal_places=2) income_24h = serializers.DecimalField(max_digits=15, decimal_places=2) expenses_24h = serializers.DecimalField(max_digits=15, decimal_places=2) income_variation = serializers.FloatField() expenses_variation = serializers.FloatField() class BudgetSerializer(serializers.ModelSerializer): """Serializer pour les budgets""" spent_amount = serializers.SerializerMethodField() percentage = serializers.SerializerMethodField() class Meta: model = Budget fields = [ 'id', 'category', 'limit', 'color', 'spent_amount', 'percentage', 'created_at', 'updated_at' ] read_only_fields = ['id', 'spent_amount', 'percentage', 'created_at', 'updated_at'] def get_spent_amount(self, obj): return obj.get_spent_amount() def get_percentage(self, obj): spent = obj.get_spent_amount() if obj.limit > 0: return float((spent / obj.limit) * 100) return 0.0 def create(self, validated_data): validated_data['user'] = self.context['request'].user return super().create(validated_data) class AdSerializer(serializers.ModelSerializer): """Serializer pour les annonces""" class Meta: model = Ad fields = [ 'id', 'product_name', 'owner_name', 'description', 'image', 'whatsapp', 'website', 'location', 'is_verified', 'created_at', 'updated_at' ] read_only_fields = ['id', 'is_verified', 'created_at', 'updated_at'] def create(self, validated_data): validated_data['user'] = self.context['request'].user return super().create(validated_data) class OverviewAnalyticsSerializer(serializers.Serializer): """Serializer pour les analytics overview (graphique barres)""" month = serializers.CharField() income = serializers.DecimalField(max_digits=15, decimal_places=2) expenses = serializers.DecimalField(max_digits=15, decimal_places=2) class BreakdownAnalyticsSerializer(serializers.Serializer): """Serializer pour le breakdown des dépenses (camembert)""" category = serializers.CharField() amount = serializers.DecimalField(max_digits=15, decimal_places=2) percentage = serializers.FloatField() class KPISerializer(serializers.Serializer): """Serializer pour les KPIs""" average_basket = serializers.DecimalField(max_digits=15, decimal_places=2) average_basket_growth = serializers.FloatField(default=0.0) estimated_mrr = serializers.DecimalField(max_digits=15, decimal_places=2) estimated_mrr_growth = serializers.FloatField(default=0.0) cac = serializers.DecimalField(max_digits=15, decimal_places=2) cac_growth = serializers.FloatField(default=0.0) class ActivityAnalyticsSerializer(serializers.Serializer): """Serializer pour l'activité hebdomadaire""" day = serializers.CharField() sales = serializers.DecimalField(max_digits=15, decimal_places=2) class BalanceHistorySerializer(serializers.Serializer): """Serializer pour l'historique du solde""" date = serializers.CharField() balance = serializers.DecimalField(max_digits=15, decimal_places=2) class NotificationSerializer(serializers.ModelSerializer): """Serializer pour les notifications""" class Meta: model = Notification fields = ['id', 'type', 'title', 'message', 'is_read', 'created_at'] read_only_fields = ['id', 'created_at'] class SupportTicketSerializer(serializers.ModelSerializer): """Serializer pour les tickets support""" class Meta: model = SupportTicket fields = ['id', 'subject', 'message', 'status', 'created_at', 'updated_at'] read_only_fields = ['id', 'status', 'created_at', 'updated_at'] def create(self, validated_data): validated_data['user'] = self.context['request'].user return super().create(validated_data)