from django.http.response import JsonResponse from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect from django.utils.decorators import method_decorator from rest_framework.parsers import JSONParser from rest_framework.views import APIView from rest_framework import status from .models import ( Teacher, Speciality, SchoolClass, Planning, Discount, Fee, PaymentPlan, PaymentMode, Domain, Category, Competency, EstablishmentCompetency ) from .serializers import ( TeacherSerializer, SpecialitySerializer, SchoolClassSerializer, PlanningSerializer, DiscountSerializer, FeeSerializer, PaymentPlanSerializer, PaymentModeSerializer, DomainSerializer, CategorySerializer, CompetencySerializer, EstablishmentCompetencySerializer ) from N3wtSchool.bdd import delete_object, getAllObjects, getObject from django.db.models import Q from collections import defaultdict @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class SpecialityListCreateView(APIView): def get(self, request): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) specialities_list = getAllObjects(Speciality) if establishment_id: specialities_list = specialities_list.filter(establishment__id=establishment_id).distinct() specialities_serializer = SpecialitySerializer(specialities_list, many=True) return JsonResponse(specialities_serializer.data, safe=False) def post(self, request): speciality_data=JSONParser().parse(request) speciality_serializer = SpecialitySerializer(data=speciality_data) if speciality_serializer.is_valid(): speciality_serializer.save() return JsonResponse(speciality_serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(speciality_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class SpecialityDetailView(APIView): def get(self, request, id): speciality = getObject(_objectName=Speciality, _columnName='id', _value=id) speciality_serializer=SpecialitySerializer(speciality) return JsonResponse(speciality_serializer.data, safe=False) def put(self, request, id): speciality_data=JSONParser().parse(request) speciality = getObject(_objectName=Speciality, _columnName='id', _value=id) speciality_serializer = SpecialitySerializer(speciality, data=speciality_data) if speciality_serializer.is_valid(): speciality_serializer.save() return JsonResponse(speciality_serializer.data, safe=False) return JsonResponse(speciality_serializer.errors, safe=False) def delete(self, request, id): return delete_object(Speciality, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class TeacherListCreateView(APIView): def get(self, request): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) teachers_list = getAllObjects(Teacher) if teachers_list: teachers_list = teachers_list.filter(profile_role__establishment_id=establishment_id) teachers_serializer = TeacherSerializer(teachers_list, many=True) return JsonResponse(teachers_serializer.data, safe=False) def post(self, request): teacher_data=JSONParser().parse(request) teacher_serializer = TeacherSerializer(data=teacher_data) if teacher_serializer.is_valid(): teacher_serializer.save() return JsonResponse(teacher_serializer.data, safe=False) return JsonResponse(teacher_serializer.errors, safe=False) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class TeacherDetailView(APIView): def get (self, request, id): teacher = getObject(_objectName=Teacher, _columnName='id', _value=id) teacher_serializer=TeacherSerializer(teacher) return JsonResponse(teacher_serializer.data, safe=False) def put(self, request, id): teacher_data=JSONParser().parse(request) teacher = getObject(_objectName=Teacher, _columnName='id', _value=id) teacher_serializer = TeacherSerializer(teacher, data=teacher_data) if teacher_serializer.is_valid(): teacher_serializer.save() return JsonResponse(teacher_serializer.data, safe=False) return JsonResponse(teacher_serializer.errors, safe=False) def delete(self, request, id): return delete_object(Teacher, id, related_field='profile_role') @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class SchoolClassListCreateView(APIView): def get(self, request): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) school_classes_list = getAllObjects(SchoolClass) if school_classes_list: school_classes_list = school_classes_list.filter(establishment=establishment_id).distinct() classes_serializer = SchoolClassSerializer(school_classes_list, many=True) return JsonResponse(classes_serializer.data, safe=False) def post(self, request): classe_data=JSONParser().parse(request) classe_serializer = SchoolClassSerializer(data=classe_data) if classe_serializer.is_valid(): classe_serializer.save() return JsonResponse(classe_serializer.data, safe=False) return JsonResponse(classe_serializer.errors, safe=False) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class SchoolClassDetailView(APIView): def get (self, request, id): schoolClass = getObject(_objectName=SchoolClass, _columnName='id', _value=id) classe_serializer=SchoolClassSerializer(schoolClass) return JsonResponse(classe_serializer.data, safe=False) def put(self, request, id): classe_data=JSONParser().parse(request) schoolClass = getObject(_objectName=SchoolClass, _columnName='id', _value=id) classe_serializer = SchoolClassSerializer(schoolClass, data=classe_data) if classe_serializer.is_valid(): classe_serializer.save() return JsonResponse(classe_serializer.data, safe=False) return JsonResponse(classe_serializer.errors, safe=False) def delete(self, request, id): return delete_object(SchoolClass, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PlanningListCreateView(APIView): def get(self, request): schedulesList=getAllObjects(Planning) schedules_serializer=PlanningSerializer(schedulesList, many=True) return JsonResponse(schedules_serializer.data, safe=False) def post(self, request): planning_data=JSONParser().parse(request) planning_serializer = PlanningSerializer(data=planning_data) if planning_serializer.is_valid(): planning_serializer.save() return JsonResponse(planning_serializer.data, safe=False) return JsonResponse(planning_serializer.errors, safe=False) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PlanningDetailView(APIView): def get (self, request, id): planning = getObject(_objectName=Planning, _columnName='classe_id', _value=id) planning_serializer=PlanningSerializer(planning) return JsonResponse(planning_serializer.data, safe=False) def put(self, request, id): planning_data = JSONParser().parse(request) try: planning = Planning.objects.get(id=id) except Planning.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) except Planning.MultipleObjectsReturned: return JsonResponse({'error': 'Multiple objects found'}, status=status.HTTP_400_BAD_REQUEST) planning_serializer = PlanningSerializer(planning, data=planning_data) if planning_serializer.is_valid(): planning_serializer.save() return JsonResponse(planning_serializer.data, safe=False) return JsonResponse(planning_serializer.errors, safe=False) def delete(self, request, id): return delete_object(Planning, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class FeeListCreateView(APIView): def get(self, request, *args, **kwargs): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) filter = request.GET.get('filter', '').strip() fee_type_value = 0 if filter == 'registration' else 1 fees = Fee.objects.filter(type=fee_type_value, establishment_id=establishment_id).distinct() fee_serializer = FeeSerializer(fees, many=True) return JsonResponse(fee_serializer.data, safe=False, status=status.HTTP_200_OK) def post(self, request): fee_data = JSONParser().parse(request) fee_serializer = FeeSerializer(data=fee_data) if fee_serializer.is_valid(): fee_serializer.save() return JsonResponse(fee_serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(fee_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class FeeDetailView(APIView): def get(self, request, id): try: fee = Fee.objects.get(id=id) fee_serializer = FeeSerializer(fee) return JsonResponse(fee_serializer.data, safe=False) except Fee.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): fee_data = JSONParser().parse(request) try: fee = Fee.objects.get(id=id) except Fee.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) fee_serializer = FeeSerializer(fee, data=fee_data, partial=True) if fee_serializer.is_valid(): fee_serializer.save() return JsonResponse(fee_serializer.data, safe=False) return JsonResponse(fee_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): return delete_object(Fee, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class DiscountListCreateView(APIView): def get(self, request, *args, **kwargs): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) filter = request.GET.get('filter', '').strip() discount_type_value = 0 if filter == 'registration' else 1 discounts = Discount.objects.filter(type=discount_type_value, establishment_id=establishment_id).distinct() discounts_serializer = DiscountSerializer(discounts, many=True) return JsonResponse(discounts_serializer.data, safe=False, status=status.HTTP_200_OK) def post(self, request): discount_data = JSONParser().parse(request) discount_serializer = DiscountSerializer(data=discount_data) if discount_serializer.is_valid(): discount_serializer.save() return JsonResponse(discount_serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(discount_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class DiscountDetailView(APIView): def get(self, request, id): try: discount = Discount.objects.get(id=id) discount_serializer = DiscountSerializer(discount) return JsonResponse(discount_serializer.data, safe=False) except Discount.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): discount_data = JSONParser().parse(request) try: discount = Discount.objects.get(id=id) except Discount.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) discount_serializer = DiscountSerializer(discount, data=discount_data, partial=True) # Utilisation de partial=True if discount_serializer.is_valid(): discount_serializer.save() return JsonResponse(discount_serializer.data, safe=False) return JsonResponse(discount_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): return delete_object(Discount, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PaymentPlanListCreateView(APIView): def get(self, request, *args, **kwargs): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) filter = request.GET.get('filter', '').strip() type_value = 0 if filter == 'registration' else 1 payment_plans = PaymentPlan.objects.filter(type=type_value, establishment_id=establishment_id).distinct() payment_plans_serializer = PaymentPlanSerializer(payment_plans, many=True) return JsonResponse(payment_plans_serializer.data, safe=False, status=status.HTTP_200_OK) def post(self, request): payment_plan_data = JSONParser().parse(request) payment_plan_serializer = PaymentPlanSerializer(data=payment_plan_data) if payment_plan_serializer.is_valid(): payment_plan_serializer.save() return JsonResponse(payment_plan_serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(payment_plan_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PaymentPlanDetailView(APIView): def get(self, request, id): try: payment_plan = PaymentPlan.objects.get(id=id) payment_plan_serializer = PaymentPlanSerializer(payment_plan) return JsonResponse(payment_plan_serializer.data, safe=False) except PaymentPlan.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): payment_plan_data = JSONParser().parse(request) try: payment_plan = PaymentPlan.objects.get(id=id) except PaymentPlan.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) payment_plan_serializer = PaymentPlanSerializer(payment_plan, data=payment_plan_data, partial=True) if payment_plan_serializer.is_valid(): payment_plan_serializer.save() return JsonResponse(payment_plan_serializer.data, safe=False) return JsonResponse(payment_plan_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): return delete_object(PaymentPlan, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PaymentModeListCreateView(APIView): def get(self, request): establishment_id = request.GET.get('establishment_id', None) if establishment_id is None: return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) filter = request.GET.get('filter', '').strip() type_value = 0 if filter == 'registration' else 1 payment_modes = PaymentMode.objects.filter(type=type_value, establishment_id=establishment_id).distinct() payment_modes_serializer = PaymentModeSerializer(payment_modes, many=True) return JsonResponse(payment_modes_serializer.data, safe=False, status=status.HTTP_200_OK) def post(self, request): payment_mode_data = JSONParser().parse(request) payment_mode_serializer = PaymentModeSerializer(data=payment_mode_data) if payment_mode_serializer.is_valid(): payment_mode_serializer.save() return JsonResponse(payment_mode_serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(payment_mode_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class PaymentModeDetailView(APIView): def get(self, request, id): try: payment_mode = PaymentMode.objects.get(id=id) payment_mode_serializer = PaymentModeSerializer(payment_mode) return JsonResponse(payment_mode_serializer.data, safe=False) except PaymentMode.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): payment_mode_data = JSONParser().parse(request) try: payment_mode = PaymentMode.objects.get(id=id) except PaymentMode.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) payment_mode_serializer = PaymentModeSerializer(payment_mode, data=payment_mode_data, partial=True) if payment_mode_serializer.is_valid(): payment_mode_serializer.save() return JsonResponse(payment_mode_serializer.data, safe=False) return JsonResponse(payment_mode_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): return delete_object(PaymentMode, id) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class DomainListCreateView(APIView): def get(self, request): domains = Domain.objects.all() serializer = DomainSerializer(domains, many=True) return JsonResponse(serializer.data, safe=False) def post(self, request): data = JSONParser().parse(request) serializer = DomainSerializer(data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class DomainDetailView(APIView): def get(self, request, id): try: domain = Domain.objects.get(id=id) serializer = DomainSerializer(domain) return JsonResponse(serializer.data, safe=False) except Domain.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): try: domain = Domain.objects.get(id=id) except Domain.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) data = JSONParser().parse(request) serializer = DomainSerializer(domain, data=data, partial=True) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): try: domain = Domain.objects.get(id=id) domain.delete() return JsonResponse({'message': 'Deleted'}, safe=False) except Domain.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) # Répète la même logique pour Category, Competency, EstablishmentCompetency @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class CategoryListCreateView(APIView): def get(self, request): categories = Category.objects.all() serializer = CategorySerializer(categories, many=True) return JsonResponse(serializer.data, safe=False) def post(self, request): data = JSONParser().parse(request) serializer = CategorySerializer(data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class CategoryDetailView(APIView): def get(self, request, id): try: category = Category.objects.get(id=id) serializer = CategorySerializer(category) return JsonResponse(serializer.data, safe=False) except Category.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): try: category = Category.objects.get(id=id) except Category.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) data = JSONParser().parse(request) serializer = CategorySerializer(category, data=data, partial=True) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): try: category = Category.objects.get(id=id) category.delete() return JsonResponse({'message': 'Deleted'}, safe=False) except Category.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class CompetencyListCreateView(APIView): def get(self, request): cycle = request.GET.get('cycle') if cycle is None: return JsonResponse({'error': 'cycle est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) competencies_list = getAllObjects(Competency) competencies_list = competencies_list.filter( category__domain__cycle=cycle ).distinct() serializer = CompetencySerializer(competencies_list, many=True) print(f'len : {competencies_list.count()}') return JsonResponse(serializer.data, safe=False) def post(self, request): data = JSONParser().parse(request) serializer = CompetencySerializer(data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class CompetencyDetailView(APIView): def get(self, request, id): try: competency = Competency.objects.get(id=id) serializer = CompetencySerializer(competency) return JsonResponse(serializer.data, safe=False) except Competency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): try: competency = Competency.objects.get(id=id) except Competency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) data = JSONParser().parse(request) serializer = CompetencySerializer(competency, data=data, partial=True) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): try: competency = Competency.objects.get(id=id) competency.delete() return JsonResponse({'message': 'Deleted'}, safe=False) except Competency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class EstablishmentCompetencyListCreateView(APIView): def get(self, request): establishment_id = request.GET.get('establishment_id') cycle = request.GET.get('cycle') if not establishment_id or not cycle: return JsonResponse({'error': 'establishment_id et cycle sont requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST) # Toutes les compétences du cycle competencies = Competency.objects.filter(category__domain__cycle=cycle).select_related('category', 'category__domain') # Récupérer les EstablishmentCompetency pour l'établissement et le cycle ec_qs = EstablishmentCompetency.objects.filter( Q(competency__in=competencies) | Q(competency__isnull=True), establishment_id=establishment_id ).select_related('competency', 'custom_category') # Required = compétences de référence requises required_ids = set(ec_qs.filter(is_required=True, competency__isnull=False).values_list('competency_id', flat=True)) # Custom = compétences custom (pas de lien vers Competency) custom_ecs = ec_qs.filter(is_required=False, competency__isnull=True) # Organisation par domaine > catégorie result = [] selected_count = 0 domaines = Domain.objects.filter(cycle=cycle) for domaine in domaines: domaine_dict = { "domaine_id": domaine.id, "domaine_nom": domaine.name, "categories": [] } categories = domaine.categories.all() for categorie in categories: categorie_dict = { "categorie_id": categorie.id, "categorie_nom": categorie.name, "competences": [] } # Liste des noms de compétences custom pour cette catégorie custom_for_cat = custom_ecs.filter(custom_category=categorie) custom_names = set(ec.custom_name.strip().lower() for ec in custom_for_cat if ec.custom_name) # Compétences de référence (on saute celles qui sont déjà en custom) competences = categorie.competencies.all() for comp in competences: if comp.name.strip().lower() in custom_names: continue # On n'affiche pas la compétence de référence si une custom du même nom existe if comp.id in required_ids: state = "required" selected_count += 1 else: state = "none" categorie_dict["competences"].append({ "competence_id": comp.id, "nom": comp.name, "state": state }) # Ajout des compétences custom for ec in custom_for_cat: categorie_dict["competences"].append({ "competence_id": ec.id, "nom": ec.custom_name, "state": "custom" }) selected_count += 1 domaine_dict["categories"].append(categorie_dict) result.append(domaine_dict) return JsonResponse({ "selected_count": selected_count, "data": result }, safe=False) def post(self, request): """ Crée une ou plusieurs compétences custom pour un établissement (is_required=False) Attendu dans le body : [ { "establishment_id": ..., "category_id": ..., "nom": ... }, ... ] """ data = JSONParser().parse(request) # Si data est un dict (un seul objet), on le met dans une liste if isinstance(data, dict): data = [data] created = [] errors = [] for item in data: establishment_id = item.get("establishment_id") category_id = item.get("category_id") nom = item.get("nom") if not establishment_id or not category_id or not nom: errors.append({"error": "establishment_id, category_id et nom sont requis", "item": item}) continue try: category = Category.objects.get(id=category_id) # Vérifier si une compétence custom du même nom existe déjà pour cet établissement et cette catégorie ec_exists = EstablishmentCompetency.objects.filter( establishment_id=establishment_id, competency__isnull=True, custom_name=nom, ).exists() if ec_exists: errors.append({"error": "Une compétence custom de ce nom existe déjà pour cet établissement", "item": item}) continue ec = EstablishmentCompetency.objects.create( establishment_id=establishment_id, competency=None, custom_name=nom, custom_category=category, is_required=False ) created.append({ "competence_id": ec.id, "nom": ec.custom_name, "state": "custom" }) except Exception as e: errors.append({"error": str(e), "item": item}) status_code = status.HTTP_201_CREATED if created else status.HTTP_400_BAD_REQUEST return JsonResponse({ "created": created, "errors": errors }, status=status_code, safe=False) def delete(self, request): """ Supprime une ou plusieurs compétences custom (EstablishmentCompetency) à partir d'une liste d'IDs. Attendu dans le body : { "ids": [1, 2, 3, ...] } """ data = JSONParser().parse(request) ids = data.get("ids", []) deleted = [] errors = [] for ec_id in ids: try: ec = EstablishmentCompetency.objects.get(id=ec_id) ec.delete() deleted.append(ec_id) except EstablishmentCompetency.DoesNotExist: errors.append({"id": ec_id, "error": "No object found"}) return JsonResponse({ "deleted": deleted, "errors": errors }, safe=False) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') class EstablishmentCompetencyDetailView(APIView): def get(self, request, id): try: ec = EstablishmentCompetency.objects.get(id=id) serializer = EstablishmentCompetencySerializer(ec) return JsonResponse(serializer.data, safe=False) except EstablishmentCompetency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) def put(self, request, id): try: ec = EstablishmentCompetency.objects.get(id=id) except EstablishmentCompetency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND) data = JSONParser().parse(request) serializer = EstablishmentCompetencySerializer(ec, data=data, partial=True) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, safe=False) return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): try: ec = EstablishmentCompetency.objects.get(id=id) ec.delete() return JsonResponse({'message': 'Deleted'}, safe=False) except EstablishmentCompetency.DoesNotExist: return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)