update
This commit is contained in:
parent
94e180f776
commit
4ca3f7159a
Binary file not shown.
@ -51,7 +51,7 @@ class AppointmentRequestForm(forms.ModelForm):
|
|||||||
self.fields['provider'].queryset = User.objects.filter(
|
self.fields['provider'].queryset = User.objects.filter(
|
||||||
tenant=user.tenant,
|
tenant=user.tenant,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
|
employee_profile__role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT']
|
||||||
).order_by('last_name', 'first_name')
|
).order_by('last_name', 'first_name')
|
||||||
|
|
||||||
def clean_preferred_date(self):
|
def clean_preferred_date(self):
|
||||||
|
|||||||
173
current_prompt.md
Normal file
173
current_prompt.md
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
Agent Instructions:
|
||||||
|
You are a senior Django architect and full-stack developer. This is a very large, mission-critical project—do **not** dump all code at once. Follow this strict phased plan-and-approve workflow to minimize hallucination and ensure accuracy:
|
||||||
|
|
||||||
|
**Phase 1 – Planning**
|
||||||
|
1. Produce a high-level outline of every app/module, its responsibilities, and the key models, views/endpoints, HTMX interactions, Celery tasks, HL7 and DICOM/PACS interfaces, AI analytics hooks, and compliance/multitenancy considerations.
|
||||||
|
2. Pause and wait for my confirmation before proceeding.
|
||||||
|
|
||||||
|
**Phase 2 – Scoping & Approval (per app)**
|
||||||
|
For each confirmed app (one at a time):
|
||||||
|
1. List all models, fields, relationships, and choice enums in full detail.
|
||||||
|
2. List required UI views (with HTMX attributes) and REST API endpoints/URLs.
|
||||||
|
3. List any Celery tasks, HL7/DICOM integration points, IoT hooks, and AI rule triggers.
|
||||||
|
4. Pause and wait for my “👍 go ahead with [app_name]” before generating any code.
|
||||||
|
|
||||||
|
**Phase 3 – Implementation (per app)**
|
||||||
|
When I approve an app:
|
||||||
|
1. Generate **models.py** for that app only.
|
||||||
|
2. Pause for my review and approval.
|
||||||
|
3. Generate **serializers.py** and/or **forms.py**, then pause for review.
|
||||||
|
4. Generate **views.py**, **templates/**, and any necessary HTMX snippets, then pause for review.
|
||||||
|
5. Generate **static asset scaffolding** (SASS partials, HTMX/JS modules) and pause for review.
|
||||||
|
|
||||||
|
**Phase 4 – Shared Tooling & Final Integration**
|
||||||
|
After all apps are complete:
|
||||||
|
1. Generate Webpack (or Django-Webpack-Loader) setup, SCSS/JS bundling, and `django-compressor` config.
|
||||||
|
2. Generate Celery configuration with Redis broker and example tasks (including HL7/DICOM polling, IoT data ingestion, AI analytics jobs).
|
||||||
|
3. Generate the **hl7_interface** and **pacs_interface** apps: models, utilities, management commands, and Celery tasks for HL7 v2.x and DICOM messaging.
|
||||||
|
4. Generate DRF API docs (Swagger) config, pytest setup, and GitHub Actions CI workflow.
|
||||||
|
5. Generate example Gunicorn + Nginx deployment snippets with multitenancy and SSL/TLS, and notes on GDPR/HIPAA compliance (encryption at rest, audit logs, consent management).
|
||||||
|
6. Provide a comprehensive README covering:
|
||||||
|
- Python virtualenv setup
|
||||||
|
- `npm install && npm run build`
|
||||||
|
- `manage.py migrate`, superuser setup
|
||||||
|
- ColorAdmin license integration
|
||||||
|
- HTMX usage guidelines
|
||||||
|
- HL7/DICOM endpoint configuration
|
||||||
|
- IoT device onboarding
|
||||||
|
- AI risk-scoring configuration
|
||||||
|
- Multitenancy setup
|
||||||
|
- Compliance controls (2FA, encryption, consent capture)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Project Specification**
|
||||||
|
Project name: `hospital_management`
|
||||||
|
UI theme: ColorAdmin template (all CSS/JS centralized—no inline or per-template scripts/styles)
|
||||||
|
Dynamic behavior: HTMX for all interactive features
|
||||||
|
Messaging: Optional inbound/outbound HL7 and DICOM/PACS interfaces
|
||||||
|
Analytics: AI-driven predictive risk scoring hooks in `decision_support`
|
||||||
|
Security & Compliance:
|
||||||
|
- Two-factor authentication, encryption at rest, GDPR/HIPAA audit trails
|
||||||
|
- Consent management, digital signatures, detailed audit logs
|
||||||
|
- Tenant-scoped data isolation for multi-hospital support
|
||||||
|
|
||||||
|
**Apps, Models & Fields**
|
||||||
|
|
||||||
|
1. **accounts**
|
||||||
|
- `User` (extends AbstractUser): username, email, first_name, last_name, password, role (choices: Admin, Doctor, Nurse, LabTech, Pharmacist, Receptionist, Patient, EMS), is_active, date_joined, tenant
|
||||||
|
- `TwoFactorDevice`: user FK, device_type, secret_key, confirmed
|
||||||
|
- `SocialAccount` (django-allauth)
|
||||||
|
|
||||||
|
2. **core**
|
||||||
|
- `AuditLogEntry`: user FK, action, timestamp, object_type, object_id, change_detail
|
||||||
|
- HL7Utility & DICOMUtility modules (no models; parsing/building functions)
|
||||||
|
|
||||||
|
3. **patients**
|
||||||
|
- `PatientProfile`: user FK (Patient), medical_record_number, date_of_birth, gender, blood_type, allergies (text), address, phone, emergency_contact FK, insurance_info FK
|
||||||
|
- `EmergencyContact`: patient FK, name, relationship, phone, email
|
||||||
|
- `InsuranceInfo`: patient FK, provider, policy_number, group_number, coverage_start_date, coverage_end_date
|
||||||
|
- `ConsentForm`: patient FK, form_type, document (FileField), signed_at, signed_by FK
|
||||||
|
|
||||||
|
4. **appointments**
|
||||||
|
- `AppointmentRequest`: patient FK, doctor FK, department, requested_datetime, status (Pending/Confirmed/Cancelled), created_at, updated_at
|
||||||
|
- `SlotAvailability`: doctor FK, date, start_time, end_time, is_available
|
||||||
|
- `WaitingQueue`: appointment FK, position, created_at
|
||||||
|
- VirtualCare scheduled via `TelemedicineSession`: patient FK, provider FK, session_url, start_time, end_time, status
|
||||||
|
|
||||||
|
5. **inpatients**
|
||||||
|
- `Ward`: name, floor, capacity, department
|
||||||
|
- `Bed`: ward FK, bed_number, bed_type (choices: General/ICU/Private), status
|
||||||
|
- `Admission`: patient FK, ward FK, bed FK, admitted_at, admitted_by FK, reason, status
|
||||||
|
- `DischargeSummary`: admission FK, summary_text, discharged_at, discharged_by FK
|
||||||
|
- `Transfer`: admission FK, from_ward FK, to_ward FK, transferred_at, reason
|
||||||
|
- `SurgerySchedule`: patient FK, surgeon FK, or_block FK, scheduled_at, duration, status
|
||||||
|
|
||||||
|
6. **emr**
|
||||||
|
- `Encounter`: patient FK, encounter_date, provider FK, encounter_type, notes
|
||||||
|
- `VitalSigns`: encounter FK, recorded_at, temperature, heart_rate, bp_systolic, bp_diastolic, respiratory_rate, oxygen_saturation
|
||||||
|
- `ProblemList`: patient FK, description, onset_date, status, notes
|
||||||
|
- `CarePlan`: encounter FK, goal, interventions, status
|
||||||
|
- `ClinicalNote`: encounter FK, note_type, content, created_at, created_by FK
|
||||||
|
|
||||||
|
7. **billing**
|
||||||
|
- `Invoice`: patient FK, date_issued, due_date, total_amount, status
|
||||||
|
- `ChargeItem`: invoice FK, description, code, quantity, unit_price, total_price
|
||||||
|
- `Payment`: invoice FK, amount, method, paid_at, transaction_id
|
||||||
|
- `InsuranceClaim`: invoice FK, claim_number, status, submitted_at, adjudicated_at
|
||||||
|
|
||||||
|
8. **pharmacy**
|
||||||
|
- `Medication`: name, code, description, unit, dosage_form
|
||||||
|
- `Prescription`: patient FK, prescriber FK, prescribed_at, status
|
||||||
|
- `DispenseRecord`: prescription FK, medication FK, quantity, dispensed_at, dispenser FK
|
||||||
|
- `StockItem`: medication FK, batch_number, expiration_date, quantity_on_hand, minimum_threshold
|
||||||
|
|
||||||
|
9. **laboratory**
|
||||||
|
- `LabTest`: name, code, description, specimen_type, department
|
||||||
|
- `Specimen`: lab_test FK, patient FK, collected_at, collected_by FK, status
|
||||||
|
- `Result`: specimen FK, result_value, units, reference_range, result_date, verified_by FK
|
||||||
|
- `LISIntegrationLog`: message_id, direction, payload, status, processed_at
|
||||||
|
|
||||||
|
10. **radiology**
|
||||||
|
- `RadiologyOrder`: patient FK, imaging_type, ordered_by FK, order_date, priority, status
|
||||||
|
- `ImagingStudy`: order FK, modality, study_date, images_count, report_status
|
||||||
|
- `RadiologyReport`: study FK, report_text, dictated_by FK, dictated_at, approved_by FK, approved_at
|
||||||
|
- `DICOMStudy`: study_instance_uid, patient_fk, modality, study_date, series_data (JSON)
|
||||||
|
|
||||||
|
11. **inventory**
|
||||||
|
- `SupplyItem`: name, sku, description, category, unit, reorder_level, location
|
||||||
|
- `PurchaseOrder`: supplier FK, order_date, expected_date, status, total_amount
|
||||||
|
- `StockTransaction`: item FK, transaction_type, quantity, transaction_date, reference
|
||||||
|
|
||||||
|
12. **decision_support**
|
||||||
|
- `CDSSRule`: name, trigger_event, condition_expression, action, active
|
||||||
|
- `AlertLog`: rule FK, patient FK, triggered_at, message, status
|
||||||
|
- AI hooks: risk_scoring_config (JSON), last_run, score_thresholds
|
||||||
|
|
||||||
|
13. **reporting**
|
||||||
|
- `CustomReport`: name, description, owner FK, query_definition (JSON), created_at, updated_at
|
||||||
|
- `DashboardWidget`: name, report FK, widget_type, settings (JSON), position
|
||||||
|
|
||||||
|
14. **hl7_interface**
|
||||||
|
- `HL7Endpoint`: name, host, port, protocol, is_active, last_checked
|
||||||
|
- `HL7MessageLog`: endpoint FK, direction, message_type, raw_message, parsed_message, sent_at, received_at, status
|
||||||
|
|
||||||
|
15. **pacs_interface**
|
||||||
|
- `PACSConnection`: name, ae_title, host, port, is_active
|
||||||
|
- `PACSLog`: connection FK, direction, dicom_uid, raw_payload, processed_at, status
|
||||||
|
|
||||||
|
16. **operating_theatre**
|
||||||
|
- `ORBlock`: name, theater_number, department, available_slots (JSON)
|
||||||
|
- `EquipmentReservation`: device FK, or_block FK, reserved_from, reserved_to, status
|
||||||
|
|
||||||
|
17. **assets**
|
||||||
|
- `MedicalDevice`: name, serial_number, category, location, status, last_maintenance
|
||||||
|
- `MaintenanceLog`: device FK, performed_at, performed_by FK, notes
|
||||||
|
- `IoTSensorReading`: device FK, timestamp, data (JSON)
|
||||||
|
|
||||||
|
18. **ems**
|
||||||
|
- `DispatchRequest`: caller_info, location, priority, status, created_at
|
||||||
|
- `Ambulance`: identifier, capacity, status, location
|
||||||
|
- `CrewMember`: user FK, ambulance FK, role
|
||||||
|
- `TripLog`: dispatch FK, ambulance FK, start_time, end_time, patient_fk
|
||||||
|
|
||||||
|
19. **nutrition**
|
||||||
|
- `MealPlan`: patient FK, date, meals (JSON), dietary_restrictions
|
||||||
|
- `DietaryOrder`: patient FK, meal_type, order_time, status
|
||||||
|
- `KitchenTask`: plan FK, task_description, assigned_to FK, status, completed_at
|
||||||
|
|
||||||
|
20. **security**
|
||||||
|
- `EncryptionKey`: key_name, key_type, created_at, rotation_date
|
||||||
|
- `AuditLogEntry` (enhanced for GDPR/HIPAA as above)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Shared Tooling, Interactivity & Deployment**
|
||||||
|
- **Assets**: SCSS in `assets/scss/` → `static/dist/main.css`; JS in `assets/js/` → `static/dist/main.js` via Webpack + Babel; `django-compressor` for compression.
|
||||||
|
- **HTMX**: All dynamic features use `hx-*` attributes—no per-template JS.
|
||||||
|
- **API**: DRF ModelViewSets under `/api/v1/`, secured with JWT/OAuth2, Swagger UI at `/api/docs/`.
|
||||||
|
- **Background**: Celery+Redis for notifications, HL7/DICOM messaging, IoT ingestion, AI scoring.
|
||||||
|
- **Testing/CI**: `pytest` + GitHub Actions for lint/test/build.
|
||||||
|
- **Deployment**: Gunicorn+Nginx configs, multitenancy notes, SSL/TLS, GDPR/HIPAA compliance checklist, 2FA setup, consent management, and monitoring guidance.
|
||||||
|
|
||||||
|
Ensure phased execution and strictly pause for approvals at each step. Good luck!
|
||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -511,6 +511,26 @@ class Bed(models.Model):
|
|||||||
return timezone.now() - self.occupied_since
|
return timezone.now() - self.occupied_since
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def mark_maintenance(self, notes=None):
|
||||||
|
"""
|
||||||
|
Mark bed for maintenance.
|
||||||
|
"""
|
||||||
|
self.status = 'MAINTENANCE'
|
||||||
|
self.last_maintenance = timezone.now()
|
||||||
|
if notes:
|
||||||
|
self.maintenance_notes = notes
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def mark_cleaned(self, user, cleaning_level='STANDARD'):
|
||||||
|
"""
|
||||||
|
Mark bed as cleaned.
|
||||||
|
"""
|
||||||
|
self.status = 'AVAILABLE'
|
||||||
|
self.last_cleaned = timezone.now()
|
||||||
|
self.cleaned_by = user
|
||||||
|
self.cleaning_level = cleaning_level
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
class Admission(models.Model):
|
class Admission(models.Model):
|
||||||
"""
|
"""
|
||||||
@ -1719,4 +1739,3 @@ class SurgerySchedule(models.Model):
|
|||||||
if self.actual_duration_minutes:
|
if self.actual_duration_minutes:
|
||||||
return self.actual_duration_minutes - self.estimated_duration_minutes
|
return self.actual_duration_minutes - self.estimated_duration_minutes
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
{% block title %}Bed {{ object.bed_number }} Details{% endblock %}
|
{% block title %}Bed {{ object.bed_number }} Details{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_head %}
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<div>
|
<div>
|
||||||
@ -190,86 +194,27 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Bed History -->
|
<!-- Bed History -->
|
||||||
<div class="panel panel-inverse" data-sortable-id="index-3">
|
<div class="panel panel-inverse" data-sortable-id="index-3">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
<i class="fas fa-history me-2"></i>Bed History
|
<i class="fas fa-history me-2"></i>Bed History
|
||||||
</h4>
|
</h4>
|
||||||
<div class="panel-heading-btn">
|
<div class="panel-heading-btn">
|
||||||
<button type="button" class="btn btn-xs btn-outline-primary me-2" onclick="refreshHistory()">
|
<button type="button" class="btn btn-xs btn-outline-primary me-2" hx-get="{% url 'inpatients:refresh_bed_history' object.pk %}" hx-target="#bed-history-body" hx-swap="innerHTML">
|
||||||
<i class="fas fa-sync me-2"></i>Refresh
|
<i class="fas fa-sync me-2"></i>Refresh
|
||||||
</button>
|
</button>
|
||||||
<a href="javascript:" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
<a href="javascript:" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
||||||
<a href="javascript:" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
<a href="javascript:" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
||||||
<a href="javascript:" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
<a href="javascript:" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
||||||
<a href="javascript:" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>
|
<a href="javascript:" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if admission_history %}
|
<div id="bed-history-body">
|
||||||
<div class="table-responsive">
|
{% include 'inpatients/partials/bed_history.html' %}
|
||||||
<table class="table table-hover">
|
</div>
|
||||||
<thead>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<th>Date</th>
|
|
||||||
<th>Action</th>
|
|
||||||
<th>Patient</th>
|
|
||||||
<th>Duration</th>
|
|
||||||
<th>Notes</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for history in admission_history %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div>{{ history.admission_datetime|date:"M d, Y" }}</div>
|
|
||||||
<div class="small text-muted">{{ history.admission_datetime|time:"g:i A" }}</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-{% if history.action == 'ADMISSION' %}success{% elif history.action == 'DISCHARGE' %}info{% elif history.action == 'TRANSFER' %}warning{% else %}secondary{% endif %}">
|
|
||||||
{{ history.get_action_display }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if history.patient %}
|
|
||||||
<a href="{% url 'patients:patient_detail' history.patient.pk %}">
|
|
||||||
{{ history.patient.get_full_name }}
|
|
||||||
</a>
|
|
||||||
<div class="small text-muted">{{ history.patient.mrn }}</div>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted">System action</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if history.duration %}
|
|
||||||
{{ history.duration }}
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted">-</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if history.notes %}
|
|
||||||
<span class="text-truncate" style="max-width: 200px;" title="{{ history.notes }}">
|
|
||||||
{{ history.notes }}
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted">-</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="text-center text-muted py-4">
|
|
||||||
<i class="fas fa-history fa-3x mb-3"></i>
|
|
||||||
<h5>No History Available</h5>
|
|
||||||
<p>No bed history records found for this bed.</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xl-3">
|
<div class="col-xl-3">
|
||||||
@ -439,7 +384,7 @@
|
|||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="statusUpdateForm">
|
<form id="statusUpdateForm" method="post" action="{% url 'inpatients:update_bed_status' object.pk %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" id="newStatus" name="status">
|
<input type="hidden" id="newStatus" name="status">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -456,6 +401,310 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Assign Patient Modal -->
|
||||||
|
<div class="modal fade" id="assignPatientModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Assign Patient to Bed</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="assignPatientForm" method="post" action="{% url 'inpatients:assign_patient_to_bed' object.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="patientSearch" class="form-label">Search Patient</label>
|
||||||
|
<input type="text" class="form-control" id="patientSearch" placeholder="Search by name or MRN..." onkeyup="searchPatients()">
|
||||||
|
<div id="patientResults" class="mt-2" style="max-height: 200px; overflow-y: auto;"></div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="selectedPatientId" name="patient_id">
|
||||||
|
<div id="selectedPatientInfo" class="d-none">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="card-title">Selected Patient</h6>
|
||||||
|
<div id="patientDetails"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="assignBtn" disabled onclick="assignPatientToBed()">Assign Patient</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Discharge Patient Modal -->
|
||||||
|
<div class="modal fade" id="dischargePatientModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Discharge Patient</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{% if object.current_admission %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||||
|
You are about to discharge <strong>{{ object.current_admission.patient.get_full_name }}</strong> from this bed.
|
||||||
|
</div>
|
||||||
|
<form id="dischargeForm" method="post" action="{% url 'inpatients:discharge_patient' object.current_admission.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="dischargeReason" class="form-label">Discharge Reason</label>
|
||||||
|
<select class="form-control" id="dischargeReason" name="discharge_reason" required>
|
||||||
|
<option value="">Select reason...</option>
|
||||||
|
<option value="RECOVERED">Recovered</option>
|
||||||
|
<option value="TRANSFERRED">Transferred to another facility</option>
|
||||||
|
<option value="AGAINST_MEDICAL_ADVICE">Against medical advice</option>
|
||||||
|
<option value="DECEASED">Deceased</option>
|
||||||
|
<option value="OTHER">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="dischargeNotes" class="form-label">Discharge Notes</label>
|
||||||
|
<textarea class="form-control" id="dischargeNotes" name="notes" rows="3" placeholder="Additional notes..."></textarea>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
No patient is currently assigned to this bed.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
{% if object.current_admission %}
|
||||||
|
<button type="button" class="btn btn-danger" onclick="dischargePatientConfirm()">Discharge Patient</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Transfer Patient Modal -->
|
||||||
|
<div class="modal fade" id="transferPatientModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Transfer Patient</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{% if object.current_admission %}
|
||||||
|
<form id="transferForm" method="post" action="{% url 'inpatients:transfer_patient' object.current_admission.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Current Location</label>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<strong>Ward:</strong> {{ object.ward.name }}<br>
|
||||||
|
<strong>Bed:</strong> {{ object.bed_number }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<strong>Patient:</strong> {{ object.current_admission.patient.get_full_name }}<br>
|
||||||
|
<strong>Admission Date:</strong> {{ object.current_admission.admission_datetime|date:"M d, Y" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="toWard" class="form-label">Transfer to Ward</label>
|
||||||
|
<select class="form-control" id="toWard" name="to_ward" required onchange="loadAvailableBeds()">
|
||||||
|
<option value="">Select ward...</option>
|
||||||
|
{% for ward in wards %}
|
||||||
|
{% if ward != object.ward %}
|
||||||
|
<option value="{{ ward.pk }}">{{ ward.name }} ({{ ward.available_beds }} available)</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="toBed" class="form-label">Transfer to Bed</label>
|
||||||
|
<select class="form-control" id="toBed" name="to_bed">
|
||||||
|
<option value="">Select bed...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="transferReason" class="form-label">Transfer Reason</label>
|
||||||
|
<select class="form-control" id="transferReason" name="reason" required>
|
||||||
|
<option value="">Select reason...</option>
|
||||||
|
<option value="CLINICAL_NEED">Clinical need</option>
|
||||||
|
<option value="BED_AVAILABILITY">Bed availability</option>
|
||||||
|
<option value="PATIENT_REQUEST">Patient request</option>
|
||||||
|
<option value="WARD_MAINTENANCE">Ward maintenance</option>
|
||||||
|
<option value="OTHER">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="transferPriority" class="form-label">Priority</label>
|
||||||
|
<select class="form-control" id="transferPriority" name="priority">
|
||||||
|
<option value="ROUTINE">Routine</option>
|
||||||
|
<option value="URGENT">Urgent</option>
|
||||||
|
<option value="EMERGENCY">Emergency</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="transferNotes" class="form-label">Notes</label>
|
||||||
|
<textarea class="form-control" id="transferNotes" name="notes" rows="2" placeholder="Additional notes..."></textarea>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
No patient is currently assigned to this bed.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
{% if object.current_admission %}
|
||||||
|
<button type="button" class="btn btn-primary" onclick="transferPatientConfirm()">Initiate Transfer</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Schedule Cleaning Modal -->
|
||||||
|
<div class="modal fade" id="scheduleCleaningModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Schedule Cleaning</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="cleaningForm" method="post" action="{% url 'inpatients:clean_bed' object.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="cleaningLevel" class="form-label">Cleaning Level</label>
|
||||||
|
<select class="form-control" id="cleaningLevel" name="cleaning_level" required>
|
||||||
|
<option value="ROUTINE">Routine</option>
|
||||||
|
<option value="DEEP">Deep cleaning</option>
|
||||||
|
<option value="TERMINAL">Terminal cleaning</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="cleaningNotes" class="form-label">Notes</label>
|
||||||
|
<textarea class="form-control" id="cleaningNotes" name="notes" rows="2" placeholder="Special instructions..."></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="markCleaned" name="mark_cleaned">
|
||||||
|
<label class="form-check-label" for="markCleaned">
|
||||||
|
Mark as cleaned immediately
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="scheduleCleaningConfirm()">Schedule Cleaning</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Schedule Maintenance Modal -->
|
||||||
|
<div class="modal fade" id="scheduleMaintenanceModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Schedule Maintenance</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="maintenanceForm" method="post" action="{% url 'inpatients:maintenance_bed' object.pk %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="maintenanceType" class="form-label">Maintenance Type</label>
|
||||||
|
<select class="form-control" id="maintenanceType" name="maintenance_type" required>
|
||||||
|
<option value="REPAIR">Repair</option>
|
||||||
|
<option value="INSPECTION">Inspection</option>
|
||||||
|
<option value="REPLACEMENT">Equipment replacement</option>
|
||||||
|
<option value="UPGRADE">Upgrade</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="maintenanceNotes" class="form-label">Description</label>
|
||||||
|
<textarea class="form-control" id="maintenanceNotes" name="notes" rows="3" placeholder="Describe the maintenance needed..." required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="priority" class="form-label">Priority</label>
|
||||||
|
<select class="form-control" id="priority" name="priority">
|
||||||
|
<option value="LOW">Low</option>
|
||||||
|
<option value="MEDIUM">Medium</option>
|
||||||
|
<option value="HIGH">High</option>
|
||||||
|
<option value="URGENT">Urgent</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="scheduleMaintenanceConfirm()">Schedule Maintenance</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bed Utilization Chart Modal -->
|
||||||
|
<div class="modal fade" id="bedChartModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-xl">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Bed Utilization Chart</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<canvas id="utilizationChart" width="400" height="200"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h6 class="card-title mb-0">Statistics</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<span>Current Occupancy:</span>
|
||||||
|
<span id="currentOccupancy">{{ bed_stats.occupancy_rate|default:0 }}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<span>Total Admissions:</span>
|
||||||
|
<span>{{ bed_stats.total_admissions|default:0 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<span>Avg Stay (days):</span>
|
||||||
|
<span>{{ bed_stats.avg_stay_days|default:0 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
<script src="{% static 'plugins/chart.js/dist/chart.umd.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
function updateBedStatus(status) {
|
function updateBedStatus(status) {
|
||||||
document.getElementById('newStatus').value = status;
|
document.getElementById('newStatus').value = status;
|
||||||
@ -465,52 +714,151 @@ function updateBedStatus(status) {
|
|||||||
|
|
||||||
function confirmStatusUpdate() {
|
function confirmStatusUpdate() {
|
||||||
const form = document.getElementById('statusUpdateForm');
|
const form = document.getElementById('statusUpdateForm');
|
||||||
const formData = new FormData(form);
|
form.submit();
|
||||||
|
|
||||||
// In a real implementation, this would submit via AJAX
|
|
||||||
console.log('Updating bed status to:', formData.get('status'));
|
|
||||||
|
|
||||||
// Close modal and refresh page
|
|
||||||
bootstrap.Modal.getInstance(document.getElementById('updateStatusModal')).hide();
|
|
||||||
location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignPatient() {
|
function assignPatient() {
|
||||||
// In a real implementation, this would open a patient selection modal
|
const modal = new bootstrap.Modal(document.getElementById('assignPatientModal'));
|
||||||
alert('Patient assignment functionality would be implemented here.');
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchPatients() {
|
||||||
|
const query = document.getElementById('patientSearch').value;
|
||||||
|
if (query.length < 2) {
|
||||||
|
document.getElementById('patientResults').innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/patients/api/search/?q=${encodeURIComponent(query)}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
let html = '';
|
||||||
|
data.forEach(patient => {
|
||||||
|
html += `
|
||||||
|
<div class="patient-result p-2 border-bottom" onclick="selectPatient(${patient.id}, '${patient.full_name}', '${patient.mrn}', '${patient.date_of_birth}')">
|
||||||
|
<strong>${patient.full_name}</strong><br>
|
||||||
|
<small class="text-muted">MRN: ${patient.mrn} | DOB: ${patient.date_of_birth}</small>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
document.getElementById('patientResults').innerHTML = html;
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error searching patients:', error));
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPatient(id, name, mrn, dob) {
|
||||||
|
document.getElementById('selectedPatientId').value = id;
|
||||||
|
document.getElementById('patientDetails').innerHTML = `
|
||||||
|
<strong>${name}</strong><br>
|
||||||
|
<small class="text-muted">MRN: ${mrn} | DOB: ${dob}</small>
|
||||||
|
`;
|
||||||
|
document.getElementById('selectedPatientInfo').classList.remove('d-none');
|
||||||
|
document.getElementById('assignBtn').disabled = false;
|
||||||
|
document.getElementById('patientResults').innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignPatientToBed() {
|
||||||
|
const form = document.getElementById('assignPatientForm');
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function dischargePatient() {
|
function dischargePatient() {
|
||||||
if (confirm('Are you sure you want to discharge the current patient?')) {
|
const modal = new bootstrap.Modal(document.getElementById('dischargePatientModal'));
|
||||||
// In a real implementation, this would handle discharge process
|
modal.show();
|
||||||
alert('Discharge process would be initiated here.');
|
}
|
||||||
}
|
|
||||||
|
function dischargePatientConfirm() {
|
||||||
|
const form = document.getElementById('dischargeForm');
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferPatient() {
|
function transferPatient() {
|
||||||
// In a real implementation, this would open a transfer modal
|
const modal = new bootstrap.Modal(document.getElementById('transferPatientModal'));
|
||||||
alert('Patient transfer functionality would be implemented here.');
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAvailableBeds() {
|
||||||
|
const wardId = document.getElementById('toWard').value;
|
||||||
|
const bedSelect = document.getElementById('toBed');
|
||||||
|
|
||||||
|
if (!wardId) {
|
||||||
|
bedSelect.innerHTML = '<option value="">Select bed...</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/inpatients/beds/available/?ward_id=${wardId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
let html = '<option value="">Select bed...</option>';
|
||||||
|
data.beds.forEach(bed => {
|
||||||
|
html += `<option value="${bed.id}">${bed.name}</option>`;
|
||||||
|
});
|
||||||
|
bedSelect.innerHTML = html;
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error loading beds:', error));
|
||||||
|
}
|
||||||
|
|
||||||
|
function transferPatientConfirm() {
|
||||||
|
const form = document.getElementById('transferForm');
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function scheduleCleaning() {
|
function scheduleCleaning() {
|
||||||
// In a real implementation, this would open a cleaning schedule modal
|
const modal = new bootstrap.Modal(document.getElementById('scheduleCleaningModal'));
|
||||||
alert('Cleaning schedule functionality would be implemented here.');
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleCleaningConfirm() {
|
||||||
|
const form = document.getElementById('cleaningForm');
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function scheduleMaintenance() {
|
function scheduleMaintenance() {
|
||||||
// In a real implementation, this would open a maintenance schedule modal
|
const modal = new bootstrap.Modal(document.getElementById('scheduleMaintenanceModal'));
|
||||||
alert('Maintenance schedule functionality would be implemented here.');
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleMaintenanceConfirm() {
|
||||||
|
const form = document.getElementById('maintenanceForm');
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function viewBedChart() {
|
function viewBedChart() {
|
||||||
// In a real implementation, this would show utilization charts
|
const modal = new bootstrap.Modal(document.getElementById('bedChartModal'));
|
||||||
alert('Bed utilization charts would be displayed here.');
|
modal.show();
|
||||||
|
|
||||||
|
// Load chart data
|
||||||
|
fetch(`/inpatients/beds/{{ object.pk }}/utilization/`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const ctx = document.getElementById('utilizationChart').getContext('2d');
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: data.labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Occupancy Rate (%)',
|
||||||
|
data: data.data,
|
||||||
|
borderColor: 'rgb(75, 192, 192)',
|
||||||
|
tension: 0.1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
max: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error loading chart data:', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshHistory() {
|
function refreshHistory() {
|
||||||
// In a real implementation, this would refresh the history via AJAX
|
// HTMX handles this
|
||||||
location.reload();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,380 +1,123 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load static %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}Delete Discharge Record{% endblock %}
|
{% block title %}{% trans "Delete Discharge Summary" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex align-items-center mb-3">
|
|
||||||
<div>
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'inpatients:dashboard' %}">Inpatients</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_list' %}">Discharges</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_detail' object.pk %}">Discharge #{{ object.pk }}</a></li>
|
|
||||||
<li class="breadcrumb-item active">Delete</li>
|
|
||||||
</ol>
|
|
||||||
<h1 class="page-header mb-0">Delete Discharge Record</h1>
|
|
||||||
</div>
|
|
||||||
<div class="ms-auto">
|
|
||||||
<a href="{% url 'inpatients:discharge_detail' object.pk %}" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-arrow-left me-2"></i>Back to Discharge
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row justify-content-center">
|
<!-- BEGIN breadcrumb -->
|
||||||
<div class="col-xl-8">
|
<ol class="breadcrumb float-xl-end">
|
||||||
<div class="card">
|
<li class="breadcrumb-item"><a href="javascript:;">Home</a></li>
|
||||||
<div class="card-header bg-danger text-white">
|
<li class="breadcrumb-item"><a href="javascript:;">Inpatients</a></li>
|
||||||
<h4 class="card-title mb-0">
|
<li class="breadcrumb-item"><a href="javascript:;">Discharges</a></li>
|
||||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_summary_list' %}">Discharge Summaries</a></li>
|
||||||
Confirm Discharge Record Deletion
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_summary_detail' discharge_summary.id %}">{{ discharge_summary.admission.patient.get_full_name }}</a></li>
|
||||||
</h4>
|
<li class="breadcrumb-item active">Delete</li>
|
||||||
</div>
|
</ol>
|
||||||
<div class="card-body">
|
<!-- END breadcrumb -->
|
||||||
<div class="alert alert-warning">
|
<!-- BEGIN page-header -->
|
||||||
<h5 class="alert-heading">
|
<h1 class="page-header">Delete Discharge Summary <small>{{ discharge_summary.admission.patient.get_full_name }}</small></h1>
|
||||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
<!-- END page-header -->
|
||||||
Are you sure you want to delete this discharge record?
|
|
||||||
</h5>
|
|
||||||
<p class="mb-0">
|
|
||||||
This action cannot be undone. The discharge record and all associated data will be permanently removed from the system.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Discharge Details -->
|
<!-- BEGIN row -->
|
||||||
<div class="row mb-4">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<!-- BEGIN col-12 -->
|
||||||
<div class="card bg-light">
|
<div class="col-xl-12">
|
||||||
<div class="card-body">
|
<!-- BEGIN panel -->
|
||||||
<h6 class="card-title">
|
<div class="panel panel-inverse" data-sortable-id="delete-discharge-summary">
|
||||||
<i class="fas fa-user-injured me-2"></i>Patient Information
|
<div class="panel-heading">
|
||||||
</h6>
|
<h4 class="panel-title">
|
||||||
<div class="mb-2">
|
<i class="fa fa-trash-alt me-2"></i>{% trans "Delete Discharge Summary" %}
|
||||||
<strong>Patient:</strong> {{ object.admission.patient.get_full_name }}
|
<span class="badge bg-danger ms-2">
|
||||||
</div>
|
<i class="fa fa-exclamation-triangle me-1"></i>{% trans "Warning" %}
|
||||||
<div class="mb-2">
|
</span>
|
||||||
<strong>MRN:</strong> {{ object.admission.patient.medical_record_number }}
|
</h4>
|
||||||
</div>
|
<div class="panel-heading-btn">
|
||||||
<div class="mb-2">
|
<a href="{% url 'inpatients:discharge_summary_detail' discharge_summary.id %}" class="btn btn-xs btn-icon btn-info me-1" title="{% trans 'View' %}">
|
||||||
<strong>DOB:</strong> {{ object.admission.patient.date_of_birth|date:"M d, Y" }}
|
<i class="fa fa-eye"></i>
|
||||||
</div>
|
</a>
|
||||||
<div>
|
<a href="{% url 'inpatients:discharge_summary_update' discharge_summary.id %}" class="btn btn-xs btn-icon btn-warning me-1" title="{% trans 'Edit' %}">
|
||||||
<strong>Age:</strong> {{ object.admission.patient.age }} years
|
<i class="fa fa-edit"></i>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
||||||
</div>
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
||||||
</div>
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
||||||
<div class="col-md-6">
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>
|
||||||
<div class="card bg-light">
|
</div>
|
||||||
<div class="card-body">
|
</div>
|
||||||
<h6 class="card-title">
|
<div class="panel-body">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Discharge Information
|
<!-- Warning Alert -->
|
||||||
</h6>
|
<div class="note alert-danger mb-4 p-4">
|
||||||
<div class="mb-2">
|
<h5 class="alert-heading mb-3">
|
||||||
<strong>Discharge Date:</strong> {{ object.discharge_date|date:"M d, Y g:i A" }}
|
<i class="fa fa-exclamation-triangle me-2"></i>{% trans "Warning: This action cannot be undone!" %}
|
||||||
</div>
|
</h5>
|
||||||
<div class="mb-2">
|
<p class="mb-0">{% trans "Are you sure you want to delete this discharge summary? This will permanently remove all associated data." %}</p>
|
||||||
<strong>Discharge Type:</strong> {{ object.get_discharge_type_display }}
|
</div>
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<strong>Status:</strong>
|
|
||||||
<span class="badge bg-{% if object.status == 'completed' %}success{% elif object.status == 'pending' %}warning{% else %}info{% endif %}">
|
|
||||||
{{ object.get_status_display }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<strong>Discharge ID:</strong> {{ object.pk }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Admission Details -->
|
<!-- Summary Information -->
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12">
|
<div class="col-md-8">
|
||||||
<div class="card bg-light">
|
<div class="bg-light p-3 rounded">
|
||||||
<div class="card-body">
|
<h6 class="text-primary mb-3"><i class="fa fa-file-medical me-2"></i>{% trans "Discharge Summary Details" %}</h6>
|
||||||
<h6 class="card-title">
|
<div class="row">
|
||||||
<i class="fas fa-hospital me-2"></i>Related Admission Information
|
<div class="col-md-6">
|
||||||
</h6>
|
<p class="mb-2"><i class="fa fa-user me-2"></i><strong>{% trans "Patient" %}:</strong> {{ discharge_summary.admission.patient.get_full_name }}</p>
|
||||||
<div class="row">
|
<p class="mb-2"><i class="fa fa-id-card me-2"></i><strong>{% trans "MRN" %}:</strong> {{ discharge_summary.admission.patient.mrn }}</p>
|
||||||
<div class="col-md-6">
|
<p class="mb-0"><i class="fa fa-calendar-plus me-2"></i><strong>{% trans "Admission Date" %}:</strong> {{ discharge_summary.admission.admission_datetime|date:"M d, Y g:i A" }}</p>
|
||||||
<div class="mb-2">
|
</div>
|
||||||
<strong>Admission Date:</strong> {{ object.admission.admission_date|date:"M d, Y g:i A" }}
|
<div class="col-md-6">
|
||||||
</div>
|
<p class="mb-2"><i class="fa fa-calendar-minus me-2"></i><strong>{% trans "Discharge Date" %}:</strong> {{ discharge_summary.discharge_date|date:"M d, Y" }} {{ discharge_summary.discharge_time|time:"g:i A" }}</p>
|
||||||
<div class="mb-2">
|
<p class="mb-2"><i class="fa fa-user-md me-2"></i><strong>{% trans "Physician" %}:</strong> {{ discharge_summary.discharging_physician.get_full_name }}</p>
|
||||||
<strong>Length of Stay:</strong> {{ object.length_of_stay }} days
|
<p class="mb-0"><i class="fa fa-clock me-2"></i><strong>{% trans "Length of Stay" %}:</strong> {{ discharge_summary.length_of_stay }} {% trans "days" %}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<strong>Ward:</strong> {{ object.admission.ward.name }}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-4">
|
||||||
<div class="col-md-6">
|
<div class="bg-light p-3 rounded h-100">
|
||||||
<div class="mb-2">
|
<h6 class="text-info mb-3"><i class="fa fa-info-circle me-2"></i>{% trans "Status" %}</h6>
|
||||||
<strong>Bed:</strong> {{ object.admission.bed.bed_number }}
|
{% if discharge_summary.summary_completed %}
|
||||||
</div>
|
<span class="badge bg-success d-block mb-2">
|
||||||
<div class="mb-2">
|
<i class="fa fa-check me-1"></i>{% trans "Summary Completed" %}
|
||||||
<strong>Attending Physician:</strong> {{ object.admission.attending_physician.get_full_name }}
|
</span>
|
||||||
</div>
|
{% if discharge_summary.summary_signed %}
|
||||||
<div>
|
<span class="badge bg-info d-block mb-2">
|
||||||
<strong>Admission Diagnosis:</strong> {{ object.admission.primary_diagnosis }}
|
<i class="fa fa-signature me-1"></i>{% trans "Summary Signed" %}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
{% else %}
|
||||||
</div>
|
<span class="badge bg-warning d-block mb-2">
|
||||||
</div>
|
<i class="fa fa-clock me-1"></i>{% trans "Incomplete" %}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
{% endif %}
|
||||||
|
{% if discharge_summary.patient_copy_provided %}
|
||||||
|
<span class="badge bg-primary d-block">
|
||||||
|
<i class="fa fa-copy me-1"></i>{% trans "Patient Copy Provided" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if object.discharge_summary %}
|
<!-- Confirmation Form -->
|
||||||
<div class="row mb-4">
|
<div class="text-center">
|
||||||
<div class="col-12">
|
<p class="text-muted mb-4">{% trans "Please confirm that you want to permanently delete this discharge summary." %}</p>
|
||||||
<div class="card bg-light">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title">
|
|
||||||
<i class="fas fa-file-medical me-2"></i>Discharge Summary
|
|
||||||
</h6>
|
|
||||||
<div class="alert alert-info mb-0">
|
|
||||||
{{ object.discharge_summary|truncatewords:50 }}
|
|
||||||
{% if object.discharge_summary|wordcount > 50 %}
|
|
||||||
<div class="mt-2">
|
|
||||||
<small class="text-muted">Summary truncated for display...</small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if object.discharge_medications.exists %}
|
<form method="post" class="d-inline">
|
||||||
<div class="row mb-4">
|
{% csrf_token %}
|
||||||
<div class="col-12">
|
<button type="submit" class="btn btn-danger btn-lg me-3">
|
||||||
<div class="card bg-light">
|
<i class="fa fa-trash-alt me-2"></i>{% trans "Yes, Delete Discharge Summary" %}
|
||||||
<div class="card-body">
|
</button>
|
||||||
<h6 class="card-title">
|
<a href="{% url 'inpatients:discharge_summary_detail' discharge_summary.id %}" class="btn btn-outline-secondary btn-lg">
|
||||||
<i class="fas fa-pills me-2"></i>Discharge Medications
|
<i class="fa fa-times me-2"></i>{% trans "Cancel" %}
|
||||||
</h6>
|
</a>
|
||||||
<div class="row">
|
</form>
|
||||||
{% for medication in object.discharge_medications.all|slice:":6" %}
|
</div>
|
||||||
<div class="col-md-6 mb-2">
|
</div>
|
||||||
<div class="d-flex align-items-center">
|
</div>
|
||||||
<i class="fas fa-pill text-primary me-2"></i>
|
<!-- END panel -->
|
||||||
<div>
|
</div>
|
||||||
<strong>{{ medication.medication.name }}</strong>
|
<!-- END col-12 -->
|
||||||
<div class="small text-muted">{{ medication.dosage }} - {{ medication.frequency }}</div>
|
</div>
|
||||||
</div>
|
<!-- END row -->
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% if object.discharge_medications.count > 6 %}
|
|
||||||
<div class="col-12">
|
|
||||||
<small class="text-muted">And {{ object.discharge_medications.count|add:"-6" }} more medications...</small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Deletion Form -->
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="deletion_reason" class="form-label">
|
|
||||||
<strong>Reason for Deletion *</strong>
|
|
||||||
</label>
|
|
||||||
<select class="form-select" id="deletion_reason" name="deletion_reason" required>
|
|
||||||
<option value="">Select a reason</option>
|
|
||||||
<option value="data_error">Data Entry Error</option>
|
|
||||||
<option value="duplicate_record">Duplicate Record</option>
|
|
||||||
<option value="patient_request">Patient Request</option>
|
|
||||||
<option value="privacy_compliance">Privacy Compliance</option>
|
|
||||||
<option value="system_error">System Error</option>
|
|
||||||
<option value="incorrect_discharge">Incorrect Discharge</option>
|
|
||||||
<option value="administrative">Administrative Correction</option>
|
|
||||||
<option value="other">Other</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="deletion_notes" class="form-label">
|
|
||||||
<strong>Additional Notes</strong>
|
|
||||||
</label>
|
|
||||||
<textarea class="form-control"
|
|
||||||
id="deletion_notes"
|
|
||||||
name="deletion_notes"
|
|
||||||
rows="3"
|
|
||||||
placeholder="Provide additional details about why this discharge record is being deleted..."></textarea>
|
|
||||||
<div class="form-text">
|
|
||||||
These notes will be recorded for audit purposes and compliance.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check mb-3">
|
|
||||||
<input class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
id="confirm_deletion"
|
|
||||||
name="confirm_deletion"
|
|
||||||
required>
|
|
||||||
<label class="form-check-label" for="confirm_deletion">
|
|
||||||
I understand that this action cannot be undone and confirm the deletion of this discharge record.
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check mb-3">
|
|
||||||
<input class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
id="notify_stakeholders"
|
|
||||||
name="notify_stakeholders">
|
|
||||||
<label class="form-check-label" for="notify_stakeholders">
|
|
||||||
Notify relevant stakeholders (attending physician, nursing staff, billing department) about this deletion.
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<h6 class="alert-heading">
|
|
||||||
<i class="fas fa-info-circle me-2"></i>What happens when you delete this discharge record?
|
|
||||||
</h6>
|
|
||||||
<ul class="mb-0">
|
|
||||||
<li>The discharge record will be permanently removed from the system</li>
|
|
||||||
<li>The associated admission will be marked as "active" again</li>
|
|
||||||
<li>The patient's bed will be marked as occupied</li>
|
|
||||||
<li>Discharge medications and instructions will be deleted</li>
|
|
||||||
<li>Billing records may be affected and require manual adjustment</li>
|
|
||||||
<li>This action will be logged in the audit trail</li>
|
|
||||||
<li>Follow-up appointments may need to be rescheduled</li>
|
|
||||||
<li>Insurance claims may need to be updated</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<a href="{% url 'inpatients:discharge_detail' object.pk %}" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-times me-2"></i>Cancel
|
|
||||||
</a>
|
|
||||||
<button type="submit" class="btn btn-danger" onclick="return confirmDeletion()">
|
|
||||||
<i class="fas fa-trash me-2"></i>Delete Discharge Record
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Impact Warning -->
|
|
||||||
{% if object.status == 'completed' %}
|
|
||||||
<div class="card mt-4">
|
|
||||||
<div class="card-header bg-warning text-dark">
|
|
||||||
<h5 class="card-title mb-0">
|
|
||||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
||||||
Important Considerations
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<strong>Completed Discharge:</strong> This discharge has been completed. Deleting it may affect:
|
|
||||||
<ul class="mb-0 mt-2">
|
|
||||||
<li>Billing and insurance claims that have already been processed</li>
|
|
||||||
<li>Quality metrics and hospital statistics</li>
|
|
||||||
<li>Regulatory reporting requirements</li>
|
|
||||||
<li>Patient care continuity and follow-up schedules</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if object.follow_up_appointments.exists %}
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<strong>Follow-up Appointments:</strong> This discharge has {{ object.follow_up_appointments.count }} associated follow-up appointment{{ object.follow_up_appointments.count|pluralize }}.
|
|
||||||
These may need to be rescheduled or cancelled.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Related Information -->
|
|
||||||
<div class="card mt-4">
|
|
||||||
<div class="card-header">
|
|
||||||
<h5 class="card-title">
|
|
||||||
<i class="fas fa-link me-2"></i>
|
|
||||||
Related Information
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h6>Discharge Details</h6>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li><strong>Discharge ID:</strong> {{ object.pk }}</li>
|
|
||||||
<li><strong>Created:</strong> {{ object.created_at|date:"M d, Y g:i A" }}</li>
|
|
||||||
<li><strong>Last Updated:</strong> {{ object.updated_at|date:"M d, Y g:i A" }}</li>
|
|
||||||
<li><strong>Created By:</strong> {{ object.created_by.get_full_name|default:"System" }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h6>System Information</h6>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li><strong>Admission ID:</strong> {{ object.admission.pk }}</li>
|
|
||||||
<li><strong>Patient ID:</strong> {{ object.admission.patient.pk }}</li>
|
|
||||||
{% if object.discharge_medications.exists %}
|
|
||||||
<li><strong>Medications:</strong> {{ object.discharge_medications.count }} prescribed</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if object.follow_up_appointments.exists %}
|
|
||||||
<li><strong>Follow-ups:</strong> {{ object.follow_up_appointments.count }} scheduled</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function confirmDeletion() {
|
|
||||||
const reason = document.getElementById('deletion_reason').value;
|
|
||||||
const confirmed = document.getElementById('confirm_deletion').checked;
|
|
||||||
|
|
||||||
if (!reason) {
|
|
||||||
alert('Please select a reason for deletion.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
alert('Please confirm that you understand this action cannot be undone.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dischargeId = "{{ object.pk }}";
|
|
||||||
const patientName = "{{ object.admission.patient.get_full_name }}";
|
|
||||||
const dischargeDate = "{{ object.discharge_date|date:'M d, Y' }}";
|
|
||||||
|
|
||||||
const message = `Are you absolutely sure you want to delete this discharge record?\n\nPatient: ${patientName}\nDischarge Date: ${dischargeDate}\nDischarge ID: ${dischargeId}\n\nThis action cannot be undone and may affect billing, statistics, and patient care continuity.`;
|
|
||||||
|
|
||||||
return confirm(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
// Auto-focus on deletion reason
|
|
||||||
document.getElementById('deletion_reason').focus();
|
|
||||||
|
|
||||||
// Show/hide additional notes based on reason
|
|
||||||
const reasonSelect = document.getElementById('deletion_reason');
|
|
||||||
const notesTextarea = document.getElementById('deletion_notes');
|
|
||||||
|
|
||||||
reasonSelect.addEventListener('change', function() {
|
|
||||||
if (this.value === 'other') {
|
|
||||||
notesTextarea.required = true;
|
|
||||||
notesTextarea.placeholder = 'Please specify the reason for deletion...';
|
|
||||||
} else {
|
|
||||||
notesTextarea.required = false;
|
|
||||||
notesTextarea.placeholder = 'Provide additional details about why this discharge record is being deleted...';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,454 +1,458 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load static %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{{ object|yesno:"Edit,Create" }} Discharge - Inpatients{% endblock %}
|
{% block title %}{% if form.instance.pk %}{% trans "Edit Discharge Summary" %}{% else %}{% trans "Create Discharge Summary" %}{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
<link href="{% static 'assets/plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
||||||
<link href="{% static 'assets/plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
|
||||||
<link href="{% static 'assets/plugins/bootstrap-timepicker/css/bootstrap-timepicker.min.css' %}" rel="stylesheet" />
|
|
||||||
<link href="{% static 'assets/plugins/summernote/dist/summernote-lite.css' %}" rel="stylesheet" />
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- BEGIN breadcrumb -->
|
|
||||||
<ol class="breadcrumb float-xl-end">
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'inpatients:dashboard' %}">Inpatients</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_list' %}">Discharges</a></li>
|
|
||||||
<li class="breadcrumb-item active">{{ object|yesno:"Edit,Create" }} Discharge</li>
|
|
||||||
</ol>
|
|
||||||
<!-- END breadcrumb -->
|
|
||||||
|
|
||||||
<!-- BEGIN page-header -->
|
<!-- BEGIN breadcrumb -->
|
||||||
<h1 class="page-header">{{ object|yesno:"Edit,Create" }} Patient Discharge</h1>
|
<ol class="breadcrumb float-xl-end">
|
||||||
<!-- END page-header -->
|
<li class="breadcrumb-item"><a href="javascript:;">Home</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="javascript:;">Inpatients</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="javascript:;">Discharges</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:discharge_summary_list' %}">Discharge Summaries</a></li>
|
||||||
|
<li class="breadcrumb-item active">{% if form.instance.pk %}Edit{% else %}Create{% endif %}</li>
|
||||||
|
</ol>
|
||||||
|
<!-- END breadcrumb -->
|
||||||
|
<!-- BEGIN page-header -->
|
||||||
|
<h1 class="page-header">{% if form.instance.pk %}Edit{% else %}Create{% endif %} Discharge Summary <small>{% if form.instance.pk %}{{ form.instance.admission.patient.get_full_name }}{% else %}New Summary{% endif %}</small></h1>
|
||||||
|
<!-- END page-header -->
|
||||||
|
|
||||||
<div class="row">
|
<!-- BEGIN row -->
|
||||||
<div class="col-xl-8">
|
<div class="row">
|
||||||
<!-- BEGIN panel -->
|
<!-- BEGIN col-12 -->
|
||||||
<div class="panel panel-inverse">
|
<div class="col-xl-12">
|
||||||
<div class="panel-heading">
|
<!-- BEGIN panel -->
|
||||||
<h4 class="panel-title">Discharge Information</h4>
|
<div class="panel panel-inverse" data-sortable-id="discharge-form">
|
||||||
<div class="panel-heading-btn">
|
<div class="panel-heading">
|
||||||
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
<h4 class="panel-title">
|
||||||
</div>
|
<i class="fa fa-file-medical me-2"></i>{% if form.instance.pk %}{% trans "Edit Discharge Summary" %}{% else %}{% trans "Create Discharge Summary" %}{% endif %}
|
||||||
</div>
|
{% if form.instance.pk %}
|
||||||
<div class="panel-body">
|
{% if form.instance.summary_completed %}
|
||||||
<form method="post" id="discharge-form">
|
<span class="badge bg-success ms-2">
|
||||||
{% csrf_token %}
|
<i class="fa fa-check me-1"></i>{% trans "Completed" %}
|
||||||
|
</span>
|
||||||
<!-- Patient and Admission Information -->
|
{% else %}
|
||||||
<div class="row mb-3">
|
<span class="badge bg-warning ms-2">
|
||||||
<div class="col-md-6">
|
<i class="fa fa-clock me-1"></i>{% trans "Incomplete" %}
|
||||||
<label class="form-label" for="{{ form.admission.id_for_label }}">Admission <span class="text-danger">*</span></label>
|
</span>
|
||||||
{{ form.admission }}
|
{% endif %}
|
||||||
{% if form.admission.errors %}
|
{% else %}
|
||||||
<div class="invalid-feedback d-block">{{ form.admission.errors.0 }}</div>
|
<span class="badge bg-primary ms-2">
|
||||||
{% endif %}
|
<i class="fa fa-plus me-1"></i>{% trans "New" %}
|
||||||
<div class="form-text">Select the admission to discharge</div>
|
</span>
|
||||||
</div>
|
{% endif %}
|
||||||
<div class="col-md-6">
|
</h4>
|
||||||
<label class="form-label" for="{{ form.discharge_type.id_for_label }}">Discharge Type <span class="text-danger">*</span></label>
|
<div class="panel-heading-btn">
|
||||||
{{ form.discharge_type }}
|
{% if form.instance.pk %}
|
||||||
{% if form.discharge_type.errors %}
|
<a href="{% url 'inpatients:discharge_summary_detail' form.instance.pk %}" class="btn btn-xs btn-icon btn-info me-1" title="{% trans 'View' %}">
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_type.errors.0 }}</div>
|
<i class="fa fa-eye"></i>
|
||||||
{% endif %}
|
</a>
|
||||||
</div>
|
<a href="{% url 'inpatients:discharge_summary_delete' form.instance.pk %}" class="btn btn-xs btn-icon btn-danger me-1" title="{% trans 'Delete' %}">
|
||||||
</div>
|
<i class="fa fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Discharge Date and Time -->
|
<!-- Basic Information Section -->
|
||||||
<div class="row mb-3">
|
<div class="d-flex align-items-center mb-3">
|
||||||
<div class="col-md-4">
|
<i class="fa fa-info-circle fa-2x text-primary me-3"></i>
|
||||||
<label class="form-label" for="{{ form.discharge_date.id_for_label }}">Discharge Date <span class="text-danger">*</span></label>
|
<div>
|
||||||
{{ form.discharge_date }}
|
<h5 class="mb-1">{% trans "Basic Information" %}</h5>
|
||||||
{% if form.discharge_date.errors %}
|
<small class="text-muted">Admission and discharge details</small>
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_date.errors.0 }}</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label" for="{{ form.discharge_time.id_for_label }}">Discharge Time <span class="text-danger">*</span></label>
|
|
||||||
{{ form.discharge_time }}
|
|
||||||
{% if form.discharge_time.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_time.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label" for="{{ form.discharge_status.id_for_label }}">Status</label>
|
|
||||||
{{ form.discharge_status }}
|
|
||||||
{% if form.discharge_status.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_status.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Discharge Destination -->
|
<div class="row mb-4">
|
||||||
<div class="row mb-3">
|
<div class="col-md-6">
|
||||||
<div class="col-md-6">
|
<div class="bg-light p-3 rounded">
|
||||||
<label class="form-label" for="{{ form.discharge_destination.id_for_label }}">Discharge Destination</label>
|
<h6 class="text-primary mb-3"><i class="fa fa-hospital-user me-2"></i>{% trans "Admission Details" %}</h6>
|
||||||
{{ form.discharge_destination }}
|
<div class="mb-3">
|
||||||
{% if form.discharge_destination.errors %}
|
<label class="form-label fw-bold">{% trans "Admission" %}</label>
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_destination.errors.0 }}</div>
|
{{ form.admission }}
|
||||||
{% endif %}
|
{% if form.admission.errors %}
|
||||||
</div>
|
<div class="invalid-feedback d-block">{{ form.admission.errors }}</div>
|
||||||
<div class="col-md-6">
|
{% endif %}
|
||||||
<label class="form-label" for="{{ form.attending_physician.id_for_label }}">Attending Physician</label>
|
</div>
|
||||||
{{ form.attending_physician }}
|
<div class="mb-3">
|
||||||
{% if form.attending_physician.errors %}
|
<label class="form-label fw-bold">{% trans "Discharging Physician" %}</label>
|
||||||
<div class="invalid-feedback d-block">{{ form.attending_physician.errors.0 }}</div>
|
{{ form.discharging_physician }}
|
||||||
{% endif %}
|
{% if form.discharging_physician.errors %}
|
||||||
</div>
|
<div class="invalid-feedback d-block">{{ form.discharging_physician.errors }}</div>
|
||||||
</div>
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-success mb-3"><i class="fa fa-calendar-check me-2"></i>{% trans "Discharge Details" %}</h6>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Discharge Date" %}</label>
|
||||||
|
{{ form.discharge_date }}
|
||||||
|
{% if form.discharge_date.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.discharge_date.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Discharge Time" %}</label>
|
||||||
|
{{ form.discharge_time }}
|
||||||
|
{% if form.discharge_time.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.discharge_time.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Length of Stay (days)" %}</label>
|
||||||
|
{{ form.length_of_stay }}
|
||||||
|
{% if form.length_of_stay.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.length_of_stay.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Clinical Information -->
|
<!-- Status Section -->
|
||||||
<h5 class="mb-3 mt-4">Clinical Information</h5>
|
<div class="d-flex align-items-center mb-3">
|
||||||
<div class="row mb-3">
|
<i class="fa fa-tasks fa-2x text-warning me-3"></i>
|
||||||
<div class="col-md-6">
|
<div>
|
||||||
<label class="form-label" for="{{ form.primary_diagnosis.id_for_label }}">Primary Diagnosis</label>
|
<h5 class="mb-1">{% trans "Status & Documentation" %}</h5>
|
||||||
{{ form.primary_diagnosis }}
|
<small class="text-muted">Completion status and documentation</small>
|
||||||
{% if form.primary_diagnosis.errors %}
|
</div>
|
||||||
<div class="invalid-feedback d-block">{{ form.primary_diagnosis.errors.0 }}</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="{{ form.secondary_diagnoses.id_for_label }}">Secondary Diagnoses</label>
|
|
||||||
{{ form.secondary_diagnoses }}
|
|
||||||
{% if form.secondary_diagnoses.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.secondary_diagnoses.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="row mb-4">
|
||||||
<label class="form-label" for="{{ form.discharge_summary.id_for_label }}">Discharge Summary</label>
|
<div class="col-md-4">
|
||||||
{{ form.discharge_summary }}
|
<div class="form-check mb-3">
|
||||||
{% if form.discharge_summary.errors %}
|
{{ form.summary_completed }}
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_summary.errors.0 }}</div>
|
<label class="form-check-label fw-bold">
|
||||||
{% endif %}
|
<i class="fa fa-check-circle text-success me-2"></i>{% trans "Summary Completed" %}
|
||||||
<div class="form-text">Comprehensive summary of the patient's stay and treatment</div>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.summary_signed }}
|
||||||
|
<label class="form-check-label fw-bold">
|
||||||
|
<i class="fa fa-signature text-info me-2"></i>{% trans "Summary Signed" %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.patient_copy_provided }}
|
||||||
|
<label class="form-check-label fw-bold">
|
||||||
|
<i class="fa fa-copy text-primary me-2"></i>{% trans "Patient Copy Provided" %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Medications and Instructions -->
|
<hr>
|
||||||
<h5 class="mb-3 mt-4">Discharge Instructions</h5>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="{{ form.discharge_medications.id_for_label }}">Discharge Medications</label>
|
|
||||||
{{ form.discharge_medications }}
|
|
||||||
{% if form.discharge_medications.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_medications.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="form-text">List all medications the patient should continue at home</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- Clinical Summary Section -->
|
||||||
<label class="form-label" for="{{ form.discharge_instructions.id_for_label }}">Patient Instructions</label>
|
<div class="d-flex align-items-center mb-3">
|
||||||
{{ form.discharge_instructions }}
|
<i class="fa fa-clipboard-list fa-2x text-info me-3"></i>
|
||||||
{% if form.discharge_instructions.errors %}
|
<div>
|
||||||
<div class="invalid-feedback d-block">{{ form.discharge_instructions.errors.0 }}</div>
|
<h5 class="mb-1">{% trans "Clinical Summary" %}</h5>
|
||||||
{% endif %}
|
<small class="text-muted">Medical diagnosis and hospital course details</small>
|
||||||
<div class="form-text">Detailed instructions for patient care at home</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="row mb-4">
|
||||||
<label class="form-label" for="{{ form.follow_up_instructions.id_for_label }}">Follow-up Instructions</label>
|
<div class="col-md-6">
|
||||||
{{ form.follow_up_instructions }}
|
<div class="bg-light p-3 rounded">
|
||||||
{% if form.follow_up_instructions.errors %}
|
<h6 class="text-primary mb-3"><i class="fa fa-diagnoses me-2"></i>{% trans "Diagnoses" %}</h6>
|
||||||
<div class="invalid-feedback d-block">{{ form.follow_up_instructions.errors.0 }}</div>
|
<div class="mb-3">
|
||||||
{% endif %}
|
<label class="form-label fw-bold">{% trans "Admission Diagnosis" %}</label>
|
||||||
<div class="form-text">When and where the patient should follow up</div>
|
{{ form.admission_diagnosis }}
|
||||||
</div>
|
{% if form.admission_diagnosis.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.admission_diagnosis.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Final Diagnosis" %}</label>
|
||||||
|
{{ form.final_diagnosis }}
|
||||||
|
{% if form.final_diagnosis.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.final_diagnosis.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Secondary Diagnoses (JSON list)" %}</label>
|
||||||
|
{{ form.secondary_diagnoses }}
|
||||||
|
{% if form.secondary_diagnoses.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.secondary_diagnoses.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-success mb-3"><i class="fa fa-procedures me-2"></i>{% trans "Procedures & Course" %}</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Procedures Performed (JSON list)" %}</label>
|
||||||
|
{{ form.procedures_performed }}
|
||||||
|
{% if form.procedures_performed.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.procedures_performed.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Hospital Course" %}</label>
|
||||||
|
{{ form.hospital_course }}
|
||||||
|
{% if form.hospital_course.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.hospital_course.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Complications" %}</label>
|
||||||
|
{{ form.complications }}
|
||||||
|
{% if form.complications.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.complications.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Activity and Diet -->
|
<hr>
|
||||||
<h5 class="mb-3 mt-4">Activity and Diet Restrictions</h5>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="{{ form.activity_restrictions.id_for_label }}">Activity Restrictions</label>
|
|
||||||
{{ form.activity_restrictions }}
|
|
||||||
{% if form.activity_restrictions.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.activity_restrictions.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="{{ form.diet_restrictions.id_for_label }}">Diet Restrictions</label>
|
|
||||||
{{ form.diet_restrictions }}
|
|
||||||
{% if form.diet_restrictions.errors %}
|
|
||||||
<div class="invalid-feedback d-block">{{ form.diet_restrictions.errors.0 }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Additional Information -->
|
<!-- Medications and Instructions Section -->
|
||||||
<div class="row mb-3">
|
<div class="d-flex align-items-center mb-3">
|
||||||
<div class="col-md-6">
|
<i class="fa fa-pills fa-2x text-warning me-3"></i>
|
||||||
<div class="form-check">
|
<div>
|
||||||
{{ form.patient_education_provided }}
|
<h5 class="mb-1">{% trans "Medications and Instructions" %}</h5>
|
||||||
<label class="form-check-label" for="{{ form.patient_education_provided.id_for_label }}">
|
<small class="text-muted">Discharge medications and patient care instructions</small>
|
||||||
Patient education provided
|
</div>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-check">
|
|
||||||
{{ form.discharge_planning_completed }}
|
|
||||||
<label class="form-check-label" for="{{ form.discharge_planning_completed.id_for_label }}">
|
|
||||||
Discharge planning completed
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="row mb-4">
|
||||||
<label class="form-label" for="{{ form.notes.id_for_label }}">Additional Notes</label>
|
<div class="col-md-6">
|
||||||
{{ form.notes }}
|
<div class="bg-light p-3 rounded">
|
||||||
{% if form.notes.errors %}
|
<h6 class="text-warning mb-3"><i class="fa fa-prescription-bottle me-2"></i>{% trans "Medications" %}</h6>
|
||||||
<div class="invalid-feedback d-block">{{ form.notes.errors.0 }}</div>
|
<div class="mb-3">
|
||||||
{% endif %}
|
<label class="form-label fw-bold">{% trans "Discharge Medications (JSON list)" %}</label>
|
||||||
</div>
|
{{ form.discharge_medications }}
|
||||||
|
{% if form.discharge_medications.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.discharge_medications.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Medication Changes" %}</label>
|
||||||
|
{{ form.medication_changes }}
|
||||||
|
{% if form.medication_changes.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.medication_changes.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-success mb-3"><i class="fa fa-clipboard-check me-2"></i>{% trans "Patient Instructions" %}</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Activity Restrictions" %}</label>
|
||||||
|
{{ form.activity_restrictions }}
|
||||||
|
{% if form.activity_restrictions.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.activity_restrictions.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Diet Instructions" %}</label>
|
||||||
|
{{ form.diet_instructions }}
|
||||||
|
{% if form.diet_instructions.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.diet_instructions.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Wound Care" %}</label>
|
||||||
|
{{ form.wound_care }}
|
||||||
|
{% if form.wound_care.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.wound_care.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Special Instructions" %}</label>
|
||||||
|
{{ form.special_instructions }}
|
||||||
|
{% if form.special_instructions.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.special_instructions.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Form Actions -->
|
<hr>
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<a href="{% url 'inpatients:discharge_list' %}" class="btn btn-default">
|
|
||||||
<i class="fa fa-arrow-left me-2"></i>Cancel
|
|
||||||
</a>
|
|
||||||
<div>
|
|
||||||
<button type="submit" name="action" value="save_draft" class="btn btn-warning me-2">
|
|
||||||
<i class="fa fa-save me-2"></i>Save as Draft
|
|
||||||
</button>
|
|
||||||
<button type="submit" name="action" value="save" class="btn btn-success">
|
|
||||||
<i class="fa fa-check me-2"></i>{{ object|yesno:"Update,Complete" }} Discharge
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- END panel -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-4">
|
<!-- Follow-up and Disposition Section -->
|
||||||
<!-- BEGIN panel -->
|
<div class="d-flex align-items-center mb-3">
|
||||||
<div class="panel panel-inverse">
|
<i class="fa fa-calendar-check fa-2x text-primary me-3"></i>
|
||||||
<div class="panel-heading">
|
<div>
|
||||||
<h4 class="panel-title">Discharge Guidelines</h4>
|
<h5 class="mb-1">{% trans "Follow-up and Disposition" %}</h5>
|
||||||
<div class="panel-heading-btn">
|
<small class="text-muted">Post-discharge care and discharge destination</small>
|
||||||
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
</div>
|
||||||
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<h6><i class="fa fa-info-circle me-2"></i>Discharge Checklist</h6>
|
|
||||||
<ul class="mb-0">
|
|
||||||
<li>Patient is medically stable for discharge</li>
|
|
||||||
<li>All necessary medications prescribed</li>
|
|
||||||
<li>Follow-up appointments scheduled</li>
|
|
||||||
<li>Patient/family education completed</li>
|
|
||||||
<li>Transportation arranged</li>
|
|
||||||
<li>Discharge summary completed</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alert alert-warning">
|
<div class="row mb-4">
|
||||||
<h6><i class="fa fa-exclamation-triangle me-2"></i>Required Documentation</h6>
|
<div class="col-md-6">
|
||||||
<ul class="mb-0">
|
<div class="bg-light p-3 rounded">
|
||||||
<li>Discharge summary with diagnoses</li>
|
<h6 class="text-primary mb-3"><i class="fa fa-calendar-plus me-2"></i>{% trans "Follow-up Care" %}</h6>
|
||||||
<li>Medication reconciliation</li>
|
<div class="mb-3">
|
||||||
<li>Patient instruction sheet</li>
|
<label class="form-label fw-bold">{% trans "Follow-up Instructions" %}</label>
|
||||||
<li>Follow-up appointment details</li>
|
{{ form.follow_up_instructions }}
|
||||||
<li>Emergency contact information</li>
|
{% if form.follow_up_instructions.errors %}
|
||||||
</ul>
|
<div class="invalid-feedback d-block">{{ form.follow_up_instructions.errors }}</div>
|
||||||
</div>
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Follow-up Appointments (JSON list)" %}</label>
|
||||||
|
{{ form.follow_up_appointments }}
|
||||||
|
{% if form.follow_up_appointments.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.follow_up_appointments.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-danger mb-3"><i class="fa fa-exclamation-triangle me-2"></i>{% trans "Warning Signs" %}</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Warning Signs" %}</label>
|
||||||
|
{{ form.warning_signs }}
|
||||||
|
{% if form.warning_signs.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.warning_signs.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "When to Call" %}</label>
|
||||||
|
{{ form.when_to_call }}
|
||||||
|
{% if form.when_to_call.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.when_to_call.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-success">
|
<div class="row mb-4">
|
||||||
<h6><i class="fa fa-check-circle me-2"></i>Discharge Types</h6>
|
<div class="col-md-6">
|
||||||
<ul class="mb-0">
|
<div class="bg-light p-3 rounded">
|
||||||
<li><strong>Home:</strong> Patient returns to home environment</li>
|
<h6 class="text-secondary mb-3"><i class="fa fa-sign-out-alt me-2"></i>{% trans "Discharge Disposition" %}</h6>
|
||||||
<li><strong>Transfer:</strong> Transfer to another facility</li>
|
<div class="mb-3">
|
||||||
<li><strong>AMA:</strong> Against medical advice</li>
|
<label class="form-label fw-bold">{% trans "Discharge Disposition" %}</label>
|
||||||
<li><strong>Expired:</strong> Patient deceased during stay</li>
|
{{ form.discharge_disposition }}
|
||||||
</ul>
|
{% if form.discharge_disposition.errors %}
|
||||||
</div>
|
<div class="invalid-feedback d-block">{{ form.discharge_disposition.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Discharge Location" %}</label>
|
||||||
|
{{ form.discharge_location }}
|
||||||
|
{% if form.discharge_location.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.discharge_location.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-info mb-3"><i class="fa fa-box-open me-2"></i>{% trans "Equipment & Supplies" %}</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Durable Medical Equipment (JSON list)" %}</label>
|
||||||
|
{{ form.durable_medical_equipment }}
|
||||||
|
{% if form.durable_medical_equipment.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.durable_medical_equipment.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Supplies Provided (JSON list)" %}</label>
|
||||||
|
{{ form.supplies_provided }}
|
||||||
|
{% if form.supplies_provided.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.supplies_provided.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if object and object.admission %}
|
<hr>
|
||||||
<div class="alert alert-secondary">
|
|
||||||
<h6><i class="fa fa-user me-2"></i>Patient Information</h6>
|
|
||||||
<ul class="mb-0">
|
|
||||||
<li><strong>Patient:</strong> {{ object.admission.patient.get_full_name }}</li>
|
|
||||||
<li><strong>MRN:</strong> {{ object.admission.patient.medical_record_number }}</li>
|
|
||||||
<li><strong>Admission Date:</strong> {{ object.admission.admission_date|date:"M d, Y" }}</li>
|
|
||||||
<li><strong>Length of Stay:</strong> {{ object.admission.get_length_of_stay }} days</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- END panel -->
|
|
||||||
|
|
||||||
{% if object and object.admission %}
|
<!-- Additional Information Section -->
|
||||||
<!-- BEGIN panel -->
|
<div class="d-flex align-items-center mb-3">
|
||||||
<div class="panel panel-inverse">
|
<i class="fa fa-chart-bar fa-2x text-dark me-3"></i>
|
||||||
<div class="panel-heading">
|
<div>
|
||||||
<h4 class="panel-title">Admission Summary</h4>
|
<h5 class="mb-1">{% trans "Additional Information" %}</h5>
|
||||||
<div class="panel-heading-btn">
|
<small class="text-muted">Patient education and assessment data</small>
|
||||||
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
</div>
|
||||||
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="row mb-4">
|
||||||
<div class="panel-body">
|
<div class="col-md-6">
|
||||||
<div class="small">
|
<div class="bg-light p-3 rounded">
|
||||||
<div class="mb-2">
|
<h6 class="text-success mb-3"><i class="fa fa-graduation-cap me-2"></i>{% trans "Patient Education" %}</h6>
|
||||||
<strong>Admission Reason:</strong><br>
|
<div class="mb-3">
|
||||||
{{ object.admission.admission_reason|default:"Not specified" }}
|
<label class="form-label fw-bold">{% trans "Education Provided (JSON list)" %}</label>
|
||||||
</div>
|
{{ form.education_provided }}
|
||||||
|
{% if form.education_provided.errors %}
|
||||||
<div class="mb-2">
|
<div class="invalid-feedback d-block">{{ form.education_provided.errors }}</div>
|
||||||
<strong>Attending Physician:</strong><br>
|
{% endif %}
|
||||||
{{ object.admission.attending_physician.get_full_name|default:"Not assigned" }}
|
</div>
|
||||||
</div>
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Patient Understanding" %}</label>
|
||||||
<div class="mb-2">
|
{{ form.patient_understanding }}
|
||||||
<strong>Current Bed:</strong><br>
|
{% if form.patient_understanding.errors %}
|
||||||
{{ object.admission.bed|default:"Not assigned" }}
|
<div class="invalid-feedback d-block">{{ form.patient_understanding.errors }}</div>
|
||||||
</div>
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="mb-2">
|
</div>
|
||||||
<strong>Admission Type:</strong><br>
|
</div>
|
||||||
{{ object.admission.get_admission_type_display }}
|
<div class="col-md-6">
|
||||||
</div>
|
<div class="bg-light p-3 rounded">
|
||||||
|
<h6 class="text-warning mb-3"><i class="fa fa-chart-line me-2"></i>{% trans "Assessment & Satisfaction" %}</h6>
|
||||||
<div class="mb-2">
|
<div class="mb-3">
|
||||||
<strong>Insurance:</strong><br>
|
<label class="form-label fw-bold">{% trans "Readmission Risk" %}</label>
|
||||||
{{ object.admission.insurance_information|default:"Not provided" }}
|
{{ form.readmission_risk }}
|
||||||
</div>
|
{% if form.readmission_risk.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.readmission_risk.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">{% trans "Patient Satisfaction (1-10)" %}</label>
|
||||||
|
{{ form.patient_satisfaction }}
|
||||||
|
{% if form.patient_satisfaction.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ form.patient_satisfaction.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Form Actions -->
|
||||||
|
<div class="d-flex justify-content-end gap-2">
|
||||||
|
<button type="submit" class="btn btn-success btn-lg">
|
||||||
|
<i class="fa fa-save me-2"></i>{% trans "Save Discharge Summary" %}
|
||||||
|
</button>
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_list' %}" class="btn btn-outline-secondary btn-lg">
|
||||||
|
<i class="fa fa-times me-2"></i>{% trans "Cancel" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END panel -->
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script src="{% static 'assets/plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
||||||
<script src="{% static 'assets/plugins/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js' %}"></script>
|
|
||||||
<script src="{% static 'assets/plugins/bootstrap-timepicker/js/bootstrap-timepicker.min.js' %}"></script>
|
|
||||||
<script src="{% static 'assets/plugins/summernote/dist/summernote-lite.min.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
// Initialize Select2
|
|
||||||
$('.select2').select2({
|
|
||||||
theme: 'bootstrap-5',
|
|
||||||
width: '100%'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize date picker
|
|
||||||
$('input[type="date"]').datepicker({
|
|
||||||
format: 'yyyy-mm-dd',
|
|
||||||
autoclose: true,
|
|
||||||
todayHighlight: true,
|
|
||||||
endDate: new Date()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize time picker
|
|
||||||
$('input[type="time"]').timepicker({
|
|
||||||
showMeridian: false,
|
|
||||||
defaultTime: 'current'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize Summernote
|
|
||||||
$('.summernote').summernote({
|
|
||||||
height: 150,
|
|
||||||
toolbar: [
|
|
||||||
['style', ['style']],
|
|
||||||
['font', ['bold', 'italic', 'underline', 'clear']],
|
|
||||||
['para', ['ul', 'ol', 'paragraph']],
|
|
||||||
['insert', ['link']],
|
|
||||||
['view', ['fullscreen', 'codeview']]
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Form validation
|
|
||||||
$('#discharge-form').on('submit', function(e) {
|
|
||||||
var isValid = true;
|
|
||||||
var requiredFields = ['admission', 'discharge_type', 'discharge_date', 'discharge_time'];
|
|
||||||
|
|
||||||
requiredFields.forEach(function(field) {
|
|
||||||
var input = $('[name="' + field + '"]');
|
|
||||||
if (!input.val()) {
|
|
||||||
input.addClass('is-invalid');
|
|
||||||
isValid = false;
|
|
||||||
} else {
|
|
||||||
input.removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!isValid) {
|
|
||||||
e.preventDefault();
|
|
||||||
toastr.error('Please fill in all required fields.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Real-time validation
|
|
||||||
$('input, select, textarea').on('change blur', function() {
|
|
||||||
if ($(this).val()) {
|
|
||||||
$(this).removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load admission details when admission is selected
|
|
||||||
$('select[name="admission"]').on('change', function() {
|
|
||||||
var admissionId = $(this).val();
|
|
||||||
if (admissionId) {
|
|
||||||
$.ajax({
|
|
||||||
url: '{% url "inpatients:admission_detail_api" 0 %}'.replace('0', admissionId),
|
|
||||||
success: function(data) {
|
|
||||||
// Pre-fill attending physician if available
|
|
||||||
if (data.attending_physician) {
|
|
||||||
$('select[name="attending_physician"]').val(data.attending_physician).trigger('change');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show admission information
|
|
||||||
toastr.info('Admission details loaded: ' + data.patient_name);
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
toastr.warning('Could not load admission details');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Auto-populate current date and time
|
|
||||||
if (!$('input[name="discharge_date"]').val()) {
|
|
||||||
$('input[name="discharge_date"]').val(new Date().toISOString().split('T')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$('input[name="discharge_time"]').val()) {
|
|
||||||
var now = new Date();
|
|
||||||
var time = now.getHours().toString().padStart(2, '0') + ':' +
|
|
||||||
now.getMinutes().toString().padStart(2, '0');
|
|
||||||
$('input[name="discharge_time"]').val(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discharge type change handler
|
|
||||||
$('select[name="discharge_type"]').on('change', function() {
|
|
||||||
var dischargeType = $(this).val();
|
|
||||||
|
|
||||||
// Show/hide relevant fields based on discharge type
|
|
||||||
if (dischargeType === 'transfer') {
|
|
||||||
$('input[name="discharge_destination"]').closest('.col-md-6').show();
|
|
||||||
$('input[name="discharge_destination"]').attr('required', true);
|
|
||||||
} else if (dischargeType === 'ama') {
|
|
||||||
// Show warning for AMA discharge
|
|
||||||
if (!$('.ama-warning').length) {
|
|
||||||
$('<div class="alert alert-warning ama-warning mt-2">' +
|
|
||||||
'<strong>Against Medical Advice:</strong> Ensure proper documentation and patient acknowledgment.' +
|
|
||||||
'</div>').insertAfter($(this).closest('.col-md-6'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$('.ama-warning').remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|||||||
160
inpatients/templates/inpatients/discharges/discharge_list.html
Normal file
160
inpatients/templates/inpatients/discharges/discharge_list.html
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "Discharge Summaries" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<!-- BEGIN breadcrumb -->
|
||||||
|
<ol class="breadcrumb float-xl-end">
|
||||||
|
<li class="breadcrumb-item"><a href="javascript:;">Home</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="javascript:;">Inpatients</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="javascript:;">Discharges</a></li>
|
||||||
|
<li class="breadcrumb-item active">Discharge Summaries</li>
|
||||||
|
</ol>
|
||||||
|
<!-- END breadcrumb -->
|
||||||
|
<!-- BEGIN page-header -->
|
||||||
|
<h1 class="page-header">Discharge Summaries <small>List of all discharge summaries</small></h1>
|
||||||
|
<!-- END page-header -->
|
||||||
|
|
||||||
|
<!-- BEGIN row -->
|
||||||
|
<div class="row">
|
||||||
|
<!-- BEGIN col-12 -->
|
||||||
|
<div class="col-xl-12">
|
||||||
|
<!-- BEGIN panel -->
|
||||||
|
<div class="panel panel-inverse" data-sortable-id="discharge-summaries">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4 class="panel-title">Discharge Summaries</h4>
|
||||||
|
<div class="panel-heading-btn">
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_create' %}" class="btn btn-xs btn-icon btn-success me-1" title="Create New">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<!-- Search and Filters -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="search" class="form-control" placeholder="{% trans 'Search by patient name or diagnosis' %}" value="{{ search_query }}">
|
||||||
|
<button class="btn btn-outline-secondary" type="button">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<select name="completed" class="form-select">
|
||||||
|
<option value="">{% trans "All Status" %}</option>
|
||||||
|
<option value="true" {% if completed_filter == 'true' %}selected{% endif %}>{% trans "Completed" %}</option>
|
||||||
|
<option value="false" {% if completed_filter == 'false' %}selected{% endif %}>{% trans "Incomplete" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<input type="date" name="date_from" class="form-control" value="{{ date_from }}">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fa fa-filter me-1"></i>{% trans "Filter" %}
|
||||||
|
</button>
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_list' %}" class="btn btn-outline-secondary">
|
||||||
|
<i class="fa fa-times me-1"></i>{% trans "Clear" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-striped">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Patient" %}</th>
|
||||||
|
<th>{% trans "Discharge Date" %}</th>
|
||||||
|
<th>{% trans "Physician" %}</th>
|
||||||
|
<th>{% trans "Status" %}</th>
|
||||||
|
<th>{% trans "Actions" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for summary in discharge_summaries %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="me-3">
|
||||||
|
<i class="fa fa-user fa-2x text-primary"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_detail' summary.pk %}" class="fw-bold">
|
||||||
|
{{ summary.admission.patient.get_full_name }}
|
||||||
|
</a>
|
||||||
|
<br><small class="text-muted">{{ summary.admission.patient.mrn }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<i class="fa fa-calendar me-1"></i>{{ summary.discharge_date|date:"M d, Y" }}
|
||||||
|
<br><small class="text-muted">{{ summary.discharge_time|time:"g:i A" }}</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<i class="fa fa-user-md me-1"></i>{{ summary.discharging_physician.get_full_name }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if summary.summary_completed %}
|
||||||
|
<span class="badge bg-success">
|
||||||
|
<i class="fa fa-check me-1"></i>{% trans "Completed" %}
|
||||||
|
</span>
|
||||||
|
{% if summary.summary_signed %}
|
||||||
|
<br><span class="badge bg-info">
|
||||||
|
<i class="fa fa-signature me-1"></i>{% trans "Signed" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-warning">
|
||||||
|
<i class="fa fa-clock me-1"></i>{% trans "Incomplete" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_detail' summary.pk %}" class="btn btn-sm btn-info" title="{% trans 'View' %}">
|
||||||
|
<i class="fa fa-eye"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_update' summary.pk %}" class="btn btn-sm btn-warning" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'inpatients:discharge_summary_delete' summary.pk %}" class="btn btn-sm btn-danger" title="{% trans 'Delete' %}">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center py-4">
|
||||||
|
<i class="fa fa-inbox fa-3x text-muted mb-3"></i>
|
||||||
|
<h6 class="text-muted">{% trans "No discharge summaries found." %}</h6>
|
||||||
|
<p class="text-muted">{% trans "Try adjusting your search criteria or create a new discharge summary." %}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
{% if is_paginated %}
|
||||||
|
{% include 'partial/pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END panel -->
|
||||||
|
</div>
|
||||||
|
<!-- END col-12 -->
|
||||||
|
</div>
|
||||||
|
<!-- END row -->
|
||||||
|
{% endblock %}
|
||||||
File diff suppressed because it is too large
Load Diff
62
inpatients/templates/inpatients/partials/bed_history.html
Normal file
62
inpatients/templates/inpatients/partials/bed_history.html
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{% if admission_history %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Patient</th>
|
||||||
|
<th>Duration</th>
|
||||||
|
<th>Notes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for history in admission_history %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div>{{ history.admission_datetime|date:"M d, Y" }}</div>
|
||||||
|
<div class="small text-muted">{{ history.admission_datetime|time:"g:i A" }}</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-{% if history.action == 'ADMISSION' %}success{% elif history.action == 'DISCHARGE' %}info{% elif history.action == 'TRANSFER' %}warning{% else %}secondary{% endif %}">
|
||||||
|
{{ history.get_action_display }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if history.patient %}
|
||||||
|
<a href="{% url 'patients:patient_detail' history.patient.pk %}">
|
||||||
|
{{ history.patient.get_full_name }}
|
||||||
|
</a>
|
||||||
|
<div class="small text-muted">{{ history.patient.mrn }}</div>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">System action</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if history.duration %}
|
||||||
|
{{ history.duration }}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if history.notes %}
|
||||||
|
<span class="text-truncate" style="max-width: 200px;" title="{{ history.notes }}">
|
||||||
|
{{ history.notes }}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-center text-muted py-4">
|
||||||
|
<i class="fas fa-history fa-3x mb-3"></i>
|
||||||
|
<h5>No History Available</h5>
|
||||||
|
<p>No bed history records found for this bed.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
1224
inpatients/templates/temp
Normal file
1224
inpatients/templates/temp
Normal file
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,13 @@ urlpatterns = [
|
|||||||
path('discharge/<int:admission_id>/', views.discharge_patient, name='discharge_patient'),
|
path('discharge/<int:admission_id>/', views.discharge_patient, name='discharge_patient'),
|
||||||
# path('discharge/<int:admission_id>/summary/', views.discharge_summary, name='discharge_summary'),
|
# path('discharge/<int:admission_id>/summary/', views.discharge_summary, name='discharge_summary'),
|
||||||
|
|
||||||
|
# Discharge Summaries
|
||||||
|
path('discharges/', views.DischargeSummaryListView.as_view(), name='discharge_summary_list'),
|
||||||
|
path('discharges/<int:pk>/', views.DischargeSummaryDetailView.as_view(), name='discharge_summary_detail'),
|
||||||
|
path('discharges/create/', views.DischargeSummaryCreateView.as_view(), name='discharge_summary_create'),
|
||||||
|
path('discharges/<int:pk>/edit/', views.DischargeSummaryUpdateView.as_view(), name='discharge_summary_update'),
|
||||||
|
path('discharges/<int:pk>/delete/', views.DischargeSummaryDeleteView.as_view(), name='discharge_summary_delete'),
|
||||||
|
|
||||||
|
|
||||||
path('transfers/', views.TransferManagementView.as_view(), name='transfer_management'),
|
path('transfers/', views.TransferManagementView.as_view(), name='transfer_management'),
|
||||||
path('transfer/<int:admission_id>/', views.transfer_patient, name='transfer_patient'),
|
path('transfer/<int:admission_id>/', views.transfer_patient, name='transfer_patient'),
|
||||||
@ -48,8 +55,11 @@ urlpatterns = [
|
|||||||
path('beds/<int:pk>/unblock/', views.unblock_bed, name='unblock_bed'),
|
path('beds/<int:pk>/unblock/', views.unblock_bed, name='unblock_bed'),
|
||||||
path('beds/<int:pk>/maintenance/', views.maintenance_bed, name='maintenance_bed'),
|
path('beds/<int:pk>/maintenance/', views.maintenance_bed, name='maintenance_bed'),
|
||||||
path('beds/grid/', views.bed_grid, name='bed_grid'),
|
path('beds/grid/', views.bed_grid, name='bed_grid'),
|
||||||
path('beds/status/', views.bed_status_board, name='update_bed_status'),
|
path('beds/<int:bed_id>/status/', views.update_bed_status, name='update_bed_status'),
|
||||||
|
path('beds/<int:bed_id>/assign-patient/', views.assign_patient_to_bed, name='assign_patient_to_bed'),
|
||||||
|
path('beds/<int:bed_id>/utilization/', views.bed_utilization, name='bed_utilization'),
|
||||||
path('beds/<int:bed_id>/details/', views.bed_details, name='bed_details'),
|
path('beds/<int:bed_id>/details/', views.bed_details, name='bed_details'),
|
||||||
|
path('beds/<int:bed_id>/refresh-history/', views.refresh_bed_history, name='refresh_bed_history'),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -74,4 +84,3 @@ urlpatterns = [
|
|||||||
# API endpoints
|
# API endpoints
|
||||||
# path('api/', include('inpatients.api.urls')),
|
# path('api/', include('inpatients.api.urls')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
|
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
|
||||||
from django.http import JsonResponse, HttpResponse
|
from django.http import JsonResponse, HttpResponse
|
||||||
from django.db.models import Q, Count, Sum, F, ExpressionWrapper, fields
|
from django.db.models import Q, Count, Sum, F, ExpressionWrapper, fields, DurationField, Avg
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@ -435,6 +435,7 @@ class BedDetailView(LoginRequiredMixin, DetailView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
bed = self.get_object()
|
bed = self.get_object()
|
||||||
|
tenant = self.request.user.tenant
|
||||||
|
|
||||||
# Get bed history - admissions that used this bed
|
# Get bed history - admissions that used this bed
|
||||||
context['admission_history'] = Admission.objects.filter(
|
context['admission_history'] = Admission.objects.filter(
|
||||||
@ -442,8 +443,28 @@ class BedDetailView(LoginRequiredMixin, DetailView):
|
|||||||
'patient', 'admitting_physician',
|
'patient', 'admitting_physician',
|
||||||
).order_by('-admission_datetime')
|
).order_by('-admission_datetime')
|
||||||
|
|
||||||
|
# Get wards for transfer modal
|
||||||
|
context['wards'] = Ward.objects.filter(
|
||||||
|
tenant=tenant,
|
||||||
|
is_active=True
|
||||||
|
).exclude(pk=bed.ward.pk).order_by('name')
|
||||||
|
|
||||||
# context['maintenance_history'] = bed.maintenance_history.all().order_by('-scheduled_date')[:10]
|
# Bed stats
|
||||||
|
admissions = Admission.objects.filter(current_bed=bed)
|
||||||
|
total_admissions = admissions.count()
|
||||||
|
avg_stay_days = 0
|
||||||
|
if total_admissions > 0:
|
||||||
|
avg_duration = admissions.aggregate(avg_duration=Avg(ExpressionWrapper(F('discharge_datetime') - F('admission_datetime'), output_field=DurationField())))['avg_duration']
|
||||||
|
avg_stay_days = avg_duration.total_seconds() / 86400 if avg_duration else 0
|
||||||
|
|
||||||
|
context['bed_stats'] = {
|
||||||
|
'occupancy_rate': 0, # Placeholder - would need more complex calculation
|
||||||
|
'total_admissions': total_admissions,
|
||||||
|
'avg_stay_days': avg_stay_days,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Placeholder for maintenance schedule
|
||||||
|
context['maintenance_schedule'] = []
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -1593,9 +1614,169 @@ def bed_details(request, bed_id):
|
|||||||
tenant = request.user.tenant
|
tenant = request.user.tenant
|
||||||
bed = get_object_or_404(Bed, ward__tenant=tenant,id=bed_id)
|
bed = get_object_or_404(Bed, ward__tenant=tenant,id=bed_id)
|
||||||
|
|
||||||
|
# Bed stats
|
||||||
|
admissions = Admission.objects.filter(current_bed=bed)
|
||||||
|
total_admissions = admissions.count()
|
||||||
|
avg_stay_days = 0
|
||||||
|
if total_admissions > 0:
|
||||||
|
avg_duration = admissions.aggregate(avg_duration=Avg(ExpressionWrapper(F('discharge_datetime') - F('admission_datetime'), output_field=DurationField())))['avg_duration']
|
||||||
|
avg_stay_days = avg_duration.total_seconds() / 86400 if avg_duration else 0
|
||||||
|
|
||||||
|
context['bed_stats'] = {
|
||||||
|
'occupancy_rate': bed.occupancy_rate if hasattr(bed, 'occupancy_rate') else 0,
|
||||||
|
'total_admissions': total_admissions,
|
||||||
|
'avg_stay_days': avg_stay_days,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Placeholder for maintenance schedule
|
||||||
|
context['maintenance_schedule'] = []
|
||||||
|
|
||||||
return render(request, 'inpatients/partials/bed_details.html', {'object':bed})
|
return render(request, 'inpatients/partials/bed_details.html', {'object':bed})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def refresh_bed_history(request, bed_id):
|
||||||
|
"""
|
||||||
|
HTMX endpoint to refresh bed history.
|
||||||
|
"""
|
||||||
|
bed = get_object_or_404(Bed, id=bed_id, ward__tenant=request.user.tenant)
|
||||||
|
|
||||||
|
# Get bed history - admissions that used this bed
|
||||||
|
admission_history = Admission.objects.filter(
|
||||||
|
current_bed=bed
|
||||||
|
).select_related(
|
||||||
|
'patient', 'admitting_physician',
|
||||||
|
).order_by('-admission_datetime')
|
||||||
|
|
||||||
|
return render(request, 'inpatients/partials/bed_history.html', {
|
||||||
|
'admission_history': admission_history
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def assign_patient_to_bed(request, bed_id):
|
||||||
|
"""
|
||||||
|
View to assign a patient to a bed.
|
||||||
|
"""
|
||||||
|
bed = get_object_or_404(Bed, id=bed_id, ward__tenant=request.user.tenant)
|
||||||
|
if request.method == 'POST':
|
||||||
|
patient_id = request.POST.get('patient_id')
|
||||||
|
if patient_id:
|
||||||
|
patient = get_object_or_404(PatientProfile, id=patient_id, tenant=request.user.tenant)
|
||||||
|
bed.current_patient = patient
|
||||||
|
bed.status = 'OCCUPIED'
|
||||||
|
bed.occupied_since = timezone.now()
|
||||||
|
bed.save()
|
||||||
|
messages.success(request, 'Patient assigned to bed successfully.')
|
||||||
|
return redirect('inpatients:bed_detail', pk=bed.pk)
|
||||||
|
# GET: show form with patient search
|
||||||
|
patients = PatientProfile.objects.filter(tenant=request.user.tenant).order_by('-created_at')[:20]
|
||||||
|
return render(request, 'inpatients/assign_patient.html', {'bed': bed, 'patients': patients})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def bed_utilization(request, bed_id):
|
||||||
|
"""
|
||||||
|
View for bed utilization chart data.
|
||||||
|
"""
|
||||||
|
bed = get_object_or_404(Bed, id=bed_id, ward__tenant=request.user.tenant)
|
||||||
|
|
||||||
|
# Generate last 30 days of data
|
||||||
|
end_date = timezone.now().date()
|
||||||
|
start_date = end_date - timedelta(days=29)
|
||||||
|
|
||||||
|
labels = []
|
||||||
|
data_points = []
|
||||||
|
|
||||||
|
current_date = start_date
|
||||||
|
while current_date <= end_date:
|
||||||
|
labels.append(current_date.strftime('%b %d'))
|
||||||
|
|
||||||
|
# Calculate occupancy for this date
|
||||||
|
# This is a simplified calculation - in a real system you'd track historical occupancy
|
||||||
|
# For now, we'll use a random-ish calculation based on bed admissions
|
||||||
|
admissions_on_date = Admission.objects.filter(
|
||||||
|
current_bed=bed,
|
||||||
|
admission_datetime__date=current_date
|
||||||
|
).count()
|
||||||
|
|
||||||
|
# Simple heuristic: if there were admissions, assume some occupancy
|
||||||
|
occupancy_rate = min(admissions_on_date * 20 + 30, 100) # Cap at 100%
|
||||||
|
data_points.append(occupancy_rate)
|
||||||
|
|
||||||
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'labels': labels,
|
||||||
|
'data': data_points
|
||||||
|
}
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def update_bed_status(request, bed_id):
|
||||||
|
"""
|
||||||
|
View to update bed status.
|
||||||
|
"""
|
||||||
|
bed = get_object_or_404(Bed, id=bed_id, ward__tenant=request.user.tenant)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
new_status = request.POST.get('status')
|
||||||
|
notes = request.POST.get('notes', '')
|
||||||
|
|
||||||
|
if new_status and new_status in dict(Bed.BedStatus.choices):
|
||||||
|
old_status = bed.status
|
||||||
|
bed.status = new_status
|
||||||
|
|
||||||
|
# Handle special cases
|
||||||
|
if new_status == 'AVAILABLE' and old_status == 'CLEANING':
|
||||||
|
bed.last_cleaned = timezone.now()
|
||||||
|
bed.cleaned_by = request.user
|
||||||
|
elif new_status == 'MAINTENANCE':
|
||||||
|
bed.last_maintenance = timezone.now()
|
||||||
|
|
||||||
|
if notes:
|
||||||
|
bed.notes = notes
|
||||||
|
|
||||||
|
bed.save()
|
||||||
|
|
||||||
|
# Log the action
|
||||||
|
AuditLogger.log_event(
|
||||||
|
actor=request.user,
|
||||||
|
action='BED_STATUS_UPDATED',
|
||||||
|
target=bed,
|
||||||
|
target_repr=str(bed),
|
||||||
|
description=f"Bed status updated from {dict(Bed.BedStatus.choices)[old_status]} to {dict(Bed.BedStatus.choices)[new_status]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
messages.success(request, f"Bed status updated to {bed.get_status_display()}")
|
||||||
|
else:
|
||||||
|
messages.error(request, "Invalid bed status")
|
||||||
|
|
||||||
|
return redirect('inpatients:bed_detail', pk=bed.pk)
|
||||||
|
|
||||||
|
return redirect('inpatients:bed_detail', pk=bed.pk)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def refresh_bed_history(request, bed_id):
|
||||||
|
"""
|
||||||
|
HTMX endpoint to refresh bed history.
|
||||||
|
"""
|
||||||
|
bed = get_object_or_404(Bed, id=bed_id, ward__tenant=request.user.tenant)
|
||||||
|
|
||||||
|
# Get bed history - admissions that used this bed
|
||||||
|
admission_history = Admission.objects.filter(
|
||||||
|
current_bed=bed
|
||||||
|
).select_related(
|
||||||
|
'patient', 'admitting_physician',
|
||||||
|
).order_by('-admission_datetime')
|
||||||
|
|
||||||
|
return render(request, 'inpatients/partials/bed_history.html', {
|
||||||
|
'admission_history': admission_history
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def clean_bed(request, pk):
|
def clean_bed(request, pk):
|
||||||
"""
|
"""
|
||||||
@ -2337,6 +2518,149 @@ class AdmissionDetailView(LoginRequiredMixin, DetailView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DischargeSummaryListView(LoginRequiredMixin, ListView):
|
||||||
|
"""
|
||||||
|
List view for discharge summaries.
|
||||||
|
"""
|
||||||
|
model = DischargeSummary
|
||||||
|
template_name = 'inpatients/discharges/discharge_list.html'
|
||||||
|
context_object_name = 'discharge_summaries'
|
||||||
|
paginate_by = 20
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
"""Filter discharge summaries by tenant and search query."""
|
||||||
|
queryset = DischargeSummary.objects.filter(
|
||||||
|
admission__tenant=self.request.user.tenant
|
||||||
|
).select_related(
|
||||||
|
'admission', 'admission__patient', 'discharging_physician'
|
||||||
|
).order_by('-discharge_date')
|
||||||
|
|
||||||
|
# Handle search query
|
||||||
|
search_query = self.request.GET.get('search', '')
|
||||||
|
if search_query:
|
||||||
|
queryset = queryset.filter(
|
||||||
|
Q(admission__patient__first_name__icontains=search_query) |
|
||||||
|
Q(admission__patient__last_name__icontains=search_query) |
|
||||||
|
Q(admission__patient__mrn__icontains=search_query) |
|
||||||
|
Q(admission_diagnosis__icontains=search_query) |
|
||||||
|
Q(final_diagnosis__icontains=search_query)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Handle filter by status (e.g., completed)
|
||||||
|
completed = self.request.GET.get('completed', '')
|
||||||
|
if completed == 'true':
|
||||||
|
queryset = queryset.filter(summary_completed=True)
|
||||||
|
elif completed == 'false':
|
||||||
|
queryset = queryset.filter(summary_completed=False)
|
||||||
|
|
||||||
|
# Handle filter by date range
|
||||||
|
date_from = self.request.GET.get('date_from', '')
|
||||||
|
if date_from:
|
||||||
|
queryset = queryset.filter(discharge_date__gte=date_from)
|
||||||
|
|
||||||
|
date_to = self.request.GET.get('date_to', '')
|
||||||
|
if date_to:
|
||||||
|
queryset = queryset.filter(discharge_date__lte=date_to)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context.update({
|
||||||
|
'search_query': self.request.GET.get('search', ''),
|
||||||
|
'completed_filter': self.request.GET.get('completed', ''),
|
||||||
|
'date_from': self.request.GET.get('date_from', ''),
|
||||||
|
'date_to': self.request.GET.get('date_to', ''),
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DischargeSummaryDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
"""
|
||||||
|
Detail view for a discharge summary.
|
||||||
|
"""
|
||||||
|
model = DischargeSummary
|
||||||
|
template_name = 'inpatients/discharges/discharge_detail.html'
|
||||||
|
context_object_name = 'discharge_summary'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
"""Filter discharge summaries by tenant."""
|
||||||
|
return DischargeSummary.objects.filter(
|
||||||
|
admission__tenant=self.request.user.tenant
|
||||||
|
).select_related(
|
||||||
|
'admission', 'admission__patient', 'discharging_physician', 'primary_nurse'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DischargeSummaryCreateView(LoginRequiredMixin, CreateView):
|
||||||
|
"""
|
||||||
|
Create view for a discharge summary.
|
||||||
|
"""
|
||||||
|
model = DischargeSummary
|
||||||
|
form_class = DischargeSummaryForm
|
||||||
|
template_name = 'inpatients/discharges/discharge_form.html'
|
||||||
|
permission_required = 'inpatients.add_dischargesummary' # Assuming permission exists
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super().get_form_kwargs()
|
||||||
|
kwargs['user'] = self.request.user
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.created_by = self.request.user
|
||||||
|
messages.success(self.request, 'Discharge summary created successfully')
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('inpatients:discharge_summary_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class DischargeSummaryUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
|
"""
|
||||||
|
Update view for a discharge summary.
|
||||||
|
"""
|
||||||
|
model = DischargeSummary
|
||||||
|
form_class = DischargeSummaryForm
|
||||||
|
template_name = 'inpatients/discharges/discharge_form.html'
|
||||||
|
permission_required = 'inpatients.change_dischargesummary'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
"""Filter discharge summaries by tenant."""
|
||||||
|
return DischargeSummary.objects.filter(admission__tenant=self.request.user.tenant)
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super().get_form_kwargs()
|
||||||
|
kwargs['user'] = self.request.user
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
messages.success(self.request, 'Discharge summary updated successfully')
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse('inpatients:discharge_summary_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class DischargeSummaryDeleteView(LoginRequiredMixin, DeleteView):
|
||||||
|
"""
|
||||||
|
Delete view for a discharge summary.
|
||||||
|
"""
|
||||||
|
model = DischargeSummary
|
||||||
|
template_name = 'inpatients/discharges/discharge_confirm_delete.html'
|
||||||
|
permission_required = 'inpatients.delete_dischargesummary'
|
||||||
|
success_url = reverse_lazy('inpatients:discharge_summary_list')
|
||||||
|
context_object_name = 'discharge_summary'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
"""Filter discharge summaries by tenant."""
|
||||||
|
return DischargeSummary.objects.filter(admission__tenant=self.request.user.tenant)
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
summary = self.get_object()
|
||||||
|
messages.success(request, 'Discharge summary deleted successfully')
|
||||||
|
return super().delete(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
54026
media/docs/2024-17021.pdf
Normal file
54026
media/docs/2024-17021.pdf
Normal file
File diff suppressed because one or more lines are too long
209
prd_hospital_management_system_v4.md
Normal file
209
prd_hospital_management_system_v4.md
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# Product Requirements Document (PRD): Hospital Management System v4
|
||||||
|
|
||||||
|
## 1. Introduction
|
||||||
|
|
||||||
|
### 1.1 Purpose
|
||||||
|
This PRD documents the current state of the Hospital Management System (HMS) v4, a comprehensive Django-based web application designed to manage hospital operations. The system supports multi-tenant environments, integrates healthcare standards (e.g., ICD-10 codes, SBS billing), and covers key domains such as patient care, administrative functions, financial billing, and facility operations. It facilitates efficient workflows for healthcare providers, administrators, and support staff.
|
||||||
|
|
||||||
|
### 1.2 Scope
|
||||||
|
The system is modular, with Django apps handling specific functionalities. Core features include patient registration, appointment scheduling, electronic medical records (EMR), inpatient management, laboratory and radiology services, pharmacy, billing, HR, inventory, blood bank, operating theatre, quality assurance, communications, analytics, and facility management. Data generation scripts (e.g., `hr_data.py`, `inpatients_data.py`) and compliance documents (e.g., ICD-10 XML files, SBS code lists) indicate support for testing and regulatory adherence.
|
||||||
|
|
||||||
|
### 1.3 Target Users
|
||||||
|
- **Clinical Staff**: Doctors, nurses (EMR, appointments, inpatients, lab/radiology/pharmacy).
|
||||||
|
- **Administrative Staff**: Receptionists, admins (patient profiles, billing, HR, inventory).
|
||||||
|
- **Management**: Executives (analytics, quality, facility management).
|
||||||
|
- **Support**: IT (integrations, core system config).
|
||||||
|
|
||||||
|
### 1.4 Assumptions and Dependencies
|
||||||
|
- Built on Django with PostgreSQL/SQLite (evident from `db.sqlite3` and migrations).
|
||||||
|
- Uses external libraries (e.g., via `requirements.txt`, `uv.lock`).
|
||||||
|
- Multi-tenant via `core.models.Tenant`.
|
||||||
|
- Compliance with Saudi health standards (SBS V2, ICD-10).
|
||||||
|
|
||||||
|
## 2. System Architecture
|
||||||
|
|
||||||
|
### 2.1 High-Level Overview
|
||||||
|
- **Framework**: Django (MVC pattern) with apps for modularity.
|
||||||
|
- **Database**: Relational (models use Django ORM); supports audit logging (`core.models.AuditLogEntry`).
|
||||||
|
- **Frontend**: Django templates (e.g., dashboards for HR/inpatients, lists for assets/maintenance).
|
||||||
|
- **Backend**: Views and forms for CRUD operations; API endpoints in most apps (e.g., `accounts/api/`).
|
||||||
|
- **Integrations**: External systems via `integration` app (endpoints, webhooks, logs).
|
||||||
|
- **Security**: Two-factor auth, password history (`accounts`); consents (`patients`).
|
||||||
|
- **File Structure**: Root-level data scripts, Django project (`hospital_management`), apps with models/views/templates/migrations.
|
||||||
|
|
||||||
|
### 2.2 Key Technologies
|
||||||
|
- Python/Django.
|
||||||
|
- Templates: HTML with partials (e.g., bed details, transfer forms).
|
||||||
|
- Standards: ICD-10 (`emr.models.Icd10`), SBS billing (`billing`).
|
||||||
|
|
||||||
|
## 3. Features
|
||||||
|
|
||||||
|
The system implements a wide range of hospital workflows. Below is a breakdown by module.
|
||||||
|
|
||||||
|
### 3.1 Core System (`core`)
|
||||||
|
- Tenant management for multi-hospital support.
|
||||||
|
- System configurations, notifications, audit logs.
|
||||||
|
- Middleware and context processors for global functionality.
|
||||||
|
|
||||||
|
### 3.2 User Accounts and Authentication (`accounts`)
|
||||||
|
- User sessions, social accounts, two-factor devices.
|
||||||
|
- Password history for security compliance.
|
||||||
|
|
||||||
|
### 3.3 Patient Management (`patients`)
|
||||||
|
- Patient profiles with emergency contacts.
|
||||||
|
- Insurance info, claims (with documents, status history).
|
||||||
|
- Consent templates and forms.
|
||||||
|
- Patient notes for documentation.
|
||||||
|
|
||||||
|
### 3.4 Appointments (`appointments`)
|
||||||
|
- Appointment requests and slot availability.
|
||||||
|
- Waiting queues and lists with contact logs.
|
||||||
|
- Telemedicine sessions.
|
||||||
|
- Templates for recurring schedules.
|
||||||
|
|
||||||
|
### 3.5 Electronic Medical Records (EMR) (`emr`)
|
||||||
|
- Encounters linking to patient visits.
|
||||||
|
- Vital signs tracking.
|
||||||
|
- Problem lists, care plans, clinical notes (with templates).
|
||||||
|
- ICD-10 code integration for diagnoses.
|
||||||
|
|
||||||
|
### 3.6 Inpatient Management (`inpatients`)
|
||||||
|
- Wards and bed management (status updates).
|
||||||
|
- Admissions, discharge summaries.
|
||||||
|
- Patient transfers.
|
||||||
|
- Surgery schedules.
|
||||||
|
|
||||||
|
UI: Dashboards, ward/bed lists/details, transfer forms/management (from open tabs).
|
||||||
|
|
||||||
|
### 3.7 Laboratory (`laboratory`)
|
||||||
|
- Lab tests, orders, specimens.
|
||||||
|
- Results with quality control and reference ranges.
|
||||||
|
|
||||||
|
### 3.8 Radiology (`radiology`)
|
||||||
|
- Imaging studies, series, DICOM images.
|
||||||
|
- Reports with templates.
|
||||||
|
- Orders for procedures.
|
||||||
|
|
||||||
|
### 3.9 Pharmacy (`pharmacy`)
|
||||||
|
- Medication catalog with interactions.
|
||||||
|
- Prescriptions, inventory items, dispense records.
|
||||||
|
- Administration tracking.
|
||||||
|
|
||||||
|
### 3.10 Operating Theatre (`operating_theatre`)
|
||||||
|
- Operating rooms and block scheduling.
|
||||||
|
- Surgical cases, notes (with templates), equipment usage.
|
||||||
|
|
||||||
|
### 3.11 Blood Bank (`blood_bank`)
|
||||||
|
- Blood groups, donors, components, units.
|
||||||
|
- Testing (cross-match, infectious diseases).
|
||||||
|
- Requests, issues, transfusions, adverse reactions.
|
||||||
|
- Inventory locations and quality control.
|
||||||
|
|
||||||
|
### 3.12 Billing (`billing`)
|
||||||
|
- Medical bills with line items.
|
||||||
|
- Insurance claims, payments, status updates.
|
||||||
|
- Billing configurations for SBS compliance.
|
||||||
|
|
||||||
|
### 3.13 Human Resources (HR) (`hr`)
|
||||||
|
- Employee profiles, departments.
|
||||||
|
- Schedules, assignments, time entries.
|
||||||
|
- Performance reviews.
|
||||||
|
- Training programs (modules, prerequisites, sessions, records, attendance, assessments, certificates).
|
||||||
|
|
||||||
|
UI: HR dashboard (from open tabs).
|
||||||
|
|
||||||
|
### 3.14 Inventory (`inventory`)
|
||||||
|
- Items, stock levels, locations.
|
||||||
|
- Purchase orders, suppliers.
|
||||||
|
|
||||||
|
### 3.15 Facility Management (`facility_management`)
|
||||||
|
- Buildings, floors, rooms.
|
||||||
|
- Assets (categories), maintenance (requests, schedules, types).
|
||||||
|
- Vendors, service contracts, inspections.
|
||||||
|
- Energy meters/readings, space reservations.
|
||||||
|
|
||||||
|
UI: Asset/maintenance lists (from open tabs).
|
||||||
|
|
||||||
|
### 3.16 Quality Assurance (`quality`)
|
||||||
|
- Quality indicators and measurements.
|
||||||
|
- Incident reports, risk assessments.
|
||||||
|
- Audit plans/findings.
|
||||||
|
- Improvement projects.
|
||||||
|
|
||||||
|
### 3.17 Communications (`communications`)
|
||||||
|
- Messages and recipients.
|
||||||
|
- Notification templates, alert rules/instances.
|
||||||
|
- Channels and delivery logs.
|
||||||
|
|
||||||
|
### 3.18 Analytics (`analytics`)
|
||||||
|
- Dashboards with widgets.
|
||||||
|
- Data sources, reports, executions.
|
||||||
|
- Metric definitions and values.
|
||||||
|
|
||||||
|
### 3.19 Integrations (`integration`)
|
||||||
|
- External systems, endpoints, data mappings.
|
||||||
|
- Execution logs, webhooks.
|
||||||
|
|
||||||
|
## 4. Data Model
|
||||||
|
|
||||||
|
The system uses Django models for relational data. Key entities (from 144+ models):
|
||||||
|
|
||||||
|
- **Patients/Encounters**: `PatientProfile`, `Encounter`, `VitalSigns`, `ProblemList`, `CarePlan`.
|
||||||
|
- **Clinical Data**: `ClinicalNote`, `Icd10`, `LabResult`, `ImagingStudy`, `Prescription`, `MedicationAdministration`.
|
||||||
|
- **Administrative**: `Employee`, `Department`, `AppointmentRequest`, `MedicalBill`, `InsuranceClaim`.
|
||||||
|
- **Operational**: `Ward`, `Bed`, `Admission`, `Transfer`, `SurgicalCase`, `BloodUnit`, `InventoryItem`, `Asset`, `MaintenanceRequest`.
|
||||||
|
- **Support**: `AuditLogEntry`, `SystemConfiguration`, `QualityIndicator`, `IncidentReport`.
|
||||||
|
- Relationships: Foreign keys link entities (e.g., `Admission` to `PatientProfile`, `LabOrder` to `Encounter`). Choices (e.g., `TrainingType`) and many-to-many (e.g., schedules).
|
||||||
|
|
||||||
|
Data integrity via signals (e.g., `accounts/signals.py`, `facility_management/signals.py`). Migrations ensure schema evolution.
|
||||||
|
|
||||||
|
## 5. User Interface and Experience
|
||||||
|
|
||||||
|
- **Dashboards**: Centralized views (e.g., inpatients dashboard, HR dashboard).
|
||||||
|
- **Lists and Details**: Paginated lists (wards, beds, assets, maintenance); detail views with partials (bed details, update forms).
|
||||||
|
- **Forms**: Interactive (e.g., transfer forms, bed status updates).
|
||||||
|
- **Templates**: Modular (e.g., `inpatients/templates/inpatients/partials/` for reusable components).
|
||||||
|
- Responsive design inferred from Django templates; no explicit JS frameworks noted.
|
||||||
|
|
||||||
|
Open tabs indicate focus on inpatient workflows (wards, beds, transfers) and HR/facility management.
|
||||||
|
|
||||||
|
## 6. Non-Functional Requirements
|
||||||
|
|
||||||
|
### 6.1 Security
|
||||||
|
- Authentication: Sessions, 2FA, social login.
|
||||||
|
- Auditing: Logs for all actions.
|
||||||
|
- Consents: Managed forms.
|
||||||
|
|
||||||
|
### 6.2 Performance
|
||||||
|
- Analytics for metrics; scalable via Django ORM.
|
||||||
|
- Inventory/quality control for real-time tracking.
|
||||||
|
|
||||||
|
### 6.3 Compliance
|
||||||
|
- ICD-10 for diagnoses (`emr`).
|
||||||
|
- SBS V2 for billing (`billing`).
|
||||||
|
- Quality indicators for accreditation.
|
||||||
|
|
||||||
|
### 6.4 Testing and Data
|
||||||
|
- Test files in apps (e.g., `tests.py`).
|
||||||
|
- Data generators (e.g., `patients_data.py`) for population.
|
||||||
|
|
||||||
|
## 7. Current Status and Gaps
|
||||||
|
|
||||||
|
### 7.1 Implemented
|
||||||
|
- Full CRUD for core entities.
|
||||||
|
- Web UI for key modules (inpatients, HR, facility).
|
||||||
|
- Backend APIs and integrations ready.
|
||||||
|
|
||||||
|
### 7.2 Potential Gaps
|
||||||
|
- No explicit mobile/responsive UI details.
|
||||||
|
- Advanced features (e.g., AI analytics) not evident.
|
||||||
|
- Full end-to-end testing coverage unknown.
|
||||||
|
- Deployment config (e.g., ASGI in `hospital_management/asgi.py`).
|
||||||
|
|
||||||
|
### 7.3 Next Steps Recommendations
|
||||||
|
- Implement user roles/permissions.
|
||||||
|
- Add real-time features (e.g., WebSockets for notifications).
|
||||||
|
- Integrate with external APIs (e.g., via `integration`).
|
||||||
|
- Conduct security audits and performance testing.
|
||||||
|
|
||||||
|
This PRD is based on the codebase analysis as of 9/21/2025. Total models: 144+, indicating a mature, feature-rich system.
|
||||||
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
BIN
static/plugins/.DS_Store
vendored
BIN
static/plugins/.DS_Store
vendored
Binary file not shown.
BIN
static/plugins/ionicons/.DS_Store
vendored
Normal file
BIN
static/plugins/ionicons/.DS_Store
vendored
Normal file
Binary file not shown.
62
system_prompt.md
Normal file
62
system_prompt.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
Agent Instructions — Complete & Finish Hospital Management System v4
|
||||||
|
You are a senior Django architect + full-stack developer and your job is to finish the partially-completed `hospital_management` codebase so it fully matches the provided PRD (Hospital Management System v4). This is mission-critical: do **not** dump all code at once. Follow a strict phased plan-and-approve workflow so I can verify each step and reduce hallucination.
|
||||||
|
|
||||||
|
BEFORE YOU START: you must compare the "current prompt / implemented spec" (the system you already produced) with the PRD attached by the user and produce a short gap analysis (a list of missing features, mismatches, and priority items). Show the gap analysis first and pause for my confirmation. Do not implement anything until I confirm the gap analysis.
|
||||||
|
|
||||||
|
PHASES (high level)
|
||||||
|
1) Gap Analysis (required) — produce a structured list of missing modules, missing fields, missing integrations, missing non-functional items (ASGI/websockets, mobile/responsive, AI analytics hooks, tests, CI, deployment configs), and any commented JS functions in templates that appear unimplemented. Pause.
|
||||||
|
2) Discovery & Repo Scan — when I approve the gap analysis, scan the repo (templates, apps, static assets, migrations) and produce an inventory: list of apps, list of templates that contain commented JS functions (with file path + exact commented code snippet), list of endpoints/views that exist vs. required by the PRD, list of missing migrations, and test coverage gaps. Pause.
|
||||||
|
3) Per-App Scoping & Approval — for each app I approve (one at a time), produce a complete scope: models (full fields + choices), serializers/forms, views (UI + HTMX endpoints + API), templates/partials, static asset list (SASS partials), Celery tasks, HL7/DICOM/PACS hooks, WebSocket events (if relevant), tests (unit + integration). Pause and wait for “👍 go ahead with [app_name]”.
|
||||||
|
4) Implementation (per app, incremental) — after approval for an app, implement only that app’s deliverables in this order: models.py → pause → serializers/forms & admin → pause → views + templates + HTMX snippets + JS modules (if genuinely needed) → pause → tests (pytest) → pause → migrations & fixture seeds → pause. Each pause is a hard stop for my review.
|
||||||
|
5) Shared Tooling & Final Integration (last phase) — Webpack/asset pipeline, HTMX guidelines, ASGI + Channels setup for WebSockets, Celery + Redis, HL7 + PACS interfaces, DRF docs, pytest + coverage, GitHub Actions CI, deployment (Gunicorn+Nginx + ASGI workers, multi-tenant notes), GDPR/HIPAA checklist, monitoring, backups, and runbook. Pause for final signoff.
|
||||||
|
|
||||||
|
MANDATORY RULES FOR THE AGENT
|
||||||
|
- Always pause after the Gap Analysis and after each deliverable chunk listed above and wait for explicit approval before continuing. Use the exact pause phrasing: “**Paused — awaiting approval: [description]**”.
|
||||||
|
- NEVER leave CSS or JS scattered in templates. All styles must be SCSS partials under `static/css/` and JS modules (if required) under `static/js/`. Templates must only include bundle loaders (e.g., `{% render_bundle 'main' 'css' %}`, `{% render_bundle 'main' 'js' %}`) or HTMX attributes.
|
||||||
|
- HTMX is the preferred mechanism for dynamic interactions. Use small unobtrusive JS only when HTMX cannot provide the functionality (charting libraries are acceptable).
|
||||||
|
- For any UI interaction previously implemented with commented JavaScript functions inside templates: you must:
|
||||||
|
1. List every template file that contains commented JS functions (file path + exact commented function body).
|
||||||
|
2. For each such function decide whether it should be replaced with an HTMX endpoint, a Django view (returning partial HTML), or a small JS module imported via Webpack. Prefer HTMX where possible.
|
||||||
|
3. Implement the change: uncomment the function (or replace it), create the correct server side view / DRF endpoint / HTMX fragment, wire the template (remove inline script if replaced by HTMX), and add tests that validate both the front-end interaction (via a simple integration test using Django's test client or HTMX-compatible request) and the server behavior.
|
||||||
|
4. Add a comment in the template referencing the view name and test id.
|
||||||
|
**Do not** leave any commented JS functions in templates after your work—either remove them or make them active and covered by tests.
|
||||||
|
- Provide a traceability matrix that maps every PRD item to the exact file(s) and tests that implement it (e.g., PRD §3.6 → `inpatients/models.py:Admission`, `inpatients/views.py:AdmissionUpdateView`, `tests/inpatients/test_admission_flow.py`). This matrix must be updated as you implement items.
|
||||||
|
- Add or update migrations and provide `./manage.py migrate` run notes (including any data migrations) in the README.
|
||||||
|
- Add pytest tests for each implemented feature (models, views, HTMX flows, integrations). Target at least 85% coverage for newly implemented modules; report coverage per app.
|
||||||
|
- For integrations (HL7, PACS/DICOM, external APIs listed in PRD e.g., BestCare, Cerner, Epic): provide concrete adapter stubs with config examples and tests that simulate inbound/outbound messages. Use environment variables for credentials; do not hardcode secrets.
|
||||||
|
|
||||||
|
PRIORITY ITEMS (must be in the Gap Analysis and implemented first once approved)
|
||||||
|
- WebSockets/real-time notifications (ASGI + Channels) for: waiting queue updates, bed status, telemedicine session start, OR schedule changes, ambulance dispatch updates.
|
||||||
|
- Mobile/responsive work: ensure core templates are responsive and provide a mobile view for patient portal and clinician quick-actions.
|
||||||
|
- AI analytics hooks and a sample risk-scoring job integrated into `decision_support` (a stub that runs over recent encounters and emits alerts into `AlertLog`).
|
||||||
|
- Blood Bank app completeness (blood units, cross-match, transfusions) if missing.
|
||||||
|
- Full HL7 v2.x inbound/outbound wiring and a PACS adapter for DICOMStudy ingestion (stubs with tests).
|
||||||
|
- Ensure multi-tenant isolation is consistently applied (Tenant FK or tenant middleware where appropriate).
|
||||||
|
- Tests and CI (GitHub Actions) for all implemented parts.
|
||||||
|
- Commented JS functions: list + implement (see above mandatory rule).
|
||||||
|
|
||||||
|
DELIVERABLE FORMAT (for each pause)
|
||||||
|
- Short summary (2–5 lines) of what you did / will do next.
|
||||||
|
- File list changed/added (paths).
|
||||||
|
- Relevant code snippets (only the smallest necessary to explain, not full files unless asked).
|
||||||
|
- Tests added (paths).
|
||||||
|
- “Paused — awaiting approval: [description]”
|
||||||
|
|
||||||
|
EXTRA REQUIREMENTS & STANDARDS
|
||||||
|
- Code style: black + isort + flake8. Include pre-commit config.
|
||||||
|
- Migrations: No destructive migrations without a data-migration plan stated in the pause note.
|
||||||
|
- Security: Add 2FA (already present but ensure it's fully wired in login flow), encryption key rotation notes, and an audit log for all PII access.
|
||||||
|
- Documentation: update README with per-app setup, developer notes for HTMX, asset build commands, how to run the async workers, and how to test HL7/DICOM adapters locally (with sample payloads).
|
||||||
|
- Accessibility: ensure forms use proper labels and aria attributes for key patient/clinician views.
|
||||||
|
- Performance: add simple caching strategy (per-tenant cache keys) for dashboards/widgets that query large analytics tables.
|
||||||
|
|
||||||
|
FINAL PHASE & SIGNOFF
|
||||||
|
When all apps and the shared tooling are complete, produce:
|
||||||
|
1. Full traceability matrix (PRD → code + tests).
|
||||||
|
2. Final test coverage report and CI badge.
|
||||||
|
3. Deployment runbook (step-by-step: build assets, apply migrations, start ASGI/WSGI workers, start Celery, configure Nginx, configure load balancer, backup/rollback procedures).
|
||||||
|
4. A “what changed” summary for operations (including required config changes, env vars, credentials to set, and any manual steps for cutover).
|
||||||
|
|
||||||
|
START NOW (but remember: FIRST produce the Gap Analysis and pause)
|
||||||
|
- Step 0: Output a clear Gap Analysis comparing the current implemented prompt/spec vs the PRD attached (identify missing apps, missing model fields, missing integrations, commented JS functions in templates, missing ASGI/websocket, missing tests/CI, mobile issues, compliance items). The Gap Analysis must be a numbered list grouped by priority (Critical, High, Medium, Low).
|
||||||
|
**Paused — awaiting approval: Gap Analysis**
|
||||||
Loading…
x
Reference in New Issue
Block a user