785 lines
26 KiB
Python
785 lines
26 KiB
Python
"""
|
|
ABA views for the Tenhal Multidisciplinary Healthcare Platform.
|
|
|
|
This module contains views for ABA (Applied Behavior Analysis) documentation including:
|
|
- ABA consultations (ABA-F-1)
|
|
- Functional behavior interviews
|
|
- Behavior tracking
|
|
- Antecedents and consequences analysis
|
|
- Recommendations
|
|
"""
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.contrib import messages
|
|
from django.db.models import Q
|
|
from django.http import HttpResponseRedirect
|
|
from django.shortcuts import get_object_or_404
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import ListView, DetailView, CreateView, UpdateView, View
|
|
from django.urls import reverse_lazy
|
|
|
|
from core.mixins import (
|
|
TenantFilterMixin,
|
|
RolePermissionMixin,
|
|
AuditLogMixin,
|
|
HTMXResponseMixin,
|
|
SuccessMessageMixin,
|
|
PaginationMixin,
|
|
ConsentRequiredMixin,
|
|
)
|
|
from core.models import User, Patient
|
|
from appointments.models import Appointment
|
|
from .models import ABAConsult, ABABehavior, ABASession, ABASkillTarget
|
|
from .forms import ABAConsultForm, ABABehaviorFormSet, ABASessionForm, ABASkillTargetFormSet
|
|
|
|
|
|
class ABAConsultListView(LoginRequiredMixin, TenantFilterMixin, PaginationMixin,
|
|
HTMXResponseMixin, ListView):
|
|
"""
|
|
ABA consultation list view (ABA-F-1).
|
|
|
|
Features:
|
|
- Filter by patient, provider, date range
|
|
- Search by patient name/MRN
|
|
- Role-based filtering
|
|
"""
|
|
model = ABAConsult
|
|
template_name = 'aba/consult_list.html'
|
|
htmx_template_name = 'aba/partials/consult_list_partial.html'
|
|
context_object_name = 'consults'
|
|
paginate_by = 25
|
|
|
|
def get_queryset(self):
|
|
"""Get filtered queryset."""
|
|
queryset = super().get_queryset()
|
|
user = self.request.user
|
|
|
|
# Role-based filtering
|
|
if user.role == User.Role.ABA:
|
|
queryset = queryset.filter(provider=user)
|
|
|
|
# Apply search
|
|
search_query = self.request.GET.get('search', '').strip()
|
|
if search_query:
|
|
queryset = queryset.filter(
|
|
Q(patient__first_name_en__icontains=search_query) |
|
|
Q(patient__last_name_en__icontains=search_query) |
|
|
Q(patient__mrn__icontains=search_query)
|
|
)
|
|
|
|
# Apply filters
|
|
patient_id = self.request.GET.get('patient')
|
|
if patient_id:
|
|
queryset = queryset.filter(patient_id=patient_id)
|
|
|
|
date_from = self.request.GET.get('date_from')
|
|
if date_from:
|
|
queryset = queryset.filter(consultation_date__gte=date_from)
|
|
|
|
date_to = self.request.GET.get('date_to')
|
|
if date_to:
|
|
queryset = queryset.filter(consultation_date__lte=date_to)
|
|
|
|
return queryset.select_related('patient', 'provider', 'appointment').order_by('-consultation_date')
|
|
|
|
|
|
class ABAConsultDetailView(LoginRequiredMixin, TenantFilterMixin, DetailView):
|
|
"""
|
|
ABA consultation detail view (ABA-F-1).
|
|
|
|
Features:
|
|
- Full consultation details
|
|
- Reason of referral
|
|
- Parental and school concerns
|
|
- Respondents and interviewer info
|
|
- Diagnosed conditions
|
|
- Interaction hours
|
|
- Physiological/medical factors
|
|
- Behaviors with frequency, duration, intensity
|
|
- Antecedents (likely/least likely contexts)
|
|
- Recommendations
|
|
"""
|
|
model = ABAConsult
|
|
template_name = 'aba/consult_detail.html'
|
|
context_object_name = 'consult'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add related behaviors."""
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
# Get behaviors
|
|
context['behaviors'] = self.object.behaviors.all()
|
|
|
|
return context
|
|
|
|
|
|
class ABAConsultCreateView(ConsentRequiredMixin, LoginRequiredMixin, RolePermissionMixin,
|
|
AuditLogMixin, SuccessMessageMixin, CreateView):
|
|
"""
|
|
ABA consultation creation view (ABA-F-1).
|
|
|
|
Features:
|
|
- Complete functional interview form
|
|
- Reason of referral (radio options)
|
|
- Parental concern, school concern
|
|
- Respondents, interviewer, diagnosed
|
|
- Interaction hours
|
|
- Physiological/medical factors (booleans + text)
|
|
- Behaviors (1..n) with frequency, duration, intensity
|
|
- Antecedents (likely/least likely contexts)
|
|
- Recommendations
|
|
- Consent verification enforced before creation
|
|
"""
|
|
model = ABAConsult
|
|
form_class = ABAConsultForm
|
|
template_name = 'aba/consult_form.html'
|
|
success_message = _("ABA consultation recorded successfully!")
|
|
allowed_roles = [User.Role.ADMIN, User.Role.ABA]
|
|
|
|
# Consent enforcement
|
|
consent_service_type = 'ABA'
|
|
consent_error_message = _(
|
|
"Patient must sign ABA therapy consent and photo/video consent "
|
|
"before consultation can be documented."
|
|
)
|
|
|
|
def get_success_url(self):
|
|
"""Redirect to consult detail."""
|
|
return reverse_lazy('aba:consult_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def get_patient(self):
|
|
"""Get patient for consent verification."""
|
|
patient_id = self.request.GET.get('patient')
|
|
appointment_id = self.request.GET.get('appointment_id')
|
|
|
|
if patient_id:
|
|
return Patient.objects.get(
|
|
pk=patient_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
elif appointment_id:
|
|
appointment = Appointment.objects.get(
|
|
pk=appointment_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
return appointment.patient
|
|
|
|
return None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add form title, patient/appointment info, and behavior formset."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['form_title'] = _('ABA Consultation (ABA-F-1)')
|
|
context['submit_text'] = _('Save Consultation')
|
|
|
|
# Add behavior formset
|
|
if self.request.POST:
|
|
context['behavior_formset'] = ABABehaviorFormSet(self.request.POST)
|
|
else:
|
|
context['behavior_formset'] = ABABehaviorFormSet()
|
|
|
|
# Get patient if provided
|
|
patient_id = self.request.GET.get('patient')
|
|
if patient_id:
|
|
try:
|
|
context['patient'] = Patient.objects.get(
|
|
pk=patient_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
except Patient.DoesNotExist:
|
|
pass
|
|
|
|
# Get appointment if provided
|
|
appointment_id = self.request.GET.get('appointment_id')
|
|
if appointment_id:
|
|
try:
|
|
context['appointment'] = Appointment.objects.get(
|
|
pk=appointment_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
context['patient'] = context['appointment'].patient
|
|
except Appointment.DoesNotExist:
|
|
pass
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Set tenant and provider, handle behavior formset."""
|
|
# Set tenant
|
|
form.instance.tenant = self.request.user.tenant
|
|
|
|
# Set provider
|
|
form.instance.provider = self.request.user
|
|
|
|
# Set consultation date if not provided
|
|
if not form.instance.consultation_date:
|
|
form.instance.consultation_date = timezone.now().date()
|
|
|
|
# Get the formset
|
|
context = self.get_context_data()
|
|
behavior_formset = context['behavior_formset']
|
|
|
|
# Validate formset
|
|
if behavior_formset.is_valid():
|
|
# Save the consultation first
|
|
self.object = form.save()
|
|
|
|
# Save the behaviors
|
|
behavior_formset.instance = self.object
|
|
behavior_formset.save()
|
|
|
|
return super().form_valid(form)
|
|
else:
|
|
# Formset is invalid, return to form with errors
|
|
return self.form_invalid(form)
|
|
|
|
|
|
class ABASessionSignView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin, View):
|
|
"""
|
|
Sign an ABA session.
|
|
|
|
Features:
|
|
- Only the provider or admin can sign
|
|
- Records signature timestamp and user
|
|
- Prevents re-signing already signed sessions
|
|
"""
|
|
allowed_roles = [User.Role.ADMIN, User.Role.ABA]
|
|
|
|
def post(self, request, pk):
|
|
"""Sign the session."""
|
|
session = get_object_or_404(
|
|
ABASession,
|
|
pk=pk,
|
|
tenant=request.user.tenant
|
|
)
|
|
|
|
# Check if already signed
|
|
if session.signed_by:
|
|
messages.warning(
|
|
request,
|
|
_("This session has already been signed.")
|
|
)
|
|
return HttpResponseRedirect(
|
|
reverse_lazy('aba:session_detail', kwargs={'pk': pk})
|
|
)
|
|
|
|
# Check if user is the provider or admin
|
|
if session.provider != request.user and request.user.role != User.Role.ADMIN:
|
|
messages.error(
|
|
request,
|
|
_("Only the session provider or an administrator can sign this session.")
|
|
)
|
|
return HttpResponseRedirect(
|
|
reverse_lazy('aba:session_detail', kwargs={'pk': pk})
|
|
)
|
|
|
|
# Sign the session
|
|
session.signed_by = request.user
|
|
session.signed_at = timezone.now()
|
|
session.save()
|
|
|
|
messages.success(
|
|
request,
|
|
_("Session signed successfully!")
|
|
)
|
|
|
|
return HttpResponseRedirect(
|
|
reverse_lazy('aba:session_detail', kwargs={'pk': pk})
|
|
)
|
|
|
|
|
|
class ABAConsultUpdateView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin,
|
|
AuditLogMixin, SuccessMessageMixin, UpdateView):
|
|
"""
|
|
ABA consultation update view (ABA-F-1).
|
|
|
|
Features:
|
|
- Update consultation details
|
|
- Version history
|
|
- Audit trail
|
|
"""
|
|
model = ABAConsult
|
|
form_class = ABAConsultForm
|
|
template_name = 'aba/consult_form.html'
|
|
success_message = _("ABA consultation updated successfully!")
|
|
allowed_roles = [User.Role.ADMIN, User.Role.ABA]
|
|
|
|
def get_success_url(self):
|
|
"""Redirect to consult detail."""
|
|
return reverse_lazy('aba:consult_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add form title, behavior formset, and history."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['form_title'] = _('Update ABA Consultation - %(mrn)s') % {'mrn': self.object.patient.mrn}
|
|
context['submit_text'] = _('Update Consultation')
|
|
context['patient'] = self.object.patient
|
|
|
|
# Add behavior formset
|
|
if self.request.POST:
|
|
context['behavior_formset'] = ABABehaviorFormSet(self.request.POST, instance=self.object)
|
|
else:
|
|
context['behavior_formset'] = ABABehaviorFormSet(instance=self.object)
|
|
|
|
# Add version history if available
|
|
if hasattr(self.object, 'history'):
|
|
context['history'] = self.object.history.all()[:10]
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Handle behavior formset."""
|
|
# Get the formset
|
|
context = self.get_context_data()
|
|
behavior_formset = context['behavior_formset']
|
|
|
|
# Validate formset
|
|
if behavior_formset.is_valid():
|
|
# Save the consultation first
|
|
self.object = form.save()
|
|
|
|
# Save the behaviors
|
|
behavior_formset.instance = self.object
|
|
behavior_formset.save()
|
|
|
|
return super().form_valid(form)
|
|
else:
|
|
# Formset is invalid, return to form with errors
|
|
return self.form_invalid(form)
|
|
|
|
|
|
class PatientABAHistoryView(LoginRequiredMixin, TenantFilterMixin, ListView):
|
|
"""
|
|
Patient ABA history view.
|
|
|
|
Features:
|
|
- All ABA consultations for specific patient
|
|
- Behavior tracking over time
|
|
- Progress visualization
|
|
"""
|
|
model = ABAConsult
|
|
template_name = 'aba/patient_history.html'
|
|
context_object_name = 'consults'
|
|
paginate_by = 50
|
|
|
|
def get_queryset(self):
|
|
"""Get all consults for patient."""
|
|
patient_id = self.kwargs.get('patient_id')
|
|
return ABAConsult.objects.filter(
|
|
patient_id=patient_id,
|
|
tenant=self.request.user.tenant
|
|
).order_by('-consultation_date')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add patient and behavior tracking data."""
|
|
import json
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
patient_id = self.kwargs.get('patient_id')
|
|
context['patient'] = get_object_or_404(
|
|
Patient,
|
|
pk=patient_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
|
|
# Get all behaviors across consultations for this patient
|
|
consults = self.get_queryset()
|
|
all_behaviors = []
|
|
high_intensity_count = 0
|
|
|
|
for consult in consults:
|
|
behaviors = consult.behaviors.all()
|
|
for behavior in behaviors:
|
|
all_behaviors.append({
|
|
'date': consult.consultation_date.strftime('%Y-%m-%d'),
|
|
'behavior': behavior.behavior_description,
|
|
'frequency': behavior.get_frequency_display(),
|
|
'intensity': behavior.get_intensity_display(),
|
|
})
|
|
# Count high intensity behaviors
|
|
if behavior.intensity == 'SEVERE':
|
|
high_intensity_count += 1
|
|
|
|
# Add statistics
|
|
context['total_behaviors_count'] = len(all_behaviors)
|
|
context['high_intensity_count'] = high_intensity_count
|
|
|
|
# Properly serialize to JSON for chart
|
|
context['all_behaviors'] = json.dumps(all_behaviors)
|
|
|
|
return context
|
|
|
|
|
|
class BehaviorTrackingView(LoginRequiredMixin, TenantFilterMixin, ListView):
|
|
"""
|
|
Behavior tracking view across all patients.
|
|
|
|
Features:
|
|
- Track specific behaviors
|
|
- Frequency analysis
|
|
- Intensity trends
|
|
- Intervention effectiveness
|
|
"""
|
|
model = ABABehavior
|
|
template_name = 'aba/behavior_tracking.html'
|
|
context_object_name = 'behaviors'
|
|
paginate_by = 50
|
|
|
|
def get_queryset(self):
|
|
"""Get behaviors with filters."""
|
|
queryset = ABABehavior.objects.filter(
|
|
consult__tenant=self.request.user.tenant
|
|
).select_related('consult', 'consult__patient')
|
|
|
|
# Apply filters
|
|
behavior_type = self.request.GET.get('behavior_type')
|
|
if behavior_type:
|
|
queryset = queryset.filter(behavior_description__icontains=behavior_type)
|
|
|
|
frequency = self.request.GET.get('frequency')
|
|
if frequency:
|
|
queryset = queryset.filter(frequency=frequency)
|
|
|
|
intensity = self.request.GET.get('intensity')
|
|
if intensity:
|
|
queryset = queryset.filter(intensity=intensity)
|
|
|
|
return queryset.order_by('-consult__consultation_date')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add statistics."""
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
queryset = self.get_queryset()
|
|
|
|
# Add statistics
|
|
context['stats'] = {
|
|
'total_behaviors': queryset.count(),
|
|
'high_intensity': queryset.filter(intensity='SEVERE').count(),
|
|
'daily_frequency': queryset.filter(frequency='DAILY').count(),
|
|
}
|
|
|
|
context['frequency_choices'] = ABABehavior.Frequency.choices
|
|
context['intensity_choices'] = ABABehavior.Intensity.choices
|
|
|
|
return context
|
|
|
|
|
|
class RecommendationTrackingView(LoginRequiredMixin, TenantFilterMixin, ListView):
|
|
"""
|
|
Recommendation tracking view.
|
|
|
|
Features:
|
|
- Track recommendations across consultations
|
|
- Implementation status
|
|
- Effectiveness analysis
|
|
"""
|
|
model = ABAConsult
|
|
template_name = 'aba/recommendation_tracking.html'
|
|
context_object_name = 'consults'
|
|
paginate_by = 25
|
|
|
|
def get_queryset(self):
|
|
"""Get consults with recommendations."""
|
|
queryset = super().get_queryset()
|
|
|
|
# Filter only consults with recommendations
|
|
queryset = queryset.exclude(recommendations='').exclude(recommendations__isnull=True)
|
|
|
|
# Apply filters
|
|
patient_id = self.request.GET.get('patient')
|
|
if patient_id:
|
|
queryset = queryset.filter(patient_id=patient_id)
|
|
|
|
return queryset.select_related('patient', 'provider').order_by('-consultation_date')
|
|
|
|
|
|
class ABASessionListView(LoginRequiredMixin, TenantFilterMixin, PaginationMixin,
|
|
HTMXResponseMixin, ListView):
|
|
"""
|
|
ABA session list view.
|
|
|
|
Features:
|
|
- Filter by patient, provider, date range, session type
|
|
- Search by patient name/MRN
|
|
- Role-based filtering
|
|
- Shows unsigned sessions notification
|
|
"""
|
|
model = ABASession
|
|
template_name = 'aba/session_list.html'
|
|
htmx_template_name = 'aba/partials/session_list_partial.html'
|
|
context_object_name = 'sessions'
|
|
paginate_by = 25
|
|
|
|
def get_queryset(self):
|
|
"""Get filtered queryset."""
|
|
queryset = super().get_queryset()
|
|
user = self.request.user
|
|
|
|
# Role-based filtering
|
|
if user.role == User.Role.ABA:
|
|
queryset = queryset.filter(provider=user)
|
|
|
|
# Apply search
|
|
search_query = self.request.GET.get('search', '').strip()
|
|
if search_query:
|
|
queryset = queryset.filter(
|
|
Q(patient__first_name_en__icontains=search_query) |
|
|
Q(patient__last_name_en__icontains=search_query) |
|
|
Q(patient__mrn__icontains=search_query)
|
|
)
|
|
|
|
# Apply filters
|
|
patient_id = self.request.GET.get('patient')
|
|
if patient_id:
|
|
queryset = queryset.filter(patient_id=patient_id)
|
|
|
|
session_type = self.request.GET.get('session_type')
|
|
if session_type:
|
|
queryset = queryset.filter(session_type=session_type)
|
|
|
|
date_from = self.request.GET.get('date_from')
|
|
if date_from:
|
|
queryset = queryset.filter(session_date__gte=date_from)
|
|
|
|
date_to = self.request.GET.get('date_to')
|
|
if date_to:
|
|
queryset = queryset.filter(session_date__lte=date_to)
|
|
|
|
return queryset.select_related('patient', 'provider', 'appointment', 'signed_by').order_by('-session_date')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add unsigned sessions count for current user."""
|
|
context = super().get_context_data(**kwargs)
|
|
user = self.request.user
|
|
|
|
# Get unsigned sessions for current user
|
|
unsigned_sessions_query = ABASession.objects.filter(
|
|
tenant=user.tenant,
|
|
signed_by__isnull=True
|
|
)
|
|
|
|
# Filter by provider if ABA role
|
|
if user.role == User.Role.ABA:
|
|
unsigned_sessions_query = unsigned_sessions_query.filter(provider=user)
|
|
|
|
context['unsigned_sessions_count'] = unsigned_sessions_query.count()
|
|
context['unsigned_sessions'] = unsigned_sessions_query.select_related(
|
|
'patient', 'provider'
|
|
).order_by('-session_date')[:10] # Show latest 10 unsigned sessions
|
|
|
|
return context
|
|
|
|
|
|
class ABASessionDetailView(LoginRequiredMixin, TenantFilterMixin, DetailView):
|
|
"""
|
|
ABA session detail view.
|
|
|
|
Features:
|
|
- Full session details
|
|
- Session type, duration
|
|
- Engagement and cooperation levels
|
|
- Target behaviors and interventions
|
|
- Skill targets with mastery tracking
|
|
- Progress notes and recommendations
|
|
"""
|
|
model = ABASession
|
|
template_name = 'aba/session_detail.html'
|
|
context_object_name = 'session'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add skill targets and progress data."""
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
# Get skill targets
|
|
context['skill_targets'] = self.object.skill_targets.all()
|
|
|
|
# Get previous sessions for comparison
|
|
context['previous_sessions'] = ABASession.objects.filter(
|
|
patient=self.object.patient,
|
|
session_date__lt=self.object.session_date
|
|
).order_by('-session_date')[:5]
|
|
|
|
return context
|
|
|
|
|
|
class ABASessionCreateView(ConsentRequiredMixin, LoginRequiredMixin, RolePermissionMixin,
|
|
AuditLogMixin, SuccessMessageMixin, CreateView):
|
|
"""
|
|
ABA session creation view.
|
|
|
|
Features:
|
|
- Session date, type, duration
|
|
- Engagement and cooperation levels (1-5)
|
|
- Target behaviors and interventions
|
|
- Activities performed
|
|
- Behavioral observations
|
|
- Progress notes
|
|
- Recommendations and home program
|
|
- Skill targets with mastery tracking
|
|
- Consent verification enforced before creation
|
|
"""
|
|
model = ABASession
|
|
form_class = ABASessionForm
|
|
template_name = 'aba/session_form.html'
|
|
success_message = _("ABA session recorded successfully!")
|
|
allowed_roles = [User.Role.ADMIN, User.Role.ABA]
|
|
|
|
# Consent enforcement
|
|
consent_service_type = 'ABA'
|
|
consent_error_message = _(
|
|
"Patient must sign ABA therapy consent and photo/video consent "
|
|
"before session can be documented."
|
|
)
|
|
|
|
def get_success_url(self):
|
|
"""Redirect to session detail."""
|
|
return reverse_lazy('aba:session_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def get_patient(self):
|
|
"""Get patient for consent verification."""
|
|
patient_id = self.request.GET.get('patient')
|
|
appointment_id = self.request.GET.get('appointment_id')
|
|
|
|
if patient_id:
|
|
return Patient.objects.get(
|
|
pk=patient_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
elif appointment_id:
|
|
appointment = Appointment.objects.get(
|
|
pk=appointment_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
return appointment.patient
|
|
|
|
return None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add form title, patient/appointment info, and skill target formset."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['form_title'] = _('ABA Session Note')
|
|
context['submit_text'] = _('Save Session')
|
|
|
|
# Add skill target formset
|
|
if self.request.POST:
|
|
context['skill_target_formset'] = ABASkillTargetFormSet(self.request.POST)
|
|
else:
|
|
context['skill_target_formset'] = ABASkillTargetFormSet()
|
|
|
|
# Get patient if provided
|
|
patient_id = self.request.GET.get('patient')
|
|
if patient_id:
|
|
try:
|
|
context['patient'] = Patient.objects.get(
|
|
pk=patient_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
except Patient.DoesNotExist:
|
|
pass
|
|
|
|
# Get appointment if provided
|
|
appointment_id = self.request.GET.get('appointment_id')
|
|
if appointment_id:
|
|
try:
|
|
context['appointment'] = Appointment.objects.get(
|
|
pk=appointment_id,
|
|
tenant=self.request.user.tenant
|
|
)
|
|
context['patient'] = context['appointment'].patient
|
|
except Appointment.DoesNotExist:
|
|
pass
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Set tenant and provider, handle skill target formset."""
|
|
# Set tenant
|
|
form.instance.tenant = self.request.user.tenant
|
|
|
|
# Set provider
|
|
form.instance.provider = self.request.user
|
|
|
|
# Set session date if not provided
|
|
if not form.instance.session_date:
|
|
form.instance.session_date = timezone.now().date()
|
|
|
|
# Get the formset
|
|
context = self.get_context_data()
|
|
skill_target_formset = context['skill_target_formset']
|
|
|
|
# Validate formset
|
|
if skill_target_formset.is_valid():
|
|
# Save the session first
|
|
self.object = form.save()
|
|
|
|
# Save the skill targets
|
|
skill_target_formset.instance = self.object
|
|
skill_target_formset.save()
|
|
|
|
return super().form_valid(form)
|
|
else:
|
|
# Formset is invalid, return to form with errors
|
|
return self.form_invalid(form)
|
|
|
|
|
|
class ABASessionUpdateView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin,
|
|
AuditLogMixin, SuccessMessageMixin, UpdateView):
|
|
"""
|
|
ABA session update view.
|
|
|
|
Features:
|
|
- Update session details
|
|
- Version history
|
|
- Audit trail
|
|
"""
|
|
model = ABASession
|
|
form_class = ABASessionForm
|
|
template_name = 'aba/session_form.html'
|
|
success_message = _("ABA session updated successfully!")
|
|
allowed_roles = [User.Role.ADMIN, User.Role.ABA]
|
|
|
|
def get_success_url(self):
|
|
"""Redirect to session detail."""
|
|
return reverse_lazy('aba:session_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Add form title, skill target formset, and history."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['form_title'] = _('Update ABA Session - %(mrn)s') % {'mrn': self.object.patient.mrn}
|
|
context['submit_text'] = _('Update Session')
|
|
context['patient'] = self.object.patient
|
|
|
|
# Add skill target formset
|
|
if self.request.POST:
|
|
context['skill_target_formset'] = ABASkillTargetFormSet(self.request.POST, instance=self.object)
|
|
else:
|
|
context['skill_target_formset'] = ABASkillTargetFormSet(instance=self.object)
|
|
|
|
# Add version history if available
|
|
if hasattr(self.object, 'history'):
|
|
context['history'] = self.object.history.all()[:10]
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Handle skill target formset."""
|
|
# Get the formset
|
|
context = self.get_context_data()
|
|
skill_target_formset = context['skill_target_formset']
|
|
|
|
# Validate formset
|
|
if skill_target_formset.is_valid():
|
|
# Save the session first
|
|
self.object = form.save()
|
|
|
|
# Save the skill targets
|
|
skill_target_formset.instance = self.object
|
|
skill_target_formset.save()
|
|
|
|
return super().form_valid(form)
|
|
else:
|
|
# Formset is invalid, return to form with errors
|
|
return self.form_invalid(form)
|