138 lines
5.2 KiB
Python
138 lines
5.2 KiB
Python
"""
|
|
PX Action Center forms - Manual action creation and management
|
|
"""
|
|
from django import forms
|
|
from django.db.models import Q
|
|
|
|
from apps.core.models import PriorityChoices, SeverityChoices
|
|
|
|
from .models import PXAction, ActionSource, ActionStatus
|
|
|
|
|
|
class ManualActionForm(forms.ModelForm):
|
|
"""
|
|
Form for manually creating PX Actions.
|
|
|
|
Features:
|
|
- Source type selection including meeting types
|
|
- User permission-based filtering
|
|
- Cascading dropdowns (hospital → department)
|
|
- Assignment to users
|
|
"""
|
|
|
|
class Meta:
|
|
model = PXAction
|
|
fields = [
|
|
'source_type', 'title', 'description',
|
|
'hospital', 'department', 'category',
|
|
'priority', 'severity', 'assigned_to',
|
|
'due_at', 'requires_approval', 'action_plan'
|
|
]
|
|
widgets = {
|
|
'title': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Brief title for the action plan'
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Detailed description of the issue or improvement needed'
|
|
}),
|
|
'due_at': forms.DateTimeInput(attrs={
|
|
'type': 'datetime-local',
|
|
'class': 'form-control'
|
|
}),
|
|
'action_plan': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Proposed action steps to address the issue'
|
|
}),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# Make hospital field required
|
|
self.fields['hospital'].required = True
|
|
self.fields['hospital'].widget.attrs['class'] = 'form-select'
|
|
|
|
# Make source type required
|
|
self.fields['source_type'].required = True
|
|
self.fields['source_type'].widget.attrs['class'] = 'form-select'
|
|
|
|
# Make category required
|
|
self.fields['category'].required = True
|
|
self.fields['category'].widget.attrs['class'] = 'form-select'
|
|
|
|
# Make priority and severity required
|
|
self.fields['priority'].required = True
|
|
self.fields['priority'].widget.attrs['class'] = 'form-select'
|
|
self.fields['severity'].required = True
|
|
self.fields['severity'].widget.attrs['class'] = 'form-select'
|
|
|
|
# Filter hospitals based on user permissions
|
|
if user and not user.is_px_admin():
|
|
if user.hospital:
|
|
self.fields['hospital'].queryset = self.fields['hospital'].queryset.filter(
|
|
id=user.hospital.id
|
|
)
|
|
self.fields['hospital'].initial = user.hospital.id
|
|
self.fields['hospital'].widget.attrs['disabled'] = True
|
|
else:
|
|
# User doesn't have a hospital, can't create actions
|
|
self.fields['hospital'].queryset = self.fields['hospital'].queryset.none()
|
|
|
|
# Filter departments based on selected hospital
|
|
if user and user.hospital:
|
|
self.fields['department'].queryset = self.fields['department'].queryset.filter(
|
|
hospital=user.hospital
|
|
)
|
|
self.fields['department'].widget.attrs['class'] = 'form-select'
|
|
|
|
# Filter assignable users
|
|
from apps.accounts.models import User
|
|
if user and user.hospital:
|
|
self.fields['assigned_to'].queryset = User.objects.filter(
|
|
is_active=True,
|
|
hospital=user.hospital
|
|
).order_by('first_name', 'last_name')
|
|
self.fields['assigned_to'].widget.attrs['class'] = 'form-select'
|
|
elif user and user.is_px_admin():
|
|
# PX admins can assign to any active user
|
|
self.fields['assigned_to'].queryset = User.objects.filter(
|
|
is_active=True
|
|
).order_by('first_name', 'last_name')
|
|
self.fields['assigned_to'].widget.attrs['class'] = 'form-select'
|
|
else:
|
|
self.fields['assigned_to'].queryset = User.objects.none()
|
|
|
|
# Set default for requires_approval
|
|
self.fields['requires_approval'].initial = True
|
|
self.fields['requires_approval'].widget.attrs['class'] = 'form-check-input'
|
|
|
|
def clean_hospital(self):
|
|
"""Validate hospital field"""
|
|
hospital = self.cleaned_data.get('hospital')
|
|
if not hospital:
|
|
raise forms.ValidationError("Hospital is required.")
|
|
return hospital
|
|
|
|
def clean_due_at(self):
|
|
"""Validate due date is in the future"""
|
|
due_at = self.cleaned_data.get('due_at')
|
|
if due_at:
|
|
from django.utils import timezone
|
|
if due_at <= timezone.now():
|
|
raise forms.ValidationError("Due date must be in the future.")
|
|
return due_at
|
|
|
|
def save(self, commit=True):
|
|
"""Save action with manual source type"""
|
|
action = super().save(commit=False)
|
|
action.source_type = ActionSource.MANUAL
|
|
|
|
if commit:
|
|
action.save()
|
|
|
|
return action |