diff --git a/backend/api/v1/employees/views/actions.py b/backend/api/v1/employees/views/actions.py index dc9e1c41..2b145036 100644 --- a/backend/api/v1/employees/views/actions.py +++ b/backend/api/v1/employees/views/actions.py @@ -4,21 +4,17 @@ from __future__ import annotations import logging -from django.conf import settings from django.db import transaction from django.utils import timezone from employees.constants import ACTION_DISMISSED -from employees.ldap.directory_service import DirectoryService -from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError, - DirectoryServiceError) -from employees.models import EmployeeAction, EmployeeDepartment, LdapSyncState +from employees.models import EmployeeAction, EmployeeDepartment from rest_framework import filters, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from ...permissions import AdminOrActionOrModelPerms from ..serializers import EmployeeActionSerializer -from ._helpers import HistoryActionMixin, _is_ldap_enabled +from ._helpers import HistoryActionMixin logger = logging.getLogger(__name__) @@ -82,153 +78,32 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet): # --- бизнес-эффекты после записи события --- def _apply_effects(self, action_obj: EmployeeAction): + """Применяет эффекты кадрового события. + + Работает только с БД. LDAP синхронизация через сигналы: + - sync_employee_to_ldap_on_save: активация/деактивация в LDAP + - sync_member (signals_department.py): удаление из отделов в LDAP + """ emp = action_obj.employee - ldap_enabled = _is_ldap_enabled() if action_obj.action == ACTION_DISMISSED: - # Сначала деактивируем сотрудника + # Деактивируем сотрудника (сигнал синхронизирует в LDAP) if emp.is_active: emp.is_active = False + emp._ldap_changes = {"is_active": False} emp.save(update_fields=["is_active"]) - # Деактивируем связи с отделами в БД + # Деактивируем связи с отделами (сигналы синхронизируют в LDAP) EmployeeDepartment.objects.filter(employee=emp, is_active=True).update( is_active=False, date_to=timezone.now().date() ) - - # Синхронизируем с LDAP - if ldap_enabled: - try: - svc = DirectoryService() - has_ldap_dn = LdapSyncState.objects.filter( - model="employee", object_pk=str(emp.pk), ldap_dn__isnull=False - ).exists() - - if has_ldap_dn: - svc.update_user(emp, changes={"is_active": False}) - - active_departments = EmployeeDepartment.objects.filter( - employee=emp - ).select_related("department") - - departments_processed = False - for emp_dept in active_departments: - try: - svc.remove_member(emp_dept.department, emp) - departments_processed = True - except ( - DirectoryLdapError, - DirectoryDbError, - DirectoryServiceError, - ) as e: - logger.error( - f"Failed to remove dismissed employee from department: " - f"employee_id={emp.id}, department_id={emp_dept.department.id}, error={e}" - ) - - if not departments_processed: - try: - from employees.ldap.utils.ldap_utils import \ - get_base_dn_for_employee - - sync_state = LdapSyncState.objects.filter( - model="employee", object_pk=str(emp.pk) - ).first() - - if sync_state and sync_state.ldap_dn: - target_base = get_base_dn_for_employee(emp) - current_dn = sync_state.ldap_dn - - if not current_dn.lower().endswith( - target_base.lower() - ): - try: - new_dn = svc.move_user_to_base( - emp, target_base - ) - logger.info( - f"Dismissed employee without department moved to OU=Dismissed: " - f"employee_id={emp.id}, new_dn={new_dn}" - ) - except Exception as move_err: - logger.error( - f"Failed to move dismissed employee: {move_err}" - ) - except Exception as e: - logger.error( - f"Failed to move dismissed employee without department to OU=Dismissed: " - f"employee_id={emp.id}, error={e}" - ) - except ( - DirectoryLdapError, - DirectoryDbError, - DirectoryServiceError, - ) as e: - logger.error( - f"Failed to disable user in LDAP during dismissal: " - f"employee_id={emp.id}, error={e}" - ) else: - # Любое иное событие делает сотрудника активным - was_inactive = not emp.is_active - if was_inactive: + # Любое иное событие делает сотрудника активным (сигнал синхронизирует в LDAP) + if not emp.is_active: emp.is_active = True + emp._ldap_changes = {"is_active": True} emp.save(update_fields=["is_active"]) - if ldap_enabled: - try: - svc = DirectoryService() - has_ldap_dn = LdapSyncState.objects.filter( - model="employee", object_pk=str(emp.pk), ldap_dn__isnull=False - ).exists() - - if has_ldap_dn: - svc.update_user(emp, changes={"is_active": True}) - - if was_inactive: - try: - sync_state = LdapSyncState.objects.get( - model="employee", object_pk=str(emp.pk) - ) - current_dn = sync_state.ldap_dn - dismissed_base = getattr( - settings, "LDAP_DISMISSED_BASE", "" - ) - - if dismissed_base and current_dn.lower().endswith( - dismissed_base.lower() - ): - users_base = getattr( - settings, "LDAP_USERS_BASE", None - ) or getattr(settings, "LDAP_USER_BASE", None) - if users_base: - try: - new_dn = svc.move_user_to_base( - emp, users_base - ) - logger.info( - f"Restored employee moved from Dismissed to Users: " - f"employee_id={emp.id}, new_dn={new_dn}" - ) - except Exception as move_err: - logger.error( - f"Failed to move restored employee: {move_err}" - ) - except Exception as e: - logger.error( - f"Failed to move restored employee from Dismissed to Users: " - f"employee_id={emp.id}, error={e}" - ) - except ( - DirectoryLdapError, - DirectoryDbError, - DirectoryServiceError, - ) as e: - logger.error( - f"Failed to enable user in LDAP during action: " - f"employee_id={emp.id}, action={action_obj.action}, error={e}" - ) - @transaction.atomic def perform_create(self, serializer): obj = serializer.save()