Add native CodeIgniter 4 report generation functionality replacing legacy spooler_db system. Provides centralized report generation with audit logging and multi-language support. New Features: - Report generation with Indonesian and English language support - Role-based access control (Lab, Admin, Superuser: generate; CS: print only) - Preview mode for validation workflow - Print audit logging to AUDIT_REQUESTS table - Multi-page report support with proper pagination - Dual unit system (Conventional and International units) Controllers: - ReportController: Main controller for report generation, preview, and print - generate(): Full report with audit logging - preview(): Preview mode without audit logging - print(): Print-only access for CS role - Home::printReport(): Route handler redirecting based on user role Libraries: - ReportHelper: Comprehensive report data retrieval - Patient information (name, MR number, demographics, referral) - Test results with reference ranges and unit conversions - Collection and reception data with timestamps - Validation status and validator information - Special handling for pending samples and Chinese translations Routes: - /report/(:num) - Generate report (Lab, Admin, Superuser) - /report/(:num)/preview - Preview without audit logging - /report/(:num)/eng - English language report - /report/print/(:num) - Print-only access (CS role) - /print/(:num) - Redirect based on role (all roles) Views: - report/template.php: Professional lab report template with Gleneagles branding - Header and footer images - Patient information table - Test results with dual unit columns - Collection and reception timestamps - Authorization signature area - Preview watermark Role Index Views: - Removed dialog_preview.php inclusion from all role dashboards - Consolidated print button directly linking to new report routes Assets: - Report-specific CSS files (normalize.min.css, style.css, pdf.css, style_qr.css) - Gleneagles header and footer images - Legacy spooler_db files preserved in public/spooler_db/ for reference Tests: - ReportTest.php: Unit tests for report generation functionality Database: - Uses existing tables: REQUESTS, TESTS, DICT_TESTS, SP_REQUESTS, PATIENTS - Inserts print audit records into AUDIT_REQUESTS table Security: - Parameterized queries throughout (SQL injection prevention) - Role-based access control enforced at route level - Proper output escaping with esc() in views
242 lines
8.5 KiB
PHP
242 lines
8.5 KiB
PHP
|
|
function getResultDebug($conn, $ACCESSNUMBER, $eng) {
|
|
include("_inc.php");
|
|
$sql = "SELECT DC.FULLTEXT, DT.TESTCODE, T.VALIDATIONSTATUS,
|
|
RESULT = CASE
|
|
WHEN T.RESTYPE=0 THEN 'Pending'
|
|
WHEN T.RESTYPE=4 AND T.RESVALUE='' AND T.RESSTATUS=1 THEN '.' -- null -> .
|
|
WHEN T.RESTYPE IN (7,15,4) THEN T.RESVALUE
|
|
WHEN T.RESTYPE=9 THEN +'< '+T.RESVALUE
|
|
WHEN T.RESTYPE=10 THEN +'> '+T.RESVALUE
|
|
WHEN T.RESVALUE IS NULL THEN
|
|
CASE
|
|
WHEN T.CODEDRESULTID IS NULL AND DT.TESTTYPE IN (4,5) THEN null
|
|
WHEN T.CODEDRESULTID IS NULL THEN TC.COMMENTTEXT
|
|
WHEN T.CODEDRESULTID IS NOT NULL AND T.RESTYPE=6 AND SUBSTRING(DX.FULLTEXT,1,3) NOT LIKE '%#%' THEN DX.FULLTEXT
|
|
END
|
|
ELSE T.RESVALUE
|
|
END,
|
|
T.MINIMUM, T.MAXIMUM,
|
|
DT.FULLTEXT,
|
|
DT.RESPRECISION,DT.RESPRECISION2, DT.OPERAND, DT.SOFTCONVERSION, DT.UNITS, DT.UNITS2, T.RESTYPE, VI.FULLTEXT,
|
|
case
|
|
when TC.COMMENTTEXT is null then DX2.FULLTEXT
|
|
else TC.COMMENTTEXT
|
|
end, T.RERUN
|
|
FROM TESTS T
|
|
JOIN DICT_TESTS DT ON DT.TESTID=T.TESTID
|
|
LEFT JOIN DICT_TEXTS DX ON DX.TEXTID=T.CODEDRESULTID
|
|
LEFT JOIN TESTS_COMMENTS TC ON TC.REQTESTID=T.REQTESTID
|
|
LEFT JOIN DICT_TEXTS DX2 ON DX2.TEXTID=TC.COMMENTCODEDID
|
|
LEFT JOIN REQUESTS R ON R.REQUESTID=T.REQUESTID
|
|
LEFT JOIN DICT_CHAPTERS DC ON DC.CHAPID=T.CHAPID
|
|
LEFT JOIN GDC_CMOD.dbo.V_INTER2 VI ON VI.ATR_ACCESSNUMBER=R.ACCESSNUMBER AND DT.TESTCODE=VI.ATR_TESTCODE
|
|
WHERE R.ACCESSNUMBER='$ACCESSNUMBER' AND T.NOTPRINTABLE IS NULL AND DT.TESTCODE<>'STATS'
|
|
ORDER BY T.TESTORDER";
|
|
$stmt = sqlsrv_query( $conn, $sql );
|
|
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
|
$CHAP = "";
|
|
$i = 0;
|
|
$page = 1;
|
|
$line = 0;
|
|
$lpp = 34; // line per page
|
|
$done[1]= "";
|
|
$nline = 0;
|
|
$RERUN=1;
|
|
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC)) {
|
|
$CHAPTER = $row[0];
|
|
$TESTCODE = $row[1];
|
|
$VALIDATIONSTATUS = $row[2];
|
|
$R1 = $row[3];
|
|
if($R1=='****') {$R1='-';}
|
|
$L1 = $row[4];
|
|
$H1 = $row[5];
|
|
$FULLTEXT = $row[6];
|
|
$PRECISION1 = $row[7];
|
|
$PRECISION2 = $row[8];
|
|
$OPERAND = $row[9];// 3* 4/
|
|
$SOFTCONVERSION =$row[10];
|
|
$U1 = $row[11];
|
|
$U2 = $row[12];
|
|
$RESTYPE = $row[13];
|
|
$I = $row[14];
|
|
$RESCOM = $row[15];
|
|
|
|
// Get ITEXT or ETEXT
|
|
if($eng==1) {
|
|
$ICHAPTER = substr($CHAPTER, strpos($CHAPTER,'#E')+2, strrpos($CHAPTER,'#E')-strpos($CHAPTER,'#E')-2 );
|
|
if($ICHAPTER != $CHAP) {
|
|
$raw[$i] = " <tr><td colspan='7'><pre>$ICHAPTER</pre></td> </tr>\r\n";
|
|
$nline += 1;
|
|
}
|
|
$CHAP = $ICHAPTER;
|
|
$ITEXT = substr($FULLTEXT, strpos($FULLTEXT,'#E')+2, strrpos($FULLTEXT,'#E')-strpos($FULLTEXT,'#E')-2 );
|
|
} else {
|
|
$ICHAPTER = substr($CHAPTER,2, strrpos($CHAPTER,'#I')-2 );
|
|
if($ICHAPTER != $CHAP) {
|
|
$raw[$i] = " <tr><td colspan='7'><pre>$ICHAPTER</pre></td> </tr>\r\n";
|
|
$nline += 1;
|
|
}
|
|
$CHAP = $ICHAPTER;
|
|
$ITEXT = substr($FULLTEXT,2, strrpos($FULLTEXT,'#I')-2 );
|
|
}
|
|
// GRP | ELE
|
|
if($TESTCODE=='PCRN') { $raw[$i] .= " <tr> <td></td> <td colspan='6'><br/><pre>$ITEXT</pre></td></tr>"; $done[$page] .= $raw[$i]; }
|
|
elseif(!is_numeric($RESTYPE)) {
|
|
// ch
|
|
if( array_key_exists( $TESTCODE, $_chinese) ) { $ITEXT = rtrim($ITEXT)." <span class='textC'>".$_chinese[$TESTCODE].'</span>'; }
|
|
if($ITEXT!='') {
|
|
$ITEXT = " <tr> <td colspan='7'><pre>$ITEXT</pre></td> </tr>\r\n";
|
|
$nline += 1;
|
|
$raw[$i] .= $ITEXT;
|
|
}
|
|
|
|
$RERUN = $row[16];
|
|
} else {
|
|
//flagging
|
|
if( substr($R1,0,2)=='< ' && is_numeric(substr($R1,2,strlen($R1))) ) { $r1 = substr($R1,2,strlen($R1)); $r1-=1;}
|
|
elseif( substr($R1,0,2)=='> ' && is_numeric(substr($R1,2,strlen($R1))) ) { $r1 = substr($R1,2,strlen($R1)); $r1+=1;}
|
|
else {$r1 = $R1;}
|
|
if($r1 < $L1 && is_numeric($r1) && is_numeric($L1)) {$F = "*L";}
|
|
elseif($r1 > $H1 && is_numeric($r1) && is_numeric($H1)) {$F = "*H";}
|
|
else {$F="";}
|
|
//echo "$R1<br/>";
|
|
|
|
//get R2 L2 H2
|
|
if($RESTYPE == 0) { $R2=""; $L1=""; $H1=""; $L2=""; $H2=""; }
|
|
else {
|
|
if( in_array($RESTYPE,[7,15,4]) && $OPERAND == 3 ) {
|
|
if(is_numeric($R1)) { $R2 = NUMBER_FORMAT($R1 * $SOFTCONVERSION, $PRECISION2,'.',''); }
|
|
else {$R2 = 0;}
|
|
if($L1 != 0) { $L2 = NUMBER_FORMAT($L1 * $SOFTCONVERSION, $PRECISION2); }
|
|
else {$L2 = 0;}
|
|
if($H1 != 0) { $H2 = NUMBER_FORMAT($H1 * $SOFTCONVERSION, $PRECISION2); }
|
|
else {$H2 = 0;}
|
|
} elseif( in_array($RESTYPE,[7,15,4]) && $OPERAND == 4 ) {
|
|
IF(is_numeric($R1)) { $R2 = NUMBER_FORMAT($R1 / $SOFTCONVERSION, $PRECISION2); }
|
|
ELSE {$R2 = 0;}
|
|
IF($L1 != 0) { $L2 = NUMBER_FORMAT($L1 / $SOFTCONVERSION, $PRECISION2); }
|
|
ELSE {$L2 = 0;}
|
|
IF($H1 != 0) { $H2 = NUMBER_FORMAT($H1 / $SOFTCONVERSION, $PRECISION2); }
|
|
ELSE {$H2 = 0;}
|
|
} else { $R2=$R1; $L2=$L1; $H2=$H1; }
|
|
}
|
|
//precision1
|
|
if(is_numeric($R1) && is_numeric($PRECISION1)) { $R1 = NUMBER_FORMAT($R1,$PRECISION1,'.',''); }
|
|
|
|
// split in half - multi line
|
|
// text | result
|
|
$TEXT = explode("\r\n",$ITEXT);
|
|
$test = array();
|
|
$res = array();
|
|
foreach($TEXT as $text) {
|
|
$test[]= substr($text,0,33);
|
|
$res[]= substr($text,33,strlen($text));
|
|
}
|
|
$space = ( strlen($test[0])-strlen(ltrim($test[0])) ) * 7;
|
|
$test = rtrim(implode("\r\n",$test));
|
|
$res = implode("\r\n",$res);
|
|
// italic
|
|
if( in_array( $TESTCODE, $_italic) ) { $test ="<i>$test</i>"; }
|
|
// ch
|
|
if( array_key_exists( $TESTCODE, $_chinese) ) { $test.=" <span class='textC'>".$_chinese[$TESTCODE].'</span>'; }
|
|
//line count
|
|
$tline = count( explode(PHP_EOL, $test) );
|
|
$rline = count( explode(PHP_EOL, $res) );
|
|
$r1line = count( explode(PHP_EOL, $R1) );
|
|
if($rline < $r1line) { $rline = $r1line; }
|
|
|
|
if ($test == ' Note') {
|
|
$ITEXT = " <tr> <td style='padding-left:".$space."px'><br/>$test</td> <td colspan='6'><br/><pre>$res </pre></td> </tr>\r\n";
|
|
} elseif ( strlen($RESCOM) < 2 ) {
|
|
$ITEXT = " <tr> <td style='padding-left:".$space."px'>$test</td> <td colspan='6'><pre>$res </pre></td> </tr>\r\n";
|
|
} else {
|
|
$rline += count( explode(PHP_EOL, $RESCOM) );
|
|
$res = rtrim($res);
|
|
$ITEXT = " <tr> <td style='padding-left:".$space."px'>$test</td> <td colspan='6'><pre>$res \r\n$RESCOM</pre></td> </tr>\r\n ";
|
|
}
|
|
if($tline > $rline) { $nline += $tline; } else { $nline += $rline; }
|
|
|
|
/*
|
|
## replace {R1 {L1 {H1 {R2 {L2 {H2 {I ##
|
|
GET STRING POS
|
|
DELETE ALL STRING
|
|
{R1,{R2,{I,{L1,{H1,{L2,{H2 // ORDER
|
|
GET NEW STRING LENGTH
|
|
*/
|
|
// Get all string pos
|
|
$posR1 = strpos($ITEXT, "{R1");
|
|
$posR12 = strrpos($ITEXT, "{R1");
|
|
$posR2 = strpos($ITEXT, "{R2");
|
|
$posR22 = strrpos($ITEXT, "{R2");
|
|
$posI1 = strpos($ITEXT, "{I");
|
|
$posI2 = strrpos($ITEXT, "{I");
|
|
$posL1 = strpos($ITEXT, "{L1");
|
|
$posH1 = strpos($ITEXT, "{H1");
|
|
$posL2 = strpos($ITEXT, "{L2");
|
|
$posH2 = strpos($ITEXT, "{H2");
|
|
$posU1 = strpos($ITEXT, "{U1");
|
|
$posU2 = strpos($ITEXT, "{U2");
|
|
#echo "<pre>$ITEXT</pre>\r\n";
|
|
// Delete all string
|
|
$ITEXT = str_replace( "{R1", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{R2", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{I", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{L1", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{H1", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{L2", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{H2", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{U1", " ", $ITEXT );
|
|
$ITEXT = str_replace( "{U2", " ", $ITEXT );
|
|
// REPLACE
|
|
if(in_array($RESTYPE, [4,6,7,9,10,15])) {
|
|
$ITEXT = f_repl($ITEXT,$R1.' '.$F,$posR1);
|
|
if($posR1 != $posR12) { $ITEXT = f_repl($ITEXT,$R1.' '.$F,$posR12); }
|
|
$ITEXT = f_repl($ITEXT,$L1,$posL1);
|
|
$ITEXT = f_repl($ITEXT,$H1,$posH1);
|
|
if(isset($R2)) {
|
|
$ITEXT = f_repl($ITEXT,$R2.' '.$F,$posR2);
|
|
if($posR2 != $posR22) { $ITEXT = f_repl($ITEXT,$R2.' '.$F,$posR22); }
|
|
}
|
|
if(isset($L2)) { $ITEXT = f_repl($ITEXT,$L2,$posL2); }
|
|
if(isset($H2)) { $ITEXT = f_repl($ITEXT,$H2,$posH2); }
|
|
if($I == 'Negative') {
|
|
$I1 = "Negatif";
|
|
$I2 = "Negative";
|
|
$ITEXT = f_repl($ITEXT,$I1,$posI1);
|
|
$ITEXT = f_repl($ITEXT,$I2,$posI2);
|
|
} else {
|
|
$ITEXT = f_repl($ITEXT,$I,$posI1);
|
|
$ITEXT = f_repl($ITEXT,$I,$posI2);
|
|
}
|
|
$ITEXT = f_repl($ITEXT,$U1,$posU1);
|
|
$ITEXT = f_repl($ITEXT,$U2,$posU2);
|
|
} elseif(in_array($RESTYPE,[0,5])) {
|
|
if(strlen($RESCOM) < 2) {
|
|
$ITEXT = substr($ITEXT, 0, $posR1); $ITEXT .= $R1."</pre></td> </tr>";
|
|
} else {
|
|
$ITEXT = substr($ITEXT, 0, $posR1); $ITEXT .= "$R1 \r\n$RESCOM</pre></td> </tr>";
|
|
}
|
|
}
|
|
// bold flag
|
|
//$ITEXT = str_replace('*L', '<b>*L</b>', $ITEXT);
|
|
//$ITEXT = str_replace('*H', '<b>*H</b>', $ITEXT);
|
|
$raw[$i] .= $ITEXT;
|
|
$line += $nline;
|
|
|
|
if($TESTCODE != 'COVGG') {
|
|
if($line > $lpp) {$page++; $done[$page] = ""; $line = $nline; }
|
|
} else {
|
|
if($line > $lpp-14) {$page++; $done[$page] = ""; $line = $nline; }
|
|
}
|
|
|
|
if($line > $lpp) {$page++; $done[$page] = ""; $line = $nline; }
|
|
$done[$page] .= $raw[$i];
|
|
$i++;
|
|
$raw[$i] = "";
|
|
$nline = 0;
|
|
}
|
|
}
|
|
return $done;
|
|
}
|