592 lines
22 KiB
HTML
592 lines
22 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Delete Blood Unit - {{ blood_unit.unit_number }}{% endblock %}
|
|
|
|
{% block css %}
|
|
<style>
|
|
.danger-zone {
|
|
background: #f8d7da;
|
|
border: 2px solid #dc3545;
|
|
border-radius: 10px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.unit-info {
|
|
background: #d1ecf1;
|
|
border-left: 4px solid #17a2b8;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.impact-assessment {
|
|
background: #fff3cd;
|
|
border-left: 4px solid #ffc107;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.related-records {
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.deletion-options {
|
|
background: #e2e3e5;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.warning-icon {
|
|
color: #dc3545;
|
|
font-size: 3em;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.status-badge {
|
|
font-size: 0.9em;
|
|
padding: 5px 10px;
|
|
}
|
|
|
|
.record-count {
|
|
font-weight: bold;
|
|
color: #dc3545;
|
|
}
|
|
|
|
.alternative-action {
|
|
background: #d4edda;
|
|
border: 1px solid #28a745;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-top: 20px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:dashboard' %}">Blood Bank</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:blood_unit_list' %}">Blood Units</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:blood_unit_detail' blood_unit.id %}">{{ blood_unit.unit_number }}</a></li>
|
|
<li class="breadcrumb-item active">Delete</li>
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">Delete Blood Unit <small>{{ blood_unit.unit_number }}</small></h1>
|
|
<!-- END page-header -->
|
|
|
|
<!-- BEGIN danger zone -->
|
|
<div class="danger-zone text-center">
|
|
<i class="fa fa-exclamation-triangle warning-icon"></i>
|
|
<h3 class="text-danger mb-3">⚠️ CRITICAL ACTION REQUIRED ⚠️</h3>
|
|
<h5 class="mb-3">You are about to permanently delete this blood unit</h5>
|
|
<p class="mb-0">This action cannot be undone and may have serious implications for patient safety and regulatory compliance.</p>
|
|
</div>
|
|
<!-- END danger zone -->
|
|
|
|
<!-- BEGIN unit information -->
|
|
<div class="unit-info">
|
|
<h5><i class="fa fa-tint text-info"></i> Blood Unit Information</h5>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless mb-0">
|
|
<tr>
|
|
<td class="fw-bold">Unit Number:</td>
|
|
<td>{{ blood_unit.unit_number }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Blood Group:</td>
|
|
<td><span class="badge bg-primary">{{ blood_unit.blood_group.display_name }}</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Component:</td>
|
|
<td>{{ blood_unit.component.get_name_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Volume:</td>
|
|
<td>{{ blood_unit.volume_ml }} ml</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Status:</td>
|
|
<td>
|
|
<span class="badge status-badge bg-{% if blood_unit.status == 'available' %}success{% elif blood_unit.status == 'issued' %}warning{% elif blood_unit.status == 'expired' %}danger{% else %}secondary{% endif %}">
|
|
{{ blood_unit.get_status_display }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless mb-0">
|
|
<tr>
|
|
<td class="fw-bold">Donor:</td>
|
|
<td>
|
|
<a href="{% url 'blood_bank:donor_detail' blood_unit.donor.id %}">
|
|
{{ blood_unit.donor.full_name }}
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Collection Date:</td>
|
|
<td>{{ blood_unit.collection_date|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Expiry Date:</td>
|
|
<td>{{ blood_unit.expiry_date|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Location:</td>
|
|
<td>{{ blood_unit.location.name }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Created:</td>
|
|
<td>{{ blood_unit.created_at|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END unit information -->
|
|
|
|
<!-- BEGIN impact assessment -->
|
|
<div class="impact-assessment">
|
|
<h5><i class="fa fa-exclamation-triangle text-warning"></i> Impact Assessment</h5>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="alert alert-warning">
|
|
<h6><i class="fa fa-info-circle"></i> Deletion Impact Analysis</h6>
|
|
<ul class="mb-0">
|
|
{% if blood_unit.status == 'issued' %}
|
|
<li><strong>CRITICAL:</strong> This unit has been issued and may be in use for patient transfusion</li>
|
|
{% endif %}
|
|
{% if blood_unit.status == 'available' %}
|
|
<li><strong>WARNING:</strong> This unit is currently available in inventory</li>
|
|
{% endif %}
|
|
{% if blood_unit.blood_tests.exists %}
|
|
<li>Blood test records will be permanently lost</li>
|
|
{% endif %}
|
|
{% if blood_unit.crossmatch_results.exists %}
|
|
<li>Crossmatch results will be permanently deleted</li>
|
|
{% endif %}
|
|
{% if blood_unit.transfusions.exists %}
|
|
<li><strong>CRITICAL:</strong> Transfusion records will be affected</li>
|
|
{% endif %}
|
|
<li>Audit trail and traceability will be compromised</li>
|
|
<li>Regulatory compliance may be affected</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END impact assessment -->
|
|
|
|
<!-- BEGIN related records -->
|
|
<div class="related-records">
|
|
<h5><i class="fa fa-link text-secondary"></i> Related Records</h5>
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="record-count">{{ blood_unit.blood_tests.count }}</h4>
|
|
<small class="text-muted">Blood Tests</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="record-count">{{ blood_unit.crossmatch_results.count }}</h4>
|
|
<small class="text-muted">Crossmatch Results</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="record-count">{{ blood_unit.transfusions.count }}</h4>
|
|
<small class="text-muted">Transfusions</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="record-count">{{ blood_unit.quality_control_tests.count }}</h4>
|
|
<small class="text-muted">QC Tests</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if blood_unit.transfusions.exists %}
|
|
<div class="mt-3">
|
|
<h6>Associated Transfusions:</h6>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Transfusion ID</th>
|
|
<th>Patient</th>
|
|
<th>Date</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for transfusion in blood_unit.transfusions.all %}
|
|
<tr>
|
|
<td>
|
|
<a href="{% url 'blood_bank:transfusion_detail' transfusion.id %}">
|
|
{{ transfusion.transfusion_id }}
|
|
</a>
|
|
</td>
|
|
<td>{{ transfusion.patient.full_name }}</td>
|
|
<td>{{ transfusion.start_time|date:"M d, Y" }}</td>
|
|
<td>
|
|
<span class="badge bg-{% if transfusion.status == 'completed' %}success{% elif transfusion.status == 'in_progress' %}warning{% else %}secondary{% endif %}">
|
|
{{ transfusion.get_status_display }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<!-- END related records -->
|
|
|
|
<!-- BEGIN deletion options -->
|
|
<div class="deletion-options">
|
|
<h5><i class="fa fa-cogs text-secondary"></i> Deletion Options</h5>
|
|
<form method="post" id="deleteForm">
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="deletionReason" class="form-label">
|
|
Reason for Deletion <span class="text-danger">*</span>
|
|
</label>
|
|
<select class="form-select" id="deletionReason" name="deletion_reason" required>
|
|
<option value="">Select reason...</option>
|
|
<option value="expired">Unit Expired</option>
|
|
<option value="contaminated">Contamination Detected</option>
|
|
<option value="damaged">Physical Damage</option>
|
|
<option value="recall">Product Recall</option>
|
|
<option value="quality_failure">Quality Control Failure</option>
|
|
<option value="administrative">Administrative Error</option>
|
|
<option value="other">Other (specify in notes)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="authorizedBy" class="form-label">
|
|
Authorized By <span class="text-danger">*</span>
|
|
</label>
|
|
<select class="form-select" id="authorizedBy" name="authorized_by" required>
|
|
<option value="">Select authorizing person...</option>
|
|
{% for user in authorized_users %}
|
|
<option value="{{ user.id }}">{{ user.get_full_name }} - {{ user.title }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="form-group">
|
|
<label for="deletionNotes" class="form-label">
|
|
Deletion Notes <span class="text-danger">*</span>
|
|
</label>
|
|
<textarea class="form-control" id="deletionNotes" name="deletion_notes" rows="4"
|
|
placeholder="Provide detailed explanation for this deletion..." required></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="archiveData" name="archive_data" checked>
|
|
<label class="form-check-label" for="archiveData">
|
|
Archive data before deletion (recommended)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="notifyStakeholders" name="notify_stakeholders" checked>
|
|
<label class="form-check-label" for="notifyStakeholders">
|
|
Notify relevant stakeholders
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-md-12">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="confirmDeletion" name="confirm_deletion" required>
|
|
<label class="form-check-label" for="confirmDeletion">
|
|
<strong>I understand that this action is irreversible and confirm the deletion of this blood unit</strong>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- END deletion options -->
|
|
|
|
<!-- BEGIN alternative action -->
|
|
<div class="alternative-action">
|
|
<h5><i class="fa fa-lightbulb text-success"></i> Alternative Recommendation</h5>
|
|
<p class="mb-3">
|
|
<strong>Consider these alternatives instead of permanent deletion:</strong>
|
|
</p>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6>Mark as Inactive</h6>
|
|
<p class="small">Preserve all data while removing from active inventory</p>
|
|
<button type="button" class="btn btn-outline-success btn-sm" onclick="markInactive()">
|
|
<i class="fa fa-pause"></i> Mark Inactive
|
|
</button>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Update Status</h6>
|
|
<p class="small">Change status to reflect current condition</p>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="updateStatus()">
|
|
<i class="fa fa-edit"></i> Update Status
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END alternative action -->
|
|
|
|
<!-- BEGIN form actions -->
|
|
<div class="d-flex justify-content-between mt-4">
|
|
<a href="{% url 'blood_bank:blood_unit_detail' blood_unit.id %}" class="btn btn-secondary">
|
|
<i class="fa fa-arrow-left"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="button" class="btn btn-warning" onclick="validateDeletion()">
|
|
<i class="fa fa-check"></i> Validate Deletion
|
|
</button>
|
|
<button type="button" class="btn btn-danger" onclick="confirmDeletion()">
|
|
<i class="fa fa-trash"></i> Delete Blood Unit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- END form actions -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Disable delete button initially
|
|
$('button[onclick="confirmDeletion()"]').prop('disabled', true);
|
|
|
|
// Enable delete button only when confirmation is checked
|
|
$('#confirmDeletion').on('change', function() {
|
|
$('button[onclick="confirmDeletion()"]').prop('disabled', !this.checked);
|
|
});
|
|
|
|
// Show warning for critical statuses
|
|
{% if blood_unit.status == 'issued' or blood_unit.transfusions.exists %}
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Critical Unit Detected',
|
|
text: 'This blood unit has active transfusion records. Deletion may affect patient safety.',
|
|
confirmButtonText: 'I Understand'
|
|
});
|
|
{% endif %}
|
|
});
|
|
|
|
function validateDeletion() {
|
|
var errors = [];
|
|
|
|
// Check required fields
|
|
if (!$('#deletionReason').val()) {
|
|
errors.push('Please select a reason for deletion');
|
|
}
|
|
|
|
if (!$('#authorizedBy').val()) {
|
|
errors.push('Please select an authorizing person');
|
|
}
|
|
|
|
if (!$('#deletionNotes').val().trim()) {
|
|
errors.push('Please provide detailed deletion notes');
|
|
}
|
|
|
|
if (!$('#confirmDeletion').is(':checked')) {
|
|
errors.push('Please confirm that you understand this action is irreversible');
|
|
}
|
|
|
|
// Check for critical conditions
|
|
{% if blood_unit.status == 'issued' %}
|
|
errors.push('WARNING: This unit is currently issued and may be in use');
|
|
{% endif %}
|
|
|
|
{% if blood_unit.transfusions.exists %}
|
|
errors.push('WARNING: This unit has transfusion records that will be affected');
|
|
{% endif %}
|
|
|
|
if (errors.length > 0) {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Validation Issues',
|
|
html: '<ul class="text-start"><li>' + errors.join('</li><li>') + '</li></ul>',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
return false;
|
|
}
|
|
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Validation Passed',
|
|
text: 'All required information has been provided.',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
function confirmDeletion() {
|
|
if (!validateDeletion()) {
|
|
return;
|
|
}
|
|
|
|
var reason = $('#deletionReason option:selected').text();
|
|
var notes = $('#deletionNotes').val();
|
|
|
|
Swal.fire({
|
|
title: 'FINAL CONFIRMATION',
|
|
html: `
|
|
<div class="text-start">
|
|
<div class="alert alert-danger">
|
|
<strong>⚠️ CRITICAL WARNING ⚠️</strong><br>
|
|
You are about to permanently delete blood unit <strong>{{ blood_unit.unit_number }}</strong>
|
|
</div>
|
|
<p><strong>Reason:</strong> ${reason}</p>
|
|
<p><strong>Notes:</strong> ${notes.substring(0, 100)}${notes.length > 100 ? '...' : ''}</p>
|
|
<p><strong>This action will:</strong></p>
|
|
<ul>
|
|
<li>Permanently remove the blood unit from the system</li>
|
|
<li>Delete all associated test results and records</li>
|
|
<li>Affect audit trails and traceability</li>
|
|
<li>Cannot be undone</li>
|
|
</ul>
|
|
<div class="form-check mt-3">
|
|
<input class="form-check-input" type="checkbox" id="finalConfirm">
|
|
<label class="form-check-label" for="finalConfirm">
|
|
<strong>I have read and understand the consequences</strong>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
`,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#d33',
|
|
cancelButtonColor: '#3085d6',
|
|
confirmButtonText: 'DELETE PERMANENTLY',
|
|
cancelButtonText: 'Cancel',
|
|
preConfirm: () => {
|
|
if (!document.getElementById('finalConfirm').checked) {
|
|
Swal.showValidationMessage('Please confirm that you understand the consequences');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Submit the form
|
|
$('#deleteForm').submit();
|
|
}
|
|
});
|
|
}
|
|
|
|
function markInactive() {
|
|
Swal.fire({
|
|
title: 'Mark Blood Unit as Inactive?',
|
|
text: 'This will preserve all data while removing the unit from active inventory.',
|
|
icon: 'question',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Mark Inactive',
|
|
cancelButtonText: 'Cancel'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Here you would make an AJAX call to mark as inactive
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Unit Marked Inactive',
|
|
text: 'The blood unit has been marked as inactive.',
|
|
confirmButtonText: 'OK'
|
|
}).then(() => {
|
|
window.location.href = "{% url 'blood_bank:blood_unit_detail' blood_unit.id %}";
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateStatus() {
|
|
Swal.fire({
|
|
title: 'Update Blood Unit Status',
|
|
html: `
|
|
<div class="text-start">
|
|
<div class="mb-3">
|
|
<label class="form-label">New Status</label>
|
|
<select class="form-select" id="newStatus">
|
|
<option value="">Select new status...</option>
|
|
<option value="quarantined">Quarantined</option>
|
|
<option value="expired">Expired</option>
|
|
<option value="damaged">Damaged</option>
|
|
<option value="recalled">Recalled</option>
|
|
<option value="discarded">Discarded</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Reason</label>
|
|
<textarea class="form-control" id="statusReason" rows="3" placeholder="Explain the reason for status change..."></textarea>
|
|
</div>
|
|
</div>
|
|
`,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Update Status',
|
|
cancelButtonText: 'Cancel',
|
|
preConfirm: () => {
|
|
const status = document.getElementById('newStatus').value;
|
|
const reason = document.getElementById('statusReason').value;
|
|
|
|
if (!status) {
|
|
Swal.showValidationMessage('Please select a new status');
|
|
return false;
|
|
}
|
|
|
|
if (!reason.trim()) {
|
|
Swal.showValidationMessage('Please provide a reason for the status change');
|
|
return false;
|
|
}
|
|
|
|
return { status, reason };
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Status Updated',
|
|
text: 'The blood unit status has been updated.',
|
|
confirmButtonText: 'OK'
|
|
}).then(() => {
|
|
window.location.href = "{% url 'blood_bank:blood_unit_detail' blood_unit.id %}";
|
|
});
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|