From 5d729fa1f0f3c69e84f316357c318f81ee457aa1 Mon Sep 17 00:00:00 2001 From: lizerk Date: Wed, 18 Mar 2026 18:28:11 +0300 Subject: [PATCH] =?UTF-8?q?fix(views):=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20bulk=20update=20=D0=B8=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B8=D1=82=D1=8C=20=D0=BD=D0=B5=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Критические исправления: - actions.py: заменить bulk update() на save() для EmployeeDepartment Причина: bulk update НЕ вызывает Django signals! Было: .update(is_active=False) - сигнал не срабатывает Стало: for loop с save() - сигнал срабатывает для каждой записи - _helpers.py: удалить неиспользуемую функцию _ldap_try() Нигде не используется после рефакторинга - _helpers.py: удалить неиспользуемые импорты DirectoryLdapError, DirectoryServiceError, DirectoryDbError, status - actions.py: обновить комментарий с правильным названием сигнала sync_department_member_to_ldap вместо устаревшего sync_member Функционал сохранен: при увольнении сотрудника теперь корректно срабатывают сигналы для каждого EmployeeDepartment, что приводит к корректной синхронизации с LDAP (перемещение из OU отделов). --- backend/api/v1/employees/views/_helpers.py | 25 ++++------------------ backend/api/v1/employees/views/actions.py | 11 ++++++---- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/backend/api/v1/employees/views/_helpers.py b/backend/api/v1/employees/views/_helpers.py index a6ebcec8..98b467aa 100644 --- a/backend/api/v1/employees/views/_helpers.py +++ b/backend/api/v1/employees/views/_helpers.py @@ -7,10 +7,7 @@ import logging from django.conf import settings from django.contrib.auth import get_user_model from django.db.models import Q -from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError, - DirectoryServiceError) from employees.utils import _detect_phone_field -from rest_framework import status from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -23,25 +20,11 @@ PHONE_FIELD = _detect_phone_field() def _is_ldap_enabled() -> bool: - """Проверяет, включена ли интеграция с LDAP.""" - return getattr(settings, "LDAP_ENABLED", False) - - -def _ldap_try(fn): - """Выполняет функцию, которая работает с LDAP, и обрабатывает ошибки. - - Если LDAP отключен, функция не выполняется и возвращается None. + """Проверяет, включена ли интеграция с LDAP. + + Используется только в RegisterAPIView для создания LDAP пользователей. """ - if not _is_ldap_enabled(): - return None - - try: - fn() - return None - except (DirectoryLdapError, DirectoryServiceError, DirectoryDbError) as e: - return Response( - {"detail": f"LDAP sync failed: {e}"}, status=status.HTTP_502_BAD_GATEWAY - ) + return getattr(settings, "LDAP_ENABLED", False) class HistoryActionMixin: diff --git a/backend/api/v1/employees/views/actions.py b/backend/api/v1/employees/views/actions.py index 2b145036..ea7a0f6b 100644 --- a/backend/api/v1/employees/views/actions.py +++ b/backend/api/v1/employees/views/actions.py @@ -82,7 +82,7 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet): Работает только с БД. LDAP синхронизация через сигналы: - sync_employee_to_ldap_on_save: активация/деактивация в LDAP - - sync_member (signals_department.py): удаление из отделов в LDAP + - sync_department_member_to_ldap: удаление из отделов в LDAP """ emp = action_obj.employee @@ -94,9 +94,12 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet): emp.save(update_fields=["is_active"]) # Деактивируем связи с отделами (сигналы синхронизируют в LDAP) - EmployeeDepartment.objects.filter(employee=emp, is_active=True).update( - is_active=False, date_to=timezone.now().date() - ) + # ВАЖНО: используем save() для каждой записи, чтобы сработали сигналы + today = timezone.now().date() + for emp_dept in EmployeeDepartment.objects.filter(employee=emp, is_active=True): + emp_dept.is_active = False + emp_dept.date_to = today + emp_dept.save(update_fields=["is_active", "date_to"]) else: # Любое иное событие делает сотрудника активным (сигнал синхронизирует в LDAP) if not emp.is_active: