340 lines
10 KiB
Python
340 lines
10 KiB
Python
"""
|
|
Feedback forms - Forms for feedback management
|
|
"""
|
|
from django import forms
|
|
|
|
from apps.organizations.models import Department, Hospital, Patient, Physician
|
|
|
|
from .models import Feedback, FeedbackResponse, FeedbackStatus, FeedbackType, FeedbackCategory
|
|
|
|
|
|
class FeedbackForm(forms.ModelForm):
|
|
"""Form for creating and editing feedback"""
|
|
|
|
class Meta:
|
|
model = Feedback
|
|
fields = [
|
|
'patient',
|
|
'is_anonymous',
|
|
'contact_name',
|
|
'contact_email',
|
|
'contact_phone',
|
|
'hospital',
|
|
'department',
|
|
'physician',
|
|
'feedback_type',
|
|
'title',
|
|
'message',
|
|
'category',
|
|
'subcategory',
|
|
'rating',
|
|
'priority',
|
|
'encounter_id',
|
|
]
|
|
widgets = {
|
|
'patient': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'id': 'id_patient'
|
|
}),
|
|
'is_anonymous': forms.CheckboxInput(attrs={
|
|
'class': 'form-check-input',
|
|
'id': 'id_is_anonymous'
|
|
}),
|
|
'contact_name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter contact name'
|
|
}),
|
|
'contact_email': forms.EmailInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter email address'
|
|
}),
|
|
'contact_phone': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter phone number'
|
|
}),
|
|
'hospital': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
'department': forms.Select(attrs={
|
|
'class': 'form-select'
|
|
}),
|
|
'physician': forms.Select(attrs={
|
|
'class': 'form-select'
|
|
}),
|
|
'feedback_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
'title': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter feedback title',
|
|
'required': True
|
|
}),
|
|
'message': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 5,
|
|
'placeholder': 'Enter your feedback message...',
|
|
'required': True
|
|
}),
|
|
'category': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
'subcategory': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter subcategory (optional)'
|
|
}),
|
|
'rating': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 1,
|
|
'max': 5,
|
|
'placeholder': 'Rate from 1 to 5'
|
|
}),
|
|
'priority': forms.Select(attrs={
|
|
'class': 'form-select'
|
|
}),
|
|
'encounter_id': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter encounter ID (optional)'
|
|
}),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# Filter hospitals based on user permissions
|
|
if user:
|
|
if not user.is_px_admin() and user.hospital:
|
|
self.fields['hospital'].queryset = Hospital.objects.filter(
|
|
id=user.hospital.id,
|
|
status='active'
|
|
)
|
|
else:
|
|
self.fields['hospital'].queryset = Hospital.objects.filter(status='active')
|
|
|
|
# Set initial hospital if user has one
|
|
if user and user.hospital and not self.instance.pk:
|
|
self.fields['hospital'].initial = user.hospital
|
|
|
|
# Filter departments and physicians based on selected hospital
|
|
if self.instance.pk and self.instance.hospital:
|
|
self.fields['department'].queryset = Department.objects.filter(
|
|
hospital=self.instance.hospital,
|
|
status='active'
|
|
)
|
|
self.fields['physician'].queryset = Physician.objects.filter(
|
|
hospital=self.instance.hospital,
|
|
status='active'
|
|
)
|
|
else:
|
|
self.fields['department'].queryset = Department.objects.none()
|
|
self.fields['physician'].queryset = Physician.objects.none()
|
|
|
|
# Make patient optional if anonymous
|
|
if self.data.get('is_anonymous'):
|
|
self.fields['patient'].required = False
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
is_anonymous = cleaned_data.get('is_anonymous')
|
|
patient = cleaned_data.get('patient')
|
|
contact_name = cleaned_data.get('contact_name')
|
|
|
|
# Validate anonymous feedback
|
|
if is_anonymous:
|
|
if not contact_name:
|
|
raise forms.ValidationError(
|
|
"Contact name is required for anonymous feedback."
|
|
)
|
|
else:
|
|
if not patient:
|
|
raise forms.ValidationError(
|
|
"Please select a patient or mark as anonymous."
|
|
)
|
|
|
|
# Validate rating
|
|
rating = cleaned_data.get('rating')
|
|
if rating is not None and (rating < 1 or rating > 5):
|
|
raise forms.ValidationError("Rating must be between 1 and 5.")
|
|
|
|
return cleaned_data
|
|
|
|
|
|
class FeedbackResponseForm(forms.ModelForm):
|
|
"""Form for adding responses to feedback"""
|
|
|
|
class Meta:
|
|
model = FeedbackResponse
|
|
fields = ['response_type', 'message', 'is_internal']
|
|
widgets = {
|
|
'response_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
'message': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Enter your response...',
|
|
'required': True
|
|
}),
|
|
'is_internal': forms.CheckboxInput(attrs={
|
|
'class': 'form-check-input'
|
|
}),
|
|
}
|
|
|
|
|
|
class FeedbackFilterForm(forms.Form):
|
|
"""Form for filtering feedback list"""
|
|
|
|
search = forms.CharField(
|
|
required=False,
|
|
widget=forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Search by title, message, patient...'
|
|
})
|
|
)
|
|
|
|
feedback_type = forms.ChoiceField(
|
|
required=False,
|
|
choices=[('', 'All Types')] + list(FeedbackType.choices),
|
|
widget=forms.Select(attrs={'class': 'form-select'})
|
|
)
|
|
|
|
status = forms.ChoiceField(
|
|
required=False,
|
|
choices=[('', 'All Statuses')] + list(FeedbackStatus.choices),
|
|
widget=forms.Select(attrs={'class': 'form-select'})
|
|
)
|
|
|
|
category = forms.ChoiceField(
|
|
required=False,
|
|
choices=[('', 'All Categories')] + list(FeedbackCategory.choices),
|
|
widget=forms.Select(attrs={'class': 'form-select'})
|
|
)
|
|
|
|
sentiment = forms.ChoiceField(
|
|
required=False,
|
|
choices=[
|
|
('', 'All Sentiments'),
|
|
('positive', 'Positive'),
|
|
('neutral', 'Neutral'),
|
|
('negative', 'Negative'),
|
|
],
|
|
widget=forms.Select(attrs={'class': 'form-select'})
|
|
)
|
|
|
|
priority = forms.ChoiceField(
|
|
required=False,
|
|
choices=[
|
|
('', 'All Priorities'),
|
|
('low', 'Low'),
|
|
('medium', 'Medium'),
|
|
('high', 'High'),
|
|
('urgent', 'Urgent'),
|
|
],
|
|
widget=forms.Select(attrs={'class': 'form-select'})
|
|
)
|
|
|
|
hospital = forms.ModelChoiceField(
|
|
required=False,
|
|
queryset=Hospital.objects.filter(status='active'),
|
|
widget=forms.Select(attrs={'class': 'form-select'}),
|
|
empty_label='All Hospitals'
|
|
)
|
|
|
|
department = forms.ModelChoiceField(
|
|
required=False,
|
|
queryset=Department.objects.filter(status='active'),
|
|
widget=forms.Select(attrs={'class': 'form-select'}),
|
|
empty_label='All Departments'
|
|
)
|
|
|
|
rating_min = forms.IntegerField(
|
|
required=False,
|
|
min_value=1,
|
|
max_value=5,
|
|
widget=forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Min rating'
|
|
})
|
|
)
|
|
|
|
rating_max = forms.IntegerField(
|
|
required=False,
|
|
min_value=1,
|
|
max_value=5,
|
|
widget=forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Max rating'
|
|
})
|
|
)
|
|
|
|
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_featured = forms.BooleanField(
|
|
required=False,
|
|
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
)
|
|
|
|
requires_follow_up = forms.BooleanField(
|
|
required=False,
|
|
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
)
|
|
|
|
|
|
class FeedbackStatusChangeForm(forms.Form):
|
|
"""Form for changing feedback status"""
|
|
|
|
status = forms.ChoiceField(
|
|
choices=FeedbackStatus.choices,
|
|
widget=forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
})
|
|
)
|
|
|
|
note = forms.CharField(
|
|
required=False,
|
|
widget=forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Add a note about this status change (optional)...'
|
|
})
|
|
)
|
|
|
|
|
|
class FeedbackAssignForm(forms.Form):
|
|
"""Form for assigning feedback to a user"""
|
|
|
|
user_id = forms.UUIDField(
|
|
widget=forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
})
|
|
)
|
|
|
|
note = forms.CharField(
|
|
required=False,
|
|
widget=forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 2,
|
|
'placeholder': 'Add a note about this assignment (optional)...'
|
|
})
|
|
)
|