439 lines
19 KiB
HTML
439 lines
19 KiB
HTML
<!-- Add Stock Modal -->
|
|
<div class="modal fade" id="addStockModal" tabindex="-1" aria-labelledby="addStockModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="addStockModalLabel">
|
|
<i class="fas fa-plus-circle me-2"></i>Add Stock
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<form id="addStockForm" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-body">
|
|
<!-- Item Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card bg-light">
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<h6 class="card-title mb-1" id="add-item-name">Item Name</h6>
|
|
<p class="card-text small text-muted mb-1">
|
|
<span class="me-3">
|
|
<i class="fas fa-barcode me-1"></i>
|
|
<span id="add-item-code">Item Code</span>
|
|
</span>
|
|
<span class="me-3">
|
|
<i class="fas fa-layer-group me-1"></i>
|
|
<span id="add-item-category">Category</span>
|
|
</span>
|
|
</p>
|
|
<p class="card-text small text-muted mb-0">
|
|
<i class="fas fa-map-marker-alt me-1"></i>
|
|
<span id="add-item-location">Location</span>
|
|
</p>
|
|
</div>
|
|
<div class="col-md-4 text-end">
|
|
<div class="current-stock">
|
|
<small class="text-muted">Current Stock</small>
|
|
<h4 class="mb-0" id="add-current-stock">0</h4>
|
|
<small class="text-muted" id="add-stock-unit">units</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stock Addition Details -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_quantity">
|
|
Quantity to Add <span class="text-danger">*</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<input type="number" class="form-control" id="add_quantity"
|
|
name="add_quantity" min="0.01" step="0.01" required>
|
|
<span class="input-group-text" id="add-quantity-unit">units</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_unit_cost">
|
|
Unit Cost
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">$</span>
|
|
<input type="number" class="form-control" id="add_unit_cost"
|
|
name="add_unit_cost" min="0" step="0.01" placeholder="0.00">
|
|
</div>
|
|
<small class="form-text text-muted">Cost per unit</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_supplier">
|
|
Supplier
|
|
</label>
|
|
<select class="form-select" id="add_supplier" name="add_supplier">
|
|
<option value="">Select supplier...</option>
|
|
{% for supplier in suppliers %}
|
|
<option value="{{ supplier.id }}">{{ supplier.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_purchase_order">
|
|
Purchase Order Number
|
|
</label>
|
|
<input type="text" class="form-control" id="add_purchase_order"
|
|
name="add_purchase_order" placeholder="PO-XXXX">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_batch_number">
|
|
Batch/Lot Number
|
|
</label>
|
|
<input type="text" class="form-control" id="add_batch_number"
|
|
name="add_batch_number" placeholder="Batch number">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_expiry_date">
|
|
Expiry Date
|
|
</label>
|
|
<input type="date" class="form-control" id="add_expiry_date"
|
|
name="add_expiry_date">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_received_date">
|
|
Received Date <span class="text-danger">*</span>
|
|
</label>
|
|
<input type="date" class="form-control" id="add_received_date"
|
|
name="add_received_date" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_received_by">
|
|
Received By
|
|
</label>
|
|
<select class="form-select" id="add_received_by" name="add_received_by">
|
|
<option value="">Select staff member...</option>
|
|
{% for staff in pharmacy_staff %}
|
|
<option value="{{ staff.id }}" {% if staff.id == request.user.id %}selected{% endif %}>
|
|
{{ staff.get_full_name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-group mb-3">
|
|
<label class="form-label" for="add_notes">
|
|
Notes
|
|
</label>
|
|
<textarea class="form-control" id="add_notes" name="add_notes"
|
|
rows="3" placeholder="Additional notes about this stock addition..."></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cost Calculation -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card border-success" id="cost-calculation" style="display: none;">
|
|
<div class="card-header bg-success text-white">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fas fa-calculator me-2"></i>Cost Calculation
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row text-center">
|
|
<div class="col-md-3">
|
|
<div class="calc-item">
|
|
<small class="text-muted">Quantity</small>
|
|
<h5 class="mb-0" id="calc-quantity">0</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="calc-item">
|
|
<small class="text-muted">Unit Cost</small>
|
|
<h5 class="mb-0" id="calc-unit-cost">$0.00</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="calc-item">
|
|
<small class="text-muted">Total Cost</small>
|
|
<h5 class="mb-0 text-success" id="calc-total-cost">$0.00</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="calc-item">
|
|
<small class="text-muted">New Stock</small>
|
|
<h5 class="mb-0 text-primary" id="calc-new-stock">0</h5>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Alerts -->
|
|
<div id="add-stock-alerts" style="display: none;">
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<span id="alert-message">Alert message</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
<i class="fas fa-times me-1"></i>Cancel
|
|
</button>
|
|
<button type="submit" class="btn btn-success" id="add-submit-btn" disabled>
|
|
<i class="fas fa-plus me-1"></i>Add Stock
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize add stock modal
|
|
$('#addStockModal').on('show.bs.modal', function(event) {
|
|
const button = $(event.relatedTarget);
|
|
const itemId = button.data('item-id');
|
|
const itemName = button.data('item-name');
|
|
const itemCode = button.data('item-code');
|
|
const itemCategory = button.data('item-category');
|
|
const itemLocation = button.data('item-location');
|
|
const currentStock = button.data('current-stock');
|
|
const stockUnit = button.data('stock-unit');
|
|
|
|
// Update modal content
|
|
$('#add-item-name').text(itemName);
|
|
$('#add-item-code').text(itemCode);
|
|
$('#add-item-category').text(itemCategory);
|
|
$('#add-item-location').text(itemLocation);
|
|
$('#add-current-stock').text(currentStock);
|
|
$('#add-stock-unit').text(stockUnit);
|
|
$('#add-quantity-unit').text(stockUnit);
|
|
|
|
// Store item data
|
|
$('#addStockForm').data('item-id', itemId);
|
|
$('#addStockForm').data('current-stock', currentStock);
|
|
$('#addStockForm').data('stock-unit', stockUnit);
|
|
|
|
// Set default received date to today
|
|
const today = new Date().toISOString().split('T')[0];
|
|
$('#add_received_date').val(today);
|
|
|
|
// Reset form
|
|
$('#addStockForm')[0].reset();
|
|
$('#add_received_date').val(today);
|
|
$('#cost-calculation').hide();
|
|
$('#add-stock-alerts').hide();
|
|
$('#add-submit-btn').prop('disabled', true);
|
|
});
|
|
|
|
// Handle input changes for calculation
|
|
$('#add_quantity, #add_unit_cost').on('input', function() {
|
|
updateCostCalculation();
|
|
});
|
|
|
|
// Handle form validation
|
|
$('#add_quantity, #add_received_date').on('input change', function() {
|
|
validateAddForm();
|
|
});
|
|
|
|
// Handle expiry date validation
|
|
$('#add_expiry_date').on('change', function() {
|
|
const expiryDate = new Date($(this).val());
|
|
const today = new Date();
|
|
|
|
if (expiryDate <= today) {
|
|
$('#alert-message').text('Warning: The expiry date is in the past or today.');
|
|
$('#add-stock-alerts .alert').removeClass('alert-info').addClass('alert-warning');
|
|
$('#add-stock-alerts').show();
|
|
} else {
|
|
$('#add-stock-alerts').hide();
|
|
}
|
|
});
|
|
|
|
// Form submission
|
|
$('#addStockForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = new FormData(this);
|
|
const itemId = $(this).data('item-id');
|
|
|
|
// Add item ID to form data
|
|
formData.append('item_id', itemId);
|
|
|
|
// Show loading state
|
|
const submitBtn = $('#add-submit-btn');
|
|
const originalText = submitBtn.html();
|
|
submitBtn.html('<i class="fas fa-spinner fa-spin me-1"></i>Adding...').prop('disabled', true);
|
|
|
|
$.ajax({
|
|
url: '',
|
|
method: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(response) {
|
|
if (response.success) {
|
|
// Show success message
|
|
showToast('success', 'Stock added successfully');
|
|
|
|
// Close modal
|
|
$('#addStockModal').modal('hide');
|
|
|
|
// Refresh page or update stock display
|
|
if (typeof refreshStockData === 'function') {
|
|
refreshStockData();
|
|
} else {
|
|
location.reload();
|
|
}
|
|
} else {
|
|
showToast('error', response.message || 'Error adding stock');
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
let errorMessage = 'Error adding stock';
|
|
if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
errorMessage = xhr.responseJSON.message;
|
|
}
|
|
showToast('error', errorMessage);
|
|
},
|
|
complete: function() {
|
|
// Restore button state
|
|
submitBtn.html(originalText).prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
function updateCostCalculation() {
|
|
const quantity = parseFloat($('#add_quantity').val()) || 0;
|
|
const unitCost = parseFloat($('#add_unit_cost').val()) || 0;
|
|
const currentStock = parseFloat($('#addStockForm').data('current-stock')) || 0;
|
|
|
|
if (quantity > 0) {
|
|
const totalCost = quantity * unitCost;
|
|
const newStock = currentStock + quantity;
|
|
|
|
// Update calculation display
|
|
$('#calc-quantity').text(quantity);
|
|
$('#calc-unit-cost').text('$' + unitCost.toFixed(2));
|
|
$('#calc-total-cost').text('$' + totalCost.toFixed(2));
|
|
$('#calc-new-stock').text(newStock);
|
|
|
|
// Show calculation
|
|
$('#cost-calculation').show();
|
|
} else {
|
|
$('#cost-calculation').hide();
|
|
}
|
|
}
|
|
|
|
function validateAddForm() {
|
|
const quantity = parseFloat($('#add_quantity').val()) || 0;
|
|
const receivedDate = $('#add_received_date').val();
|
|
|
|
const isValid = quantity > 0 && receivedDate;
|
|
|
|
$('#add-submit-btn').prop('disabled', !isValid);
|
|
|
|
if (isValid) {
|
|
$('#add-submit-btn').removeClass('btn-outline-success').addClass('btn-success');
|
|
} else {
|
|
$('#add-submit-btn').removeClass('btn-success').addClass('btn-outline-success');
|
|
}
|
|
}
|
|
|
|
function showToast(type, message) {
|
|
// Simple toast notification
|
|
const toastClass = type === 'success' ? 'alert-success' : 'alert-danger';
|
|
const toastHtml = `
|
|
<div class="alert ${toastClass} alert-dismissible fade show position-fixed"
|
|
style="top: 20px; right: 20px; z-index: 9999;">
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
`;
|
|
$('body').append(toastHtml);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(function() {
|
|
$('.alert').fadeOut();
|
|
}, 5000);
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.calc-item {
|
|
padding: 10px;
|
|
border-right: 1px solid #dee2e6;
|
|
}
|
|
|
|
.calc-item:last-child {
|
|
border-right: none;
|
|
}
|
|
|
|
.current-stock {
|
|
text-align: center;
|
|
padding: 10px;
|
|
background: #f8f9fa;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
#cost-calculation .card-body {
|
|
padding: 15px;
|
|
}
|
|
|
|
.modal-lg {
|
|
max-width: 800px;
|
|
}
|
|
|
|
/* Mobile responsive */
|
|
@media (max-width: 768px) {
|
|
.calc-item {
|
|
border-right: none;
|
|
border-bottom: 1px solid #dee2e6;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.calc-item:last-child {
|
|
border-bottom: none;
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
</style>
|
|
|