devsofttech_hms_ci4/app/Views/medical/invoice_edit.php

970 lines
50 KiB
PHP

<?php $isIpdInvoice = ((int)($invoice->ipd_id ?? 0) > 0); ?>
<div class="row g-3">
<div class="<?= $isIpdInvoice ? 'col-lg-12' : 'col-lg-8' ?>">
<div class="card border-danger">
<div class="card-header bg-danger text-white d-flex justify-content-between align-items-center flex-wrap gap-2">
<h5 class="mb-0">Medical Invoice No. <?= esc($invoice->inv_med_code ?? ('M' . date('ym') . str_pad(substr((string) ((int)($invoice->id ?? 0)), -7, 7), 7, '0', STR_PAD_LEFT))) ?></h5>
<div class="d-flex gap-1 ms-auto">
<?php if ((int)($invoice->ipd_id ?? 0) > 0): ?>
<button type="button" class="btn btn-secondary btn-sm" onclick="javascript:load_form_div('<?= base_url('Medical/list_med_inv/' . (int)($invoice->ipd_id ?? 0)) ?>','medical-main');">Back to IPD Invoice List</button>
<?php endif; ?>
<button type="button" class="btn btn-warning btn-sm" onclick="javascript:load_form_div('<?= base_url('Medical/edit_invoice_edit/' . (int)($invoice->id ?? 0)) ?>','medical-main');">Edit Invoice Header</button>
<button type="button" class="btn btn-success btn-sm" onclick="javascript:load_form_div('<?= base_url('Medical/invoice_edit/' . (int)($invoice->id ?? 0)) ?>','medical-main');">Refresh Invoice</button>
</div>
</div>
<div class="card-body pt-3">
<?php if (!empty($message)): ?>
<div class="alert alert-info py-2"><?= esc($message) ?></div>
<?php endif; ?>
<div id="invoice-ajax-notice" class="alert py-2 d-none" role="alert"></div>
<?php if (!empty($isFinalized)): ?>
<div class="alert alert-warning py-2">Invoice is finalized. Edit actions are locked.</div>
<?php endif; ?>
<div class="small mb-2">
<strong>Name :</strong> <?= esc($invoice->inv_name ?? '-') ?> /
<strong>P Code :</strong> <?= esc($invoice->patient_code ?? '-') ?> /
<?php if ((int)($invoice->ipd_id ?? 0) > 0): ?>
<strong>IPD ID :</strong> <?= esc((string) ((int)($invoice->ipd_id ?? 0))) ?> /
<?php endif; ?>
<strong>Invoice No. :</strong> <?= esc($invoice->inv_med_code ?? ('M' . date('ym') . str_pad(substr((string) ((int)($invoice->id ?? 0)), -7, 7), 7, '0', STR_PAD_LEFT))) ?> /
<strong>Date :</strong> <?= esc(!empty($invoice->inv_date) ? date('d/m/Y', strtotime((string)$invoice->inv_date)) : '-') ?>
</div>
<?php if (empty($isFinalized)): ?>
<?php
$currentDocId = (int) ($invoice->doc_id ?? 0);
$currentDocName = trim((string) ($invoice->doc_name ?? ''));
$docFound = false;
if (!empty($docList) && $currentDocId > 0) {
foreach ($docList as $d) {
if ((int) ($d->id ?? 0) === $currentDocId) {
$docFound = true;
break;
}
}
}
// Auto-match doctor by name if doc_id is 0 or unassigned
if (!$docFound && !empty($docList) && $currentDocName !== '') {
$cleanCurrentDoc = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $currentDocName));
foreach ($docList as $d) {
$dName = trim((string) ($d->p_fname ?? ''));
$cleanDName = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $dName));
if (strcasecmp($dName, $currentDocName) === 0 || strcasecmp($cleanDName, $cleanCurrentDoc) === 0) {
$currentDocId = (int) ($d->id ?? 0);
$currentDocName = $dName;
$docFound = true;
break;
}
}
}
// If not found in hospital doctors list but doctor name exists, treat as outside doctor
$isOtherDoc = (!$docFound && ($currentDocId === 0 || $currentDocId === 999999) && $currentDocName !== '');
?>
<div class="row g-2 mb-3 align-items-end" id="invoice-doctor-panel">
<input type="hidden" name="doc_id" id="hidden_doc_id" value="<?= $currentDocId ?>">
<input type="hidden" name="doc_name" id="hidden_doc_name" value="<?= esc($currentDocName) ?>">
<div class="col-md-4 col-sm-6">
<label class="form-label form-label-sm mb-1 fw-bold text-secondary">
<i class="bi bi-person-badge"></i> Doctor
</label>
<select id="invoice_doc_select" class="form-select form-select-sm">
<option value="">-- Select Doctor --</option>
<?php foreach (($docList ?? []) as $doc): ?>
<?php
$dId = (int) ($doc->id ?? 0);
$dName = trim((string) ($doc->p_fname ?? ('Doctor #' . $dId)));
$isSelected = (!$isOtherDoc && $currentDocId === $dId);
?>
<option value="<?= $dId ?>" data-name="<?= esc($dName) ?>" <?= $isSelected ? 'selected' : '' ?>>
<?= esc($dName) ?>
</option>
<?php endforeach; ?>
<option value="other" <?= $isOtherDoc ? 'selected' : '' ?>>Outside Doctor / Other</option>
</select>
</div>
<div class="col-md-4 col-sm-6" id="wrap_doc_other" style="<?= $isOtherDoc ? '' : 'display: none;' ?>">
<label class="form-label form-label-sm mb-1 fw-bold text-secondary">
<i class="bi bi-pencil-square"></i> Outside Doctor Name
</label>
<div class="input-group input-group-sm">
<input type="text" id="input_doc_other" class="form-control form-control-sm" placeholder="Enter Doctor Name" value="<?= $isOtherDoc ? esc($currentDocName) : '' ?>">
<button type="button" id="btn_save_doc_other" class="btn btn-outline-primary btn-sm" title="Save Doctor">Save</button>
</div>
</div>
<div class="col-auto">
<span id="doc_save_indicator" class="badge bg-success-subtle text-success border border-success-subtle py-1 px-2 d-none">
<i class="bi bi-check-circle-fill"></i> Saved
</span>
</div>
</div>
<?php else: ?>
<div class="small mb-2 text-muted">
<strong>Doctor :</strong> <span class="badge bg-light text-dark border"><?= esc($invoice->doc_name ?: 'Not Specified') ?></span>
</div>
<?php endif; ?>
<div id="show_item_list" class="table-responsive mb-3">
<table class="table table-sm table-bordered align-middle mb-0">
<thead>
<tr>
<th>#</th>
<th>Item Name</th>
<th>Batch No</th>
<th>Exp.</th>
<th class="text-end">Rate</th>
<th class="text-end">S.Qty.</th>
<th class="text-end">Qty</th>
<th class="text-end">Disc.</th>
<th class="text-end">Amount</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php
$itemCodeCounts = [];
if (!empty($items)) {
foreach ($items as $tmpItem) {
$codeKey = (string) ($tmpItem->item_code ?? '');
if ($codeKey !== '') {
$itemCodeCounts[$codeKey] = ($itemCodeCounts[$codeKey] ?? 0) + 1;
}
}
}
?>
<?php if (!empty($items)): ?>
<?php foreach ($items as $i => $item): ?>
<?php
$rowStyle = '';
$itemNameStyle = '';
$isReturnRow = ((int) ($item->sale_return ?? 0) === 1)
|| ((float) ($item->amount ?? 0) < 0)
|| ((float) ($item->tamount ?? 0) < 0)
|| ((float) ($item->twdisc_amount ?? 0) < 0);
if ($isReturnRow) {
$rowStyle = 'background:orange;';
}
$expiryDays = 1000;
if (!empty($item->expiry)) {
$expiryTs = strtotime((string) $item->expiry);
if ($expiryTs !== false) {
$expiryDays = (int) floor(($expiryTs - strtotime(date('Y-m-d'))) / 86400);
}
}
if ($expiryDays < 90) {
$rowStyle = 'color:red;';
}
$sQty = (float) ($item->s_qty ?? 0);
if ($sQty < 6) {
$rowStyle = 'color:red;';
}
$itemCode = (string) ($item->item_code ?? '');
if ($itemCode !== '' && (int) ($itemCodeCounts[$itemCode] ?? 0) > 1) {
$itemNameStyle = 'color:green;';
}
?>
<tr<?= $rowStyle !== '' ? ' style="' . esc($rowStyle, 'attr') . '"' : '' ?>>
<td><?= $i + 1 ?></td>
<td<?= $itemNameStyle !== '' ? ' style="' . esc($itemNameStyle, 'attr') . '"' : '' ?>><?= esc($item->item_Name ?? '-') ?></td>
<td><?= esc($item->batch_no ?? '-') ?></td>
<td><?= esc(!empty($item->expiry) ? date('Y-m-d', strtotime((string)$item->expiry)) : '-') ?></td>
<td class="text-end"><?= esc(number_format((float)($item->price ?? 0), 2)) ?></td>
<td class="text-end"><?= esc(number_format((float)($item->qty ?? 0), 0, '.', '')) ?></td>
<td class="text-end">
<?php if (empty($isFinalized) && (int)($item->sale_return ?? 0) === 0): ?>
<form method="post" action="<?= base_url('Medical/update_item_qty') ?>" class="d-inline-flex gap-1 align-items-center quick-qty-form m-0">
<?= csrf_field() ?>
<input type="hidden" name="inv_id" value="<?= (int)($invoice->id ?? 0) ?>">
<input type="hidden" name="item_id" value="<?= (int)($item->id ?? 0) ?>">
<input type="number" name="u_qty" value="<?= esc(number_format((float)($item->qty ?? 0), 0, '.', '')) ?>" min="1" step="1" class="form-control form-control-sm" style="width:65px;">
<button class="btn btn-sm btn-outline-info" type="submit">✎</button>
</form>
<?php else: ?>
<?= esc(number_format((float)($item->qty ?? 0), 2)) ?>
<?php endif; ?>
</td>
<td class="text-end"><?= esc(number_format((float)($item->disc_amount ?? 0), 2)) ?></td>
<td class="text-end"><?= esc(number_format((float)($item->tamount ?? 0), 2)) ?></td>
<td>
<?php if (empty($isFinalized)): ?>
<form method="post" action="<?= base_url('Medical/remove_item') ?>" class="m-0 quick-remove-form">
<?= csrf_field() ?>
<input type="hidden" name="inv_id" value="<?= (int)($invoice->id ?? 0) ?>">
<input type="hidden" name="item_id" value="<?= (int)($item->id ?? 0) ?>">
<button class="btn btn-sm btn-outline-danger" type="submit">✖</button>
</form>
<?php else: ?>
<span class="text-muted small">Locked</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="10" class="text-center text-muted">No items in invoice.</td>
</tr>
<?php endif; ?>
</tbody>
<tfoot>
<tr>
<th colspan="8" class="text-end">Gross Total</th>
<th class="text-end"><?= esc(number_format((float)($totals->gross ?? 0), 2)) ?></th>
<th></th>
</tr>
<tr>
<th colspan="8" class="text-end">Net Total</th>
<th class="text-end"><?= esc(number_format((float)($totals->net ?? 0), 2)) ?></th>
<th></th>
</tr>
</tfoot>
</table>
</div>
<?php if (empty($isFinalized)): ?>
<div class="border-top pt-3">
<h6 class="mb-2">Product Search</h6>
<div class="card border-secondary mb-3">
<div class="card-body py-2">
<div class="row g-2 align-items-center mb-2">
<div class="col-md-8">
<label class="form-label form-label-sm mb-1">Product Search:</label>
<input class="form-control form-control-sm" name="input_drug" id="input_drug" placeholder="Like Item Code , Item Name" type="text" autocomplete="off">
</div>
<div class="col-md-4">
<span class="text-muted" id="input_product_code"></span>
</div>
</div>
<input type="hidden" id="l_ssno" name="l_ssno" value="0">
<input type="hidden" id="item_code" name="item_code" value="">
<input type="hidden" id="hid_expiry_alert" name="hid_expiry_alert" value="">
<input type="hidden" id="hid_c_qty" name="hid_c_qty" value="0">
<p class="mb-2 small">
<span class="text-success" id="input_product_name"></span>
<span class="text-info" id="input_batch"></span>
<span class="text-danger" id="input_product_mrp"></span>
<span class="text-warning" id="stock_product_qty"></span>
</p>
<form method="post" action="<?= base_url('Medical/add_item') ?>" class="row g-2 align-items-end" id="auto-add-form">
<?= csrf_field() ?>
<input type="hidden" name="inv_id" value="<?= (int)($invoice->id ?? 0) ?>">
<input type="hidden" name="stock_id" id="stock_id_input" value="0">
<div class="col-md-3">
<label class="form-label form-label-sm mb-1">Unit Rate</label>
<input class="form-control form-control-sm" name="input_product_unit_rate" id="input_product_unit_rate" placeholder="Unit Rate" autocomplete="off" readonly>
</div>
<div class="col-md-4">
<label class="form-label form-label-sm mb-1">Qty</label>
<input class="form-control form-control-sm" name="qty" id="input_product_qty" placeholder="Qty" type="number" min="1" step="1" value="" autocomplete="off" required>
</div>
<div class="col-md-3">
<label class="form-label form-label-sm mb-1">Disc %</label>
<input class="form-control form-control-sm" name="disc_per" id="input_disc" placeholder="Discount %" type="number" min="0" max="100" value="0" autocomplete="off">
</div>
<div class="col-md-2">
<button class="btn btn-sm btn-primary w-100" type="submit" id="additem" disabled>Add</button>
</div>
</form>
</div>
</div>
<?php if (!empty($stockRows)): ?>
<div class="table-responsive mb-2">
<table class="table table-sm table-striped align-middle mb-0">
<thead>
<tr>
<th>Item</th>
<th>Batch</th>
<th>Exp.</th>
<th class="text-end">S.Qty</th>
<th class="text-end">Rate</th>
<th>Add</th>
</tr>
</thead>
<tbody>
<?php foreach ($stockRows as $row): ?>
<tr>
<td><?= esc($row->item_name ?? '-') ?></td>
<td><?= esc($row->batch_no ?? '-') ?></td>
<td><?= esc($row->expiry_date ?? '-') ?></td>
<td class="text-end"><?= esc($row->current_qty ?? 0) ?></td>
<td class="text-end"><?= esc(number_format((float)($row->selling_unit_rate ?? 0), 2)) ?></td>
<td>
<form method="post" action="<?= base_url('Medical/add_item') ?>" class="d-flex gap-1 align-items-center quick-add-form">
<?= csrf_field() ?>
<input type="hidden" name="inv_id" value="<?= (int)($invoice->id ?? 0) ?>">
<input type="hidden" name="stock_id" value="<?= (int)($row->stock_id ?? 0) ?>">
<input type="number" name="qty" value="1" min="1" step="1" class="form-control form-control-sm" style="width:80px;">
<input type="number" name="disc_per" value="0" min="0" max="100" class="form-control form-control-sm" style="width:90px;" title="Disc %">
<button class="btn btn-sm btn-primary" type="submit">Add</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php elseif (!empty($query)): ?>
<div class="text-muted small">No stock items found for search.</div>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="d-flex gap-2 mt-3">
<?php if (empty($isFinalized)): ?>
<a class="btn btn-success btn-sm" href="javascript:load_form_div('<?= base_url('Medical/final_invoice/' . (int)($invoice->id ?? 0)) ?>','medical-main');">Final Invoice</a>
<?php endif; ?>
<a class="btn btn-outline-dark btn-sm" target="_blank" href="<?= base_url('Medical/invoice_print/' . (int)($invoice->id ?? 0)) ?>">PDF Bill</a>
</div>
</div>
</div>
</div>
<?php if (!$isIpdInvoice): ?>
<div class="col-lg-4">
<div class="card border-info">
<div class="card-header bg-info text-white">
<div class="d-flex justify-content-between align-items-center mb-2">
<h5 class="mb-0">Sale Medicine</h5>
<div class="d-flex gap-1">
<button type="button" class="btn btn-warning btn-sm" onclick="window.scrollTo({top:0,behavior:'smooth'})">Search OLD</button>
<button type="button" class="btn btn-success btn-sm" onclick="window.scrollTo({top:0,behavior:'smooth'})">Search Panel</button>
</div>
</div>
</div>
<div class="card-body pt-2">
<?php if (!empty($invoice->patient_id) && !empty($oldInvoices)): ?>
<div style="max-height: 78vh; overflow:auto;">
<?php foreach ($oldInvoices as $old): ?>
<?php $oldInvId = (int)($old->id ?? 0); ?>
<table class="table table-sm table-bordered mb-2">
<thead>
<tr class="table-warning">
<th>#</th>
<th><?= esc($old->inv_med_code ?? ('M' . date('ym') . str_pad(substr((string) $oldInvId, -7, 7), 7, '0', STR_PAD_LEFT))) ?></th>
<th><?= esc(!empty($old->inv_date) ? date('Y-m-d', strtotime((string)$old->inv_date)) : '-') ?></th>
<th colspan="3" class="text-end">
<a class="btn btn-sm btn-outline-dark" href="javascript:load_form('<?= base_url('Medical/invoice_edit/' . $oldInvId) ?>','Medical Invoice');">Show Bill</a>
</th>
</tr>
<tr>
<th>#</th>
<th>Item</th>
<th>Bat.</th>
<th>Exp.Dt</th>
<th>Qty</th>
<th>R.Qty</th>
</tr>
</thead>
<tbody>
<?php if (!empty($old->_items)): ?>
<?php foreach ($old->_items as $n => $oldItem): ?>
<tr>
<td><?= (int)$n + 1 ?></td>
<td><?= esc($oldItem->item_Name ?? '-') ?></td>
<td><?= esc($oldItem->batch_no ?? '-') ?></td>
<td><?= esc(!empty($oldItem->expiry) ? date('m-Y', strtotime((string)$oldItem->expiry)) : '-') ?></td>
<td><?= esc(number_format((float)($oldItem->qty ?? 0), 0)) ?></td>
<td>
<?php if (empty($isFinalized) && !empty($oldItem->id)): ?>
<form method="post" action="<?= base_url('Medical/add_remove_item') ?>" class="d-flex gap-1 align-items-center quick-return-form m-0">
<?= csrf_field() ?>
<input type="hidden" name="inv_id" value="<?= (int)($invoice->id ?? 0) ?>">
<input type="hidden" name="itemid" value="<?= (int)($oldItem->id ?? 0) ?>">
<input type="number" name="rqty" value="1" min="1" step="1" class="form-control form-control-sm" style="width:60px;">
<button class="btn btn-sm btn-outline-danger" type="submit">⊖</button>
</form>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6" class="text-center text-muted">No item rows.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<?php endforeach; ?>
</div>
<?php elseif (!empty($invoice->patient_id)): ?>
<div class="text-muted">No old invoices for this patient.</div>
<?php else: ?>
<div class="text-muted">Walk-in invoice. Previous patient history is unavailable.</div>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script>
(function () {
var invoiceId = <?= (int)($invoice->id ?? 0) ?>;
function refreshInvoicePanel() {
if (typeof load_form_div === 'function') {
load_form_div('<?= base_url('Medical/invoice_edit/' . (int)($invoice->id ?? 0)) ?>', 'medical-main');
return;
}
window.location.href = '<?= base_url('Medical/invoice_edit/' . (int)($invoice->id ?? 0)) ?>';
}
function markFocusAfterReload() {
try {
window.sessionStorage.setItem('medical_invoice_focus_after_add', '1');
} catch (e) {}
}
function storeNoticeAfterReload(type, text) {
try {
window.sessionStorage.setItem('medical_invoice_notice_type', type || 'info');
window.sessionStorage.setItem('medical_invoice_notice_text', text || '');
} catch (e) {}
}
function showInlineNotice(type, text) {
var box = document.getElementById('invoice-ajax-notice');
if (!box) {
return;
}
box.classList.remove('d-none', 'alert-success', 'alert-danger', 'alert-info', 'alert-warning');
if (type === 'success') {
box.classList.add('alert-success');
} else if (type === 'danger') {
box.classList.add('alert-danger');
} else if (type === 'warning') {
box.classList.add('alert-warning');
} else {
box.classList.add('alert-info');
}
box.textContent = text || '';
}
function consumeNoticeAfterReload() {
var text = '';
var type = 'info';
try {
text = window.sessionStorage.getItem('medical_invoice_notice_text') || '';
type = window.sessionStorage.getItem('medical_invoice_notice_type') || 'info';
window.sessionStorage.removeItem('medical_invoice_notice_text');
window.sessionStorage.removeItem('medical_invoice_notice_type');
} catch (e) {}
if (text) {
showInlineNotice(type, text);
}
}
function focusProductSearchIfMarked() {
var shouldFocus = false;
try {
shouldFocus = window.sessionStorage.getItem('medical_invoice_focus_after_add') === '1';
if (shouldFocus) {
window.sessionStorage.removeItem('medical_invoice_focus_after_add');
}
} catch (e) {}
if (!shouldFocus) {
return;
}
setTimeout(function () {
var inputDrug = document.getElementById('input_drug');
if (!inputDrug) {
return;
}
inputDrug.focus();
if (typeof inputDrug.select === 'function') {
inputDrug.select();
}
}, 120);
}
function ajaxSubmitForm(form, done) {
var formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(function () {
if (typeof done === 'function') {
done(true);
}
}).catch(function () {
if (typeof done === 'function') {
done(false);
}
});
}
function ajaxSubmitReturnForm(form, done) {
var formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(function (response) {
return response.json();
}).then(function (data) {
if (typeof done === 'function') {
done(true, data || {});
}
}).catch(function () {
if (typeof done === 'function') {
done(false, null);
}
});
}
function ensureJqueryUi(callback) {
if (!window.jQuery) {
return;
}
if (window.jQuery.ui && window.jQuery.ui.autocomplete) {
callback();
return;
}
if (!document.getElementById('jq-ui-css')) {
var css = document.createElement('link');
css.id = 'jq-ui-css';
css.rel = 'stylesheet';
css.href = '<?= base_url('assets/vendor/jquery-ui/jquery-ui.min.css') ?>';
document.head.appendChild(css);
}
if (document.getElementById('jq-ui-js')) {
setTimeout(function () { ensureJqueryUi(callback); }, 100);
return;
}
var script = document.createElement('script');
script.id = 'jq-ui-js';
script.src = '<?= base_url('assets/vendor/jquery-ui/jquery-ui.min.js') ?>';
script.onload = callback;
document.body.appendChild(script);
}
function setAutoItem(item) {
var stockInput = document.getElementById('l_ssno');
var stockIdInput = document.getElementById('stock_id_input');
var addBtn = document.getElementById('additem');
var qtyInput = document.getElementById('input_product_qty');
var unitRateInput = document.getElementById('input_product_unit_rate');
var itemCodeInput = document.getElementById('item_code');
document.getElementById('input_product_code').innerHTML = '| Product Code: ' + (item.l_item_code || '-');
document.getElementById('input_product_name').innerHTML = 'Name: ' + (item.value || '-');
document.getElementById('input_batch').innerHTML = ' | Batch No.: ' + (item.l_Batch || '-') + ' | Exp.Dt: ' + (item.l_Expiry || '-');
document.getElementById('input_product_mrp').innerHTML = ' | MRP: ' + (item.l_mrp || '-') + ' | Unit Rate: ' + (item.l_unit_rate || '-');
document.getElementById('stock_product_qty').innerHTML = ' |Qty : ' + (item.l_c_qty || '-') + ' |Pak : ' + (item.l_packing || '-');
document.getElementById('hid_expiry_alert').value = item.expiry_alert || '';
document.getElementById('hid_c_qty').value = item.l_c_qty || '';
if (stockInput) {
stockInput.value = item.l_ss_no || 0;
}
if (stockIdInput) {
stockIdInput.value = item.l_ss_no || 0;
}
if (unitRateInput) {
unitRateInput.value = item.l_unit_rate || '';
}
if (itemCodeInput) {
itemCodeInput.value = item.item_code || '';
}
if (addBtn) {
addBtn.disabled = !item.l_ss_no;
}
if (qtyInput) {
qtyInput.value = '';
qtyInput.focus();
}
}
function initDrugAutocomplete() {
if (!window.jQuery || !window.jQuery.ui || !window.jQuery.ui.autocomplete) {
return;
}
var $ = window.jQuery;
$("#input_drug").autocomplete({
source: function (request, response) {
$.getJSON("<?= base_url('Medical/get_drug') ?>", request, function (data) {
response(data || []);
});
},
minLength: 1,
autofocus: true,
select: function (event, ui) {
setAutoItem(ui.item || {});
}
}).autocomplete("instance")._renderItem = function (ul, item) {
var label = item.label || '';
if ((item.l_new_stock || '0') > 0) {
label = ' 💡 ' + label;
}
if (parseFloat(item.expiry_alert || '999') < 2) {
return $("<li class='ui-state-disabled'>")
.append("<div>" + label + "<br>" + (item.desc || '') + "</div>")
.appendTo(ul);
}
return $("<li>")
.append("<div>" + label + "<br>" + (item.desc || '') + "</div>")
.appendTo(ul);
};
}
ensureJqueryUi(initDrugAutocomplete);
focusProductSearchIfMarked();
consumeNoticeAfterReload();
var forms = document.querySelectorAll('.quick-add-form');
forms.forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
var button = form.querySelector('button[type="submit"]');
if (button) {
button.disabled = true;
}
ajaxSubmitForm(form, function (ok) {
if (!ok) {
if (button) {
button.disabled = false;
}
alert('Unable to add item. Please try again.');
return;
}
markFocusAfterReload();
refreshInvoicePanel();
});
});
});
var removeForms = document.querySelectorAll('.quick-remove-form');
removeForms.forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
var button = form.querySelector('button[type="submit"]');
if (button) {
button.disabled = true;
}
ajaxSubmitForm(form, function (ok) {
if (!ok) {
if (button) {
button.disabled = false;
}
alert('Unable to remove item. Please try again.');
return;
}
refreshInvoicePanel();
});
});
});
var qtyForms = document.querySelectorAll('.quick-qty-form');
qtyForms.forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
var qtyInput = form.querySelector('input[name="u_qty"]');
var qtyValue = parseFloat((qtyInput && qtyInput.value) ? qtyInput.value : '0');
if (!qtyValue || qtyValue <= 0) {
showInlineNotice('danger', 'Enter valid Qty greater than 0.');
if (qtyInput) {
qtyInput.focus();
}
return;
}
var button = form.querySelector('button[type="submit"]');
if (button) {
button.disabled = true;
}
ajaxSubmitReturnForm(form, function (ok, data) {
if (!ok) {
if (button) {
button.disabled = false;
}
showInlineNotice('danger', 'Unable to update qty. Please try again.');
return;
}
var updateValue = parseInt((data && data.update) ? data.update : '0', 10);
if (!updateValue) {
if (button) {
button.disabled = false;
}
showInlineNotice('danger', (data && data.msg_text) ? data.msg_text : 'Qty update failed.');
return;
}
storeNoticeAfterReload('success', (data && data.msg_text) ? data.msg_text : 'Qty updated.');
refreshInvoicePanel();
});
});
});
var returnForms = document.querySelectorAll('.quick-return-form');
returnForms.forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
var qtyInput = form.querySelector('input[name="rqty"]');
var qtyValue = parseFloat((qtyInput && qtyInput.value) ? qtyInput.value : '0');
if (!qtyValue || qtyValue <= 0) {
alert('Enter valid return Qty greater than 0.');
if (qtyInput) {
qtyInput.focus();
}
return;
}
var button = form.querySelector('button[type="submit"]');
if (button) {
button.disabled = true;
}
ajaxSubmitReturnForm(form, function (ok, data) {
if (!ok) {
if (button) {
button.disabled = false;
}
showInlineNotice('danger', 'Unable to process return item. Please try again.');
return;
}
var updateValue = parseInt((data && data.update) ? data.update : '0', 10);
if (!updateValue) {
if (button) {
button.disabled = false;
}
showInlineNotice('danger', (data && data.msg_text) ? data.msg_text : 'Return item was not added.');
return;
}
storeNoticeAfterReload('success', (data && data.msg_text) ? data.msg_text : 'Return item updated.');
refreshInvoicePanel();
});
});
});
var autoAddForm = document.getElementById('auto-add-form');
if (autoAddForm) {
autoAddForm.addEventListener('submit', function (event) {
var stockInput = document.getElementById('l_ssno');
var stockIdInput = document.getElementById('stock_id_input');
var addBtn = document.getElementById('additem');
var stockId = parseInt((stockInput && stockInput.value) ? stockInput.value : '0', 10);
if (!stockId && stockIdInput) {
stockId = parseInt(stockIdInput.value || '0', 10);
}
if (!stockId) {
event.preventDefault();
alert('Select medicine from autocomplete list.');
return;
}
var qtyInput = document.getElementById('input_product_qty');
var rawQty = (qtyInput && qtyInput.value) ? qtyInput.value.trim() : '';
var qtyValue = parseFloat(rawQty || '0');
if (!rawQty || isNaN(qtyValue) || qtyValue <= 0) {
event.preventDefault();
alert('Please enter valid Qty greater than 0.');
if (qtyInput) {
qtyInput.value = '';
qtyInput.focus();
}
return;
}
if (addBtn) {
addBtn.disabled = true;
}
event.preventDefault();
ajaxSubmitForm(autoAddForm, function (ok) {
if (!ok) {
if (addBtn) {
addBtn.disabled = false;
}
alert('Unable to add item. Please try again.');
return;
}
markFocusAfterReload();
refreshInvoicePanel();
});
});
}
var inputDrug = document.getElementById('input_drug');
if (inputDrug) {
inputDrug.accessKey = 's';
}
var addBtn = document.getElementById('additem');
if (addBtn) {
addBtn.accessKey = 'i';
}
// Doctor Select & Outside Doctor AJAX save handler
(function () {
var docSelect = document.getElementById('invoice_doc_select');
var wrapOther = document.getElementById('wrap_doc_other');
var inputOther = document.getElementById('input_doc_other');
var btnSaveOther = document.getElementById('btn_save_doc_other');
var hiddenDocId = document.getElementById('hidden_doc_id');
var hiddenDocName = document.getElementById('hidden_doc_name');
var saveIndicator = document.getElementById('doc_save_indicator');
var invId = <?= (int) ($invoice->id ?? 0) ?>;
if (!docSelect || !invId) {
return;
}
function showSaveStatus(text, isError) {
if (!saveIndicator) return;
saveIndicator.classList.remove('d-none', 'bg-success-subtle', 'text-success', 'border-success-subtle', 'bg-danger-subtle', 'text-danger', 'border-danger-subtle');
if (isError) {
saveIndicator.classList.add('bg-danger-subtle', 'text-danger', 'border-danger-subtle');
saveIndicator.innerHTML = '<i class="bi bi-exclamation-circle-fill"></i> ' + (text || 'Error');
} else {
saveIndicator.classList.add('bg-success-subtle', 'text-success', 'border-success-subtle');
saveIndicator.innerHTML = '<i class="bi bi-check-circle-fill"></i> ' + (text || 'Saved');
}
setTimeout(function () {
if (saveIndicator) saveIndicator.classList.add('d-none');
}, 2500);
}
function updateDoctorAjax(docId, docName, onSuccess) {
var csrfInput = document.querySelector('input[name="<?= csrf_token() ?>"]');
var csrfHash = csrfInput ? csrfInput.value : '';
var body = new URLSearchParams();
body.append('<?= csrf_token() ?>', csrfHash);
body.append('med_invoice_id', String(invId));
body.append('doc_id', String(docId));
body.append('doc_name', String(docName || ''));
fetch('<?= base_url('Medical/update_doctor') ?>', {
method: 'POST',
body: body,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function (res) {
return res.json();
}).then(function (res) {
if (res && res.csrfHash) {
document.querySelectorAll('input[name="<?= csrf_token() ?>"]').forEach(function (inp) {
inp.value = res.csrfHash;
});
}
if (res && res.status) {
if (hiddenDocId) hiddenDocId.value = docId;
if (hiddenDocName) hiddenDocName.value = docName;
showSaveStatus(docId === 0 ? 'Outside Doctor Saved' : 'Doctor Updated', false);
if (typeof onSuccess === 'function') onSuccess();
} else {
showSaveStatus((res && res.remark) ? res.remark : 'Save Failed', true);
}
}).catch(function () {
showSaveStatus('Network Error', true);
});
}
docSelect.addEventListener('change', function () {
var val = docSelect.value;
if (val === 'other') {
if (wrapOther) {
wrapOther.style.display = '';
}
if (inputOther) {
inputOther.focus();
if (inputOther.value.trim() !== '') {
updateDoctorAjax(0, inputOther.value.trim());
}
}
} else if (val === '') {
if (wrapOther) {
wrapOther.style.display = 'none';
}
updateDoctorAjax(0, '');
} else {
if (wrapOther) {
wrapOther.style.display = 'none';
}
var opt = docSelect.options[docSelect.selectedIndex];
var docName = opt ? (opt.getAttribute('data-name') || opt.text.trim()) : '';
updateDoctorAjax(parseInt(val, 10), docName);
}
});
function saveOtherDoctor() {
if (!inputOther) return;
var otherName = inputOther.value.trim();
if (!otherName) {
inputOther.focus();
showSaveStatus('Enter Doctor Name', true);
return;
}
updateDoctorAjax(0, otherName);
}
if (btnSaveOther) {
btnSaveOther.addEventListener('click', saveOtherDoctor);
}
if (inputOther) {
inputOther.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
saveOtherDoctor();
}
});
inputOther.addEventListener('blur', function () {
if (docSelect.value === 'other' && inputOther.value.trim() !== '') {
saveOtherDoctor();
}
});
}
})();
})();
</script>