Compare commits

2 Commits

Author SHA1 Message Date
Hanan Askarim
43342bf361 add api poli 2026-06-22 15:00:49 +07:00
Hanan Askarim
cf648ac9ba fix birt proxy 2026-06-17 11:40:27 +07:00
5 changed files with 1594 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
@baseUrl = https://devone.aplikasi.web.id/one-api-lab
@token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJNX1VzZXJJRCI6IjMiLCJNX1VzZXJVc2VybmFtZSI6ImFkbWluICIsIk1fVXNlckdyb3VwRGFzaGJvYXJkIjoib25lLXVpLWxhYlwvdGVzdFwvdnVleFwvb25lLXBhdGllbnQtbGlzdC1iYXJjb2RlLXZ2LTYtY3BvbmVcLyIsIk1fVXNlckRlZmF1bHRUX1NhbXBsZVN0YXRpb25JRCI6IjAiLCJNX1N0YWZmTmFtZSI6IkFCSVRBIEpVV0lUQSBTQVJJIiwiaXNfY291cmllciI6Ik4iLCJ0aW1lX2F1dG9sb2dvdXQiOiIxMDAwMDAwIiwiaXAiOiIxMDMuMy4yMjAuMjIxIiwiYWdlbnQiOiJNb3ppbGxhXC81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXRcLzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZVwvMTQ5LjAuMC4wIFNhZmFyaVwvNTM3LjM2IiwidmVyc2lvbiI6InYyIiwibGFzdC1sb2dpbiI6IjIwMjYtMDYtMjIgMTE6MjM6MjkiLCJNX1NhdGVsbGl0ZUlEIjowfQ.wkQFPGQ52TeceDQARm8auj6jEb159V46BzTZ9NEE_vM
@poliId = 1
### Search Poli
POST {{baseUrl}}/mockup/masterdata/poli/search
Content-Type: application/json
{
"token": "{{token}}",
"search": "",
"page": 1,
"row_per_page": 10,
"order_by": "id",
"order": "asc"
}
### Search Poli By Name
POST {{baseUrl}}/mockup/masterdata/poli/search
Content-Type: application/json
{
"token": "{{token}}",
"search": "khitan",
"page": 1,
"row_per_page": 10,
"order_by": "name",
"order": "asc"
}
### Get Screening Templates
POST {{baseUrl}}/mockup/masterdata/poli/gettemplates
Content-Type: application/json
{
"token": "{{token}}"
}
### Add Poli
POST {{baseUrl}}/mockup/masterdata/poli/add
Content-Type: application/json
{
"token": "{{token}}",
"code": "POLI_TEST",
"name": "Poli Test",
"description": "Poli untuk test API",
"satusehat_location_id": "",
"screening_template_id": null
}
### Update Poli
POST {{baseUrl}}/mockup/masterdata/poli/update
Content-Type: application/json
{
"token": "{{token}}",
"id": {{poliId}},
"code": "POLI_TEST",
"name": "Poli Test Update",
"description": "Poli untuk test API update",
"satusehat_location_id": "",
"screening_template_id": null
}
### Delete Poli
POST {{baseUrl}}/mockup/masterdata/poli/delete
Content-Type: application/json
{
"token": "{{token}}",
"id": {{poliId}}
}

View File

@@ -0,0 +1,323 @@
<?php
class Poli extends MY_Controller
{
var $db_oneklinik;
public function __construct()
{
parent::__construct();
$this->db_oneklinik = $this->load->database("onedev", true);
}
public function index()
{
echo "POLI API";
}
public function search()
{
try {
if (!$this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$prm = $this->sys_input;
$search = isset($prm['search']) ? trim($prm['search']) : (isset($prm['name']) ? trim($prm['name']) : '');
$like = '%' . $search . '%';
$row_per_page = isset($prm['row_per_page']) && intval($prm['row_per_page']) > 0 ? intval($prm['row_per_page']) : 10;
$page = 1;
if (isset($prm['page']) && intval($prm['page']) > 0) {
$page = intval($prm['page']);
} elseif (isset($prm['current_page']) && intval($prm['current_page']) > 0) {
$page = intval($prm['current_page']);
}
$offset = ($page - 1) * $row_per_page;
$allowed_order_by = array(
'id' => 'cu.M_ClinicUnitID',
'code' => 'cu.M_ClinicUnitCode',
'name' => 'cu.M_ClinicUnitName',
'description' => 'cu.M_ClinicUnitDescription',
'screening_template_name' => 'st.M_ScreeningTemplateName'
);
$order_by = 'cu.M_ClinicUnitID';
if (isset($prm['order_by']) && isset($allowed_order_by[$prm['order_by']])) {
$order_by = $allowed_order_by[$prm['order_by']];
}
$order = isset($prm['order']) && strtolower($prm['order']) === 'desc' ? 'DESC' : 'ASC';
$sql_count = "SELECT COUNT(*) AS total
FROM one_klinik.m_clinic_unit cu
LEFT JOIN one_klinik.m_screening_template st
ON st.M_ScreeningTemplateID = cu.M_ClinicUnitM_ScreeningTemplateID
AND st.M_ScreeningTemplateIsActive = 'Y'
WHERE cu.M_ClinicUnitIsActive = 'Y'
AND (
cu.M_ClinicUnitCode LIKE ?
OR cu.M_ClinicUnitName LIKE ?
OR IFNULL(cu.M_ClinicUnitDescription, '') LIKE ?
OR IFNULL(cu.M_ClinicUnitSatusehatLocationID, '') LIKE ?
OR IFNULL(st.M_ScreeningTemplateName, '') LIKE ?
)";
$query_count = $this->db_oneklinik->query($sql_count, array($like, $like, $like, $like, $like));
if (!$query_count) {
$this->sys_error_db("m_clinic_unit count", $this->db_oneklinik);
exit;
}
$total_filter = intval($query_count->row()->total);
$total_page = ceil($total_filter / $row_per_page);
$sql = "SELECT
cu.M_ClinicUnitID AS id,
cu.M_ClinicUnitCode AS code,
cu.M_ClinicUnitName AS name,
cu.M_ClinicUnitDescription AS description,
cu.M_ClinicUnitSatusehatLocationID AS satusehat_location_id,
cu.M_ClinicUnitM_ScreeningTemplateID AS screening_template_id,
st.M_ScreeningTemplateCode AS screening_template_code,
st.M_ScreeningTemplateName AS screening_template_name,
cu.M_ClinicUnitIsActive AS is_active,
cu.M_ClinicUnitCreated AS created,
cu.M_ClinicUnitLastUpdated AS last_updated
FROM one_klinik.m_clinic_unit cu
LEFT JOIN one_klinik.m_screening_template st
ON st.M_ScreeningTemplateID = cu.M_ClinicUnitM_ScreeningTemplateID
AND st.M_ScreeningTemplateIsActive = 'Y'
WHERE cu.M_ClinicUnitIsActive = 'Y'
AND (
cu.M_ClinicUnitCode LIKE ?
OR cu.M_ClinicUnitName LIKE ?
OR IFNULL(cu.M_ClinicUnitDescription, '') LIKE ?
OR IFNULL(cu.M_ClinicUnitSatusehatLocationID, '') LIKE ?
OR IFNULL(st.M_ScreeningTemplateName, '') LIKE ?
)
ORDER BY {$order_by} {$order}
LIMIT ? OFFSET ?";
$query = $this->db_oneklinik->query($sql, array($like, $like, $like, $like, $like, $row_per_page, $offset));
if (!$query) {
$this->sys_error_db("m_clinic_unit select", $this->db_oneklinik);
exit;
}
$rows = $query->result_array();
$this->sys_ok(array(
"total" => $total_page,
"total_filter" => $total_filter,
"records" => $rows
));
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
public function gettemplates()
{
try {
if (!$this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$sql = "SELECT
M_ScreeningTemplateID AS id,
M_ScreeningTemplateCode AS code,
M_ScreeningTemplateName AS name,
M_ScreeningTemplateDescription AS description
FROM one_klinik.m_screening_template
WHERE M_ScreeningTemplateIsActive = 'Y'
ORDER BY M_ScreeningTemplateName ASC";
$query = $this->db_oneklinik->query($sql);
if (!$query) {
$this->sys_error_db("m_screening_template select", $this->db_oneklinik);
exit;
}
$rows = $query->result_array();
$this->sys_ok(array("total" => count($rows), "records" => $rows));
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
public function add()
{
try {
if (!$this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$prm = $this->sys_input;
$code = isset($prm['code']) ? trim($prm['code']) : '';
$name = isset($prm['name']) ? trim($prm['name']) : '';
$description = isset($prm['description']) ? trim($prm['description']) : null;
$satusehat_location_id = isset($prm['satusehat_location_id']) ? trim($prm['satusehat_location_id']) : null;
$screening_template_id = isset($prm['screening_template_id']) && $prm['screening_template_id'] !== '' ? intval($prm['screening_template_id']) : null;
$userid = $this->sys_user["M_UserID"];
if ($code === '' || $name === '') {
$this->sys_error("code and name are mandatory");
exit;
}
$duplicate = $this->db_oneklinik->query(
"SELECT COUNT(*) AS total
FROM one_klinik.m_clinic_unit
WHERE M_ClinicUnitCode = ?
OR (M_ClinicUnitIsActive = 'Y' AND M_ClinicUnitName = ?)",
array($code, $name)
);
if (!$duplicate) {
$this->sys_error_db("m_clinic_unit duplicate check", $this->db_oneklinik);
exit;
}
if (intval($duplicate->row()->total) > 0) {
$this->sys_ok(array(
"total" => -1,
"errors" => array(array("field" => "code", "msg" => "Kode atau nama sudah ada")),
"records" => 0
));
exit;
}
$sql = "INSERT INTO one_klinik.m_clinic_unit (
M_ClinicUnitCode,
M_ClinicUnitName,
M_ClinicUnitDescription,
M_ClinicUnitSatusehatLocationID,
M_ClinicUnitM_ScreeningTemplateID,
M_ClinicUnitUserID,
M_ClinicUnitCreated,
M_ClinicUnitLastUpdated
) VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())";
$query = $this->db_oneklinik->query($sql, array(
$code,
$name,
$description,
$satusehat_location_id,
$screening_template_id,
$userid
));
if (!$query) {
$this->sys_error_db("m_clinic_unit insert", $this->db_oneklinik);
exit;
}
$this->sys_ok(array(
"total" => 1,
"records" => array("xid" => $this->db_oneklinik->insert_id())
));
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
public function update()
{
try {
if (!$this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$prm = $this->sys_input;
$id = isset($prm['id']) ? intval($prm['id']) : 0;
$code = isset($prm['code']) ? trim($prm['code']) : '';
$name = isset($prm['name']) ? trim($prm['name']) : '';
$description = isset($prm['description']) ? trim($prm['description']) : null;
$satusehat_location_id = isset($prm['satusehat_location_id']) ? trim($prm['satusehat_location_id']) : null;
$screening_template_id = isset($prm['screening_template_id']) && $prm['screening_template_id'] !== '' ? intval($prm['screening_template_id']) : null;
$userid = $this->sys_user["M_UserID"];
if (!$id || $code === '' || $name === '') {
$this->sys_error("id, code and name are mandatory");
exit;
}
$duplicate = $this->db_oneklinik->query(
"SELECT COUNT(*) AS total
FROM one_klinik.m_clinic_unit
WHERE M_ClinicUnitID <> ?
AND (M_ClinicUnitCode = ?
OR (M_ClinicUnitIsActive = 'Y' AND M_ClinicUnitName = ?))",
array($id, $code, $name)
);
if (!$duplicate) {
$this->sys_error_db("m_clinic_unit duplicate check", $this->db_oneklinik);
exit;
}
if (intval($duplicate->row()->total) > 0) {
$this->sys_ok(array(
"total" => -1,
"errors" => array(array("field" => "code", "msg" => "Kode atau nama sudah ada")),
"records" => 0
));
exit;
}
$sql = "UPDATE one_klinik.m_clinic_unit SET
M_ClinicUnitCode = ?,
M_ClinicUnitName = ?,
M_ClinicUnitDescription = ?,
M_ClinicUnitSatusehatLocationID = ?,
M_ClinicUnitM_ScreeningTemplateID = ?,
M_ClinicUnitUserID = ?,
M_ClinicUnitLastUpdated = NOW()
WHERE M_ClinicUnitID = ?
AND M_ClinicUnitIsActive = 'Y'";
$query = $this->db_oneklinik->query($sql, array(
$code,
$name,
$description,
$satusehat_location_id,
$screening_template_id,
$userid,
$id
));
if (!$query) {
$this->sys_error_db("m_clinic_unit update", $this->db_oneklinik);
exit;
}
$this->sys_ok(array("total" => 1, "records" => array("xid" => $id)));
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
public function delete()
{
try {
if (!$this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$prm = $this->sys_input;
$id = isset($prm['id']) ? intval($prm['id']) : 0;
if (!$id) {
$this->sys_error("id is mandatory");
exit;
}
$userid = $this->sys_user["M_UserID"];
$sql = "UPDATE one_klinik.m_clinic_unit SET
M_ClinicUnitIsActive = 'N',
M_ClinicUnitUserID = ?,
M_ClinicUnitLastUpdated = NOW()
WHERE M_ClinicUnitID = ?";
$query = $this->db_oneklinik->query($sql, array($userid, $id));
if (!$query) {
$this->sys_error_db("m_clinic_unit delete", $this->db_oneklinik);
exit;
}
$this->sys_ok(array("total" => 1, "records" => array("xid" => $id)));
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
}

View File

@@ -539,6 +539,8 @@ class Birt_proxy extends MY_Controller
$umur = $dob . ' / ' . ($row['T_OrderHeaderM_PatientAge'] ?? '');
$this->_populate_cache($order_id);
$data = [
'T_OrderHeaderDate' => $row['T_OrderHeaderDate'] ?? '',
'T_OrderHeaderLabNumber' => $row['T_OrderHeaderLabNumber'] ?? '',

View File

@@ -0,0 +1,598 @@
<?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
{
public $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);
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 ($payment_id <= 0 && $order_id > 0) {
$payment_id = $this->_resolve_payment_id_by_order($order_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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name);
if ($url === false) {
$this->_delete_cache($cache_id);
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$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);
$payment_id = intval($prm['PPaymentID'] ?? 0);
if (!$report_code) {
$this->sys_error('report_code wajib diisi');
return;
}
if ($payment_id <= 0 && $order_id > 0) {
$payment_id = $this->_resolve_payment_id_by_order($order_id);
}
$patient_name = '';
if ($order_id > 0) {
$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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
} else {
$cache_id = null;
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name);
if ($url === false) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$full_url = $this->_resolve_fetch_url($url);
$context = stream_context_create([
'http' => [
'timeout' => 120,
'method' => 'GET',
]
]);
$pdf = @file_get_contents($full_url, false, $context);
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;
}
$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);
$patient_name = '';
if ($order_id > 0) {
$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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, 0, $patient_name);
if ($url === false) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$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_payment_id_by_order($order_id)
{
$row = $this->db_onedev->query(
"SELECT F_PaymentID
FROM f_payment
WHERE F_PaymentT_OrderHeaderID = ?
ORDER BY F_PaymentID DESC
LIMIT 1",
[$order_id]
)->row_array();
return intval($row['F_PaymentID'] ?? 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 _resolve_patient_name_from_enc_by_order($order_id)
{
$row = $this->db_onedev->query(
"SELECT M_PatientName_enc
FROM t_orderheader
JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID
WHERE T_OrderHeaderID = ?
LIMIT 1",
[$order_id]
)->row_array();
return trim($this->ibl_encryptor->decrypt($row['M_PatientName_enc'] ?? '') ?? '');
}
private function _resolve_report_username()
{
if (!empty($this->sys_user['M_StaffName'])) {
return trim($this->sys_user['M_StaffName']);
}
if (!empty($this->sys_user['M_UserUsername'])) {
return trim($this->sys_user['M_UserUsername']);
}
if (!empty($this->sys_user['userName'])) {
return trim($this->sys_user['userName']);
}
return 'ADMIN';
}
private function _build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name)
{
$row = $this->db_onedev->query(
"SELECT Print_TransactionUrl
FROM print_transaction
WHERE Print_TransactionCode = ?
LIMIT 1",
[$report_code]
)->row_array();
if (!$row) {
return false;
}
$url_template = $this->_apply_report_template_hotfix($report_code, $row['Print_TransactionUrl']);
$username = $this->_resolve_report_username();
$tm = round(microtime(true) * 1000);
$resolved_payment_id = $payment_id > 0 ? $payment_id : $this->_resolve_payment_id_by_order($order_id);
$is_internal_app_url = $this->_is_internal_app_url($url_template);
$replacements = [
'PUsername' => $this->_format_report_string_param($username, $is_internal_app_url),
'PT_OrderHeaderID' => $order_id,
'PPaymentID' => $resolved_payment_id,
'PAn' => $this->_format_report_string_param($patient_name, $is_internal_app_url),
'TS' => $tm,
];
$url = $url_template;
foreach ($replacements as $placeholder => $value) {
if ($value === null) {
$value = '';
}
$url = str_replace($placeholder, $value, $url);
}
return $url;
}
private function _apply_report_template_hotfix($report_code, $url_template)
{
$print_report_hotfix = [
'LAB-RESULT-P-01' => [
'from' => 'rpt_test.rptdesign',
'to' => 'rpt_test_bkp020626.rptdesign',
],
'MIKROO-RESULT-P-01' => [
'from' => 'rpt_test.rptdesign',
'to' => 'rpt_test_bkp020626.rptdesign',
],
];
if (!isset($print_report_hotfix[$report_code])) {
return $url_template;
}
$hotfix = $print_report_hotfix[$report_code];
$resolved_url = str_replace($hotfix['from'], $hotfix['to'], $url_template);
if (strpos($resolved_url, 'username=') === false) {
$resolved_url .= (strpos($resolved_url, '?') === false ? '?' : '&') . 'username=PUsername';
}
return $resolved_url;
}
// GET /tools/birt_proxy/header_json?PID=<order_id>
// Hanya bisa diakses dari localhost (127.0.0.1) — dipanggil oleh BIRT scripted dataset
// Return JSON semua kolom sp_rpt_hasil_header, PII sudah di-decrypt
public function header_json()
{
$order_id = intval($this->input->get('PID') ?? 0);
if ($order_id <= 0) {
echo json_encode(['error' => 'PID required']);
exit;
}
$row = $this->db_onedev->query("
SELECT
DATE_FORMAT(T_OrderHeaderDate, '%d-%m-%Y') AS T_OrderHeaderDate,
T_OrderHeaderLabNumber,
M_TitleName,
M_PatientName,
M_PatientName_enc,
m_sexname AS Gender,
M_PatientNoReg,
M_PatientDOB,
M_PatientDOB_enc,
T_OrderHeaderM_PatientAge,
M_CompanyName AS CorporateName,
M_PatientHp,
M_PatientHP_enc,
M_PatientEmail,
M_PatientEmail_enc,
'' AS M_PatientAddressCity,
'' AS M_PatientAddressState,
M_CompanyName AS CorporateAddress,
M_CompanyEmail AS CorporateEmail,
M_CompanyPhone AS CorporatePhone,
M_CompanyAddressCity AS CorporateAddressCity,
'' AS CorporateAddressState,
TRIM(CONCAT(IFNULL(pj.M_DoctorPrefix,''),' ',IFNULL(pj.M_DoctorPrefix2,''),' ',IFNULL(pj.M_DoctorName,''),' ',IFNULL(pj.M_DoctorSufix,''),' ',IFNULL(pj.M_DoctorSufix2,''))) AS M_DoctorName,
TRIM(CONCAT(IFNULL(pjj.M_DoctorPrefix,''),' ',IFNULL(pjj.M_DoctorPrefix2,''),' ',IFNULL(pjj.M_DoctorName,''),' ',IFNULL(pjj.M_DoctorSufix,''),' ',IFNULL(pjj.M_DoctorSufix2,''))) AS M_DoctorName2,
M_PatientID,
M_PatientNIP, M_PatientJob, M_PatientPosisi, M_PatientDivisi, M_PatientLocation,
CONCAT(IFNULL(M_PatientDepartement,''),' - ',IFNULL(M_PatientNIP,'')) AS M_PatientDepartement
FROM t_orderheader
LEFT JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID AND M_PatientIsActive = 'Y'
LEFT JOIN m_sex ON M_PatientM_SexID = M_SexID
LEFT JOIN m_title ON M_PatientM_TitleID = M_TitleID AND M_TitleIsActive = 'Y'
JOIN m_company ON T_OrderHeaderM_CompanyID = M_CompanyID AND M_CompanyIsActive = 'Y'
LEFT JOIN m_doctor pjj ON T_OrderHeaderPj2M_DoctorID = pjj.M_DoctorID AND pjj.M_DoctorIsActive = 'Y'
LEFT JOIN m_doctor pj ON T_OrderHeaderPjM_DoctorID = pj.M_DoctorID AND pj.M_DoctorIsActive = 'Y'
WHERE T_OrderHeaderID = ? AND T_OrderHeaderIsActive = 'Y'
", [$order_id])->row_array();
if (!$row) {
echo json_encode(['error' => 'order not found']);
exit;
}
$enc = $this->ibl_encryptor;
$name = $enc->decrypt($row['M_PatientName_enc'] ?? '') ?: ($row['M_PatientName'] ?? '');
$dob = $enc->decrypt($row['M_PatientDOB_enc'] ?? '') ?: date('d-m-Y', strtotime($row['M_PatientDOB'] ?? 'now'));
$hp = $enc->decrypt($row['M_PatientHP_enc'] ?? '') ?: ($row['M_PatientHp'] ?? '');
$email= $enc->decrypt($row['M_PatientEmail_enc']?? '') ?: ($row['M_PatientEmail'] ?? '');
$addr_row = $this->db_onedev->query("
SELECT CONCAT(
IFNULL(M_PatientAddressDescription,''),' ',
IFNULL((SELECT regional_nm FROM regional WHERE regional_cd = NULLIF(TRIM(M_PatientAddressRegionalCd),'') LIMIT 1),'')
) AS addr,
M_PatientAddressDescription_enc
FROM m_patientaddress
WHERE M_PatientAddressM_PatientID = ? AND M_PatientAddressIsActive = 'Y'
ORDER BY M_PatientAddressID LIMIT 1
", [$row['M_PatientID']])->row_array();
$address = '';
if ($addr_row) {
$address = $enc->decrypt($addr_row['M_PatientAddressDescription_enc'] ?? '') ?: trim($addr_row['addr'] ?? '');
}
$umur = $dob . ' / ' . ($row['T_OrderHeaderM_PatientAge'] ?? '');
$data = [
'T_OrderHeaderDate' => $row['T_OrderHeaderDate'] ?? '',
'T_OrderHeaderLabNumber' => $row['T_OrderHeaderLabNumber'] ?? '',
'M_PatientName' => trim(($row['M_TitleName'] ?? '') . '. ' . $name),
'Gender' => $row['Gender'] ?? '',
'M_PatientNoReg' => $row['M_PatientNoReg'] ?? '',
'M_PatientDOB' => $dob,
'T_OrderHeaderM_PatientAge' => $row['T_OrderHeaderM_PatientAge'] ?? '',
'CorporateName' => $row['CorporateName'] ?? '',
'M_PatientAddress' => $address,
'M_PatientHp' => $hp,
'M_PatientEmail' => $email,
'M_PatientAddressCity' => '',
'M_PatientAddressState' => '',
'CorporateAddress' => $row['CorporateAddress'] ?? '',
'CorporateEmail' => $row['CorporateEmail'] ?? '',
'CorporatePhone' => $row['CorporatePhone'] ?? '',
'CorporateAddressCity' => $row['CorporateAddressCity'] ?? '',
'CorporateAddressState' => '',
'M_DoctorName' => $row['M_DoctorName'] ?? '',
'M_DoctorName2' => $row['M_DoctorName2'] ?? '',
'Umur' => $umur,
'M_PatientNIP' => $row['M_PatientNIP'] ?? '',
'M_PatientJob' => $row['M_PatientJob'] ?? '',
'M_PatientPosisi' => $row['M_PatientPosisi'] ?? '',
'M_PatientDivisi' => $row['M_PatientDivisi'] ?? '',
'M_PatientLocation' => $row['M_PatientLocation'] ?? '',
'M_PatientDepartement' => $row['M_PatientDepartement'] ?? '',
];
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
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 . "'");
}
}

View File

@@ -0,0 +1,598 @@
<?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
{
public $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);
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 ($payment_id <= 0 && $order_id > 0) {
$payment_id = $this->_resolve_payment_id_by_order($order_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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name);
if ($url === false) {
$this->_delete_cache($cache_id);
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$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);
$payment_id = intval($prm['PPaymentID'] ?? 0);
if (!$report_code) {
$this->sys_error('report_code wajib diisi');
return;
}
if ($payment_id <= 0 && $order_id > 0) {
$payment_id = $this->_resolve_payment_id_by_order($order_id);
}
$patient_name = '';
if ($order_id > 0) {
$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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
} else {
$cache_id = null;
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name);
if ($url === false) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$full_url = $this->_resolve_fetch_url($url);
$context = stream_context_create([
'http' => [
'timeout' => 120,
'method' => 'GET',
]
]);
$pdf = @file_get_contents($full_url, false, $context);
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;
}
$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);
$patient_name = '';
if ($order_id > 0) {
$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);
}
if ($patient_name === '') {
$patient_name = $this->_resolve_patient_name_from_enc_by_order($order_id);
}
}
$url = $this->_build_birt_url_by_code($report_code, $order_id, 0, $patient_name);
if ($url === false) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$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_payment_id_by_order($order_id)
{
$row = $this->db_onedev->query(
"SELECT F_PaymentID
FROM f_payment
WHERE F_PaymentT_OrderHeaderID = ?
ORDER BY F_PaymentID DESC
LIMIT 1",
[$order_id]
)->row_array();
return intval($row['F_PaymentID'] ?? 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 _resolve_patient_name_from_enc_by_order($order_id)
{
$row = $this->db_onedev->query(
"SELECT M_PatientName_enc
FROM t_orderheader
JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID
WHERE T_OrderHeaderID = ?
LIMIT 1",
[$order_id]
)->row_array();
return trim($this->ibl_encryptor->decrypt($row['M_PatientName_enc'] ?? '') ?? '');
}
private function _resolve_report_username()
{
if (!empty($this->sys_user['M_StaffName'])) {
return trim($this->sys_user['M_StaffName']);
}
if (!empty($this->sys_user['M_UserUsername'])) {
return trim($this->sys_user['M_UserUsername']);
}
if (!empty($this->sys_user['userName'])) {
return trim($this->sys_user['userName']);
}
return 'ADMIN';
}
private function _build_birt_url_by_code($report_code, $order_id, $payment_id, $patient_name)
{
$row = $this->db_onedev->query(
"SELECT Print_TransactionUrl
FROM print_transaction
WHERE Print_TransactionCode = ?
LIMIT 1",
[$report_code]
)->row_array();
if (!$row) {
return false;
}
$url_template = $this->_apply_report_template_hotfix($report_code, $row['Print_TransactionUrl']);
$username = $this->_resolve_report_username();
$tm = round(microtime(true) * 1000);
$resolved_payment_id = $payment_id > 0 ? $payment_id : $this->_resolve_payment_id_by_order($order_id);
$is_internal_app_url = $this->_is_internal_app_url($url_template);
$replacements = [
'PUsername' => $this->_format_report_string_param($username, $is_internal_app_url),
'PT_OrderHeaderID' => $order_id,
'PPaymentID' => $resolved_payment_id,
'PAn' => $this->_format_report_string_param($patient_name, $is_internal_app_url),
'TS' => $tm,
];
$url = $url_template;
foreach ($replacements as $placeholder => $value) {
if ($value === null) {
$value = '';
}
$url = str_replace($placeholder, $value, $url);
}
return $url;
}
private function _apply_report_template_hotfix($report_code, $url_template)
{
$print_report_hotfix = [
'LAB-RESULT-P-01' => [
'from' => 'rpt_test.rptdesign',
'to' => 'rpt_test_bkp020626.rptdesign',
],
'MIKROO-RESULT-P-01' => [
'from' => 'rpt_test.rptdesign',
'to' => 'rpt_test_bkp020626.rptdesign',
],
];
if (!isset($print_report_hotfix[$report_code])) {
return $url_template;
}
$hotfix = $print_report_hotfix[$report_code];
$resolved_url = str_replace($hotfix['from'], $hotfix['to'], $url_template);
if (strpos($resolved_url, 'username=') === false) {
$resolved_url .= (strpos($resolved_url, '?') === false ? '?' : '&') . 'username=PUsername';
}
return $resolved_url;
}
// GET /tools/birt_proxy/header_json?PID=<order_id>
// Hanya bisa diakses dari localhost (127.0.0.1) — dipanggil oleh BIRT scripted dataset
// Return JSON semua kolom sp_rpt_hasil_header, PII sudah di-decrypt
public function header_json()
{
$order_id = intval($this->input->get('PID') ?? 0);
if ($order_id <= 0) {
echo json_encode(['error' => 'PID required']);
exit;
}
$row = $this->db_onedev->query("
SELECT
DATE_FORMAT(T_OrderHeaderDate, '%d-%m-%Y') AS T_OrderHeaderDate,
T_OrderHeaderLabNumber,
M_TitleName,
M_PatientName,
M_PatientName_enc,
m_sexname AS Gender,
M_PatientNoReg,
M_PatientDOB,
M_PatientDOB_enc,
T_OrderHeaderM_PatientAge,
M_CompanyName AS CorporateName,
M_PatientHp,
M_PatientHP_enc,
M_PatientEmail,
M_PatientEmail_enc,
'' AS M_PatientAddressCity,
'' AS M_PatientAddressState,
M_CompanyName AS CorporateAddress,
M_CompanyEmail AS CorporateEmail,
M_CompanyPhone AS CorporatePhone,
M_CompanyAddressCity AS CorporateAddressCity,
'' AS CorporateAddressState,
TRIM(CONCAT(IFNULL(pj.M_DoctorPrefix,''),' ',IFNULL(pj.M_DoctorPrefix2,''),' ',IFNULL(pj.M_DoctorName,''),' ',IFNULL(pj.M_DoctorSufix,''),' ',IFNULL(pj.M_DoctorSufix2,''))) AS M_DoctorName,
TRIM(CONCAT(IFNULL(pjj.M_DoctorPrefix,''),' ',IFNULL(pjj.M_DoctorPrefix2,''),' ',IFNULL(pjj.M_DoctorName,''),' ',IFNULL(pjj.M_DoctorSufix,''),' ',IFNULL(pjj.M_DoctorSufix2,''))) AS M_DoctorName2,
M_PatientID,
M_PatientNIP, M_PatientJob, M_PatientPosisi, M_PatientDivisi, M_PatientLocation,
CONCAT(IFNULL(M_PatientDepartement,''),' - ',IFNULL(M_PatientNIP,'')) AS M_PatientDepartement
FROM t_orderheader
LEFT JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID AND M_PatientIsActive = 'Y'
LEFT JOIN m_sex ON M_PatientM_SexID = M_SexID
LEFT JOIN m_title ON M_PatientM_TitleID = M_TitleID AND M_TitleIsActive = 'Y'
JOIN m_company ON T_OrderHeaderM_CompanyID = M_CompanyID AND M_CompanyIsActive = 'Y'
LEFT JOIN m_doctor pjj ON T_OrderHeaderPj2M_DoctorID = pjj.M_DoctorID AND pjj.M_DoctorIsActive = 'Y'
LEFT JOIN m_doctor pj ON T_OrderHeaderPjM_DoctorID = pj.M_DoctorID AND pj.M_DoctorIsActive = 'Y'
WHERE T_OrderHeaderID = ? AND T_OrderHeaderIsActive = 'Y'
", [$order_id])->row_array();
if (!$row) {
echo json_encode(['error' => 'order not found']);
exit;
}
$enc = $this->ibl_encryptor;
$name = $enc->decrypt($row['M_PatientName_enc'] ?? '') ?: ($row['M_PatientName'] ?? '');
$dob = $enc->decrypt($row['M_PatientDOB_enc'] ?? '') ?: date('d-m-Y', strtotime($row['M_PatientDOB'] ?? 'now'));
$hp = $enc->decrypt($row['M_PatientHP_enc'] ?? '') ?: ($row['M_PatientHp'] ?? '');
$email= $enc->decrypt($row['M_PatientEmail_enc']?? '') ?: ($row['M_PatientEmail'] ?? '');
$addr_row = $this->db_onedev->query("
SELECT CONCAT(
IFNULL(M_PatientAddressDescription,''),' ',
IFNULL((SELECT regional_nm FROM regional WHERE regional_cd = NULLIF(TRIM(M_PatientAddressRegionalCd),'') LIMIT 1),'')
) AS addr,
M_PatientAddressDescription_enc
FROM m_patientaddress
WHERE M_PatientAddressM_PatientID = ? AND M_PatientAddressIsActive = 'Y'
ORDER BY M_PatientAddressID LIMIT 1
", [$row['M_PatientID']])->row_array();
$address = '';
if ($addr_row) {
$address = $enc->decrypt($addr_row['M_PatientAddressDescription_enc'] ?? '') ?: trim($addr_row['addr'] ?? '');
}
$umur = $dob . ' / ' . ($row['T_OrderHeaderM_PatientAge'] ?? '');
$data = [
'T_OrderHeaderDate' => $row['T_OrderHeaderDate'] ?? '',
'T_OrderHeaderLabNumber' => $row['T_OrderHeaderLabNumber'] ?? '',
'M_PatientName' => trim(($row['M_TitleName'] ?? '') . '. ' . $name),
'Gender' => $row['Gender'] ?? '',
'M_PatientNoReg' => $row['M_PatientNoReg'] ?? '',
'M_PatientDOB' => $dob,
'T_OrderHeaderM_PatientAge' => $row['T_OrderHeaderM_PatientAge'] ?? '',
'CorporateName' => $row['CorporateName'] ?? '',
'M_PatientAddress' => $address,
'M_PatientHp' => $hp,
'M_PatientEmail' => $email,
'M_PatientAddressCity' => '',
'M_PatientAddressState' => '',
'CorporateAddress' => $row['CorporateAddress'] ?? '',
'CorporateEmail' => $row['CorporateEmail'] ?? '',
'CorporatePhone' => $row['CorporatePhone'] ?? '',
'CorporateAddressCity' => $row['CorporateAddressCity'] ?? '',
'CorporateAddressState' => '',
'M_DoctorName' => $row['M_DoctorName'] ?? '',
'M_DoctorName2' => $row['M_DoctorName2'] ?? '',
'Umur' => $umur,
'M_PatientNIP' => $row['M_PatientNIP'] ?? '',
'M_PatientJob' => $row['M_PatientJob'] ?? '',
'M_PatientPosisi' => $row['M_PatientPosisi'] ?? '',
'M_PatientDivisi' => $row['M_PatientDivisi'] ?? '',
'M_PatientLocation' => $row['M_PatientLocation'] ?? '',
'M_PatientDepartement' => $row['M_PatientDepartement'] ?? '',
];
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
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 . "'");
}
}