1271 lines
43 KiB
Python
1271 lines
43 KiB
Python
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)
|