Marwan Alwali 0422966e14 update
2025-08-30 19:32:46 +03:00

2687 lines
95 KiB
Python

"""
Operating Theatre app views with healthcare-focused CRUD operations.
Implements appropriate access patterns for surgical and OR management workflows.
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import (
ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
)
from django.http import JsonResponse, HttpResponse
from django.db.models import Q, Count, Avg, Sum, F
from django.utils import timezone
from django.contrib import messages
from django.urls import reverse_lazy, reverse
from django.core.paginator import Paginator
from django.template.loader import render_to_string
from datetime import datetime, timedelta, date
import json
from core.utils import AuditLogger
from .models import (
OperatingRoom, ORBlock, SurgicalCase, SurgicalNote,
EquipmentUsage, SurgicalNoteTemplate
)
from .forms import (
OperatingRoomForm, ORBlockForm, SurgicalCaseForm, SurgicalNoteForm,
EquipmentUsageForm, SurgicalNoteTemplateForm
)
# ============================================================================
# DASHBOARD AND OVERVIEW VIEWS
# ============================================================================
class OperatingTheatreDashboardView(LoginRequiredMixin, TemplateView):
"""
Main operating theatre dashboard with key metrics and recent activity.
"""
template_name = 'operating_theatre/dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
today = timezone.now().date()
# Dashboard statistics
context.update({
'total_rooms': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True
).count(),
'rooms_available': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True,
status='AVAILABLE'
).count(),
'rooms_in_use': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True,
status='IN_USE'
).count(),
'rooms_maintenance': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True,
status='MAINTENANCE'
).count(),
'cases_today': SurgicalCase.objects.filter(
admission__tenant=tenant,
scheduled_start__date=today
).count(),
'cases_in_progress': SurgicalCase.objects.filter(
admission__tenant=tenant,
status='IN_PROGRESS'
).count(),
'cases_completed_today': SurgicalCase.objects.filter(
admission__tenant=tenant,
actual_end__date=today,
status='COMPLETED'
).count(),
'emergency_cases_today': SurgicalCase.objects.filter(
admission__tenant=tenant,
scheduled_start__date=today,
case_type='EMERGENCY'
).count(),
'blocks_today': ORBlock.objects.filter(
operating_room__tenant=tenant,
date=today
).count(),
'equipment_in_use': EquipmentUsage.objects.filter(
surgical_case__admission__tenant=tenant,
# status='IN_USE'
).count(),
'notes_pending': SurgicalNote.objects.filter(
surgical_case__admission__tenant=tenant,
status='DRAFT'
).count(),
})
# Recent surgical cases
context['recent_cases'] = SurgicalCase.objects.filter(
admission__tenant=tenant
).select_related(
'patient', 'primary_surgeon', 'or_block__operating_room'
).order_by('-scheduled_start')[:10]
# Today's schedule
context['todays_schedule'] = SurgicalCase.objects.filter(
admission__tenant=tenant,
scheduled_start__date=today
).select_related(
'patient', 'primary_surgeon', 'or_block__operating_room'
).order_by('scheduled_start')
# Room utilization
# context['room_utilization'] = OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True
# ).annotate(
# cases_today=Count(
# 'or_block__surgical_cases',
# filter=Q(surgical_cases__scheduled_start__date=today)
# )
# ).order_by('room_number')
return context
# ============================================================================
# OPERATING ROOM VIEWS (FULL CRUD - Master Data)
# ============================================================================
class OperatingRoomListView(LoginRequiredMixin, ListView):
"""
List all operating rooms with filtering and search.
"""
model = OperatingRoom
template_name = 'operating_theatre/rooms/operating_room_list.html'
context_object_name = 'operating_rooms'
paginate_by = 25
def get_queryset(self):
queryset = OperatingRoom.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(room_number__icontains=search) |
Q(room_name__icontains=search) |
Q(location__icontains=search)
)
# Filter by room type
room_type = self.request.GET.get('room_type')
if room_type:
queryset = queryset.filter(room_type=room_type)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by floor
floor = self.request.GET.get('floor')
if floor:
queryset = queryset.filter(floor=floor)
# Filter by active status
active_only = self.request.GET.get('active_only')
if active_only:
queryset = queryset.filter(is_active=True)
return queryset.order_by('room_number')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'room_types': OperatingRoom._meta.get_field('room_type').choices,
'statuses': OperatingRoom._meta.get_field('status').choices,
'search_query': self.request.GET.get('search', ''),
})
return context
class OperatingRoomDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about an operating room.
"""
model = OperatingRoom
template_name = 'operating_theatre/rooms/operating_room_detail.html'
context_object_name = 'operating_room'
def get_queryset(self):
return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
operating_room = self.object
today = timezone.now().date()
# Get today's cases for this room
context['todays_cases'] = operating_room.surgical_cases.filter(
scheduled_start_time__date=today
).select_related('patient', 'primary_surgeon').order_by('scheduled_start_time')
# Get recent cases
context['recent_cases'] = operating_room.surgical_cases.all().select_related(
'patient', 'primary_surgeon'
).order_by('-scheduled_start_time')[:10]
# Get equipment usage
context['equipment_usage'] = EquipmentUsage.objects.filter(
operating_room=operating_room,
tenant=self.request.user.tenant
).order_by('-start_time')[:10]
# Room statistics
context['room_stats'] = {
'total_cases': operating_room.surgical_cases.count(),
'cases_this_month': operating_room.surgical_cases.filter(
scheduled_start_time__month=timezone.now().month,
scheduled_start_time__year=timezone.now().year
).count(),
'average_case_duration': operating_room.surgical_cases.filter(
actual_end_time__isnull=False
).aggregate(
avg_duration=Avg(
F('actual_end_time') - F('actual_start_time')
)
)['avg_duration'],
}
return context
class OperatingRoomCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new operating room.
"""
model = OperatingRoom
form_class = OperatingRoomForm
template_name = 'operating_theatre/rooms/operating_room_form.html'
permission_required = 'operating_theatre.add_operatingroom'
success_url = reverse_lazy('operating_theatre:operating_room_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='OPERATING_ROOM_CREATED',
model='OperatingRoom',
object_id=str(self.object.id),
details={
'room_number': self.object.room_number,
'room_name': self.object.room_name,
'room_type': self.object.room_type
}
)
messages.success(self.request, f'Operating room "{self.object.room_number}" created successfully.')
return response
class OperatingRoomUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update an existing operating room.
"""
model = OperatingRoom
form_class = OperatingRoomForm
template_name = 'operating_theatre/rooms/operating_room_form.html'
permission_required = 'operating_theatre.change_operatingroom'
def get_queryset(self):
return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('operating_theatre:operating_room_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='OPERATING_ROOM_UPDATED',
model='OperatingRoom',
object_id=str(self.object.id),
details={
'room_number': self.object.room_number,
'changes': form.changed_data
}
)
messages.success(self.request, f'Operating room "{self.object.room_number}" updated successfully.')
return response
class OperatingRoomDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete an operating room (soft delete by deactivating).
"""
model = OperatingRoom
template_name = 'operating_theatre/rooms/operating_room_confirm_delete.html'
permission_required = 'operating_theatre.delete_operatingroom'
success_url = reverse_lazy('operating_theatre:operating_room_list')
def get_queryset(self):
return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Check if room has active cases
active_cases = self.object.surgical_cases.filter(
status__in=['SCHEDULED', 'IN_PROGRESS']
).count()
if active_cases > 0:
messages.error(
request,
f'Cannot deactivate room "{self.object.room_number}" - it has {active_cases} active cases.'
)
return redirect('operating_theatre:operating_room_detail', pk=self.object.pk)
# Soft delete by deactivating
self.object.is_active = False
self.object.status = 'OUT_OF_SERVICE'
self.object.save()
# Log the action
AuditLogger.log_event(
user=request.user,
action='OPERATING_ROOM_DEACTIVATED',
model='OperatingRoom',
object_id=str(self.object.id),
details={'room_number': self.object.room_number}
)
messages.success(request, f'Operating room "{self.object.room_number}" deactivated successfully.')
return redirect(self.success_url)
# ============================================================================
# SURGICAL NOTE TEMPLATE VIEWS (FULL CRUD - Master Data)
# ============================================================================
class SurgicalNoteTemplateListView(LoginRequiredMixin, ListView):
"""
List all surgical note templates with filtering and search.
"""
model = SurgicalNoteTemplate
template_name = 'operating_theatre/surgical_note_template_list.html'
context_object_name = 'surgical_note_templates'
paginate_by = 25
def get_queryset(self):
queryset = SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(template_name__icontains=search) |
Q(procedure_type__icontains=search) |
Q(specialty__icontains=search)
)
# Filter by specialty
specialty = self.request.GET.get('specialty')
if specialty:
queryset = queryset.filter(specialty=specialty)
# Filter by active status
active_only = self.request.GET.get('active_only')
if active_only:
queryset = queryset.filter(is_active=True)
return queryset.order_by('template_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'specialties': SurgicalNoteTemplate._meta.get_field('specialty').choices,
'search_query': self.request.GET.get('search', ''),
})
return context
class SurgicalNoteTemplateDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a surgical note template.
"""
model = SurgicalNoteTemplate
template_name = 'operating_theatre/surgical_note_template_detail.html'
context_object_name = 'surgical_note_template'
def get_queryset(self):
return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
template = self.object
# Get recent notes using this template
context['recent_notes'] = SurgicalNote.objects.filter(
template=template,
tenant=self.request.user.tenant
).select_related('surgical_case__patient').order_by('-created_at')[:10]
return context
class SurgicalNoteTemplateCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new surgical note template.
"""
model = SurgicalNoteTemplate
form_class = SurgicalNoteTemplateForm
template_name = 'operating_theatre/surgical_note_template_form.html'
permission_required = 'operating_theatre.add_surgicalnotetemplate'
success_url = reverse_lazy('operating_theatre:surgical_note_template_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
form.instance.created_by = self.request.user
response = super().form_valid(form)
# Log the action
AuditLogger.log_event(
user=self.request.user,
action='SURGICAL_NOTE_TEMPLATE_CREATED',
model='SurgicalNoteTemplate',
object_id=str(self.object.id),
details={
'template_name': self.object.template_name,
'specialty': self.object.specialty
}
)
messages.success(self.request, f'Surgical note template "{self.object.template_name}" created successfully.')
return response
class SurgicalNoteTemplateUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update an existing surgical note template.
"""
model = SurgicalNoteTemplate
form_class = SurgicalNoteTemplateForm
template_name = 'operating_theatre/surgical_note_template_form.html'
permission_required = 'operating_theatre.change_surgicalnotetemplate'
def get_queryset(self):
return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('operating_theatre:surgical_note_template_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='SURGICAL_NOTE_TEMPLATE_UPDATED',
model='SurgicalNoteTemplate',
object_id=str(self.object.id),
details={
'template_name': self.object.template_name,
'changes': form.changed_data
}
)
messages.success(self.request, f'Surgical note template "{self.object.template_name}" updated successfully.')
return response
class SurgicalNoteTemplateDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete a surgical note template (soft delete by deactivating).
"""
model = SurgicalNoteTemplate
template_name = 'operating_theatre/surgical_note_template_confirm_delete.html'
permission_required = 'operating_theatre.delete_surgicalnotetemplate'
success_url = reverse_lazy('operating_theatre:surgical_note_template_list')
def get_queryset(self):
return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Soft delete by deactivating
self.object.is_active = False
self.object.save()
# Log the action
AuditLogger.log_action(
user=request.user,
action='SURGICAL_NOTE_TEMPLATE_DEACTIVATED',
model='SurgicalNoteTemplate',
object_id=str(self.object.id),
details={'template_name': self.object.template_name}
)
messages.success(request, f'Surgical note template "{self.object.template_name}" deactivated successfully.')
return redirect(self.success_url)
# ============================================================================
# OR BLOCK VIEWS (LIMITED CRUD - Operational Data)
# ============================================================================
class ORBlockListView(LoginRequiredMixin, ListView):
"""
List all OR blocks with filtering and search.
"""
model = ORBlock
template_name = 'operating_theatre/or_block_list.html'
context_object_name = 'or_blocks'
paginate_by = 25
def get_queryset(self):
queryset = ORBlock.objects.filter(tenant=self.request.user.tenant)
# Filter by date range
date_from = self.request.GET.get('date_from')
date_to = self.request.GET.get('date_to')
if date_from:
queryset = queryset.filter(date__gte=date_from)
if date_to:
queryset = queryset.filter(date__lte=date_to)
# Filter by surgeon
surgeon_id = self.request.GET.get('surgeon')
if surgeon_id:
queryset = queryset.filter(surgeon_id=surgeon_id)
# Filter by operating room
room_id = self.request.GET.get('room')
if room_id:
queryset = queryset.filter(operating_room_id=room_id)
return queryset.select_related(
'operating_room', 'surgeon'
).order_by('-date', 'start_time')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'operating_rooms': OperatingRoom.objects.filter(
tenant=self.request.user.tenant,
is_active=True
).order_by('room_number'),
})
return context
class ORBlockDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about an OR block.
"""
model = ORBlock
template_name = 'operating_theatre/or_block_detail.html'
context_object_name = 'or_block'
def get_queryset(self):
return ORBlock.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
or_block = self.object
# Get cases scheduled in this block
context['scheduled_cases'] = SurgicalCase.objects.filter(
operating_room=or_block.operating_room,
scheduled_start_time__date=or_block.date,
scheduled_start_time__time__gte=or_block.start_time,
scheduled_start_time__time__lt=or_block.end_time,
tenant=self.request.user.tenant
).select_related('patient', 'primary_surgeon').order_by('scheduled_start_time')
# Calculate utilization
total_block_minutes = (
timezone.datetime.combine(timezone.now().date(), or_block.end_time) -
timezone.datetime.combine(timezone.now().date(), or_block.start_time)
).total_seconds() / 60
used_minutes = 0
for case in context['scheduled_cases']:
if case.estimated_duration_minutes:
used_minutes += case.estimated_duration_minutes
context['utilization_percentage'] = (
(used_minutes / total_block_minutes) * 100 if total_block_minutes > 0 else 0
)
return context
class ORBlockCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new OR block.
"""
model = ORBlock
form_class = ORBlockForm
template_name = 'operating_theatre/or_block_form.html'
permission_required = 'operating_theatre.add_orblock'
success_url = reverse_lazy('operating_theatre:or_block_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='OR_BLOCK_CREATED',
model='ORBlock',
object_id=str(self.object.id),
details={
'date': str(self.object.date),
'operating_room': self.object.operating_room.room_number,
'surgeon': f"{self.object.surgeon.first_name} {self.object.surgeon.last_name}"
}
)
messages.success(self.request, 'OR block created successfully.')
return response
class ORBlockUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update an OR block (limited to notes and time adjustments).
"""
model = ORBlock
fields = ['start_time', 'end_time', 'notes'] # Restricted fields
template_name = 'operating_theatre/or_block_update_form.html'
permission_required = 'operating_theatre.change_orblock'
def get_queryset(self):
return ORBlock.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('operating_theatre:or_block_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='OR_BLOCK_UPDATED',
model='ORBlock',
object_id=str(self.object.id),
details={
'date': str(self.object.date),
'changes': form.changed_data
}
)
messages.success(self.request, 'OR block updated successfully.')
return response
# ============================================================================
# SURGICAL CASE VIEWS (RESTRICTED CRUD - Clinical Data)
# ============================================================================
class SurgicalCaseListView(LoginRequiredMixin, ListView):
"""
List all surgical cases with filtering and search.
"""
model = SurgicalCase
template_name = 'operating_theatre/surgical_case_list.html'
context_object_name = 'surgical_cases'
paginate_by = 25
def get_queryset(self):
tenant = self.request.user.tenant
queryset = SurgicalCase.objects.filter(admission__tenant=tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(patient__first_name__icontains=search) |
Q(patient__last_name__icontains=search) |
Q(patient__mrn__icontains=search) |
Q(procedure_name__icontains=search)
)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by priority
priority = self.request.GET.get('priority')
if priority:
queryset = queryset.filter(priority=priority)
# Filter by surgeon
surgeon_id = self.request.GET.get('surgeon')
if surgeon_id:
queryset = queryset.filter(primary_surgeon_id=surgeon_id)
# Filter by operating room
room_id = self.request.GET.get('room')
if room_id:
queryset = queryset.filter(operating_room_id=room_id)
# Filter by date range
date_from = self.request.GET.get('date_from')
date_to = self.request.GET.get('date_to')
if date_from:
queryset = queryset.filter(scheduled_start__date__gte=date_from)
if date_to:
queryset = queryset.filter(scheduled_start__date__lte=date_to)
return queryset.select_related(
'patient', 'primary_surgeon', 'or_block__operating_room'
).order_by('-scheduled_start')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'statuses': SurgicalCase.STATUS_CHOICES,
'priorities': SurgicalCase.CASE_TYPE_CHOICES,
'operating_rooms': OperatingRoom.objects.filter(
tenant=self.request.user.tenant,
is_active=True
).order_by('room_number'),
})
return context
class SurgicalCaseDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a surgical case.
"""
model = SurgicalCase
template_name = 'operating_theatre/cases/surgical_case_detail.html'
context_object_name = 'surgical_case'
def get_queryset(self):
return SurgicalCase.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
surgical_case = self.object
# Get surgical notes for this case
context['surgical_notes'] = surgical_case.surgical_notes.all().order_by('-created_at')
# Get equipment usage for this case
context['equipment_usage'] = EquipmentUsage.objects.filter(
surgical_case=surgical_case,
tenant=self.request.user.tenant
).order_by('-start_time')
# Calculate actual duration if case is completed
if surgical_case.actual_start_time and surgical_case.actual_end_time:
context['actual_duration'] = surgical_case.actual_end_time - surgical_case.actual_start_time
return context
class SurgicalCaseCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new surgical case.
"""
model = SurgicalCase
form_class = SurgicalCaseForm
template_name = 'operating_theatre/cases/surgical_case_form.html'
permission_required = 'operating_theatre.add_surgicalcase'
success_url = reverse_lazy('operating_theatre:surgical_case_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='SURGICAL_CASE_CREATED',
model='SurgicalCase',
object_id=str(self.object.case_id),
details={
'patient_name': f"{self.object.patient.first_name} {self.object.patient.last_name}",
'procedure_name': self.object.procedure_name,
'priority': self.object.priority
}
)
messages.success(self.request, 'Surgical case created successfully.')
return response
class SurgicalCaseUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update surgical case (limited to status and notes after surgery starts).
"""
model = SurgicalCase
template_name = 'operating_theatre/cases/surgical_case_form.html'
permission_required = 'operating_theatre.change_surgicalcase'
def get_queryset(self):
return SurgicalCase.objects.filter(tenant=self.request.user.tenant)
def get_form_class(self):
# Limit fields based on case status
if self.object.status in ['IN_PROGRESS', 'COMPLETED']:
# Limited fields for cases that have started
class RestrictedSurgicalCaseForm(SurgicalCaseForm):
class Meta(SurgicalCaseForm.Meta):
fields = ['status', 'notes', 'complications']
return RestrictedSurgicalCaseForm
else:
return SurgicalCaseForm
def get_success_url(self):
return reverse('operating_theatre:surgical_case_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log the action
AuditLogger.log_event(
user=self.request.user,
action='SURGICAL_CASE_UPDATED',
model='SurgicalCase',
object_id=str(self.object.case_id),
details={
'patient_name': f"{self.object.patient.first_name} {self.object.patient.last_name}",
'changes': form.changed_data
}
)
messages.success(self.request, 'Surgical case updated successfully.')
return response
# ============================================================================
# SURGICAL NOTE VIEWS (APPEND-ONLY - Clinical Records)
# ============================================================================
class SurgicalNoteListView(LoginRequiredMixin, ListView):
"""
List all surgical notes with filtering and search.
"""
model = SurgicalNote
template_name = 'operating_theatre/surgical_note_list.html'
context_object_name = 'surgical_notes'
paginate_by = 25
def get_queryset(self):
queryset = SurgicalNote.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(surgical_case__patient__first_name__icontains=search) |
Q(surgical_case__patient__last_name__icontains=search) |
Q(surgical_case__patient__mrn__icontains=search) |
Q(surgical_case__procedure_name__icontains=search) |
Q(note_content__icontains=search)
)
# Filter by note type
note_type = self.request.GET.get('note_type')
if note_type:
queryset = queryset.filter(note_type=note_type)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by surgeon
surgeon_id = self.request.GET.get('surgeon')
if surgeon_id:
queryset = queryset.filter(surgeon_id=surgeon_id)
return queryset.select_related(
'surgical_case__patient', 'surgeon', 'template'
).order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'note_types': SurgicalNote._meta.get_field('note_type').choices,
'statuses': SurgicalNote._meta.get_field('status').choices,
})
return context
class SurgicalNoteDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a surgical note.
"""
model = SurgicalNote
template_name = 'operating_theatre/surgical_note_detail.html'
context_object_name = 'surgical_note'
def get_queryset(self):
return SurgicalNote.objects.filter(tenant=self.request.user.tenant)
class SurgicalNoteCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new surgical note.
"""
model = SurgicalNote
form_class = SurgicalNoteForm
template_name = 'operating_theatre/surgical_note_form.html'
permission_required = 'operating_theatre.add_surgicalnote'
success_url = reverse_lazy('operating_theatre:surgical_note_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
form.instance.surgeon = self.request.user
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='SURGICAL_NOTE_CREATED',
model='SurgicalNote',
object_id=str(self.object.note_id),
details={
'patient_name': f"{self.object.surgical_case.patient.first_name} {self.object.surgical_case.patient.last_name}",
'note_type': self.object.note_type
}
)
messages.success(self.request, 'Surgical note created successfully.')
return response
# Note: No UpdateView or DeleteView for SurgicalNote - Append-only for clinical records
# ============================================================================
# EQUIPMENT USAGE VIEWS (LIMITED CRUD - Operational Data)
# ============================================================================
class EquipmentUsageListView(LoginRequiredMixin, ListView):
"""
List all equipment usage records with filtering and search.
"""
model = EquipmentUsage
template_name = 'operating_theatre/equipment_usage_list.html'
context_object_name = 'equipment_usage_records'
paginate_by = 25
def get_queryset(self):
queryset = EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
# Filter by equipment type
equipment_type = self.request.GET.get('equipment_type')
if equipment_type:
queryset = queryset.filter(equipment_type=equipment_type)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by operating room
room_id = self.request.GET.get('room')
if room_id:
queryset = queryset.filter(operating_room_id=room_id)
# Filter by date range
date_from = self.request.GET.get('date_from')
date_to = self.request.GET.get('date_to')
if date_from:
queryset = queryset.filter(start_time__date__gte=date_from)
if date_to:
queryset = queryset.filter(start_time__date__lte=date_to)
return queryset.select_related(
'operating_room', 'surgical_case__patient'
).order_by('-start_time')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'equipment_types': EquipmentUsage._meta.get_field('equipment_type').choices,
'statuses': EquipmentUsage._meta.get_field('status').choices,
'operating_rooms': OperatingRoom.objects.filter(
tenant=self.request.user.tenant,
is_active=True
).order_by('room_number'),
})
return context
class EquipmentUsageDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about equipment usage.
"""
model = EquipmentUsage
template_name = 'operating_theatre/equipment_usage_detail.html'
context_object_name = 'equipment_usage'
def get_queryset(self):
return EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
equipment_usage = self.object
# Calculate usage duration if ended
if equipment_usage.end_time:
context['usage_duration'] = equipment_usage.end_time - equipment_usage.start_time
return context
class EquipmentUsageCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create a new equipment usage record.
"""
model = EquipmentUsage
form_class = EquipmentUsageForm
template_name = 'operating_theatre/equipment_usage_form.html'
permission_required = 'operating_theatre.add_equipmentusage'
success_url = reverse_lazy('operating_theatre:equipment_usage_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='EQUIPMENT_USAGE_CREATED',
model='EquipmentUsage',
object_id=str(self.object.id),
details={
'equipment_name': self.object.equipment_name,
'equipment_type': self.object.equipment_type,
'operating_room': self.object.operating_room.room_number
}
)
messages.success(self.request, 'Equipment usage record created successfully.')
return response
class EquipmentUsageUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update equipment usage record (limited to status and end time).
"""
model = EquipmentUsage
fields = ['status', 'end_time', 'notes'] # Restricted fields
template_name = 'operating_theatre/equipment_usage_update_form.html'
permission_required = 'operating_theatre.change_equipmentusage'
def get_queryset(self):
return EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('operating_theatre:equipment_usage_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log the action
AuditLogger.log_action(
user=self.request.user,
action='EQUIPMENT_USAGE_UPDATED',
model='EquipmentUsage',
object_id=str(self.object.id),
details={
'equipment_name': self.object.equipment_name,
'changes': form.changed_data
}
)
messages.success(self.request, 'Equipment usage record updated successfully.')
return response
# ============================================================================
# HTMX VIEWS FOR REAL-TIME UPDATES
# ============================================================================
@login_required
def operating_theatre_stats(request):
"""
HTMX endpoint for operating theatre statistics.
"""
tenant = request.user.tenant
today = timezone.now().date()
stats = {
'rooms_available': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True,
status='AVAILABLE'
).count(),
'rooms_in_use': OperatingRoom.objects.filter(
tenant=tenant,
is_active=True,
status='IN_USE'
).count(),
'cases_in_progress': SurgicalCase.objects.filter(
tenant=tenant,
status='IN_PROGRESS'
).count(),
'cases_completed_today': SurgicalCase.objects.filter(
tenant=tenant,
actual_end_time__date=today,
status='COMPLETED'
).count(),
'emergency_cases_today': SurgicalCase.objects.filter(
tenant=tenant,
scheduled_start_time__date=today,
priority='EMERGENCY'
).count(),
}
return render(request, 'operating_theatre/partials/or_stats.html', {'stats': stats})
@login_required
def case_search(request):
"""
HTMX endpoint for surgical case search.
"""
search = request.GET.get('search', '')
status = request.GET.get('status', '')
priority = request.GET.get('priority', '')
queryset = SurgicalCase.objects.filter(tenant=request.user.tenant)
if search:
queryset = queryset.filter(
Q(patient__first_name__icontains=search) |
Q(patient__last_name__icontains=search) |
Q(patient__mrn__icontains=search) |
Q(procedure_name__icontains=search)
)
if status:
queryset = queryset.filter(status=status)
if priority:
queryset = queryset.filter(priority=priority)
cases = queryset.select_related(
'patient', 'primary_surgeon', 'operating_room'
).order_by('-scheduled_start_time')[:20]
return render(request, 'operating_theatre/partials/case_list.html', {'cases': cases})
# ============================================================================
# ACTION VIEWS
# ============================================================================
@login_required
def start_case(request, case_id):
"""
Start a surgical case.
"""
if request.method == 'POST':
case = get_object_or_404(
SurgicalCase,
id=case_id,
tenant=request.user.tenant
)
case.status = 'IN_PROGRESS'
case.actual_start_time = timezone.now()
case.save()
# Update room status
if case.operating_room:
case.operating_room.status = 'IN_USE'
case.operating_room.save()
# Log the action
AuditLogger.log_action(
user=request.user,
action='SURGICAL_CASE_STARTED',
model='SurgicalCase',
object_id=str(case.case_id),
details={
'patient_name': f"{case.patient.first_name} {case.patient.last_name}",
'procedure_name': case.procedure_name
}
)
messages.success(request, 'Surgical case started successfully.')
if request.headers.get('HX-Request'):
return render(request, 'operating_theatre/partials/case_status.html', {'case': case})
return redirect('operating_theatre:surgical_case_detail', pk=case.pk)
return JsonResponse({'success': False})
@login_required
def complete_case(request, case_id):
"""
Complete a surgical case.
"""
if request.method == 'POST':
case = get_object_or_404(
SurgicalCase,
id=case_id,
tenant=request.user.tenant
)
case.status = 'COMPLETED'
case.actual_end_time = timezone.now()
case.save()
# Update room status
if case.operating_room:
case.operating_room.status = 'CLEANING'
case.operating_room.save()
# Log the action
AuditLogger.log_action(
user=request.user,
action='SURGICAL_CASE_COMPLETED',
model='SurgicalCase',
object_id=str(case.case_id),
details={
'patient_name': f"{case.patient.first_name} {case.patient.last_name}",
'procedure_name': case.procedure_name,
'duration': str(case.actual_end_time - case.actual_start_time) if case.actual_start_time else None
}
)
messages.success(request, 'Surgical case completed successfully.')
if request.headers.get('HX-Request'):
return render(request, 'operating_theatre/partials/case_status.html', {'case': case})
return redirect('operating_theatre:surgical_case_detail', pk=case.pk)
return JsonResponse({'success': False})
@login_required
def sign_note(request, note_id):
"""
Sign a surgical note.
"""
if request.method == 'POST':
note = get_object_or_404(
SurgicalNote,
id=note_id,
tenant=request.user.tenant
)
# Only allow signing if note is in draft status
if note.status != 'DRAFT':
messages.error(request, 'Only draft notes can be signed.')
return redirect('operating_theatre:surgical_note_detail', pk=note.pk)
note.status = 'SIGNED'
note.signed_datetime = timezone.now()
note.signed_by = request.user
note.save()
# Log the action
AuditLogger.log_action(
user=request.user,
action='SURGICAL_NOTE_SIGNED',
model='SurgicalNote',
object_id=str(note.note_id),
details={
'patient_name': f"{note.surgical_case.patient.first_name} {note.surgical_case.patient.last_name}",
'note_type': note.note_type
}
)
messages.success(request, 'Surgical note signed successfully.')
if request.headers.get('HX-Request'):
return render(request, 'operating_theatre/partials/note_status.html', {'note': note})
return redirect('operating_theatre:surgical_note_detail', pk=note.pk)
return JsonResponse({'success': False})
@login_required
def update_room_status(request, room_id):
"""
Update operating room status.
"""
if request.method == 'POST':
room = get_object_or_404(
OperatingRoom,
id=room_id,
tenant=request.user.tenant
)
new_status = request.POST.get('status')
if new_status in dict(OperatingRoom._meta.get_field('status').choices):
old_status = room.status
room.status = new_status
room.save()
# Log the action
AuditLogger.log_action(
user=request.user,
action='OPERATING_ROOM_STATUS_UPDATED',
model='OperatingRoom',
object_id=str(room.id),
details={
'room_number': room.room_number,
'old_status': old_status,
'new_status': new_status
}
)
messages.success(request, f'Room {room.room_number} status updated to {room.get_status_display()}.')
if request.headers.get('HX-Request'):
return render(request, 'operating_theatre/partials/room_status.html', {'room': room})
return redirect('operating_theatre:operating_room_detail', pk=room.pk)
return JsonResponse({'success': False})
#
# """
# Operating Theatre app views with healthcare-focused CRUD operations.
# Implements appropriate access patterns for surgical and OR management workflows.
# """
#
# from django.shortcuts import render, get_object_or_404, redirect
# from django.contrib.auth.decorators import login_required
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.views.generic import (
# ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
# )
# from django.http import JsonResponse, HttpResponse
# from django.db.models import Q, Count, Avg, Sum, F
# from django.utils import timezone
# from django.contrib import messages
# from django.urls import reverse_lazy, reverse
# from django.core.paginator import Paginator
# from django.template.loader import render_to_string
# from datetime import datetime, timedelta, date
# import json
#
# from core.utils import AuditLogger
# from .models import (
# OperatingRoom, ORBlock, SurgicalCase, SurgicalNote,
# EquipmentUsage, SurgicalNoteTemplate
# )
# from .forms import (
# OperatingRoomForm, ORBlockForm, SurgicalCaseForm, SurgicalNoteForm,
# EquipmentUsageForm, SurgicalNoteTemplateForm
# )
#
#
# # ============================================================================
# # DASHBOARD AND OVERVIEW VIEWS
# # ============================================================================
#
# class OperatingTheatreDashboardView(LoginRequiredMixin, TemplateView):
# """
# Main operating theatre dashboard with key metrics and recent activity.
# """
# template_name = 'operating_theatre/dashboard.html'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.request.user.tenant
# today = timezone.now().date()
#
# # Dashboard statistics
# context.update({
# 'total_rooms': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True
# ).count(),
# 'rooms_available': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True,
# status='AVAILABLE'
# ).count(),
# 'rooms_in_use': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True,
# status='IN_USE'
# ).count(),
# 'rooms_maintenance': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True,
# status='MAINTENANCE'
# ).count(),
# 'cases_today': SurgicalCase.objects.filter(
# tenant=tenant,
# scheduled_start_time__date=today
# ).count(),
# 'cases_in_progress': SurgicalCase.objects.filter(
# tenant=tenant,
# status='IN_PROGRESS'
# ).count(),
# 'cases_completed_today': SurgicalCase.objects.filter(
# tenant=tenant,
# actual_end_time__date=today,
# status='COMPLETED'
# ).count(),
# 'emergency_cases_today': SurgicalCase.objects.filter(
# tenant=tenant,
# scheduled_start_time__date=today,
# priority='EMERGENCY'
# ).count(),
# 'blocks_today': ORBlock.objects.filter(
# tenant=tenant,
# date=today
# ).count(),
# 'equipment_in_use': EquipmentUsage.objects.filter(
# tenant=tenant,
# status='IN_USE'
# ).count(),
# 'notes_pending': SurgicalNote.objects.filter(
# tenant=tenant,
# status='DRAFT'
# ).count(),
# })
#
# # Recent surgical cases
# context['recent_cases'] = SurgicalCase.objects.filter(
# tenant=tenant
# ).select_related(
# 'patient', 'primary_surgeon', 'operating_room'
# ).order_by('-scheduled_start_time')[:10]
#
# # Today's schedule
# context['todays_schedule'] = SurgicalCase.objects.filter(
# tenant=tenant,
# scheduled_start_time__date=today
# ).select_related(
# 'patient', 'primary_surgeon', 'operating_room'
# ).order_by('scheduled_start_time')
#
# # Room utilization
# context['room_utilization'] = OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True
# ).annotate(
# cases_today=Count(
# 'surgical_cases',
# filter=Q(surgical_cases__scheduled_start_time__date=today)
# )
# ).order_by('room_number')
#
# return context
#
#
# # ============================================================================
# # OPERATING ROOM VIEWS (FULL CRUD - Master Data)
# # ============================================================================
#
# class OperatingRoomListView(LoginRequiredMixin, ListView):
# """
# List all operating rooms with filtering and search.
# """
# model = OperatingRoom
# template_name = 'operating_theatre/operating_room_list.html'
# context_object_name = 'operating_rooms'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = OperatingRoom.objects.filter(tenant=self.request.user.tenant)
#
# # Search functionality
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(room_number__icontains=search) |
# Q(room_name__icontains=search) |
# Q(location__icontains=search)
# )
#
# # Filter by room type
# room_type = self.request.GET.get('room_type')
# if room_type:
# queryset = queryset.filter(room_type=room_type)
#
# # Filter by status
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# # Filter by floor
# floor = self.request.GET.get('floor')
# if floor:
# queryset = queryset.filter(floor=floor)
#
# # Filter by active status
# active_only = self.request.GET.get('active_only')
# if active_only:
# queryset = queryset.filter(is_active=True)
#
# return queryset.order_by('room_number')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'room_types': OperatingRoom._meta.get_field('room_type').choices,
# 'statuses': OperatingRoom._meta.get_field('status').choices,
# 'search_query': self.request.GET.get('search', ''),
# })
# return context
#
#
# class OperatingRoomDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about an operating room.
# """
# model = OperatingRoom
# template_name = 'operating_theatre/operating_room_detail.html'
# context_object_name = 'operating_room'
#
# def get_queryset(self):
# return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# operating_room = self.object
# today = timezone.now().date()
#
# # Get today's cases for this room
# context['todays_cases'] = operating_room.surgical_cases.filter(
# scheduled_start_time__date=today
# ).select_related('patient', 'primary_surgeon').order_by('scheduled_start_time')
#
# # Get recent cases
# context['recent_cases'] = operating_room.surgical_cases.all().select_related(
# 'patient', 'primary_surgeon'
# ).order_by('-scheduled_start_time')[:10]
#
# # Get equipment usage
# context['equipment_usage'] = EquipmentUsage.objects.filter(
# operating_room=operating_room,
# tenant=self.request.user.tenant
# ).order_by('-start_time')[:10]
#
# # Room statistics
# context['room_stats'] = {
# 'total_cases': operating_room.surgical_cases.count(),
# 'cases_this_month': operating_room.surgical_cases.filter(
# scheduled_start_time__month=timezone.now().month,
# scheduled_start_time__year=timezone.now().year
# ).count(),
# 'average_case_duration': operating_room.surgical_cases.filter(
# actual_end_time__isnull=False
# ).aggregate(
# avg_duration=Avg(
# F('actual_end_time') - F('actual_start_time')
# )
# )['avg_duration'],
# }
#
# return context
#
#
# class OperatingRoomCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new operating room.
# """
# model = OperatingRoom
# form_class = OperatingRoomForm
# template_name = 'operating_theatre/operating_room_form.html'
# permission_required = 'operating_theatre.add_operatingroom'
# success_url = reverse_lazy('operating_theatre:operating_room_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='OPERATING_ROOM_CREATED',
# model='OperatingRoom',
# object_id=str(self.object.id),
# details={
# 'room_number': self.object.room_number,
# 'room_name': self.object.room_name,
# 'room_type': self.object.room_type
# }
# )
#
# messages.success(self.request, f'Operating room "{self.object.room_number}" created successfully.')
# return response
#
#
# class OperatingRoomUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update an existing operating room.
# """
# model = OperatingRoom
# form_class = OperatingRoomForm
# template_name = 'operating_theatre/operating_room_form.html'
# permission_required = 'operating_theatre.change_operatingroom'
#
# def get_queryset(self):
# return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
#
# def get_success_url(self):
# return reverse('operating_theatre:operating_room_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='OPERATING_ROOM_UPDATED',
# model='OperatingRoom',
# object_id=str(self.object.id),
# details={
# 'room_number': self.object.room_number,
# 'changes': form.changed_data
# }
# )
#
# messages.success(self.request, f'Operating room "{self.object.room_number}" updated successfully.')
# return response
#
#
# class OperatingRoomDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete an operating room (soft delete by deactivating).
# """
# model = OperatingRoom
# template_name = 'operating_theatre/operating_room_confirm_delete.html'
# permission_required = 'operating_theatre.delete_operatingroom'
# success_url = reverse_lazy('operating_theatre:operating_room_list')
#
# def get_queryset(self):
# return OperatingRoom.objects.filter(tenant=self.request.user.tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
#
# # Check if room has active cases
# active_cases = self.object.surgical_cases.filter(
# status__in=['SCHEDULED', 'IN_PROGRESS']
# ).count()
#
# if active_cases > 0:
# messages.error(
# request,
# f'Cannot deactivate room "{self.object.room_number}" - it has {active_cases} active cases.'
# )
# return redirect('operating_theatre:operating_room_detail', pk=self.object.pk)
#
# # Soft delete by deactivating
# self.object.is_active = False
# self.object.status = 'OUT_OF_SERVICE'
# self.object.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='OPERATING_ROOM_DEACTIVATED',
# model='OperatingRoom',
# object_id=str(self.object.id),
# details={'room_number': self.object.room_number}
# )
#
# messages.success(request, f'Operating room "{self.object.room_number}" deactivated successfully.')
# return redirect(self.success_url)
#
#
# # ============================================================================
# # SURGICAL NOTE TEMPLATE VIEWS (FULL CRUD - Master Data)
# # ============================================================================
#
# class SurgicalNoteTemplateListView(LoginRequiredMixin, ListView):
# """
# List all surgical note templates with filtering and search.
# """
# model = SurgicalNoteTemplate
# template_name = 'operating_theatre/surgical_note_template_list.html'
# context_object_name = 'surgical_note_templates'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
#
# # Search functionality
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(template_name__icontains=search) |
# Q(procedure_type__icontains=search) |
# Q(specialty__icontains=search)
# )
#
# # Filter by specialty
# specialty = self.request.GET.get('specialty')
# if specialty:
# queryset = queryset.filter(specialty=specialty)
#
# # Filter by active status
# active_only = self.request.GET.get('active_only')
# if active_only:
# queryset = queryset.filter(is_active=True)
#
# return queryset.order_by('template_name')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'specialties': SurgicalNoteTemplate._meta.get_field('specialty').choices,
# 'search_query': self.request.GET.get('search', ''),
# })
# return context
#
#
# class SurgicalNoteTemplateDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about a surgical note template.
# """
# model = SurgicalNoteTemplate
# template_name = 'operating_theatre/surgical_note_template_detail.html'
# context_object_name = 'surgical_note_template'
#
# def get_queryset(self):
# return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# template = self.object
#
# # Get recent notes using this template
# context['recent_notes'] = SurgicalNote.objects.filter(
# template=template,
# tenant=self.request.user.tenant
# ).select_related('surgical_case__patient').order_by('-created_at')[:10]
#
# return context
#
#
# class SurgicalNoteTemplateCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new surgical note template.
# """
# model = SurgicalNoteTemplate
# form_class = SurgicalNoteTemplateForm
# template_name = 'operating_theatre/surgical_note_template_form.html'
# permission_required = 'operating_theatre.add_surgicalnotetemplate'
# success_url = reverse_lazy('operating_theatre:surgical_note_template_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# form.instance.created_by = self.request.user
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='SURGICAL_NOTE_TEMPLATE_CREATED',
# model='SurgicalNoteTemplate',
# object_id=str(self.object.id),
# details={
# 'template_name': self.object.template_name,
# 'specialty': self.object.specialty
# }
# )
#
# messages.success(self.request, f'Surgical note template "{self.object.template_name}" created successfully.')
# return response
#
#
# class SurgicalNoteTemplateUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update an existing surgical note template.
# """
# model = SurgicalNoteTemplate
# form_class = SurgicalNoteTemplateForm
# template_name = 'operating_theatre/surgical_note_template_form.html'
# permission_required = 'operating_theatre.change_surgicalnotetemplate'
#
# def get_queryset(self):
# return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
#
# def get_success_url(self):
# return reverse('operating_theatre:surgical_note_template_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='SURGICAL_NOTE_TEMPLATE_UPDATED',
# model='SurgicalNoteTemplate',
# object_id=str(self.object.id),
# details={
# 'template_name': self.object.template_name,
# 'changes': form.changed_data
# }
# )
#
# messages.success(self.request, f'Surgical note template "{self.object.template_name}" updated successfully.')
# return response
#
#
# class SurgicalNoteTemplateDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete a surgical note template (soft delete by deactivating).
# """
# model = SurgicalNoteTemplate
# template_name = 'operating_theatre/surgical_note_template_confirm_delete.html'
# permission_required = 'operating_theatre.delete_surgicalnotetemplate'
# success_url = reverse_lazy('operating_theatre:surgical_note_template_list')
#
# def get_queryset(self):
# return SurgicalNoteTemplate.objects.filter(tenant=self.request.user.tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
#
# # Soft delete by deactivating
# self.object.is_active = False
# self.object.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='SURGICAL_NOTE_TEMPLATE_DEACTIVATED',
# model='SurgicalNoteTemplate',
# object_id=str(self.object.id),
# details={'template_name': self.object.template_name}
# )
#
# messages.success(request, f'Surgical note template "{self.object.template_name}" deactivated successfully.')
# return redirect(self.success_url)
#
#
# # ============================================================================
# # OR BLOCK VIEWS (LIMITED CRUD - Operational Data)
# # ============================================================================
#
# class ORBlockListView(LoginRequiredMixin, ListView):
# """
# List all OR blocks with filtering and search.
# """
# model = ORBlock
# template_name = 'operating_theatre/or_block_list.html'
# context_object_name = 'or_blocks'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = ORBlock.objects.filter(tenant=self.request.user.tenant)
#
# # Filter by date range
# date_from = self.request.GET.get('date_from')
# date_to = self.request.GET.get('date_to')
# if date_from:
# queryset = queryset.filter(date__gte=date_from)
# if date_to:
# queryset = queryset.filter(date__lte=date_to)
#
# # Filter by surgeon
# surgeon_id = self.request.GET.get('surgeon')
# if surgeon_id:
# queryset = queryset.filter(surgeon_id=surgeon_id)
#
# # Filter by operating room
# room_id = self.request.GET.get('room')
# if room_id:
# queryset = queryset.filter(operating_room_id=room_id)
#
# return queryset.select_related(
# 'operating_room', 'surgeon'
# ).order_by('-date', 'start_time')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'operating_rooms': OperatingRoom.objects.filter(
# tenant=self.request.user.tenant,
# is_active=True
# ).order_by('room_number'),
# })
# return context
#
#
# class ORBlockDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about an OR block.
# """
# model = ORBlock
# template_name = 'operating_theatre/or_block_detail.html'
# context_object_name = 'or_block'
#
# def get_queryset(self):
# return ORBlock.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# or_block = self.object
#
# # Get cases scheduled in this block
# context['scheduled_cases'] = SurgicalCase.objects.filter(
# operating_room=or_block.operating_room,
# scheduled_start_time__date=or_block.date,
# scheduled_start_time__time__gte=or_block.start_time,
# scheduled_start_time__time__lt=or_block.end_time,
# tenant=self.request.user.tenant
# ).select_related('patient', 'primary_surgeon').order_by('scheduled_start_time')
#
# # Calculate utilization
# total_block_minutes = (
# timezone.datetime.combine(timezone.now().date(), or_block.end_time) -
# timezone.datetime.combine(timezone.now().date(), or_block.start_time)
# ).total_seconds() / 60
#
# used_minutes = 0
# for case in context['scheduled_cases']:
# if case.estimated_duration_minutes:
# used_minutes += case.estimated_duration_minutes
#
# context['utilization_percentage'] = (
# (used_minutes / total_block_minutes) * 100 if total_block_minutes > 0 else 0
# )
#
# return context
#
#
# class ORBlockCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new OR block.
# """
# model = ORBlock
# form_class = ORBlockForm
# template_name = 'operating_theatre/or_block_form.html'
# permission_required = 'operating_theatre.add_orblock'
# success_url = reverse_lazy('operating_theatre:or_block_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='OR_BLOCK_CREATED',
# model='ORBlock',
# object_id=str(self.object.id),
# details={
# 'date': str(self.object.date),
# 'operating_room': self.object.operating_room.room_number,
# 'surgeon': f"{self.object.surgeon.first_name} {self.object.surgeon.last_name}"
# }
# )
#
# messages.success(self.request, 'OR block created successfully.')
# return response
#
#
# class ORBlockUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update an OR block (limited to notes and time adjustments).
# """
# model = ORBlock
# fields = ['start_time', 'end_time', 'notes'] # Restricted fields
# template_name = 'operating_theatre/or_block_update_form.html'
# permission_required = 'operating_theatre.change_orblock'
#
# def get_queryset(self):
# return ORBlock.objects.filter(tenant=self.request.user.tenant)
#
# def get_success_url(self):
# return reverse('operating_theatre:or_block_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='OR_BLOCK_UPDATED',
# model='ORBlock',
# object_id=str(self.object.id),
# details={
# 'date': str(self.object.date),
# 'changes': form.changed_data
# }
# )
#
# messages.success(self.request, 'OR block updated successfully.')
# return response
#
#
# # ============================================================================
# # SURGICAL CASE VIEWS (RESTRICTED CRUD - Clinical Data)
# # ============================================================================
#
# class SurgicalCaseListView(LoginRequiredMixin, ListView):
# """
# List all surgical cases with filtering and search.
# """
# model = SurgicalCase
# template_name = 'operating_theatre/surgical_case_list.html'
# context_object_name = 'surgical_cases'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = SurgicalCase.objects.filter(tenant=self.request.user.tenant)
#
# # Search functionality
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(patient__first_name__icontains=search) |
# Q(patient__last_name__icontains=search) |
# Q(patient__mrn__icontains=search) |
# Q(procedure_name__icontains=search)
# )
#
# # Filter by status
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# # Filter by priority
# priority = self.request.GET.get('priority')
# if priority:
# queryset = queryset.filter(priority=priority)
#
# # Filter by surgeon
# surgeon_id = self.request.GET.get('surgeon')
# if surgeon_id:
# queryset = queryset.filter(primary_surgeon_id=surgeon_id)
#
# # Filter by operating room
# room_id = self.request.GET.get('room')
# if room_id:
# queryset = queryset.filter(operating_room_id=room_id)
#
# # Filter by date range
# date_from = self.request.GET.get('date_from')
# date_to = self.request.GET.get('date_to')
# if date_from:
# queryset = queryset.filter(scheduled_start_time__date__gte=date_from)
# if date_to:
# queryset = queryset.filter(scheduled_start_time__date__lte=date_to)
#
# return queryset.select_related(
# 'patient', 'primary_surgeon', 'operating_room'
# ).order_by('-scheduled_start_time')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'statuses': SurgicalCase._meta.get_field('status').choices,
# 'priorities': SurgicalCase._meta.get_field('priority').choices,
# 'operating_rooms': OperatingRoom.objects.filter(
# tenant=self.request.user.tenant,
# is_active=True
# ).order_by('room_number'),
# })
# return context
#
#
# class SurgicalCaseDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about a surgical case.
# """
# model = SurgicalCase
# template_name = 'operating_theatre/surgical_case_detail.html'
# context_object_name = 'surgical_case'
#
# def get_queryset(self):
# return SurgicalCase.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# surgical_case = self.object
#
# # Get surgical notes for this case
# context['surgical_notes'] = surgical_case.surgical_notes.all().order_by('-created_at')
#
# # Get equipment usage for this case
# context['equipment_usage'] = EquipmentUsage.objects.filter(
# surgical_case=surgical_case,
# tenant=self.request.user.tenant
# ).order_by('-start_time')
#
# # Calculate actual duration if case is completed
# if surgical_case.actual_start_time and surgical_case.actual_end_time:
# context['actual_duration'] = surgical_case.actual_end_time - surgical_case.actual_start_time
#
# return context
#
#
# class SurgicalCaseCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new surgical case.
# """
# model = SurgicalCase
# form_class = SurgicalCaseForm
# template_name = 'operating_theatre/surgical_case_form.html'
# permission_required = 'operating_theatre.add_surgicalcase'
# success_url = reverse_lazy('operating_theatre:surgical_case_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='SURGICAL_CASE_CREATED',
# model='SurgicalCase',
# object_id=str(self.object.case_id),
# details={
# 'patient_name': f"{self.object.patient.first_name} {self.object.patient.last_name}",
# 'procedure_name': self.object.procedure_name,
# 'priority': self.object.priority
# }
# )
#
# messages.success(self.request, 'Surgical case created successfully.')
# return response
#
#
# class SurgicalCaseUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update surgical case (limited to status and notes after surgery starts).
# """
# model = SurgicalCase
# template_name = 'operating_theatre/surgical_case_update_form.html'
# permission_required = 'operating_theatre.change_surgicalcase'
#
# def get_queryset(self):
# return SurgicalCase.objects.filter(tenant=self.request.user.tenant)
#
# def get_form_class(self):
# # Limit fields based on case status
# if self.object.status in ['IN_PROGRESS', 'COMPLETED']:
# # Limited fields for cases that have started
# class RestrictedSurgicalCaseForm(SurgicalCaseForm):
# class Meta(SurgicalCaseForm.Meta):
# fields = ['status', 'notes', 'complications']
#
# return RestrictedSurgicalCaseForm
# else:
# return SurgicalCaseForm
#
# def get_success_url(self):
# return reverse('operating_theatre:surgical_case_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='SURGICAL_CASE_UPDATED',
# model='SurgicalCase',
# object_id=str(self.object.case_id),
# details={
# 'patient_name': f"{self.object.patient.first_name} {self.object.patient.last_name}",
# 'changes': form.changed_data
# }
# )
#
# messages.success(self.request, 'Surgical case updated successfully.')
# return response
#
#
# # ============================================================================
# # SURGICAL NOTE VIEWS (APPEND-ONLY - Clinical Records)
# # ============================================================================
#
# class SurgicalNoteListView(LoginRequiredMixin, ListView):
# """
# List all surgical notes with filtering and search.
# """
# model = SurgicalNote
# template_name = 'operating_theatre/surgical_note_list.html'
# context_object_name = 'surgical_notes'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = SurgicalNote.objects.filter(tenant=self.request.user.tenant)
#
# # Search functionality
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(surgical_case__patient__first_name__icontains=search) |
# Q(surgical_case__patient__last_name__icontains=search) |
# Q(surgical_case__patient__mrn__icontains=search) |
# Q(surgical_case__procedure_name__icontains=search) |
# Q(note_content__icontains=search)
# )
#
# # Filter by note type
# note_type = self.request.GET.get('note_type')
# if note_type:
# queryset = queryset.filter(note_type=note_type)
#
# # Filter by status
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# # Filter by surgeon
# surgeon_id = self.request.GET.get('surgeon')
# if surgeon_id:
# queryset = queryset.filter(surgeon_id=surgeon_id)
#
# return queryset.select_related(
# 'surgical_case__patient', 'surgeon', 'template'
# ).order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'note_types': SurgicalNote._meta.get_field('note_type').choices,
# 'statuses': SurgicalNote._meta.get_field('status').choices,
# })
# return context
#
#
# class SurgicalNoteDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about a surgical note.
# """
# model = SurgicalNote
# template_name = 'operating_theatre/surgical_note_detail.html'
# context_object_name = 'surgical_note'
#
# def get_queryset(self):
# return SurgicalNote.objects.filter(tenant=self.request.user.tenant)
#
#
# class SurgicalNoteCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new surgical note.
# """
# model = SurgicalNote
# form_class = SurgicalNoteForm
# template_name = 'operating_theatre/surgical_note_form.html'
# permission_required = 'operating_theatre.add_surgicalnote'
# success_url = reverse_lazy('operating_theatre:surgical_note_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# form.instance.surgeon = self.request.user
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='SURGICAL_NOTE_CREATED',
# model='SurgicalNote',
# object_id=str(self.object.note_id),
# details={
# 'patient_name': f"{self.object.surgical_case.patient.first_name} {self.object.surgical_case.patient.last_name}",
# 'note_type': self.object.note_type
# }
# )
#
# messages.success(self.request, 'Surgical note created successfully.')
# return response
#
#
# # Note: No UpdateView or DeleteView for SurgicalNote - Append-only for clinical records
#
#
# # ============================================================================
# # EQUIPMENT USAGE VIEWS (LIMITED CRUD - Operational Data)
# # ============================================================================
#
# class EquipmentUsageListView(LoginRequiredMixin, ListView):
# """
# List all equipment usage records with filtering and search.
# """
# model = EquipmentUsage
# template_name = 'operating_theatre/equipment_usage_list.html'
# context_object_name = 'equipment_usage_records'
# paginate_by = 25
#
# def get_queryset(self):
# queryset = EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
#
# # Filter by equipment type
# equipment_type = self.request.GET.get('equipment_type')
# if equipment_type:
# queryset = queryset.filter(equipment_type=equipment_type)
#
# # Filter by status
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# # Filter by operating room
# room_id = self.request.GET.get('room')
# if room_id:
# queryset = queryset.filter(operating_room_id=room_id)
#
# # Filter by date range
# date_from = self.request.GET.get('date_from')
# date_to = self.request.GET.get('date_to')
# if date_from:
# queryset = queryset.filter(start_time__date__gte=date_from)
# if date_to:
# queryset = queryset.filter(start_time__date__lte=date_to)
#
# return queryset.select_related(
# 'operating_room', 'surgical_case__patient'
# ).order_by('-start_time')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'equipment_types': EquipmentUsage._meta.get_field('equipment_type').choices,
# 'statuses': EquipmentUsage._meta.get_field('status').choices,
# 'operating_rooms': OperatingRoom.objects.filter(
# tenant=self.request.user.tenant,
# is_active=True
# ).order_by('room_number'),
# })
# return context
#
#
# class EquipmentUsageDetailView(LoginRequiredMixin, DetailView):
# """
# Display detailed information about equipment usage.
# """
# model = EquipmentUsage
# template_name = 'operating_theatre/equipment_usage_detail.html'
# context_object_name = 'equipment_usage'
#
# def get_queryset(self):
# return EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# equipment_usage = self.object
#
# # Calculate usage duration if ended
# if equipment_usage.end_time:
# context['usage_duration'] = equipment_usage.end_time - equipment_usage.start_time
#
# return context
#
#
# class EquipmentUsageCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create a new equipment usage record.
# """
# model = EquipmentUsage
# form_class = EquipmentUsageForm
# template_name = 'operating_theatre/equipment_usage_form.html'
# permission_required = 'operating_theatre.add_equipmentusage'
# success_url = reverse_lazy('operating_theatre:equipment_usage_list')
#
# def form_valid(self, form):
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='EQUIPMENT_USAGE_CREATED',
# model='EquipmentUsage',
# object_id=str(self.object.id),
# details={
# 'equipment_name': self.object.equipment_name,
# 'equipment_type': self.object.equipment_type,
# 'operating_room': self.object.operating_room.room_number
# }
# )
#
# messages.success(self.request, 'Equipment usage record created successfully.')
# return response
#
#
# class EquipmentUsageUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update equipment usage record (limited to status and end time).
# """
# model = EquipmentUsage
# fields = ['status', 'end_time', 'notes'] # Restricted fields
# template_name = 'operating_theatre/equipment_usage_update_form.html'
# permission_required = 'operating_theatre.change_equipmentusage'
#
# def get_queryset(self):
# return EquipmentUsage.objects.filter(tenant=self.request.user.tenant)
#
# def get_success_url(self):
# return reverse('operating_theatre:equipment_usage_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='EQUIPMENT_USAGE_UPDATED',
# model='EquipmentUsage',
# object_id=str(self.object.id),
# details={
# 'equipment_name': self.object.equipment_name,
# 'changes': form.changed_data
# }
# )
#
# messages.success(self.request, 'Equipment usage record updated successfully.')
# return response
#
#
# # ============================================================================
# # HTMX VIEWS FOR REAL-TIME UPDATES
# # ============================================================================
#
# @login_required
# def operating_theatre_stats(request):
# """
# HTMX endpoint for operating theatre statistics.
# """
# tenant = request.user.tenant
# today = timezone.now().date()
#
# stats = {
# 'rooms_available': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True,
# status='AVAILABLE'
# ).count(),
# 'rooms_in_use': OperatingRoom.objects.filter(
# tenant=tenant,
# is_active=True,
# status='IN_USE'
# ).count(),
# 'cases_in_progress': SurgicalCase.objects.filter(
# tenant=tenant,
# status='IN_PROGRESS'
# ).count(),
# 'cases_completed_today': SurgicalCase.objects.filter(
# tenant=tenant,
# actual_end_time__date=today,
# status='COMPLETED'
# ).count(),
# 'emergency_cases_today': SurgicalCase.objects.filter(
# tenant=tenant,
# scheduled_start_time__date=today,
# priority='EMERGENCY'
# ).count(),
# }
#
# return render(request, 'operating_theatre/partials/or_stats.html', {'stats': stats})
#
#
# @login_required
# def case_search(request):
# """
# HTMX endpoint for surgical case search.
# """
# search = request.GET.get('search', '')
# status = request.GET.get('status', '')
# priority = request.GET.get('priority', '')
#
# queryset = SurgicalCase.objects.filter(tenant=request.user.tenant)
#
# if search:
# queryset = queryset.filter(
# Q(patient__first_name__icontains=search) |
# Q(patient__last_name__icontains=search) |
# Q(patient__mrn__icontains=search) |
# Q(procedure_name__icontains=search)
# )
#
# if status:
# queryset = queryset.filter(status=status)
#
# if priority:
# queryset = queryset.filter(priority=priority)
#
# cases = queryset.select_related(
# 'patient', 'primary_surgeon', 'operating_room'
# ).order_by('-scheduled_start_time')[:20]
#
# return render(request, 'operating_theatre/partials/case_list.html', {'cases': cases})
#
#
# # ============================================================================
# # ACTION VIEWS
# # ============================================================================
#
# @login_required
# def start_case(request, case_id):
# """
# Start a surgical case.
# """
# if request.method == 'POST':
# case = get_object_or_404(
# SurgicalCase,
# id=case_id,
# tenant=request.user.tenant
# )
#
# case.status = 'IN_PROGRESS'
# case.actual_start_time = timezone.now()
# case.save()
#
# # Update room status
# if case.operating_room:
# case.operating_room.status = 'IN_USE'
# case.operating_room.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='SURGICAL_CASE_STARTED',
# model='SurgicalCase',
# object_id=str(case.case_id),
# details={
# 'patient_name': f"{case.patient.first_name} {case.patient.last_name}",
# 'procedure_name': case.procedure_name
# }
# )
#
# messages.success(request, 'Surgical case started successfully.')
#
# if request.headers.get('HX-Request'):
# return render(request, 'operating_theatre/partials/case_status.html', {'case': case})
#
# return redirect('operating_theatre:surgical_case_detail', pk=case.pk)
#
# return JsonResponse({'success': False})
#
#
# @login_required
# def complete_case(request, case_id):
# """
# Complete a surgical case.
# """
# if request.method == 'POST':
# case = get_object_or_404(
# SurgicalCase,
# id=case_id,
# tenant=request.user.tenant
# )
#
# case.status = 'COMPLETED'
# case.actual_end_time = timezone.now()
# case.save()
#
# # Update room status
# if case.operating_room:
# case.operating_room.status = 'CLEANING'
# case.operating_room.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='SURGICAL_CASE_COMPLETED',
# model='SurgicalCase',
# object_id=str(case.case_id),
# details={
# 'patient_name': f"{case.patient.first_name} {case.patient.last_name}",
# 'procedure_name': case.procedure_name,
# 'duration': str(case.actual_end_time - case.actual_start_time) if case.actual_start_time else None
# }
# )
#
# messages.success(request, 'Surgical case completed successfully.')
#
# if request.headers.get('HX-Request'):
# return render(request, 'operating_theatre/partials/case_status.html', {'case': case})
#
# return redirect('operating_theatre:surgical_case_detail', pk=case.pk)
#
# return JsonResponse({'success': False})
#
#
# @login_required
# def sign_note(request, note_id):
# """
# Sign a surgical note.
# """
# if request.method == 'POST':
# note = get_object_or_404(
# SurgicalNote,
# id=note_id,
# tenant=request.user.tenant
# )
#
# # Only allow signing if note is in draft status
# if note.status != 'DRAFT':
# messages.error(request, 'Only draft notes can be signed.')
# return redirect('operating_theatre:surgical_note_detail', pk=note.pk)
#
# note.status = 'SIGNED'
# note.signed_datetime = timezone.now()
# note.signed_by = request.user
# note.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='SURGICAL_NOTE_SIGNED',
# model='SurgicalNote',
# object_id=str(note.note_id),
# details={
# 'patient_name': f"{note.surgical_case.patient.first_name} {note.surgical_case.patient.last_name}",
# 'note_type': note.note_type
# }
# )
#
# messages.success(request, 'Surgical note signed successfully.')
#
# if request.headers.get('HX-Request'):
# return render(request, 'operating_theatre/partials/note_status.html', {'note': note})
#
# return redirect('operating_theatre:surgical_note_detail', pk=note.pk)
#
# return JsonResponse({'success': False})
#
#
# @login_required
# def update_room_status(request, room_id):
# """
# Update operating room status.
# """
# if request.method == 'POST':
# room = get_object_or_404(
# OperatingRoom,
# id=room_id,
# tenant=request.user.tenant
# )
#
# new_status = request.POST.get('status')
# if new_status in dict(OperatingRoom._meta.get_field('status').choices):
# old_status = room.status
# room.status = new_status
# room.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='OPERATING_ROOM_STATUS_UPDATED',
# model='OperatingRoom',
# object_id=str(room.id),
# details={
# 'room_number': room.room_number,
# 'old_status': old_status,
# 'new_status': new_status
# }
# )
#
# messages.success(request, f'Room {room.room_number} status updated to {room.get_status_display()}.')
#
# if request.headers.get('HX-Request'):
# return render(request, 'operating_theatre/partials/room_status.html', {'room': room})
#
# return redirect('operating_theatre:operating_room_detail', pk=room.pk)
#
# return JsonResponse({'success': False})
#
#
#
#