Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/compose-shared-apache.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ services:
OPENEMR_ENABLE_CI_PHP: "1"
ENABLE_COVERAGE: "${ENABLE_COVERAGE:-false}"
SELENIUM_BASE_URL: "http://openemr"
OPENEMR_SETTING_ccda_alt_service_enable: "3"
healthcheck:
test:
- CMD
Expand Down
1 change: 1 addition & 0 deletions ci/compose-shared-nginx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ services:
OPENEMR_ENABLE_CI_PHP: "1"
ENABLE_COVERAGE: "${ENABLE_COVERAGE:-false}"
SELENIUM_BASE_URL: "http://nginx"
OPENEMR_SETTING_ccda_alt_service_enable: "3"
volumes:
- ../:/usr/share/nginx/html/openemr
- ./nginx/php.ini:/usr/local/etc/php/php.ini:ro
Expand Down
2 changes: 1 addition & 1 deletion ci/inferno/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ services:
retries: 3
openemr:
restart: always
image: openemr/openemr:flex-3.20
image: openemr/openemr:flex-3.22-php-8.4
ports:
- 8080:80
- 8523:443
Expand Down
2 changes: 1 addition & 1 deletion ci/inferno/inferno-files
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public function generate(
$date_options
);
$content = $this->socket_get($data);
$content = trim((string) $content);
$content = trim($content);
// split content if unstructured is included from service.
// service will send back a CDA and an auto created unstructured document
// if CCM sends the documents(patient_files object) with data array.
Expand Down Expand Up @@ -166,7 +166,7 @@ public function generate(
return $generatedResult;
}

public function socket_get($data)
public function socket_get($data): string
{
$serviceRequestor = new CcdaServiceDocumentRequestor();
$content = $serviceRequestor->socket_get($data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
namespace Carecoordination\Model;

use Exception;
use OpenEMR\Common\Logging\SystemLoggerAwareTrait;
use OpenEMR\Common\System\System;

class CcdaServiceDocumentRequestor
{
use SystemLoggerAwareTrait;

/**
* @throws CcdaServiceConnectionException
*/
public function socket_get($data)
{
$this->getSystemLogger()->debug("Calling CcdaServiceDocumentRequestor::socket_get");
$output = "";
$system = new System();

Expand All @@ -33,8 +37,9 @@ public function socket_get($data)
}
// Let's check if server is already running but suppress warning with @ operator
$server_active = @socket_connect($socket, "127.0.0.1", "6661");

$this->getSystemLogger()->debug("CcdaServiceDocumentRequestor::socket_get server active: " . var_export($server_active, true));
if ($server_active === false) {
$this->getSystemLogger()->debug("CcdaServiceDocumentRequestor::socket_get starting local ccda service");
// 1 -> Care coordination module, 2-> portal, 3 -> Both so the local service is on if it's greater than 0
if ($GLOBALS['ccda_alt_service_enable'] > 0) { // we're local service
$path = $GLOBALS['fileroot'] . "/ccdaservice";
Expand All @@ -49,7 +54,7 @@ public function socket_get($data)
throw new CcdaServiceConnectionException("Failed to start local ccdaservice");
}
if (pclose($pipeHandle) === -1) {
error_log("Failed to close pipehandle for ccdaservice");
$this->getSystemLogger()->errorLogCaller("Failed to close pipehandle for ccdaservice");
}
} else {
$command = 'node';
Expand All @@ -58,24 +63,25 @@ public function socket_get($data)
// older or custom Ubuntu systems that have nodejs rather than node command
$command = 'nodejs';
} else {
error_log("Node is not installed on the system. Connection failed");
$this->getSystemLogger()->errorLogCaller("Node is not installed on the system. Connection failed");
throw new CcdaServiceConnectionException('Connection Failed.');
}
}
$cmd = $system->escapeshellcmd("$command " . $path . "/serveccda.js");
exec($cmd . " > /dev/null &");
}
sleep(5); // give cpu a rest
$this->getSystemLogger()->debug("CcdaServiceDocumentRequestor::socket_get attempting connection again after starting service");
// now try to connect to the server
$result = socket_connect($socket, "127.0.0.1", 6661);
if ($result === false) {
$errorCode = socket_last_error($socket);
$errorMsg = socket_strerror($errorCode);
error_log("Socket connection error $errorCode: $errorMsg");
$this->getSystemLogger()->errorLogCaller("Socket connection error $errorCode: $errorMsg");
throw new CcdaServiceConnectionException("Connection Failed: $errorMsg");
}
} else {
error_log("C-CDA Service is not enabled in Global Settings");
$this->getSystemLogger()->errorLogCaller("C-CDA Service is not enabled in Global Settings");
throw new CcdaServiceConnectionException("Please Enable C-CDA Alternate Service in Global Settings");
}
}
Expand All @@ -85,7 +91,7 @@ public function socket_get($data)
// Set default buffer size to target data array size.
$good_buf = socket_set_option($socket, SOL_SOCKET, SO_SNDBUF, $len);
if ($good_buf === false) { // Can't set buffer
error_log("Failed to set socket buffer to " . $len);
$this->getSystemLogger()->errorLogCaller("Failed to set socket buffer to " . $len);
}
// make writeSize chunk either the size set above or the default buffer size (64Kb).
$writeSize = socket_get_option($socket, SOL_SOCKET, SO_SNDBUF);
Expand All @@ -103,7 +109,7 @@ public function socket_get($data)
// pause for the receiving side
usleep(200000);
} while ($out !== false && $pos < $len && $currentCounter++ <= $maxLineAttempts);

$this->getSystemLogger()->debug("CcdaServiceDocumentRequestor::socket_get finished writing to socket");
socket_set_nonblock($socket);
//Read back rendered document from node service!
do {
Expand All @@ -113,6 +119,7 @@ public function socket_get($data)
} while (!empty($line));

$output = substr(trim($output), 0, strlen($output) - 1);
$this->getSystemLogger()->debug("CcdaServiceDocumentRequestor::socket_get finished reading from socket");
// Close and return.
socket_close($socket);
if ($output == "Authentication Failure") {
Expand Down
9 changes: 6 additions & 3 deletions src/Services/FHIR/FhirDocRefService.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace OpenEMR\Services\FHIR;

use OpenEMR\Common\Logging\SystemLogger;
use OpenEMR\Common\Logging\SystemLoggerAwareTrait;
use OpenEMR\Common\System\System;
use OpenEMR\Common\Uuid\UuidRegistry;
use OpenEMR\Cqm\Qdm\BaseTypes\DateTime;
Expand Down Expand Up @@ -46,6 +47,7 @@ class FhirDocRefService
{
use ResourceServiceSearchTrait;
use PatientSearchTrait;
use SystemLoggerAwareTrait;

private $resourceSearchParameters;

Expand Down Expand Up @@ -82,6 +84,7 @@ protected function loadSearchParameters()
*/
public function getAll($searchParams, $puuidBind): ProcessingResult
{
$this->getSystemLogger()->debug("FhirDocRefService::getAll called", ['searchParams' => $searchParams]);
$fhirSearchResult = new ProcessingResult();
$oeSearchParameters = $this->createOpenEMRSearchParameters($searchParams, $puuidBind);
$type = $oeSearchParameters['type'] ?? $this->createDefaultType();
Expand All @@ -94,7 +97,7 @@ public function getAll($searchParams, $puuidBind): ProcessingResult

// if no start & end, return current CCD
if ($this->shouldReturnMostCurrentCCD($oeSearchParameters)) {
$documentReference = $this->getMostCurrentCCDReference($oeSearchParameters, $fhirSearchResult);
$documentReference = $this->getMostCurrentCCDReference($oeSearchParameters);
} else {
// else
// generate CCD using start & end
Expand Down Expand Up @@ -131,8 +134,8 @@ private function getPatientRecordForSearchParameters($oeSearchParameters): array
$searchPatient = $oeSearchParameters[$mappedField->getField()];

// we only allow one patient CCD to be generated at a time.
if (empty($searchPatient->getValues()) || count($searchPatient->getValues()) > 1) {
throw new SearchFieldException($mappedField->getField(), "Field is required and cardinality is 1..1");
if (empty($searchPatient) || empty($searchPatient->getValues()) || count($searchPatient->getValues()) > 1) {
throw new SearchFieldException($mappedField->getField(), "patient field is required and cardinality is 1..1");
}

$fhirPatientService = new FhirPatientService();
Expand Down
2 changes: 1 addition & 1 deletion tests/Tests/Api/ApiTestClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ApiTestClient
const BOGUS_CLIENTSECRET = "jJVKPZveRiyjAtfWFzxx_MF-3K2rGpDfzzrBjwq52L5_BvnqkCiKitcQDGgz_goJHiQt9yMTh3hu33vhp_UQOg";
const BOGUS_ACCESS_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJRRl80RlRkV2h4eGJlb1Y4SGU5c1ZRQUl3STlQZWdYM3IyVUdiTTVjaWtNIiwianRpIjoiYWZmYWEyOTk5NWY5MjRjZDlmMjc0YTdhZGM5NmM0YzJmZTYwNGE3MjA0ODFkMTdmMWZiYTg2ZDg4ZWIxOWI0YWVlM2RhZTM1Zjg3MjcwMDAiLCJpYXQiOjE2MDcyMTc5MTksIm5iZiI6MTYwNzIxNzkxOSwiZXhwIjoxNjA3MjIxNTE5LCJzdWIiOiI5MjJjYzYzNi01NTNiLTQ1MGQtYTJkZC1hNmRjYmM4ZDNiMDciLCJzY29wZXMiOlsib3BlbmlkIiwic2l0ZTpkZWZhdWx0Il19.u2Ujtln3vEKIR8E0rSd-xr6m-3huCxiFMaTm9_NQplVNsBkrc6Y3KLy9FRZVS3xSY1Qgav-UvOxikYT2zNNlK-LotEoEvZdtj87X6fh4wh-h5BU87lHh9aNjXFUemSO9DGKJLSZdLSeC_2w4YmbhQykGFISiltD2_PAJRKuKbpcBo3-Lafe2N83mF5i8mZXSCu_fbLrmTMYPCnsRaU_sWStzFp6p0SM3zGfLt1kjw-hcE82Ci1puqRS2nR5Z3kEOXz-hQOdXmQMq0s_gkeQZvLPOJwLGfEX5d4eIU4BfngksjGkKQhC7rUKT-_2F-U_z30P3izzZM6m4dZ10IiP80g";
const BOGUS_REFRESH_TOKEN = "def50200cd30606a46a09d2ba242e77528d247769112924ccff8e5d9ff9785ad032b6e91e22c9d716106efa0735b134f1bde452c9902ac75e1360ec2b8061b39c4b980ff0ffd18f9d66644c1bb3383feaa2594afd137475f60157ea6f5014cad0f5fa4e142fba5b414b7189e964ca154bbe9ffae90d0843dbf988f47485b41195eae073b5d1fa55c0b5c4a9ff5e876903d55ddd9ca1fbf7d70a0a6dcb70a76a91287b9cfd7e89ae91b4401142e46379ea7a573f9973a282fbd837a176051e25845300bf141033c2fcf28a7675106cc25e405852b13b4ab653eef2ac9f3c43db12f94a15b155c9533d2bad577e316194d179df281124280a993e438a806c5ba6a5b5c31c5a8893e3071ffb1df8507001f7b387c2882e8cd1e0ed50000dc2ad7954d243bdd4fac41e0bbced450a4f87e87317372cda3a6c22a5f9b6b6d8aab66e4d68739588bb4c5412a21d0e4f561fcb081eea24d7e79ba446630a53ebd05634735440181d73268f584ffa0b05e0708b0781ec5f8f3e2e92c0375d71d90f1f8e470d54cc4cb24b15545c4231edae046a9d9dd2fc78cc63768c66ffb19a9008fdd39952cd8e0e626747ac6f1dfdfc373f8064499533914d00452b70fe8a0353626a04ca57723e743";
const ALL_SCOPES = "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read user/DocumentReference.read user/Goal.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Coverage.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read patient/DocumentReference.read patient/Goal.read patient/DiagnosticReport.read user/DiagnosticReport.read user/CarePlan.read patient/CarePlan.read user/Device.read patient/Device.read patient/Provenance.read user/Provenance.read";
const ALL_SCOPES = "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read user/DocumentReference.read user/Goal.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Coverage.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read patient/DocumentReference.read patient/Goal.read patient/DiagnosticReport.read user/DiagnosticReport.read user/CarePlan.read patient/CarePlan.read user/Device.read patient/Device.read patient/Provenance.read user/Provenance.read user/DocumentReference.\$docref user/Binary.read";
const PUBLIC_CLIENT_SCOPES = "openid api:oemr api:fhir api:port patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Coverage.read patient/Encounter.read patient/Immunization.read patient/Medication.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read";

protected $headers;
Expand Down
Loading
Loading