HH/apps/organizations/ui_views.py
2026-02-22 08:35:53 +03:00

1215 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 .models import Department, Hospital, Organization, Patient, Staff, StaffSection, StaffSubsection
from .forms import StaffForm
@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)
@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)
@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)
@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)
@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)
@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')
@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)
@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)
@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)
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(user=request.user)
context = {
'form': form,
}
return render(request, 'organizations/staff_form.html', context)
@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, user=request.user)
context = {
'form': form,
'staff': staff,
}
return render(request, 'organizations/staff_form.html', context)
@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)
@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 ====================
@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)
@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)
@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 ====================
@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)
@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)
@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)
@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 ====================
@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)
@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)
@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)
@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)
@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)
@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)
@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)
@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)