838 lines
39 KiB
HTML
838 lines
39 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit{% else %}New{% endif %} Dispensing - Pharmacy{% endblock %}
|
|
|
|
{% 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 'pharmacy:dashboard' %}">Pharmacy</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'pharmacy:dispensing_list' %}">Dispensing</a></li>
|
|
{% if object %}
|
|
<li class="breadcrumb-item"><a href="{% url 'pharmacy:dispensing_detail' object.pk %}">{{ object.prescription.prescription_number }}</a></li>
|
|
<li class="breadcrumb-item active">Edit</li>
|
|
{% else %}
|
|
<li class="breadcrumb-item active">New</li>
|
|
{% endif %}
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">
|
|
{% if object %}Edit Dispensing{% else %}New Dispensing{% endif %}
|
|
<small>{% if object %}{{ object.prescription.prescription_number }}{% else %}Create new dispensing record{% endif %}</small>
|
|
</h1>
|
|
<!-- END page-header -->
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Dispensing Details</h4>
|
|
<div class="panel-heading-btn">
|
|
<button type="button" class="btn btn-xs btn-info me-2" onclick="checkInteractions()">
|
|
<i class="fa fa-search"></i> Check Interactions
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-secondary me-2" onclick="saveDraft()">
|
|
<i class="fa fa-save"></i> Save Draft
|
|
</button>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<form method="post" id="dispensing-form" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<!-- Prescription Selection -->
|
|
<div class="card border-primary mb-4">
|
|
<div class="card-header bg-primary text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-prescription me-2"></i>Prescription Information
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="form-floating mb-3">
|
|
{{ form.prescription }}
|
|
<label for="{{ form.prescription.id_for_label }}">Prescription <span class="text-danger">*</span></label>
|
|
{% if form.prescription.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.prescription.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Select the prescription to dispense.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.priority }}
|
|
<label for="{{ form.priority.id_for_label }}">Priority <span class="text-danger">*</span></label>
|
|
{% if form.priority.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.priority.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Dispensing priority level.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Prescription Information Display -->
|
|
<div id="prescription-info" class="card border-info mt-3" style="display: none;">
|
|
<div class="card-header bg-info text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-info-circle me-2"></i>Prescription Details
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div id="rx-patient" class="mb-2"></div>
|
|
<div id="rx-prescriber" class="mb-2"></div>
|
|
<div id="rx-date" class="mb-2"></div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div id="rx-medication" class="mb-2"></div>
|
|
<div id="rx-quantity" class="mb-2"></div>
|
|
<div id="rx-refills" class="mb-2"></div>
|
|
</div>
|
|
</div>
|
|
<div class="row mt-2">
|
|
<div class="col-12">
|
|
<div id="rx-directions" class="mb-2"></div>
|
|
<div id="rx-alerts" class="mb-2"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dispensing Information -->
|
|
<div class="card border-success mb-4">
|
|
<div class="card-header bg-success text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-pills me-2"></i>Dispensing Information
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.quantity_dispensed }}
|
|
<label for="{{ form.quantity_dispensed.id_for_label }}">Quantity to Dispense <span class="text-danger">*</span></label>
|
|
{% if form.quantity_dispensed.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.quantity_dispensed.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Number of units to dispense.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.days_supply }}
|
|
<label for="{{ form.days_supply.id_for_label }}">Days Supply <span class="text-danger">*</span></label>
|
|
{% if form.days_supply.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.days_supply.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Number of days the medication will last.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.pharmacist }}
|
|
<label for="{{ form.pharmacist.id_for_label }}">Pharmacist <span class="text-danger">*</span></label>
|
|
{% if form.pharmacist.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.pharmacist.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Dispensing pharmacist.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Medication and Inventory -->
|
|
<div class="card border-warning mb-4">
|
|
<div class="card-header bg-warning text-dark">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-boxes me-2"></i>Medication and Inventory
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.medication }}
|
|
<label for="{{ form.medication.id_for_label }}">Medication <span class="text-danger">*</span></label>
|
|
{% if form.medication.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.medication.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Select specific medication to dispense.</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.inventory_record }}
|
|
<label for="{{ form.inventory_record.id_for_label }}">Inventory Record</label>
|
|
{% if form.inventory_record.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.inventory_record.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Select inventory lot to dispense from.</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.lot_number }}
|
|
<label for="{{ form.lot_number.id_for_label }}">Lot Number</label>
|
|
{% if form.lot_number.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.lot_number.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Medication lot number.</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.expiration_date }}
|
|
<label for="{{ form.expiration_date.id_for_label }}">Expiration Date</label>
|
|
{% if form.expiration_date.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.expiration_date.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Medication expiration date.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stock Availability Display -->
|
|
<div id="stock-info" class="alert alert-info" style="display: none;">
|
|
<h6 class="alert-heading">
|
|
<i class="fa fa-info-circle me-2"></i>Stock Information
|
|
</h6>
|
|
<div id="stock-details"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Safety Checks -->
|
|
<div class="card border-danger mb-4">
|
|
<div class="card-header bg-danger text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-shield-alt me-2"></i>Patient Safety Checks
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-check mb-3">
|
|
{{ form.allergy_checked }}
|
|
<label class="form-check-label" for="{{ form.allergy_checked.id_for_label }}">
|
|
<i class="fa fa-exclamation-triangle text-warning me-1"></i>
|
|
Allergies checked and verified
|
|
</label>
|
|
</div>
|
|
<div class="form-check mb-3">
|
|
{{ form.interaction_checked }}
|
|
<label class="form-check-label" for="{{ form.interaction_checked.id_for_label }}">
|
|
<i class="fa fa-pills text-info me-1"></i>
|
|
Drug interactions reviewed
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-check mb-3">
|
|
{{ form.dosage_verified }}
|
|
<label class="form-check-label" for="{{ form.dosage_verified.id_for_label }}">
|
|
<i class="fa fa-calculator text-primary me-1"></i>
|
|
Dosage calculations verified
|
|
</label>
|
|
</div>
|
|
<div class="form-check mb-3">
|
|
{{ form.patient_counseled }}
|
|
<label class="form-check-label" for="{{ form.patient_counseled.id_for_label }}">
|
|
<i class="fa fa-comments text-success me-1"></i>
|
|
Patient counseled on medication
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Safety Alerts Display -->
|
|
<div id="safety-alerts" class="mt-3" style="display: none;">
|
|
<h6 class="text-danger">Safety Alerts:</h6>
|
|
<div id="alert-list"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status and Dates -->
|
|
<div class="card border-secondary mb-4">
|
|
<div class="card-header bg-secondary text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-calendar me-2"></i>Status and Dates
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.status }}
|
|
<label for="{{ form.status.id_for_label }}">Status <span class="text-danger">*</span></label>
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.status.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Current dispensing status.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.dispensed_date }}
|
|
<label for="{{ form.dispensed_date.id_for_label }}">Dispensed Date</label>
|
|
{% if form.dispensed_date.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.dispensed_date.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Date medication was dispensed.</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.pickup_date }}
|
|
<label for="{{ form.pickup_date.id_for_label }}">Pickup Date</label>
|
|
{% if form.pickup_date.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.pickup_date.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="form-text">Date patient picked up medication.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="card border-info mb-4">
|
|
<div class="card-header bg-info text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fa fa-sticky-note me-2"></i>Notes and Comments
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.notes.id_for_label }}" class="form-label">General Notes</label>
|
|
{{ form.notes }}
|
|
{% if form.notes.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.notes.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">General dispensing notes.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.pharmacist_notes.id_for_label }}" class="form-label">Pharmacist Notes</label>
|
|
{{ form.pharmacist_notes }}
|
|
{% if form.pharmacist_notes.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.pharmacist_notes.errors.0 }}</div>
|
|
{% endif %}
|
|
<div class="form-text">Clinical notes from pharmacist.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<a href="{% if object %}{% url 'pharmacy:dispensing_detail' object.pk %}{% else %}{% url 'pharmacy:dispensing_list' %}{% endif %}" class="btn btn-secondary">
|
|
<i class="fa fa-arrow-left me-2"></i>Cancel
|
|
</a>
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-info me-2" onclick="saveDraft()">
|
|
<i class="fa fa-save me-2"></i>Save Draft
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-check me-2"></i>{% if object %}Update{% else %}Create{% endif %} Dispensing
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Dispensing Guidelines</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="alert alert-info">
|
|
<h6 class="alert-heading">Safety Checklist</h6>
|
|
<ul class="mb-0 small">
|
|
<li>Verify patient identity and allergies</li>
|
|
<li>Check for drug interactions</li>
|
|
<li>Confirm dosage calculations</li>
|
|
<li>Review medication directions</li>
|
|
<li>Ensure adequate stock availability</li>
|
|
<li>Provide patient counseling</li>
|
|
<li>Document all safety checks</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card border-warning mb-3">
|
|
<div class="card-header bg-warning text-dark">
|
|
<h6 class="card-title mb-0">Validation Status</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-unstyled mb-0 small">
|
|
<li id="prescription-check"><i class="fa fa-times text-danger me-2"></i>Prescription validation pending</li>
|
|
<li id="quantity-check"><i class="fa fa-times text-danger me-2"></i>Quantity validation pending</li>
|
|
<li id="stock-check"><i class="fa fa-times text-danger me-2"></i>Stock availability pending</li>
|
|
<li id="safety-check"><i class="fa fa-times text-danger me-2"></i>Safety checks pending</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Quick Actions</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-outline-info" onclick="checkInteractions()">
|
|
<i class="fa fa-search me-2"></i>Check Drug Interactions
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning" onclick="verifyAllergies()">
|
|
<i class="fa fa-exclamation-triangle me-2"></i>Verify Allergies
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary" onclick="calculateDosage()">
|
|
<i class="fa fa-calculator me-2"></i>Calculate Dosage
|
|
</button>
|
|
<button type="button" class="btn btn-outline-success" onclick="checkStock()">
|
|
<i class="fa fa-boxes me-2"></i>Check Stock
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="clearForm()">
|
|
<i class="fa fa-refresh me-2"></i>Clear Form
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Form Status</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div id="form-status">
|
|
<div class="alert alert-secondary">
|
|
<i class="fa fa-info-circle me-2"></i>
|
|
<span id="status-text">Draft dispensing record</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="small text-muted">
|
|
<div>Last saved: <span id="last-saved">Never</span></div>
|
|
<div>Auto-save: <span class="text-success">Enabled</span></div>
|
|
<div>Validation: <span id="validation-status" class="text-warning">Pending</span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
var autoSaveTimer;
|
|
|
|
$(document).ready(function() {
|
|
// Initialize form behavior
|
|
initializeFormBehavior();
|
|
|
|
// Auto-save functionality
|
|
$('#dispensing-form input, #dispensing-form select, #dispensing-form textarea').on('change input', function() {
|
|
clearTimeout(autoSaveTimer);
|
|
autoSaveTimer = setTimeout(function() {
|
|
saveDraft();
|
|
}, 5000);
|
|
});
|
|
|
|
// Form validation
|
|
$('#dispensing-form').on('submit', function(e) {
|
|
if (!validateForm()) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
|
|
function initializeFormBehavior() {
|
|
// Prescription selection change
|
|
$('#{{ form.prescription.id_for_label }}').on('change', function() {
|
|
var prescriptionId = $(this).val();
|
|
if (prescriptionId) {
|
|
loadPrescriptionInfo(prescriptionId);
|
|
validatePrescription();
|
|
} else {
|
|
$('#prescription-info').hide();
|
|
}
|
|
});
|
|
|
|
// Medication selection change
|
|
$('#{{ form.medication.id_for_label }}').on('change', function() {
|
|
var medicationId = $(this).val();
|
|
if (medicationId) {
|
|
loadMedicationInfo(medicationId);
|
|
checkStock();
|
|
}
|
|
});
|
|
|
|
// Quantity change
|
|
$('#{{ form.quantity_dispensed.id_for_label }}').on('change', function() {
|
|
validateQuantity();
|
|
checkStock();
|
|
});
|
|
|
|
// Safety check changes
|
|
$('#{{ form.allergy_checked.id_for_label }}, #{{ form.interaction_checked.id_for_label }}, #{{ form.dosage_verified.id_for_label }}, #{{ form.patient_counseled.id_for_label }}').on('change', function() {
|
|
validateSafetyChecks();
|
|
});
|
|
|
|
// Status change
|
|
$('#{{ form.status.id_for_label }}').on('change', function() {
|
|
handleStatusChange();
|
|
});
|
|
}
|
|
|
|
function loadPrescriptionInfo(prescriptionId) {
|
|
$.ajax({
|
|
url: '{% url "pharmacy:prescription_info" %}',
|
|
method: 'GET',
|
|
data: {'prescription_id': prescriptionId},
|
|
success: function(response) {
|
|
var rx = response.prescription;
|
|
$('#rx-patient').html('<strong>Patient:</strong> ' + rx.patient_name + ' (DOB: ' + rx.patient_dob + ')');
|
|
$('#rx-prescriber').html('<strong>Prescriber:</strong> ' + rx.prescriber_name);
|
|
$('#rx-date').html('<strong>Date:</strong> ' + rx.date_prescribed);
|
|
$('#rx-medication').html('<strong>Medication:</strong> ' + rx.medication_name + ' ' + rx.strength);
|
|
$('#rx-quantity').html('<strong>Quantity:</strong> ' + rx.quantity + ' ' + rx.unit);
|
|
$('#rx-refills').html('<strong>Refills:</strong> ' + rx.refills_remaining + ' remaining');
|
|
$('#rx-directions').html('<strong>Directions:</strong> ' + rx.directions);
|
|
|
|
// Show alerts if any
|
|
var alerts = [];
|
|
if (rx.is_controlled) alerts.push('<span class="badge bg-warning text-dark">Controlled</span>');
|
|
if (rx.is_high_alert) alerts.push('<span class="badge bg-danger">High Alert</span>');
|
|
if (rx.has_allergies) alerts.push('<span class="badge bg-warning text-dark">Allergy Alert</span>');
|
|
|
|
$('#rx-alerts').html('<strong>Alerts:</strong> ' + (alerts.length ? alerts.join(' ') : 'None'));
|
|
$('#prescription-info').show();
|
|
|
|
// Auto-populate fields
|
|
if (rx.medication_id) {
|
|
$('#{{ form.medication.id_for_label }}').val(rx.medication_id).trigger('change');
|
|
}
|
|
$('#{{ form.quantity_dispensed.id_for_label }}').val(rx.quantity);
|
|
$('#{{ form.days_supply.id_for_label }}').val(rx.days_supply);
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to load prescription information');
|
|
}
|
|
});
|
|
}
|
|
|
|
function loadMedicationInfo(medicationId) {
|
|
$.ajax({
|
|
url: '{% url "pharmacy:medication_info" %}',
|
|
method: 'GET',
|
|
data: {'medication_id': medicationId},
|
|
success: function(response) {
|
|
// Update inventory record options
|
|
var inventorySelect = $('#{{ form.inventory_record.id_for_label }}');
|
|
inventorySelect.empty().append('<option value="">Select inventory record...</option>');
|
|
|
|
response.inventory_records.forEach(function(record) {
|
|
inventorySelect.append('<option value="' + record.id + '">' +
|
|
record.location + ' - Stock: ' + record.stock +
|
|
(record.lot_number ? ' (Lot: ' + record.lot_number + ')' : '') + '</option>');
|
|
});
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to load medication information');
|
|
}
|
|
});
|
|
}
|
|
|
|
function validateForm() {
|
|
var isValid = true;
|
|
var errors = [];
|
|
|
|
// Required field validation
|
|
var requiredFields = [
|
|
'{{ form.prescription.id_for_label }}',
|
|
'{{ form.medication.id_for_label }}',
|
|
'{{ form.quantity_dispensed.id_for_label }}',
|
|
'{{ form.days_supply.id_for_label }}',
|
|
'{{ form.pharmacist.id_for_label }}',
|
|
'{{ form.status.id_for_label }}',
|
|
'{{ form.priority.id_for_label }}'
|
|
];
|
|
|
|
requiredFields.forEach(function(fieldId) {
|
|
var field = $('#' + fieldId);
|
|
if (!field.val()) {
|
|
field.addClass('is-invalid');
|
|
errors.push(field.closest('.form-floating, .mb-3').find('label').text().replace(' *', '') + ' is required');
|
|
isValid = false;
|
|
} else {
|
|
field.removeClass('is-invalid');
|
|
}
|
|
});
|
|
|
|
// Quantity validation
|
|
var quantityDispensed = parseInt($('#{{ form.quantity_dispensed.id_for_label }}').val()) || 0;
|
|
if (quantityDispensed <= 0) {
|
|
errors.push('Quantity to dispense must be greater than zero');
|
|
isValid = false;
|
|
}
|
|
|
|
// Safety checks validation
|
|
var status = $('#{{ form.status.id_for_label }}').val();
|
|
if (status === 'dispensed') {
|
|
var safetyChecks = [
|
|
'{{ form.allergy_checked.id_for_label }}',
|
|
'{{ form.interaction_checked.id_for_label }}',
|
|
'{{ form.dosage_verified.id_for_label }}',
|
|
'{{ form.patient_counseled.id_for_label }}'
|
|
];
|
|
|
|
safetyChecks.forEach(function(checkId) {
|
|
if (!$('#' + checkId).is(':checked')) {
|
|
errors.push('All safety checks must be completed before dispensing');
|
|
isValid = false;
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!isValid) {
|
|
toastr.error('Please fix the following errors:\n' + errors.join('\n'));
|
|
$('#validation-status').text('Failed').removeClass('text-success text-warning').addClass('text-danger');
|
|
} else {
|
|
$('#validation-status').text('Passed').removeClass('text-danger text-warning').addClass('text-success');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
function validatePrescription() {
|
|
var prescriptionId = $('#{{ form.prescription.id_for_label }}').val();
|
|
|
|
if (prescriptionId) {
|
|
$('#prescription-check').html('<i class="fa fa-check text-success me-2"></i>Prescription selected');
|
|
} else {
|
|
$('#prescription-check').html('<i class="fa fa-times text-danger me-2"></i>Prescription required');
|
|
}
|
|
}
|
|
|
|
function validateQuantity() {
|
|
var quantity = parseInt($('#{{ form.quantity_dispensed.id_for_label }}').val()) || 0;
|
|
|
|
if (quantity > 0) {
|
|
$('#quantity-check').html('<i class="fa fa-check text-success me-2"></i>Quantity valid');
|
|
} else {
|
|
$('#quantity-check').html('<i class="fa fa-times text-danger me-2"></i>Invalid quantity');
|
|
}
|
|
}
|
|
|
|
function validateSafetyChecks() {
|
|
var allChecked = true;
|
|
var safetyChecks = [
|
|
'{{ form.allergy_checked.id_for_label }}',
|
|
'{{ form.interaction_checked.id_for_label }}',
|
|
'{{ form.dosage_verified.id_for_label }}',
|
|
'{{ form.patient_counseled.id_for_label }}'
|
|
];
|
|
|
|
safetyChecks.forEach(function(checkId) {
|
|
if (!$('#' + checkId).is(':checked')) {
|
|
allChecked = false;
|
|
}
|
|
});
|
|
|
|
if (allChecked) {
|
|
$('#safety-check').html('<i class="fa fa-check text-success me-2"></i>All safety checks completed');
|
|
} else {
|
|
$('#safety-check').html('<i class="fa fa-exclamation-triangle text-warning me-2"></i>Safety checks incomplete');
|
|
}
|
|
}
|
|
|
|
function checkStock() {
|
|
var medicationId = $('#{{ form.medication.id_for_label }}').val();
|
|
var quantity = parseInt($('#{{ form.quantity_dispensed.id_for_label }}').val()) || 0;
|
|
|
|
if (!medicationId || !quantity) {
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '{% url "pharmacy:check_stock_availability" %}',
|
|
method: 'POST',
|
|
data: {
|
|
'medication_id': medicationId,
|
|
'quantity': quantity,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.available) {
|
|
$('#stock-check').html('<i class="fa fa-check text-success me-2"></i>Stock available');
|
|
$('#stock-details').html(
|
|
'<div class="row">' +
|
|
'<div class="col-6"><strong>Available:</strong> ' + response.total_stock + '</div>' +
|
|
'<div class="col-6"><strong>Requested:</strong> ' + quantity + '</div>' +
|
|
'</div>'
|
|
);
|
|
$('#stock-info').show();
|
|
} else {
|
|
$('#stock-check').html('<i class="fa fa-times text-danger me-2"></i>Insufficient stock');
|
|
$('#stock-details').html(
|
|
'<div class="text-danger">' +
|
|
'<strong>Insufficient stock:</strong> ' + response.total_stock + ' available, ' + quantity + ' requested' +
|
|
'</div>'
|
|
);
|
|
$('#stock-info').show();
|
|
}
|
|
},
|
|
error: function() {
|
|
$('#stock-check').html('<i class="fa fa-exclamation-triangle text-warning me-2"></i>Stock check failed');
|
|
}
|
|
});
|
|
}
|
|
|
|
function checkInteractions() {
|
|
var prescriptionId = $('#{{ form.prescription.id_for_label }}').val();
|
|
|
|
if (!prescriptionId) {
|
|
toastr.warning('Please select a prescription first');
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '{% url "pharmacy:check_drug_interactions" %}',
|
|
method: 'POST',
|
|
data: {
|
|
'prescription_id': prescriptionId,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.interactions.length > 0) {
|
|
var alertHtml = '';
|
|
response.interactions.forEach(function(interaction) {
|
|
alertHtml += '<div class="alert alert-warning mb-2">' +
|
|
'<strong>' + interaction.severity + ':</strong> ' + interaction.description +
|
|
'</div>';
|
|
});
|
|
$('#alert-list').html(alertHtml);
|
|
$('#safety-alerts').show();
|
|
toastr.warning('Drug interactions found - review alerts');
|
|
} else {
|
|
$('#safety-alerts').hide();
|
|
toastr.success('No drug interactions found');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to check drug interactions');
|
|
}
|
|
});
|
|
}
|
|
|
|
function verifyAllergies() {
|
|
var prescriptionId = $('#{{ form.prescription.id_for_label }}').val();
|
|
|
|
if (!prescriptionId) {
|
|
toastr.warning('Please select a prescription first');
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '{% url "pharmacy:verify_allergies" %}',
|
|
method: 'POST',
|
|
data: {
|
|
'prescription_id': prescriptionId,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.allergies.length > 0) {
|
|
toastr.warning('Patient has known allergies - review carefully');
|
|
$('#{{ form.allergy_checked.id_for_label }}').prop('checked', true);
|
|
} else {
|
|
toastr.success('No known allergies');
|
|
$('#{{ form.allergy_checked.id_for_label }}').prop('checked', true);
|
|
}
|
|
validateSafetyChecks();
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to verify allergies');
|
|
}
|
|
});
|
|
}
|
|
|
|
function calculateDosage() {
|
|
// Implementation for dosage calculation
|
|
toastr.info('Dosage calculation feature coming soon');
|
|
$('#{{ form.dosage_verified.id_for_label }}').prop('checked', true);
|
|
validateSafetyChecks();
|
|
}
|
|
|
|
function handleStatusChange() {
|
|
var status = $('#{{ form.status.id_for_label }}').val();
|
|
|
|
if (status === 'dispensed') {
|
|
$('#{{ form.dispensed_date.id_for_label }}').val(new Date().toISOString().slice(0, 16));
|
|
}
|
|
}
|
|
|
|
function saveDraft() {
|
|
var formData = $('#dispensing-form').serialize();
|
|
|
|
$.ajax({
|
|
url: '{% url "pharmacy:save_dispensing_draft" %}',
|
|
method: 'POST',
|
|
data: formData,
|
|
success: function(response) {
|
|
updateFormStatus('Draft saved', 'success');
|
|
$('#last-saved').text(new Date().toLocaleTimeString());
|
|
},
|
|
error: function() {
|
|
updateFormStatus('Failed to save draft', 'danger');
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateFormStatus(message, type) {
|
|
var alertClass = 'alert-' + type;
|
|
$('#form-status').html('<div class="alert ' + alertClass + '"><i class="fa fa-info-circle me-2"></i>' + message + '</div>');
|
|
}
|
|
|
|
function clearForm() {
|
|
if (confirm('Are you sure you want to clear all form data?')) {
|
|
$('#dispensing-form')[0].reset();
|
|
$('#prescription-info').hide();
|
|
$('#stock-info').hide();
|
|
$('#safety-alerts').hide();
|
|
updateFormStatus('Form cleared', 'info');
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|