135 lines
4.3 KiB
Python

"""
Celery tasks для автоматизации кадровых событий из заявок.
"""
import logging
from celery import shared_task
from django.utils import timezone
logger = logging.getLogger(__name__)
@shared_task(bind=True, max_retries=3)
def create_scheduled_action(self, request_id):
"""
Создать кадровое событие для заявки по расписанию.
Вызывается в date_from для vacation/sick_leave/day_off.
Args:
request_id: ID заявки
"""
from .models import Request
from .enums import RequestStatus
from employees.constants import (
ACTION_ON_DAY_OFF,
ACTION_ON_LEAVE,
ACTION_ON_MATERNITY,
ACTION_ON_SICK_LEAVE,
)
from employees.services.request_actions import (
build_request_action_comment,
create_request_action,
)
try:
request = Request.objects.get(id=request_id)
# Проверяем, что заявка все еще одобрена
if request.status != RequestStatus.APPROVED:
logger.info(
f"Request #{request_id} is no longer approved "
f"(status={request.status}), skipping action creation"
)
return
# Определяем тип события
action_mapping = {
"vacation": ACTION_ON_LEAVE,
"sick_leave": ACTION_ON_SICK_LEAVE,
"day_off": ACTION_ON_DAY_OFF,
"maternity": ACTION_ON_MATERNITY,
}
action_type = action_mapping.get(request.type)
if not action_type:
logger.warning(
f"Request #{request_id} has type '{request.type}' "
f"which doesn't map to scheduled action"
)
return
action, created = create_request_action(
request=request,
action_type=action_type,
action_date=request.date_from,
date_to=request.date_to,
comment=build_request_action_comment(request),
extra={
"approved_by": (request.approver.id if request.approver else None),
"scheduled": True,
},
)
if not created:
logger.info(f"Action already exists for Request #{request_id}, skipping")
return
logger.info(
f"Created scheduled EmployeeAction #{action.id} ({action_type}) "
f"for Request #{request_id}"
)
return f"Created action {action.id}"
except Request.DoesNotExist:
logger.error(f"Request #{request_id} not found")
raise
except Exception as e:
logger.error(
f"Failed to create scheduled action for Request #{request_id}: {e}",
exc_info=True,
)
# Retry через 5 минут
raise self.retry(exc=e, countdown=300)
@shared_task(bind=True, max_retries=3)
def schedule_auto_return(self, request_id):
"""
Legacy no-op для старых очередей Celery.
Возвраты больше не закрывают временные кадровые состояния: период
хранится в EmployeeAction.date_to. Старые запланированные задачи должны
спокойно завершаться и не создавать дублирующих событий.
"""
from .models import Request
try:
request = Request.objects.get(id=request_id)
logger.info(
"Skipping legacy auto-return for Request #%s; interval ends at %s",
request_id,
request.date_to,
)
return "Auto-return disabled"
except Request.DoesNotExist:
logger.error(f"Request #{request_id} not found for auto-return")
raise
except Exception as e:
logger.error(
f"Failed to process legacy auto-return for Request #{request_id}: {e}",
exc_info=True,
)
raise self.retry(exc=e, countdown=300)
@shared_task
def cleanup_missed_returns():
"""
Legacy no-op: возвратные события больше не создаются автоматически.
"""
logger.info("cleanup_missed_returns skipped: auto-return is disabled")
return 0