update on the complaint sla and staff hierarchy

This commit is contained in:
ismail 2026-01-15 14:31:54 +03:00
parent 8b65f9a52e
commit e3b3490bc9
30 changed files with 220 additions and 62 deletions

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.utils.timezone
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,6 +1,8 @@
"""
Complaints forms
"""
import os
from django import forms
from django.db import models
from django.core.exceptions import ValidationError
@ -25,7 +27,7 @@ class MultiFileInput(forms.FileInput):
"""
Custom FileInput widget that supports multiple file uploads.
Unlike the standard FileInput which only supports single files,
Unlike standard FileInput which only supports single files,
this widget allows users to upload multiple files at once.
"""
def __init__(self, attrs=None):
@ -157,7 +159,7 @@ class PublicComplaintForm(forms.ModelForm):
)
)
# Hidden fields - these will be set by the view or AI
# Hidden fields - these will be set by view or AI
severity = forms.ChoiceField(
label=_("Severity"),
choices=SeverityChoices.choices,
@ -236,7 +238,6 @@ class PublicComplaintForm(forms.ModelForm):
# Check file type
allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf', '.doc', '.docx']
import os
ext = os.path.splitext(file.name)[1].lower()
if ext not in allowed_extensions:
raise ValidationError(_('Allowed file types: JPG, PNG, GIF, PDF, DOC, DOCX'))
@ -317,18 +318,16 @@ class ComplaintForm(forms.ModelForm):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Filter hospital and patient by user permissions
# Filter hospitals and patients based on user permissions
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'].queryset = Hospital.objects.filter(id=user.hospital.id)
self.fields['hospital'].initial = user.hospital
self.fields['patient'].queryset = Patient.objects.filter(
primary_hospital=user.hospital,
status='active'
)
# Check for hospital selection in both initial data and POST data
# This is needed for validation to work correctly
hospital_id = None
if 'hospital' in self.data:
hospital_id = self.data.get('hospital')
@ -424,11 +423,11 @@ class InquiryForm(forms.ModelForm):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Filter hospital by user permissions
# 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'].queryset = Hospital.objects.filter(id=user.hospital.id)
self.fields['hospital'].initial = user.hospital
self.fields['hospital'].widget.attrs['readonly'] = True
# Check for hospital selection in both initial data and POST data
hospital_id = None
@ -445,9 +444,6 @@ class InquiryForm(forms.ModelForm):
).order_by('name')
class SLAConfigForm(forms.ModelForm):
"""Form for creating and editing SLA configurations"""

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -2,6 +2,7 @@
Complaints UI views - Server-rendered templates for complaints console
"""
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
@ -241,6 +242,16 @@ def complaint_detail(request, pk):
explanation_attachments = explanation.attachments.all()
context = {
'complaint': complaint,
'timeline': timeline,
'attachments': attachments,
'px_actions': px_actions,
'assignable_users': assignable_users,
'status_choices': ComplaintStatus.choices,
'can_edit': user.is_px_admin() or user.is_hospital_admin(),
'hospital_departments': hospital_departments,
'base_layout': base_layout,
'source_user': source_user,
"complaint": complaint,
"timeline": timeline,
"attachments": attachments,
@ -249,8 +260,6 @@ def complaint_detail(request, pk):
"status_choices": ComplaintStatus.choices,
"can_edit": user.is_px_admin() or user.is_hospital_admin(),
"hospital_departments": hospital_departments,
'base_layout': base_layout,
'source_user': source_user,
"explanation": explanation,
"explanations": explanations,
"explanation_attachments": explanation_attachments,
@ -271,6 +280,7 @@ def complaint_create(request):
base_layout = 'layouts/source_user_base.html' if source_user else 'layouts/base.html'
if request.method == 'POST':
# Handle form submission
form = ComplaintForm(request.POST, user=request.user)
@ -315,6 +325,46 @@ def complaint_create(request):
complaint.created_by = request.user
complaint.save()
from apps.organizations.models import Patient
# Get form data
patient_id = request.POST.get("patient_id")
hospital_id = request.POST.get("hospital_id")
department_id = request.POST.get("department_id", None)
staff_id = request.POST.get("staff_id", None)
description = request.POST.get("description")
category_id = request.POST.get("category")
subcategory_id = request.POST.get("subcategory", "")
source = request.POST.get("source")
encounter_id = request.POST.get("encounter_id", "")
# Validate required fields
if not all([patient_id, hospital_id, description, category_id, source]):
messages.error(request, "Please fill in all required fields.")
return redirect("complaints:complaint_create")
# Get category and subcategory objects
category = ComplaintCategory.objects.get(id=category_id)
subcategory_obj = None
if subcategory_id:
subcategory_obj = ComplaintCategory.objects.get(id=subcategory_id)
# Create complaint with AI defaults
complaint = Complaint.objects.create(
patient_id=patient_id,
hospital_id=hospital_id,
department_id=department_id if department_id else None,
staff_id=staff_id if staff_id else None,
title="Complaint", # AI will generate title
description=description,
category=category,
subcategory=subcategory_obj.code if subcategory_obj else "",
priority="medium", # AI will update
severity="medium", # AI will update
source=source,
encounter_id=encounter_id,
)
# Create initial update
ComplaintUpdate.objects.create(
@ -336,9 +386,10 @@ def complaint_create(request):
user=request.user,
content_object=complaint,
metadata={
# "category": category.name_en,
'severity': complaint.severity,
"category": category.name_en,
"severity": complaint.severity,
"patient_mrn": complaint.patient.mrn,
"patient_mrn": complaint.patient.mrn if complaint.patient else None,
"ai_analysis_pending": True,
},
)
@ -352,9 +403,6 @@ def complaint_create(request):
except ComplaintCategory.DoesNotExist:
messages.error(request, "Selected category not found.")
return redirect("complaints:complaint_create")
except Exception as e:
messages.error(request, f"Error creating complaint: {str(e)}")
return redirect("complaints:complaint_create")
# GET request - show form
# Check for hospital parameter from URL (for pre-selection)
@ -369,6 +417,7 @@ def complaint_create(request):
'form': form,
'base_layout': base_layout,
'source_user': source_user,
# "hospitals": hospitals,
}
return render(request, "complaints/complaint_form.html", context)
@ -960,12 +1009,12 @@ def inquiry_detail(request, pk):
]
context = {
"inquiry": inquiry,
"timeline": timeline,
"attachments": attachments,
"assignable_users": assignable_users,
"status_choices": status_choices,
"can_edit": user.is_px_admin() or user.is_hospital_admin(),
'inquiry': inquiry,
'timeline': timeline,
'attachments': attachments,
'assignable_users': assignable_users,
'status_choices': status_choices,
'can_edit': user.is_px_admin() or user.is_hospital_admin(),
'base_layout': base_layout,
'source_user': source_user,
}
@ -980,36 +1029,40 @@ def inquiry_create(request):
from .models import Inquiry
from .forms import InquiryForm
from apps.organizations.models import Patient
from apps.px_sources.models import SourceUser, PXSource
# Determine base layout based on user type
source_user = SourceUser.objects.filter(user=request.user).first()
base_layout = 'layouts/source_user_base.html' if source_user else 'layouts/base.html'
if request.method == 'POST':
# Handle form submission
form = InquiryForm(request.POST, user=request.user)
if not form.is_valid():
messages.error(request, f"Please correct the errors: {form.errors}")
context = {
'form': form,
'base_layout': base_layout,
'source_user': source_user,
}
return render(request, 'complaints/inquiry_form.html', context)
if request.method == "POST":
try:
# Save inquiry
inquiry = form.save(commit=False)
# Set source for source users
source_user = SourceUser.objects.filter(user=request.user).first()
if source_user:
inquiry.source = source_user.source
inquiry.created_by = request.user
inquiry.save()
# Get form data
patient_id = request.POST.get("patient_id", None)
hospital_id = request.POST.get("hospital_id")
department_id = request.POST.get("department_id", None)
subject = request.POST.get("subject")
message = request.POST.get("message")
category = request.POST.get("category")
# Contact info (if no patient)
contact_name = request.POST.get("contact_name", "")
contact_phone = request.POST.get("contact_phone", "")
contact_email = request.POST.get("contact_email", "")
# Validate required fields
if not all([hospital_id, subject, message, category]):
messages.error(request, "Please fill in all required fields.")
return redirect("complaints:inquiry_create")
# Create inquiry
inquiry = Inquiry.objects.create(
patient_id=patient_id if patient_id else None,
hospital_id=hospital_id,
department_id=department_id if department_id else None,
subject=subject,
message=message,
category=category,
contact_name=contact_name,
contact_phone=contact_phone,
contact_email=contact_email,
)
# Log audit
AuditService.log_event(
@ -1028,15 +1081,12 @@ def inquiry_create(request):
return redirect("complaints:inquiry_create")
# GET request - show form
form = InquiryForm(user=request.user)
hospitals = Hospital.objects.filter(status='active')
hospitals = Hospital.objects.filter(status="active")
if not request.user.is_px_admin() and request.user.hospital:
hospitals = hospitals.filter(id=request.user.hospital.id)
context = {
'form': form,
'base_layout': base_layout,
'source_user': source_user,
"hospitals": hospitals,
}
return render(request, "complaints/inquiry_form.html", context)

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.db import migrations, models

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import apps.observations.models
import django.db.models.deletion

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import apps.references.models
import django.db.models.deletion

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
from django.db import migrations, models

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.core.validators
import django.db.models.deletion

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid