agdar/CLINICAL_SIGNING_IMPLEMENTATION_PLAN.md
Marwan Alwali a04817ef6e update
2025-11-02 19:25:08 +03:00

288 lines
8.4 KiB
Markdown

# Clinical Document Signing Implementation Plan
## Overview
This document outlines the implementation of clinical document signing functionality across all therapy modules that use `ClinicallySignableMixin`.
## Completed Implementation
### ✅ ABA Module
- **Models**: ABAConsult, ABASession
- **Views**: Added `ABASessionSignView` for signing sessions
- **URLs**: Added `/sessions/<uuid:pk>/sign/` route
- **Templates**:
- `session_detail.html`: Sign button for unsigned sessions
- `session_list.html`: Unsigned sessions notification banner + signature status column
- **Features**:
- Role-based access (provider or admin only)
- Confirmation dialog before signing
- Audit trail (signed_by, signed_at)
- Visual indicators (badges, alerts)
## Pending Implementation
### 1. OT (Occupational Therapy) Module
#### Models to Implement
- **OTConsult** - Consultation forms
- **OTSession** - Session notes
- **OTProgressReport** - Progress reports
#### Required Changes
**Views** (`ot/views.py`):
```python
# Add sign views for each model
class OTConsultSignView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin, View):
allowed_roles = [User.Role.ADMIN, User.Role.OT]
# Similar implementation to ABASessionSignView
class OTSessionSignView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin, View):
allowed_roles = [User.Role.ADMIN, User.Role.OT]
class OTProgressReportSignView(LoginRequiredMixin, RolePermissionMixin, TenantFilterMixin, View):
allowed_roles = [User.Role.ADMIN, User.Role.OT]
```
**URLs** (`ot/urls.py`):
```python
# Add sign routes
path('consults/<uuid:pk>/sign/', views.OTConsultSignView.as_view(), name='consult_sign'),
path('sessions/<uuid:pk>/sign/', views.OTSessionSignView.as_view(), name='session_sign'),
path('progress-reports/<uuid:pk>/sign/', views.OTProgressReportSignView.as_view(), name='progress_report_sign'),
```
**Templates**:
- `ot/templates/ot/consult_detail.html` - Add signature status card with sign button
- `ot/templates/ot/consult_list.html` - Add unsigned notifications + signature column
- `ot/templates/ot/session_detail.html` - Add signature status card with sign button
- `ot/templates/ot/session_list.html` - Add unsigned notifications + signature column
- `ot/templates/ot/progress_report_detail.html` - Add signature status card with sign button
- `ot/templates/ot/progress_report_list.html` - Add unsigned notifications + signature column
**List Views** - Update `get_context_data()`:
```python
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = self.request.user
# Get unsigned documents for current user
unsigned_query = ModelName.objects.filter(
tenant=user.tenant,
signed_by__isnull=True
)
if user.role == User.Role.OT:
unsigned_query = unsigned_query.filter(provider=user)
context['unsigned_count'] = unsigned_query.count()
context['unsigned_items'] = unsigned_query.select_related('patient', 'provider').order_by('-date_field')[:10]
return context
```
### 2. SLP (Speech-Language Pathology) Module
#### Models to Implement
- **SLPConsult** - Consultation forms
- **SLPAssessment** - Assessment reports
- **SLPIntervention** - Intervention notes
- **SLPProgressReport** - Progress reports
#### Required Changes
Same pattern as OT module:
- Add 4 sign views (one per model)
- Add 4 URL routes
- Update 8 templates (4 detail + 4 list)
- Update 4 list views with unsigned counts
**Views** (`slp/views.py`):
```python
class SLPConsultSignView(...)
class SLPAssessmentSignView(...)
class SLPInterventionSignView(...)
class SLPProgressReportSignView(...)
```
**URLs** (`slp/urls.py`):
```python
path('consults/<uuid:pk>/sign/', ...),
path('assessments/<uuid:pk>/sign/', ...),
path('interventions/<uuid:pk>/sign/', ...),
path('progress-reports/<uuid:pk>/sign/', ...),
```
### 3. Medical Module
#### Models to Implement
- **MedicalConsultation** - Medical consultations
- **MedicalFollowUp** - Follow-up visits
#### Required Changes
Same pattern:
- Add 2 sign views
- Add 2 URL routes
- Update 4 templates (2 detail + 2 list)
- Update 2 list views
**Views** (`medical/views.py`):
```python
class MedicalConsultationSignView(...)
class MedicalFollowUpSignView(...)
```
**URLs** (`medical/urls.py`):
```python
path('consultations/<uuid:pk>/sign/', ...),
path('follow-ups/<uuid:pk>/sign/', ...),
```
### 4. Nursing Module
#### Models to Implement
- **NursingEncounter** - Nursing encounters
#### Required Changes
- Add 1 sign view
- Add 1 URL route
- Update 2 templates (1 detail + 1 list)
- Update 1 list view
**Views** (`nursing/views.py`):
```python
class NursingEncounterSignView(...)
```
**URLs** (`nursing/urls.py`):
```python
path('encounters/<uuid:pk>/sign/', ...),
```
## Implementation Checklist
### Per Model Implementation Steps:
- [ ] Create sign view class in views.py
- [ ] Add URL route in urls.py
- [ ] Update detail template with signature status card
- [ ] Update list template with unsigned notification banner
- [ ] Add signature status column to list table
- [ ] Update list view to include unsigned counts
- [ ] Test signing functionality
- [ ] Test role-based access control
- [ ] Verify audit trail (signed_by, signed_at)
### OT Module
- [ ] OTConsult signing (3 steps above)
- [ ] OTSession signing (3 steps above)
- [ ] OTProgressReport signing (3 steps above)
### SLP Module
- [ ] SLPConsult signing
- [ ] SLPAssessment signing
- [ ] SLPIntervention signing
- [ ] SLPProgressReport signing
### Medical Module
- [ ] MedicalConsultation signing
- [ ] MedicalFollowUp signing
### Nursing Module
- [ ] NursingEncounter signing
## Code Reusability
### Generic Sign View Template
Consider creating a generic mixin or base class to reduce code duplication:
```python
# core/mixins.py
class ClinicalDocumentSignMixin:
"""Mixin for signing clinical documents."""
def post(self, request, pk):
model = self.model
document = get_object_or_404(
model,
pk=pk,
tenant=request.user.tenant
)
# Check if already signed
if document.signed_by:
messages.warning(request, "This document has already been signed.")
return HttpResponseRedirect(self.get_success_url(pk))
# Check if user is the provider or admin
if document.provider != request.user and request.user.role != User.Role.ADMIN:
messages.error(request, "Only the provider or an administrator can sign this document.")
return HttpResponseRedirect(self.get_success_url(pk))
# Sign the document
document.signed_by = request.user
document.signed_at = timezone.now()
document.save()
messages.success(request, f"{model._meta.verbose_name} signed successfully!")
return HttpResponseRedirect(self.get_success_url(pk))
def get_success_url(self, pk):
raise NotImplementedError("Subclasses must implement get_success_url()")
```
### Template Includes
Create reusable template snippets:
**`templates/includes/signature_status_card.html`**:
```django
<div class="card mb-3">
<div class="card-header">
<h6 class="mb-0"><i class="fas fa-signature me-2"></i>{% trans "Signature Status" %}</h6>
</div>
<div class="card-body">
{% if document.signed_by %}
<!-- Signed content -->
{% else %}
<!-- Unsigned content with sign button -->
{% endif %}
</div>
</div>
```
**`templates/includes/unsigned_notification.html`**:
```django
{% if unsigned_count > 0 %}
<div class="alert alert-warning alert-dismissible fade show mb-3" role="alert">
<!-- Notification content -->
</div>
{% endif %}
```
## Testing Requirements
For each implementation:
1. Test signing as provider
2. Test signing as admin
3. Test access denial for other users
4. Test re-signing prevention
5. Test unsigned notifications display
6. Test signature status indicators
7. Verify audit trail records
## Priority Order
1. **High Priority**: OT and SLP modules (most frequently used)
2. **Medium Priority**: Medical module
3. **Low Priority**: Nursing module
## Estimated Effort
- Per model: ~30-45 minutes
- Total: ~6-8 hours for all modules
## Notes
- All implementations should follow the ABA module pattern
- Maintain consistency in UI/UX across all modules
- Ensure proper role-based access control
- Include proper error handling and user feedback
- Add appropriate translations for all user-facing text