fix: Running OPD zero-value validity, update_doc_field HTTP 500, PDF Unicode font (Devanagari)
- Opd.php showfee(): exclude zero-amount OPD from validity window query - Opd.php confirm_opd(): anchor last_opdvisit_date to most recent paid OPD for zero-value running - Opd.php buildOpdLetterPrintData(): use paid OPD start date for expiry on zero-value entries - OpdModel.php insertOpd(): exclude fee_type=3/zero-amount from running_opd_id lookup; anchor visit count to paid OPD start when isZeroValueRunning - DoctorDocument.php update_doc_field(): wrap in try/catch, schema-safe payload via filterPayloadByExistingColumns, structured JSON errors - DoctorDocument.php create_final(): configure mPDF with FreeSans/FreeSerif (GNU FreeFont), useOTL=0xFF, autoScriptToLang=true for Devanagari/Hindi rendering - doc_letterhead_print.php: add body/p/td/th font-family freesans for PDF Unicode output
This commit is contained in:
parent
a81162f954
commit
21ddeefe40
|
|
@ -828,52 +828,98 @@ class DoctorDocument extends BaseController
|
|||
if ($resp = $this->ensureAccess()) {
|
||||
return $resp;
|
||||
}
|
||||
try {
|
||||
if (! $this->db->tableExists('patient_doc') || ! $this->db->tableExists('patient_doc_raw')) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Document tables not available',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$pending = $this->db->table('patient_doc_raw')
|
||||
->where('p_doc_id', $patientDocId)
|
||||
->where('update_data', 0)
|
||||
->countAllResults();
|
||||
$pending = 0;
|
||||
if ($this->hasColumn('patient_doc_raw', 'update_data')) {
|
||||
$pending = $this->db->table('patient_doc_raw')
|
||||
->where('p_doc_id', $patientDocId)
|
||||
->where('update_data', 0)
|
||||
->countAllResults();
|
||||
}
|
||||
|
||||
if ($pending > 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Some field pending',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$patientDoc = $this->db->table('patient_doc')->where('id', $patientDocId)->get(1)->getRowArray();
|
||||
if (! is_array($patientDoc)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Document not found',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$report = (string) ($patientDoc['raw_data'] ?? '');
|
||||
|
||||
$values = $this->db->table('patient_doc_raw r')
|
||||
->select('r.p_doc_raw_value,s.input_code')
|
||||
->join('doc_format_sub s', 'r.p_doc_sub_id=s.id', 'left')
|
||||
->where('r.p_doc_id', $patientDocId)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($values as $row) {
|
||||
$code = trim((string) ($row['input_code'] ?? ''));
|
||||
if ($code === '') {
|
||||
continue;
|
||||
}
|
||||
$val = nl2br((string) ($row['p_doc_raw_value'] ?? ''));
|
||||
$report = str_replace('{' . $code . '}', $val, $report);
|
||||
}
|
||||
|
||||
$updatePayload = [
|
||||
'raw_data' => $report,
|
||||
'update_pre_value' => 1,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
$updatePayload = $this->filterPayloadByExistingColumns('patient_doc', $updatePayload);
|
||||
|
||||
if (empty($updatePayload)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Unable to compile due to schema mismatch',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->table('patient_doc')->where('id', $patientDocId)->update($updatePayload);
|
||||
|
||||
if ($pending > 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Compile done',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'DoctorDocument update_doc_field failed for doc_id {doc_id}: {message}', [
|
||||
'doc_id' => $patientDocId,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return $this->response->setStatusCode(500)->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Some field pending',
|
||||
'error_text' => 'Compile failed due to server error',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$patientDoc = $this->db->table('patient_doc')->where('id', $patientDocId)->get(1)->getRowArray();
|
||||
$report = (string) ($patientDoc['raw_data'] ?? '');
|
||||
|
||||
$values = $this->db->table('patient_doc_raw r')
|
||||
->select('r.p_doc_raw_value,s.input_code')
|
||||
->join('doc_format_sub s', 'r.p_doc_sub_id=s.id', 'left')
|
||||
->where('r.p_doc_id', $patientDocId)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($values as $row) {
|
||||
$code = trim((string) ($row['input_code'] ?? ''));
|
||||
if ($code === '') {
|
||||
continue;
|
||||
}
|
||||
$val = nl2br((string) ($row['p_doc_raw_value'] ?? ''));
|
||||
$report = str_replace('{' . $code . '}', $val, $report);
|
||||
}
|
||||
|
||||
$this->db->table('patient_doc')->where('id', $patientDocId)->update([
|
||||
'raw_data' => $report,
|
||||
'update_pre_value' => 1,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Compile done',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function load_doc(int $patientDocId)
|
||||
|
|
@ -1063,6 +1109,10 @@ class DoctorDocument extends BaseController
|
|||
mkdir($mpdfTempDir, 0755, true);
|
||||
}
|
||||
|
||||
// FreeSans (GNU FreeFont) ships with mPDF and covers Devanagari (Hindi) Unicode glyphs.
|
||||
$mpdfFontDir = realpath(__DIR__ . '/../../vendor/mpdf/mpdf/ttfonts');
|
||||
$mpdfFontDirs = $mpdfFontDir !== false ? [$mpdfFontDir] : [];
|
||||
|
||||
try {
|
||||
$mpdf = new Mpdf([
|
||||
'format' => $pageSize,
|
||||
|
|
@ -1073,8 +1123,28 @@ class DoctorDocument extends BaseController
|
|||
'margin_header' => $printHeaderMargin * 10,
|
||||
'margin_footer' => $printFooterMargin * 10,
|
||||
'tempDir' => $mpdfTempDir,
|
||||
'autoScriptToLang' => false,
|
||||
'autoLanguageDetection' => false,
|
||||
'default_font' => 'freesans',
|
||||
'fontDir' => $mpdfFontDirs,
|
||||
'fontdata' => [
|
||||
'freesans' => [
|
||||
'R' => 'FreeSans.ttf',
|
||||
'B' => 'FreeSansBold.ttf',
|
||||
'I' => 'FreeSansOblique.ttf',
|
||||
'BI' => 'FreeSansBoldOblique.ttf',
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
'freeserif' => [
|
||||
'R' => 'FreeSerif.ttf',
|
||||
'B' => 'FreeSerifBold.ttf',
|
||||
'I' => 'FreeSerifItalic.ttf',
|
||||
'BI' => 'FreeSerifBoldItalic.ttf',
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
],
|
||||
'autoScriptToLang' => true,
|
||||
'autoLanguageDetection' => true,
|
||||
'autoArabic' => false,
|
||||
'autoVietnamese' => false,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1378,7 +1378,8 @@ class Opd extends BaseController
|
|||
$docInfo = $query->getResult();
|
||||
|
||||
$sql = "select * from opd_master where p_id=" . $pId . " and doc_id=" . $docId .
|
||||
" and apointment_date >= date_add(curdate(),interval -" . $noOpdDays . " day) and opd_fee_type<>3";
|
||||
" and apointment_date >= date_add(curdate(),interval -" . $noOpdDays . " day)"
|
||||
. " and opd_fee_type<>3 and coalesce(opd_fee_amount,0) > 0";
|
||||
$query = $this->db->query($sql);
|
||||
$opdRunning = $query->getResult();
|
||||
|
||||
|
|
@ -1544,7 +1545,25 @@ class Opd extends BaseController
|
|||
'prepared_by' => $userNameInfo,
|
||||
];
|
||||
|
||||
if (count($opdMaster) > 0) {
|
||||
$isZeroValueRunning = ((int) ($docFee[0]->doc_fee_type ?? 0) === 3)
|
||||
|| ((float) ($docFee[0]->amount ?? 0) <= 0);
|
||||
|
||||
if ($isZeroValueRunning) {
|
||||
$sql = "select apointment_date from opd_master"
|
||||
. " where p_id=" . $pid
|
||||
. " and doc_id=" . $docId
|
||||
. " and opd_fee_type<>3"
|
||||
. " and coalesce(opd_fee_amount,0) > 0"
|
||||
. " order by opd_id desc limit 1";
|
||||
$query = $this->db->query($sql);
|
||||
$previousPaid = $query->getResult();
|
||||
|
||||
if (!empty($previousPaid[0]->apointment_date ?? null)) {
|
||||
$insert['last_opdvisit_date'] = $previousPaid[0]->apointment_date;
|
||||
} elseif (count($opdMaster) > 0) {
|
||||
$insert['last_opdvisit_date'] = $opdMaster[0]->apointment_date;
|
||||
}
|
||||
} elseif (count($opdMaster) > 0) {
|
||||
$insert['last_opdvisit_date'] = $opdMaster[0]->apointment_date;
|
||||
}
|
||||
|
||||
|
|
@ -3488,10 +3507,16 @@ class Opd extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
$sql = "select *,date_format(apointment_date,'%d-%m-%Y') as str_apointment_date,
|
||||
date_format(date_add(apointment_date,interval " . $noOpdDays . " day),'%d-%m-%Y') as opd_Exp_Date,
|
||||
$sql = "select o.*,date_format(o.apointment_date,'%d-%m-%Y') as str_apointment_date,
|
||||
date_format(date_add(
|
||||
case
|
||||
when (coalesce(o.running_opd,0)=1 or coalesce(o.opd_fee_amount,0)<=0) and coalesce(o.running_opd_id,0)>0
|
||||
then coalesce((select apointment_date from opd_master where opd_id=o.running_opd_id), o.apointment_date)
|
||||
else o.apointment_date
|
||||
end,
|
||||
interval " . $noOpdDays . " day),'%d-%m-%Y') as opd_Exp_Date,
|
||||
(case payment_status when 1 then 'Cash' when 2 then 'Bank Card' when 3 then 'Org. Credit' else 'Pending' end) as Payment_type_str
|
||||
from opd_master where opd_id=" . (int) $opdId;
|
||||
from opd_master o where o.opd_id=" . (int) $opdId;
|
||||
$query = $this->db->query($sql);
|
||||
$data['opd_master'] = $query->getResult();
|
||||
|
||||
|
|
@ -3511,11 +3536,25 @@ class Opd extends BaseController
|
|||
$pRow->age = get_age_1($pRow->dob ?? null, $pRow->age ?? '', $pRow->age_in_month ?? '', $pRow->estimate_dob ?? '', $opdRow->apointment_date ?? null);
|
||||
}
|
||||
|
||||
$sql = "select *,date_format(apointment_date,'%d-%m-%Y') as str_apointment_date,
|
||||
date_format(date_add(apointment_date,interval " . $noOpdDays . " day),'%d-%m-%Y') as opd_Exp_Date
|
||||
from opd_master where p_id=" . (int) $opdRow->p_id . " and opd_id < " . (int) $opdId . " order by opd_id desc limit 1";
|
||||
$query = $this->db->query($sql);
|
||||
$data['old_opd'] = $query->getResult();
|
||||
$data['old_opd'] = [];
|
||||
if (!empty($opdRow->last_opdvisit_date)) {
|
||||
$sql = "select *,date_format(apointment_date,'%d-%m-%Y') as str_apointment_date,
|
||||
date_format(date_add(apointment_date,interval " . $noOpdDays . " day),'%d-%m-%Y') as opd_Exp_Date
|
||||
from opd_master where p_id=" . (int) $opdRow->p_id
|
||||
. " and doc_id=" . (int) ($opdRow->doc_id ?? 0)
|
||||
. " and apointment_date=" . $this->db->escape((string) $opdRow->last_opdvisit_date)
|
||||
. " order by opd_id desc limit 1";
|
||||
$query = $this->db->query($sql);
|
||||
$data['old_opd'] = $query->getResult();
|
||||
}
|
||||
|
||||
if (empty($data['old_opd'])) {
|
||||
$sql = "select *,date_format(apointment_date,'%d-%m-%Y') as str_apointment_date,
|
||||
date_format(date_add(apointment_date,interval " . $noOpdDays . " day),'%d-%m-%Y') as opd_Exp_Date
|
||||
from opd_master where p_id=" . (int) $opdRow->p_id . " and opd_id < " . (int) $opdId . " order by opd_id desc limit 1";
|
||||
$query = $this->db->query($sql);
|
||||
$data['old_opd'] = $query->getResult();
|
||||
}
|
||||
|
||||
$sql = "select * from hc_insurance where id=" . (int) ($opdRow->insurance_id ?? 0);
|
||||
$query = $this->db->query($sql);
|
||||
|
|
|
|||
|
|
@ -42,14 +42,6 @@ class OpdModel
|
|||
return 0;
|
||||
}
|
||||
|
||||
$opdTimesRow = $this->db->table('opd_master')
|
||||
->select('count(*) as xtimes')
|
||||
->where('opd_id <=', $insertId)
|
||||
->where('p_id', $pId)
|
||||
->get()
|
||||
->getRow();
|
||||
$opdTimes = (int) ($opdTimesRow->xtimes ?? 0);
|
||||
|
||||
$opdNoRow = $this->db->table('opd_master')
|
||||
->select('count(*) as no_max')
|
||||
->where('apointment_date', date('Y-m-d'))
|
||||
|
|
@ -66,6 +58,8 @@ class OpdModel
|
|||
|
||||
$runningOpd = 0;
|
||||
$lastOpdId = 0;
|
||||
$isZeroValueRunning = ((int) ($data['opd_fee_type'] ?? 0) === 3)
|
||||
|| ((float) ($data['opd_fee_amount'] ?? 0) <= 0);
|
||||
|
||||
if ((int) ($data['opd_fee_type'] ?? 0) === 3) {
|
||||
$runningOpd = 1;
|
||||
|
|
@ -75,6 +69,8 @@ class OpdModel
|
|||
->where('apointment_date >=', date('Y-m-d', strtotime('-4 days')))
|
||||
->where('apointment_date <=', date('Y-m-d'))
|
||||
->where('running_opd', 0)
|
||||
->where('opd_fee_type <>', 3)
|
||||
->where('coalesce(opd_fee_amount,0) >', 0, false)
|
||||
->where('doc_id', $docId)
|
||||
->where('p_id', $pId)
|
||||
->get()
|
||||
|
|
@ -83,6 +79,21 @@ class OpdModel
|
|||
$lastOpdId = (int) ($lastOpdRow->last_opd_id ?? 0);
|
||||
}
|
||||
|
||||
$opdTimesBuilder = $this->db->table('opd_master')
|
||||
->select('count(*) as xtimes')
|
||||
->where('opd_id <=', $insertId)
|
||||
->where('p_id', $pId);
|
||||
|
||||
if ($isZeroValueRunning && $lastOpdId > 0) {
|
||||
// For zero-value running OPD, keep visit count within the same paid OPD validity cycle.
|
||||
$opdTimesBuilder
|
||||
->where('opd_id >=', $lastOpdId)
|
||||
->where('doc_id', $docId);
|
||||
}
|
||||
|
||||
$opdTimesRow = $opdTimesBuilder->get()->getRow();
|
||||
$opdTimes = (int) ($opdTimesRow->xtimes ?? 0);
|
||||
|
||||
$update = [
|
||||
'opd_code' => $opdCode,
|
||||
'no_visit' => $opdTimes,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ $hasSelectedPrintTemplate = ! empty($has_selected_print_template);
|
|||
header: html_myHeader;
|
||||
footer: html_myFooter;
|
||||
}
|
||||
body, p, td, th, div, span, li {
|
||||
font-family: 'freesans', 'freeserif', sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
<htmlpageheader name="myHeader">
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user