diff --git a/app/Config/Routes.php b/app/Config/Routes.php index a491ba7..763f701 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -289,6 +289,11 @@ service('auth')->routes($routes); // Legacy compatibility: some IPD charge screens still refresh via old IpdNew URL. $routes->get('IpdNew/show_ipd_items/(:num)', 'Billing\\Ipd::panelTab/$1/ipd-charges'); $routes->get('IpdNew/show_ipd_items/(:num)/(:num)', 'Billing\\Ipd::panelTab/$1/ipd-charges'); +// Legacy compatibility: patient profile still calls old new-IPD URL. +$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'); // 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'); @@ -407,6 +412,7 @@ $routes->group('billing', function($routes) { $routes->post('charges/cancel-invoice/(:num)', 'Billing\\Charges::cancel_invoice/$1'); $routes->post('charges/update-correction', 'Billing\\Charges::update_correction_charges'); $routes->get('charges/show/(:num)', 'Billing\\Charges::show/$1'); + $routes->get('charges/print_invoice/(:num)/(:num)', 'Billing\\Charges::print_invoice/$1/$2'); $routes->post('charges/delete', 'Billing\\Charges::delete'); $routes->post('charges/update-discount', 'Billing\\Charges::updateDiscount'); }); diff --git a/app/Controllers/Billing/CaseMaster.php b/app/Controllers/Billing/CaseMaster.php index 272b5ef..31542d8 100644 --- a/app/Controllers/Billing/CaseMaster.php +++ b/app/Controllers/Billing/CaseMaster.php @@ -119,6 +119,7 @@ class CaseMaster extends BaseController 'input_insurance_id' => 'required|min_length[2]|max_length[30]', 'input_card_holder_name' => 'required|min_length[2]|max_length[50]', ]; + $validation = service('validation'); $validation->setRules($rules); if (! $validation->withRequest($this->request)->run()) { $errorText = implode("\n", $validation->getErrors()); diff --git a/app/Controllers/Billing/Charges.php b/app/Controllers/Billing/Charges.php index b77eb3a..9578e66 100644 --- a/app/Controllers/Billing/Charges.php +++ b/app/Controllers/Billing/Charges.php @@ -4,6 +4,7 @@ namespace App\Controllers\Billing; use App\Controllers\BaseController; use App\Models\InvoiceModel; +use Mpdf\Mpdf; class Charges extends BaseController { @@ -1017,4 +1018,116 @@ class Charges extends BaseController return $this->response->setJSON(['update' => 1]); } + + public function print_invoice(int $invoiceId, int $printMode = 0) + { + if ($resp = $this->requirePermission('billing.charges.view')) { + return $resp; + } + + // Retrieve all invoice data (same as show method) + $invoiceModel = new InvoiceModel(); + $invoiceModel->updateInvoiceFinal($invoiceId); + + $sql = "select i.*,t.group_desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id + where i.inv_master_id=" . (int) $invoiceId; + $query = $this->db->query($sql); + $data['invoiceDetails'] = $query->getResult(); + + $sql = "select *, + (case payment_mode when 1 then 'Cash' when 2 then 'Bank Card/Online' when 3 then 'IPD Credit' when 4 then 'Org. Credit' else 'Pending' end) as Payment_type_str + from invoice_master where id=" . (int) $invoiceId; + $query = $this->db->query($sql); + $data['invoice_master'] = $query->getResult(); + + if (empty($data['invoice_master'])) { + return $this->response->setStatusCode(404)->setBody('Invoice not found'); + } + + $insCompId = (int) ($data['invoice_master'][0]->insurance_id ?? 0); + $insId = (int) ($data['invoice_master'][0]->insurance_card_id ?? 0); + + $sql = "select * from hc_insurance_card where id=" . $insId; + $query = $this->db->query($sql); + $data['hc_insurance_card'] = $query->getResult(); + + $sql = "select * from hc_insurance where id=" . $insCompId; + $query = $this->db->query($sql); + $data['insurance'] = $query->getResult(); + + $sql = "select p.*,f.full_path as profile_picture + from patient_master p + left join file_upload_data f on p.profile_file_id=f.id + where p.id=" . (int) ($data['invoice_master'][0]->attach_id ?? 0); + $query = $this->db->query($sql); + $data['patient_master'] = $query->getResult(); + if (!empty($data['patient_master'])) { + $row = $data['patient_master'][0]; + $row->age = get_age_1($row->dob ?? null, $row->age ?? '', $row->age_in_month ?? '', $row->estimate_dob ?? ''); + $row->xgender = ($row->gender ?? 0) == 1 ? 'Male' : 'Female'; + } + + $sql = "select * from ipd_master where ipd_status=0 and p_id=" . (int) ($data['invoice_master'][0]->attach_id ?? 0); + if (($data['invoice_master'][0]->ipd_id ?? 0) > 0) { + $sql = "select * from ipd_master where id=" . (int) $data['invoice_master'][0]->ipd_id; + } + $query = $this->db->query($sql); + $data['ipd_master'] = $query->getResult(); + + $sql = "select * from organization_case_master where case_type=0 and status=0 and p_id=" . (int) ($data['invoice_master'][0]->attach_id ?? 0); + if (($data['invoice_master'][0]->insurance_case_id ?? 0) > 0) { + $sql = "select * from organization_case_master where case_type=0 and id=" . (int) $data['invoice_master'][0]->insurance_case_id; + } elseif (count($data['ipd_master'] ?? []) > 0) { + if (($data['ipd_master'][0]->case_id ?? 0) > 0) { + $sql = "select * from organization_case_master where case_type=0 and id=" . (int) $data['ipd_master'][0]->case_id; + } + } + $query = $this->db->query($sql); + $data['case_master'] = $query->getResult(); + + $sql = "select *, + (case payment_mode when 1 then 'Cash' when 2 then 'Bank Card' when 3 then 'Org Credit' when 4 then 'Adjustment' else 'Pending' end) as Payment_type_str + from payment_history where payof_type=2 and payof_id=" . (int) $invoiceId; + $query = $this->db->query($sql); + $data['payment_history_details'] = $query->getResult(); + + // Generate PDF using mPDF + $mpdfTempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf'; + if (!is_dir($mpdfTempDir)) { + mkdir($mpdfTempDir, 0755, true); + } + + if ($printMode === 1) { + // Legacy behavior: A4 landscape with two copies side-by-side in one page. + $htmlContent = view('billing/charges/invoice_pdf_double', $data); + $mpdf = new Mpdf([ + 'tempDir' => $mpdfTempDir, + 'format' => 'A4-L', + 'margin_top' => 12, + 'margin_bottom' => 10, + 'margin_left' => 5, + 'margin_right' => 5, + ]); + $mpdf->WriteHTML($htmlContent); + } else { + $htmlContent = view('billing/charges/invoice_pdf_template', $data); + $mpdf = new Mpdf([ + 'tempDir' => $mpdfTempDir, + 'format' => 'A4', + 'margin_top' => 10, + 'margin_bottom' => 10, + 'margin_left' => 10, + 'margin_right' => 10, + ]); + $mpdf->WriteHTML($htmlContent); + } + + $invoiceCode = (string) ($data['invoice_master'][0]->invoice_code ?? 'Invoice'); + $fileName = $invoiceCode . '.pdf'; + + return $this->response + ->setHeader('Content-Type', 'application/pdf') + ->setHeader('Content-Disposition', 'inline; filename="' . $fileName . '"') + ->setBody($mpdf->Output($fileName, 'S')); + } } diff --git a/app/Controllers/Billing/Ipd.php b/app/Controllers/Billing/Ipd.php index 79d5267..4d5c239 100644 --- a/app/Controllers/Billing/Ipd.php +++ b/app/Controllers/Billing/Ipd.php @@ -170,6 +170,205 @@ class Ipd extends BaseController return view('billing/ipd/panel', $panelData); } + public function legacyAddIpd(int $patientId) + { + $permission = $this->requireAnyPermission([ + 'billing.access', + 'billing.ipd.current-admission', + 'billing.ipd.invoice', + ]); + if ($permission) { + return $permission; + } + + $patientId = (int) $patientId; + if ($patientId <= 0) { + return redirect()->to(base_url('billing/ipd/current-admission')); + } + + $activeIpd = $this->db->table('ipd_master') + ->select('id') + ->where('p_id', $patientId) + ->where('ipd_status', 0) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + + if (! empty($activeIpd['id'])) { + return redirect()->to(base_url('billing/ipd/panel/' . (int) $activeIpd['id'])); + } + + $data = $this->buildLegacyIpdRegistrationData($patientId); + if (empty($data['person_info'])) { + return $this->response->setStatusCode(404)->setBody('Patient not found'); + } + + return view('billing/ipd/legacy_registration', $data); + } + + public function legacyAddNew() + { + $permission = $this->requireAnyPermission([ + 'billing.access', + 'billing.ipd.current-admission', + 'billing.ipd.invoice', + ]); + if ($permission) { + return $permission; + } + + if (! $this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON([ + 'insertid' => 0, + 'error_text' => 'Invalid request', + ]); + } + + $patientId = (int) ($this->request->getPost('pid') ?? 0); + $docList = $this->request->getPost('doc_id'); + $docList = is_array($docList) ? array_values(array_filter(array_map('intval', $docList), static fn ($id) => $id > 0)) : []; + + if ($patientId <= 0 || empty($docList)) { + return $this->response->setJSON([ + 'insertid' => 0, + 'error_text' => 'Please select at least one doctor.', + ]); + } + + $registerDateInput = (string) ($this->request->getPost('res_date') ?? ''); + $registerDate = $registerDateInput !== '' ? str_to_MysqlDate($registerDateInput) : date('Y-m-d'); + + $master = [ + 'p_id' => $patientId, + 'P_name' => (string) ($this->request->getPost('pname') ?? ''), + 'relation' => (string) ($this->request->getPost('r_relation') ?? ''), + 'contact_person_Name' => (string) ($this->request->getPost('rp_name') ?? ''), + 'insurance_id' => (int) ($this->request->getPost('insur_list') ?? 0), + 'policy_no' => (string) ($this->request->getPost('insur_no') ?? ''), + 'register_date' => $registerDate, + 'problem' => (string) ($this->request->getPost('problem') ?? ''), + 'remark' => (string) ($this->request->getPost('remark') ?? ''), + 'P_mobile1' => (string) ($this->request->getPost('phone1') ?? ''), + 'P_mobile2' => (string) ($this->request->getPost('phone2') ?? ''), + 'case_type' => (int) ($this->request->getPost('optionsRadios_mlc') ?? 0), + 'case_id' => (int) ($this->request->getPost('optionsRadios_org') ?? 0), + 'reg_time' => (string) ($this->request->getPost('res_time') ?? date('H:i')), + 'refer_by' => (int) ($this->request->getPost('refer_by_list') ?? 0), + 'dept_id' => (int) ($this->request->getPost('dept_id') ?? 0), + ]; + + $insertId = $this->ipdEditModel->insertIpd([ + 'master' => $master, + 'doc_list' => $docList, + ]); + + if ($insertId > 0) { + $roomId = (int) ($this->request->getPost('room_list') ?? 0); + if ($roomId > 0) { + $this->ipdEditModel->bedAssign([ + 'ipd_id' => $insertId, + 'Fdate' => date('Y-m-d H:i:s'), + 'TDate' => date('Y-m-d H:i:s'), + 'bed_id' => $roomId, + ]); + } + + $caseId = (int) ($master['case_id'] ?? 0); + if ($caseId > 0 && $this->db->tableExists('organization_case_master')) { + $this->db->table('organization_case_master') + ->where('id', $caseId) + ->update(['ipd_id' => $insertId]); + } + } + + return $this->response->setJSON([ + 'insertid' => (int) $insertId, + ]); + } + + private function buildLegacyIpdRegistrationData(int $patientId): array + { + $person = $this->db->table('patient_master') + ->select("*, if(gender=1,'Male','FeMale') as xgender", false) + ->where('id', $patientId) + ->get() + ->getRow(); + + if ($person) { + $person->age = get_age_1( + $person->dob ?? null, + $person->age ?? '', + $person->age_in_month ?? '', + $person->estimate_dob ?? '' + ); + } + + $docSpecList = $this->db->query( + "select d.id, d.p_fname, group_concat(m.SpecName) as SpecName + from doctor_master d + join doc_spec s on d.id = s.doc_id + join med_spec m on s.med_spec_id = m.id + where d.active = 1 + group by d.id + order by d.p_fname" + )->getResult(); + + $ipdBedList = []; + if ($this->db->tableExists('bed_master')) { + $ipdBedList = $this->db->query( + "select b.id, + concat('Bed No:', coalesce(b.bed_number, b.bed_code), '/', '[', coalesce(w.ward_name, ''), ']') as Bed_Desc + from bed_master b + left join ward_master w on w.id = b.ward_id + where b.bed_status = 'available' + order by b.bed_number, b.id" + )->getResult(); + } elseif ($this->db->tableExists('hc_bed_master')) { + $ipdBedList = $this->db->query( + "select id, concat('Bed No:', coalesce(bed_no, bed_number), '/', '[', coalesce(room_name, ward_name), ']') as Bed_Desc + from hc_bed_master + where ifnull(bed_used_p_id,0)=0" + )->getResult(); + } + + $caseMaster = []; + if ($this->db->tableExists('organization_case_master')) { + $caseMaster = $this->db->table('organization_case_master') + ->where('status', 0) + ->where('case_type', 1) + ->where('ipd_id', 0) + ->where('p_id', $patientId) + ->get() + ->getResult(); + } + + $referMaster = []; + if ($this->db->tableExists('refer_master')) { + $referMaster = $this->db->table('refer_master') + ->where('active', 1) + ->orderBy('f_name', 'ASC') + ->get() + ->getResult(); + } + + $hcDepartment = []; + if ($this->db->tableExists('hc_department')) { + $hcDepartment = $this->db->table('hc_department') + ->orderBy('vName', 'ASC') + ->get() + ->getResult(); + } + + return [ + 'person_info' => $person, + 'doc_spec_l' => $docSpecList, + 'ipd_bed_list' => $ipdBedList, + 'case_master' => $caseMaster, + 'refer_master' => $referMaster, + 'hc_department' => $hcDepartment, + ]; + } + public function panelTab(int $ipdId, string $tab) { $permission = $this->requireAnyPermission([ diff --git a/app/Controllers/Diagnosis.php b/app/Controllers/Diagnosis.php index 3b8eed5..fed2247 100644 --- a/app/Controllers/Diagnosis.php +++ b/app/Controllers/Diagnosis.php @@ -860,7 +860,7 @@ class Diagnosis extends BaseController $dataLabTestList = $this->db->query($itemSql, [$labReqId])->getResult(); $repoFormat = $this->db->table('lab_repo') - ->select('mstRepoKey, Title, HTMLData') + ->select('mstRepoKey, Title, HTMLData, RTFData') ->where('mstRepoKey', (int) $labRequest->lab_repo_id) ->get() ->getRow(); @@ -869,7 +869,10 @@ class Diagnosis extends BaseController ? $repoFormat->Title : ($labRequest->report_name ?? 'Lab Report'); - $reportString = $repoFormat->HTMLData ?? ''; + $reportString = (string) ($repoFormat->HTMLData ?? ''); + if (trim($reportString) === '') { + $reportString = (string) ($repoFormat->RTFData ?? ''); + } $reportHeader = '

' . htmlspecialchars((string) $reportTitle, ENT_QUOTES, 'UTF-8') . '

'; @@ -971,7 +974,7 @@ class Diagnosis extends BaseController } $repoFormat = $this->db->table('lab_repo') - ->select('Title, HTMLData') + ->select('Title, HTMLData, RTFData') ->where('mstRepoKey', (int) ($labRequest->lab_repo_id ?? 0)) ->get() ->getRow(); @@ -981,6 +984,9 @@ class Diagnosis extends BaseController : (string) ($labRequest->report_name ?? 'Radiology Report'); $reportString = (string) ($repoFormat->HTMLData ?? ''); + if (trim($reportString) === '') { + $reportString = (string) ($repoFormat->RTFData ?? ''); + } $reportHeader = '

' . htmlspecialchars($reportTitle, ENT_QUOTES, 'UTF-8') . '

'; diff --git a/app/Controllers/Setting/Template.php b/app/Controllers/Setting/Template.php index 639415a..248cdb9 100644 --- a/app/Controllers/Setting/Template.php +++ b/app/Controllers/Setting/Template.php @@ -81,6 +81,47 @@ class Template extends BaseController return $map[$modality] ?? null; } + private function buildDefaultPathologyTemplate(string $reportName): string + { + $name = strtolower(trim($reportName)); + $isCbc = str_contains($name, 'cbc') || str_contains($name, 'complete blood count') || str_contains($name, 'hemogram'); + + if (! $isCbc) { + return ''; + } + + return <<COMPLETE BLOOD COUNT (CBC)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
InvestigationResultUnitReference Range
Hemoglobin (Hb) g/dL12.0 - 16.0
Total WBC Count (TLC) /cumm4,000 - 11,000
Neutrophils %40 - 75
Lymphocytes %20 - 40
Eosinophils %1 - 6
Monocytes %2 - 10
Basophils %0 - 2
RBC Count million/cumm4.0 - 5.5
PCV (HCT) %36 - 46
MCV fL80 - 100
MCH pg27 - 32
MCHC g/dL31 - 36
Platelet Count lakh/cumm1.5 - 4.5
ESR mm/hr0 - 20
+

Peripheral Smear: Normocytic normochromic RBCs. No hemoparasite seen.

+HTML; + } + private function requireModalityPermission(int $modality) { $permission = $this->permissionForModality($modality); @@ -194,6 +235,24 @@ class Template extends BaseController $query = $this->db->query($sql); $data['labReport_master'] = $query->getResult(); + if (! empty($data['labReport_master'])) { + $existingHtml = trim((string) ($data['labReport_master'][0]->HTMLData ?? '')); + if ($existingHtml === '') { + $legacyHtml = trim((string) ($data['labReport_master'][0]->RTFData ?? '')); + if ($legacyHtml !== '') { + $data['labReport_master'][0]->HTMLData = $legacyHtml; + $existingHtml = $legacyHtml; + } + } + + if ($existingHtml === '') { + $defaultHtml = $this->buildDefaultPathologyTemplate((string) ($data['labReport_master'][0]->Title ?? '')); + if ($defaultHtml !== '') { + $data['labReport_master'][0]->HTMLData = $defaultHtml; + } + } + } + $itemId = 0; if (! empty($data['labReport_master'])) { $itemId = (int) ($data['labReport_master'][0]->charge_id ?? 0); @@ -264,6 +323,13 @@ class Template extends BaseController $groupId = (int) $this->request->getPost('group_id'); $htmlData = (string) $this->request->getPost('HTMLData'); + if (trim($htmlData) === '') { + $defaultHtml = $this->buildDefaultPathologyTemplate($inputReportName); + if ($defaultHtml !== '') { + $htmlData = $defaultHtml; + } + } + if ($repoId <= 0 || $inputReportName === '') { return $this->response->setJSON([ 'update_record' => 0, @@ -277,6 +343,7 @@ class Template extends BaseController 'GrpKey' => $groupId, 'charge_id' => $chargeId, 'HTMLData' => $htmlData, + 'RTFData' => $htmlData, ], $repoId); return $this->response->setJSON([ @@ -303,6 +370,13 @@ class Template extends BaseController $groupId = (int) $this->request->getPost('group_id'); $htmlData = (string) $this->request->getPost('HTMLData'); + if (trim($htmlData) === '') { + $defaultHtml = $this->buildDefaultPathologyTemplate($inputReportName); + if ($defaultHtml !== '') { + $htmlData = $defaultHtml; + } + } + if ($inputReportName === '') { return $this->response->setJSON([ 'insertid' => 0, @@ -316,6 +390,7 @@ class Template extends BaseController 'GrpKey' => $groupId, 'charge_id' => $chargeId, 'HTMLData' => $htmlData, + 'RTFData' => $htmlData, ]); return $this->response->setJSON([ diff --git a/app/Models/IpdModel.php b/app/Models/IpdModel.php index fb70753..d7ae749 100644 --- a/app/Models/IpdModel.php +++ b/app/Models/IpdModel.php @@ -56,11 +56,15 @@ class IpdModel extends Model $docList = $data['doc_list'] ?? []; if (! empty($docList)) { foreach ($docList as $docId) { - $this->db->table('ipd_master_doc_list')->insert([ + $docPayload = $this->filterTableDataByExistingColumns('ipd_master_doc_list', [ 'doc_id' => $docId, 'ipd_id' => $insertId, 'log' => 'Insert By :' . $userSignature, ]); + + if (! empty($docPayload)) { + $this->db->table('ipd_master_doc_list')->insert($docPayload); + } } } @@ -69,6 +73,11 @@ class IpdModel extends Model public function addIpdDoc(array $docData): int { + $docData = $this->filterTableDataByExistingColumns('ipd_master_doc_list', $docData); + if (empty($docData)) { + return 0; + } + $inserted = $this->db->table('ipd_master_doc_list')->insert($docData); return $inserted ? (int) $this->db->insertID() : 0; @@ -101,22 +110,93 @@ class IpdModel extends Model return 1; } + private function filterTableDataByExistingColumns(string $table, array $data): array + { + if (! $this->db->tableExists($table)) { + return []; + } + + $fields = $this->db->getFieldNames($table) ?? []; + if (empty($fields)) { + return $data; + } + + return array_intersect_key($data, array_flip($fields)); + } + public function bedAssign(array $data): int { - $inserted = $this->db->table('ipd_bed_assign')->insert($data); - if (! $inserted) { + $ipdId = (int) ($data['ipd_id'] ?? 0); + $bedId = (int) ($data['bed_id'] ?? 0); + $fromDate = (string) ($data['Fdate'] ?? date('Y-m-d H:i:s')); + $toDate = (string) ($data['TDate'] ?? $fromDate); + + if ($ipdId <= 0 || $bedId <= 0) { return 0; } - $insertId = (int) $this->db->insertID(); + $insertId = 0; - $this->db->table('hc_bed_master') - ->where('bed_used_p_id', $data['ipd_id']) - ->update(['bed_used_p_id' => 0]); + if ($this->db->tableExists('bed_assignment_history')) { + $wardId = null; + if ($this->db->tableExists('bed_master') && in_array('ward_id', $this->db->getFieldNames('bed_master') ?? [], true)) { + $bedRow = $this->db->table('bed_master') + ->select('ward_id') + ->where('id', $bedId) + ->get() + ->getRowArray(); + $wardId = isset($bedRow['ward_id']) ? (int) $bedRow['ward_id'] : null; + } - $this->db->table('hc_bed_master') - ->where('id', $data['bed_id']) - ->update(['bed_used_p_id' => $data['ipd_id']]); + $assignedBy = (int) ($this->getUserIdentity()['id'] ?? 0); + + $inserted = $this->db->table('bed_assignment_history')->insert([ + 'ipd_id' => $ipdId, + 'bed_id' => $bedId, + 'assignment_type' => 'admission', + 'assigned_date' => $fromDate, + 'discharged_date' => $toDate, + 'assigned_by' => $assignedBy > 0 ? $assignedBy : null, + 'ward_id' => $wardId, + ]); + + if (! $inserted) { + return 0; + } + + $insertId = (int) $this->db->insertID(); + } elseif ($this->db->tableExists('ipd_bed_assign')) { + $inserted = $this->db->table('ipd_bed_assign')->insert([ + 'ipd_id' => $ipdId, + 'Fdate' => $fromDate, + 'TDate' => $toDate, + 'bed_id' => $bedId, + ]); + + if (! $inserted) { + return 0; + } + + $insertId = (int) $this->db->insertID(); + } else { + return 0; + } + + if ($this->db->tableExists('hc_bed_master') && in_array('bed_used_p_id', $this->db->getFieldNames('hc_bed_master') ?? [], true)) { + $this->db->table('hc_bed_master') + ->where('bed_used_p_id', $ipdId) + ->update(['bed_used_p_id' => 0]); + + $this->db->table('hc_bed_master') + ->where('id', $bedId) + ->update(['bed_used_p_id' => $ipdId]); + } + + if ($this->db->tableExists('bed_master') && in_array('bed_status', $this->db->getFieldNames('bed_master') ?? [], true)) { + $this->db->table('bed_master') + ->where('id', $bedId) + ->update(['bed_status' => 'occupied']); + } return $insertId; } diff --git a/app/Views/Setting/Insurance/insurance_create_V.php b/app/Views/Setting/Insurance/insurance_create_V.php index 3917376..543b78d 100644 --- a/app/Views/Setting/Insurance/insurance_create_V.php +++ b/app/Views/Setting/Insurance/insurance_create_V.php @@ -1,4 +1,53 @@ -
+ + +

Insurance Company - Add New

diff --git a/app/Views/Setting/Insurance/insurance_profile_V.php b/app/Views/Setting/Insurance/insurance_profile_V.php index 36d6c7e..cdcddc2 100644 --- a/app/Views/Setting/Insurance/insurance_profile_V.php +++ b/app/Views/Setting/Insurance/insurance_profile_V.php @@ -1,5 +1,62 @@ + + -
+

Insurance Company - ins_company_name ?? '') ?>

diff --git a/app/Views/billing/charges/charges_invoice_show.php b/app/Views/billing/charges/charges_invoice_show.php index 2883839..5ab2b04 100644 --- a/app/Views/billing/charges/charges_invoice_show.php +++ b/app/Views/billing/charges/charges_invoice_show.php @@ -123,6 +123,22 @@ + + + payment_status ?? 0) == 0 && $canChargePay) : ?>
diff --git a/app/Views/billing/charges/invoice_pdf_double.php b/app/Views/billing/charges/invoice_pdf_double.php new file mode 100644 index 0000000..d0f428d --- /dev/null +++ b/app/Views/billing/charges/invoice_pdf_double.php @@ -0,0 +1,216 @@ +invoice_code ?? ''); +$invoiceDate = (string) ($invoice->inv_date ?? ''); +$grossAmount = (float) ($invoice->total_amount ?? 0); +$discount = (float) ($invoice->discount_amount ?? 0); +$netAmount = (float) ($invoice->net_amount ?? 0); + +$amountReceived = (float) ($invoice->payment_part_received ?? 0); +$balanceAmount = (float) ($invoice->payment_part_balance ?? $netAmount); + +$orgCaseInfo = ''; +if (!empty($caseRow)) { + $shortName = (string) ($caseRow->short_name ?? ''); + $caseCode = (string) ($caseRow->case_id_code ?? ''); + if ($shortName !== '') { + $orgCaseInfo .= 'Org. Name : ' . $shortName . '
'; + } + if ($caseCode !== '') { + $orgCaseInfo .= 'Org. ID : ' . $caseCode; + } +} + +$qrParts = [ + (string) ($patient->p_code ?? ''), + $invoiceCode, + 'TAmt-' . number_format($netAmount, 2, '.', ''), + 'P-' . date('Y-m-d H:i:s'), +]; +$qrContent = implode(':', array_filter($qrParts, static fn ($v) => trim((string) $v) !== '')); +$paymentHistory = $payment_history_details ?? []; + +if (!function_exists('convertNumberToWords')) { + function convertNumberToWords($num) + { + $num = (int) round((float) $num); + $ones = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine']; + $teens = ['Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen']; + $tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety']; + + if ($num === 0) return 'Zero'; + if ($num < 0) return 'Negative ' . convertNumberToWords(-$num); + + if ($num < 10) return $ones[$num]; + if ($num < 20) return $teens[$num - 10]; + if ($num < 100) return $tens[(int) ($num / 10)] . ($num % 10 ? ' ' . $ones[$num % 10] : ''); + if ($num < 1000) return $ones[(int) ($num / 100)] . ' Hundred' . ($num % 100 ? ' ' . convertNumberToWords($num % 100) : ''); + if ($num < 100000) return convertNumberToWords((int) ($num / 1000)) . ' Thousand' . ($num % 1000 ? ' ' . convertNumberToWords($num % 1000) : ''); + if ($num < 10000000) return convertNumberToWords((int) ($num / 100000)) . ' Lakh' . ($num % 100000 ? ' ' . convertNumberToWords($num % 100000) : ''); + + return convertNumberToWords((int) ($num / 10000000)) . ' Crore' . ($num % 10000000 ? ' ' . convertNumberToWords($num % 10000000) : ''); + } +} +?> + + + + + + + + +
+ + + + + + +
+ + logo + + +
+
+ +
Phone:
+ +
+
INVOICE
+
+ + + +
+ + + + + + +
+ Bill To
+ UHID : p_code ?? '')) ?>
+ Name : p_fname ?? ''))) ?>
+ p_relative ?? '')) ?> p_rname ?? ''))) ?>
+ Sex : xgender ?? '')) ?> age ?? '')) ?> + P.No. : mphone1 ?? '')) ?> +
+ +
+ Address : add1 ?? '') . ',' . ($patient->city ?? ''))) ?>
+ Date :
+ Refer By : Dr.refer_by_other ?? '')) ?> +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + 0) : ?> + + + + + + + + + + +
#Charges GroupCharge NameRateQtyAmt.
group_desc ?? '')) ?>item_name ?? '')) ?>item_rate ?? '')) ?>item_qty ?? '')) ?>item_amount ?? 0), 2, '.', '')) ?>
#Gross Total
#Deductiondiscount_desc ?? '')) ?>-
#Net Amount
+
+ +
+ Amount received : + / Balance Amount : + / Net Amount : +
+
+ Amount in Words : Rs. Only
+ Prepared By : prepared_by ?? '')) ?> +
+
+ payment_mode ?? 0) > 2) : ?> + Payment Details [Payment_type_str ?? '')) ?>] + + Payment Details [Payment No.:Mode of Payment:Amount]: + + [id ?? '')) ?>:Payment_type_str ?? '')) ?>:amount ?? 0), 2, '.', '')) ?>]/ + + +
+
+ Signature
+ Date : confirm_invoice_datetime ?? date('Y-m-d H:i:s'))) ?> +
+
diff --git a/app/Views/billing/charges/invoice_pdf_template.php b/app/Views/billing/charges/invoice_pdf_template.php new file mode 100644 index 0000000..7da7c6b --- /dev/null +++ b/app/Views/billing/charges/invoice_pdf_template.php @@ -0,0 +1,293 @@ + 42) { + $hospitalNameFontSize = 14; +} elseif ($hospitalNameLen > 36) { + $hospitalNameFontSize = 16; +} elseif ($hospitalNameLen > 30) { + $hospitalNameFontSize = 18; +} + +$invoiceCode = (string) ($invoice->invoice_code ?? ''); +$invoiceDate = (string) ($invoice->inv_date ?? ''); +$printedOn = date('d-m-Y h:i:s A'); +$invoiceStatus = ((int) ($invoice->invoice_status ?? 0) === 1) ? 'Paid' : (((int) ($invoice->invoice_status ?? 0) === 2) ? 'Cancelled' : 'Pending'); +$currencyPrefix = 'Rs.'; +$grossAmount = (float) ($invoice->total_amount ?? 0); +$discount = (float) ($invoice->discount_amount ?? 0); +$netAmount = (float) ($invoice->net_amount ?? 0); + +$logoPathCandidates = []; +if ($hospitalLogoName !== '') { + $logoPathCandidates[] = FCPATH . 'assets/images/' . $hospitalLogoName; + $logoPathCandidates[] = FCPATH . 'assets/img/' . $hospitalLogoName; +} +$logoPathCandidates[] = FCPATH . 'assets/img/logo.png'; + +$logoSrc = ''; +foreach ($logoPathCandidates as $candidate) { + if (is_file($candidate)) { + $logoSrc = str_replace('\\', '/', $candidate); + break; + } +} + +$qrParts = [ + 'Hospital:' . $hospitalName, + 'HospitalPhone:' . $hospitalPhone, + 'Invoice:' . $invoiceCode, + 'Patient:' . (string) ($patient->p_code ?? ''), + 'Name:' . trim((string) ($patient->p_fname ?? '')), + 'Date:' . $invoiceDate, + 'Net:' . number_format($netAmount, 2, '.', ''), + 'Status:' . $invoiceStatus, +]; +$qrContent = implode(' | ', array_filter($qrParts, static fn ($v) => trim((string) $v) !== '')); +$qrPackageAvailable = class_exists('\\Mpdf\\QrCode\\QrCode'); + +/** + * Convert numbers to words (basic implementation for Indian system) + * Wrapped with function_exists to prevent redeclaration when rendering multiple times + */ +if (!function_exists('convertNumberToWords')) { + function convertNumberToWords($num) { + $ones = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine']; + $teens = ['Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen']; + $tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety']; + + if ($num == 0) return 'Zero'; + if ($num < 0) return 'Negative ' . convertNumberToWords(-$num); + + if ($num < 10) return $ones[$num]; + if ($num < 20) return $teens[$num - 10]; + if ($num < 100) return $tens[(int)($num / 10)] . ($num % 10 ? ' ' . $ones[$num % 10] : ''); + if ($num < 1000) return $ones[(int)($num / 100)] . ' Hundred' . ($num % 100 ? ' ' . convertNumberToWords($num % 100) : ''); + if ($num < 100000) return convertNumberToWords((int)($num / 1000)) . ' Thousand' . ($num % 1000 ? ' ' . convertNumberToWords($num % 1000) : ''); + if ($num < 10000000) return convertNumberToWords((int)($num / 100000)) . ' Lakh' . ($num % 100000 ? ' ' . convertNumberToWords($num % 100000) : ''); + if ($num < 1000000000) return convertNumberToWords((int)($num / 10000000)) . ' Crore' . ($num % 10000000 ? ' ' . convertNumberToWords($num % 10000000) : ''); + + return (string)$num; + } +} +?> + + + + + Invoice + + + +
+ + + + + + +
+
+ +
+ + +
+ + + +
+ +
+
INVOICE
+
+
+
+
+ +
+ +
Scan for info
+
+ +
+ + + + + + + +
+
Patient Details
+
Patient ID: p_code ?? '')) ?>
+
Name: p_fname ?? ''))) ?>
+
Gender: xgender ?? '')) ?>
+
Age: age ?? '')) ?>
+
Phone: mphone1 ?? '')) ?>
+
+
Refer Details
+
Refer By: refer_by_other ?? '')) ?>
+
Invoice Date:
+
Printed On:
+
+
Invoice Details
+
Invoice ID:
+
Status:
+
Payment Mode: payment_mode ?? 0); + echo $mode === 1 ? 'Cash' : ($mode === 2 ? 'Bank Card/Online' : ($mode === 3 ? 'IPD Credit' : ($mode === 4 ? 'Org. Credit' : 'Pending'))); + ?>
+
+ + + + + + + +
+
Insurance / Organization
+ +
Insurance: ins_company_name ?? '')) ?>
+ + +
Org. Case No: case_id_code ?? '')) ?>
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + 0) : ?> + + + + + + +
#Charges GroupCharge NameRateQtyAmount
group_desc ?? '')) ?>item_name ?? '')) ?>item_rate ?? '')) ?>item_qty ?? '')) ?> item_amount ?? 0), 2) ?>
Discountdiscount_desc ?? '') ? (' - ' . esc((string) ($invoice->discount_desc ?? ''))) : '' ?>-
+ + + + + + +
+
+
Amount received: | Balance Amount: | Net Amount:
+
Amount in Words:
+
+
+ + + + + + 0) : ?> + + + + + + + + + +
Gross Total
Discount-
Net Amount
+
+ + +
+ + diff --git a/app/Views/billing/ipd/legacy_registration.php b/app/Views/billing/ipd/legacy_registration.php new file mode 100644 index 0000000..7665c9e --- /dev/null +++ b/app/Views/billing/ipd/legacy_registration.php @@ -0,0 +1,372 @@ + + +
+

+ IPD + Registration +

+ +
+ + +
Patient not found.
+ +
+ +
+
+
+

+ Name :p_fname ?? '') ?> + p_relative ?? '') ?> p_rname ?? '') ?> + / Age :age ?? '') ?> + / Gender :xgender ?? '') ?> + / P Code :p_code ?? '') ?> +

+ + +
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+
+
+ +
+
+ +
+ + +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + +
+
+
+
+ + + +
+
+
+ + +
+
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
+

Remarks + Write some about the problem +

+
+ + +
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ + +