576 lines
16 KiB
PHP
576 lines
16 KiB
PHP
<?php
|
|
class Satu_sehat
|
|
{
|
|
var $base_url, $base_consent_url, $base_oauth_url;
|
|
var $is_staging, $organizationID;
|
|
var $key, $secret;
|
|
var $tz;
|
|
var $db, $dbname;
|
|
function __construct()
|
|
{
|
|
$this->tz = "+07:00";
|
|
$this->is_staging = false;
|
|
$this->base_url = "https://api-satusehat.kemkes.go.id/fhir-r4/v1";
|
|
$this->base_oauth_url = "https://api-satusehat.kemkes.go.id/oauth2/v1";
|
|
$this->base_consent_url = "https://api-satusehat.dto.kemkes.go.id/consent/v1";
|
|
$CI = &get_instance();
|
|
$this->db = $CI->load->database("default", true);
|
|
|
|
$this->dbname = "one_health";
|
|
if ($this->is_staging) {
|
|
$this->base_url = "https://api-satusehat-stg.kemkes.go.id/fhir-r4/v1";
|
|
$this->base_oauth_url = "https://api-satusehat-stg.kemkes.go.id/oauth2/v1";
|
|
$this->base_consent_url = "https://api-satusehat-stg.dto.kemkes.go.id/consent/v1";
|
|
$this->dbname = "one_health_dev";
|
|
}
|
|
$this->get_organization_id();
|
|
}
|
|
|
|
function ss_organization()
|
|
{
|
|
$this->get_organization_id();
|
|
$o_resp = $this->ss_get("/Organization/{$this->organizationID}");
|
|
$resp = $this->objToArray($o_resp);
|
|
$id = $resp["id"];
|
|
$name = $resp["name"];
|
|
$x_type = $resp["type"][0]["coding"][0];
|
|
$type = $x_type["display"];
|
|
$code = $x_type["code"];
|
|
$system = $x_type["system"];
|
|
return json_encode([
|
|
"ID" => $id,
|
|
"Name" => $name,
|
|
"Type" => $type,
|
|
"CodeSystem" => $code . " | " . $system,
|
|
]);
|
|
}
|
|
|
|
function search_practicioner_by_nik($nik, $debug = "")
|
|
{
|
|
$service = "/Practitioner?identifier=https://fhir.kemkes.go.id/id/nik|" . $nik;
|
|
$o_resp = $this->ss_get($service, $debug);
|
|
$resp = $this->objToArray($o_resp);
|
|
if (count($resp["entry"]) > 0) {
|
|
$rs = $resp["entry"][0]["resource"];
|
|
return json_encode([
|
|
"status" => "OK",
|
|
"ihsID" => $rs["id"],
|
|
"name" => $rs["name"][0]["text"]
|
|
]);
|
|
}
|
|
return json_encode([
|
|
"status" => "ERR",
|
|
"message" => "Practitioner not found [$nik]"
|
|
]);
|
|
}
|
|
|
|
function search_patient_by_nik($nik, $debug = "")
|
|
{
|
|
$service = "/Patient?identifier=https://fhir.kemkes.go.id/id/nik|" . $nik;
|
|
$resp = $this->ss_get($service);
|
|
if ($debug != "") {
|
|
echo "resp : ";
|
|
print_r($resp);
|
|
}
|
|
$a_resp = $this->objToArray($resp);
|
|
if (isset($a_resp["entry"][0]["resource"]["id"])) {
|
|
return $a_resp["entry"][0]["resource"]["id"];
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function location_by_organization($organizationIhsID, $debug = "")
|
|
{
|
|
$service = "/Location?organization=" . $organizationIhsID;
|
|
$resp = $this->ss_get($service);
|
|
if ($debug != "") {
|
|
echo "resp : ";
|
|
print_r($resp);
|
|
}
|
|
$a_resp = $this->objToArray($resp);
|
|
return $a_resp;
|
|
}
|
|
|
|
function location_create(
|
|
$code,
|
|
$name,
|
|
$description,
|
|
$address,
|
|
$city,
|
|
$kodePos,
|
|
$administrativeCode,
|
|
$rt,
|
|
$rw,
|
|
$phone,
|
|
$type,
|
|
$partOf = "",
|
|
$email = "",
|
|
$fax = "",
|
|
$url = "",
|
|
$long = "",
|
|
$lat = ""
|
|
) {
|
|
$this->get_organization_id();
|
|
$organizationID = $this->organizationID;
|
|
list($type_code, $type_display) = explode("^", $type);
|
|
$telecom = [];
|
|
$telecom[] = ["system" => "phone", "value" => "$phone", "use" => "work"];
|
|
if ($fax != "") $telecom[] = ["system" => "fax", "value" => "$fax", "use" => "work"];
|
|
if ($email != "") $telecom[] = ["system" => "email", "value" => "$email"];
|
|
if ($url != "") $telecom[] = ["system" => "url", "value" => "$url"];
|
|
$provCode = substr($administrativeCode, 0, 2);
|
|
$cityCode = substr($administrativeCode, 0, 4);
|
|
$districtCode = substr($administrativeCode, 0, 7);
|
|
$villageCode = substr($administrativeCode, 0, 10);
|
|
|
|
$data = [
|
|
"resourceType" => "Location",
|
|
"identifier" => [
|
|
[
|
|
"system" => "http://sys-ids.kemkes.go.id/location/{$organizationID}",
|
|
"value" => "$code",
|
|
],
|
|
],
|
|
"status" => "active",
|
|
"name" => "$name",
|
|
"description" => "$description",
|
|
"mode" => "instance",
|
|
"telecom" => $telecom,
|
|
"address" => [
|
|
"use" => "work",
|
|
"line" => [
|
|
$address,
|
|
],
|
|
"city" => "$city",
|
|
"postalCode" => "$kodePos",
|
|
"country" => "ID",
|
|
"extension" => [
|
|
[
|
|
"url" =>
|
|
"https://fhir.kemkes.go.id/r4/StructureDefinition/administrativeCode",
|
|
"extension" => [
|
|
["url" => "province", "valueCode" => $provCode],
|
|
["url" => "city", "valueCode" => $cityCode],
|
|
["url" => "district", "valueCode" => "$districtCode"],
|
|
["url" => "village", "valueCode" => "$villageCode"],
|
|
["url" => "rt", "valueCode" => "$rt"],
|
|
["url" => "rw", "valueCode" => "$rw"],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
"physicalType" => [
|
|
"coding" => [
|
|
[
|
|
"system" =>
|
|
"http://terminology.hl7.org/CodeSystem/location-physical-type",
|
|
"code" => "$type_code",
|
|
"display" => "$type_display",
|
|
],
|
|
],
|
|
],
|
|
"position" => [
|
|
"longitude" => intval($long),
|
|
"latitude" => intval($lat),
|
|
"altitude" => 0,
|
|
],
|
|
"managingOrganization" => ["reference" => "Organization/{$organizationID}"],
|
|
];
|
|
if ($partOf != "") {
|
|
$data["partOf"] = [
|
|
"reference" => "Location/$partOf"
|
|
];
|
|
}
|
|
$service = "/Location";
|
|
$resp = $this->ss_post($service, $data);
|
|
return $this->objToArray($resp);
|
|
}
|
|
|
|
function location_nonactive(
|
|
$ihsID
|
|
) {
|
|
$this->get_organization_id();
|
|
$data = [
|
|
[
|
|
"op" => "replace",
|
|
"path" => "/status",
|
|
"value" => "inactive"
|
|
]
|
|
];
|
|
|
|
$service = "/Location/$ihsID";
|
|
$resp = $this->ss_patch($service, $data);
|
|
return $this->objToArray($resp);
|
|
}
|
|
function get_location($locationID)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
function encounter_by_id($encounterID)
|
|
{
|
|
$this->get_organization_id();
|
|
$service = "/Encounter/$";
|
|
$resp = $this->ss_get($service);
|
|
return $this->objToArray($resp);
|
|
}
|
|
function encounter_by_subject($patientIhsID)
|
|
{
|
|
$this->get_organization_id();
|
|
$service = "/Encounter?subject=$patientIhsID";
|
|
$resp = $this->ss_get($service);
|
|
return $this->objToArray($resp);
|
|
}
|
|
function encounter(
|
|
$orderDate,
|
|
$patientIhsID,
|
|
$patientName,
|
|
$doctorIhsID,
|
|
$doctorName,
|
|
$locationID,
|
|
$locationName,
|
|
$labNumber,
|
|
$tz = "+07:00",
|
|
$payload_only = false
|
|
) {
|
|
$service = "/Encounter";
|
|
$xdate = substr($orderDate, 0, 10) . "T" . substr($orderDate, 11) . $tz;
|
|
$this->get_organization_id();
|
|
$param = $this->encounter_param(
|
|
$patientIhsID,
|
|
$patientName,
|
|
$doctorIhsID,
|
|
$doctorName,
|
|
$locationID,
|
|
$locationName,
|
|
$this->organizationID,
|
|
$labNumber,
|
|
$xdate
|
|
);
|
|
$payload = json_encode($param);
|
|
if ($payload_only) {
|
|
return ["", "", $payload, ""];
|
|
}
|
|
$jresp = $this->ss_post($service, $param);
|
|
$resp = $this->objToArray($jresp);
|
|
$response = json_encode($resp);
|
|
if (is_array($resp) && isset($resp["id"])) {
|
|
$encounterResponseID = $resp["id"];
|
|
return [$encounterResponseID, "", $payload, $response];
|
|
} else {
|
|
return ["", $response, $payload, $response];
|
|
}
|
|
}
|
|
function encounter_param(
|
|
$patientIhs,
|
|
$patientName,
|
|
$dpjpIhs,
|
|
$dpjpName,
|
|
$locationIhs,
|
|
$locationName,
|
|
$organizationID,
|
|
$orderHeaderNumber,
|
|
$dateTime // 2022-06-14T07:00:00+07:00
|
|
) {
|
|
if ($this->is_staging) {
|
|
$dpjpIhs = "N10000001";
|
|
$dpjpName = "Dokter Bronsig";
|
|
}
|
|
$encounterParam = [
|
|
"resourceType" => "Encounter",
|
|
"status" => "arrived",
|
|
"class" => [
|
|
"system" => "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
|
"code" => "AMB",
|
|
"display" => "ambulatory"
|
|
],
|
|
"subject" => [
|
|
"reference" => "Patient/{$patientIhs}",
|
|
"display" => "$patientName"
|
|
],
|
|
"participant" => [
|
|
[
|
|
"type" => [
|
|
[
|
|
"coding" => [
|
|
[
|
|
"system" => "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
|
|
"code" => "ATND",
|
|
"display" => "attender"
|
|
]
|
|
]
|
|
]
|
|
],
|
|
"individual" => [
|
|
"reference" => "Practitioner/{$dpjpIhs}",
|
|
"display" => "$dpjpName"
|
|
]
|
|
]
|
|
],
|
|
"period" => [
|
|
"start" => "$dateTime",
|
|
],
|
|
"location" => [
|
|
[
|
|
"location" => [
|
|
"reference" => "Location/$locationIhs",
|
|
"display" => "$locationName"
|
|
]
|
|
]
|
|
],
|
|
"statusHistory" => [
|
|
[
|
|
"status" => "arrived",
|
|
"period" => [
|
|
"start" => $dateTime
|
|
]
|
|
]
|
|
],
|
|
"serviceProvider" => [
|
|
"reference" => "Organization/{$organizationID}"
|
|
],
|
|
"identifier" => [
|
|
[
|
|
"system" => "http://sys-ids.kemkes.go.id/encounter/{$organizationID}",
|
|
"value" => "$orderHeaderNumber"
|
|
]
|
|
]
|
|
];
|
|
return $encounterParam;
|
|
}
|
|
|
|
|
|
|
|
|
|
// helper
|
|
function get_organization_id()
|
|
{
|
|
|
|
$sql = "SELECT organizationID
|
|
FROM {$this->dbname}.organization
|
|
JOIN m_branch ON organizationM_BranchID = M_BranchID AND M_BranchIsDefault = 'Y' AND M_BranchIsActive = 'Y'
|
|
WHERE organizationIsActive = 'Y'";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
return;
|
|
}
|
|
$rows = $qry->result_array();
|
|
if (count($rows) > 0) {
|
|
$this->organizationID = $rows[0]["organizationID"];
|
|
}
|
|
}
|
|
|
|
function ss_patch($service, $data)
|
|
{
|
|
$token = $this->get_token();
|
|
$authorization = "Authorization: Bearer " . $token;
|
|
$xbase_url = $this->base_url;
|
|
$url = $xbase_url . "$service";
|
|
$ch = curl_init($url);
|
|
# Setup request to send json via POST.
|
|
$payload = json_encode($data);
|
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json-patch+json', $authorization));
|
|
# Return response instead of printing.
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
# Send request.
|
|
$result = curl_exec($ch);
|
|
curl_close($ch);
|
|
# Print response.
|
|
$data_rst = json_decode($result);
|
|
return $data_rst;
|
|
}
|
|
|
|
function get_client_key($debug = "")
|
|
{
|
|
$sql = "select * from {$this->dbname}.client where clientIsActive = 'Y'";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
return [false, "", ""];
|
|
}
|
|
$rows = $qry->result_array();
|
|
if (count($rows) == 0) {
|
|
if ($debug != "") {
|
|
print_r([false, "", ""]);
|
|
}
|
|
return [false, "", ""];
|
|
}
|
|
if ($debug != "") {
|
|
print_r([true, $rows[0]["clientKey"], $rows[0]["clientSecret"]]);
|
|
}
|
|
|
|
return [true, $rows[0]["clientKey"], $rows[0]["clientSecret"]];
|
|
}
|
|
|
|
function reset_token()
|
|
{
|
|
$sql = "delete from {$this->dbname}.token ";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
echo "ERR : " . $this->db->error()["message"];
|
|
echo " " . $this->db->last_query();
|
|
exit;
|
|
}
|
|
}
|
|
|
|
function put_token()
|
|
{
|
|
$auth_url = $this->base_oauth_url;
|
|
$url = $auth_url . "/accesstoken?grant_type=client_credentials";
|
|
list($status, $key, $secret) = $this->get_client_key();
|
|
$data = [
|
|
"client_id" => $key,
|
|
"client_secret" => $secret
|
|
];
|
|
$ch = curl_init($url);
|
|
$post_data = http_build_query($data);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
$result = curl_exec($ch);
|
|
curl_close($ch);
|
|
if ($result) {
|
|
$token_rst = json_decode($result);
|
|
$sql = "select count(*) as xcount, tokenID
|
|
from {$this->dbname}.token
|
|
where
|
|
tokenIsActive = 'y'
|
|
";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
echo "get count token error";
|
|
exit;
|
|
}
|
|
|
|
$rst_count = $qry->row_array();
|
|
// print_r($token_rst);
|
|
if ($rst_count['xcount'] > 0) {
|
|
$sql = "update {$this->dbname}.token set tokenValue = ?, tokenExpired = date_add(now(), interval 50 minute)
|
|
where tokenID = ?";
|
|
$qry = $this->db->query($sql, [$token_rst->access_token, $rst_count['tokenID']]);
|
|
if (!$qry) {
|
|
$this->sys_error_db("refresh token error", $this->db->last_query());
|
|
exit;
|
|
}
|
|
} else {
|
|
$sql = "update {$this->dbname}.token set tokenIsActive = 'N' where tokenIsActive = 'Y'";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
echo "nonactive token error";
|
|
exit;
|
|
}
|
|
|
|
$sql = "insert into {$this->dbname}.token(tokenValue,tokenExpired) values(?,date_add(now(), interval 50 minute))";
|
|
$qry = $this->db->query($sql, [$token_rst->access_token]);
|
|
if (!$qry) {
|
|
echo "insert token error";
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$sql = "select tokenValue
|
|
from {$this->dbname}.token
|
|
where
|
|
tokenIsActive = 'Y' limit 1
|
|
";
|
|
$qry = $this->db->query($sql);
|
|
if (!$qry) {
|
|
echo "get token error";
|
|
exit;
|
|
}
|
|
|
|
return $qry->row()->tokenValue;
|
|
}
|
|
}
|
|
|
|
function get_token()
|
|
{
|
|
$sql = "SELECT COUNT(*) as xcount, tokenValue
|
|
FROM {$this->dbname}.token
|
|
WHERE tokenIsActive = 'Y' AND NOW() < tokenExpired AND tokenValue IS NOT NULL ";
|
|
$qry = $this->db->query($sql);
|
|
$this->check_error($qry, "select token");
|
|
|
|
$data_token = $qry->row_array();
|
|
//print_r($data_token);
|
|
if ($data_token['xcount'] > 0) {
|
|
return $data_token['tokenValue'];
|
|
} else {
|
|
return $this->put_token();
|
|
}
|
|
}
|
|
|
|
|
|
function ss_post($service, $data)
|
|
{
|
|
$token = $this->get_token();
|
|
$authorization = "Authorization: Bearer " . $token;
|
|
$xbase_url = $this->base_url;
|
|
$url = $xbase_url . "$service";
|
|
$ch = curl_init($url);
|
|
# Setup request to send json via POST.
|
|
$payload = json_encode($data);
|
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $authorization));
|
|
# Return response instead of printing.
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
# Send request.
|
|
$result = curl_exec($ch);
|
|
curl_close($ch);
|
|
# Print response.
|
|
$data_rst = json_decode($result);
|
|
return $data_rst;
|
|
}
|
|
function ss_get($service, $debug = "")
|
|
{
|
|
$token = $this->get_token();
|
|
$authorization = "Authorization: Bearer " . $token;
|
|
$xbase_url = $this->base_url;
|
|
$url = $xbase_url . "$service";
|
|
$ch = curl_init($url);
|
|
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $authorization));
|
|
# Return response instead of printing.
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
# Send request.
|
|
$result = curl_exec($ch);
|
|
curl_close($ch);
|
|
# Print response.
|
|
if ($debug != "") {
|
|
echo "url : $url \n";
|
|
print_r($result);
|
|
}
|
|
$data_rst = json_decode($result);
|
|
return $data_rst;
|
|
}
|
|
protected function objToArray($obj)
|
|
{
|
|
if (!is_object($obj) && !is_array($obj)) {
|
|
return $obj;
|
|
}
|
|
foreach ($obj as $key => $value) {
|
|
$arr[$key] = $this->objToArray($value);
|
|
}
|
|
return $arr;
|
|
}
|
|
|
|
function check_error($qry, $stage)
|
|
{
|
|
if (!$qry) {
|
|
echo json_encode([
|
|
"status" => "ERR",
|
|
"message" => $this->db->error(),
|
|
"sql" => $this->db->last_query()
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
}
|