from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from apps.core.decorators import block_source_user, hospital_admin_required from .models import Department, Hospital, Organization, Patient, Staff, StaffSection, StaffSubsection from .forms import StaffForm @block_source_user @login_required def hospital_list(request): """Hospitals list view""" queryset = Hospital.objects.all() # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(id=user.hospital.id) # Apply filters status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(name_ar__icontains=search_query) | Q(code__icontains=search_query) ) # Ordering queryset = queryset.order_by("name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) context = { "page_obj": page_obj, "hospitals": page_obj.object_list, "filters": request.GET, } return render(request, "organizations/hospital_list.html", context) @block_source_user @login_required def department_list(request): """Departments list view""" queryset = Department.objects.select_related("hospital", "manager") # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(hospital=user.hospital) # Apply filters hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(hospital_id=hospital_filter) status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(name_ar__icontains=search_query) | Q(code__icontains=search_query) ) # Ordering queryset = queryset.order_by("hospital", "name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get hospitals for filter hospitals = Hospital.objects.filter(status="active") if not user.is_px_admin() and user.hospital: hospitals = hospitals.filter(id=user.hospital.id) context = { "page_obj": page_obj, "departments": page_obj.object_list, "hospitals": hospitals, "filters": request.GET, } return render(request, "organizations/department_list.html", context) @block_source_user @login_required def staff_list(request): """Staff list view - filtered by tenant hospital""" queryset = Staff.objects.select_related("hospital", "department", "user") # Always filter by tenant_hospital (set by TenantMiddleware) # This handles both PX admins (with selected hospital) and regular users if request.tenant_hospital: queryset = queryset.filter(hospital=request.tenant_hospital) # Apply filters department_filter = request.GET.get("department") if department_filter: queryset = queryset.filter(department_id=department_filter) status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) staff_type_filter = request.GET.get("staff_type") if staff_type_filter: queryset = queryset.filter(staff_type=staff_type_filter) # is_head filter is_head_filter = request.GET.get("is_head") if is_head_filter: if is_head_filter.lower() == "true": queryset = queryset.filter(is_head=True) elif is_head_filter.lower() == "false": queryset = queryset.filter(is_head=False) # Filter by department ForeignKey department_filter = request.GET.get("department") if department_filter: queryset = queryset.filter(department_id=department_filter) section_filter = request.GET.get("section") if section_filter: queryset = queryset.filter(section__icontains=section_filter) subsection_filter = request.GET.get("subsection") if subsection_filter: queryset = queryset.filter(subsection__icontains=subsection_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(first_name__icontains=search_query) | Q(last_name__icontains=search_query) | Q(employee_id__icontains=search_query) | Q(license_number__icontains=search_query) | Q(specialization__icontains=search_query) | Q(job_title__icontains=search_query) ) # Ordering queryset = queryset.order_by("last_name", "first_name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get departments for filter dropdown (from current hospital context) if request.tenant_hospital: departments = Department.objects.filter(hospital=request.tenant_hospital, status="active").order_by("name") else: departments = Department.objects.filter(status="active").order_by("name") # Get unique values for section/subsection filters base_queryset = Staff.objects.select_related("hospital", "department", "user") if request.tenant_hospital: base_queryset = base_queryset.filter(hospital=request.tenant_hospital) sections = base_queryset.exclude(section="").values_list("section", flat=True).distinct().order_by("section") subsections = ( base_queryset.exclude(subsection="").values_list("subsection", flat=True).distinct().order_by("subsection") ) context = { "staff": page_obj, "filters": request.GET, "departments": departments, "sections": sections, "subsections": subsections, } return render(request, "organizations/staff_list.html", context) @block_source_user @login_required def organization_list(request): """Organizations list view""" queryset = Organization.objects.all() # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital and user.hospital.organization: queryset = queryset.filter(id=user.hospital.organization.id) # Apply filters status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) city_filter = request.GET.get("city") if city_filter: queryset = queryset.filter(city__icontains=city_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(name_ar__icontains=search_query) | Q(code__icontains=search_query) | Q(license_number__icontains=search_query) ) # Ordering queryset = queryset.order_by("name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) context = { "page_obj": page_obj, "organizations": page_obj.object_list, "filters": request.GET, } return render(request, "organizations/organization_list.html", context) @block_source_user @login_required def organization_detail(request, pk): """Organization detail view""" organization = Organization.objects.get(pk=pk) # Apply RBAC filters user = request.user if not user.is_px_admin(): if user.hospital and user.hospital.organization: if organization.id != user.hospital.organization.id: # User doesn't have access to this organization from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to view this organization") else: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to view this organization") hospitals = organization.hospitals.all() context = { "organization": organization, "hospitals": hospitals, } return render(request, "organizations/organization_detail.html", context) @block_source_user @login_required def organization_create(request): """Create organization view""" # Only PX Admins can create organizations user = request.user if not user.is_px_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("Only PX Admins can create organizations") if request.method == "POST": name = request.POST.get("name") name_ar = request.POST.get("name_ar") code = request.POST.get("code") address = request.POST.get("address", "") city = request.POST.get("city", "") phone = request.POST.get("phone", "") email = request.POST.get("email", "") website = request.POST.get("website", "") license_number = request.POST.get("license_number", "") status = request.POST.get("status", "active") if name and code: organization = Organization.objects.create( name=name, name_ar=name_ar or name, code=code, address=address, city=city, phone=phone, email=email, website=website, license_number=license_number, status=status, ) # Redirect to organization detail from django.shortcuts import redirect return redirect("organizations:organization_detail", pk=organization.id) return render(request, "organizations/organization_form.html") @block_source_user @login_required def patient_list(request): """Patients list view""" queryset = Patient.objects.select_related("primary_hospital") # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(primary_hospital=user.hospital) # Apply filters hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(primary_hospital_id=hospital_filter) status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(mrn__icontains=search_query) | Q(first_name__icontains=search_query) | Q(last_name__icontains=search_query) | Q(national_id__icontains=search_query) | Q(phone__icontains=search_query) ) # Ordering queryset = queryset.order_by("last_name", "first_name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get hospitals for filter hospitals = Hospital.objects.filter(status="active") if not user.is_px_admin() and user.hospital: hospitals = hospitals.filter(id=user.hospital.id) context = { "page_obj": page_obj, "patients": page_obj.object_list, "hospitals": hospitals, "filters": request.GET, } return render(request, "organizations/patient_list.html", context) @block_source_user @login_required def staff_detail(request, pk): """Staff detail view""" staff = get_object_or_404(Staff.objects.select_related("user", "hospital", "department"), pk=pk) # Apply RBAC filters user = request.user if not user.is_px_admin() and staff.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to view this staff member") context = { "staff": staff, } return render(request, "organizations/staff_detail.html", context) @block_source_user @login_required def staff_create(request): """Create staff view""" # Only PX Admins and Hospital Admins can create staff user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to create staff") if request.method == "POST": form = StaffForm(request.POST, request=request) if form.is_valid(): staff = form.save(commit=False) # Handle user account creation create_user = request.POST.get("create_user") == "on" if create_user and not staff.user and staff.email: from .services import StaffService try: role = StaffService.get_staff_type_role(staff.staff_type) user_account, was_created, password = StaffService.create_user_for_staff( staff, role=role, request=request ) if was_created and password: try: StaffService.send_credentials_email(staff, password, request) messages.success(request, "Staff member created and credentials email sent successfully.") except Exception as e: messages.warning(request, f"Staff member created but email sending failed: {str(e)}") elif not was_created: messages.success(request, "Existing user account linked successfully.") except Exception as e: messages.error(request, f"Staff member created but user account creation failed: {str(e)}") staff.save() # Send invitation email if requested if create_user and staff.user and request.POST.get("send_email") != "false": from .services import StaffService try: password = StaffService.generate_password() staff.user.set_password(password) staff.user.save() StaffService.send_credentials_email(staff, password, request) messages.success(request, "Credentials email sent successfully.") except Exception as e: messages.warning(request, f"Email sending failed: {str(e)}") messages.success(request, "Staff member created successfully.") return redirect("organizations:staff_detail", pk=staff.id) else: form = StaffForm(request=request) context = { "form": form, } return render(request, "organizations/staff_form.html", context) @block_source_user @login_required def staff_update(request, pk): """Update staff view""" staff = get_object_or_404(Staff.objects.select_related("user"), pk=pk) # Apply RBAC filters user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to update this staff member") if user.is_hospital_admin() and staff.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to update this staff member") if request.method == "POST": form = StaffForm(request.POST, instance=staff) if form.is_valid(): staff = form.save(commit=False) # Handle user account creation create_user = request.POST.get("create_user") == "on" if create_user and not staff.user and staff.email: from .services import StaffService try: role = StaffService.get_staff_type_role(staff.staff_type) user_account, was_created, password = StaffService.create_user_for_staff( staff, role=role, request=request ) if was_created and password: try: StaffService.send_credentials_email(staff, password, request) messages.success(request, "User account created and credentials email sent.") except Exception as e: messages.warning(request, f"User account created but email sending failed: {str(e)}") elif not was_created: messages.success(request, "Existing user account linked successfully.") except Exception as e: messages.error(request, f"User account creation failed: {str(e)}") staff.save() messages.success(request, "Staff member updated successfully.") return redirect("organizations:staff_detail", pk=staff.id) else: form = StaffForm(instance=staff, request=request) context = { "form": form, "staff": staff, } return render(request, "organizations/staff_form.html", context) @block_source_user @login_required def staff_hierarchy(request): """ Staff hierarchy tree view Shows organizational structure based on report_to relationships """ queryset = Staff.objects.select_related("hospital", "department", "report_to") # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(hospital=user.hospital) # Apply filters hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(hospital_id=hospital_filter) department_filter = request.GET.get("department") if department_filter: queryset = queryset.filter(department_id=department_filter) # Search functionality search_query = request.GET.get("search") search_result = None if search_query: try: search_result = Staff.objects.get( Q(employee_id__iexact=search_query) | Q(first_name__icontains=search_query) | Q(last_name__icontains=search_query) ) # If search result exists and user has access, start hierarchy from that staff if search_result and (user.is_px_admin() or search_result.hospital == user.hospital): queryset = Staff.objects.filter(Q(id=search_result.id) | Q(hospital=search_result.hospital)) except Staff.DoesNotExist: pass # Build hierarchy structure def build_hierarchy(staff_list, parent=None, level=0): """Recursively build hierarchy tree""" result = [] for staff in staff_list: if staff.report_to == parent: node = { "staff": staff, "level": level, "direct_reports": build_hierarchy(staff_list, staff, level + 1), "has_children": bool(staff.direct_reports.exists()), } result.append(node) return result # Get all staff for the current filter all_staff = list(queryset) # If searching, build hierarchy from search result up if search_result: # Get all managers up the chain manager_chain = [] current = search_result.report_to while current: if current in all_staff: manager_chain.insert(0, current) current = current.report_to # Add search result to chain if search_result not in manager_chain: manager_chain.append(search_result) # Build hierarchy for managers and their reports hierarchy = build_hierarchy(all_staff, parent=None) # Find and highlight search result def find_and_mark(node, target_id, path=None): if path is None: path = [] if node["staff"].id == target_id: node["is_search_result"] = True node["search_path"] = path + [node["staff"].id] return node for child in node["direct_reports"]: result = find_and_mark(child, target_id, path + [node["staff"].id]) if result: return result return None search_result_node = None for root in hierarchy: result = find_and_mark(root, search_result.id) if result: search_result_node = result break else: # Build hierarchy starting from top-level (no report_to) hierarchy = build_hierarchy(all_staff, parent=None) # Get hospitals for filter hospitals = Hospital.objects.filter(status="active") if not user.is_px_admin() and user.hospital: hospitals = hospitals.filter(id=user.hospital.id) # Get departments for filter departments = Department.objects.filter(status="active") if not user.is_px_admin() and user.hospital: departments = departments.filter(hospital=user.hospital) # Calculate statistics total_staff = queryset.count() top_managers = len(hierarchy) context = { "hierarchy": hierarchy, "hospitals": hospitals, "departments": departments, "filters": request.GET, "total_staff": total_staff, "top_managers": top_managers, "search_result": search_result, } return render(request, "organizations/staff_hierarchy.html", context) @block_source_user @login_required def staff_hierarchy_d3(request): """ Staff hierarchy D3 visualization view Shows interactive organizational chart using D3.js """ # Get hospitals for filter (used by client-side filters) hospitals = Hospital.objects.filter(status="active") user = request.user if not user.is_px_admin() and user.hospital: hospitals = hospitals.filter(id=user.hospital.id) context = { "hospitals": hospitals, } return render(request, "organizations/staff_hierarchy_d3.html", context) # ==================== Department CRUD ==================== @block_source_user @login_required def department_create(request): """Create department view""" user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to create departments") if request.method == "POST": name = request.POST.get("name") name_ar = request.POST.get("name_ar", "") code = request.POST.get("code") hospital_id = request.POST.get("hospital") status = request.POST.get("status", "active") phone = request.POST.get("phone", "") email = request.POST.get("email", "") location = request.POST.get("location", "") if name and code and hospital_id: # RBAC: Non-admins can only create in their hospital if not user.is_px_admin(): if str(user.hospital_id) != hospital_id: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only create departments in your hospital") department = Department.objects.create( name=name, name_ar=name_ar or name, code=code, hospital_id=hospital_id, status=status, phone=phone, email=email, location=location, ) messages.success(request, "Department created successfully.") return redirect("organizations:department_list") # Get hospitals for dropdown hospitals = Hospital.objects.filter(status="active") if not user.is_px_admin() and user.hospital: hospitals = hospitals.filter(id=user.hospital.id) context = { "hospitals": hospitals, } return render(request, "organizations/department_form.html", context) @block_source_user @login_required def department_update(request, pk): """Update department view""" department = get_object_or_404(Department, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to update departments") if not user.is_px_admin() and department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only update departments in your hospital") if request.method == "POST": department.name = request.POST.get("name", department.name) department.name_ar = request.POST.get("name_ar", "") department.code = request.POST.get("code", department.code) department.status = request.POST.get("status", department.status) department.phone = request.POST.get("phone", "") department.email = request.POST.get("email", "") department.location = request.POST.get("location", "") department.save() messages.success(request, "Department updated successfully.") return redirect("organizations:department_list") context = { "department": department, } return render(request, "organizations/department_form.html", context) @block_source_user @login_required def department_delete(request, pk): """Delete department view""" department = get_object_or_404(Department, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to delete departments") if not user.is_px_admin() and department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only delete departments in your hospital") if request.method == "POST": # Check for linked staff staff_count = department.staff.count() if staff_count > 0: messages.error(request, f"Cannot delete department. {staff_count} staff members are assigned to it.") return redirect("organizations:department_list") department.delete() messages.success(request, "Department deleted successfully.") return redirect("organizations:department_list") context = { "department": department, } return render(request, "organizations/department_confirm_delete.html", context) # ==================== Staff Section CRUD ==================== @block_source_user @login_required def section_list(request): """Sections list view""" queryset = StaffSection.objects.select_related("department", "department__hospital", "head") # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(department__hospital=user.hospital) # Apply filters department_filter = request.GET.get("department") if department_filter: queryset = queryset.filter(department_id=department_filter) status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(name_ar__icontains=search_query) | Q(code__icontains=search_query) ) # Ordering queryset = queryset.order_by("department__name", "name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get departments for filter departments = Department.objects.filter(status="active") if not user.is_px_admin() and user.hospital: departments = departments.filter(hospital=user.hospital) context = { "page_obj": page_obj, "sections": page_obj.object_list, "departments": departments, "filters": request.GET, } return render(request, "organizations/section_list.html", context) @block_source_user @login_required def section_create(request): """Create section view""" user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to create sections") if request.method == "POST": name = request.POST.get("name") name_ar = request.POST.get("name_ar", "") code = request.POST.get("code", "") department_id = request.POST.get("department") status = request.POST.get("status", "active") head_id = request.POST.get("head") if name and department_id: department = get_object_or_404(Department, pk=department_id) # RBAC check if not user.is_px_admin() and department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only create sections in your hospital") section = StaffSection.objects.create( name=name, name_ar=name_ar or name, code=code, department=department, status=status, head_id=head_id if head_id else None, ) messages.success(request, "Section created successfully.") return redirect("organizations:section_list") # Get departments for dropdown departments = Department.objects.filter(status="active") if not user.is_px_admin() and user.hospital: departments = departments.filter(hospital=user.hospital) context = { "departments": departments, } return render(request, "organizations/section_form.html", context) @block_source_user @login_required def section_update(request, pk): """Update section view""" section = get_object_or_404(StaffSection, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to update sections") if not user.is_px_admin() and section.department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only update sections in your hospital") if request.method == "POST": section.name = request.POST.get("name", section.name) section.name_ar = request.POST.get("name_ar", "") section.code = request.POST.get("code", "") section.status = request.POST.get("status", section.status) head_id = request.POST.get("head") section.head_id = head_id if head_id else None section.save() messages.success(request, "Section updated successfully.") return redirect("organizations:section_list") # Get departments for dropdown departments = Department.objects.filter(status="active") if not user.is_px_admin() and user.hospital: departments = departments.filter(hospital=user.hospital) context = { "section": section, "departments": departments, } return render(request, "organizations/section_form.html", context) @block_source_user @login_required def section_delete(request, pk): """Delete section view""" section = get_object_or_404(StaffSection, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to delete sections") if not user.is_px_admin() and section.department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only delete sections in your hospital") if request.method == "POST": subsection_count = section.subsections.count() if subsection_count > 0: messages.error(request, f"Cannot delete section. {subsection_count} subsections are linked to it.") return redirect("organizations:section_list") section.delete() messages.success(request, "Section deleted successfully.") return redirect("organizations:section_list") context = { "section": section, } return render(request, "organizations/section_confirm_delete.html", context) # ==================== Staff Subsection CRUD ==================== @block_source_user @login_required def subsection_list(request): """Subsections list view""" queryset = StaffSubsection.objects.select_related( "section", "section__department", "section__department__hospital", "head" ) # Apply RBAC filters user = request.user if not user.is_px_admin() and user.hospital: queryset = queryset.filter(section__department__hospital=user.hospital) # Apply filters section_filter = request.GET.get("section") if section_filter: queryset = queryset.filter(section_id=section_filter) department_filter = request.GET.get("department") if department_filter: queryset = queryset.filter(section__department_id=department_filter) status_filter = request.GET.get("status") if status_filter: queryset = queryset.filter(status=status_filter) # Search search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(name_ar__icontains=search_query) | Q(code__icontains=search_query) ) # Ordering queryset = queryset.order_by("section__name", "name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get sections and departments for filter departments = Department.objects.filter(status="active") sections = StaffSection.objects.filter(status="active") if not user.is_px_admin() and user.hospital: departments = departments.filter(hospital=user.hospital) sections = sections.filter(department__hospital=user.hospital) context = { "page_obj": page_obj, "subsections": page_obj.object_list, "sections": sections, "departments": departments, "filters": request.GET, } return render(request, "organizations/subsection_list.html", context) @block_source_user @login_required def subsection_create(request): """Create subsection view""" user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to create subsections") if request.method == "POST": name = request.POST.get("name") name_ar = request.POST.get("name_ar", "") code = request.POST.get("code", "") section_id = request.POST.get("section") status = request.POST.get("status", "active") head_id = request.POST.get("head") if name and section_id: section = get_object_or_404(StaffSection, pk=section_id) # RBAC check if not user.is_px_admin() and section.department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only create subsections in your hospital") subsection = StaffSubsection.objects.create( name=name, name_ar=name_ar or name, code=code, section=section, status=status, head_id=head_id if head_id else None, ) messages.success(request, "Subsection created successfully.") return redirect("organizations:subsection_list") # Get sections for dropdown sections = StaffSection.objects.filter(status="active").select_related("department") if not user.is_px_admin() and user.hospital: sections = sections.filter(department__hospital=user.hospital) context = { "sections": sections, } return render(request, "organizations/subsection_form.html", context) @block_source_user @login_required def subsection_update(request, pk): """Update subsection view""" subsection = get_object_or_404(StaffSubsection, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to update subsections") if not user.is_px_admin() and subsection.section.department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only update subsections in your hospital") if request.method == "POST": subsection.name = request.POST.get("name", subsection.name) subsection.name_ar = request.POST.get("name_ar", "") subsection.code = request.POST.get("code", "") subsection.status = request.POST.get("status", subsection.status) head_id = request.POST.get("head") subsection.head_id = head_id if head_id else None subsection.save() messages.success(request, "Subsection updated successfully.") return redirect("organizations:subsection_list") # Get sections for dropdown sections = StaffSection.objects.filter(status="active").select_related("department") if not user.is_px_admin() and user.hospital: sections = sections.filter(department__hospital=user.hospital) context = { "subsection": subsection, "sections": sections, } return render(request, "organizations/subsection_form.html", context) @block_source_user @login_required def subsection_delete(request, pk): """Delete subsection view""" subsection = get_object_or_404(StaffSubsection, pk=pk) user = request.user if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to delete subsections") if not user.is_px_admin() and subsection.section.department.hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You can only delete subsections in your hospital") if request.method == "POST": subsection.delete() messages.success(request, "Subsection deleted successfully.") return redirect("organizations:subsection_list") context = { "subsection": subsection, } return render(request, "organizations/subsection_confirm_delete.html", context) @block_source_user @login_required def patient_detail(request, pk): """Patient detail view""" patient = get_object_or_404(Patient.objects.select_related("primary_hospital"), pk=pk) # Apply RBAC filters user = request.user if not user.is_px_admin() and patient.primary_hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to view this patient") # Get patient's survey history from apps.surveys.models import SurveyInstance surveys = ( SurveyInstance.objects.filter(patient=patient).select_related("survey_template").order_by("-created_at")[:10] ) context = { "patient": patient, "surveys": surveys, } return render(request, "organizations/patient_detail.html", context) @block_source_user @login_required def patient_create(request): """Create patient view""" user = request.user # Only PX Admins and Hospital Admins can create patients if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to create patients") if request.method == "POST": form = PatientForm(user, request.POST) if form.is_valid(): patient = form.save() messages.success(request, f"Patient {patient.get_full_name()} created successfully.") return redirect("organizations:patient_detail", pk=patient.pk) else: form = PatientForm(user) context = { "form": form, "title": _("Create Patient"), } return render(request, "organizations/patient_form.html", context) @block_source_user @login_required def patient_update(request, pk): """Update patient view""" patient = get_object_or_404(Patient, pk=pk) user = request.user # Apply RBAC filters if not user.is_px_admin() and patient.primary_hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to edit this patient") # Only PX Admins and Hospital Admins can update patients if not user.is_px_admin() and not user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to edit patients") if request.method == "POST": form = PatientForm(user, request.POST, instance=patient) if form.is_valid(): patient = form.save() messages.success(request, f"Patient {patient.get_full_name()} updated successfully.") return redirect("organizations:patient_detail", pk=patient.pk) else: form = PatientForm(user, instance=patient) context = { "form": form, "patient": patient, "title": _("Edit Patient"), } return render(request, "organizations/patient_form.html", context) @block_source_user @login_required def patient_delete(request, pk): """Delete patient view""" patient = get_object_or_404(Patient, pk=pk) user = request.user # Apply RBAC filters if not user.is_px_admin() and patient.primary_hospital != user.hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden("You don't have permission to delete this patient") # Only PX Admins can delete patients if not user.is_px_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden("Only PX Admins can delete patients") if request.method == "POST": patient_name = patient.get_full_name() patient.delete() messages.success(request, f"Patient {patient_name} deleted successfully.") return redirect("organizations:patient_list") context = { "patient": patient, } return render(request, "organizations/patient_confirm_delete.html", context)