diff --git a/app/Config/App.php b/app/Config/App.php
index 99d7deb..15b9768 100644
--- a/app/Config/App.php
+++ b/app/Config/App.php
@@ -150,7 +150,7 @@ class App extends BaseConfig
* @see https://www.php.net/manual/en/timezones.php for list of timezones
* supported by PHP.
*/
- public string $appTimezone = 'UTC';
+ public string $appTimezone = 'Asia/Kolkata';
/**
* --------------------------------------------------------------------------
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 9446a07..7dc2b67 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -294,6 +294,10 @@ $routes->get('IpdNew/addipd/(:num)', 'Billing\\Ipd::legacyAddIpd/$1');
$routes->post('IpdNew/AddNew', 'Billing\\Ipd::legacyAddNew');
$routes->post('IpdNew/addnew', 'Billing\\Ipd::legacyAddNew');
$routes->get('IpdNew/ipd_panel/(:num)', 'Billing\\Ipd::panel/$1');
+$routes->get('IpdNew/show_ipd_form/(:num)', 'Billing\\Ipd::showIpdForm/$1/1');
+$routes->get('IpdNew/show_ipd_form/(:num)/(:num)', 'Billing\\Ipd::showIpdForm/$1/$2');
+$routes->get('ipdNew/show_ipd_form/(:num)', 'Billing\\Ipd::showIpdForm/$1/1');
+$routes->get('ipdNew/show_ipd_form/(:num)/(:num)', 'Billing\\Ipd::showIpdForm/$1/$2');
// Legacy compatibility: old discharge summary links should open current discharge tab.
$routes->match(['get', 'post'], 'Ipd_discharge/ipd_select/(:num)', 'Ipd_discharge::ipd_select/$1');
@@ -346,6 +350,8 @@ $routes->group('billing', function($routes) {
$routes->post('ipd/panel/(:num)/discharge/charge/(:num)', 'Billing\\Ipd::updateDischargeCharge/$1/$2');
$routes->get('ipd/bill-print/(:num)', 'Billing\\Ipd::billPrint/$1');
$routes->get('ipd/bill-print/(:num)/(:num)', 'Billing\\Ipd::billPrint/$1/$2');
+ $routes->get('ipd/show-form/(:num)', 'Billing\\Ipd::showIpdForm/$1/1');
+ $routes->get('ipd/show-form/(:num)/(:num)', 'Billing\\Ipd::showIpdForm/$1/$2');
$routes->post('ipd/charge/add/(:num)', 'Billing\\Ipd::addIpdCharge/$1');
$routes->post('ipd/charge/update/(:num)', 'Billing\\Ipd::updateIpdCharge/$1');
$routes->post('ipd/charge/delete/(:num)', 'Billing\\Ipd::deleteIpdCharge/$1');
@@ -457,6 +463,7 @@ $routes->post('Opd/showfee', 'Opd::showfee');
$routes->post('Opd/confirm_opd', 'Opd::confirm_opd');
$routes->post('Opd/confirm_payment', 'Opd::confirm_payment');
$routes->post('Opd/opd_discount_update/(:num)', 'Opd::opd_discount_update/$1');
+$routes->post('Opd/opd_cancel/(:num)', 'Opd::opd_cancel/$1');
$routes->match(['get', 'post'], 'Opd/opd_load_doc/(:num)', 'Opd::opd_load_doc/$1');
$routes->match(['get', 'post'], 'Opd/opd_file_last_list', 'Opd::opd_file_last_list');
$routes->match(['get', 'post'], 'Opd/opd_file_last_list/(:num)', 'Opd::opd_file_last_list/$1');
@@ -599,6 +606,8 @@ $routes->get('Opd_prescription/show_medical_item/(:num)', 'Opd_prescription::sho
$routes->get('Opd_prescription/prescribed_dose/(:num)/(:num)', 'Opd_prescription::prescribed_dose/$1/$2');
$routes->get('Invoice/list_req_payment', 'Invoice::list_req_payment');
+$routes->get('Invoice/opdlist', 'Invoice::opdlist');
+$routes->get('Invoice/chargeslist', 'Invoice::chargeslist');
$routes->post('Invoice/getRequestTable', 'Invoice::getRequestTable');
$routes->get('Invoice/payment_form/(:num)', 'Invoice::payment_form/$1');
$routes->post('Invoice/req_payment_process', 'Invoice::req_payment_process');
@@ -633,6 +642,8 @@ $routes->post('Lab_Admin/test_item_search', 'Setting\Template::test_item_search'
$routes->match(['get', 'post'], 'setting/template/discharge_templates', 'Setting\Template::discharge_templates');
$routes->get('setting/template/discharge_templates/delete/(:num)', 'Setting\Template::discharge_template_delete/$1');
+$routes->match(['get', 'post'], 'setting/template/ipd_document_templates', 'Setting\Template::ipd_document_templates');
+$routes->get('setting/template/ipd_document_templates/delete/(:num)', 'Setting\Template::ipd_document_template_delete/$1');
$routes->match(['get', 'post'], 'setting/template/diagnosis_print_settings', 'Setting\Template::diagnosis_print_settings');
$routes->match(['get', 'post'], 'setting/template/diagnosis_print_settings/(:num)', 'Setting\Template::diagnosis_print_settings/$1');
$routes->match(['get', 'post'], 'setting/template/document_print_settings', 'Setting\Template::document_print_settings');
@@ -901,6 +912,13 @@ $routes->group('setting', static function($routes) {
$routes->post('admin/reffer/types/update', 'Setting\\Reffer::updateType');
$routes->post('admin/reffer/types/delete', 'Setting\\Reffer::deleteType');
$routes->get('admin/bed-management', 'Setting\\BedManagement::index');
+ $routes->get('admin/departments', 'Setting\\BedManagement::departments');
+ $routes->post('admin/departments/save', 'Setting\\BedManagement::saveDepartment');
+ $routes->post('admin/departments/delete', 'Setting\\BedManagement::deleteDepartment');
+ $routes->get('admin/wards', 'Setting\\BedManagement::wards');
+ $routes->get('admin/bed-status', 'Setting\\BedManagement::bedStatus');
+ $routes->post('admin/wards/save', 'Setting\\BedManagement::saveWard');
+ $routes->post('admin/wards/delete', 'Setting\\BedManagement::deleteWard');
$routes->get('admin/bed-categories', 'Setting\\BedManagement::categories');
$routes->post('admin/bed-categories/save', 'Setting\\BedManagement::saveCategory');
$routes->post('admin/bed-categories/delete', 'Setting\\BedManagement::deleteCategory');
diff --git a/app/Controllers/Billing/Ipd.php b/app/Controllers/Billing/Ipd.php
index 5010093..ccd9ce8 100644
--- a/app/Controllers/Billing/Ipd.php
+++ b/app/Controllers/Billing/Ipd.php
@@ -474,6 +474,13 @@ class Ipd extends BaseController
return view('billing/ipd/panel_discharge', $panelData);
}
+ if ($tab === 'documents') {
+ return view('billing/ipd/panel_documents', [
+ 'ipd_id' => $ipdId,
+ 'ipd_info' => $panelData['ipd_info'] ?? null,
+ ]);
+ }
+
return view('billing/ipd/panel_placeholder', [
'title' => ucwords(str_replace('-', ' ', $tab)),
]);
@@ -792,6 +799,67 @@ class Ipd extends BaseController
->setBody($mpdf->Output($fileName, 'S'));
}
+ public function showIpdForm(int $ipdId, int $formNo = 1)
+ {
+ $permission = $this->requireAnyPermission([
+ 'billing.ipd.bill.print',
+ 'billing.ipd.invoice',
+ ]);
+ if ($permission) {
+ return $permission;
+ }
+
+ $formMeta = $this->getIpdFormMeta($formNo);
+ if ($formMeta === null) {
+ return $this->response->setStatusCode(404)->setBody('Unsupported form ID');
+ }
+
+ $data = $this->buildIpdPrintableFormData($ipdId, $formNo);
+ if ($data === null) {
+ return $this->response->setStatusCode(404)->setBody('IPD not found');
+ }
+
+ $html = view('billing/ipd/ipd_form_print', $data);
+ $customTemplate = $this->getActiveIpdDocumentTemplate($formNo);
+ if ($customTemplate !== null) {
+ $html = $this->renderIpdDocumentTemplateHtml($customTemplate, $data);
+ }
+
+ $mpdfTempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
+ if (! is_dir($mpdfTempDir)) {
+ mkdir($mpdfTempDir, 0755, true);
+ }
+
+ $mpdfConfig = [
+ 'tempDir' => $mpdfTempDir,
+ 'margin_top' => 8,
+ 'margin_bottom' => 8,
+ 'margin_left' => 8,
+ 'margin_right' => 8,
+ ];
+
+ if (in_array($formNo, [10, 11], true)) {
+ $mpdfConfig['format'] = $formNo === 10 ? [50.8, 152.4] : [50.8, 203.2];
+ $mpdfConfig['margin_top'] = 2;
+ $mpdfConfig['margin_bottom'] = 2;
+ $mpdfConfig['margin_left'] = 2;
+ $mpdfConfig['margin_right'] = 2;
+ } else {
+ $mpdfConfig['format'] = 'A4';
+ }
+
+ $mpdf = new Mpdf($mpdfConfig);
+ $mpdf->WriteHTML($html);
+
+ $ipdCode = (string) ($data['ipd_info']->ipd_code ?? ('IPD-' . $ipdId));
+ $fileName = 'IPD_Form_' . (int) $formNo . '_' . preg_replace('/[^A-Za-z0-9_\-]/', '_', $ipdCode) . '.pdf';
+
+ return $this->response
+ ->setHeader('Content-Type', 'application/pdf')
+ ->setHeader('Content-Disposition', 'inline; filename="' . $fileName . '"')
+ ->setBody($mpdf->Output($fileName, 'S'));
+ }
+
public function addIpdCharge(int $ipdId)
{
$permission = $this->requireAnyPermission([
@@ -1775,6 +1843,157 @@ class Ipd extends BaseController
return [$start, $end];
}
+ private function getIpdFormMeta(int $formNo): ?array
+ {
+ $meta = [
+ 1 => ['title' => 'Face Form'],
+ 3 => ['title' => 'Self Declaration Form'],
+ 5 => ['title' => 'Admission Assessment Form'],
+ 8 => ['title' => 'Progress Notes and Doctor Order'],
+ 9 => ['title' => 'Fluid In / Out'],
+ 10 => ['title' => 'Sticker [2 x 6]'],
+ 11 => ['title' => 'Sticker [2 x 8]'],
+ ];
+
+ return $meta[$formNo] ?? null;
+ }
+
+ private function buildIpdPrintableFormData(int $ipdId, int $formNo): ?array
+ {
+ $panelData = $this->ipdModel->getIpdPanelInfo($ipdId);
+ if (empty($panelData)) {
+ return null;
+ }
+
+ $ipdInfo = $panelData['ipd_info'] ?? null;
+ $personInfo = $panelData['person_info'] ?? null;
+ if ($ipdInfo === null || $personInfo === null) {
+ return null;
+ }
+
+ $personInfo->age = get_age_1(
+ $personInfo->dob ?? null,
+ $personInfo->age ?? '',
+ $personInfo->age_in_month ?? '',
+ $personInfo->estimate_dob ?? ''
+ );
+
+ $doctorRows = [];
+ if ($this->db->tableExists('ipd_master_doc_list') && $this->db->tableExists('doctor_master')) {
+ $doctorRows = $this->db->table('ipd_master_doc_list l')
+ ->select("concat_ws(' ', 'Dr.', d.p_fname, d.p_mname, d.p_lname) as doc_name", false)
+ ->join('doctor_master d', 'd.id = l.doc_id', 'inner')
+ ->where('l.ipd_id', $ipdId)
+ ->groupBy('d.id, d.p_fname, d.p_mname, d.p_lname')
+ ->orderBy('d.p_fname', 'ASC')
+ ->get()
+ ->getResultArray();
+ }
+
+ $doctorNames = array_values(array_filter(array_map(
+ static fn ($row) => trim((string) ($row['doc_name'] ?? '')),
+ $doctorRows
+ )));
+
+ if (empty($doctorNames)) {
+ $fallbackDoctor = trim((string) ($ipdInfo->r_doc_name ?? ''));
+ if ($fallbackDoctor !== '') {
+ $doctorNames[] = $fallbackDoctor;
+ }
+ }
+
+ $insuranceName = trim((string) ($ipdInfo->ins_company_name ?? ''));
+ if ($insuranceName === '' && $this->db->tableExists('organization_case_master')) {
+ $insuranceRow = $this->db->table('organization_case_master o')
+ ->select('h.ins_company_name')
+ ->join('hc_insurance h', 'h.id = o.insurance_id', 'left')
+ ->where('o.id', (int) ($ipdInfo->case_id ?? 0))
+ ->get()
+ ->getRowArray();
+ $insuranceName = trim((string) ($insuranceRow['ins_company_name'] ?? ''));
+ }
+
+ $hospitalName = defined('H_Name') ? (string) constant('H_Name') : 'Hospital';
+ $hospitalAddress = defined('H_address_1') ? (string) constant('H_address_1') : '';
+
+ return [
+ 'form_no' => $formNo,
+ 'form_meta' => $this->getIpdFormMeta($formNo),
+ 'ipd_info' => $ipdInfo,
+ 'person_info' => $personInfo,
+ 'doctor_names' => $doctorNames,
+ 'insurance_name' => $insuranceName,
+ 'hospital_name' => $hospitalName,
+ 'hospital_address' => $hospitalAddress,
+ 'generated_at' => date('d-m-Y h:i A'),
+ ];
+ }
+
+ private function getActiveIpdDocumentTemplate(int $formNo): ?array
+ {
+ if (! $this->db->tableExists('ipd_document_templates')) {
+ return null;
+ }
+
+ $row = $this->db->table('ipd_document_templates')
+ ->select('id, form_no, template_name, template_html')
+ ->where('form_no', $formNo)
+ ->where('status', 1)
+ ->orderBy('id', 'DESC')
+ ->get(1)
+ ->getRowArray();
+
+ if (! is_array($row) || empty($row)) {
+ return null;
+ }
+
+ return $row;
+ }
+
+ private function renderIpdDocumentTemplateHtml(array $templateRow, array $data): string
+ {
+ $templateHtml = (string) ($templateRow['template_html'] ?? '');
+ if (trim($templateHtml) === '') {
+ return view('billing/ipd/ipd_form_print', $data);
+ }
+
+ $formMeta = $data['form_meta'] ?? [];
+ $ipd = $data['ipd_info'] ?? null;
+ $person = $data['person_info'] ?? null;
+ $doctorNames = is_array($data['doctor_names'] ?? null) ? $data['doctor_names'] : [];
+
+ $patientName = trim((string) (($person->title ?? '') . ' ' . ($person->p_fname ?? '')));
+ if ($patientName === '') {
+ $patientName = '-';
+ }
+
+ $age = (string) ($person->age ?? '-');
+ $gender = (string) ($person->xgender ?? '-');
+ $ageGender = trim($age . ' / ' . $gender);
+ if ($ageGender === '/') {
+ $ageGender = '-';
+ }
+
+ $replacements = [
+ '{{FORM_TITLE}}' => esc((string) ($formMeta['title'] ?? 'IPD Form')),
+ '{{HOSPITAL_NAME}}' => esc((string) ($data['hospital_name'] ?? 'Hospital')),
+ '{{HOSPITAL_ADDRESS}}' => esc((string) ($data['hospital_address'] ?? '')),
+ '{{PATIENT_NAME}}' => esc($patientName),
+ '{{AGE}}' => esc($age),
+ '{{GENDER}}' => esc($gender),
+ '{{AGE_GENDER}}' => esc($ageGender),
+ '{{UHID}}' => esc((string) ($person->p_code ?? '-')),
+ '{{IPD_CODE}}' => esc((string) ($ipd->ipd_code ?? '-')),
+ '{{ADMIT_DATE}}' => esc((string) ($ipd->str_register_date ?? ($ipd->register_date ?? '-'))),
+ '{{DOCTORS}}' => esc(! empty($doctorNames) ? implode(', ', $doctorNames) : '-'),
+ '{{INSURANCE_NAME}}' => esc((string) ($data['insurance_name'] ?? 'Direct')),
+ '{{CURRENT_DATE}}' => esc(date('d-m-Y')),
+ '{{CURRENT_DATETIME}}' => esc((string) ($data['generated_at'] ?? date('d-m-Y h:i A'))),
+ ];
+
+ return strtr($templateHtml, $replacements);
+ }
+
private function calculateCashBalanceTotals(array $rows): array
{
$totalPaid = 0.0;
diff --git a/app/Controllers/Invoice.php b/app/Controllers/Invoice.php
index c122f83..02921de 100644
--- a/app/Controllers/Invoice.php
+++ b/app/Controllers/Invoice.php
@@ -21,6 +21,64 @@ class Invoice extends BaseController
return view('Invoice/payment_request_list');
}
+ public function opdlist()
+ {
+ $search = trim((string) $this->request->getGet('q'));
+
+ $builder = $this->db->table('opd_master o')
+ ->select('o.opd_id, o.opd_code, o.P_name, o.p_id, o.doc_name, o.apointment_date, o.payment_status, o.payment_mode, o.insurance_id')
+ ->select('p.p_code, p.mphone1, p.email1')
+ ->join('patient_master p', 'p.id = o.p_id', 'left')
+ ->orderBy('o.opd_id', 'DESC')
+ ->limit(200);
+
+ if ($search !== '') {
+ $builder->groupStart()
+ ->like('o.opd_code', $search, 'both')
+ ->orLike('p.p_code', $search, 'both')
+ ->orLike('o.P_name', $search, 'both')
+ ->orLike('p.mphone1', $search, 'both')
+ ->orLike('p.email1', $search, 'both')
+ ->groupEnd();
+ }
+
+ $rows = $builder->get()->getResult();
+
+ return view('Invoice/opd_invoice_list', [
+ 'search' => $search,
+ 'rows' => $rows,
+ ]);
+ }
+
+ public function chargeslist()
+ {
+ $search = trim((string) $this->request->getGet('q'));
+
+ $builder = $this->db->table('invoice_master i')
+ ->select('i.id as inv_id, i.invoice_code, i.inv_date, i.attach_id, i.insurance_id, i.invoice_status, i.payment_mode, i.payment_part_balance, i.net_amount, i.refer_by_other')
+ ->select('p.p_code, p.p_fname, p.mphone1, p.email1')
+ ->join('patient_master p', 'p.id = i.attach_id and i.attach_type=0', 'left')
+ ->orderBy('i.id', 'DESC')
+ ->limit(200);
+
+ if ($search !== '') {
+ $builder->groupStart()
+ ->like('i.invoice_code', $search, 'both')
+ ->orLike('p.p_code', $search, 'both')
+ ->orLike('p.p_fname', $search, 'both')
+ ->orLike('p.mphone1', $search, 'both')
+ ->orLike('p.email1', $search, 'both')
+ ->groupEnd();
+ }
+
+ $rows = $builder->get()->getResult();
+
+ return view('Invoice/charges_invoice_list', [
+ 'search' => $search,
+ 'rows' => $rows,
+ ]);
+ }
+
public function getRequestTable()
{
if (! $this->request->isAJAX()) {
diff --git a/app/Controllers/Opd.php b/app/Controllers/Opd.php
index 65417f6..9780bb5 100644
--- a/app/Controllers/Opd.php
+++ b/app/Controllers/Opd.php
@@ -1204,6 +1204,12 @@ class Opd extends BaseController
$query = $this->db->query($sql);
$data['payment_history'] = $query->getResult();
+ $sql = "select id,payment_date,insert_time,payment_mode,credit_debit,amount,remark,card_tran_id,update_by,
+ (case payment_mode when 0 then 'Zero Amount' when 1 then 'Cash' when 2 then 'Bank/Online' when 3 then 'Return Cash' when 4 then 'Bank Return' else 'Other' end) as payment_mode_str
+ from payment_history where payof_type=1 and payof_id=" . (int) $opdId . " order by id desc";
+ $query = $this->db->query($sql);
+ $data['payment_history_rows'] = $query->getResult();
+
$paidAmount = 0;
if (!empty($data['payment_history']) && $data['payment_history'][0]->paid_amount) {
$paidAmount = (float) $data['payment_history'][0]->paid_amount;
@@ -2923,6 +2929,95 @@ class Opd extends BaseController
]);
}
+ public function opd_cancel(int $opdId)
+ {
+ if (! $this->request->isAJAX()) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'update' => 0,
+ 'error_text' => 'Invalid request',
+ ]);
+ }
+
+ $opdId = (int) ($this->request->getPost('oid') ?? $opdId);
+ if ($opdId <= 0) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => 'Invalid OPD ID',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $opdRow = $this->db->table('opd_master')->where('opd_id', $opdId)->get(1)->getRowArray();
+ if (empty($opdRow)) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => 'OPD not found',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $user = auth()->user();
+ $userId = (int) ($user->id ?? 0);
+ $userName = (string) ($user->username ?? $user->email ?? 'User');
+ $userLabel = $userName . '[' . $userId . ']:T-' . date('d-m-Y H:i:s');
+
+ $remarkInput = trim((string) $this->request->getPost('input_remark'));
+ $remarkPrefix = $remarkInput !== '' ? $remarkInput : 'Cancel OPD';
+ $statusRemark = $remarkPrefix . ' [Update By:' . $userLabel . ']';
+
+ $sql = "select coalesce(sum(if(credit_debit>0,amount*-1,amount)),0) as paid_amount
+ from payment_history where payof_type=1 and payof_id=" . (int) $opdId;
+ $query = $this->db->query($sql);
+ $paymentHistory = $query->getResult();
+ $paidAmount = (float) ($paymentHistory[0]->paid_amount ?? 0);
+
+ $refundPaymentId = 0;
+ $this->db->transStart();
+
+ if ($paidAmount > 0 && (int) ($opdRow['opd_status'] ?? 0) !== 3) {
+ $paymentModel = new PaymentModel();
+ $refundPaymentId = $paymentModel->insertPayment([
+ 'payment_mode' => '1',
+ 'payof_type' => '1',
+ 'payof_id' => $opdId,
+ 'payof_code' => (string) ($opdRow['opd_code'] ?? ''),
+ 'credit_debit' => '1',
+ 'amount' => $paidAmount,
+ 'payment_date' => date('Y-m-d H:i:s'),
+ 'remark' => 'Refund: ' . $remarkPrefix,
+ 'update_by' => $userLabel,
+ 'update_by_id' => $userId,
+ ]);
+ }
+
+ $this->db->table('opd_master')
+ ->where('opd_id', $opdId)
+ ->update([
+ 'opd_status' => '3',
+ 'opd_status_remark' => $statusRemark,
+ ]);
+
+ $this->db->transComplete();
+ if (! $this->db->transStatus()) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => 'Unable to cancel OPD. Please retry.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ return $this->response->setJSON([
+ 'update' => 1,
+ 'showcontent' => 'OPD cancelled' . ($refundPaymentId > 0 ? ' and refund posted' : ''),
+ 'refund_payment_id' => $refundPaymentId,
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
/**
* Load scan/upload modal context for a specific OPD record.
*/
diff --git a/app/Controllers/Setting/BedManagement.php b/app/Controllers/Setting/BedManagement.php
index c94a517..033a372 100644
--- a/app/Controllers/Setting/BedManagement.php
+++ b/app/Controllers/Setting/BedManagement.php
@@ -48,6 +48,341 @@ class BedManagement extends BaseController
return $builder->countAllResults() > 0;
}
+ private function wardCodeExists(string $wardCode, int $excludeId = 0): bool
+ {
+ $builder = $this->db->table('ward_master')->where('ward_code', $wardCode);
+ if ($excludeId > 0) {
+ $builder->where('id !=', $excludeId);
+ }
+
+ return $builder->countAllResults() > 0;
+ }
+
+ public function wards(): string
+ {
+ $departments = [(object) [
+ 'iId' => 0,
+ 'vName' => 'All Department',
+ ]];
+
+ if ($this->db->tableExists('hc_department')) {
+ $departmentRows = $this->db->table('hc_department')
+ ->orderBy('vName', 'ASC')
+ ->get()
+ ->getResult();
+
+ $departments = array_merge($departments, $departmentRows);
+ }
+
+ $wardBuilder = $this->db->table('ward_master w')
+ ->orderBy('w.ward_name', 'ASC');
+
+ if ($this->db->tableExists('hc_department')) {
+ $wardBuilder->select('w.*, COALESCE(d.vName, "All Department") AS department_name', false)
+ ->join('hc_department d', 'd.iId = w.department_id', 'left');
+ } else {
+ $wardBuilder->select('w.*, "All Department" AS department_name', false);
+ }
+
+ $wardRows = $wardBuilder->get()->getResult();
+
+ return view('Setting/Bed/ward_list', [
+ 'wards' => $wardRows,
+ 'departments' => $departments,
+ ]);
+ }
+
+ public function saveWard()
+ {
+ if (! $this->request->isAJAX()) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
+ }
+
+ $id = (int) $this->request->getPost('id');
+ $wardCode = trim((string) $this->request->getPost('ward_code'));
+ $wardName = trim((string) $this->request->getPost('ward_name'));
+ $departmentIdRaw = $this->request->getPost('department_id');
+ $departmentId = $departmentIdRaw === null || $departmentIdRaw === '' ? 0 : (int) $departmentIdRaw;
+
+ if ($wardCode === '' || $wardName === '') {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Ward code and ward name are required.']);
+ }
+
+ if ($this->wardCodeExists($wardCode, $id)) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Ward code already exists.']);
+ }
+
+ if ($departmentId > 0 && $this->db->tableExists('hc_department')) {
+ $departmentExists = $this->db->table('hc_department')
+ ->where('iId', $departmentId)
+ ->countAllResults();
+
+ if ($departmentExists <= 0) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid department selected.']);
+ }
+ }
+
+ $user = auth()->user();
+ $data = [
+ 'ward_code' => $wardCode,
+ 'ward_name' => $wardName,
+ 'department_id' => $departmentId,
+ 'building_id' => $this->request->getPost('building_id') ?: null,
+ 'floor_number' => $this->request->getPost('floor_number') ?: null,
+ 'ward_type' => $this->request->getPost('ward_type') ?: 'General',
+ 'gender_type' => $this->request->getPost('gender_type') ?: 'unisex',
+ 'ward_category' => $this->request->getPost('ward_category') ?: 'adult',
+ 'total_capacity' => $this->request->getPost('total_capacity') ?: 0,
+ 'nurse_station_location' => $this->request->getPost('nurse_station_location'),
+ 'has_oxygen' => $this->request->getPost('has_oxygen') ? 1 : 0,
+ 'has_suction' => $this->request->getPost('has_suction') ? 1 : 0,
+ 'has_monitor' => $this->request->getPost('has_monitor') ? 1 : 0,
+ 'status' => $this->request->getPost('status') ?: 'active',
+ 'remarks' => $this->request->getPost('remarks'),
+ ];
+
+ $model = new WardModel();
+ if ($id > 0) {
+ $updated = $model->update($id, $data);
+
+ return $this->response->setJSON([
+ 'update' => $updated ? 1 : 0,
+ 'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $data['created_by'] = $user->id ?? null;
+ $insertId = $model->insert($data);
+
+ return $this->response->setJSON([
+ 'insertid' => $insertId,
+ 'error_text' => $insertId > 0 ? '' : 'Please check',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ public function deleteWard()
+ {
+ if (! $this->request->isAJAX()) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
+ }
+
+ $id = (int) $this->request->getPost('id');
+ if ($id <= 0) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid ward ID']);
+ }
+
+ $bedCount = $this->db->table('bed_master')
+ ->where('ward_id', $id)
+ ->countAllResults();
+
+ if ($bedCount > 0) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => $bedCount . ' bed(s) are mapped with this ward. Cannot delete.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $model = new WardModel();
+ $deleted = $model->delete($id);
+
+ return $this->response->setJSON([
+ 'update' => $deleted ? 1 : 0,
+ 'error_text' => $deleted ? '' : 'Delete failed. Please try again.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ public function departments(): string
+ {
+ if (! $this->db->tableExists('hc_department')) {
+ return view('Setting/Bed/department_list', [
+ 'departments' => [],
+ 'tableMissing' => true,
+ ]);
+ }
+
+ $departmentRows = $this->db->table('hc_department')
+ ->orderBy('vName', 'ASC')
+ ->get()
+ ->getResult();
+
+ return view('Setting/Bed/department_list', [
+ 'departments' => $departmentRows,
+ 'tableMissing' => false,
+ ]);
+ }
+
+ public function saveDepartment()
+ {
+ if (! $this->request->isAJAX()) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
+ }
+
+ if (! $this->db->tableExists('hc_department')) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Department table not found.']);
+ }
+
+ $id = (int) $this->request->getPost('id');
+ $name = trim((string) $this->request->getPost('department_name'));
+ $typeId = $this->request->getPost('hc_type_id');
+ $typeId = $typeId === null || $typeId === '' ? null : (int) $typeId;
+
+ if ($name === '') {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Department name is required.']);
+ }
+
+ $duplicate = $this->db->table('hc_department')
+ ->where('vName', $name);
+ if ($id > 0) {
+ $duplicate->where('iId !=', $id);
+ }
+
+ if ($duplicate->countAllResults() > 0) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Department name already exists.']);
+ }
+
+ $payload = [
+ 'vName' => $name,
+ 'hc_type_id' => $typeId,
+ ];
+
+ if ($id > 0) {
+ $updated = $this->db->table('hc_department')
+ ->where('iId', $id)
+ ->update($payload);
+
+ return $this->response->setJSON([
+ 'update' => $updated ? 1 : 0,
+ 'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $inserted = $this->db->table('hc_department')->insert($payload);
+ $insertId = $inserted ? (int) $this->db->insertID() : 0;
+
+ return $this->response->setJSON([
+ 'insertid' => $insertId,
+ 'error_text' => $insertId > 0 ? '' : 'Please check',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ public function deleteDepartment()
+ {
+ if (! $this->request->isAJAX()) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
+ }
+
+ if (! $this->db->tableExists('hc_department')) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Department table not found.']);
+ }
+
+ $id = (int) $this->request->getPost('id');
+ if ($id <= 0) {
+ return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid department ID']);
+ }
+
+ $wardCount = $this->db->table('ward_master')
+ ->where('department_id', $id)
+ ->countAllResults();
+
+ if ($wardCount > 0) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => $wardCount . ' ward(s) use this department. Cannot delete.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $this->db->table('hc_department')->where('iId', $id)->delete();
+ $deleted = $this->db->affectedRows() > 0;
+
+ return $this->response->setJSON([
+ 'update' => $deleted ? 1 : 0,
+ 'error_text' => $deleted ? '' : 'Delete failed. Please try again.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ public function bedStatus(): string
+ {
+ $departments = [(object) ['iId' => 0, 'vName' => 'All Department']];
+ if ($this->db->tableExists('hc_department')) {
+ $departments = array_merge(
+ $departments,
+ $this->db->table('hc_department')->orderBy('vName', 'ASC')->get()->getResult()
+ );
+ }
+
+ $wards = $this->db->table('ward_master')
+ ->select('id, ward_name, department_id')
+ ->orderBy('ward_name', 'ASC')
+ ->get()
+ ->getResult();
+
+ $builder = $this->db->table('ipd_master i')
+ ->select('i.id as ipd_id, i.ipd_code, i.register_date, i.p_id')
+ ->where('i.ipd_status', 0)
+ ->orderBy('i.id', 'DESC');
+
+ if ($this->db->tableExists('patient_master')) {
+ $builder->select('p.p_code, p.p_fname, p.p_lname, p.mphone1, p.mphone2')
+ ->join('patient_master p', 'p.id = i.p_id', 'left');
+ }
+
+ if ($this->db->tableExists('bed_assignment_history')) {
+ $builder->join(
+ '(select max(id) as id, ipd_id from bed_assignment_history group by ipd_id) bah_latest',
+ 'bah_latest.ipd_id = i.id',
+ 'left',
+ false
+ )->join('bed_assignment_history bah', 'bah.id = bah_latest.id', 'left');
+
+ if ($this->db->tableExists('bed_master')) {
+ $builder->join('bed_master b', 'b.id = bah.bed_id', 'left');
+ }
+ if ($this->db->tableExists('ward_master')) {
+ $builder->join('ward_master w', 'w.id = bah.ward_id', 'left');
+ }
+ } else {
+ if ($this->db->tableExists('bed_master')) {
+ $builder->join('bed_master b', 'b.current_ipd_id = i.id', 'left');
+ }
+ if ($this->db->tableExists('ward_master')) {
+ $builder->join('ward_master w', 'w.id = b.ward_id', 'left');
+ }
+ }
+
+ $builder->select('b.bed_number, b.bed_code, w.id as ward_id, w.ward_name, w.department_id');
+
+ if ($this->db->tableExists('hc_department')) {
+ $builder->select('d.vName as department_name')
+ ->join('hc_department d', 'd.iId = w.department_id', 'left');
+ } else {
+ $builder->select('"All Department" as department_name', false);
+ }
+
+ $rows = $builder->get()->getResult();
+
+ return view('Setting/Bed/bed_status_list', [
+ 'rows' => $rows,
+ 'departments' => $departments,
+ 'wards' => $wards,
+ ]);
+ }
+
public function categories(): string
{
$model = new BedCategoryModel();
@@ -72,34 +407,35 @@ class BedManagement extends BaseController
}
$data = [
- 'category_code' => $code,
- 'category_name' => $name,
- 'category_type' => $this->request->getPost('category_type'),
- 'base_charge_per_day' => $this->request->getPost('base_charge_per_day') ?? 0,
+ 'category_code' => $code,
+ 'category_name' => $name,
+ 'category_type' => $this->request->getPost('category_type'),
+ 'base_charge_per_day' => $this->request->getPost('base_charge_per_day') ?? 0,
'nursing_charge_per_day' => $this->request->getPost('nursing_charge_per_day') ?? 0,
- 'amenities' => $this->request->getPost('amenities'),
- 'description' => $this->request->getPost('description'),
- 'status' => $this->request->getPost('status') ?? 'active',
+ 'amenities' => $this->request->getPost('amenities'),
+ 'description' => $this->request->getPost('description'),
+ 'status' => $this->request->getPost('status') ?? 'active',
];
$model = new BedCategoryModel();
if ($id > 0) {
$updated = $model->update($id, $data);
+
return $this->response->setJSON([
- 'update' => $updated ? 1 : 0,
+ 'update' => $updated ? 1 : 0,
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
$insertId = $model->insert($data);
return $this->response->setJSON([
- 'insertid' => $insertId,
+ 'insertid' => $insertId,
'error_text' => $insertId > 0 ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
@@ -114,26 +450,41 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid category ID']);
}
- $model = new BedCategoryModel();
+ // Block deletion if any beds in this category are currently occupied by IPD patients
+ $inUseCount = $this->db->table('bed_master')
+ ->where('bed_category_id', $id)
+ ->where('current_ipd_id IS NOT NULL', null, false)
+ ->countAllResults();
+
+ if ($inUseCount > 0) {
+ return $this->response->setJSON([
+ 'update' => 0,
+ 'error_text' => "{$inUseCount} bed(s) in this category are currently occupied by IPD patient(s). Cannot delete.",
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
+ ]);
+ }
+
+ $model = new BedCategoryModel();
$deleted = $model->delete($id);
return $this->response->setJSON([
- 'update' => $deleted ? 1 : 0,
- 'error_text' => $deleted ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'update' => $deleted ? 1 : 0,
+ 'error_text' => $deleted ? '' : 'Delete failed. Please try again.',
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
public function beds(): string
{
- $bedModel = new BedMasterModel();
- $wardModel = new WardModel();
+ $bedModel = new BedMasterModel();
+ $wardModel = new WardModel();
$categoryModel = new BedCategoryModel();
return view('Setting/Bed/bed_list', [
- 'beds' => $bedModel->getAllWithRelations(),
- 'wards' => $wardModel->getAllActive(),
+ 'beds' => $bedModel->getAllWithRelations(),
+ 'wards' => $wardModel->getAllActive(),
'categories' => $categoryModel->getAll(),
]);
}
@@ -144,10 +495,10 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
}
- $id = (int) $this->request->getPost('id');
- $bedCode = trim((string) $this->request->getPost('bed_code'));
- $bedNumber = trim((string) $this->request->getPost('bed_number'));
- $wardId = (int) $this->request->getPost('ward_id');
+ $id = (int) $this->request->getPost('id');
+ $bedCode = trim((string) $this->request->getPost('bed_code'));
+ $bedNumber = trim((string) $this->request->getPost('bed_number'));
+ $wardId = (int) $this->request->getPost('ward_id');
$categoryId = (int) $this->request->getPost('bed_category_id');
if ($bedCode === '' || $bedNumber === '' || $wardId <= 0 || $categoryId <= 0) {
@@ -163,41 +514,42 @@ class BedManagement extends BaseController
}
$data = [
- 'bed_code' => $bedCode,
- 'bed_number' => $bedNumber,
- 'ward_id' => $wardId,
- 'bed_category_id' => $categoryId,
- 'bed_status' => $this->request->getPost('bed_status') ?? 'available',
- 'bed_position' => $this->request->getPost('bed_position'),
- 'has_oxygen' => $this->request->getPost('has_oxygen') ? 1 : 0,
- 'has_suction' => $this->request->getPost('has_suction') ? 1 : 0,
- 'has_monitor' => $this->request->getPost('has_monitor') ? 1 : 0,
- 'has_ventilator' => $this->request->getPost('has_ventilator') ? 1 : 0,
- 'is_isolation_bed' => $this->request->getPost('is_isolation_bed') ? 1 : 0,
- 'base_charge_override' => $this->request->getPost('base_charge_override') ?: null,
+ 'bed_code' => $bedCode,
+ 'bed_number' => $bedNumber,
+ 'ward_id' => $wardId,
+ 'bed_category_id' => $categoryId,
+ 'bed_status' => $this->request->getPost('bed_status') ?? 'available',
+ 'bed_position' => $this->request->getPost('bed_position'),
+ 'has_oxygen' => $this->request->getPost('has_oxygen') ? 1 : 0,
+ 'has_suction' => $this->request->getPost('has_suction') ? 1 : 0,
+ 'has_monitor' => $this->request->getPost('has_monitor') ? 1 : 0,
+ 'has_ventilator' => $this->request->getPost('has_ventilator') ? 1 : 0,
+ 'is_isolation_bed' => $this->request->getPost('is_isolation_bed') ? 1 : 0,
+ 'base_charge_override' => $this->request->getPost('base_charge_override') ?: null,
'nursing_charge_override' => $this->request->getPost('nursing_charge_override') ?: null,
- 'status' => $this->request->getPost('status') ?? 'active',
- 'remarks' => $this->request->getPost('remarks'),
+ 'status' => $this->request->getPost('status') ?? 'active',
+ 'remarks' => $this->request->getPost('remarks'),
];
$model = new BedMasterModel();
if ($id > 0) {
$updated = $model->update($id, $data);
+
return $this->response->setJSON([
- 'update' => $updated ? 1 : 0,
+ 'update' => $updated ? 1 : 0,
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
$insertId = $model->insert($data);
return $this->response->setJSON([
- 'insertid' => $insertId,
+ 'insertid' => $insertId,
'error_text' => $insertId > 0 ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
@@ -212,20 +564,20 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid bed ID']);
}
- $model = new BedMasterModel();
+ $model = new BedMasterModel();
$deleted = $model->delete($id);
return $this->response->setJSON([
- 'update' => $deleted ? 1 : 0,
+ 'update' => $deleted ? 1 : 0,
'error_text' => $deleted ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
public function maintenance(): string
{
- $bedModel = new BedMasterModel();
+ $bedModel = new BedMasterModel();
$maintenanceModel = new BedMaintenanceLogModel();
return view('Setting/Bed/maintenance_list', [
@@ -240,45 +592,46 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
}
- $id = (int) $this->request->getPost('id');
+ $id = (int) $this->request->getPost('id');
$bedId = (int) $this->request->getPost('bed_id');
- $type = trim((string) $this->request->getPost('maintenance_type'));
+ $type = trim((string) $this->request->getPost('maintenance_type'));
if ($bedId <= 0 || $type === '') {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed and maintenance type are required.']);
}
$data = [
- 'bed_id' => $bedId,
- 'maintenance_type' => $type,
- 'scheduled_date' => $this->request->getPost('scheduled_date') ?: null,
- 'completed_date' => $this->normalizeDateTime($this->request->getPost('completed_date')),
- 'performed_by' => $this->request->getPost('performed_by'),
- 'issue_description' => $this->request->getPost('issue_description'),
- 'action_taken' => $this->request->getPost('action_taken'),
+ 'bed_id' => $bedId,
+ 'maintenance_type' => $type,
+ 'scheduled_date' => $this->request->getPost('scheduled_date') ?: null,
+ 'completed_date' => $this->normalizeDateTime($this->request->getPost('completed_date')),
+ 'performed_by' => $this->request->getPost('performed_by'),
+ 'issue_description' => $this->request->getPost('issue_description'),
+ 'action_taken' => $this->request->getPost('action_taken'),
'next_maintenance_date' => $this->request->getPost('next_maintenance_date') ?: null,
- 'cost' => $this->request->getPost('cost') ?: 0,
- 'status' => $this->request->getPost('status') ?? 'pending',
+ 'cost' => $this->request->getPost('cost') ?: 0,
+ 'status' => $this->request->getPost('status') ?? 'pending',
];
$model = new BedMaintenanceLogModel();
if ($id > 0) {
$updated = $model->update($id, $data);
+
return $this->response->setJSON([
- 'update' => $updated ? 1 : 0,
+ 'update' => $updated ? 1 : 0,
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
$insertId = $model->insert($data);
return $this->response->setJSON([
- 'insertid' => $insertId,
+ 'insertid' => $insertId,
'error_text' => $insertId > 0 ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
@@ -293,27 +646,27 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid maintenance ID']);
}
- $model = new BedMaintenanceLogModel();
+ $model = new BedMaintenanceLogModel();
$deleted = $model->delete($id);
return $this->response->setJSON([
- 'update' => $deleted ? 1 : 0,
+ 'update' => $deleted ? 1 : 0,
'error_text' => $deleted ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
public function assignmentHistory(): string
{
- $model = new BedAssignmentHistoryModel();
- $bedModel = new BedMasterModel();
+ $model = new BedAssignmentHistoryModel();
+ $bedModel = new BedMasterModel();
$wardModel = new WardModel();
return view('Setting/Bed/assignment_history', [
'assignments' => $model->getAllWithRelations(),
- 'beds' => $bedModel->getAllWithRelations(),
- 'wards' => $wardModel->getAllActive(),
+ 'beds' => $bedModel->getAllWithRelations(),
+ 'wards' => $wardModel->getAllActive(),
]);
}
@@ -323,10 +676,10 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
}
- $id = (int) $this->request->getPost('id');
- $bedId = (int) $this->request->getPost('bed_id');
- $wardId = (int) $this->request->getPost('ward_id');
- $type = trim((string) $this->request->getPost('assignment_type'));
+ $id = (int) $this->request->getPost('id');
+ $bedId = (int) $this->request->getPost('bed_id');
+ $wardId = (int) $this->request->getPost('ward_id');
+ $type = trim((string) $this->request->getPost('assignment_type'));
$assignedDate = $this->normalizeDateTime($this->request->getPost('assigned_date'));
if ($bedId <= 0 || $wardId <= 0 || $type === '' || $assignedDate === null) {
@@ -334,39 +687,40 @@ class BedManagement extends BaseController
}
$data = [
- 'ipd_id' => $this->request->getPost('ipd_id') ?: null,
- 'bed_id' => $bedId,
- 'assignment_type' => $type,
- 'assigned_date' => $assignedDate,
- 'discharged_date' => $this->normalizeDateTime($this->request->getPost('discharged_date')),
- 'assigned_by' => $this->request->getPost('assigned_by') ?: null,
- 'transfer_reason' => $this->request->getPost('transfer_reason'),
+ 'ipd_id' => $this->request->getPost('ipd_id') ?: null,
+ 'bed_id' => $bedId,
+ 'assignment_type' => $type,
+ 'assigned_date' => $assignedDate,
+ 'discharged_date' => $this->normalizeDateTime($this->request->getPost('discharged_date')),
+ 'assigned_by' => $this->request->getPost('assigned_by') ?: null,
+ 'transfer_reason' => $this->request->getPost('transfer_reason'),
'transfer_from_bed_id' => $this->request->getPost('transfer_from_bed_id') ?: null,
- 'remarks' => $this->request->getPost('remarks'),
- 'ward_id' => $wardId,
- 'released_date' => $this->normalizeDateTime($this->request->getPost('released_date')),
- 'total_days' => $this->request->getPost('total_days') ?: 0,
- 'release_reason' => $this->request->getPost('release_reason'),
+ 'remarks' => $this->request->getPost('remarks'),
+ 'ward_id' => $wardId,
+ 'released_date' => $this->normalizeDateTime($this->request->getPost('released_date')),
+ 'total_days' => $this->request->getPost('total_days') ?: 0,
+ 'release_reason' => $this->request->getPost('release_reason'),
];
$model = new BedAssignmentHistoryModel();
if ($id > 0) {
$updated = $model->update($id, $data);
+
return $this->response->setJSON([
- 'update' => $updated ? 1 : 0,
+ 'update' => $updated ? 1 : 0,
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
$insertId = $model->insert($data);
return $this->response->setJSON([
- 'insertid' => $insertId,
+ 'insertid' => $insertId,
'error_text' => $insertId > 0 ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
@@ -381,14 +735,14 @@ class BedManagement extends BaseController
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid assignment ID']);
}
- $model = new BedAssignmentHistoryModel();
+ $model = new BedAssignmentHistoryModel();
$deleted = $model->delete($id);
return $this->response->setJSON([
- 'update' => $deleted ? 1 : 0,
+ 'update' => $deleted ? 1 : 0,
'error_text' => $deleted ? '' : 'Please check',
- 'csrfName' => csrf_token(),
- 'csrfHash' => csrf_hash(),
+ 'csrfName' => csrf_token(),
+ 'csrfHash' => csrf_hash(),
]);
}
-}
+}
\ No newline at end of file
diff --git a/app/Controllers/Setting/Template.php b/app/Controllers/Setting/Template.php
index 248cdb9..cd25deb 100644
--- a/app/Controllers/Setting/Template.php
+++ b/app/Controllers/Setting/Template.php
@@ -1346,4 +1346,343 @@ HTML;
return redirect()->to(base_url('setting/template/discharge_templates'));
}
+
+ private function ensureIpdDocumentTemplateTable(): void
+ {
+ if ($this->db->tableExists('ipd_document_templates')) {
+ return;
+ }
+
+ $sql = "CREATE TABLE IF NOT EXISTS ipd_document_templates (
+ id INT NOT NULL AUTO_INCREMENT,
+ form_no INT NOT NULL,
+ template_name VARCHAR(160) NOT NULL,
+ template_html LONGTEXT NOT NULL,
+ status TINYINT(1) NOT NULL DEFAULT 1,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ KEY idx_form_no (form_no),
+ KEY idx_status (status)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
+
+ $this->db->query($sql);
+ }
+
+ private function defaultIpdDocumentTemplates(): array
+ {
+ return [
+ [
+ 'form_no' => 1,
+ 'template_name' => 'Legacy Face Form (IPD2)',
+ 'template_html' => <<<'HTML'
+
+
+HTML,
+ ],
+ [
+ 'form_no' => 3,
+ 'template_name' => 'Legacy Self Declaration (IPD2)',
+ 'template_html' => <<<'HTML'
+
+
SELF DECLARATION FROM HEALTH INSURANCE CARD HOLDER
+
मेडिक्लेम बीमा कार्ड धारक द्वारा स्वघोषणा
+
+
+
+ Patient Name: {{PATIENT_NAME}}
+ UHID: {{UHID}}
+ IPD: {{IPD_CODE}}
+
+
+ Age/Gender: {{AGE_GENDER}}
+ Admission: {{ADMIT_DATE}}
+ Insurance: {{INSURANCE_NAME}}
+
+
+
+
+ मैं __________________________ यह घोषणा करता/करती हूँ कि मरीज {{PATIENT_NAME}} का मेडिक्लेम {{INSURANCE_NAME}} में है,
+ और भर्ती दिनांक {{ADMIT_DATE}} को हुई है। मैंने आवश्यक दस्तावेज जमा कर दिए हैं और यदि क्लेम पूर्ण/आंशिक स्वीकृत नहीं होता
+ है तो शेष देय राशि का भुगतान स्वयं करूँगा/करूँगी।
+
+
+
हस्ताक्षर / अंगूठा निशान: __________________________
+
नाम: __________________________ मरीज से संबंध: __________________________
+
पता: __________________________ फ़ोन नंबर: __________________________
+
दिनांक: {{CURRENT_DATE}}
+
+HTML,
+ ],
+ [
+ 'form_no' => 5,
+ 'template_name' => 'Legacy Admission History & Physical Assessment',
+ 'template_html' => <<<'HTML'
+
+
ADMISSION HISTORY AND PHYSICAL ASSESSMENT FORM
+
Patient: {{PATIENT_NAME}} Age/Gender: {{AGE_GENDER}} UHID: {{UHID}} IPD: {{IPD_CODE}} Admit Date: {{ADMIT_DATE}}
+
Diagnosis: ______________________________________________
+
Time of Patient Arrival: ____________ Time of Doctor Assessment: ____________
+
Consciousness: [ ] Awake [ ] Alert [ ] In pain [ ] Response to verbal commands [ ] Unresponsive
+
GCS: E___ V___ M___ Airway/Breathing: [ ] Clear [ ] Noisy [ ] Stridor [ ] Obstruction
+
Allergic To: ______________________________________________
+
Present Complaints:
+
+
+
Past Medical History:
+
+ Diabetes / Metabolic Jaundice / CLD
+ Hypertension / IHD Osteoarthritis
+ Asthma / COPD / TB Tuberculosis
+ Others:
+
+
+
Drug History:
+
+
Past Surgical History:
+
+
+
Declaration: I hereby declare that the facts recorded above are accurate to the best of my knowledge.
+
Name of Patient/Relative: ________________________ Signature: ________________________
+
Date: {{CURRENT_DATE}}
+
+HTML,
+ ],
+ [
+ 'form_no' => 8,
+ 'template_name' => 'Legacy Progress Notes and Doctor Order',
+ 'template_html' => <<<'HTML'
+
+
PROGRESS NOTES AND DOCTOR'S ORDER
+
Name: {{PATIENT_NAME}} IPD: {{IPD_CODE}} UHID: {{UHID}} Age/Gender: {{AGE_GENDER}}
+
+
+
+ DATE
+ PROGRESS NOTES AND DOCTOR'S ORDER
+
+
+
+
+
+
+
+HTML,
+ ],
+ [
+ 'form_no' => 9,
+ 'template_name' => 'Legacy Oral / Enteral Intake Output Chart',
+ 'template_html' => <<<'HTML'
+
+
ORAL / ENTERAL INTAKE & OUTPUT CHART
+
Name: {{PATIENT_NAME}} IPD: {{IPD_CODE}} UHID: {{UHID}} Age/Gender: {{AGE_GENDER}}
+
+
+
+ SR.No.
+ Date
+ Time
+ Description
+ Vol.
+ Vol.
+ Total
+ Urine
+ Stool
+ Other
+ Other
+ Other
+ Total
+
+ 1
+ 2
+ 3
+ 4
+ 5
+
+
+HTML,
+ ],
+ [
+ 'form_no' => 10,
+ 'template_name' => 'Legacy Sticker [2 x 6]',
+ 'template_html' => <<<'HTML'
+
+
{{HOSPITAL_NAME}}
+
Patient Name: {{PATIENT_NAME}}
+
Age / Gender: {{AGE_GENDER}}
+
UHID / Patient ID: {{UHID}}
+
IPD Code: {{IPD_CODE}}
+
Dept./Doctor: {{DOCTORS}}
+
Date of Admission: {{ADMIT_DATE}}
+
+HTML,
+ ],
+ [
+ 'form_no' => 11,
+ 'template_name' => 'Legacy Sticker [2 x 8]',
+ 'template_html' => <<<'HTML'
+
+
{{HOSPITAL_NAME}}
+
{{HOSPITAL_ADDRESS}}
+
Patient Name: {{PATIENT_NAME}}
+
Age / Gender: {{AGE_GENDER}}
+
UHID / Patient ID: {{UHID}}
+
IPD Code: {{IPD_CODE}}
+
Dept./Doctor: {{DOCTORS}}
+
Date of Admission: {{ADMIT_DATE}}
+
Insurance: {{INSURANCE_NAME}}
+
+HTML,
+ ],
+ ];
+ }
+
+ private function ensureDefaultIpdDocumentTemplatesSeeded(): void
+ {
+ $this->ensureIpdDocumentTemplateTable();
+ if (! $this->db->tableExists('ipd_document_templates')) {
+ return;
+ }
+
+ $table = $this->db->table('ipd_document_templates');
+ foreach ($this->defaultIpdDocumentTemplates() as $row) {
+ $formNo = (int) ($row['form_no'] ?? 0);
+ $templateName = (string) ($row['template_name'] ?? '');
+ if ($formNo <= 0 || $templateName === '') {
+ continue;
+ }
+
+ $exists = $this->db->table('ipd_document_templates')
+ ->where('form_no', $formNo)
+ ->where('template_name', $templateName)
+ ->countAllResults();
+
+ if ($exists > 0) {
+ continue;
+ }
+
+ $table->insert([
+ 'form_no' => $formNo,
+ 'template_name' => $templateName,
+ 'template_html' => (string) ($row['template_html'] ?? ''),
+ 'status' => 1,
+ ]);
+ }
+ }
+
+ public function ipd_document_templates()
+ {
+ if ($resp = $this->requireAnyPermission(['template.discharge'])) {
+ return $resp;
+ }
+
+ $this->ensureDefaultIpdDocumentTemplatesSeeded();
+
+ $notice = '';
+ $noticeType = 'success';
+
+ if (strtolower($this->request->getMethod()) === 'post') {
+ $id = (int) ($this->request->getPost('id') ?? 0);
+ $formNo = (int) ($this->request->getPost('form_no') ?? 0);
+ $templateName = trim((string) ($this->request->getPost('template_name') ?? ''));
+ $templateHtml = (string) ($this->request->getPost('template_html') ?? '');
+ $status = (int) ($this->request->getPost('status') ?? 1) === 1 ? 1 : 0;
+
+ if (! in_array($formNo, [1, 3, 5, 8, 9, 10, 11], true)) {
+ $notice = 'Invalid form number.';
+ $noticeType = 'danger';
+ } elseif ($templateName === '' || trim($templateHtml) === '') {
+ $notice = 'Form number, template name and HTML are required.';
+ $noticeType = 'danger';
+ } else {
+ $table = $this->db->table('ipd_document_templates');
+ $data = [
+ 'form_no' => $formNo,
+ 'template_name' => $templateName,
+ 'template_html' => $templateHtml,
+ 'status' => $status,
+ ];
+
+ if ($id > 0) {
+ $table->where('id', $id)->update($data);
+ $notice = 'Template updated.';
+ } else {
+ $table->insert($data);
+ $notice = 'Template created.';
+ }
+ }
+ }
+
+ $editId = (int) ($this->request->getGet('edit') ?? 0);
+ $editRow = [];
+ if ($editId > 0) {
+ $editRow = $this->db->table('ipd_document_templates')
+ ->where('id', $editId)
+ ->get(1)
+ ->getRowArray() ?? [];
+ }
+
+ $rows = $this->db->table('ipd_document_templates')
+ ->orderBy('form_no', 'ASC')
+ ->orderBy('id', 'ASC')
+ ->get()
+ ->getResultArray();
+
+ return view('Setting/Template/ipd_document_templates', [
+ 'rows' => $rows,
+ 'edit_row' => $editRow,
+ 'notice' => $notice,
+ 'notice_type' => $noticeType,
+ ]);
+ }
+
+ public function ipd_document_template_delete(int $id)
+ {
+ if ($resp = $this->requireAnyPermission(['template.discharge'])) {
+ return $resp;
+ }
+
+ $id = (int) $id;
+ if ($id > 0 && $this->db->tableExists('ipd_document_templates')) {
+ $this->db->table('ipd_document_templates')->where('id', $id)->delete();
+ }
+
+ return redirect()->to(base_url('setting/template/ipd_document_templates'));
+ }
}
diff --git a/app/Helpers/common_helper.php b/app/Helpers/common_helper.php
index ab8acbe..f811ce6 100644
--- a/app/Helpers/common_helper.php
+++ b/app/Helpers/common_helper.php
@@ -2,7 +2,13 @@
function str_to_MysqlDate(string $strDate): string
{
+ $strDate = trim($strDate);
+
if ($strDate !== '') {
+ if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $strDate) === 1) {
+ return $strDate;
+ }
+
$date = explode('/', $strDate);
if (count($date) === 3) {
return $date[2] . '-' . $date[1] . '-' . $date[0];
diff --git a/app/Models/BedCategoryModel.php b/app/Models/BedCategoryModel.php
index c452a58..896e775 100644
--- a/app/Models/BedCategoryModel.php
+++ b/app/Models/BedCategoryModel.php
@@ -6,8 +6,9 @@ use CodeIgniter\Model;
class BedCategoryModel extends Model
{
- protected $table = 'bed_category_master';
- protected $primaryKey = 'id';
+ protected $table = 'bed_category_master';
+ protected $primaryKey = 'id';
+ protected $returnType = 'object';
protected $allowedFields = [
'category_code',
'category_name',
diff --git a/app/Models/BedMasterModel.php b/app/Models/BedMasterModel.php
index 4da2e45..10be772 100644
--- a/app/Models/BedMasterModel.php
+++ b/app/Models/BedMasterModel.php
@@ -6,8 +6,9 @@ use CodeIgniter\Model;
class BedMasterModel extends Model
{
- protected $table = 'bed_master';
+ protected $table = 'bed_master';
protected $primaryKey = 'id';
+ protected $returnType = 'object';
protected $allowedFields = [
'bed_code',
'bed_number',
diff --git a/app/Models/WardModel.php b/app/Models/WardModel.php
index cd72de2..d740d07 100644
--- a/app/Models/WardModel.php
+++ b/app/Models/WardModel.php
@@ -6,8 +6,9 @@ use CodeIgniter\Model;
class WardModel extends Model
{
- protected $table = 'ward_master';
+ protected $table = 'ward_master';
protected $primaryKey = 'id';
+ protected $returnType = 'object';
protected $allowedFields = [
'ward_code',
'ward_name',
@@ -27,6 +28,11 @@ class WardModel extends Model
'created_by',
];
+ public function getAll(): array
+ {
+ return $this->orderBy('ward_name', 'ASC')->findAll();
+ }
+
public function getAllActive(): array
{
return $this->where('status', 'active')
diff --git a/app/Views/Invoice/charges_invoice_list.php b/app/Views/Invoice/charges_invoice_list.php
new file mode 100644
index 0000000..c474ada
--- /dev/null
+++ b/app/Views/Invoice/charges_invoice_list.php
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+ Invoice Code
+ Patient
+ Patient Code
+ Date
+ Mobile
+ Type
+ Amount
+ Action
+
+
+
+
+ insurance_id ?? 0) > 1) ? 'Org.' : 'Direct';
+ $invDate = ! empty($row->inv_date) ? date('d-m-Y', strtotime((string) $row->inv_date)) : '-';
+ ?>
+
+ = esc((string) ($row->invoice_code ?? '-')) ?>
+ = esc((string) ($row->p_fname ?? '-')) ?>
+ = esc((string) ($row->p_code ?? '-')) ?>
+ = esc($invDate) ?>
+ = esc((string) ($row->mphone1 ?? '-')) ?>
+ = esc($invType) ?>
+ = esc(number_format((float) ($row->net_amount ?? 0), 2, '.', '')) ?>
+
+ Open
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/Invoice/opd_invoice_list.php b/app/Views/Invoice/opd_invoice_list.php
new file mode 100644
index 0000000..e1724d5
--- /dev/null
+++ b/app/Views/Invoice/opd_invoice_list.php
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+ OPD Code
+ Patient
+ Patient Code
+ Date
+ Doctor
+ Mobile
+ Type
+ Action
+
+
+
+
+ insurance_id ?? 0) > 1) ? 'Org.' : 'Direct';
+ $opdDate = ! empty($row->apointment_date) ? date('d-m-Y', strtotime((string) $row->apointment_date)) : '-';
+ ?>
+
+ = esc((string) ($row->opd_code ?? '-')) ?>
+ = esc((string) ($row->P_name ?? '-')) ?>
+ = esc((string) ($row->p_code ?? '-')) ?>
+ = esc($opdDate) ?>
+ = esc((string) ($row->doc_name ?? '-')) ?>
+ = esc((string) ($row->mphone1 ?? '-')) ?>
+ = esc($invType) ?>
+
+ Open
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/Setting/Bed/bed_list.php b/app/Views/Setting/Bed/bed_list.php
index 4f7ab56..d50192b 100644
--- a/app/Views/Setting/Bed/bed_list.php
+++ b/app/Views/Setting/Bed/bed_list.php
@@ -1,10 +1,16 @@
@@ -28,6 +34,9 @@
= esc($ward->ward_name ?? '') ?>
+
+ Manage Wards
+
Category
diff --git a/app/Views/Setting/Bed/bed_status_list.php b/app/Views/Setting/Bed/bed_status_list.php
new file mode 100644
index 0000000..3256438
--- /dev/null
+++ b/app/Views/Setting/Bed/bed_status_list.php
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+ All Department
+
+ vName ?? '')); ?>
+
+ = esc($label) ?>
+
+
+
+
+
+ All Wards
+
+ = esc((string) ($ward->ward_name ?? '')) ?>
+
+
+
+
+
+
+
+
+
+ IPD Code
+ Patient Code
+ Patient Name
+ Mobile
+ Department
+ Ward
+ Bed No
+ Admit Date
+
+
+
+
+ p_fname ?? '') . ' ' . ($row->p_lname ?? '')));
+ if ($fullName === '') {
+ $fullName = '-';
+ }
+ $mobile = trim((string) ($row->mphone1 ?? ''));
+ if ($mobile === '' || $mobile === '0') {
+ $mobile = trim((string) ($row->mphone2 ?? ''));
+ }
+ if ($mobile === '' || $mobile === '0') {
+ $mobile = '-';
+ }
+ $bedNo = trim((string) ($row->bed_number ?? ''));
+ if ($bedNo === '' || $bedNo === '0') {
+ $bedNo = trim((string) ($row->bed_code ?? ''));
+ }
+ if ($bedNo === '') {
+ $bedNo = '-';
+ }
+ $departmentName = trim((string) ($row->department_name ?? ''));
+ if ($departmentName === '') {
+ $departmentName = 'All Department';
+ }
+ $wardName = trim((string) ($row->ward_name ?? ''));
+ if ($wardName === '') {
+ $wardName = '-';
+ }
+ $admitDate = trim((string) ($row->register_date ?? ''));
+ if ($admitDate === '') {
+ $admitDate = '-';
+ }
+ ?>
+
+ = esc((string) ($row->ipd_code ?? '-')) ?>
+ = esc((string) ($row->p_code ?? '-')) ?>
+ = esc($fullName) ?>
+ = esc($mobile) ?>
+ = esc($departmentName) ?>
+ = esc($wardName) ?>
+ = esc($bedNo) ?>
+ = esc($admitDate) ?>
+
+
+
+
+
+
+
+
diff --git a/app/Views/Setting/Bed/department_list.php b/app/Views/Setting/Bed/department_list.php
new file mode 100644
index 0000000..e14aedb
--- /dev/null
+++ b/app/Views/Setting/Bed/department_list.php
@@ -0,0 +1,143 @@
+
+
+
+
+
Department table (hc_department) is not available in this database.
+
+
+
+
+
+
+
+
+
+
+ ID
+ Name
+ Type ID
+ Action
+
+
+
+
+
+ = esc($row->iId ?? 0) ?>
+ = esc($row->vName ?? '') ?>
+ = esc($row->hc_type_id ?? '') ?>
+
+ Edit
+ Delete
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/Setting/Bed/index.php b/app/Views/Setting/Bed/index.php
index 807e943..deb2bdb 100644
--- a/app/Views/Setting/Bed/index.php
+++ b/app/Views/Setting/Bed/index.php
@@ -10,6 +10,24 @@
+
+
+
diff --git a/app/Views/Setting/Bed/ward_list.php b/app/Views/Setting/Bed/ward_list.php
new file mode 100644
index 0000000..7a5104d
--- /dev/null
+++ b/app/Views/Setting/Bed/ward_list.php
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+
+
+ All Types
+
+
+
+
+ All Status
+
+
+
+
+
+
+
+
+ Code
+ Name
+ Department
+ Type
+ Capacity
+ Status
+ Action
+
+
+
+
+
+ = esc($row->ward_code ?? '') ?>
+ = esc($row->ward_name ?? '') ?>
+ = esc($row->department_name ?? 'All Department') ?>
+ = esc($row->ward_type ?? '') ?>
+ = esc($row->total_capacity ?? 0) ?>
+ = esc($row->status ?? '') ?>
+
+ Edit
+ Delete
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/Setting/Doctor/Doctor_V.php b/app/Views/Setting/Doctor/Doctor_V.php
index 780f325..f311024 100644
--- a/app/Views/Setting/Doctor/Doctor_V.php
+++ b/app/Views/Setting/Doctor/Doctor_V.php
@@ -11,6 +11,13 @@
+dob)) {
+ $doctorDobValue = trim((string) $data[0]->dob);
+}
+?>
diff --git a/app/Views/Setting/Template/index.php b/app/Views/Setting/Template/index.php
index fc01c59..af1c831 100644
--- a/app/Views/Setting/Template/index.php
+++ b/app/Views/Setting/Template/index.php
@@ -206,6 +206,12 @@ $hasTemplateAccess = $canPathology || $canUltrasound || $canXray || $canCt || $c
IPD Discharge Template
+
diff --git a/app/Views/Setting/Template/ipd_document_templates.php b/app/Views/Setting/Template/ipd_document_templates.php
new file mode 100644
index 0000000..fa07f61
--- /dev/null
+++ b/app/Views/Setting/Template/ipd_document_templates.php
@@ -0,0 +1,173 @@
+{{FORM_TITLE}}{{PATIENT_NAME}}
');
+$status = (int) ($edit['status'] ?? 1);
+
+$formMap = [
+ 1 => 'Print Face Form',
+ 3 => 'Self Declaration Form',
+ 5 => 'Admission Form',
+ 8 => 'Progress Notes',
+ 9 => 'Fluid In / Out',
+ 10 => 'Sticker [2 x 6]',
+ 11 => 'Sticker [2 x 8]',
+];
+?>
+
+
+
+
+
+
+
= esc($notice) ?>
+
+
+
+ Placeholders: {{FORM_TITLE}}, {{HOSPITAL_NAME}}, {{HOSPITAL_ADDRESS}},
+ {{PATIENT_NAME}}, {{AGE}}, {{GENDER}}, {{AGE_GENDER}}, {{UHID}},
+ {{IPD_CODE}}, {{ADMIT_DATE}}, {{DOCTORS}}, {{INSURANCE_NAME}},
+ {{CURRENT_DATE}}, {{CURRENT_DATETIME}}.
+
+
+
+ Local-language design supported. You can copy HTML blocks from old HMS files under old_code_ci3/views/IPD_Format and adapt them here.
+
+
+
+
+
+
+
+
+ ID
+ Form
+ Template Name
+ Status
+ Action
+
+
+
+
+ No templates found.
+
+
+
+
+ = (int) ($row['id'] ?? 0) ?>
+ = $fNo ?> - = esc($formMap[$fNo] ?? 'Unknown') ?>
+ = esc((string) ($row['template_name'] ?? '')) ?>
+ = (int) ($row['status'] ?? 0) === 1 ? 'Active' : 'Inactive' ?>
+
+ Edit
+ Delete
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/billing/ipd/ipd_form_print.php b/app/Views/billing/ipd/ipd_form_print.php
new file mode 100644
index 0000000..a1ca00e
--- /dev/null
+++ b/app/Views/billing/ipd/ipd_form_print.php
@@ -0,0 +1,264 @@
+ 'IPD Form'];
+$ipd = $ipd_info ?? null;
+$person = $person_info ?? null;
+$doctorList = is_array($doctor_names ?? null) ? $doctor_names : [];
+$doctorText = ! empty($doctorList) ? implode(', ', $doctorList) : '-';
+$insuranceText = trim((string) ($insurance_name ?? ''));
+$hospitalName = trim((string) ($hospital_name ?? 'Hospital'));
+$hospitalAddress = trim((string) ($hospital_address ?? ''));
+$generatedAt = (string) ($generated_at ?? date('d-m-Y h:i A'));
+
+$patientName = trim((string) (($person->title ?? '') . ' ' . ($person->p_fname ?? '')));
+if ($patientName === '') {
+ $patientName = '-';
+}
+$patientAge = (string) ($person->age ?? '-');
+$patientGender = (string) ($person->xgender ?? '-');
+$patientCode = (string) ($person->p_code ?? '-');
+$ipdCode = (string) ($ipd->ipd_code ?? '-');
+$admitDate = (string) ($ipd->str_register_date ?? '');
+if ($admitDate === '') {
+ $admitDate = (string) ($ipd->register_date ?? '-');
+}
+?>
+
+
+
+
+
+
+
+
+
+
= esc($hospitalName) ?>
+
+
+
= esc($hospitalAddress) ?>
+
+
Patient: = esc($patientName) ?>
+
Age/Gender: = esc($patientAge) ?> / = esc($patientGender) ?>
+
UHID: = esc($patientCode) ?>
+
IPD: = esc($ipdCode) ?>
+
Doctor: = esc($doctorText) ?>
+
Admit: = esc($admitDate) ?>
+
+
Insurance: = esc($insuranceText) ?>
+
+
+
+
+
+
+
+
+
+
Patient Consent
+
+ I willingly agree for treatment, examination, consultation, investigations, medication, and medically indicated procedures during this IPD admission.
+ I confirm that the information shared with the treating team is true and complete to the best of my knowledge.
+
+
+ I understand that the hospital may take emergency decisions in the patient's best interest when immediate care is required.
+ I also agree to follow hospital rules regarding safety, infection control, and billing process.
+
+
+
+ Patient / Attendant Signature: ____________________
+ Hospital Representative: ____________________
+
+
+
+
Self Declaration
+
+ I, ____________________, declare that patient = esc($patientName) ?> is admitted under IPD code = esc($ipdCode) ?>
+ on date = esc($admitDate) ?>.
+
+ The patient is covered under insurance provider = esc($insuranceText) ?>.
+
+ This admission is under self / direct payment category.
+
+
+
+ I confirm that all submitted details and documents are genuine and I will remain responsible for any differences in authorization, exclusions, or final bill settlement.
+
+
+
+ Declarant Signature: ____________________
+ Date: ____________________
+
+
+
+
Admission Assessment
+
+ Assessment Item Observation
+ Chief Complaint
+ History of Present Illness
+ Past Medical / Surgical History
+ Allergy History
+ Medication History
+ Physical Examination
+ Provisional Diagnosis
+ Initial Plan
+
+
+
Progress Notes and Doctor Order
+
+
+ Date
+ Time
+ Progress Notes / Orders
+ Doctor Sign
+
+
+
+
+
+
+
+
+
+
+
+
Fluid In / Out
+
+
+ S.No.
+ Date / Time
+ Fluid In (ml)
+ Fluid Out (ml)
+ Remark
+
+
+
+ = $i ?>
+
+
+
+
+
+
+
+ Total
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/billing/ipd/panel.php b/app/Views/billing/ipd/panel.php
index 76df154..b2b1966 100644
--- a/app/Views/billing/ipd/panel.php
+++ b/app/Views/billing/ipd/panel.php
@@ -180,6 +180,9 @@ if ($person) {
Discharge Process
+
+ Documents
+
@@ -209,6 +212,9 @@ if ($person) {
+
diff --git a/app/Views/billing/ipd/panel_documents.php b/app/Views/billing/ipd/panel_documents.php
new file mode 100644
index 0000000..e9ea5ae
--- /dev/null
+++ b/app/Views/billing/ipd/panel_documents.php
@@ -0,0 +1,53 @@
+ipd_code ?? ('IPD-' . $ipdId));
+
+$documents = [
+ ['id' => 1, 'label' => 'Print Face Form'],
+ ['id' => 5, 'label' => 'Admission Form'],
+ ['id' => 10, 'label' => 'Sticker [2 x 6]'],
+ ['id' => 11, 'label' => 'Sticker [2 x 8]'],
+ ['id' => 8, 'label' => 'Progress Notes'],
+ ['id' => 9, 'label' => 'Fluid In / Out'],
+ ['id' => 3, 'label' => 'Self Declaration Form'],
+];
+?>
+
+
+
+
+
Pre-Print Documents
+
+ IPD: = esc($ipdCode) ?>
+
+ Document Master
+
+
+
+
+
+
+
+
+ Form ID
+ Document
+ Action
+
+
+
+
+
+ = (int) $document['id'] ?>
+ = esc($document['label']) ?>
+
+
+ Print
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/billing/opd_invoice_V.php b/app/Views/billing/opd_invoice_V.php
index 8bb1ca6..da32477 100644
--- a/app/Views/billing/opd_invoice_V.php
+++ b/app/Views/billing/opd_invoice_V.php
@@ -1,9 +1,16 @@
user();
-if ($user && method_exists($user, 'inGroup')) {
- $canEdit = $user->inGroup('OPDEdit');
+if ($user) {
+ if (method_exists($user, 'can') && $user->can('billing.opd.edit')) {
+ $canEdit = true;
+ }
+
+ if (! $canEdit && method_exists($user, 'inGroup')) {
+ $canEdit = $user->inGroup('OPDEdit');
+ }
}
+$paymentHistoryRows = $payment_history_rows ?? [];
?>
+
+
+
+
Payment History
+
+
+
+
+ Date
+ Type
+ Mode
+ Amount
+ Remark
+
+
+
+
+
+ credit_debit ?? 0) === 1;
+ $historyDate = trim((string) ($historyRow->payment_date ?? ''));
+ if ($historyDate === '') {
+ $historyDate = trim((string) ($historyRow->insert_time ?? ''));
+ }
+ ?>
+
+ = esc($historyDate) ?>
+ = $isRefund ? 'Refund ' : 'Received ' ?>
+ = esc($historyRow->payment_mode_str ?? '') ?>
+ = esc(number_format((float) ($historyRow->amount ?? 0), 2, '.', '')) ?>
+ = esc($historyRow->remark ?? '') ?>
+
+
+
+
+ No payment history entries.
+
+
+
+
+
+
+
+
opd_status ?? 0) === 1 || (int) ($opd_master[0]->opd_status ?? 0) === 2)) : ?>
@@ -419,7 +470,8 @@ if ($user && method_exists($user, 'inGroup')) {
"oid": $('#oid').val(),
"input_remark": $('#input_remark').val(),
[csrf.name]: csrf.value
- }, function() {
+ }, function(data) {
+ updateCsrf(data);
load_form('= base_url('Opd/invoice') ?>/' + $('#oid').val());
});
}
diff --git a/app/Views/partials/header.php b/app/Views/partials/header.php
index a091ba8..171b337 100644
--- a/app/Views/partials/header.php
+++ b/app/Views/partials/header.php
@@ -39,8 +39,24 @@
}
}
}
+
+ $serverTimeZoneId = 'Asia/Kolkata';
+ $serverNow = new DateTimeImmutable('now', new DateTimeZone($serverTimeZoneId));
+ $serverTimeZoneLabel = trim((string) $serverNow->format('T'));
+ if ($serverTimeZoneLabel === '' || $serverTimeZoneLabel === 'GMT') {
+ $serverTimeZoneLabel = $serverTimeZoneId;
+ }
+ $serverEpochMs = (int) round(microtime(true) * 1000);
+ $serverDisplayTime = $serverNow->format('d-m-Y h:i A') . ' (' . $serverTimeZoneLabel . ')';
?>
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/app/Views/partials/sidebar.php b/app/Views/partials/sidebar.php
index 0876adf..db1a5b2 100644
--- a/app/Views/partials/sidebar.php
+++ b/app/Views/partials/sidebar.php
@@ -107,6 +107,12 @@ if (! $canDiagnosis && $user && method_exists($user, 'inGroup')) {
Dashboard
+
+
+
+ Bed Status
+
+
Billing
@@ -115,6 +121,18 @@ if (! $canDiagnosis && $user && method_exists($user, 'inGroup')) {
Patient List
+
+
+
+
+ OPD Invoice
+
+
+
+
+
+ Charges Invoice
+