2026-09-07 19:43:48 +03:00

124 lines
3.7 KiB
Python

from dataclasses import dataclass
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.db.models import Q
from django.utils import timezone
from notifications.cache import invalidate_unread_summary
from notifications.models import Notification
from notifications.realtime import send_notifications_read_all_event
from procurement.models import ProcurementItem, ProcurementRequest
@dataclass(frozen=True)
class ProcurementNotificationReadResult:
notification_ids: list[int]
count: int
class ProcurementNotificationReadService:
"""Use case for reading notifications related to a procurement request."""
procurement_verb_filter = Q(verb__startswith="procurement_") | Q(
verb__startswith="equipment_"
)
def mark_request_notifications_as_read(
self,
*,
user,
procurement_request: ProcurementRequest,
) -> ProcurementNotificationReadResult:
queryset = self._get_unread_queryset(
user_id=user.id,
procurement_request=procurement_request,
).exclude(verb="procurement_item_commented")
return self._mark_queryset_as_read(user_id=user.id, queryset=queryset)
def mark_item_comment_notifications_as_read(
self,
*,
user,
item: ProcurementItem,
) -> ProcurementNotificationReadResult:
item_id = item.id
queryset = Notification.objects.filter(
recipient_id=user.id,
unread=True,
deleted=False,
verb="procurement_item_commented",
).filter(Q(data__item_id=item_id) | Q(data__item_id=str(item_id)))
return self._mark_queryset_as_read(user_id=user.id, queryset=queryset)
def _mark_queryset_as_read(
self,
*,
user_id: int,
queryset,
) -> ProcurementNotificationReadResult:
notification_ids = list(queryset.values_list("id", flat=True))
if not notification_ids:
return ProcurementNotificationReadResult(
notification_ids=[],
count=0,
)
read_at = timezone.now()
count = Notification.objects.filter(
id__in=notification_ids,
).update(
unread=False,
timestamp_read=read_at,
)
invalidate_unread_summary(user_id)
def notify_after_commit():
invalidate_unread_summary(user_id)
send_notifications_read_all_event(user_id, notification_ids)
transaction.on_commit(notify_after_commit)
return ProcurementNotificationReadResult(
notification_ids=notification_ids,
count=count,
)
def _get_unread_queryset(
self,
*,
user_id: int,
procurement_request: ProcurementRequest,
):
request_content_type = ContentType.objects.get_for_model(
ProcurementRequest,
)
request_id = procurement_request.id
request_id_text = str(request_id)
request_filter = (
Q(data__request_id=request_id)
| Q(data__request_id=request_id_text)
| Q(
target_content_type=request_content_type,
target_object_id=request_id_text,
)
| Q(
action_object_content_type=request_content_type,
action_object_object_id=request_id_text,
)
)
return (
Notification.objects.filter(
recipient_id=user_id,
unread=True,
deleted=False,
)
.filter(self.procurement_verb_filter)
.filter(request_filter)
.distinct()
)