- Ibl_patient_decrypt: tambah fetch_birt_pdf() + pre_cache_and_get_url() - Reporturl.php: auto pre-cache sebelum return URL atau fetch PDF - Rv_patient.php: pre_cache sebelum return URL ke frontend - tgram/Hasil.php: fetch_birt_pdf() via dl_report() - Qr_report_uploader.php: populate/delete cache wrapping download_file() - Ibl_merge_report_gateway.php: populate/delete cache wrapping Go merge service call - send_email.php: populate_birt_cache() + delete_birt_cache() untuk email attachment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
266 lines
8.3 KiB
PHP
266 lines
8.3 KiB
PHP
<?php
|
|
|
|
class Qr_report_uploader extends MY_Controller
|
|
{
|
|
var $db_onedev;
|
|
var $db_log;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->load->library('ibl_patient_decrypt');
|
|
$this->db_onedev = $this->load->database('onedev', true);
|
|
$this->db_log = $this->load->database('one_lab_log', true);
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
echo "QR report uploader tool";
|
|
}
|
|
|
|
public function run($limit = 10)
|
|
{
|
|
$limit = (int)$limit;
|
|
if ($limit <= 0) {
|
|
$limit = 10;
|
|
}
|
|
|
|
$endpointUrl = $this->get_active_endpoint_url();
|
|
if ($endpointUrl === '') {
|
|
$this->reply_result([
|
|
'status' => 'ERR',
|
|
'message' => 'QR_ReportEndpointUrl aktif tidak ditemukan.',
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$rows = $this->get_pending_rows($limit);
|
|
$summary = [
|
|
'endpoint_url' => $endpointUrl,
|
|
'limit' => $limit,
|
|
'total_pending' => count($rows),
|
|
'uploaded' => 0,
|
|
'failed' => 0,
|
|
'failed_permanent' => 0,
|
|
'skipped' => 0,
|
|
'details' => [],
|
|
];
|
|
|
|
foreach ($rows as $row) {
|
|
$result = $this->process_row($row, $endpointUrl);
|
|
$summary['details'][] = $result;
|
|
|
|
if ($result['status'] === 'uploaded') {
|
|
$summary['uploaded']++;
|
|
} elseif ($result['status'] === 'failed') {
|
|
$summary['failed']++;
|
|
} elseif ($result['status'] === 'failed_permanent') {
|
|
$summary['failed_permanent']++;
|
|
} else {
|
|
$summary['skipped']++;
|
|
}
|
|
}
|
|
|
|
$this->reply_result([
|
|
'status' => 'OK',
|
|
'data' => $summary,
|
|
]);
|
|
}
|
|
|
|
private function get_pending_rows($limit)
|
|
{
|
|
$sql = "SELECT QR_PrintOutID,
|
|
QR_PrintOutT_OrderHeaderID,
|
|
QR_PrintOutUUID,
|
|
QR_PrintOutVerifyURL,
|
|
QR_PrintOutReportURL,
|
|
QR_PrintOutUploadStatus,
|
|
QR_PrintOutRetryCount
|
|
FROM qr_printout
|
|
WHERE QR_PrintOutIsActive = 1
|
|
AND (QR_PrintOutUploadStatus = 'pending' OR QR_PrintOutUploadStatus = 'failed')
|
|
AND QR_PrintOutRetryCount < 3
|
|
AND QR_PrintOutReportURL IS NOT NULL
|
|
AND QR_PrintOutReportURL != ''
|
|
ORDER BY QR_PrintOutCreatedAt ASC
|
|
LIMIT ?";
|
|
$qry = $this->db_onedev->query($sql, [$limit]);
|
|
if (!$qry) {
|
|
$this->reply_result([
|
|
'status' => 'ERR',
|
|
'message' => 'Gagal mengambil daftar pending.',
|
|
'db_error' => $this->db_onedev->error(),
|
|
]);
|
|
exit;
|
|
}
|
|
return $qry->result_array();
|
|
}
|
|
|
|
private function get_active_endpoint_url()
|
|
{
|
|
$sql = "SELECT QR_ReportEndpointUrl
|
|
FROM qr_report_endpoint
|
|
WHERE QR_ReportEndpointIsActive = 'Y'
|
|
LIMIT 1";
|
|
$qry = $this->db_onedev->query($sql);
|
|
if (!$qry) {
|
|
return '';
|
|
}
|
|
|
|
$row = $qry->row_array();
|
|
if (!$row || empty($row['QR_ReportEndpointUrl'])) {
|
|
return '';
|
|
}
|
|
|
|
return rtrim($row['QR_ReportEndpointUrl'], '/') . '/';
|
|
}
|
|
|
|
private function process_row($row, $endpointUrl)
|
|
{
|
|
$printoutID = (int)$row['QR_PrintOutID'];
|
|
$orderHeaderID = (int)$row['QR_PrintOutT_OrderHeaderID'];
|
|
$reportUrl = $row['QR_PrintOutReportURL'];
|
|
|
|
// Populate cache sebelum fetch dari BIRT
|
|
$cache_id = $this->ibl_patient_decrypt->populate_cache_by_order($orderHeaderID);
|
|
$pdfContent = $this->download_file($reportUrl);
|
|
$this->ibl_patient_decrypt->delete_cache($cache_id);
|
|
|
|
if ($pdfContent === false) {
|
|
return $this->mark_failed($row, $orderHeaderID, '', 'DOWNLOAD_FAILED');
|
|
}
|
|
|
|
if (strpos($pdfContent, '%PDF') === false) {
|
|
return $this->mark_failed($row, $orderHeaderID, '', 'INVALID_PDF');
|
|
}
|
|
|
|
$payload = json_encode([
|
|
'qrcode' => $row['QR_PrintOutUUID'],
|
|
'url' => $row['QR_PrintOutReportURL'],
|
|
'type' => 'pdf',
|
|
'name' => $row['QR_PrintOutUUID'] . '.pdf',
|
|
'base64_file' => base64_encode($pdfContent),
|
|
], JSON_UNESCAPED_SLASHES);
|
|
|
|
$response = $this->post_json($endpointUrl . 'upload', $payload, "secure-token-libCBxciByZXBvcnQ=");
|
|
$decoded = json_decode($response, true);
|
|
|
|
if (is_array($decoded) && isset($decoded['status']) && $decoded['status'] === 'OK') {
|
|
$this->log_insert_qr($printoutID, $orderHeaderID, $payload, $response);
|
|
$this->db_onedev->query(
|
|
"UPDATE qr_printout
|
|
SET QR_PrintOutUploadStatus = 'uploaded',
|
|
QR_PrintOutUploadedAt = NOW()
|
|
WHERE QR_PrintOutID = ?",
|
|
[$printoutID]
|
|
);
|
|
|
|
return [
|
|
'printout_id' => $printoutID,
|
|
'order_header_id' => $orderHeaderID,
|
|
'status' => 'uploaded',
|
|
'message' => 'Upload berhasil',
|
|
];
|
|
}
|
|
|
|
return $this->mark_failed($row, $orderHeaderID, $payload, $response);
|
|
}
|
|
|
|
private function mark_failed($row, $orderHeaderID, $payload, $response)
|
|
{
|
|
$printoutID = (int)$row['QR_PrintOutID'];
|
|
$retry = (int)$row['QR_PrintOutRetryCount'] + 1;
|
|
$newStatus = $retry >= 3 ? 'failed_permanent' : 'failed';
|
|
|
|
if ($payload !== '' || $response !== '') {
|
|
$this->log_insert_qr($printoutID, $orderHeaderID, $payload, $response);
|
|
}
|
|
|
|
$this->db_onedev->query(
|
|
"UPDATE qr_printout
|
|
SET QR_PrintOutUploadStatus = ?,
|
|
QR_PrintOutRetryCount = ?,
|
|
QR_PrintOutLastRetryAt = NOW()
|
|
WHERE QR_PrintOutID = ?",
|
|
[$newStatus, $retry, $printoutID]
|
|
);
|
|
|
|
return [
|
|
'printout_id' => $printoutID,
|
|
'order_header_id' => $orderHeaderID,
|
|
'status' => $newStatus,
|
|
'message' => is_string($response) ? $response : 'Upload gagal',
|
|
];
|
|
}
|
|
|
|
private function log_insert_qr($printoutID, $orderHeaderID, $json, $response)
|
|
{
|
|
$sql = "INSERT INTO one_lab_log.log_qr_printout(
|
|
Log_QR_PrintOutQR_PrintOutID,
|
|
Log_QR_PrintOutT_OrderHeaderID,
|
|
Log_QR_PrintOutJSON,
|
|
Log_QR_PrintOutResponse,
|
|
Log_QR_PrintOutDateTime
|
|
) VALUES(?,?,?,?,NOW())";
|
|
$this->db_onedev->query($sql, [
|
|
$printoutID,
|
|
$orderHeaderID,
|
|
$json,
|
|
$response,
|
|
]);
|
|
}
|
|
|
|
private function post_json($url, $data, $token)
|
|
{
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/json',
|
|
'Content-Length: ' . strlen($data),
|
|
"Authorization: Bearer {$token}",
|
|
]);
|
|
$result = curl_exec($ch);
|
|
|
|
if (curl_error($ch) !== '') {
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
return "ERROR API [{$url}] : {$error}";
|
|
}
|
|
|
|
curl_close($ch);
|
|
return $result;
|
|
}
|
|
|
|
private function download_file($url)
|
|
{
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
|
|
$result = curl_exec($ch);
|
|
if (curl_error($ch)) {
|
|
curl_close($ch);
|
|
return false;
|
|
}
|
|
|
|
curl_close($ch);
|
|
return $result;
|
|
}
|
|
|
|
private function reply_result($result)
|
|
{
|
|
if ($this->input->is_cli_request()) {
|
|
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
|
|
return;
|
|
}
|
|
|
|
echo json_encode($result);
|
|
}
|
|
}
|