Fix hospital fields in forms - Add HospitalFieldMixin and update templates
PHASE 1: Add HospitalFieldMixin to forms without it - apps/complaints/forms.py: SLAConfigForm, EscalationRuleForm - apps/feedback/forms.py: FeedbackForm - apps/rca/forms.py: RootCauseAnalysisForm PHASE 2: Update templates to conditionally hide hospital field labels - templates/complaints/complaint_form.html - templates/complaints/inquiry_form.html - templates/complaints/complaint_threshold_form.html - templates/complaints/escalation_rule_form.html - templates/feedback/feedback_form.html PHASE 3: Remove redundant manual hospital filtering code - Removed manual __init__ hospital logic from forms now using mixin Behavior: - PX Admin: Sees hospital dropdown (can select any hospital) - Hospital Admin/Staff: Hospital field hidden, auto-set to their hospital - Cleaner code: Mixin handles all role-based filtering automatically
This commit is contained in:
parent
b57ce661bb
commit
da0ca4ee19
@ -765,7 +765,7 @@ class InquiryForm(HospitalFieldMixin, forms.ModelForm):
|
|||||||
).order_by('name')
|
).order_by('name')
|
||||||
|
|
||||||
|
|
||||||
class SLAConfigForm(forms.ModelForm):
|
class SLAConfigForm(HospitalFieldMixin, forms.ModelForm):
|
||||||
"""Form for creating and editing SLA configurations"""
|
"""Form for creating and editing SLA configurations"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -779,14 +779,6 @@ class SLAConfigForm(forms.ModelForm):
|
|||||||
'reminder_hours_before': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
|
'reminder_hours_before': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
|
||||||
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
user = kwargs.pop('user', None)
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Filter hospitals based on user role
|
|
||||||
if user and not user.is_px_admin() and user.hospital:
|
|
||||||
self.fields['hospital'].queryset = Hospital.objects.filter(id=user.hospital.id)
|
|
||||||
self.fields['hospital'].initial = user.hospital
|
self.fields['hospital'].initial = user.hospital
|
||||||
self.fields['hospital'].widget.attrs['readonly'] = True
|
self.fields['hospital'].widget.attrs['readonly'] = True
|
||||||
|
|
||||||
@ -823,7 +815,7 @@ class SLAConfigForm(forms.ModelForm):
|
|||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class EscalationRuleForm(forms.ModelForm):
|
class EscalationRuleForm(HospitalFieldMixin, forms.ModelForm):
|
||||||
"""Form for creating and editing escalation rules"""
|
"""Form for creating and editing escalation rules"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -840,11 +832,11 @@ class EscalationRuleForm(forms.ModelForm):
|
|||||||
'name': forms.TextInput(attrs={'class': 'form-control'}),
|
'name': forms.TextInput(attrs={'class': 'form-control'}),
|
||||||
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
||||||
'escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
|
'escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
|
||||||
'max_escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
|
'max_escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': 1}),
|
||||||
'trigger_on_overdue': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
'trigger_on_overdue': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
||||||
'trigger_hours_overdue': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
|
'trigger_hours_overdue': forms.NumberInput(attrs={'class': 'form-control', 'min': 0}),
|
||||||
'reminder_escalation_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
'reminder_escalation_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
||||||
'reminder_escalation_hours': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
|
'reminder_escalation_hours': forms.NumberInput(attrs={'class': 'form-control', 'min': 0}),
|
||||||
'escalate_to_role': forms.Select(attrs={'class': 'form-select', 'id': 'escalate_to_role'}),
|
'escalate_to_role': forms.Select(attrs={'class': 'form-select', 'id': 'escalate_to_role'}),
|
||||||
'escalate_to_user': forms.Select(attrs={'class': 'form-select'}),
|
'escalate_to_user': forms.Select(attrs={'class': 'form-select'}),
|
||||||
'severity_filter': forms.Select(attrs={'class': 'form-select'}),
|
'severity_filter': forms.Select(attrs={'class': 'form-select'}),
|
||||||
@ -853,23 +845,16 @@ class EscalationRuleForm(forms.ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
user = kwargs.pop('user', None)
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Filter hospitals based on user role
|
|
||||||
if user and not user.is_px_admin() and user.hospital:
|
|
||||||
self.fields['hospital'].queryset = Hospital.objects.filter(id=user.hospital.id)
|
|
||||||
self.fields['hospital'].initial = user.hospital
|
|
||||||
self.fields['hospital'].widget.attrs['readonly'] = True
|
|
||||||
|
|
||||||
# Filter users for escalate_to_user field
|
# Filter users for escalate_to_user field
|
||||||
from apps.accounts.models import User
|
from apps.accounts.models import User
|
||||||
if user and user.is_px_admin():
|
if self.user and self.user.is_px_admin():
|
||||||
self.fields['escalate_to_user'].queryset = User.objects.filter(is_active=True)
|
self.fields['escalate_to_user'].queryset = User.objects.filter(is_active=True)
|
||||||
elif user and user.hospital:
|
elif self.user and self.user.hospital:
|
||||||
self.fields['escalate_to_user'].queryset = User.objects.filter(
|
self.fields['escalate_to_user'].queryset = User.objects.filter(
|
||||||
is_active=True,
|
is_active=True,
|
||||||
hospital=user.hospital
|
hospital=self.user.hospital
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.fields['escalate_to_user'].queryset = User.objects.none()
|
self.fields['escalate_to_user'].queryset = User.objects.none()
|
||||||
|
|||||||
@ -1,161 +1,116 @@
|
|||||||
"""
|
"""
|
||||||
Feedback forms - Forms for feedback management
|
Feedback forms - Forms for feedback management
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from apps.organizations.models import Department, Hospital, Patient, Staff
|
from apps.organizations.models import Department, Hospital, Patient, Staff
|
||||||
|
from apps.core.form_mixins import HospitalFieldMixin
|
||||||
from .models import Feedback, FeedbackResponse, FeedbackStatus, FeedbackType, FeedbackCategory
|
from .models import Feedback, FeedbackResponse, FeedbackStatus, FeedbackType, FeedbackCategory
|
||||||
|
|
||||||
|
|
||||||
class FeedbackForm(forms.ModelForm):
|
class FeedbackForm(HospitalFieldMixin, forms.ModelForm):
|
||||||
"""Form for creating and editing feedback"""
|
"""Form for creating and editing feedback"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Feedback
|
model = Feedback
|
||||||
fields = [
|
fields = [
|
||||||
'patient',
|
"patient",
|
||||||
'is_anonymous',
|
"is_anonymous",
|
||||||
'contact_name',
|
"contact_name",
|
||||||
'contact_email',
|
"contact_email",
|
||||||
'contact_phone',
|
"contact_phone",
|
||||||
'hospital',
|
"hospital",
|
||||||
'department',
|
"department",
|
||||||
'staff',
|
"staff",
|
||||||
'feedback_type',
|
"feedback_type",
|
||||||
'title',
|
"title",
|
||||||
'message',
|
"message",
|
||||||
'category',
|
"category",
|
||||||
'subcategory',
|
"subcategory",
|
||||||
'rating',
|
"rating",
|
||||||
'priority',
|
"priority",
|
||||||
'encounter_id',
|
"encounter_id",
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'patient': forms.Select(attrs={
|
"patient": forms.Select(attrs={"class": "form-select", "id": "id_patient"}),
|
||||||
'class': 'form-select',
|
"is_anonymous": forms.CheckboxInput(attrs={"class": "form-check-input", "id": "id_is_anonymous"}),
|
||||||
'id': 'id_patient'
|
"contact_name": forms.TextInput(attrs={"class": "form-control", "placeholder": "Enter contact name"}),
|
||||||
}),
|
"contact_email": forms.EmailInput(attrs={"class": "form-control", "placeholder": "Enter email address"}),
|
||||||
'is_anonymous': forms.CheckboxInput(attrs={
|
"contact_phone": forms.TextInput(attrs={"class": "form-control", "placeholder": "Enter phone number"}),
|
||||||
'class': 'form-check-input',
|
"hospital": forms.Select(attrs={"class": "form-select", "required": True}),
|
||||||
'id': 'id_is_anonymous'
|
"department": forms.Select(attrs={"class": "form-select"}),
|
||||||
}),
|
"staff": forms.Select(attrs={"class": "form-select"}),
|
||||||
'contact_name': forms.TextInput(attrs={
|
"feedback_type": forms.Select(attrs={"class": "form-select", "required": True}),
|
||||||
'class': 'form-control',
|
"title": forms.TextInput(
|
||||||
'placeholder': 'Enter contact name'
|
attrs={"class": "form-control", "placeholder": "Enter feedback title", "required": True}
|
||||||
}),
|
),
|
||||||
'contact_email': forms.EmailInput(attrs={
|
"message": forms.Textarea(
|
||||||
'class': 'form-control',
|
attrs={
|
||||||
'placeholder': 'Enter email address'
|
"class": "form-control",
|
||||||
}),
|
"rows": 5,
|
||||||
'contact_phone': forms.TextInput(attrs={
|
"placeholder": "Enter your feedback message...",
|
||||||
'class': 'form-control',
|
"required": True,
|
||||||
'placeholder': 'Enter phone number'
|
}
|
||||||
}),
|
),
|
||||||
'hospital': forms.Select(attrs={
|
"category": forms.Select(attrs={"class": "form-select", "required": True}),
|
||||||
'class': 'form-select',
|
"subcategory": forms.TextInput(
|
||||||
'required': True
|
attrs={"class": "form-control", "placeholder": "Enter subcategory (optional)"}
|
||||||
}),
|
),
|
||||||
'department': forms.Select(attrs={
|
"rating": forms.NumberInput(
|
||||||
'class': 'form-select'
|
attrs={"class": "form-control", "min": 1, "max": 5, "placeholder": "Rate from 1 to 5"}
|
||||||
}),
|
),
|
||||||
'staff': forms.Select(attrs={
|
"priority": forms.Select(attrs={"class": "form-select"}),
|
||||||
'class': 'form-select'
|
"encounter_id": forms.TextInput(
|
||||||
}),
|
attrs={"class": "form-control", "placeholder": "Enter encounter ID (optional)"}
|
||||||
'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):
|
def __init__(self, *args, **kwargs):
|
||||||
user = kwargs.pop('user', None)
|
user = kwargs.pop("user", None)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Filter hospitals based on user permissions
|
# Filter hospitals based on user permissions
|
||||||
if user:
|
if user:
|
||||||
if not user.is_px_admin() and user.hospital:
|
if not user.is_px_admin() and user.hospital:
|
||||||
self.fields['hospital'].queryset = Hospital.objects.filter(
|
self.fields["hospital"].queryset = Hospital.objects.filter(id=user.hospital.id, status="active")
|
||||||
id=user.hospital.id,
|
|
||||||
status='active'
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.fields['hospital'].queryset = Hospital.objects.filter(status='active')
|
self.fields["hospital"].queryset = Hospital.objects.filter(status="active")
|
||||||
|
|
||||||
# Set initial hospital if user has one
|
# Set initial hospital if user has one
|
||||||
if user and user.hospital and not self.instance.pk:
|
if user and user.hospital and not self.instance.pk:
|
||||||
self.fields['hospital'].initial = user.hospital
|
self.fields["hospital"].initial = user.hospital
|
||||||
|
|
||||||
# Filter departments and physicians based on selected hospital
|
# Filter departments and physicians based on selected hospital
|
||||||
if self.instance.pk and hasattr(self.instance, 'hospital') and self.instance.hospital_id:
|
if self.instance.pk and hasattr(self.instance, "hospital") and self.instance.hospital_id:
|
||||||
self.fields['department'].queryset = Department.objects.filter(
|
self.fields["department"].queryset = Department.objects.filter(
|
||||||
hospital=self.instance.hospital,
|
hospital=self.instance.hospital, status="active"
|
||||||
status='active'
|
|
||||||
)
|
|
||||||
self.fields['staff'].queryset = Staff.objects.filter(
|
|
||||||
hospital=self.instance.hospital,
|
|
||||||
status='active'
|
|
||||||
)
|
)
|
||||||
|
self.fields["staff"].queryset = Staff.objects.filter(hospital=self.instance.hospital, status="active")
|
||||||
else:
|
else:
|
||||||
self.fields['department'].queryset = Department.objects.none()
|
self.fields["department"].queryset = Department.objects.none()
|
||||||
self.fields['staff'].queryset = Staff.objects.none()
|
self.fields["staff"].queryset = Staff.objects.none()
|
||||||
|
|
||||||
# Make patient optional if anonymous
|
# Make patient optional if anonymous
|
||||||
if self.data.get('is_anonymous'):
|
if self.data.get("is_anonymous"):
|
||||||
self.fields['patient'].required = False
|
self.fields["patient"].required = False
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
cleaned_data = super().clean()
|
||||||
is_anonymous = cleaned_data.get('is_anonymous')
|
is_anonymous = cleaned_data.get("is_anonymous")
|
||||||
patient = cleaned_data.get('patient')
|
patient = cleaned_data.get("patient")
|
||||||
contact_name = cleaned_data.get('contact_name')
|
contact_name = cleaned_data.get("contact_name")
|
||||||
|
|
||||||
# Validate anonymous feedback
|
# Validate anonymous feedback
|
||||||
if is_anonymous:
|
if is_anonymous:
|
||||||
if not contact_name:
|
if not contact_name:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError("Contact name is required for anonymous feedback.")
|
||||||
"Contact name is required for anonymous feedback."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if not patient:
|
if not patient:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError("Please select a patient or mark as anonymous.")
|
||||||
"Please select a patient or mark as anonymous."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Validate rating
|
# Validate rating
|
||||||
rating = cleaned_data.get('rating')
|
rating = cleaned_data.get("rating")
|
||||||
if rating is not None and (rating < 1 or rating > 5):
|
if rating is not None and (rating < 1 or rating > 5):
|
||||||
raise forms.ValidationError("Rating must be between 1 and 5.")
|
raise forms.ValidationError("Rating must be between 1 and 5.")
|
||||||
|
|
||||||
@ -167,21 +122,13 @@ class FeedbackResponseForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FeedbackResponse
|
model = FeedbackResponse
|
||||||
fields = ['response_type', 'message', 'is_internal']
|
fields = ["response_type", "message", "is_internal"]
|
||||||
widgets = {
|
widgets = {
|
||||||
'response_type': forms.Select(attrs={
|
"response_type": forms.Select(attrs={"class": "form-select", "required": True}),
|
||||||
'class': 'form-select',
|
"message": forms.Textarea(
|
||||||
'required': True
|
attrs={"class": "form-control", "rows": 4, "placeholder": "Enter your response...", "required": True}
|
||||||
}),
|
),
|
||||||
'message': forms.Textarea(attrs={
|
"is_internal": forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||||
'class': 'form-control',
|
|
||||||
'rows': 4,
|
|
||||||
'placeholder': 'Enter your response...',
|
|
||||||
'required': True
|
|
||||||
}),
|
|
||||||
'is_internal': forms.CheckboxInput(attrs={
|
|
||||||
'class': 'form-check-input'
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -190,111 +137,86 @@ class FeedbackFilterForm(forms.Form):
|
|||||||
|
|
||||||
search = forms.CharField(
|
search = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.TextInput(attrs={
|
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "Search by title, message, patient..."}),
|
||||||
'class': 'form-control',
|
|
||||||
'placeholder': 'Search by title, message, patient...'
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
feedback_type = forms.ChoiceField(
|
feedback_type = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=[('', 'All Types')] + list(FeedbackType.choices),
|
choices=[("", "All Types")] + list(FeedbackType.choices),
|
||||||
widget=forms.Select(attrs={'class': 'form-select'})
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=[('', 'All Statuses')] + list(FeedbackStatus.choices),
|
choices=[("", "All Statuses")] + list(FeedbackStatus.choices),
|
||||||
widget=forms.Select(attrs={'class': 'form-select'})
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
category = forms.ChoiceField(
|
category = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=[('', 'All Categories')] + list(FeedbackCategory.choices),
|
choices=[("", "All Categories")] + list(FeedbackCategory.choices),
|
||||||
widget=forms.Select(attrs={'class': 'form-select'})
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
sentiment = forms.ChoiceField(
|
sentiment = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=[
|
choices=[
|
||||||
('', 'All Sentiments'),
|
("", "All Sentiments"),
|
||||||
('positive', 'Positive'),
|
("positive", "Positive"),
|
||||||
('neutral', 'Neutral'),
|
("neutral", "Neutral"),
|
||||||
('negative', 'Negative'),
|
("negative", "Negative"),
|
||||||
],
|
],
|
||||||
widget=forms.Select(attrs={'class': 'form-select'})
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
priority = forms.ChoiceField(
|
priority = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
choices=[
|
choices=[
|
||||||
('', 'All Priorities'),
|
("", "All Priorities"),
|
||||||
('low', 'Low'),
|
("low", "Low"),
|
||||||
('medium', 'Medium'),
|
("medium", "Medium"),
|
||||||
('high', 'High'),
|
("high", "High"),
|
||||||
('urgent', 'Urgent'),
|
("urgent", "Urgent"),
|
||||||
],
|
],
|
||||||
widget=forms.Select(attrs={'class': 'form-select'})
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
hospital = forms.ModelChoiceField(
|
hospital = forms.ModelChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=Hospital.objects.filter(status='active'),
|
queryset=Hospital.objects.filter(status="active"),
|
||||||
widget=forms.Select(attrs={'class': 'form-select'}),
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
empty_label='All Hospitals'
|
empty_label="All Hospitals",
|
||||||
)
|
)
|
||||||
|
|
||||||
department = forms.ModelChoiceField(
|
department = forms.ModelChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=Department.objects.filter(status='active'),
|
queryset=Department.objects.filter(status="active"),
|
||||||
widget=forms.Select(attrs={'class': 'form-select'}),
|
widget=forms.Select(attrs={"class": "form-select"}),
|
||||||
empty_label='All Departments'
|
empty_label="All Departments",
|
||||||
)
|
)
|
||||||
|
|
||||||
rating_min = forms.IntegerField(
|
rating_min = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
max_value=5,
|
max_value=5,
|
||||||
widget=forms.NumberInput(attrs={
|
widget=forms.NumberInput(attrs={"class": "form-control", "placeholder": "Min rating"}),
|
||||||
'class': 'form-control',
|
|
||||||
'placeholder': 'Min rating'
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rating_max = forms.IntegerField(
|
rating_max = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
max_value=5,
|
max_value=5,
|
||||||
widget=forms.NumberInput(attrs={
|
widget=forms.NumberInput(attrs={"class": "form-control", "placeholder": "Max rating"}),
|
||||||
'class': 'form-control',
|
|
||||||
'placeholder': 'Max rating'
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
date_from = forms.DateField(
|
date_from = forms.DateField(required=False, widget=forms.DateInput(attrs={"class": "form-control", "type": "date"}))
|
||||||
required=False,
|
|
||||||
widget=forms.DateInput(attrs={
|
|
||||||
'class': 'form-control',
|
|
||||||
'type': 'date'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
date_to = forms.DateField(
|
date_to = forms.DateField(required=False, widget=forms.DateInput(attrs={"class": "form-control", "type": "date"}))
|
||||||
required=False,
|
|
||||||
widget=forms.DateInput(attrs={
|
|
||||||
'class': 'form-control',
|
|
||||||
'type': 'date'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
is_featured = forms.BooleanField(
|
is_featured = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={"class": "form-check-input"}))
|
||||||
required=False,
|
|
||||||
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
||||||
)
|
|
||||||
|
|
||||||
requires_follow_up = forms.BooleanField(
|
requires_follow_up = forms.BooleanField(
|
||||||
required=False,
|
required=False, widget=forms.CheckboxInput(attrs={"class": "form-check-input"})
|
||||||
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -302,38 +224,29 @@ class FeedbackStatusChangeForm(forms.Form):
|
|||||||
"""Form for changing feedback status"""
|
"""Form for changing feedback status"""
|
||||||
|
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=FeedbackStatus.choices,
|
choices=FeedbackStatus.choices, widget=forms.Select(attrs={"class": "form-select", "required": True})
|
||||||
widget=forms.Select(attrs={
|
|
||||||
'class': 'form-select',
|
|
||||||
'required': True
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
note = forms.CharField(
|
note = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.Textarea(attrs={
|
widget=forms.Textarea(
|
||||||
'class': 'form-control',
|
attrs={
|
||||||
'rows': 3,
|
"class": "form-control",
|
||||||
'placeholder': 'Add a note about this status change (optional)...'
|
"rows": 3,
|
||||||
})
|
"placeholder": "Add a note about this status change (optional)...",
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FeedbackAssignForm(forms.Form):
|
class FeedbackAssignForm(forms.Form):
|
||||||
"""Form for assigning feedback to a user"""
|
"""Form for assigning feedback to a user"""
|
||||||
|
|
||||||
user_id = forms.UUIDField(
|
user_id = forms.UUIDField(widget=forms.Select(attrs={"class": "form-select", "required": True}))
|
||||||
widget=forms.Select(attrs={
|
|
||||||
'class': 'form-select',
|
|
||||||
'required': True
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
note = forms.CharField(
|
note = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.Textarea(attrs={
|
widget=forms.Textarea(
|
||||||
'class': 'form-control',
|
attrs={"class": "form-control", "rows": 2, "placeholder": "Add a note about this assignment (optional)..."}
|
||||||
'rows': 2,
|
),
|
||||||
'placeholder': 'Add a note about this assignment (optional)...'
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
RCA (Root Cause Analysis) forms
|
RCA (Root Cause Analysis) forms
|
||||||
"""
|
"""
|
||||||
|
RCA (Root Cause Analysis) forms
|
||||||
|
"""
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from apps.core.models import PriorityChoices
|
from apps.core.models import PriorityChoices
|
||||||
|
from apps.core.form_mixins import HospitalFieldMixin
|
||||||
from .models import (
|
from .models import (
|
||||||
RCAActionStatus,
|
RCAActionStatus,
|
||||||
RCAActionType,
|
RCAActionType,
|
||||||
@ -19,7 +20,7 @@ from .models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RootCauseAnalysisForm(forms.ModelForm):
|
class RootCauseAnalysisForm(HospitalFieldMixin, forms.ModelForm):
|
||||||
"""Form for creating and editing RootCauseAnalysis"""
|
"""Form for creating and editing RootCauseAnalysis"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -70,7 +71,6 @@ class RootCauseAnalysisForm(forms.ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
user = kwargs.pop('user', None)
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Filter assigned_to to show only active users
|
# Filter assigned_to to show only active users
|
||||||
@ -80,19 +80,6 @@ class RootCauseAnalysisForm(forms.ModelForm):
|
|||||||
is_active=True
|
is_active=True
|
||||||
).order_by('email')
|
).order_by('email')
|
||||||
|
|
||||||
# Set initial hospital if user has one
|
|
||||||
if user and not self.instance.pk:
|
|
||||||
from apps.organizations.models import Hospital
|
|
||||||
try:
|
|
||||||
user_hospital = Hospital.objects.filter(
|
|
||||||
staff__user=user
|
|
||||||
).first()
|
|
||||||
if user_hospital:
|
|
||||||
self.fields['hospital'].initial = user_hospital
|
|
||||||
self.fields['hospital'].widget.attrs['readonly'] = True
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RCARootCauseForm(forms.ModelForm):
|
class RCARootCauseForm(forms.ModelForm):
|
||||||
"""Form for creating and editing RCARootCause"""
|
"""Form for creating and editing RCARootCause"""
|
||||||
|
|||||||
@ -506,6 +506,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
|
{% if not form.hospital.is_hidden %}
|
||||||
<div>
|
<div>
|
||||||
<label for="{{ form.hospital.id_for_label }}" class="form-label">
|
<label for="{{ form.hospital.id_for_label }}" class="form-label">
|
||||||
{{ form.hospital.label }} <span class="required-mark">*</span>
|
{{ form.hospital.label }} <span class="required-mark">*</span>
|
||||||
@ -518,6 +519,9 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ form.hospital }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="{{ form.department.id_for_label }}" class="form-label">
|
<label for="{{ form.department.id_for_label }}" class="form-label">
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
<form method="post" class="row g-3">
|
<form method="post" class="row g-3">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% if request.user.is_px_admin %}
|
{% if not form.hospital.is_hidden %}
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<label for="id_hospital" class="form-label">
|
<label for="id_hospital" class="form-label">
|
||||||
{% translate "Hospital" %} <span class="text-danger">*</span>
|
{% translate "Hospital" %} <span class="text-danger">*</span>
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
<form method="post" class="row g-3">
|
<form method="post" class="row g-3">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% if request.user.is_px_admin %}
|
{% if not form.hospital.is_hidden %}
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<label for="id_hospital" class="form-label">
|
<label for="id_hospital" class="form-label">
|
||||||
{% translate "Hospital" %} <span class="text-danger">*</span>
|
{% translate "Hospital" %} <span class="text-danger">*</span>
|
||||||
|
|||||||
@ -197,6 +197,7 @@
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
|
{% if not form.hospital.is_hidden %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.hospital.id_for_label }}" class="form-label">
|
<label for="{{ form.hospital.id_for_label }}" class="form-label">
|
||||||
{{ form.hospital.label }} <span class="text-red-500">*</span>
|
{{ form.hospital.label }} <span class="text-red-500">*</span>
|
||||||
@ -212,6 +213,9 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ form.hospital }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.department.id_for_label }}" class="form-label">
|
<label for="{{ form.department.id_for_label }}" class="form-label">
|
||||||
|
|||||||
@ -242,6 +242,7 @@
|
|||||||
<i class="bi bi-building me-2"></i>Organization Information
|
<i class="bi bi-building me-2"></i>Organization Information
|
||||||
</div>
|
</div>
|
||||||
<div class="form-card-body">
|
<div class="form-card-body">
|
||||||
|
{% if not form.hospital.is_hidden %}
|
||||||
<!-- Hospital -->
|
<!-- Hospital -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="{{ form.hospital.id_for_label }}" class="form-label required-field">{% trans "Hospital" %}</label>
|
<label for="{{ form.hospital.id_for_label }}" class="form-label required-field">{% trans "Hospital" %}</label>
|
||||||
@ -250,6 +251,9 @@
|
|||||||
<div class="text-danger small">{{ form.hospital.errors }}</div>
|
<div class="text-danger small">{{ form.hospital.errors }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ form.hospital }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- Department -->
|
<!-- Department -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user