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__champion", "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) # Must be activated (in_progress) before it can be sent to a department if complaint.status == "open": messages.error(request, _("Activate this complaint before sending it to a department.")) 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__champion", "department__manager" ).all() for dept_inv in involved_departments: dept = dept_inv.department if not dept: continue dept_key = str(dept.id) if dept_key not in department_groups: champion = dept.champion champion_email = champion.email or (champion.user.email if champion and champion.user else None) if champion 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) if champion else None, "champion_name": champion.get_full_name() if champion else None, "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: dept_key = str(dept.id) if dept_key in department_groups: department_groups[dept_key]["staff_list"].append(entry) else: champion = dept.champion champion_email = champion.email or (champion.user.email if champion and champion.user else None) if champion 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) if champion else None, "champion_name": champion.get_full_name() if champion else None, "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) if not department_groups and not involved_staff.exists(): if not involved_departments.exists(): messages.error(request, _("No departments are involved in this complaint. Please add a department first.")) 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: contact_person_id = request.POST.get(f"contact_person_{dept_id}", "") if contact_person_id: from apps.organizations.models import Department as DeptModel dept_obj = DeptModel.objects.filter(pk=dept_id).first() if dept_obj: cinfo = dept_obj.is_valid_contact_person(contact_person_id) if cinfo: dept_info["contact_person_id"] = contact_person_id dept_info["contact_person_name"] = cinfo["name"] dept_info["contact_person_role"] = cinfo["role_label"] dept_info["contact_person_email"] = cinfo["email"] dept_info["contact_person_staff"] = cinfo["staff"] preview_depts.append(dept_info) contact_person_map = { d["department_id"]: d.get("contact_person_id", "") for d in preview_depts if d.get("contact_person_id") } 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, "contact_person_map": contact_person_map, }, ) from django.contrib.sites.shortcuts import get_current_site contact_person_map = {} for dept_id in selected_dept_ids: cp_id = request.POST.get(f"contact_person_{dept_id}", "") if cp_id: contact_person_map[dept_id] = cp_id site = get_current_site(request) results = ComplaintService.send_to_department( complaint, department_groups, selected_dept_ids, request_message, request.user, site.domain, request=request, contact_person_map=contact_person_map, ) if not complaint.forwarded_to_dept_at: complaint.forwarded_to_dept_at = timezone.now() complaint.save(update_fields=["forwarded_to_dept_at"]) 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, }, )