388 lines
13 KiB
PHP
388 lines
13 KiB
PHP
<?php
|
|
defined('BASEPATH') or exit('No direct script access allowed');
|
|
|
|
/**
|
|
* Birt_proxy — PHP proxy untuk semua BIRT report call
|
|
*
|
|
* Flow:
|
|
* 1. Terima request dari frontend (report_code + params)
|
|
* 2. Decrypt patient PII dari _enc
|
|
* 3. INSERT ke patient_print_cache
|
|
* 4. Call BIRT via file_get_contents (internal)
|
|
* 5. DELETE cache
|
|
* 6. Stream PDF ke frontend
|
|
*
|
|
* Endpoint: POST /tools/birt_proxy/stream
|
|
* Params : report_code, PT_OrderHeaderID, PUsername, (optional) PID_patient
|
|
*/
|
|
class Birt_proxy extends MY_Controller
|
|
{
|
|
private $db_onedev;
|
|
private $birt_base = 'http://localhost:8080';
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->db_onedev = $this->load->database('onedev', true);
|
|
$this->load->library('ibl_encryptor');
|
|
}
|
|
|
|
// GET/POST /tools/birt_proxy/stream_by_code
|
|
// Gunakan ini untuk flow browser print yang butuh URL langsung,
|
|
// tapi cache PDP harus tetap dihapus segera setelah PDF di-stream.
|
|
public function stream_by_code()
|
|
{
|
|
if (!$this->isLogin) {
|
|
$this->sys_error('Invalid Token');
|
|
return;
|
|
}
|
|
|
|
$prm = $this->sys_input;
|
|
$report_code = trim($prm['report_code'] ?? $prm['code_report'] ?? $prm['code'] ?? '');
|
|
$order_id = intval($prm['PT_OrderHeaderID'] ?? $prm['order_id'] ?? 0);
|
|
$payment_id = intval($prm['PPaymentID'] ?? $prm['payment_id'] ?? 0);
|
|
$username = trim($prm['PUsername'] ?? ($this->sys_user['M_StaffName'] ?? $this->sys_user['M_UserUsername'] ?? $this->sys_user['userName'] ?? 'system'));
|
|
|
|
if (!$report_code) {
|
|
$this->sys_error('report_code wajib diisi');
|
|
return;
|
|
}
|
|
|
|
if ($order_id <= 0 && $payment_id > 0) {
|
|
$order_id = $this->_resolve_order_id_by_payment($payment_id);
|
|
}
|
|
|
|
if ($order_id <= 0) {
|
|
$this->sys_error('order_id tidak ditemukan');
|
|
return;
|
|
}
|
|
|
|
$cache_id = $this->_populate_cache($order_id);
|
|
$patient_name = $this->_resolve_patient_name_by_cache($cache_id);
|
|
if ($patient_name === '') {
|
|
$patient_name = $this->_resolve_patient_name_by_order($order_id);
|
|
}
|
|
|
|
$row = $this->db_onedev->query(
|
|
"SELECT Print_TransactionUrl FROM print_transaction WHERE Print_TransactionCode = ? LIMIT 1",
|
|
[$report_code]
|
|
)->row_array();
|
|
|
|
if (!$row) {
|
|
$this->_delete_cache($cache_id);
|
|
$this->sys_error("Report code tidak ditemukan: {$report_code}");
|
|
return;
|
|
}
|
|
|
|
$tm = round(microtime(true) * 1000);
|
|
$url = $row['Print_TransactionUrl'];
|
|
$is_internal_app_url = $this->_is_internal_app_url($url);
|
|
$url = str_replace('PT_OrderHeaderID', $order_id, $url);
|
|
$url = str_replace('PPaymentID', $payment_id, $url);
|
|
$url = str_replace('PAn', $this->_format_report_string_param($patient_name, $is_internal_app_url), $url);
|
|
$url = str_replace('PUsername', $this->_format_report_string_param($username, $is_internal_app_url), $url);
|
|
$url = str_replace('TS', $tm, $url);
|
|
|
|
$full_url = $this->_resolve_fetch_url($url);
|
|
$context = stream_context_create([
|
|
'http' => [
|
|
'timeout' => 120,
|
|
'method' => 'GET',
|
|
]
|
|
]);
|
|
|
|
$pdf = @file_get_contents($full_url, false, $context);
|
|
$this->_delete_cache($cache_id);
|
|
|
|
if ($pdf === false) {
|
|
$this->sys_error('Gagal generate report dari BIRT server');
|
|
return;
|
|
}
|
|
|
|
$filename = $report_code . '_' . $order_id . '_' . date('Ymd') . '.pdf';
|
|
header('Content-Type: application/pdf');
|
|
header('Content-Disposition: inline; filename="' . $filename . '"');
|
|
header('Content-Length: ' . strlen($pdf));
|
|
echo $pdf;
|
|
exit;
|
|
}
|
|
|
|
// POST /tools/birt_proxy/stream
|
|
public function stream()
|
|
{
|
|
if (!$this->isLogin) {
|
|
$this->sys_error('Invalid Token');
|
|
return;
|
|
}
|
|
|
|
$prm = $this->sys_input;
|
|
$report_code = $prm['report_code'] ?? '';
|
|
$order_id = intval($prm['PT_OrderHeaderID'] ?? 0);
|
|
$username = $prm['PUsername'] ?? ($this->sys_user['userName'] ?? 'system');
|
|
$tm = round(microtime(true) * 1000);
|
|
|
|
if (!$report_code) {
|
|
$this->sys_error('report_code wajib diisi');
|
|
return;
|
|
}
|
|
|
|
// 1. Ambil URL template dari print_transaction
|
|
$row = $this->db_onedev->query(
|
|
"SELECT Print_TransactionUrl FROM print_transaction WHERE Print_TransactionCode = ? LIMIT 1",
|
|
[$report_code]
|
|
)->row_array();
|
|
|
|
if (!$row) {
|
|
$this->sys_error("Report code tidak ditemukan: {$report_code}");
|
|
return;
|
|
}
|
|
|
|
$url = $row['Print_TransactionUrl'];
|
|
$is_internal_app_url = $this->_is_internal_app_url($url);
|
|
$url = str_replace('PT_OrderHeaderID', $order_id, $url);
|
|
$url = str_replace('PUsername', $this->_format_report_string_param($username, $is_internal_app_url), $url);
|
|
$url = str_replace('TS', $tm, $url);
|
|
|
|
// 2. Decrypt patient PII dan populate cache
|
|
$cache_id = null;
|
|
if ($order_id > 0) {
|
|
$cache_id = $this->_populate_cache($order_id);
|
|
}
|
|
|
|
// 3. Build full URL sesuai target endpoint dan fetch PDF
|
|
$full_url = $this->_resolve_fetch_url($url);
|
|
|
|
$context = stream_context_create([
|
|
'http' => [
|
|
'timeout' => 120,
|
|
'method' => 'GET',
|
|
]
|
|
]);
|
|
|
|
$pdf = @file_get_contents($full_url, false, $context);
|
|
|
|
// 4. Hapus cache
|
|
if ($cache_id) {
|
|
$this->db_onedev->query(
|
|
"DELETE FROM patient_print_cache WHERE ppc_id = ?",
|
|
[$cache_id]
|
|
);
|
|
}
|
|
|
|
if ($pdf === false) {
|
|
$this->sys_error('Gagal generate report dari BIRT server');
|
|
return;
|
|
}
|
|
|
|
// 5. Stream PDF ke frontend
|
|
$filename = $report_code . '_' . $order_id . '_' . date('Ymd') . '.pdf';
|
|
header('Content-Type: application/pdf');
|
|
header('Content-Disposition: inline; filename="' . $filename . '"');
|
|
header('Content-Length: ' . strlen($pdf));
|
|
echo $pdf;
|
|
exit;
|
|
}
|
|
|
|
// Hanya return URL (untuk iframe/window.open) — tanpa stream
|
|
// Frontend membuka URL ini secara langsung
|
|
public function get_url()
|
|
{
|
|
if (!$this->isLogin) {
|
|
$this->sys_error('Invalid Token');
|
|
return;
|
|
}
|
|
|
|
$prm = $this->sys_input;
|
|
$report_code = $prm['report_code'] ?? '';
|
|
$order_id = intval($prm['PT_OrderHeaderID'] ?? 0);
|
|
$username = $prm['PUsername'] ?? ($this->sys_user['userName'] ?? 'system');
|
|
$tm = round(microtime(true) * 1000);
|
|
|
|
$row = $this->db_onedev->query(
|
|
"SELECT Print_TransactionUrl FROM print_transaction WHERE Print_TransactionCode = ? LIMIT 1",
|
|
[$report_code]
|
|
)->row_array();
|
|
|
|
if (!$row) {
|
|
$this->sys_error("Report code tidak ditemukan: {$report_code}");
|
|
return;
|
|
}
|
|
|
|
$url = $row['Print_TransactionUrl'];
|
|
$url = str_replace('PT_OrderHeaderID', $order_id, $url);
|
|
$url = str_replace('PUsername', urlencode($username), $url);
|
|
$url = str_replace('TS', $tm, $url);
|
|
|
|
// Pre-populate cache — frontend buka URL langsung ke BIRT
|
|
// Cache hidup 5 menit, cukup untuk BIRT generate PDF
|
|
if ($order_id > 0) {
|
|
$this->_populate_cache($order_id);
|
|
}
|
|
|
|
$this->sys_ok(['url' => $url]);
|
|
}
|
|
|
|
// Decrypt patient PII dan simpan ke cache
|
|
private function _populate_cache($order_id)
|
|
{
|
|
// Ambil _enc columns dari m_patient via t_orderheader
|
|
$patient = $this->db_onedev->query(
|
|
"SELECT M_PatientID,
|
|
M_PatientName_enc, M_PatientDOB_enc, M_PatientHP_enc,
|
|
M_PatientEmail_enc, M_PatientDOB
|
|
FROM t_orderheader
|
|
JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID
|
|
WHERE T_OrderHeaderID = ? LIMIT 1",
|
|
[$order_id]
|
|
)->row_array();
|
|
|
|
if (!$patient) return null;
|
|
|
|
$addr = $this->db_onedev->query(
|
|
"SELECT M_PatientAddressDescription_enc
|
|
FROM m_patientaddress
|
|
WHERE M_PatientAddressM_PatientID = ?
|
|
AND M_PatientAddressIsActive = 'Y'
|
|
AND M_PatientAddressNote = 'Utama'
|
|
LIMIT 1",
|
|
[$patient['M_PatientID']]
|
|
)->row_array();
|
|
|
|
$enc = $this->ibl_encryptor;
|
|
$name = $enc->decrypt($patient['M_PatientName_enc'] ?? '') ?? '';
|
|
$dob = $enc->decrypt($patient['M_PatientDOB_enc'] ?? '') ?? date('d-m-Y', strtotime($patient['M_PatientDOB'] ?? 'now'));
|
|
$hp = $enc->decrypt($patient['M_PatientHP_enc'] ?? '') ?? '';
|
|
$email= $enc->decrypt($patient['M_PatientEmail_enc']?? '') ?? '';
|
|
$address = $enc->decrypt($addr['M_PatientAddressDescription_enc'] ?? '') ?? '';
|
|
|
|
// Hapus cache lama untuk order ini + cleanup expired
|
|
$this->db_onedev->query(
|
|
"DELETE FROM patient_print_cache WHERE ppc_order_id = ? OR ppc_created < NOW() - INTERVAL 5 MINUTE",
|
|
[$order_id]
|
|
);
|
|
|
|
// Insert cache baru
|
|
$this->db_onedev->query(
|
|
"INSERT INTO patient_print_cache
|
|
(ppc_order_id, ppc_patient_id, ppc_name, ppc_dob, ppc_hp, ppc_email, ppc_address, ppc_created)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())",
|
|
[$order_id, $patient['M_PatientID'], $name, $dob, $hp, $email, $address]
|
|
);
|
|
|
|
return $this->db_onedev->insert_id();
|
|
}
|
|
|
|
private function _delete_cache($cache_id)
|
|
{
|
|
if ($cache_id) {
|
|
$this->db_onedev->query(
|
|
"DELETE FROM patient_print_cache WHERE ppc_id = ?",
|
|
[$cache_id]
|
|
);
|
|
}
|
|
|
|
$this->db_onedev->query(
|
|
"DELETE FROM patient_print_cache WHERE ppc_created < NOW() - INTERVAL 5 MINUTE"
|
|
);
|
|
}
|
|
|
|
private function _resolve_fetch_url($url)
|
|
{
|
|
$url = trim((string) $url);
|
|
|
|
if ($url === '') {
|
|
return '';
|
|
}
|
|
|
|
if (preg_match('#^https?://#i', $url)) {
|
|
return $url;
|
|
}
|
|
|
|
if (strpos($url, '/birt/') === 0) {
|
|
return $this->birt_base . $url;
|
|
}
|
|
|
|
if (strpos($url, '/one-api-lab/') === 0) {
|
|
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
|
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
|
|
|
return $scheme . '://' . $host . $url;
|
|
}
|
|
|
|
if (strpos($url, '/tools/') === 0 || strpos($url, '/index.php/') === 0) {
|
|
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
|
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
|
|
|
return $scheme . '://' . $host . '/one-api-lab' . $url;
|
|
}
|
|
|
|
return $this->birt_base . $url;
|
|
}
|
|
|
|
private function _resolve_order_id_by_payment($payment_id)
|
|
{
|
|
$row = $this->db_onedev->query(
|
|
"SELECT F_PaymentT_OrderHeaderID
|
|
FROM f_payment
|
|
WHERE F_PaymentID = ?
|
|
LIMIT 1",
|
|
[$payment_id]
|
|
)->row_array();
|
|
|
|
return intval($row['F_PaymentT_OrderHeaderID'] ?? 0);
|
|
}
|
|
|
|
private function _resolve_patient_name_by_cache($cache_id)
|
|
{
|
|
if (!$cache_id) {
|
|
return '';
|
|
}
|
|
|
|
$row = $this->db_onedev->query(
|
|
"SELECT ppc_name
|
|
FROM patient_print_cache
|
|
WHERE ppc_id = ?
|
|
LIMIT 1",
|
|
[$cache_id]
|
|
)->row_array();
|
|
|
|
return trim($row['ppc_name'] ?? '');
|
|
}
|
|
|
|
private function _resolve_patient_name_by_order($order_id)
|
|
{
|
|
$row = $this->db_onedev->query(
|
|
"SELECT ppc_name
|
|
FROM patient_print_cache
|
|
WHERE ppc_order_id = ?
|
|
ORDER BY ppc_id DESC
|
|
LIMIT 1",
|
|
[$order_id]
|
|
)->row_array();
|
|
|
|
return trim($row['ppc_name'] ?? '');
|
|
}
|
|
|
|
private function _is_internal_app_url($url)
|
|
{
|
|
$url = (string) $url;
|
|
|
|
return (
|
|
strpos($url, '/one-api-lab/') === 0 ||
|
|
strpos($url, '/tools/') === 0 ||
|
|
strpos($url, '/index.php/') === 0
|
|
);
|
|
}
|
|
|
|
private function _format_report_string_param($value, $is_internal_app_url = false)
|
|
{
|
|
$value = (string) $value;
|
|
|
|
if ($is_internal_app_url) {
|
|
return rawurlencode($value);
|
|
}
|
|
|
|
return rawurlencode("'" . $value . "'");
|
|
}
|
|
}
|