214 lines
8.4 KiB
Python
214 lines
8.4 KiB
Python
from django.contrib import messages
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.http import HttpResponseForbidden
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext as _
|
|
from django.views.decorators.http import require_http_methods
|
|
|
|
from apps.core.services import AuditService
|
|
from apps.organizations.models import Staff
|
|
|
|
from .models import Complaint, ComplaintExplanation, ComplaintStatus
|
|
from .services.complaint_service import ComplaintService, ComplaintServiceError
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET", "POST"])
|
|
def send_to_department_form(request, pk):
|
|
complaint = get_object_or_404(
|
|
Complaint.objects.prefetch_related(
|
|
"involved_staff__staff__department",
|
|
"involved_staff__staff__report_to",
|
|
"involved_departments__department__respondent",
|
|
"involved_departments__department__manager",
|
|
),
|
|
pk=pk,
|
|
)
|
|
|
|
user = request.user
|
|
can_request = (
|
|
user.is_px_admin()
|
|
or user.is_hospital_admin()
|
|
or (user.is_department_manager() and complaint.department == user.department)
|
|
or (complaint.hospital == user.hospital)
|
|
)
|
|
|
|
if not can_request:
|
|
return HttpResponseForbidden(_("You don't have permission to request explanations."))
|
|
|
|
if not complaint.is_active_status:
|
|
messages.error(
|
|
request,
|
|
_(
|
|
"Cannot request explanation for complaint with status '{}'. Complaint must be Open, In Progress, or Partially Resolved."
|
|
).format(complaint.get_status_display()),
|
|
)
|
|
return redirect("complaints:complaint_detail", pk=complaint.pk)
|
|
|
|
involved_staff = complaint.involved_staff.select_related(
|
|
"staff", "staff__department", "staff__report_to"
|
|
).all()
|
|
|
|
department_groups = {}
|
|
ungrouped_staff = []
|
|
|
|
# Build department groups from involved_departments first
|
|
involved_departments = complaint.involved_departments.select_related(
|
|
"department__respondent", "department__manager"
|
|
).all()
|
|
|
|
for dept_inv in involved_departments:
|
|
dept = dept_inv.department
|
|
if not dept or not dept.respondent:
|
|
continue
|
|
|
|
dept_key = str(dept.id)
|
|
if dept_key not in department_groups:
|
|
champion = dept.respondent
|
|
champion_email = champion.email or (champion.user.email if champion.user else None)
|
|
dept_manager = dept.manager
|
|
department_groups[dept_key] = {
|
|
"department_id": dept_key,
|
|
"department_name": dept.get_localized_name(),
|
|
"champion": champion,
|
|
"champion_id": str(champion.id),
|
|
"champion_name": champion.get_full_name(),
|
|
"champion_email": champion_email,
|
|
"dept_manager": dept_manager,
|
|
"dept_manager_id": str(dept_manager.id) if dept_manager else None,
|
|
"dept_manager_name": dept_manager.get_full_name() if dept_manager else None,
|
|
"dept_manager_email": dept_manager.email if dept_manager else None,
|
|
"staff_list": [],
|
|
}
|
|
|
|
# Add involved staff to their department groups
|
|
for staff_inv in involved_staff:
|
|
staff = staff_inv.staff
|
|
dept = staff.department
|
|
entry = {
|
|
"staff_inv": staff_inv,
|
|
"staff": staff,
|
|
"staff_id": str(staff.id),
|
|
"staff_name": staff.get_full_name(),
|
|
"staff_email": staff.email or (staff.user.email if staff.user else None),
|
|
"role": staff_inv.get_role_display(),
|
|
}
|
|
|
|
if dept and dept.respondent:
|
|
dept_key = str(dept.id)
|
|
if dept_key in department_groups:
|
|
department_groups[dept_key]["staff_list"].append(entry)
|
|
else:
|
|
# This shouldn't happen if we built department_groups from involved_departments,
|
|
# but handle as fallback
|
|
champion = dept.respondent
|
|
champion_email = champion.email or (champion.user.email if champion.user else None)
|
|
dept_manager = dept.manager
|
|
department_groups[dept_key] = {
|
|
"department_id": dept_key,
|
|
"department_name": dept.get_localized_name(),
|
|
"champion": champion,
|
|
"champion_id": str(champion.id),
|
|
"champion_name": champion.get_full_name(),
|
|
"champion_email": champion_email,
|
|
"dept_manager": dept_manager,
|
|
"dept_manager_id": str(dept_manager.id) if dept_manager else None,
|
|
"dept_manager_name": dept_manager.get_full_name() if dept_manager else None,
|
|
"dept_manager_email": dept_manager.email if dept_manager else None,
|
|
"staff_list": [entry],
|
|
}
|
|
else:
|
|
ungrouped_staff.append(entry)
|
|
|
|
# Only show error if there are NO departments with champions AND no staff
|
|
if not department_groups and not involved_staff.exists():
|
|
messages.error(request, _("No staff members or departments are involved in this complaint."))
|
|
return redirect("complaints:complaint_detail", pk=complaint.pk)
|
|
|
|
if request.method == "POST":
|
|
action = request.POST.get("action", "send")
|
|
selected_dept_ids = request.POST.getlist("selected_departments")
|
|
request_message = request.POST.get("request_message", "").strip()
|
|
|
|
if not selected_dept_ids:
|
|
messages.error(request, _("Please select at least one department."))
|
|
return render(
|
|
request,
|
|
"complaints/send_to_department_form.html",
|
|
{
|
|
"complaint": complaint,
|
|
"department_groups": department_groups,
|
|
"ungrouped_staff": ungrouped_staff,
|
|
},
|
|
)
|
|
|
|
if action == "preview":
|
|
preview_depts = []
|
|
for dept_id in selected_dept_ids:
|
|
dept_info = department_groups.get(dept_id)
|
|
if dept_info:
|
|
preview_depts.append(dept_info)
|
|
|
|
return render(
|
|
request,
|
|
"complaints/send_to_department_preview.html",
|
|
{
|
|
"complaint": complaint,
|
|
"preview_depts": preview_depts,
|
|
"selected_dept_ids": selected_dept_ids,
|
|
"request_message": request_message,
|
|
},
|
|
)
|
|
|
|
from django.contrib.sites.shortcuts import get_current_site
|
|
|
|
site = get_current_site(request)
|
|
results = ComplaintService.send_to_department(
|
|
complaint,
|
|
department_groups,
|
|
selected_dept_ids,
|
|
request_message,
|
|
request.user,
|
|
site.domain,
|
|
request=request,
|
|
)
|
|
|
|
if results["champion_count"] == 0 and results["manager_count"] == 0:
|
|
if results["skipped_no_email"] > 0:
|
|
messages.warning(
|
|
request,
|
|
_(
|
|
"No explanation requests were sent. {} department(s) have champions without email addresses."
|
|
).format(results["skipped_no_email"]),
|
|
)
|
|
else:
|
|
messages.warning(
|
|
request, _("No explanation requests were sent. Please check department champion configuration.")
|
|
)
|
|
elif results["champion_count"] == 0 and results["manager_count"] > 0:
|
|
messages.warning(
|
|
request,
|
|
_(
|
|
"Only department manager notifications were sent ({}). Champion explanation requests could not be sent."
|
|
).format(results["manager_count"]),
|
|
)
|
|
else:
|
|
messages.success(
|
|
request,
|
|
_("Explanation requests sent! Champions: {}, Department managers notified: {}.").format(
|
|
results["champion_count"], results["manager_count"]
|
|
),
|
|
)
|
|
return redirect("complaints:complaint_detail", pk=complaint.pk)
|
|
|
|
return render(
|
|
request,
|
|
"complaints/send_to_department_form.html",
|
|
{
|
|
"complaint": complaint,
|
|
"department_groups": department_groups,
|
|
"ungrouped_staff": ungrouped_staff,
|
|
},
|
|
)
|