Allow editing GRN Inspection Details with full item reconciliation and live inventory synchronization

This commit is contained in:
DevSoftTech Server 2026-10-23 14:10:31 +05:30
parent 9236ff1da9
commit e946000fb9
7 changed files with 573 additions and 32 deletions

View File

@ -138,7 +138,10 @@ $routes->get('Medical/grn_list', 'MedicalProcurement::grn_list');
$routes->get('Medical/grn_new', 'MedicalProcurement::grn_new'); $routes->get('Medical/grn_new', 'MedicalProcurement::grn_new');
$routes->get('Medical/grn_new/(:num)', 'MedicalProcurement::grn_new/$1'); $routes->get('Medical/grn_new/(:num)', 'MedicalProcurement::grn_new/$1');
$routes->post('Medical/grn_create', 'MedicalProcurement::grn_create'); $routes->post('Medical/grn_create', 'MedicalProcurement::grn_create');
$routes->get('Medical/grn_detail/(:num)', 'MedicalProcurement::grn_detail/$1');
$routes->get('Medical/grn_edit/(:num)', 'MedicalProcurement::grn_edit/$1'); $routes->get('Medical/grn_edit/(:num)', 'MedicalProcurement::grn_edit/$1');
$routes->get('Medical/grn_modify/(:num)', 'MedicalProcurement::grn_edit/$1');
$routes->post('Medical/grn_update/(:num)', 'MedicalProcurement::grn_update/$1');
$routes->post('Medical/grn_post_inventory/(:num)', 'MedicalProcurement::grn_post_inventory/$1'); $routes->post('Medical/grn_post_inventory/(:num)', 'MedicalProcurement::grn_post_inventory/$1');
$routes->get('Medical/grn_print/(:num)', 'MedicalProcurement::grn_print/$1'); $routes->get('Medical/grn_print/(:num)', 'MedicalProcurement::grn_print/$1');

View File

@ -819,7 +819,7 @@ class MedicalProcurement extends BaseController
]); ]);
} }
public function grn_edit(int $grnId) public function grn_detail(int $grnId)
{ {
if ($deny = $this->ensurePharmacyAccess()) { if ($deny = $this->ensurePharmacyAccess()) {
return $deny; return $deny;
@ -845,6 +845,402 @@ class MedicalProcurement extends BaseController
]); ]);
} }
public function grn_edit(int $grnId)
{
if ($deny = $this->ensurePharmacyAccess()) {
return $deny;
}
if ($this->request->getGet('mode') === 'view') {
return $this->grn_detail($grnId);
}
$grn = $this->db->table('mst_grns grn')
->select('grn.*, s.name_supplier, po.po_number')
->join('med_supplier s', 's.sid = grn.supplier_id', 'left')
->join('mst_purchase_orders po', 'po.po_id = grn.po_id', 'left')
->where('grn.grn_id', $grnId)
->get()
->getRowArray();
if (!$grn) {
return view('medical/placeholder', ['title' => 'Goods Received Note Not Found']);
}
$items = $this->grnItemModel->where('grn_id', $grnId)->findAll();
$suppliers = $this->db->table('med_supplier')->orderBy('name_supplier', 'ASC')->get()->getResultArray();
$approvedPos = $this->poModel->orderBy('po_id', 'DESC')->findAll();
return view('medical/grn_form', [
'isEdit' => true,
'grn' => $grn,
'grnItems' => $items,
'suppliers' => $suppliers,
'approvedPos' => $approvedPos,
'selectedPo' => !empty($grn['po_id']) ? $this->poModel->find($grn['po_id']) : null,
'poItems' => [],
'nextGrnNumber' => $grn['grn_number'],
]);
}
public function grn_update(int $grnId)
{
if ($deny = $this->ensurePharmacyAccess()) {
return $deny;
}
$grn = $this->grnModel->find($grnId);
if (!$grn) {
return $this->response->setJSON(['status' => 0, 'message' => 'Goods Received Note not found.']);
}
$supplierId = (int)$this->request->getPost('supplier_id');
$poId = (int)$this->request->getPost('po_id');
$supplierInvoiceNo = trim((string)$this->request->getPost('supplier_invoice_no'));
$invoiceDate = $this->request->getPost('invoice_date');
$grnDate = $this->request->getPost('grn_date');
$gstType = $this->request->getPost('gst_type') === 'inter_state' ? 'inter_state' : 'intra_state';
$challanNo = trim((string)$this->request->getPost('challan_no'));
$remarks = trim((string)$this->request->getPost('remarks'));
$roundOff = (float)$this->request->getPost('round_off');
$syncInventory = (int)($this->request->getPost('sync_inventory') ?? $this->request->getPost('post_to_inventory') ?? 0);
$items = $this->request->getPost('items') ?? [];
if ($supplierId <= 0) {
return $this->response->setJSON(['status' => 0, 'message' => 'Please select a valid supplier/vendor.']);
}
if (empty($supplierInvoiceNo)) {
return $this->response->setJSON(['status' => 0, 'message' => 'Vendor invoice number is required.']);
}
if (empty($invoiceDate) || empty($grnDate)) {
return $this->response->setJSON(['status' => 0, 'message' => 'Please provide valid invoice and received dates.']);
}
if (empty($items) || !is_array($items)) {
return $this->response->setJSON(['status' => 0, 'message' => 'GRN must contain at least one medicine item.']);
}
$totalGross = 0.0;
$totalDisc = 0.0;
$totalTaxable = 0.0;
$totalCgst = 0.0;
$totalSgst = 0.0;
$totalIgst = 0.0;
$totalTax = 0.0;
$validItems = [];
foreach ($items as $idx => $it) {
$itemCode = !empty($it['item_code']) ? (int)$it['item_code'] : null;
$itemName = trim((string)($it['item_name'] ?? ''));
$batchNo = trim((string)($it['batch_no'] ?? ''));
$expiryDate = !empty($it['expiry_date']) ? date('Y-m-d', strtotime($it['expiry_date'])) : null;
$packing = max(1, (int)($it['packing'] ?? 1));
$receivedPacks = (float)($it['received_packs'] ?? 0);
$freePacks = (float)($it['free_packs'] ?? 0);
$unitPurchaseRate = (float)($it['unit_purchase_rate'] ?? 0);
$mrp = (float)($it['mrp'] ?? ($unitPurchaseRate * 1.3));
$sellingUnitRate = $packing > 0 ? round($mrp / $packing, 4) : $mrp;
if (empty($itemCode) || empty($itemName) || empty($batchNo) || empty($expiryDate)) {
continue;
}
$grossAmount = round($receivedPacks * $unitPurchaseRate, 2);
$discPercent = (float)($it['discount_percent'] ?? 0);
$schDiscPer = (float)($it['sch_disc_per'] ?? 0);
$schDiscAmt = (float)($it['sch_disc_amt'] ?? 0);
// Scheme discount
$schPerAmt = ($schDiscPer > 0) ? round($grossAmount * ($schDiscPer / 100), 2) : 0.0;
$lineSchDisc = $schPerAmt + $schDiscAmt;
$afterSch = max(0.0, $grossAmount - $lineSchDisc);
// Trade discount
$tradeDiscAmt = ($discPercent > 0) ? round($afterSch * ($discPercent / 100), 2) : 0.0;
$lineTaxable = max(0.0, round($afterSch - $tradeDiscAmt, 2));
$gstRate = (float)($it['gst_rate'] ?? 5);
if ($gstType === 'inter_state') {
$igstPer = $gstRate;
$cgstAmt = 0.0;
$sgstAmt = 0.0;
$igstAmt = round($lineTaxable * ($igstPer / 100), 2);
$lineTax = $igstAmt;
$cgstPer = 0.0;
$sgstPer = 0.0;
} else {
$cgstPer = round($gstRate / 2, 2);
$sgstPer = round($gstRate / 2, 2);
$igstPer = 0.0;
$cgstAmt = round($lineTaxable * ($cgstPer / 100), 2);
$sgstAmt = round($lineTaxable * ($sgstPer / 100), 2);
$igstAmt = 0.0;
$lineTax = $cgstAmt + $sgstAmt;
}
$lineTotal = round($lineTaxable + $lineTax, 2);
$totalGross += $grossAmount;
$totalDisc += ($lineSchDisc + $tradeDiscAmt);
$totalTaxable += $lineTaxable;
$totalCgst += $cgstAmt;
$totalSgst += $sgstAmt;
$totalIgst += $igstAmt;
$totalTax += $lineTax;
$validItems[] = [
'grn_item_id' => !empty($it['grn_item_id']) ? (int)$it['grn_item_id'] : 0,
'purchase_item_id' => !empty($it['purchase_item_id']) ? (int)$it['purchase_item_id'] : 0,
'po_item_id' => !empty($it['po_item_id']) ? (int)$it['po_item_id'] : null,
'item_code' => $itemCode,
'item_name' => $itemName,
'batch_no' => $batchNo,
'expiry_date' => $expiryDate,
'packing' => $packing,
'order_packs' => (float)($it['order_packs'] ?? 0),
'received_packs' => $receivedPacks,
'free_packs' => $freePacks,
'rejected_packs' => (float)($it['rejected_packs'] ?? 0),
'rejection_reason' => $it['rejection_reason'] ?? null,
'unit_purchase_rate' => $unitPurchaseRate,
'gross_amount' => $grossAmount,
'mrp' => $mrp,
'selling_unit_rate' => $sellingUnitRate,
'discount_percent' => $discPercent,
'sch_disc_per' => $schDiscPer,
'sch_disc_amt' => $schDiscAmt,
'taxable_amount' => $lineTaxable,
'cgst_percent' => $cgstPer,
'cgst_amount' => $cgstAmt,
'sgst_percent' => $sgstPer,
'sgst_amount' => $sgstAmt,
'igst_percent' => $igstPer,
'igst_amount' => $igstAmt,
'hsn_code' => !empty($it['hsn_code']) ? $it['hsn_code'] : '3004',
'total_amount' => $lineTotal,
'rack_no' => $it['rack_no'] ?? null,
'shelf_no' => $it['shelf_no'] ?? null,
'cold_storage' => $it['cold_storage'] ?? null,
];
}
if (empty($validItems)) {
return $this->response->setJSON(['status' => 0, 'message' => 'No valid item rows with batch and expiry were found.']);
}
$netTotal = round($totalTaxable + $totalTax + $roundOff, 2);
$this->db->transStart();
$grnHeaderUpdate = [
'po_id' => $poId > 0 ? $poId : null,
'supplier_id' => $supplierId,
'challan_no' => $challanNo ?: null,
'supplier_invoice_no' => $supplierInvoiceNo,
'invoice_date' => $invoiceDate,
'grn_date' => $grnDate,
'total_received_amount' => $totalTaxable,
'total_tax_amount' => $totalTax,
'cgst_amount' => $totalCgst,
'sgst_amount' => $totalSgst,
'igst_amount' => $totalIgst,
'round_off' => $roundOff,
'gst_type' => $gstType,
'net_amount' => $netTotal,
'remarks' => $remarks,
'updated_at' => date('Y-m-d H:i:s'),
];
$this->grnModel->update($grnId, $grnHeaderUpdate);
$existingGrnItems = $this->grnItemModel->where('grn_id', $grnId)->findAll();
$existingItemsById = [];
foreach ($existingGrnItems as $ei) {
$existingItemsById[(int)$ei['grn_item_id']] = $ei;
}
$isPosted = ($grn['status'] === 'posted_to_inventory') && !empty($grn['purchase_id']);
$purchaseId = $isPosted ? (int)$grn['purchase_id'] : 0;
$medModel = new MedicalModel();
$userLabel = $this->getCurrentUserLabel();
$processedGrnItemIds = [];
foreach ($validItems as $vItem) {
$grnItemId = $vItem['grn_item_id'];
$vItem['grn_id'] = $grnId;
$purchaseItemId = $vItem['purchase_item_id'];
unset($vItem['grn_item_id']);
if ($grnItemId > 0 && isset($existingItemsById[$grnItemId])) {
// Update existing GRN item
$this->grnItemModel->update($grnItemId, $vItem);
$processedGrnItemIds[] = $grnItemId;
// If posted, update linked purchase_invoice_item
if ($isPosted && $purchaseItemId > 0) {
$packing = (int)($vItem['packing'] ?: 1);
$recPacks = (float)$vItem['received_packs'];
$freePacks = (float)$vItem['free_packs'];
$totalUnits = (int)round(($recPacks + $freePacks) * $packing);
$purchasePricePerPack = (float)$vItem['unit_purchase_rate'];
$purchaseUnitRate = $packing > 0 ? round($purchasePricePerPack / $packing, 4) : $purchasePricePerPack;
$piItemUpdate = [
'item_code' => $vItem['item_code'],
'Item_name' => $vItem['item_name'],
'packing' => $packing,
'batch_no' => $vItem['batch_no'],
'purchase_price' => $purchasePricePerPack,
'expiry_date' => $vItem['expiry_date'],
'mrp' => $vItem['mrp'],
'qty' => $recPacks,
'qty_free' => $freePacks,
'tqty' => $recPacks + $freePacks,
'amount' => $vItem['gross_amount'],
'discount' => $vItem['discount_percent'],
'sch_disc_amt' => $vItem['sch_disc_amt'],
'sch_disc_per' => $vItem['sch_disc_per'],
'taxable_amount' => $vItem['taxable_amount'],
'CGST_per' => $vItem['cgst_percent'],
'CGST' => $vItem['cgst_amount'],
'SGST_per' => $vItem['sgst_percent'],
'SGST' => $vItem['sgst_amount'],
'net_amount' => $vItem['total_amount'],
'HSNCODE' => $vItem['hsn_code'],
'selling_price' => $vItem['selling_unit_rate'] * $packing,
'total_unit' => $totalUnits,
'selling_unit_rate' => $vItem['selling_unit_rate'],
'purchase_unit_rate' => $purchaseUnitRate,
'stock_date' => $invoiceDate,
'rack_no' => $vItem['rack_no'] ?: '',
'shelf_no' => $vItem['shelf_no'] ?: '',
'cold_storage' => $vItem['cold_storage'] ?: 'No',
];
$this->db->table('purchase_invoice_item')->where('id', $purchaseItemId)->update($piItemUpdate);
$medModel->updatePurchaseStockById($purchaseItemId);
}
} else {
// Insert new GRN item
$this->grnItemModel->insert($vItem);
$newGrnItemId = (int)$this->db->insertID();
$processedGrnItemIds[] = $newGrnItemId;
// If posted, also insert new purchase_invoice_item
if ($isPosted && $purchaseId > 0) {
$packing = (int)($vItem['packing'] ?: 1);
$recPacks = (float)$vItem['received_packs'];
$freePacks = (float)$vItem['free_packs'];
$totalUnits = (int)round(($recPacks + $freePacks) * $packing);
$purchasePricePerPack = (float)$vItem['unit_purchase_rate'];
$purchaseUnitRate = $packing > 0 ? round($purchasePricePerPack / $packing, 4) : $purchasePricePerPack;
$piItemData = [
'purchase_id' => $purchaseId,
'item_code' => $vItem['item_code'],
'Item_name' => $vItem['item_name'],
'packing' => $packing,
'batch_no' => $vItem['batch_no'],
'purchase_price' => $purchasePricePerPack,
'expiry_date' => $vItem['expiry_date'],
'mrp' => $vItem['mrp'],
'qty' => $recPacks,
'qty_free' => $freePacks,
'tqty' => $recPacks + $freePacks,
'amount' => $vItem['gross_amount'],
'discount' => $vItem['discount_percent'],
'sch_disc_amt' => $vItem['sch_disc_amt'],
'sch_disc_per' => $vItem['sch_disc_per'],
'taxable_amount' => $vItem['taxable_amount'],
'CGST_per' => $vItem['cgst_percent'],
'CGST' => $vItem['cgst_amount'],
'SGST_per' => $vItem['sgst_percent'],
'SGST' => $vItem['sgst_amount'],
'net_amount' => $vItem['total_amount'],
'HSNCODE' => $vItem['hsn_code'],
'selling_price' => $vItem['selling_unit_rate'] * $packing,
'total_unit' => $totalUnits,
'total_sale_unit' => 0,
'total_return_unit' => 0,
'total_lost_unit' => 0,
'selling_unit_rate' => $vItem['selling_unit_rate'],
'purchase_unit_rate' => $purchaseUnitRate,
'item_return' => 0,
'remove_item' => 0,
'stock_date' => $invoiceDate,
'rack_no' => $vItem['rack_no'] ?: '',
'shelf_no' => $vItem['shelf_no'] ?: '',
'cold_storage' => $vItem['cold_storage'] ?: 'No',
'insert_by' => $userLabel,
];
$this->db->table('purchase_invoice_item')->insert($piItemData);
$newPiItemId = (int)$this->db->insertID();
$this->grnItemModel->update($newGrnItemId, ['purchase_item_id' => $newPiItemId]);
$medModel->updatePurchaseStockById($newPiItemId);
}
}
}
// Delete any items that were removed
foreach ($existingItemsById as $oldId => $oldItem) {
if (!in_array($oldId, $processedGrnItemIds, true)) {
if ($isPosted && !empty($oldItem['purchase_item_id'])) {
$piId = (int)$oldItem['purchase_item_id'];
$piRow = $this->db->table('purchase_invoice_item')->where('id', $piId)->get()->getRowArray();
$soldUnits = (float)($piRow['total_sale_unit'] ?? 0);
if ($soldUnits <= 0) {
$this->db->table('purchase_invoice_item')->where('id', $piId)->delete();
$this->grnItemModel->delete($oldId);
} else {
// Mark removed instead of hard delete to preserve sales audit
$this->db->table('purchase_invoice_item')->where('id', $piId)->update(['remove_item' => 1]);
$this->grnItemModel->delete($oldId);
}
} else {
$this->grnItemModel->delete($oldId);
}
}
}
// Update purchase_invoice header if already posted
if ($isPosted && $purchaseId > 0) {
$supplier = $this->db->table('med_supplier')->where('sid', $supplierId)->get()->getRowArray();
$suppName = $supplier['name_supplier'] ?? 'Supplier';
$this->db->table('purchase_invoice')->where('id', $purchaseId)->update([
'sid' => $supplierId,
'ischallan' => !empty($challanNo) ? 1 : 0,
'monthyear' => date('m/Y', strtotime($invoiceDate)),
'supp_name' => $suppName,
'date_of_invoice' => $invoiceDate,
'Invoice_no' => $supplierInvoiceNo,
'Taxable_Amt' => $totalTaxable,
'CGST_Amt' => $totalCgst,
'SGST_Amt' => $totalSgst,
'T_Net_Amount' => $netTotal,
]);
} elseif (!$isPosted && $syncInventory === 1) {
// If was not posted before, but user checked "Post to live inventory"
$this->executeGrnStockPosting($grnId);
}
$this->db->transComplete();
if ($this->db->transStatus() === false) {
$err = $this->db->error();
$errMsg = !empty($err['message']) ? ': ' . $err['message'] : '.';
log_message('error', 'grn_update transaction failed' . $errMsg);
return $this->response->setJSON(['status' => 0, 'message' => 'Failed to update Goods Received Note' . $errMsg]);
}
return $this->response->setJSON([
'status' => 1,
'message' => "GRN {$grn['grn_number']} updated successfully!",
'grn_id' => $grnId,
'grn_number' => $grn['grn_number'],
]);
}
public function grn_post_inventory(int $grnId) public function grn_post_inventory(int $grnId)
{ {
if ($deny = $this->ensurePharmacyAccess()) { if ($deny = $this->ensurePharmacyAccess()) {

View File

@ -11,6 +11,9 @@
<i class="bi bi-arrow-left"></i> Back to GRN List <i class="bi bi-arrow-left"></i> Back to GRN List
</a> </a>
<?php if (!empty($grn['grn_id'])): ?> <?php if (!empty($grn['grn_id'])): ?>
<button type="button" class="btn btn-warning btn-sm" onclick="load_form_div('<?= base_url('Medical/grn_edit/' . (int)$grn['grn_id']) ?>','medical-main','Edit GRN Inspection');">
<i class="bi bi-pencil-square"></i> Edit GRN Details
</button>
<a href="<?= base_url('Medical/grn_print/' . (int)$grn['grn_id']) ?>" target="_blank" class="btn btn-outline-secondary btn-sm"> <a href="<?= base_url('Medical/grn_print/' . (int)$grn['grn_id']) ?>" target="_blank" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-printer"></i> Print Slip <i class="bi bi-printer"></i> Print Slip
</a> </a>
@ -225,6 +228,11 @@
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<?php if (!empty($grn['grn_id'])): ?>
<button type="button" class="btn btn-warning" onclick="load_form_div('<?= base_url('Medical/grn_edit/' . (int)$grn['grn_id']) ?>','medical-main','Edit GRN Inspection');">
<i class="bi bi-pencil-square"></i> Edit GRN
</button>
<?php endif; ?>
<?php if (($grn['status'] ?? '') !== 'posted_to_inventory' && !empty($grn['grn_id'])): ?> <?php if (($grn['status'] ?? '') !== 'posted_to_inventory' && !empty($grn['grn_id'])): ?>
<button type="button" class="btn btn-success px-4" onclick="postGrnToLiveInventory(<?= (int)$grn['grn_id'] ?>)"> <button type="button" class="btn btn-success px-4" onclick="postGrnToLiveInventory(<?= (int)$grn['grn_id'] ?>)">
<i class="bi bi-box-arrow-in-down"></i> Post to Live Inventory <i class="bi bi-box-arrow-in-down"></i> Post to Live Inventory
@ -245,7 +253,7 @@ function postGrnToLiveInventory(grnId) {
$.post('<?= base_url('Medical/grn_post_inventory/') ?>' + grnId, {}, function(data) { $.post('<?= base_url('Medical/grn_post_inventory/') ?>' + grnId, {}, function(data) {
alert(data.message || 'Done'); alert(data.message || 'Done');
if (data.status) { if (data.status) {
load_form_div('<?= base_url('Medical/grn_edit/') ?>' + grnId, 'medical-main', 'GRN Inspection Detail'); load_form_div('<?= base_url('Medical/grn_detail/') ?>' + grnId, 'medical-main', 'GRN Inspection Detail');
} }
}, 'json').fail(function() { }, 'json').fail(function() {
alert('Error posting GRN.'); alert('Error posting GRN.');

View File

@ -1,18 +1,34 @@
<?php <?php
$poId = !empty($selectedPo) ? (int)$selectedPo['po_id'] : 0; $isEdit = !empty($isEdit);
$supplierId = !empty($selectedPo) ? (int)$selectedPo['supplier_id'] : 0; $poId = !empty($grn['po_id']) ? (int)$grn['po_id'] : (!empty($selectedPo) ? (int)$selectedPo['po_id'] : 0);
$nextGrnNumber = $nextGrnNumber ?? 'GRN-NEW'; $supplierId = !empty($grn['supplier_id']) ? (int)$grn['supplier_id'] : (!empty($selectedPo) ? (int)$selectedPo['supplier_id'] : 0);
$displayGrnNumber = !empty($grn['grn_number']) ? $grn['grn_number'] : ($nextGrnNumber ?? 'GRN-NEW');
$isPosted = !empty($grn['status']) && $grn['status'] === 'posted_to_inventory';
?> ?>
<div class="pagetitle d-flex justify-content-between align-items-center mb-3"> <div class="pagetitle d-flex justify-content-between align-items-center mb-3">
<div> <div>
<h4 class="mb-0 text-success"> <h4 class="mb-0 text-success">
<i class="bi bi-box-arrow-in-down"></i> Create Goods Received Note (GRN) <i class="bi <?= $isEdit ? 'bi-pencil-square' : 'bi-box-arrow-in-down' ?>"></i>
<span class="badge bg-light text-dark border ms-2 font-monospace"><?= esc($nextGrnNumber) ?></span> <?= $isEdit ? 'Edit Goods Received Note (GRN)' : 'Create Goods Received Note (GRN)' ?>
<span class="badge bg-light text-dark border ms-2 font-monospace"><?= esc($displayGrnNumber) ?></span>
<?php if ($isEdit && $isPosted): ?>
<span class="badge bg-success ms-1">POSTED TO STOCK (REF #<?= (int)($grn['purchase_id'] ?? 0) ?>)</span>
<?php elseif ($isEdit): ?>
<span class="badge bg-info text-dark ms-1">INSPECTION DRAFT / VERIFIED</span>
<?php endif; ?>
</h4> </h4>
<small class="text-muted">Inward Stock Physical Inspection &amp; Vendor Invoice Reconciliation</small> <small class="text-muted">Inward Stock Physical Inspection &amp; Vendor Invoice Reconciliation</small>
</div> </div>
<div> <div class="d-flex gap-2">
<?php if ($isEdit && !empty($grn['grn_id'])): ?>
<a href="javascript:load_form_div('<?= base_url('Medical/grn_detail/' . (int)$grn['grn_id']) ?>','medical-main','GRN Inspection Detail');" class="btn btn-outline-info btn-sm">
<i class="bi bi-eye"></i> View Inspection Detail
</a>
<a href="<?= base_url('Medical/grn_print/' . (int)$grn['grn_id']) ?>" target="_blank" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-printer"></i> Print Slip
</a>
<?php endif; ?>
<a href="javascript:load_form_div('<?= base_url('Medical/grn_list') ?>','medical-main','GRN Register :Pharmacy');" class="btn btn-outline-secondary btn-sm"> <a href="javascript:load_form_div('<?= base_url('Medical/grn_list') ?>','medical-main','GRN Register :Pharmacy');" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> Back to GRN List <i class="bi bi-arrow-left"></i> Back to GRN List
</a> </a>
@ -26,6 +42,9 @@
<div class="card-body p-3"> <div class="card-body p-3">
<form id="grn-create-form" onsubmit="event.preventDefault(); submitGrnForm();"> <form id="grn-create-form" onsubmit="event.preventDefault(); submitGrnForm();">
<?= csrf_field() ?> <?= csrf_field() ?>
<?php if ($isEdit && !empty($grn['grn_id'])): ?>
<input type="hidden" name="grn_id" id="grn_id" value="<?= (int)$grn['grn_id'] ?>">
<?php endif; ?>
<div class="row g-2 mb-2"> <div class="row g-2 mb-2">
<div class="col-md-3"> <div class="col-md-3">
<label class="form-label form-label-sm fw-semibold mb-1">Linked Purchase Order (PO)</label> <label class="form-label form-label-sm fw-semibold mb-1">Linked Purchase Order (PO)</label>
@ -55,33 +74,34 @@
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<label class="form-label form-label-sm fw-semibold mb-1">Vendor Invoice / Bill # <span class="text-danger">*</span></label> <label class="form-label form-label-sm fw-semibold mb-1">Vendor Invoice / Bill # <span class="text-danger">*</span></label>
<input type="text" name="supplier_invoice_no" id="supplier_invoice_no" class="form-control form-control-sm" placeholder="e.g. INV-88421" required> <input type="text" name="supplier_invoice_no" id="supplier_invoice_no" class="form-control form-control-sm" placeholder="e.g. INV-88421" value="<?= esc($grn['supplier_invoice_no'] ?? '') ?>" required>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<label class="form-label form-label-sm fw-semibold mb-1">Invoice Date <span class="text-danger">*</span></label> <label class="form-label form-label-sm fw-semibold mb-1">Invoice Date <span class="text-danger">*</span></label>
<input type="date" name="invoice_date" id="invoice_date" class="form-control form-control-sm" value="<?= date('Y-m-d') ?>" required> <input type="date" name="invoice_date" id="invoice_date" class="form-control form-control-sm" value="<?= !empty($grn['invoice_date']) ? esc($grn['invoice_date']) : date('Y-m-d') ?>" required>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<label class="form-label form-label-sm fw-semibold mb-1">GRN Received Date <span class="text-danger">*</span></label> <label class="form-label form-label-sm fw-semibold mb-1">GRN Received Date <span class="text-danger">*</span></label>
<input type="date" name="grn_date" id="grn_date" class="form-control form-control-sm" value="<?= date('Y-m-d') ?>" required> <input type="date" name="grn_date" id="grn_date" class="form-control form-control-sm" value="<?= !empty($grn['grn_date']) ? esc($grn['grn_date']) : date('Y-m-d') ?>" required>
</div> </div>
</div> </div>
<div class="row g-2 mb-3"> <div class="row g-2 mb-3">
<div class="col-md-3"> <div class="col-md-3">
<label class="form-label form-label-sm fw-semibold mb-1">GST Supply Type</label> <label class="form-label form-label-sm fw-semibold mb-1">GST Supply Type</label>
<?php $gstType = $grn['gst_type'] ?? 'intra_state'; ?>
<select name="gst_type" id="grn_gst_type" class="form-select form-select-sm" onchange="recalculateGrnTotals();"> <select name="gst_type" id="grn_gst_type" class="form-select form-select-sm" onchange="recalculateGrnTotals();">
<option value="intra_state" selected>Intra-State (CGST + SGST)</option> <option value="intra_state" <?= ($gstType === 'intra_state') ? 'selected' : '' ?>>Intra-State (CGST + SGST)</option>
<option value="inter_state">Inter-State (IGST)</option> <option value="inter_state" <?= ($gstType === 'inter_state') ? 'selected' : '' ?>>Inter-State (IGST)</option>
</select> </select>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<label class="form-label form-label-sm fw-semibold mb-1">Delivery Challan / Gate Pass #</label> <label class="form-label form-label-sm fw-semibold mb-1">Delivery Challan / Gate Pass #</label>
<input type="text" name="challan_no" id="challan_no" class="form-control form-control-sm" placeholder="Optional Challan No."> <input type="text" name="challan_no" id="challan_no" class="form-control form-control-sm" placeholder="Optional Challan No." value="<?= esc($grn['challan_no'] ?? '') ?>">
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label form-label-sm fw-semibold mb-1">Receiving Inspection Remarks</label> <label class="form-label form-label-sm fw-semibold mb-1">Receiving Inspection Remarks</label>
<input type="text" name="remarks" id="grn_remarks" class="form-control form-control-sm" placeholder="Package integrity verified, cold chain maintained, etc."> <input type="text" name="remarks" id="grn_remarks" class="form-control form-control-sm" placeholder="Package integrity verified, cold chain maintained, etc." value="<?= esc($grn['remarks'] ?? '') ?>">
</div> </div>
</div> </div>
@ -155,7 +175,93 @@
</tr> </tr>
</thead> </thead>
<tbody id="grn-items-body"> <tbody id="grn-items-body">
<?php if (!empty($poItems)): ?> <?php if (!empty($grnItems)): ?>
<?php foreach ($grnItems as $idx => $it): ?>
<?php
$gstRate = (float)($it['igst_percent'] > 0 ? $it['igst_percent'] : ((float)($it['cgst_percent'] ?? 0) + (float)($it['sgst_percent'] ?? 0)));
if ($gstRate <= 0 && isset($it['cgst_percent']) && (float)$it['cgst_percent'] == 0 && (float)$it['sgst_percent'] == 0 && (float)$it['igst_percent'] == 0) {
$gstRate = 0;
} elseif ($gstRate <= 0) {
$gstRate = 5;
}
$recQty = (float)($it['received_packs'] ?? 0);
$freeQty = (float)($it['free_packs'] ?? 0);
$rate = (float)($it['unit_purchase_rate'] ?? 0);
$gross = isset($it['gross_amount']) && (float)$it['gross_amount'] > 0 ? (float)$it['gross_amount'] : ($recQty * $rate);
$mrp = (float)($it['mrp'] ?? ($rate * 1.3));
$tradeDisc = (float)($it['discount_percent'] ?? 0);
$schPer = (float)($it['sch_disc_per'] ?? 0);
$schAmt = (float)($it['sch_disc_amt'] ?? 0);
$taxable = isset($it['taxable_amount']) ? (float)$it['taxable_amount'] : $gross;
$lineTotal = isset($it['total_amount']) ? (float)$it['total_amount'] : $taxable;
$expDate = !empty($it['expiry_date']) ? date('Y-m-d', strtotime($it['expiry_date'])) : '';
?>
<tr>
<td class="row-num text-center"><?= $idx + 1 ?></td>
<td>
<strong class="text-dark"><?= esc($it['item_name']) ?></strong>
<input type="hidden" name="items[<?= $idx ?>][grn_item_id]" value="<?= (int)($it['grn_item_id'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][purchase_item_id]" value="<?= (int)($it['purchase_item_id'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][item_code]" value="<?= esc($it['item_code']) ?>">
<input type="hidden" name="items[<?= $idx ?>][item_name]" value="<?= esc($it['item_name']) ?>">
<input type="hidden" name="items[<?= $idx ?>][po_item_id]" value="<?= (int)($it['po_item_id'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][order_packs]" value="<?= (float)($it['order_packs'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][rejected_packs]" value="<?= (float)($it['rejected_packs'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][hsn_code]" value="<?= esc($it['hsn_code'] ?? '3004') ?>">
<input type="hidden" name="items[<?= $idx ?>][cgst_percent]" class="line-cgst" value="<?= (float)($it['cgst_percent'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][sgst_percent]" class="line-sgst" value="<?= (float)($it['sgst_percent'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][igst_percent]" class="line-igst" value="<?= (float)($it['igst_percent'] ?? 0) ?>">
<input type="hidden" name="items[<?= $idx ?>][gross_amount]" class="line-gross-hid" value="<?= number_format($gross, 2, '.', '') ?>">
<input type="hidden" name="items[<?= $idx ?>][taxable_amount]" class="line-taxable-hid" value="<?= number_format($taxable, 2, '.', '') ?>">
</td>
<td>
<input type="text" name="items[<?= $idx ?>][batch_no]" class="form-control form-control-sm font-monospace line-batch" value="<?= esc($it['batch_no'] ?? '') ?>" placeholder="Batch #" required>
</td>
<td>
<input type="date" name="items[<?= $idx ?>][expiry_date]" class="form-control form-control-sm line-expiry" value="<?= esc($expDate) ?>" required>
</td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][packing]" class="form-control form-control-sm text-center line-pack px-1" value="<?= (int)($it['packing'] ?? 10) ?>" min="1">
</td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][received_packs]" class="form-control form-control-sm text-center fw-bold line-rec px-1" value="<?= $recQty ?>" min="0" step="1" oninput="recalculateGrnTotals();" required>
</td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][free_packs]" class="form-control form-control-sm text-center text-success line-free px-1" value="<?= $freeQty ?>" min="0" step="1" oninput="recalculateGrnTotals();">
</td>
<td class="text-end">
<input type="number" name="items[<?= $idx ?>][unit_purchase_rate]" class="form-control form-control-sm text-end line-rate px-1" value="<?= number_format($rate, 2, '.', '') ?>" min="0" step="0.01" oninput="recalculateGrnTotals();">
</td>
<td class="text-end">
<input type="number" name="items[<?= $idx ?>][mrp]" class="form-control form-control-sm text-end line-mrp px-1" value="<?= number_format($mrp, 2, '.', '') ?>" min="0" step="0.01">
</td>
<td class="text-end font-monospace line-gross-disp bg-light">₹<?= number_format($gross, 2) ?></td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][discount_percent]" class="form-control form-control-sm text-center line-disc px-1" value="<?= number_format($tradeDisc, 2, '.', '') ?>" min="0" max="100" step="0.01" oninput="recalculateGrnTotals();">
</td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][sch_disc_per]" class="form-control form-control-sm text-center line-sch-per px-1" value="<?= number_format($schPer, 2, '.', '') ?>" min="0" max="100" step="0.01" oninput="recalculateGrnTotals();">
</td>
<td class="text-center">
<input type="number" name="items[<?= $idx ?>][sch_disc_amt]" class="form-control form-control-sm text-center line-sch-amt px-1" value="<?= number_format($schAmt, 2, '.', '') ?>" min="0" step="0.01" oninput="recalculateGrnTotals();">
</td>
<td class="text-end font-monospace line-taxable-disp bg-light">₹<?= number_format($taxable, 2) ?></td>
<td class="text-center">
<select name="items[<?= $idx ?>][gst_rate]" class="form-select form-select-sm text-center line-gst px-1" onchange="recalculateGrnTotals();">
<option value="5" <?= (abs($gstRate - 5) < 0.1) ? 'selected' : '' ?>>5%</option>
<option value="12" <?= (abs($gstRate - 12) < 0.1) ? 'selected' : '' ?>>12%</option>
<option value="18" <?= (abs($gstRate - 18) < 0.1) ? 'selected' : '' ?>>18%</option>
<option value="28" <?= (abs($gstRate - 28) < 0.1) ? 'selected' : '' ?>>28%</option>
<option value="0" <?= (abs($gstRate - 0) < 0.1) ? 'selected' : '' ?>>0%</option>
</select>
</td>
<td class="text-end font-monospace fw-semibold line-total-disp bg-light">₹<?= number_format($lineTotal, 2) ?></td>
<td class="text-center">
<button type="button" class="btn btn-outline-danger btn-sm py-0 px-1" onclick="removeGrnRow(this);">✖</button>
</td>
</tr>
<?php endforeach; ?>
<?php elseif (!empty($poItems)): ?>
<?php foreach ($poItems as $idx => $it): ?> <?php foreach ($poItems as $idx => $it): ?>
<?php <?php
$defGst = (float)($it['gst_rate'] ?? 5); $defGst = (float)($it['gst_rate'] ?? 5);
@ -170,6 +276,8 @@
<td class="row-num text-center"><?= $idx + 1 ?></td> <td class="row-num text-center"><?= $idx + 1 ?></td>
<td> <td>
<strong class="text-dark"><?= esc($it['item_name']) ?></strong> <strong class="text-dark"><?= esc($it['item_name']) ?></strong>
<input type="hidden" name="items[<?= $idx ?>][grn_item_id]" value="0">
<input type="hidden" name="items[<?= $idx ?>][purchase_item_id]" value="0">
<input type="hidden" name="items[<?= $idx ?>][item_code]" value="<?= (int)$it['item_id'] ?>"> <input type="hidden" name="items[<?= $idx ?>][item_code]" value="<?= (int)$it['item_id'] ?>">
<input type="hidden" name="items[<?= $idx ?>][item_name]" value="<?= esc($it['item_name']) ?>"> <input type="hidden" name="items[<?= $idx ?>][item_name]" value="<?= esc($it['item_name']) ?>">
<input type="hidden" name="items[<?= $idx ?>][po_item_id]" value="<?= (int)$it['po_item_id'] ?>"> <input type="hidden" name="items[<?= $idx ?>][po_item_id]" value="<?= (int)$it['po_item_id'] ?>">
@ -276,7 +384,7 @@
<tr> <tr>
<th colspan="13" class="text-end text-muted">Round Off (+ / -):</th> <th colspan="13" class="text-end text-muted">Round Off (+ / -):</th>
<th colspan="3" class="text-end"> <th colspan="3" class="text-end">
<input type="number" step="0.01" name="round_off" id="grn_round_off" class="form-control form-control-sm text-end font-monospace d-inline-block" style="width: 105px;" value="0.00" oninput="recalculateGrnTotals();"> <input type="number" step="0.01" name="round_off" id="grn_round_off" class="form-control form-control-sm text-end font-monospace d-inline-block" style="width: 105px;" value="<?= isset($grn['round_off']) ? number_format((float)$grn['round_off'], 2, '.', '') : '0.00' ?>" oninput="recalculateGrnTotals();">
</th> </th>
<th></th> <th></th>
</tr> </tr>
@ -293,17 +401,29 @@
<div class="card p-3 mt-3 bg-light border-0"> <div class="card p-3 mt-3 bg-light border-0">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2"> <div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
<div class="form-check"> <div>
<input class="form-check-input" type="checkbox" name="post_to_inventory" id="post_to_inventory" value="1" checked> <?php if ($isEdit && $isPosted): ?>
<label class="form-check-label fw-bold text-dark" for="post_to_inventory"> <div class="form-check">
Immediately Post Verified Quantities to Live Pharmacy Store Stock &amp; Purchase Ledgers <input class="form-check-input" type="checkbox" name="sync_inventory" id="sync_inventory" value="1" checked>
</label> <label class="form-check-label fw-bold text-success" for="sync_inventory">
<small class="d-block text-muted">Creates verified purchase invoice records and updates stock ledgers.</small> <i class="bi bi-arrow-repeat"></i> Synchronize Changes to Live Store Inventory &amp; Purchase Invoice (Ref #<?= (int)($grn['purchase_id'] ?? 0) ?>)
</label>
<small class="d-block text-muted">Automatically updates linked purchase bill line items and live stock batches.</small>
</div>
<?php else: ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="post_to_inventory" id="post_to_inventory" value="1" checked>
<label class="form-check-label fw-bold text-dark" for="post_to_inventory">
Immediately Post Verified Quantities to Live Pharmacy Store Stock &amp; Purchase Ledgers
</label>
<small class="d-block text-muted">Creates verified purchase invoice records and updates stock ledgers.</small>
</div>
<?php endif; ?>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary" onclick="load_form_div('<?= base_url('Medical/grn_list') ?>','medical-main');">Cancel</button> <button type="button" class="btn btn-outline-secondary" onclick="load_form_div('<?= $isEdit ? base_url('Medical/grn_detail/' . (int)$grn['grn_id']) : base_url('Medical/grn_list') ?>','medical-main');">Cancel</button>
<button type="submit" class="btn btn-success px-4" id="btn-save-grn"> <button type="submit" class="btn btn-success px-4" id="btn-save-grn">
<i class="bi bi-check-all"></i> Save &amp; Complete Inward GRN <i class="bi bi-check-all"></i> <?= $isEdit ? 'Update GRN Inspection' : 'Save & Complete Inward GRN' ?>
</button> </button>
</div> </div>
</div> </div>
@ -350,6 +470,11 @@ function initGrnDrugAutocomplete() {
} }
function handlePoSelection(poId) { function handlePoSelection(poId) {
<?php if ($isEdit): ?>
if (!confirm('Selecting another PO will switch to creating a new GRN. Continue?')) {
return;
}
<?php endif; ?>
if (poId && parseInt(poId) > 0) { if (poId && parseInt(poId) > 0) {
load_form_div('<?= base_url('Medical/grn_new/') ?>' + poId, 'medical-main', 'Create GRN for PO'); load_form_div('<?= base_url('Medical/grn_new/') ?>' + poId, 'medical-main', 'Create GRN for PO');
} }
@ -394,6 +519,8 @@ function addCustomItemToGrn() {
<td class="row-num text-center">${rowIdx + 1}</td> <td class="row-num text-center">${rowIdx + 1}</td>
<td> <td>
<strong class="text-dark">${escapeHtml(name)}</strong> <strong class="text-dark">${escapeHtml(name)}</strong>
<input type="hidden" name="items[${rowIdx}][grn_item_id]" value="0">
<input type="hidden" name="items[${rowIdx}][purchase_item_id]" value="0">
<input type="hidden" name="items[${rowIdx}][item_code]" value="${code}"> <input type="hidden" name="items[${rowIdx}][item_code]" value="${code}">
<input type="hidden" name="items[${rowIdx}][item_name]" value="${escapeHtml(name)}"> <input type="hidden" name="items[${rowIdx}][item_name]" value="${escapeHtml(name)}">
<input type="hidden" name="items[${rowIdx}][po_item_id]" value=""> <input type="hidden" name="items[${rowIdx}][po_item_id]" value="">
@ -614,10 +741,13 @@ function submitGrnForm() {
var formData = new FormData(form); var formData = new FormData(form);
var saveBtn = document.getElementById('btn-save-grn'); var saveBtn = document.getElementById('btn-save-grn');
var btnDefaultHtml = '<?= $isEdit ? '<i class="bi bi-check-all"></i> Update GRN Inspection' : '<i class="bi bi-check-all"></i> Save &amp; Complete Inward GRN' ?>';
saveBtn.disabled = true; saveBtn.disabled = true;
saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Processing Inward Stock...'; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Processing Inward Stock...';
fetch('<?= base_url('Medical/grn_create') ?>', { var submitUrl = '<?= $isEdit ? base_url('Medical/grn_update/' . (int)($grn['grn_id'] ?? 0)) : base_url('Medical/grn_create') ?>';
fetch(submitUrl, {
method: 'POST', method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' }, headers: { 'X-Requested-With': 'XMLHttpRequest' },
body: formData body: formData
@ -625,18 +755,19 @@ function submitGrnForm() {
.then(r => r.json()) .then(r => r.json())
.then(data => { .then(data => {
saveBtn.disabled = false; saveBtn.disabled = false;
saveBtn.innerHTML = '<i class="bi bi-check-all"></i> Save &amp; Complete Inward GRN'; saveBtn.innerHTML = btnDefaultHtml;
if (data.status) { if (data.status) {
alert(data.message); alert(data.message);
load_form_div('<?= base_url('Medical/grn_list') ?>', 'medical-main', 'GRN Register :Pharmacy'); var targetGrnId = data.grn_id || '<?= (int)($grn['grn_id'] ?? 0) ?>';
load_form_div('<?= base_url('Medical/grn_detail/') ?>' + targetGrnId, 'medical-main', 'GRN Inspection Detail');
} else { } else {
alert('Error: ' + (data.message || 'Failed to save GRN.')); alert('Error: ' + (data.message || 'Failed to save GRN.'));
} }
}) })
.catch(e => { .catch(e => {
saveBtn.disabled = false; saveBtn.disabled = false;
saveBtn.innerHTML = '<i class="bi bi-check-all"></i> Save &amp; Complete Inward GRN'; saveBtn.innerHTML = btnDefaultHtml;
alert('Server communication error.'); alert('Server communication error.');
}); });
} }

View File

@ -114,9 +114,12 @@
<a href="<?= base_url('Medical/grn_print/' . $row['grn_id']) ?>" target="_blank" class="btn btn-outline-secondary" title="Print GRN Slip"> <a href="<?= base_url('Medical/grn_print/' . $row['grn_id']) ?>" target="_blank" class="btn btn-outline-secondary" title="Print GRN Slip">
<i class="bi bi-printer"></i> <i class="bi bi-printer"></i>
</a> </a>
<button type="button" class="btn btn-outline-primary" onclick="load_form_div('<?= base_url('Medical/grn_edit/' . $row['grn_id']) ?>','medical-main','GRN Inspection Detail');" title="View Inspection Details"> <button type="button" class="btn btn-outline-primary" onclick="load_form_div('<?= base_url('Medical/grn_detail/' . $row['grn_id']) ?>','medical-main','GRN Inspection Detail');" title="View Inspection Details">
<i class="bi bi-eye"></i> View <i class="bi bi-eye"></i> View
</button> </button>
<button type="button" class="btn btn-outline-warning" onclick="load_form_div('<?= base_url('Medical/grn_edit/' . $row['grn_id']) ?>','medical-main','Edit GRN Inspection');" title="Edit Inspection Details">
<i class="bi bi-pencil-square"></i> Edit
</button>
<?php if ($row['status'] === 'verified'): ?> <?php if ($row['status'] === 'verified'): ?>
<button type="button" class="btn btn-success" onclick="postGrnToStock(<?= (int)$row['grn_id'] ?>)" title="Post to Live Hospital Stock"> <button type="button" class="btn btn-success" onclick="postGrnToStock(<?= (int)$row['grn_id'] ?>)" title="Post to Live Hospital Stock">
<i class="bi bi-box-arrow-in-down"></i> Post Stock <i class="bi bi-box-arrow-in-down"></i> Post Stock

View File

@ -20,7 +20,7 @@
<i class="bi bi-pencil-square"></i> Edit Invoice <i class="bi bi-pencil-square"></i> Edit Invoice
</button> </button>
<?php if (!empty($linked_grn)): ?> <?php if (!empty($linked_grn)): ?>
<button onclick="load_form_div('<?= base_url('Medical/grn_edit/' . (int) $linked_grn['grn_id']) ?>','medical-main','GRN Detail');" type="button" class="btn btn-outline-info btn-sm ms-1"> <button onclick="load_form_div('<?= base_url('Medical/grn_detail/' . (int) $linked_grn['grn_id']) ?>','medical-main','GRN Detail');" type="button" class="btn btn-outline-info btn-sm ms-1">
<i class="bi bi-box-arrow-left"></i> Back to GRN #<?= esc($linked_grn['grn_number'] ?? $linked_grn['grn_id']) ?> <i class="bi bi-box-arrow-left"></i> Back to GRN #<?= esc($linked_grn['grn_number'] ?? $linked_grn['grn_id']) ?>
</button> </button>
<?php endif; ?> <?php endif; ?>

View File

@ -31,7 +31,7 @@ if (!empty($inv->date_of_invoice) && $inv->date_of_invoice !== '0000-00-00') {
<i class="bi bi-card-checklist"></i> View Invoice Items <i class="bi bi-card-checklist"></i> View Invoice Items
</button> </button>
<?php if (!empty($linked_grn)): ?> <?php if (!empty($linked_grn)): ?>
<button onclick="load_form_div('<?= base_url('Medical/grn_edit/' . (int) $linked_grn['grn_id']) ?>','medical-main','GRN Detail');" type="button" class="btn btn-outline-info btn-sm ms-1"> <button onclick="load_form_div('<?= base_url('Medical/grn_detail/' . (int) $linked_grn['grn_id']) ?>','medical-main','GRN Detail');" type="button" class="btn btn-outline-info btn-sm ms-1">
<i class="bi bi-box-arrow-left"></i> Back to GRN #<?= esc($linked_grn['grn_number'] ?? $linked_grn['grn_id']) ?> <i class="bi bi-box-arrow-left"></i> Back to GRN #<?= esc($linked_grn['grn_number'] ?? $linked_grn['grn_id']) ?>
</button> </button>
<?php endif; ?> <?php endif; ?>