from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib import messages from django.utils.translation import gettext_lazy as _ from django.core.paginator import Paginator from django.db.models import Q from django.utils import timezone from .models import DocumentTemplate, ClinicalNote, NoteAddendum, NoteAuditLog from .forms import DocumentTemplateForm, ClinicalNoteForm, NoteAddendumForm, NoteSearchForm # Template Views @login_required def template_list(request): """List all document templates.""" templates = DocumentTemplate.objects.all() # Filter by category if provided category = request.GET.get('category') if category: templates = templates.filter(category=category) # Filter by active status is_active = request.GET.get('is_active') if is_active: templates = templates.filter(is_active=is_active == 'true') paginator = Paginator(templates, 20) page_number = request.GET.get('page') templates = paginator.get_page(page_number) context = { 'templates': templates, 'categories': DocumentTemplate.CATEGORY_CHOICES, } return render(request, 'documents/template_list.html', context) @login_required def template_detail(request, pk): """View template details.""" template = get_object_or_404(DocumentTemplate, pk=pk) context = { 'template': template, } return render(request, 'documents/template_detail.html', context) @login_required def template_create(request): """Create a new document template.""" if request.method == 'POST': form = DocumentTemplateForm(request.POST) if form.is_valid(): template = form.save(commit=False) template.created_by = request.user template.save() messages.success(request, _('Template created successfully.')) return redirect('documents:template-detail', pk=template.pk) else: form = DocumentTemplateForm() context = { 'form': form, 'title': _('Create Template'), } return render(request, 'documents/template_form.html', context) @login_required def template_update(request, pk): """Update an existing document template.""" template = get_object_or_404(DocumentTemplate, pk=pk) if request.method == 'POST': form = DocumentTemplateForm(request.POST, instance=template) if form.is_valid(): form.save() messages.success(request, _('Template updated successfully.')) return redirect('documents:template-detail', pk=template.pk) else: form = DocumentTemplateForm(instance=template) context = { 'form': form, 'template': template, 'title': _('Update Template'), } return render(request, 'documents/template_form.html', context) @login_required def template_delete(request, pk): """Delete a document template.""" template = get_object_or_404(DocumentTemplate, pk=pk) if request.method == 'POST': template.delete() messages.success(request, _('Template deleted successfully.')) return redirect('documents:template-list') context = { 'template': template, } return render(request, 'documents/template_confirm_delete.html', context) # Clinical Note Views @login_required def note_list(request): """List all clinical notes with search and filtering.""" notes = ClinicalNote.objects.select_related('patient', 'author', 'template') # Apply search form filters form = NoteSearchForm(request.GET) if form.is_valid(): if form.cleaned_data.get('patient'): patient_query = form.cleaned_data['patient'] notes = notes.filter( Q(patient__first_name__icontains=patient_query) | Q(patient__last_name__icontains=patient_query) | Q(patient__patient_id__icontains=patient_query) ) if form.cleaned_data.get('status'): notes = notes.filter(status=form.cleaned_data['status']) if form.cleaned_data.get('date_from'): notes = notes.filter(created_at__gte=form.cleaned_data['date_from']) if form.cleaned_data.get('date_to'): notes = notes.filter(created_at__lte=form.cleaned_data['date_to']) if form.cleaned_data.get('author'): author_query = form.cleaned_data['author'] notes = notes.filter( Q(author__first_name__icontains=author_query) | Q(author__last_name__icontains=author_query) ) paginator = Paginator(notes, 20) page_number = request.GET.get('page') notes = paginator.get_page(page_number) context = { 'notes': notes, 'search_form': form, } return render(request, 'documents/note_list.html', context) @login_required def note_detail(request, pk): """View clinical note details.""" note = get_object_or_404( ClinicalNote.objects.select_related('patient', 'author', 'template', 'finalized_by'), pk=pk ) # Log the view action NoteAuditLog.objects.create( note=note, action='viewed', user=request.user, ip_address=request.META.get('REMOTE_ADDR') ) addendums = note.addendums.select_related('author').all() context = { 'note': note, 'addendums': addendums, } return render(request, 'documents/note_detail.html', context) @login_required def note_create(request): """Create a new clinical note.""" if request.method == 'POST': form = ClinicalNoteForm(request.POST, user=request.user) if form.is_valid(): note = form.save() # Log the creation NoteAuditLog.objects.create( note=note, action='created', user=request.user, ip_address=request.META.get('REMOTE_ADDR') ) messages.success(request, _('Clinical note created successfully.')) return redirect('documents:note-detail', pk=note.pk) else: form = ClinicalNoteForm(user=request.user) context = { 'form': form, 'title': _('Create Clinical Note'), } return render(request, 'documents/note_form.html', context) @login_required def note_update(request, pk): """Update an existing clinical note.""" note = get_object_or_404(ClinicalNote, pk=pk) # Only allow editing of draft notes if note.status != 'draft': messages.error(request, _('Only draft notes can be edited. Use addendum for finalized notes.')) return redirect('documents:note-detail', pk=note.pk) if request.method == 'POST': form = ClinicalNoteForm(request.POST, instance=note, user=request.user) if form.is_valid(): old_content = note.content note = form.save() # Log the update NoteAuditLog.objects.create( note=note, action='updated', user=request.user, ip_address=request.META.get('REMOTE_ADDR'), changes={'old_content': old_content, 'new_content': note.content} ) messages.success(request, _('Clinical note updated successfully.')) return redirect('documents:note-detail', pk=note.pk) else: form = ClinicalNoteForm(instance=note, user=request.user) context = { 'form': form, 'note': note, 'title': _('Update Clinical Note'), } return render(request, 'documents/note_form.html', context) @login_required def note_finalize(request, pk): """Finalize a clinical note.""" note = get_object_or_404(ClinicalNote, pk=pk) if note.status != 'draft': messages.error(request, _('Only draft notes can be finalized.')) return redirect('documents:note-detail', pk=note.pk) if request.method == 'POST': note.status = 'final' note.finalized_at = timezone.now() note.finalized_by = request.user note.save() # Log the finalization NoteAuditLog.objects.create( note=note, action='finalized', user=request.user, ip_address=request.META.get('REMOTE_ADDR') ) messages.success(request, _('Clinical note finalized successfully.')) return redirect('documents:note-detail', pk=note.pk) context = { 'note': note, } return render(request, 'documents/note_confirm_finalize.html', context) @login_required def note_addendum(request, pk): """Add an addendum to a finalized clinical note.""" note = get_object_or_404(ClinicalNote, pk=pk) if note.status != 'final': messages.error(request, _('Addendums can only be added to finalized notes.')) return redirect('documents:note-detail', pk=note.pk) if request.method == 'POST': form = NoteAddendumForm(request.POST, user=request.user, note=note) if form.is_valid(): addendum = form.save() # Update note status to amended note.status = 'amended' note.save() # Log the addendum NoteAuditLog.objects.create( note=note, action='amended', user=request.user, ip_address=request.META.get('REMOTE_ADDR'), changes={'addendum_id': addendum.id, 'reason': addendum.reason} ) messages.success(request, _('Addendum added successfully.')) return redirect('documents:note-detail', pk=note.pk) else: form = NoteAddendumForm(user=request.user, note=note) context = { 'form': form, 'note': note, } return render(request, 'documents/note_addendum.html', context) @login_required def note_audit(request, pk): """View audit trail for a clinical note.""" note = get_object_or_404(ClinicalNote, pk=pk) audit_logs = note.audit_logs.select_related('user').all() context = { 'note': note, 'audit_logs': audit_logs, } return render(request, 'documents/note_audit.html', context)