""" QI Projects Forms Forms for creating and managing Quality Improvement projects and tasks. """ from django import forms from django.utils.translation import gettext_lazy as _ from apps.core.form_mixins import HospitalFieldMixin from apps.accounts.models import User from apps.organizations.models import Department, Hospital from .models import QIProject, QIProjectTask class QIProjectForm(HospitalFieldMixin, forms.ModelForm): """ Form for creating and editing QI Projects. Hospital field visibility: - PX Admins: See dropdown with all hospitals - Others: Hidden field, auto-set to user's hospital """ class Meta: model = QIProject fields = [ 'name', 'name_ar', 'description', 'hospital', 'department', 'project_lead', 'team_members', 'status', 'start_date', 'target_completion_date', 'outcome_description' ] widgets = { 'name': forms.TextInput(attrs={ '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', 'placeholder': _('Project name') }), 'name_ar': forms.TextInput(attrs={ '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', 'placeholder': _('اسم المشروع'), 'dir': 'rtl' }), 'description': forms.Textarea(attrs={ '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 resize-none', 'rows': 4, 'placeholder': _('Describe the project objectives and scope...') }), 'hospital': forms.Select(attrs={ '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' }), 'department': forms.Select(attrs={ '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' }), 'project_lead': forms.Select(attrs={ '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' }), 'team_members': forms.SelectMultiple(attrs={ '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 h-40' }), 'status': forms.Select(attrs={ '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' }), 'start_date': forms.DateInput(attrs={ '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', 'type': 'date' }), 'target_completion_date': forms.DateInput(attrs={ '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', 'type': 'date' }), 'outcome_description': forms.Textarea(attrs={ '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 resize-none', 'rows': 3, 'placeholder': _('Document project outcomes and results...') }), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Filter department choices based on hospital hospital_id = None if self.data.get('hospital'): hospital_id = self.data.get('hospital') elif self.initial.get('hospital'): hospital_id = self.initial.get('hospital') elif self.instance and self.instance.pk and self.instance.hospital: hospital_id = self.instance.hospital.id elif self.user and self.user.hospital: hospital_id = self.user.hospital.id if hospital_id: self.fields['department'].queryset = Department.objects.filter( hospital_id=hospital_id, status='active' ).order_by('name') # Filter user choices based on hospital self.fields['project_lead'].queryset = User.objects.filter( hospital_id=hospital_id, is_active=True ).order_by('first_name', 'last_name') self.fields['team_members'].queryset = User.objects.filter( hospital_id=hospital_id, is_active=True ).order_by('first_name', 'last_name') else: self.fields['department'].queryset = Department.objects.none() self.fields['project_lead'].queryset = User.objects.none() self.fields['team_members'].queryset = User.objects.none() class QIProjectTaskForm(forms.ModelForm): """ Form for creating and editing QI Project tasks. """ class Meta: model = QIProjectTask fields = ['title', 'description', 'assigned_to', 'status', 'due_date', 'order'] widgets = { 'title': forms.TextInput(attrs={ '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', 'placeholder': _('Task title') }), 'description': forms.Textarea(attrs={ '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 resize-none', 'rows': 3, 'placeholder': _('Task description...') }), 'assigned_to': forms.Select(attrs={ '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' }), 'status': forms.Select(attrs={ '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' }), 'due_date': forms.DateInput(attrs={ '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', 'type': 'date' }), 'order': forms.NumberInput(attrs={ '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', 'min': 0 }), } def __init__(self, *args, **kwargs): self.project = kwargs.pop('project', None) super().__init__(*args, **kwargs) # Make order field not required (has default value of 0) self.fields['order'].required = False # Filter assigned_to choices based on project hospital if self.project and self.project.hospital: self.fields['assigned_to'].queryset = User.objects.filter( hospital=self.project.hospital, is_active=True ).order_by('first_name', 'last_name') else: self.fields['assigned_to'].queryset = User.objects.none() class QIProjectTemplateForm(HospitalFieldMixin, forms.ModelForm): """ Form for creating and editing QI Project templates. Hospital field visibility: - PX Admins: See dropdown with all hospitals - Others: Hidden field, auto-set to user's hospital Templates can be: - Global (hospital=None) - available to all - Hospital-specific - available only to that hospital """ class Meta: model = QIProject fields = [ 'name', 'name_ar', 'description', 'hospital', 'department', 'target_completion_date' ] widgets = { 'name': forms.TextInput(attrs={ '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', 'placeholder': _('Template name') }), 'name_ar': forms.TextInput(attrs={ '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', 'placeholder': _('اسم القالب'), 'dir': 'rtl' }), 'description': forms.Textarea(attrs={ '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 resize-none', 'rows': 4, 'placeholder': _('Describe the project template...') }), 'hospital': forms.Select(attrs={ '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' }), 'department': forms.Select(attrs={ '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' }), 'target_completion_date': forms.DateInput(attrs={ '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', 'type': 'date' }), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Make hospital optional for templates (global templates) self.fields['hospital'].required = False self.fields['hospital'].empty_label = _('Global (All Hospitals)') # Filter department choices based on hospital hospital_id = None if self.data.get('hospital'): hospital_id = self.data.get('hospital') elif self.initial.get('hospital'): hospital_id = self.initial.get('hospital') elif self.instance and self.instance.pk and self.instance.hospital: hospital_id = self.instance.hospital.id if hospital_id: self.fields['department'].queryset = Department.objects.filter( hospital_id=hospital_id, status='active' ).order_by('name') else: self.fields['department'].queryset = Department.objects.none() class ConvertToProjectForm(forms.Form): """ Form for converting a PX Action to a QI Project. Allows selecting a template and customizing the project details. """ template = forms.ModelChoiceField( queryset=QIProject.objects.none(), required=False, empty_label=_('Blank Project'), label=_('Project Template'), widget=forms.Select(attrs={ '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' }) ) project_name = forms.CharField( max_length=200, label=_('Project Name'), widget=forms.TextInput(attrs={ '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', 'placeholder': _('Enter project name') }) ) project_lead = forms.ModelChoiceField( queryset=User.objects.none(), required=True, label=_('Project Lead'), widget=forms.Select(attrs={ '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' }) ) target_completion_date = forms.DateField( required=False, label=_('Target Completion Date'), widget=forms.DateInput(attrs={ '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', 'type': 'date' }) ) def __init__(self, *args, **kwargs): self.user = kwargs.pop('user', None) self.action = kwargs.pop('action', None) super().__init__(*args, **kwargs) if self.user and self.user.hospital: # Filter templates by hospital (or global) from django.db.models import Q self.fields['template'].queryset = QIProject.objects.filter( Q(hospital=self.user.hospital) | Q(hospital__isnull=True), status='template' # We'll add this status or use metadata ).order_by('name') # Filter project lead by hospital self.fields['project_lead'].queryset = User.objects.filter( hospital=self.user.hospital, is_active=True ).order_by('first_name', 'last_name') else: self.fields['template'].queryset = QIProject.objects.none() self.fields['project_lead'].queryset = User.objects.none()