138 lines
4.9 KiB
Python
138 lines
4.9 KiB
Python
"""
|
|
Form mixins for tenant-aware forms.
|
|
|
|
Provides mixins to handle hospital field visibility based on user role.
|
|
"""
|
|
from django import forms
|
|
from apps.organizations.models import Hospital
|
|
|
|
|
|
class HospitalFieldMixin:
|
|
"""
|
|
Mixin to handle hospital field visibility based on user role.
|
|
|
|
- PX Admins: See dropdown with all active hospitals
|
|
- Others: Hidden field, auto-set to user's hospital
|
|
|
|
Usage:
|
|
class MyForm(HospitalFieldMixin, forms.ModelForm):
|
|
class Meta:
|
|
model = MyModel
|
|
fields = ['hospital', ...]
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
# Hospital field is automatically configured
|
|
|
|
In views:
|
|
form = MyForm(user=request.user)
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if self.user and 'hospital' in self.fields:
|
|
self._setup_hospital_field()
|
|
|
|
def _setup_hospital_field(self):
|
|
"""Configure hospital field based on user role."""
|
|
hospital_field = self.fields['hospital']
|
|
|
|
if self.user.is_px_admin():
|
|
# PX Admin: Show dropdown with all active hospitals
|
|
hospital_field.queryset = Hospital.objects.filter(status='active').order_by('name')
|
|
hospital_field.required = True
|
|
# Update widget attrs instead of replacing widget to preserve choices
|
|
hospital_field.widget.attrs.update({
|
|
'class': 'w-full px-4 py-2.5 rounded-xl border border-slate-200 focus:border-navy focus:ring-2 focus:ring-navy/20 transition text-sm bg-white'
|
|
})
|
|
else:
|
|
# Regular user: Hide field and set default
|
|
hospital_field.widget = forms.HiddenInput()
|
|
hospital_field.required = False
|
|
|
|
# Set initial value to user's hospital
|
|
if self.user.hospital:
|
|
hospital_field.initial = self.user.hospital
|
|
# Limit queryset to just user's hospital (for validation)
|
|
hospital_field.queryset = Hospital.objects.filter(id=self.user.hospital.id)
|
|
else:
|
|
# User has no hospital - empty queryset
|
|
hospital_field.queryset = Hospital.objects.none()
|
|
|
|
def clean_hospital(self):
|
|
"""
|
|
Ensure non-PX admins can only use their own hospital.
|
|
PX Admins can select any hospital.
|
|
"""
|
|
hospital = self.cleaned_data.get('hospital')
|
|
|
|
if not self.user:
|
|
return hospital
|
|
|
|
if self.user.is_px_admin():
|
|
# PX Admin must select a hospital
|
|
if not hospital:
|
|
raise forms.ValidationError("Please select a hospital.")
|
|
return hospital
|
|
else:
|
|
# Non-PX admins: Force user's hospital
|
|
if self.user.hospital:
|
|
return self.user.hospital
|
|
else:
|
|
raise forms.ValidationError(
|
|
"You do not have a hospital assigned. Please contact your administrator."
|
|
)
|
|
|
|
|
|
class DepartmentFieldMixin:
|
|
"""
|
|
Mixin to handle department field filtering based on user's hospital.
|
|
|
|
- Filters departments to only show those in the selected/current hospital
|
|
- Works with HospitalFieldMixin
|
|
|
|
Usage:
|
|
class MyForm(HospitalFieldMixin, DepartmentFieldMixin, forms.ModelForm):
|
|
class Meta:
|
|
model = MyModel
|
|
fields = ['hospital', 'department', ...]
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if 'department' in self.fields:
|
|
self._setup_department_field()
|
|
|
|
def _setup_department_field(self):
|
|
"""Configure department field with hospital-based filtering."""
|
|
from apps.organizations.models import Department
|
|
|
|
department_field = self.fields['department']
|
|
|
|
# Get the hospital (either from form data or user's hospital)
|
|
hospital = None
|
|
if self.data.get('hospital'):
|
|
try:
|
|
hospital = Hospital.objects.get(id=self.data['hospital'])
|
|
except Hospital.DoesNotExist:
|
|
pass
|
|
elif self.initial.get('hospital'):
|
|
hospital = self.initial['hospital']
|
|
elif self.instance and self.instance.pk and self.instance.hospital:
|
|
hospital = self.instance.hospital
|
|
elif self.user and self.user.hospital:
|
|
hospital = self.user.hospital
|
|
|
|
if hospital:
|
|
# Filter departments to user's hospital
|
|
department_field.queryset = Department.objects.filter(
|
|
hospital=hospital,
|
|
status='active'
|
|
).order_by('name')
|
|
else:
|
|
# No hospital context - empty queryset
|
|
department_field.queryset = Department.objects.none()
|