diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index d5bfca8..0147f7d 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -605,6 +605,7 @@ $routes->post('Opd_prescription/section_template_track_usage', 'Opd_prescription
$routes->get('Opd_prescription/section_template_list', 'Opd_prescription::section_template_list');
$routes->get('Opd_prescription/section_past_data', 'Opd_prescription::section_past_data');
$routes->get('Opd_prescription/template_workspace', 'Opd_prescription::template_workspace', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
+$routes->get('doctor_work/patient_search', 'DoctorDocument::patient_search', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
$routes->get('doctor_work/document_workspace', 'DoctorDocument::workspace', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
// Legacy-compatible doctor document templates and issue flow.
diff --git a/app/Controllers/DoctorDocument.php b/app/Controllers/DoctorDocument.php
index 3510e29..3c68426 100644
--- a/app/Controllers/DoctorDocument.php
+++ b/app/Controllers/DoctorDocument.php
@@ -148,8 +148,15 @@ class DoctorDocument extends BaseController
$logoFile = defined('H_logo') ? (string) constant('H_logo') : 'logo.png';
$logoAbsPath = FCPATH . 'assets/images/' . $logoFile;
+ $logoSrc = $this->buildImageDataUriFromPath($logoAbsPath);
+ if ($logoSrc === '' && is_file($logoAbsPath)) {
+ $logoSrc = str_replace('\\', '/', $logoAbsPath);
+ }
+ if ($logoSrc === '') {
+ $logoSrc = base_url('assets/images/' . $logoFile);
+ }
$logoHtml = '
';
+ . $logoSrc . '" />';
$age = (string) ($doc['age'] ?? '');
$gender = (string) ($doc['gender'] ?? '');
@@ -158,7 +165,16 @@ class DoctorDocument extends BaseController
$drSignImg = '';
$drSignFile = (string) ($doc['dr_sign'] ?? $doc['sign_image'] ?? $doc['doctor_sign'] ?? '');
if ($drSignFile !== '') {
- $drSignImg = '
';
+ $drSignAbsPath = FCPATH . 'assets/images/' . ltrim($drSignFile, '/\\');
+ $drSignSrc = $this->buildImageDataUriFromPath($drSignAbsPath);
+ if ($drSignSrc === '' && is_file($drSignAbsPath)) {
+ $drSignSrc = str_replace('\\', '/', $drSignAbsPath);
+ }
+ if ($drSignSrc === '') {
+ $drSignSrc = base_url('assets/images/' . $drSignFile);
+ }
+
+ $drSignImg = '
';
}
$map = [
@@ -187,6 +203,29 @@ class DoctorDocument extends BaseController
return str_replace(array_keys($map), array_values($map), $html);
}
+ private function buildImageDataUriFromPath(string $absolutePath): string
+ {
+ $absolutePath = trim($absolutePath);
+ if ($absolutePath === '' || ! is_file($absolutePath) || ! is_readable($absolutePath)) {
+ return '';
+ }
+
+ $bytes = @file_get_contents($absolutePath);
+ if ($bytes === false || $bytes === '') {
+ return '';
+ }
+
+ $mime = 'image/png';
+ if (function_exists('mime_content_type')) {
+ $detected = @mime_content_type($absolutePath);
+ if (is_string($detected) && str_starts_with($detected, 'image/')) {
+ $mime = $detected;
+ }
+ }
+
+ return 'data:' . $mime . ';base64,' . base64_encode($bytes);
+ }
+
private function hasColumn(string $table, string $column): bool
{
if (! $this->db->tableExists($table)) {
@@ -226,6 +265,128 @@ class DoctorDocument extends BaseController
return view('doctor_document/workspace');
}
+ public function patient_search()
+ {
+ if ($resp = $this->ensureAccess()) {
+ return $resp;
+ }
+
+ $search = trim((string) $this->request->getGet('q'));
+ $patients = $this->searchDoctorWorkPatients($search);
+ $countsByPatient = $this->getDoctorWorkPatientCounts(array_map(static fn(array $row): int => (int) ($row['id'] ?? 0), $patients));
+
+ foreach ($patients as &$patientRow) {
+ $patientId = (int) ($patientRow['id'] ?? 0);
+ $patientCounts = $countsByPatient[$patientId] ?? [];
+ $patientRow['opd_count'] = (int) ($patientCounts['opd_count'] ?? 0);
+ $patientRow['lab_count'] = (int) ($patientCounts['lab_count'] ?? 0);
+ $patientRow['ipd_count'] = (int) ($patientCounts['ipd_count'] ?? 0);
+ }
+ unset($patientRow);
+
+ return view('doctor_document/patient_search', [
+ 'search' => $search,
+ 'patients' => $patients,
+ ]);
+ }
+
+ /**
+ * @return list>
+ */
+ private function searchDoctorWorkPatients(string $search): array
+ {
+ $search = preg_replace('/[^A-Za-z0-9 _.@\-]/', '', trim($search)) ?? '';
+
+ if ($search === '') {
+ return [];
+ }
+
+ $searchTokens = preg_split('/\s+/', $search) ?: [];
+ $whereParts = ['1=1'];
+
+ foreach ($searchTokens as $token) {
+ $token = trim((string) $token);
+ if ($token === '') {
+ continue;
+ }
+
+ $escaped = $this->db->escape($token);
+ $likeToken = $this->db->escapeLikeString($token);
+
+ if (is_numeric($token)) {
+ $whereParts[] = "(p.p_code LIKE '%{$likeToken}' ESCAPE '!' OR p.mphone1 = {$escaped} OR p.udai = {$escaped})";
+ continue;
+ }
+
+ if (ctype_alpha($token)) {
+ $whereParts[] = "(p.p_fname LIKE '%{$likeToken}%' ESCAPE '!' OR p.email1 = {$escaped})";
+ continue;
+ }
+
+ $whereParts[] = "(p.p_code LIKE '{$likeToken}' ESCAPE '!' OR p.email1 = {$escaped})";
+ }
+
+ $sql = "SELECT p.*, DATE_FORMAT(p.last_visit,'%d-%m-%Y') AS Last_Visit
+ FROM patient_master p
+ WHERE " . implode(' AND ', $whereParts) . "
+ GROUP BY p.id
+ ORDER BY p.last_visit DESC
+ LIMIT 100";
+
+ return $this->db->query($sql)->getResultArray();
+ }
+
+ /**
+ * @param list $patientIds
+ * @return array>
+ */
+ private function getDoctorWorkPatientCounts(array $patientIds): array
+ {
+ $patientIds = array_values(array_unique(array_filter(array_map('intval', $patientIds), static fn(int $id): bool => $id > 0)));
+ if ($patientIds === []) {
+ return [];
+ }
+
+ $countsByPatient = [];
+ foreach ($patientIds as $patientId) {
+ $countsByPatient[$patientId] = [
+ 'opd_count' => 0,
+ 'lab_count' => 0,
+ 'ipd_count' => 0,
+ ];
+ }
+
+ $countSources = [
+ ['table' => 'opd_master', 'column' => 'p_id', 'alias' => 'opd_count'],
+ ['table' => 'lab_request', 'column' => 'patient_id', 'alias' => 'lab_count'],
+ ['table' => 'ipd_master', 'column' => 'p_id', 'alias' => 'ipd_count'],
+ ];
+
+ foreach ($countSources as $source) {
+ if (! $this->hasColumn($source['table'], $source['column'])) {
+ continue;
+ }
+
+ $rows = $this->db->table($source['table'])
+ ->select($source['column'] . ' AS patient_id, COUNT(*) AS total_count', false)
+ ->whereIn($source['column'], $patientIds)
+ ->groupBy($source['column'])
+ ->get()
+ ->getResultArray();
+
+ foreach ($rows as $row) {
+ $patientId = (int) ($row['patient_id'] ?? 0);
+ if ($patientId <= 0 || ! array_key_exists($patientId, $countsByPatient)) {
+ continue;
+ }
+
+ $countsByPatient[$patientId][$source['alias']] = (int) ($row['total_count'] ?? 0);
+ }
+ }
+
+ return $countsByPatient;
+ }
+
public function open_by_key()
{
if ($resp = $this->ensureAccess()) {
@@ -1087,6 +1248,16 @@ class DoctorDocument extends BaseController
$patientDoc
);
+ $logoFile = defined('H_logo') ? (string) constant('H_logo') : 'logo.png';
+ $logoAbsPath = FCPATH . 'assets/images/' . $logoFile;
+ $hospitalLogoSrc = $this->buildImageDataUriFromPath($logoAbsPath);
+ if ($hospitalLogoSrc === '' && is_file($logoAbsPath)) {
+ $hospitalLogoSrc = str_replace('\\', '/', $logoAbsPath);
+ }
+ if ($hospitalLogoSrc === '') {
+ $hospitalLogoSrc = base_url('assets/images/' . $logoFile);
+ }
+
$data = [
'content' => $content,
'print_on_type' => $resolvedPrintType,
@@ -1102,6 +1273,7 @@ class DoctorDocument extends BaseController
'custom_header_html' => $customHeaderHtml,
'custom_footer_html' => $customFooterHtml,
'has_selected_print_template' => is_array($selectedPrintTemplate),
+ 'hospital_logo_src' => $hospitalLogoSrc,
];
$mpdfTempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
diff --git a/app/Views/doctor_document/doc_letterhead_print.php b/app/Views/doctor_document/doc_letterhead_print.php
index 313d62f..cce958d 100644
--- a/app/Views/doctor_document/doc_letterhead_print.php
+++ b/app/Views/doctor_document/doc_letterhead_print.php
@@ -9,6 +9,10 @@ $footerMargin = number_format((float) ($print_footer_margin ?? 1.50), 2, '.', ''
$customHeaderHtml = (string) ($custom_header_html ?? '');
$customFooterHtml = (string) ($custom_footer_html ?? '');
$hasSelectedPrintTemplate = ! empty($has_selected_print_template);
+$hospitalLogoSrc = trim((string) ($hospital_logo_src ?? ''));
+if ($hospitalLogoSrc === '') {
+ $hospitalLogoSrc = base_url('assets/images/' . (defined('H_logo') ? constant('H_logo') : 'logo.png'));
+}
?>