feat(requests): Этап 4 - обновлена система уведомлений для получателей
- notify_new_request теперь отправляет уведомления всем recipients и cc_users - При sent_to_all_department уведомления идут всем сотрудникам отделов - notify_status_change уведомляет автора, получателей, CC и сотрудников отделов - create_comment_notification уведомляет всех заинтересованных лиц - Добавлены метаданные is_primary_recipient, is_cc, is_approver - Сохранена обратная совместимость со старым полем department
This commit is contained in:
parent
ca056a15f8
commit
60fc506ef9
@ -65,6 +65,12 @@ def track_status_change(sender, instance, **kwargs):
|
|||||||
def create_comment_notification(sender, instance, created, **kwargs):
|
def create_comment_notification(sender, instance, created, **kwargs):
|
||||||
"""
|
"""
|
||||||
Создает уведомление при добавлении комментария к заявке.
|
Создает уведомление при добавлении комментария к заявке.
|
||||||
|
Уведомляет:
|
||||||
|
- Автора заявки
|
||||||
|
- Всех получателей
|
||||||
|
- Всех в копии
|
||||||
|
- Согласующего
|
||||||
|
- Сотрудников отделов (если sent_to_all_department)
|
||||||
"""
|
"""
|
||||||
if not created:
|
if not created:
|
||||||
return
|
return
|
||||||
@ -72,35 +78,42 @@ def create_comment_notification(sender, instance, created, **kwargs):
|
|||||||
comment = instance
|
comment = instance
|
||||||
request_obj = comment.request
|
request_obj = comment.request
|
||||||
author = comment.author
|
author = comment.author
|
||||||
|
recipients_set = set()
|
||||||
|
|
||||||
# Уведомляем автора заявки (если комментарий не от него)
|
# Автор заявки
|
||||||
if request_obj.employee.id != author.id:
|
if request_obj.employee.id != author.id:
|
||||||
NotificationService.create_notification(
|
recipients_set.add(request_obj.employee)
|
||||||
recipient=request_obj.employee,
|
|
||||||
notification_type_code='request_comment',
|
|
||||||
title='Новый комментарий к вашей заявке',
|
|
||||||
message=(
|
|
||||||
f'{author.get_full_name() or author.username} '
|
|
||||||
f'прокомментировал заявку: {comment.text[:100]}'
|
|
||||||
),
|
|
||||||
content_object=request_obj,
|
|
||||||
action_url=f'/requests/{request_obj.id}/',
|
|
||||||
metadata={
|
|
||||||
'request_id': request_obj.id,
|
|
||||||
'request_type': request_obj.type,
|
|
||||||
'comment_id': comment.id,
|
|
||||||
'author_id': author.id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Также уведомляем согласующего (если есть и это не он)
|
# Получатели
|
||||||
if (request_obj.approver and
|
recipients_set.update(
|
||||||
request_obj.approver.id != author.id and
|
request_obj.recipients.filter(is_active=True).exclude(id=author.id)
|
||||||
request_obj.approver.id != request_obj.employee.id):
|
)
|
||||||
|
|
||||||
|
# CC
|
||||||
|
recipients_set.update(
|
||||||
|
request_obj.cc_users.filter(is_active=True).exclude(id=author.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Согласующий
|
||||||
|
if request_obj.approver and request_obj.approver.id != author.id:
|
||||||
|
recipients_set.add(request_obj.approver)
|
||||||
|
|
||||||
|
# Если sent_to_all_department - все сотрудники отделов
|
||||||
|
if request_obj.sent_to_all_department:
|
||||||
|
dept_employees = Employee.objects.filter(
|
||||||
|
employee_departments__department__in=request_obj.departments.all(),
|
||||||
|
employee_departments__is_active=True,
|
||||||
|
is_active=True
|
||||||
|
).exclude(id__in=[author.id, request_obj.employee.id]).distinct()
|
||||||
|
|
||||||
|
recipients_set.update(dept_employees)
|
||||||
|
|
||||||
|
# Отправляем уведомления
|
||||||
|
for recipient in recipients_set:
|
||||||
NotificationService.create_notification(
|
NotificationService.create_notification(
|
||||||
recipient=request_obj.approver,
|
recipient=recipient,
|
||||||
notification_type_code='request_comment',
|
notification_type_code='request_comment',
|
||||||
title='Комментарий к заявке',
|
title='Новый комментарий к заявке',
|
||||||
message=(
|
message=(
|
||||||
f'{author.get_full_name() or author.username} '
|
f'{author.get_full_name() or author.username} '
|
||||||
f'прокомментировал заявку: {comment.text[:100]}'
|
f'прокомментировал заявку: {comment.text[:100]}'
|
||||||
@ -120,108 +133,193 @@ def create_comment_notification(sender, instance, created, **kwargs):
|
|||||||
|
|
||||||
def notify_new_request(request_obj):
|
def notify_new_request(request_obj):
|
||||||
"""
|
"""
|
||||||
Отправляет уведомление о новой заявке ответственным лицам.
|
Отправляет уведомление о новой заявке:
|
||||||
|
- Всем основным получателям (recipients)
|
||||||
|
- Всем в копии (cc_users)
|
||||||
|
- Согласующему (approver)
|
||||||
|
- Руководителям отделов
|
||||||
|
- Пользователям с правом can_process_requests
|
||||||
|
|
||||||
|
При sent_to_all_department=True отправляет всем сотрудникам отделов
|
||||||
"""
|
"""
|
||||||
# Определяем получателей в зависимости от типа заявки
|
recipients_set = set()
|
||||||
recipients = []
|
|
||||||
|
|
||||||
# 1. Руководитель отдела сотрудника
|
# 1. Основные получатели
|
||||||
|
for recipient in request_obj.recipients.filter(is_active=True):
|
||||||
|
recipients_set.add(recipient)
|
||||||
|
|
||||||
|
# 2. Копия (CC)
|
||||||
|
for cc_user in request_obj.cc_users.filter(is_active=True):
|
||||||
|
recipients_set.add(cc_user)
|
||||||
|
|
||||||
|
# 3. Если sent_to_all_department - все сотрудники отделов
|
||||||
|
if request_obj.sent_to_all_department:
|
||||||
|
dept_employees = Employee.objects.filter(
|
||||||
|
employee_departments__department__in=request_obj.departments.all(),
|
||||||
|
employee_departments__is_active=True,
|
||||||
|
is_active=True
|
||||||
|
).exclude(id=request_obj.employee.id).distinct()
|
||||||
|
|
||||||
|
recipients_set.update(dept_employees)
|
||||||
|
|
||||||
|
# 4. Согласующий
|
||||||
|
if request_obj.approver and request_obj.approver.id != request_obj.employee.id:
|
||||||
|
recipients_set.add(request_obj.approver)
|
||||||
|
|
||||||
|
# 5. Руководители отделов
|
||||||
|
for department in request_obj.departments.all():
|
||||||
|
if department.head and department.head.id != request_obj.employee.id:
|
||||||
|
recipients_set.add(department.head)
|
||||||
|
|
||||||
|
# Также проверяем старое поле department для обратной совместимости
|
||||||
if request_obj.department and request_obj.department.head:
|
if request_obj.department and request_obj.department.head:
|
||||||
head = request_obj.department.head
|
if request_obj.department.head.id != request_obj.employee.id:
|
||||||
if head.id != request_obj.employee.id:
|
recipients_set.add(request_obj.department.head)
|
||||||
recipients.append(head)
|
|
||||||
|
|
||||||
# 2. Если есть назначенный согласующий
|
# 6. Пользователи с правом обрабатывать заявки в этих отделах
|
||||||
if request_obj.approver:
|
dept_ids = list(request_obj.departments.values_list('id', flat=True))
|
||||||
if request_obj.approver not in recipients:
|
if request_obj.department_id and request_obj.department_id not in dept_ids:
|
||||||
recipients.append(request_obj.approver)
|
dept_ids.append(request_obj.department_id)
|
||||||
|
|
||||||
# 3. Пользователи с правом обрабатывать заявки
|
if dept_ids:
|
||||||
users_with_permission = Employee.objects.filter(
|
dept_processors = Employee.objects.filter(
|
||||||
user_permissions__codename='can_process_requests'
|
employee_departments__department_id__in=dept_ids,
|
||||||
).exclude(id=request_obj.employee.id)
|
employee_departments__is_active=True,
|
||||||
|
employee_departments__role__scoped_permissions__code='can_process_requests',
|
||||||
|
is_active=True
|
||||||
|
).exclude(id=request_obj.employee.id).distinct()
|
||||||
|
|
||||||
|
recipients_set.update(dept_processors)
|
||||||
|
|
||||||
for user in users_with_permission:
|
# Определяем тип уведомления для каждого получателя
|
||||||
if user not in recipients:
|
author_name = (
|
||||||
recipients.append(user)
|
request_obj.employee.get_full_name() or
|
||||||
|
request_obj.employee.username
|
||||||
|
)
|
||||||
|
|
||||||
# Отправляем уведомления
|
for recipient in recipients_set:
|
||||||
for recipient in recipients:
|
# Определяем роль получателя
|
||||||
|
is_primary = request_obj.recipients.filter(id=recipient.id).exists()
|
||||||
|
is_cc = request_obj.cc_users.filter(id=recipient.id).exists()
|
||||||
|
is_approver = request_obj.approver_id == recipient.id
|
||||||
|
|
||||||
|
# Формируем заголовок и сообщение
|
||||||
|
if is_approver:
|
||||||
|
title = f'Новая заявка на согласование от {author_name}'
|
||||||
|
notification_type = 'request_new'
|
||||||
|
elif is_primary:
|
||||||
|
title = f'Вам адресована заявка от {author_name}'
|
||||||
|
notification_type = 'request_new'
|
||||||
|
elif is_cc:
|
||||||
|
title = f'Вы в копии заявки от {author_name}'
|
||||||
|
notification_type = 'request_new'
|
||||||
|
else:
|
||||||
|
title = f'Новая заявка в отделе от {author_name}'
|
||||||
|
notification_type = 'request_new'
|
||||||
|
|
||||||
|
message = (
|
||||||
|
f'Тип: {request_obj.get_type_display()}. '
|
||||||
|
f'{request_obj.comment[:100] if request_obj.comment else ""}'
|
||||||
|
)
|
||||||
|
|
||||||
NotificationService.create_notification(
|
NotificationService.create_notification(
|
||||||
recipient=recipient,
|
recipient=recipient,
|
||||||
notification_type_code='request_new',
|
notification_type_code=notification_type,
|
||||||
title=f'Новая заявка от {request_obj.employee.get_full_name()}',
|
title=title,
|
||||||
message=(
|
message=message,
|
||||||
f'Тип: {request_obj.get_type_display()}. '
|
|
||||||
f'{request_obj.comment[:100] if request_obj.comment else ""}'
|
|
||||||
),
|
|
||||||
content_object=request_obj,
|
content_object=request_obj,
|
||||||
action_url=f'/requests/{request_obj.id}/',
|
action_url=f'/requests/{request_obj.id}/',
|
||||||
metadata={
|
metadata={
|
||||||
'request_id': request_obj.id,
|
'request_id': request_obj.id,
|
||||||
'request_type': request_obj.type,
|
'request_type': request_obj.type,
|
||||||
'employee_id': request_obj.employee.id,
|
'employee_id': request_obj.employee.id,
|
||||||
'department_id': (
|
'is_primary_recipient': is_primary,
|
||||||
request_obj.department.id
|
'is_cc': is_cc,
|
||||||
if request_obj.department else None
|
'is_approver': is_approver,
|
||||||
),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def notify_status_change(request_obj, old_status, new_status):
|
def notify_status_change(request_obj, old_status, new_status):
|
||||||
"""
|
"""
|
||||||
Отправляет уведомление при изменении статуса заявки.
|
Уведомляет о изменении статуса:
|
||||||
|
- Автора
|
||||||
|
- Всех получателей (recipients)
|
||||||
|
- Всех в копии (cc_users)
|
||||||
|
- Сотрудников отделов (если sent_to_all_department)
|
||||||
"""
|
"""
|
||||||
# Уведомляем автора заявки
|
recipients_to_notify = set()
|
||||||
recipient = request_obj.employee
|
|
||||||
|
|
||||||
# Определяем тип уведомления и сообщение
|
# 1. Автор
|
||||||
if new_status == 'approved':
|
recipients_to_notify.add(request_obj.employee)
|
||||||
notification_type = 'request_approved'
|
|
||||||
title = 'Ваша заявка одобрена'
|
|
||||||
approver_name = (
|
|
||||||
request_obj.approver.get_full_name()
|
|
||||||
if request_obj.approver else 'Руководитель'
|
|
||||||
)
|
|
||||||
message = (
|
|
||||||
f'Заявка "{request_obj.get_type_display()}" '
|
|
||||||
f'одобрена пользователем {approver_name}'
|
|
||||||
)
|
|
||||||
elif new_status == 'rejected':
|
|
||||||
notification_type = 'request_rejected'
|
|
||||||
title = 'Ваша заявка отклонена'
|
|
||||||
approver_name = (
|
|
||||||
request_obj.approver.get_full_name()
|
|
||||||
if request_obj.approver else 'Руководитель'
|
|
||||||
)
|
|
||||||
message = (
|
|
||||||
f'Заявка "{request_obj.get_type_display()}" '
|
|
||||||
f'отклонена пользователем {approver_name}'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# Общее уведомление об изменении статуса
|
|
||||||
notification_type = 'request_status_changed'
|
|
||||||
title = 'Статус заявки изменен'
|
|
||||||
message = (
|
|
||||||
f'Статус заявки "{request_obj.get_type_display()}" '
|
|
||||||
f'изменен: {old_status} → {new_status}'
|
|
||||||
)
|
|
||||||
|
|
||||||
NotificationService.create_notification(
|
# 2. Основные получатели
|
||||||
recipient=recipient,
|
recipients_to_notify.update(
|
||||||
notification_type_code=notification_type,
|
request_obj.recipients.filter(is_active=True)
|
||||||
title=title,
|
|
||||||
message=message,
|
|
||||||
content_object=request_obj,
|
|
||||||
action_url=f'/requests/{request_obj.id}/',
|
|
||||||
metadata={
|
|
||||||
'request_id': request_obj.id,
|
|
||||||
'request_type': request_obj.type,
|
|
||||||
'old_status': old_status,
|
|
||||||
'new_status': new_status,
|
|
||||||
'approver_id': (
|
|
||||||
request_obj.approver.id if request_obj.approver else None
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 3. Копия
|
||||||
|
recipients_to_notify.update(
|
||||||
|
request_obj.cc_users.filter(is_active=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 4. Если sent_to_all_department - все сотрудники отделов
|
||||||
|
if request_obj.sent_to_all_department:
|
||||||
|
dept_employees = Employee.objects.filter(
|
||||||
|
employee_departments__department__in=request_obj.departments.all(),
|
||||||
|
employee_departments__is_active=True,
|
||||||
|
is_active=True
|
||||||
|
).exclude(id=request_obj.employee.id).distinct()
|
||||||
|
|
||||||
|
recipients_to_notify.update(dept_employees)
|
||||||
|
|
||||||
|
# Формируем уведомления
|
||||||
|
for recipient in recipients_to_notify:
|
||||||
|
if new_status == 'approved':
|
||||||
|
notification_type = 'request_approved'
|
||||||
|
title = 'Заявка одобрена'
|
||||||
|
approver_name = (
|
||||||
|
request_obj.approver.get_full_name()
|
||||||
|
if request_obj.approver else 'Руководитель'
|
||||||
|
)
|
||||||
|
message = (
|
||||||
|
f'Заявка "{request_obj.get_type_display()}" '
|
||||||
|
f'одобрена пользователем {approver_name}'
|
||||||
|
)
|
||||||
|
elif new_status == 'rejected':
|
||||||
|
notification_type = 'request_rejected'
|
||||||
|
title = 'Заявка отклонена'
|
||||||
|
approver_name = (
|
||||||
|
request_obj.approver.get_full_name()
|
||||||
|
if request_obj.approver else 'Руководитель'
|
||||||
|
)
|
||||||
|
message = (
|
||||||
|
f'Заявка "{request_obj.get_type_display()}" '
|
||||||
|
f'отклонена пользователем {approver_name}'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Общее уведомление об изменении статуса
|
||||||
|
notification_type = 'request_status_changed'
|
||||||
|
title = 'Статус заявки изменен'
|
||||||
|
message = (
|
||||||
|
f'Статус заявки "{request_obj.get_type_display()}" '
|
||||||
|
f'изменен: {old_status} → {new_status}'
|
||||||
|
)
|
||||||
|
|
||||||
|
NotificationService.create_notification(
|
||||||
|
recipient=recipient,
|
||||||
|
notification_type_code=notification_type,
|
||||||
|
title=title,
|
||||||
|
message=message,
|
||||||
|
content_object=request_obj,
|
||||||
|
action_url=f'/requests/{request_obj.id}/',
|
||||||
|
metadata={
|
||||||
|
'request_id': request_obj.id,
|
||||||
|
'request_type': request_obj.type,
|
||||||
|
'old_status': old_status,
|
||||||
|
'new_status': new_status,
|
||||||
|
'approver_id': (
|
||||||
|
request_obj.approver.id if request_obj.approver else None
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user