feat: dodaj bilješke widget i admin kalendar/notifikacije
Uveden je novi Notes drawer s kalendar integracijom, zajednički DRY left-slide mehanizam te međusobno isključivo prikazivanje s Kalendar widgetom. Backend i frontend su prošireni za servisne bilješke (uključujući slanje na više servisera), dodan je users/servicers endpoint, te su uvedene warning notifikacije kada serviser ima više od 2 zadatka isti dan. U admin su dodane stavke za Bilješke i zaseban Kalendar zadataka (proxy TaskCalendar) radi lakšeg operativnog pregleda. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
# backend/modules/task_management/services.py
|
||||
|
||||
from django.db import transaction
|
||||
from django.db import transaction, models
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.contrib.auth import get_user_model
|
||||
import logging
|
||||
|
||||
from .models import Task, TaskTemplate, TaskWorkEntry
|
||||
@@ -10,6 +11,21 @@ from .exceptions import OpenWorkOrderBlockingTaskClose
|
||||
from modules.fleet.models import VehicleServiceRecord
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def _task_overload_recipients(task):
|
||||
recipients = []
|
||||
if task.assigned_to_id:
|
||||
recipients.append(task.assigned_to)
|
||||
supervisors = User.objects.filter(is_active=True).filter(
|
||||
models.Q(is_staff=True) | (models.Q(is_team_member=True) & models.Q(is_serviser=False))
|
||||
)
|
||||
recipients.extend(supervisors)
|
||||
unique = {}
|
||||
for recipient in recipients:
|
||||
unique[str(recipient.id)] = recipient
|
||||
return list(unique.values())
|
||||
|
||||
|
||||
class TaskService:
|
||||
@@ -53,6 +69,7 @@ class TaskService:
|
||||
|
||||
with transaction.atomic():
|
||||
entry.save()
|
||||
TaskService._notify_if_servicer_overloaded(entry)
|
||||
if template:
|
||||
TaskService._create_work_entries_from_template(task=entry, template=template)
|
||||
TaskService._create_service_records_from_template(task=entry, template=template, user=user)
|
||||
@@ -60,6 +77,49 @@ class TaskService:
|
||||
logger.info(f"Zadatak uspješno kreiran: {entry.id}")
|
||||
return entry
|
||||
|
||||
@staticmethod
|
||||
def _notify_if_servicer_overloaded(entry: Task):
|
||||
if not entry.assigned_to_id or not entry.scheduled_date:
|
||||
return
|
||||
if not getattr(entry.assigned_to, 'is_serviser', False):
|
||||
return
|
||||
|
||||
task_count = Task.objects.filter(
|
||||
is_active=True,
|
||||
assigned_to=entry.assigned_to,
|
||||
scheduled_date=entry.scheduled_date,
|
||||
status__in=('aktivan', 'servis', 'spreman_za_zavrsetak'),
|
||||
).count()
|
||||
if task_count <= 2:
|
||||
return
|
||||
|
||||
from modules.fleet.services import NotificationService
|
||||
|
||||
schedule_label = entry.scheduled_date.strftime('%d.%m.%Y')
|
||||
title = f"Preopterećenje rasporeda: {entry.assigned_to.get_full_name() or entry.assigned_to.email}"
|
||||
message = (
|
||||
f"Serviseru {entry.assigned_to.get_full_name() or entry.assigned_to.email} "
|
||||
f"je dodijeljeno {task_count} zadatka za {schedule_label}. "
|
||||
f"Sustav je dopustio i dodatni zadatak."
|
||||
)
|
||||
metadata = {
|
||||
"entity_type": "task_overload",
|
||||
"assigned_to_id": str(entry.assigned_to_id),
|
||||
"task_id": str(entry.id),
|
||||
"scheduled_date": entry.scheduled_date.isoformat(),
|
||||
"task_count": task_count,
|
||||
"section": "dashboard",
|
||||
}
|
||||
for recipient in _task_overload_recipients(entry):
|
||||
NotificationService.create_notification(
|
||||
recipient=recipient,
|
||||
title=title,
|
||||
message=message,
|
||||
level='warning',
|
||||
send_email=False,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _create_work_entries_from_template(*, task: Task, template: TaskTemplate):
|
||||
template_entries = list(template.entries.filter(is_active=True).order_by('sort_order', 'created_at')[:10])
|
||||
|
||||
Reference in New Issue
Block a user