Marwan Alwali a710d1c4d8 update
2025-09-11 19:01:55 +03:00

1191 lines
47 KiB
Python

"""
Forms for Appointments app CRUD operations.
"""
from django import forms
from django.core.exceptions import ValidationError
from django.utils import timezone
from datetime import datetime, time, timedelta
from .models import (
AppointmentRequest, SlotAvailability, WaitingQueue, QueueEntry,
TelemedicineSession, AppointmentTemplate
)
from patients.models import PatientProfile
from accounts.models import User
from hr.models import Employee
class AppointmentRequestForm(forms.ModelForm):
"""
Form for appointment request management.
Patient is set automatically in the view; it is NOT exposed here.
"""
class Meta:
model = AppointmentRequest
# do not include 'patient' so it cannot be tampered with
exclude = ['patient','status']
fields = [
'provider', 'appointment_type', 'specialty', 'preferred_date',
'preferred_time', 'duration_minutes', 'priority', 'chief_complaint',
'clinical_notes', 'is_telemedicine', 'location', 'room_number'
]
widgets = {
'provider': forms.Select(attrs={'class': 'form-select'}),
'appointment_type': forms.Select(attrs={'class': 'form-select'}),
'specialty': forms.Select(attrs={'class': 'form-select'}),
'preferred_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'preferred_time': forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}),
'duration_minutes': forms.NumberInput(attrs={'class': 'form-control', 'min': '15', 'step': '15'}),
'priority': forms.Select(attrs={'class': 'form-select'}),
'chief_complaint': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'clinical_notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'is_telemedicine': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'location': forms.TextInput(attrs={'class': 'form-control'}),
'room_number': forms.TextInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
# patient is optional to receive; we don't render it, but can use if needed
# self._patient = kwargs.pop('patient', None)
super().__init__(*args, **kwargs)
# Scope provider list to tenant
if user and hasattr(user, 'tenant'):
self.fields['provider'].queryset = User.objects.filter(
tenant=user.tenant,
is_active=True,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
def clean_preferred_date(self):
preferred_date = self.cleaned_data.get('preferred_date')
if preferred_date and preferred_date < timezone.now().date():
raise ValidationError('Appointment cannot be scheduled in the past.')
return preferred_date
def clean_duration_minutes(self):
duration = self.cleaned_data.get('duration_minutes')
if duration and duration < 15:
raise ValidationError('Appointment duration must be at least 15 minutes.')
if duration and duration > 480: # 8 hours
raise ValidationError('Appointment duration cannot exceed 8 hours.')
return duration
class SlotAvailabilityForm(forms.ModelForm):
"""
Form for slot availability management.
"""
class Meta:
model = SlotAvailability
fields = [
'provider', 'date', 'start_time', 'end_time', 'duration_minutes',
'max_appointments', 'location', 'room_number', 'specialty',
'availability_type', 'is_active', 'supports_telemedicine'
]
widgets = {
'provider': forms.Select(attrs={'class': 'form-select'}),
'date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'start_time': forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}),
'end_time': forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}),
'duration_minutes': forms.NumberInput(attrs={'class': 'form-control', 'min': '15', 'step': '15'}),
'max_appointments': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'location': forms.TextInput(attrs={'class': 'form-control'}),
'room_number': forms.TextInput(attrs={'class': 'form-control'}),
'specialty': forms.TextInput(attrs={'class': 'form-control'}),
'availability_type': forms.Select(attrs={'class': 'form-select'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'supports_telemedicine': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user and hasattr(user, 'tenant'):
self.fields['provider'].queryset = User.objects.filter(
tenant=user.tenant,
is_active=True,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
def clean(self):
cleaned_data = super().clean()
date = cleaned_data.get('date')
start_time = cleaned_data.get('start_time')
end_time = cleaned_data.get('end_time')
if date and date < timezone.now().date():
raise ValidationError('Availability date cannot be in the past.')
if start_time and end_time and start_time >= end_time:
raise ValidationError('Start time must be before end time.')
return cleaned_data
class WaitingQueueForm(forms.ModelForm):
"""
Form for waiting queue management.
"""
class Meta:
model = WaitingQueue
fields = [
'name', 'description', 'queue_type', 'location', 'specialty',
'max_queue_size', 'average_service_time_minutes', 'is_active'
]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'queue_type': forms.Select(attrs={'class': 'form-select'}),
'location': forms.TextInput(attrs={'class': 'form-control'}),
'specialty': forms.TextInput(attrs={'class': 'form-control'}),
'max_queue_size': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'average_service_time_minutes': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
tenant = kwargs.pop('tenant', None)
super().__init__(*args, **kwargs)
if user and tenant:
self.fields['provider'].queryset = User.objects.filter(
tenant=tenant,
is_active=True,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
class QueueEntryForm(forms.ModelForm):
"""
Form for queue entry management.
"""
class Meta:
model = QueueEntry
fields = [
'queue', 'patient', 'appointment', 'priority_score', 'assigned_provider',
'status', 'notes'
]
widgets = {
'queue': forms.Select(attrs={'class': 'form-select'}),
'patient': forms.Select(attrs={'class': 'form-select'}),
'appointment': forms.Select(attrs={'class': 'form-select'}),
'priority_score': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.1', 'min': '0'}),
'assigned_provider': forms.Select(attrs={'class': 'form-select'}),
'status': forms.Select(attrs={'class': 'form-select'}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user and hasattr(user, 'tenant'):
self.fields['queue'].queryset = WaitingQueue.objects.filter(
tenant=user.tenant,
is_active=True
).order_by('name')
self.fields['patient'].queryset = PatientProfile.objects.filter(
tenant=user.tenant,
is_active=True
).order_by('last_name', 'first_name')
self.fields['appointment'].queryset = AppointmentRequest.objects.filter(
tenant=user.tenant,
status__in=['SCHEDULED', 'CONFIRMED']
).order_by('-preferred_date')
class TelemedicineSessionForm(forms.ModelForm):
"""
Form for telemedicine session management.
"""
class Meta:
model = TelemedicineSession
fields = [
'appointment', 'platform', 'meeting_url', 'meeting_id', 'meeting_password',
'scheduled_start', 'scheduled_end', 'status', 'waiting_room_enabled',
'recording_enabled', 'recording_consent'
]
widgets = {
'appointment': forms.Select(attrs={'class': 'form-select'}),
'platform': forms.Select(attrs={'class': 'form-select'}),
'meeting_url': forms.URLInput(attrs={'class': 'form-control'}),
'meeting_id': forms.TextInput(attrs={'class': 'form-control'}),
'meeting_password': forms.PasswordInput(attrs={'class': 'form-control'}),
'scheduled_start': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'scheduled_end': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'status': forms.Select(attrs={'class': 'form-select'}),
'waiting_room_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'recording_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'recording_consent': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user and hasattr(user, 'tenant'):
self.fields['appointment'].queryset = AppointmentRequest.objects.filter(
tenant=user.tenant,
is_telemedicine=True,
status__in=['SCHEDULED', 'CONFIRMED', 'IN_PROGRESS']
).order_by('-preferred_date')
def clean(self):
cleaned_data = super().clean()
start_time = cleaned_data.get('session_start_time')
end_time = cleaned_data.get('session_end_time')
if start_time and end_time and start_time >= end_time:
raise ValidationError('Start time must be before end time.')
return cleaned_data
class AppointmentTemplateForm(forms.ModelForm):
"""
Form for appointment template management.
"""
class Meta:
model = AppointmentTemplate
fields = [
'name', 'description', 'appointment_type', 'duration_minutes',
'specialty', 'advance_booking_days', 'minimum_notice_hours',
'pre_appointment_instructions', 'post_appointment_instructions',
'is_active'
]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'appointment_type': forms.TextInput(attrs={'class': 'form-control'}),
'duration_minutes': forms.NumberInput(attrs={'class': 'form-control', 'min': '15', 'step': '15'}),
'specialty': forms.TextInput(attrs={'class': 'form-control'}),
'advance_booking_days': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'minimum_notice_hours': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'pre_appointment_instructions': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
'post_appointment_instructions': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user and hasattr(user, 'tenant'):
self.fields['provider'].queryset = User.objects.filter(
tenant=user.tenant,
is_active=True,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
class AppointmentSearchForm(forms.Form):
"""
Form for searching appointment data.
"""
search = forms.CharField(
max_length=255,
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Search appointments, patients, providers...'
})
)
appointment_type = forms.ChoiceField(
choices=[('', 'All Types')] + list(AppointmentRequest._meta.get_field('appointment_type').choices),
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
status = forms.ChoiceField(
choices=[('', 'All Status')] + list(AppointmentRequest._meta.get_field('status').choices),
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
priority = forms.ChoiceField(
choices=[('', 'All Priorities')] + list(AppointmentRequest._meta.get_field('priority').choices),
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
provider = forms.ModelChoiceField(
queryset=User.objects.none(),
required=False,
empty_label='All Providers',
widget=forms.Select(attrs={'class': 'form-select'})
)
specialty = forms.CharField(
max_length=100,
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Specialty'
})
)
date_from = forms.DateField(
required=False,
widget=forms.DateInput(attrs={
'class': 'form-control',
'type': 'date'
})
)
date_to = forms.DateField(
required=False,
widget=forms.DateInput(attrs={
'class': 'form-control',
'type': 'date'
})
)
is_telemedicine = forms.ChoiceField(
choices=[
('', 'All Appointments'),
('true', 'Telemedicine Only'),
('false', 'In-Person Only')
],
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user and hasattr(user, 'tenant'):
self.fields['provider'].queryset = User.objects.filter(
tenant=user.tenant,
is_active=True,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
class QueueSearchForm(forms.Form):
"""
Form for searching queues.
"""
search = forms.CharField(
max_length=200,
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Search queues...'
})
)
queue_type = forms.ChoiceField(
choices=[('', 'All Types')] + [
('PROVIDER', 'Provider Queue'),
('SPECIALTY', 'Specialty Queue'),
('LOCATION', 'Location Queue'),
('PROCEDURE', 'Procedure Queue'),
('EMERGENCY', 'Emergency Queue'),
],
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
is_active = forms.ChoiceField(
choices=[('', 'All'), ('true', 'Active'), ('false', 'Inactive')],
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
class SlotSearchForm(forms.Form):
"""
Form for searching appointment slots.
"""
search = forms.CharField(
max_length=200,
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Search slots...'
})
)
provider = forms.ModelChoiceField(
queryset=User.objects.none(),
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
date_from = forms.DateField(
required=False,
widget=forms.DateInput(attrs={
'class': 'form-control',
'type': 'date'
})
)
date_to = forms.DateField(
required=False,
widget=forms.DateInput(attrs={
'class': 'form-control',
'type': 'date'
})
)
is_available = forms.ChoiceField(
choices=[('', 'All'), ('true', 'Available'), ('false', 'Booked')],
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user:
self.fields['provider'].queryset = User.objects.filter(
tenant=user.tenant,
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
).order_by('last_name', 'first_name')
# from django import forms
# from django.core.exceptions import ValidationError
# from django.utils import timezone
# from django.contrib.auth.models import User
# from crispy_forms.helper import FormHelper
# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div
# from crispy_forms.bootstrap import FormActions
# from datetime import datetime, timedelta
#
# from .models import Appointment, AppointmentConfirmation, Queue, TelemedicineSession
# from patients.models import Patient
# from core.models import Department
#
#
# class AppointmentSchedulingForm(forms.ModelForm):
# """
# Form for appointment scheduling
# """
# patient_search = forms.CharField(
# required=False,
# widget=forms.TextInput(attrs={
# 'class': 'form-control',
# 'placeholder': 'Search patient by name, ID, or phone...',
# 'data-toggle': 'patient-search'
# })
# )
# preferred_time_1 = forms.TimeField(
# required=False,
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
# preferred_time_2 = forms.TimeField(
# required=False,
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
# preferred_time_3 = forms.TimeField(
# required=False,
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
# special_instructions = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# send_confirmation = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# send_reminder = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# class Meta:
# model = Appointment
# fields = [
# 'patient', 'provider', 'department', 'appointment_type',
# 'appointment_date', 'appointment_time', 'duration',
# 'urgency', 'reason', 'notes', 'special_instructions',
# 'send_confirmation', 'send_reminder'
# ]
# widgets = {
# 'patient': forms.Select(attrs={'class': 'form-control'}),
# 'provider': forms.Select(attrs={'class': 'form-control'}),
# 'department': forms.Select(attrs={'class': 'form-control'}),
# 'appointment_type': forms.Select(attrs={'class': 'form-control'}),
# 'appointment_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
# 'appointment_time': forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}),
# 'duration': forms.NumberInput(attrs={'class': 'form-control'}),
# 'urgency': forms.Select(attrs={'class': 'form-control'}),
# 'reason': forms.TextInput(attrs={'class': 'form-control'}),
# 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# }
#
# def __init__(self, *args, **kwargs):
# tenant = kwargs.pop('tenant', None)
# super().__init__(*args, **kwargs)
#
# if tenant:
# self.fields['patient'].queryset = Patient.objects.filter(tenant=tenant)
# self.fields['provider'].queryset = User.objects.filter(
# tenant=tenant,
# groups__name__in=['Doctors', 'Nurses', 'Specialists']
# )
# self.fields['department'].queryset = Department.objects.filter(tenant=tenant)
#
# # Set minimum date to today
# self.fields['appointment_date'].widget.attrs['min'] = timezone.now().date().isoformat()
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Patient Information',
# 'patient_search',
# 'patient'
# ),
# Fieldset(
# 'Appointment Details',
# Row(
# Column('provider', css_class='form-group col-md-6 mb-0'),
# Column('department', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# Row(
# Column('appointment_type', css_class='form-group col-md-6 mb-0'),
# Column('urgency', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# Row(
# Column('appointment_date', css_class='form-group col-md-4 mb-0'),
# Column('appointment_time', css_class='form-group col-md-4 mb-0'),
# Column('duration', css_class='form-group col-md-4 mb-0'),
# css_class='form-row'
# ),
# 'reason',
# 'notes',
# 'special_instructions'
# ),
# Fieldset(
# 'Preferred Times (Alternative Options)',
# Row(
# Column('preferred_time_1', css_class='form-group col-md-4 mb-0'),
# Column('preferred_time_2', css_class='form-group col-md-4 mb-0'),
# Column('preferred_time_3', css_class='form-group col-md-4 mb-0'),
# css_class='form-row'
# )
# ),
# Fieldset(
# 'Notifications',
# HTML('<div class="form-check">'),
# 'send_confirmation',
# HTML(
# '<label class="form-check-label" for="id_send_confirmation">Send appointment confirmation</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'send_reminder',
# HTML('<label class="form-check-label" for="id_send_reminder">Send appointment reminder</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Schedule Appointment', css_class='btn btn-primary'),
# HTML('<a href="{% url \'appointments:appointment_list\' %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
# def clean(self):
# cleaned_data = super().clean()
# appointment_date = cleaned_data.get('appointment_date')
# appointment_time = cleaned_data.get('appointment_time')
# provider = cleaned_data.get('provider')
#
# if appointment_date and appointment_time:
# appointment_datetime = datetime.combine(appointment_date, appointment_time)
#
# # Check if appointment is in the past
# if appointment_datetime < timezone.now():
# raise ValidationError('Appointment cannot be scheduled in the past.')
#
# # Check provider availability
# if provider and self.check_provider_conflict(provider, appointment_datetime):
# raise ValidationError('Provider is not available at the selected time.')
#
# return cleaned_data
#
# def check_provider_conflict(self, provider, appointment_datetime):
# """Check if provider has conflicting appointments"""
# duration = self.cleaned_data.get('duration', 30)
# end_time = appointment_datetime + timedelta(minutes=duration)
#
# conflicts = Appointment.objects.filter(
# provider=provider,
# appointment_date=appointment_datetime.date(),
# status__in=['scheduled', 'confirmed', 'in_progress']
# ).exclude(id=self.instance.id if self.instance else None)
#
# for conflict in conflicts:
# conflict_start = datetime.combine(conflict.appointment_date, conflict.appointment_time)
# conflict_end = conflict_start + timedelta(minutes=conflict.duration)
#
# if (appointment_datetime < conflict_end and end_time > conflict_start):
# return True
#
# return False
#
#
# class AppointmentConfirmationForm(forms.ModelForm):
# """
# Form for appointment confirmation
# """
# confirmation_method = forms.ChoiceField(
# choices=[
# ('phone', 'Phone Call'),
# ('email', 'Email'),
# ('sms', 'SMS'),
# ('in_person', 'In Person'),
# ('online', 'Online Portal')
# ],
# required=True,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# contact_attempts = forms.IntegerField(
# initial=1,
# min_value=1,
# max_value=5,
# widget=forms.NumberInput(attrs={'class': 'form-control'})
# )
# confirmation_notes = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# reschedule_requested = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# new_preferred_date = forms.DateField(
# required=False,
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
# )
# new_preferred_time = forms.TimeField(
# required=False,
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
#
# class Meta:
# model = AppointmentConfirmation
# fields = [
# 'confirmation_method', 'contact_attempts', 'confirmation_notes',
# 'reschedule_requested', 'new_preferred_date', 'new_preferred_time'
# ]
#
# def __init__(self, *args, **kwargs):
# appointment = kwargs.pop('appointment', None)
# super().__init__(*args, **kwargs)
#
# self.appointment = appointment
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Confirmation Details',
# Row(
# Column('confirmation_method', css_class='form-group col-md-6 mb-0'),
# Column('contact_attempts', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# 'confirmation_notes'
# ),
# Fieldset(
# 'Reschedule Request',
# HTML('<div class="form-check">'),
# 'reschedule_requested',
# HTML(
# '<label class="form-check-label" for="id_reschedule_requested">Patient requested reschedule</label>'),
# HTML('</div>'),
# Row(
# Column('new_preferred_date', css_class='form-group col-md-6 mb-0'),
# Column('new_preferred_time', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# )
# ),
# FormActions(
# Submit('submit', 'Confirm Appointment', css_class='btn btn-primary'),
# HTML(
# '<a href="{% url \'appointments:appointment_detail\' appointment.id %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
# def clean(self):
# cleaned_data = super().clean()
# reschedule_requested = cleaned_data.get('reschedule_requested')
# new_preferred_date = cleaned_data.get('new_preferred_date')
# new_preferred_time = cleaned_data.get('new_preferred_time')
#
# if reschedule_requested:
# if not new_preferred_date:
# raise ValidationError('New preferred date is required when reschedule is requested.')
# if not new_preferred_time:
# raise ValidationError('New preferred time is required when reschedule is requested.')
#
# return cleaned_data
#
#
# class QueueManagementForm(forms.ModelForm):
# """
# Form for queue management
# """
# estimated_wait_time = forms.IntegerField(
# required=False,
# widget=forms.NumberInput(attrs={'class': 'form-control'})
# )
# priority_adjustment = forms.ChoiceField(
# choices=[
# ('none', 'No Change'),
# ('increase', 'Increase Priority'),
# ('decrease', 'Decrease Priority')
# ],
# required=False,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# queue_notes = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# notify_patient = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# class Meta:
# model = Queue
# fields = [
# 'queue_type', 'priority', 'estimated_wait_time',
# 'priority_adjustment', 'queue_notes', 'notify_patient'
# ]
# widgets = {
# 'queue_type': forms.Select(attrs={'class': 'form-control'}),
# 'priority': forms.Select(attrs={'class': 'form-control'})
# }
#
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Queue Configuration',
# Row(
# Column('queue_type', css_class='form-group col-md-6 mb-0'),
# Column('priority', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# Row(
# Column('estimated_wait_time', css_class='form-group col-md-6 mb-0'),
# Column('priority_adjustment', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# 'queue_notes'
# ),
# Fieldset(
# 'Notifications',
# HTML('<div class="form-check">'),
# 'notify_patient',
# HTML('<label class="form-check-label" for="id_notify_patient">Notify patient of queue status</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Update Queue', css_class='btn btn-primary'),
# HTML('<a href="{% url \'appointments:queue_list\' %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
#
# class TelemedicineSetupForm(forms.ModelForm):
# """
# Form for telemedicine session setup
# """
# platform = forms.ChoiceField(
# choices=[
# ('zoom', 'Zoom'),
# ('teams', 'Microsoft Teams'),
# ('webex', 'Cisco Webex'),
# ('meet', 'Google Meet'),
# ('custom', 'Custom Platform')
# ],
# required=True,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# test_connection = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# send_instructions = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# backup_phone = forms.CharField(
# required=False,
# widget=forms.TextInput(attrs={'class': 'form-control'})
# )
# technical_support_contact = forms.CharField(
# required=False,
# widget=forms.TextInput(attrs={'class': 'form-control'})
# )
# session_recording = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# class Meta:
# model = TelemedicineSession
# fields = [
# 'platform', 'meeting_url', 'meeting_id', 'meeting_password',
# 'test_connection', 'send_instructions', 'backup_phone',
# 'technical_support_contact', 'session_recording'
# ]
# widgets = {
# 'meeting_url': forms.URLInput(attrs={'class': 'form-control'}),
# 'meeting_id': forms.TextInput(attrs={'class': 'form-control'}),
# 'meeting_password': forms.TextInput(attrs={'class': 'form-control'})
# }
#
# def __init__(self, *args, **kwargs):
# appointment = kwargs.pop('appointment', None)
# super().__init__(*args, **kwargs)
#
# self.appointment = appointment
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Platform Configuration',
# 'platform',
# 'meeting_url',
# Row(
# Column('meeting_id', css_class='form-group col-md-6 mb-0'),
# Column('meeting_password', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# )
# ),
# Fieldset(
# 'Support Information',
# Row(
# Column('backup_phone', css_class='form-group col-md-6 mb-0'),
# Column('technical_support_contact', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# )
# ),
# Fieldset(
# 'Session Options',
# HTML('<div class="form-check">'),
# 'test_connection',
# HTML(
# '<label class="form-check-label" for="id_test_connection">Test connection before appointment</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'send_instructions',
# HTML(
# '<label class="form-check-label" for="id_send_instructions">Send setup instructions to patient</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'session_recording',
# HTML(
# '<label class="form-check-label" for="id_session_recording">Record session (with consent)</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Setup Telemedicine', css_class='btn btn-primary'),
# HTML(
# '<a href="{% url \'appointments:appointment_detail\' appointment.id %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
# def clean_meeting_url(self):
# meeting_url = self.cleaned_data.get('meeting_url')
# platform = self.cleaned_data.get('platform')
#
# if platform and meeting_url:
# # Validate URL format based on platform
# if platform == 'zoom' and 'zoom.us' not in meeting_url:
# raise ValidationError('Invalid Zoom meeting URL format.')
# elif platform == 'teams' and 'teams.microsoft.com' not in meeting_url:
# raise ValidationError('Invalid Microsoft Teams meeting URL format.')
# elif platform == 'webex' and 'webex.com' not in meeting_url:
# raise ValidationError('Invalid Webex meeting URL format.')
# elif platform == 'meet' and 'meet.google.com' not in meeting_url:
# raise ValidationError('Invalid Google Meet URL format.')
#
# return meeting_url
#
#
# class AppointmentRescheduleForm(forms.Form):
# """
# Form for appointment rescheduling
# """
# new_date = forms.DateField(
# required=True,
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
# )
# new_time = forms.TimeField(
# required=True,
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
# new_provider = forms.ModelChoiceField(
# queryset=None,
# required=False,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# reschedule_reason = forms.ChoiceField(
# choices=[
# ('patient_request', 'Patient Request'),
# ('provider_unavailable', 'Provider Unavailable'),
# ('emergency', 'Emergency'),
# ('equipment_issue', 'Equipment Issue'),
# ('other', 'Other')
# ],
# required=True,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# notes = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# notify_patient = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# def __init__(self, *args, **kwargs):
# tenant = kwargs.pop('tenant', None)
# appointment = kwargs.pop('appointment', None)
# super().__init__(*args, **kwargs)
#
# if tenant:
# self.fields['new_provider'].queryset = User.objects.filter(
# tenant=tenant,
# groups__name__in=['Doctors', 'Nurses', 'Specialists']
# )
#
# # Set minimum date to today
# self.fields['new_date'].widget.attrs['min'] = timezone.now().date().isoformat()
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'New Appointment Details',
# Row(
# Column('new_date', css_class='form-group col-md-6 mb-0'),
# Column('new_time', css_class='form-group col-md-6 mb-0'),
# css_class='form-row'
# ),
# 'new_provider'
# ),
# Fieldset(
# 'Reschedule Information',
# 'reschedule_reason',
# 'notes'
# ),
# Fieldset(
# 'Notifications',
# HTML('<div class="form-check">'),
# 'notify_patient',
# HTML('<label class="form-check-label" for="id_notify_patient">Notify patient of reschedule</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Reschedule Appointment', css_class='btn btn-primary'),
# HTML(
# '<a href="{% url \'appointments:appointment_detail\' appointment.id %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
#
# class AppointmentCancellationForm(forms.Form):
# """
# Form for appointment cancellation
# """
# cancellation_reason = forms.ChoiceField(
# choices=[
# ('patient_request', 'Patient Request'),
# ('provider_unavailable', 'Provider Unavailable'),
# ('patient_no_show', 'Patient No Show'),
# ('emergency', 'Emergency'),
# ('equipment_failure', 'Equipment Failure'),
# ('other', 'Other')
# ],
# required=True,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# cancellation_notes = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# offer_reschedule = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# notify_patient = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# refund_required = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Cancellation Details',
# 'cancellation_reason',
# 'cancellation_notes'
# ),
# Fieldset(
# 'Follow-up Actions',
# HTML('<div class="form-check">'),
# 'offer_reschedule',
# HTML(
# '<label class="form-check-label" for="id_offer_reschedule">Offer to reschedule appointment</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'notify_patient',
# HTML('<label class="form-check-label" for="id_notify_patient">Notify patient of cancellation</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'refund_required',
# HTML('<label class="form-check-label" for="id_refund_required">Refund required</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Cancel Appointment', css_class='btn btn-danger'),
# HTML(
# '<a href="{% url \'appointments:appointment_detail\' appointment.id %}" class="btn btn-secondary">Back</a>')
# )
# )
#
#
# class AppointmentCheckInForm(forms.Form):
# """
# Form for appointment check-in
# """
# arrival_time = forms.TimeField(
# initial=timezone.now().time(),
# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'})
# )
# insurance_verified = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# copay_collected = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# forms_completed = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# vitals_required = forms.BooleanField(
# required=False,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
# special_needs = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 2})
# )
#
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# Fieldset(
# 'Check-in Information',
# 'arrival_time',
# 'special_needs'
# ),
# Fieldset(
# 'Pre-visit Tasks',
# HTML('<div class="form-check">'),
# 'insurance_verified',
# HTML('<label class="form-check-label" for="id_insurance_verified">Insurance verified</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'copay_collected',
# HTML('<label class="form-check-label" for="id_copay_collected">Copay collected</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'forms_completed',
# HTML('<label class="form-check-label" for="id_forms_completed">Forms completed</label>'),
# HTML('</div>'),
# HTML('<div class="form-check">'),
# 'vitals_required',
# HTML('<label class="form-check-label" for="id_vitals_required">Vitals required</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Check In Patient', css_class='btn btn-primary'),
# HTML(
# '<a href="{% url \'appointments:appointment_detail\' appointment.id %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#
#
# class BulkAppointmentForm(forms.Form):
# """
# Form for bulk appointment operations
# """
# action = forms.ChoiceField(
# choices=[
# ('confirm', 'Confirm Appointments'),
# ('reschedule', 'Reschedule Appointments'),
# ('cancel', 'Cancel Appointments'),
# ('send_reminders', 'Send Reminders')
# ],
# required=True,
# widget=forms.Select(attrs={'class': 'form-control'})
# )
# appointment_ids = forms.CharField(
# widget=forms.HiddenInput()
# )
# bulk_date = forms.DateField(
# required=False,
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
# )
# bulk_reason = forms.CharField(
# required=False,
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
# )
# notify_patients = forms.BooleanField(
# required=False,
# initial=True,
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
# )
#
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# self.helper = FormHelper()
# self.helper.layout = Layout(
# 'appointment_ids',
# Fieldset(
# 'Bulk Operation',
# 'action',
# 'bulk_date',
# 'bulk_reason'
# ),
# Fieldset(
# 'Notifications',
# HTML('<div class="form-check">'),
# 'notify_patients',
# HTML('<label class="form-check-label" for="id_notify_patients">Notify patients</label>'),
# HTML('</div>')
# ),
# FormActions(
# Submit('submit', 'Execute Bulk Operation', css_class='btn btn-primary'),
# HTML('<a href="{% url \'appointments:appointment_list\' %}" class="btn btn-secondary">Cancel</a>')
# )
# )
#