""" 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, date from .models import * from patients.models import PatientProfile from accounts.models import User from hr.models import Employee, Department 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, employee_profile__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') class WaitingListForm(forms.ModelForm): """ Form for creating and updating waiting list entries. """ class Meta: model = WaitingList fields = [ 'patient', 'department', 'provider', 'appointment_type', 'specialty', 'priority', 'urgency_score', 'clinical_indication', 'diagnosis_codes', 'preferred_date', 'preferred_time', 'flexible_scheduling', 'earliest_acceptable_date', 'latest_acceptable_date', 'acceptable_days', 'acceptable_times', 'contact_method', 'contact_phone', 'contact_email', 'requires_interpreter', 'interpreter_language', 'accessibility_requirements', 'transportation_needed', 'insurance_verified', 'authorization_required', 'referring_provider', 'referral_date', 'referral_urgency', 'notes' ] widgets = { 'patient': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'department': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'provider': forms.Select(attrs={ 'class': 'form-select' }), 'appointment_type': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'specialty': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'priority': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'urgency_score': forms.NumberInput(attrs={ 'class': 'form-control', 'min': 1, 'max': 10, 'required': True }), 'clinical_indication': forms.Textarea(attrs={ 'class': 'form-control', 'rows': 4, 'required': True, 'placeholder': 'Describe the clinical reason for this appointment request...' }), 'diagnosis_codes': forms.Textarea(attrs={ 'class': 'form-control', 'rows': 2, 'placeholder': 'Enter ICD-10 codes separated by commas' }), 'preferred_date': forms.DateInput(attrs={ 'class': 'form-control', 'type': 'date', 'min': date.today().isoformat() }), 'preferred_time': forms.TimeInput(attrs={ 'class': 'form-control', 'type': 'time' }), 'flexible_scheduling': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'earliest_acceptable_date': forms.DateInput(attrs={ 'class': 'form-control', 'type': 'date', 'min': date.today().isoformat() }), 'latest_acceptable_date': forms.DateInput(attrs={ 'class': 'form-control', 'type': 'date' }), 'acceptable_days': forms.CheckboxSelectMultiple(attrs={ 'class': 'form-check-input' }), 'contact_method': forms.Select(attrs={ 'class': 'form-select', 'required': True }), 'contact_phone': forms.TextInput(attrs={ 'class': 'form-control', 'placeholder': '(555) 123-4567' }), 'contact_email': forms.EmailInput(attrs={ 'class': 'form-control', 'placeholder': 'patient@example.com' }), 'requires_interpreter': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'interpreter_language': forms.TextInput(attrs={ 'class': 'form-control', 'placeholder': 'e.g., Spanish, Mandarin, ASL' }), 'accessibility_requirements': forms.Textarea(attrs={ 'class': 'form-control', 'rows': 3, 'placeholder': 'Describe any accessibility needs...' }), 'transportation_needed': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'insurance_verified': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'authorization_required': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'referring_provider': forms.TextInput(attrs={ 'class': 'form-control', 'placeholder': 'Dr. Smith, Internal Medicine' }), 'referral_date': forms.DateInput(attrs={ 'class': 'form-control', 'type': 'date' }), 'referral_urgency': forms.Select(attrs={ 'class': 'form-select' }), 'notes': forms.Textarea(attrs={ 'class': 'form-control', 'rows': 4, 'placeholder': 'Additional notes and comments...' }), } def __init__(self, *args, **kwargs): self.tenant = kwargs.pop('tenant', None) super().__init__(*args, **kwargs) # Filter choices based on tenant if self.tenant: self.fields['patient'].queryset = self.fields['patient'].queryset.filter( tenant=self.tenant ) self.fields['department'].queryset = self.fields['department'].queryset.filter( tenant=self.tenant ) if 'provider' in self.fields: self.fields['provider'].queryset = self.fields['provider'].queryset.filter( tenant=self.tenant ) def clean(self): cleaned_data = super().clean() # Validate date ranges preferred_date = cleaned_data.get('preferred_date') earliest_date = cleaned_data.get('earliest_acceptable_date') latest_date = cleaned_data.get('latest_acceptable_date') if preferred_date and preferred_date < date.today(): raise ValidationError("Preferred date cannot be in the past.") if earliest_date and latest_date and earliest_date > latest_date: raise ValidationError("Earliest acceptable date must be before latest acceptable date.") if preferred_date and earliest_date and preferred_date < earliest_date: raise ValidationError("Preferred date must be within acceptable date range.") if preferred_date and latest_date and preferred_date > latest_date: raise ValidationError("Preferred date must be within acceptable date range.") # Validate contact information contact_method = cleaned_data.get('contact_method') contact_phone = cleaned_data.get('contact_phone') contact_email = cleaned_data.get('contact_email') if contact_method == 'PHONE' and not contact_phone: raise ValidationError("Phone number is required when phone is selected as contact method.") if contact_method == 'EMAIL' and not contact_email: raise ValidationError("Email address is required when email is selected as contact method.") # Validate interpreter requirements requires_interpreter = cleaned_data.get('requires_interpreter') interpreter_language = cleaned_data.get('interpreter_language') if requires_interpreter and not interpreter_language: raise ValidationError("Interpreter language is required when interpreter services are needed.") return cleaned_data class WaitingListContactLogForm(forms.ModelForm): """ Form for logging contact attempts with waiting list patients. """ class Meta: model = WaitingListContactLog fields = [ 'contact_method', 'contact_outcome', 'appointment_offered', 'offered_date', 'offered_time', 'patient_response', 'notes', 'next_contact_date' ] widgets = { 'contact_method': forms.Select(attrs={ 'class': 'form-select form-select-sm', 'required': True }), 'contact_outcome': forms.Select(attrs={ 'class': 'form-select form-select-sm', 'required': True }), 'appointment_offered': forms.CheckboxInput(attrs={ 'class': 'form-check-input' }), 'offered_date': forms.DateInput(attrs={ 'class': 'form-control form-control-sm', 'type': 'date' }), 'offered_time': forms.TimeInput(attrs={ 'class': 'form-control form-control-sm', 'type': 'time' }), 'patient_response': forms.Select(attrs={ 'class': 'form-select form-select-sm' }), 'notes': forms.Textarea(attrs={ 'class': 'form-control form-control-sm', 'rows': 4, 'placeholder': 'Notes from contact attempt...' }), 'next_contact_date': forms.DateInput(attrs={ 'class': 'form-control form-control-sm', 'type': 'date', 'min': date.today().isoformat() }), } def clean(self): cleaned_data = super().clean() appointment_offered = cleaned_data.get('appointment_offered') offered_date = cleaned_data.get('offered_date') offered_time = cleaned_data.get('offered_time') patient_response = cleaned_data.get('patient_response') if appointment_offered: if not offered_date: raise ValidationError("Offered date is required when appointment is offered.") if not offered_time: raise ValidationError("Offered time is required when appointment is offered.") if not patient_response: raise ValidationError("Patient response is required when appointment is offered.") next_contact_date = cleaned_data.get('next_contact_date') if next_contact_date and next_contact_date < date.today(): raise ValidationError("Next contact date cannot be in the past.") return cleaned_data class WaitingListFilterForm(forms.Form): """ Form for filtering waiting list entries. """ PRIORITY_CHOICES = [ ('', 'All Priorities'), ('EMERGENCY', 'Emergency'), ('STAT', 'STAT'), ('URGENT', 'Urgent'), ('ROUTINE', 'Routine'), ] STATUS_CHOICES = [ ('', 'All Status'), ('ACTIVE', 'Active'), ('CONTACTED', 'Contacted'), ('OFFERED', 'Appointment Offered'), ('SCHEDULED', 'Scheduled'), ('CANCELLED', 'Cancelled'), ('EXPIRED', 'Expired'), ] department = forms.ModelChoiceField( queryset=None, required=False, empty_label="All Departments", widget=forms.Select(attrs={'class': 'form-select'}) ) specialty = forms.ChoiceField( choices=[('', 'All Specialties')] + WaitingList._meta.get_field('specialty').choices, required=False, widget=forms.Select(attrs={'class': 'form-select'}) ) priority = forms.ChoiceField( choices=PRIORITY_CHOICES, required=False, widget=forms.Select(attrs={'class': 'form-select'}) ) status = forms.ChoiceField( choices=STATUS_CHOICES, required=False, widget=forms.Select(attrs={'class': 'form-select'}) ) provider = forms.ModelChoiceField( queryset=None, required=False, empty_label="All Providers", 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' }) ) urgency_min = forms.IntegerField( required=False, min_value=1, max_value=10, widget=forms.NumberInput(attrs={ 'class': 'form-control', 'placeholder': 'Min urgency (1-10)' }) ) urgency_max = forms.IntegerField( required=False, min_value=1, max_value=10, widget=forms.NumberInput(attrs={ 'class': 'form-control', 'placeholder': 'Max urgency (1-10)' }) ) def __init__(self, *args, **kwargs): tenant = kwargs.pop('tenant', None) super().__init__(*args, **kwargs) if tenant: self.fields['department'].queryset = Department.objects.filter(tenant=tenant) self.fields['provider'].queryset = User.objects.filter( tenant=tenant ) class WaitingListBulkActionForm(forms.Form): """ Form for bulk actions on waiting list entries. """ ACTION_CHOICES = [ ('', 'Select Action'), ('contact', 'Mark as Contacted'), ('cancel', 'Cancel Entries'), ('update_priority', 'Update Priority'), ('transfer_provider', 'Transfer to Provider'), ('export', 'Export Selected'), ] action = forms.ChoiceField( choices=ACTION_CHOICES, required=True, widget=forms.Select(attrs={'class': 'form-select'}) ) # Fields for specific actions new_priority = forms.ChoiceField( choices=WaitingList._meta.get_field('priority').choices, required=False, widget=forms.Select(attrs={'class': 'form-select'}) ) transfer_provider = forms.ModelChoiceField( queryset=None, required=False, widget=forms.Select(attrs={'class': 'form-select'}) ) contact_notes = forms.CharField( required=False, widget=forms.Textarea(attrs={ 'class': 'form-control', 'rows': 3, 'placeholder': 'Notes for contact action...' }) ) cancellation_reason = forms.CharField( required=False, widget=forms.Textarea(attrs={ 'class': 'form-control', 'rows': 3, 'placeholder': 'Reason for cancellation...' }) ) def __init__(self, *args, **kwargs): tenant = kwargs.pop('tenant', None) super().__init__(*args, **kwargs) if tenant: from django.contrib.auth import get_user_model User = get_user_model() self.fields['transfer_provider'].queryset = User.objects.filter( tenant=tenant ) # 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('