Skip to content

Commit

Permalink
FHIR Coverage Resource Added (openemr#4164)
Browse files Browse the repository at this point in the history
* FHIR Coverage Resource added and associated changes

* style fixes

* add OrganizationService API

* add uuid column to insurance_companies and insurance_data

* PSR12 fixes

* add insert update to Organization Service

* add FHIR Coverage route

* add orgtype while parsing resource

* bug fix

* remove orgType

* fixed handling errors

* add validation messages

* modular functions

* moved from 6.0.0 to 6.0.1

* style fixes

* handling old api services data

* fixed review suggestions

* bug fix for php7.4+

* bug fix for php7.4

* bug fix for php7.4

* bug fix for php7.4

* add getOneById and getOneByPid functions

* styling fix

* some more fixes

* add insurance organization identifier

* checking for empty results fix

* alphatize Coverage
  • Loading branch information
vishnuyar authored Jan 12, 2021
1 parent e82e06a commit bc97754
Show file tree
Hide file tree
Showing 19 changed files with 883 additions and 85 deletions.
6 changes: 4 additions & 2 deletions API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Finally, APIs which are integrated with the new `handleProcessingResult` method
- [FHIR API Endpoints](FHIR_README.md#fhir-endpoints)
- [FHIR Capability Statement](FHIR_README.md#capability-statement)
- [FHIR Patient](FHIR_README.md#patient-resource)
- [FHIR Coverage](FHIR_README.md#coverage-resource)
- [FHIR Encounter](FHIR_README.md#encounter-resource)
- [FHIR Practitioner](FHIR_README.md#practitioner-resource)
- [FHIR PractitionerRole](FHIR_README.md#practitionerrole-resource)
Expand Down Expand Up @@ -163,6 +164,7 @@ This is a listing of scopes:
- `user/AllergyIntolerance.read`
- `user/CareTeam.read`
- `user/Condition.read`
- `user/Coverage.read`
- `user/Encounter.read`
- `user/Immunization.read`
- `user/Location.read`
Expand Down Expand Up @@ -200,7 +202,7 @@ curl -X POST -k -H 'Content-Type: application/json' -i https://localhost:9300/oa
"client_name": "A Private App",
"token_endpoint_auth_method": "client_secret_post",
"contacts": ["me@example.org", "them@example.org"],
"scope": "openid api:oemr api:fhir api:port api:pofh 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/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 patient/encounter.read patient/patient.read patient/Encounter.read patient/Patient.read"
"scope": "openid api:oemr api:fhir api:port api:pofh 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 patient/encounter.read patient/patient.read patient/Encounter.read patient/Patient.read"
}'
```

Expand All @@ -218,7 +220,7 @@ Response:
"client_name": "A Private App",
"redirect_uris": ["https:\/\/client.example.org\/callback"],
"token_endpoint_auth_method": "client_secret_post",
"scope": "openid api:oemr api:fhir api:port api:pofh 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/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 patient/encounter.read patient/patient.read patient/Encounter.read patient/Patient.read"
"scope": "openid api:oemr api:fhir api:port api:pofh 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 patient/encounter.read patient/patient.read patient/Encounter.read patient/Patient.read"
}
```

Expand Down
27 changes: 27 additions & 0 deletions FHIR_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Database Result -> Service Component -> FHIR Service Component -> Parse OpenEMR
- [FHIR API Endpoints](FHIR_README.md#fhir-endpoints)
- [Capability Statement](FHIR_README.md#capability-statement)
- [Patient](FHIR_README.md#patient-resource)
- [Coverage](FHIR_README.md#coverage-resource)
- [Encounter](FHIR_README.md#encounter-resource)
- [Practitioner](FHIR_README.md#practitioner-resource)
- [PractitionerRole](FHIR_README.md#practitionerrole-resource)
Expand Down Expand Up @@ -207,6 +208,32 @@ curl -X PUT -H 'Content-Type: application/fhir+json' 'http://localhost:8300/apis
]'
```

---

### Coverage Resource

#### GET fhir/Coverage

Request:

```sh
curl -X GET 'http://localhost:8300/apis/default/fhir/Coverage'
```

#### GET fhir/Coverage[id]

Request:

```sh
curl -X GET 'http://localhost:8300/apis/default/fhir/Coverage/926c051b-9eaf-4753-b5d3-65c3f329e656'
```

- Supported Search Parameters
- \_id
- patient
- payor


---

### Encounter Resource
Expand Down
15 changes: 15 additions & 0 deletions _rest_routes.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@
use OpenEMR\RestControllers\FHIR\FhirAllergyIntoleranceRestController;
use OpenEMR\RestControllers\FHIR\FhirCareTeamRestController;
use OpenEMR\RestControllers\FHIR\FhirConditionRestController;
use OpenEMR\RestControllers\FHIR\FhirCoverageRestController;
use OpenEMR\RestControllers\FHIR\FhirEncounterRestController;
use OpenEMR\RestControllers\FHIR\FhirObservationRestController;
use OpenEMR\RestControllers\FHIR\FhirImmunizationRestController;
Expand Down Expand Up @@ -926,6 +927,20 @@
$return = (new FhirCareTeamRestController())->getOne($uuid);
RestConfig::apiLog($return);
return $return;
},
"GET /fhir/Coverage" => function () {
RestConfig::scope_check("user", "Coverage", "read");
RestConfig::authorization_check("admin", "super");
$return = (new FhirCoverageRestController())->getAll($_GET);
RestConfig::apiLog($return);
return $return;
},
"GET /fhir/Coverage/:uuid" => function ($uuid) {
RestConfig::scope_check("user", "Coverage", "read");
RestConfig::authorization_check("admin", "super");
$return = (new FhirCoverageRestController())->getOne($uuid);
RestConfig::apiLog($return);
return $return;
}
);

Expand Down
2 changes: 1 addition & 1 deletion interface/billing/sl_eob_process.php
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ function era_callback(&$out)
if ($out['corrected'] == '1') {
if ($GLOBALS['update_mbi']) {
if ($primary && (substr($inslabel, 3) == 1)) {
$updated_ins = InsuranceService::getOne($pid, "primary");
$updated_ins = InsuranceService::getOneByPid($pid, "primary");
$updated_ins['provider'] = $insurance_id;
$updated_ins['policy_number'] = $out['corrected_mbi'];
InsuranceService::update($pid, "primary", $updated_ins);
Expand Down
8 changes: 4 additions & 4 deletions interface/reports/receipts_by_method_report.php
Original file line number Diff line number Diff line change
Expand Up @@ -579,16 +579,16 @@ function sel_procedure() {
if (empty($row['payer_id'])) {
// 'ar_session' is not capturing payer_id when entering payments through invoice or era posting
if ($row['payer_type'] == '1') {
$insurance_id = (new InsuranceService())->getOne($row['pid'], "primary");
$insurance_id = (new InsuranceService())->getOneByPid($row['pid'], "primary");
} elseif ($row['payer_type'] == '2') {
$insurance_id = (new InsuranceService())->getOne($row['pid'], "secondary");
$insurance_id = (new InsuranceService())->getOneByPid($row['pid'], "secondary");
} elseif ($row['payer_type'] == '3') {
$insurance_id = (new InsuranceService())->getOne($row['pid'], "tertiary");
$insurance_id = (new InsuranceService())->getOneByPid($row['pid'], "tertiary");
} else {
$rowmethod = xl('Unnamed insurance company');
}
if (!empty($insurance_id['provider'])) {
$insurance_company = (new InsuranceCompanyService())->getOne($insurance_id['provider']) ?? '';
$insurance_company = (new InsuranceCompanyService())->getOneById($insurance_id['provider']) ?? '';
$rowmethod = xl($insurance_company['name']);
}
} else {
Expand Down
21 changes: 21 additions & 0 deletions sql/6_0_0-to-6_1_0_upgrade.sql
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,24 @@
-- #IfDocumentNamingNeeded
-- desc: populate name field with document names.
-- arguments: none
#IfMissingColumn insurance_companies uuid
ALTER TABLE `insurance_companies` ADD `uuid` binary(16) DEFAULT NULL;
#EndIf

#IfUuidNeedUpdate insurance_companies
#EndIf

#IfNotIndex insurance_companies uuid
CREATE UNIQUE INDEX `uuid` ON `insurance_companies` (`uuid`);
#EndIf

#IfMissingColumn insurance_data uuid
ALTER TABLE `insurance_data` ADD `uuid` binary(16) DEFAULT NULL;
#EndIf

#IfUuidNeedUpdate insurance_data
#EndIf

#IfNotIndex insurance_data uuid
CREATE UNIQUE INDEX `uuid` ON `insurance_data` (`uuid`);
#EndIf
6 changes: 5 additions & 1 deletion sql/database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2970,6 +2970,7 @@ CREATE TABLE `immunizations` (
DROP TABLE IF EXISTS `insurance_companies`;
CREATE TABLE `insurance_companies` (
`id` int(11) NOT NULL default '0',
`uuid` binary(16) DEFAULT NULL,
`name` varchar(255) default NULL,
`attn` varchar(255) default NULL,
`cms_id` varchar(15) default NULL,
Expand All @@ -2980,7 +2981,8 @@ CREATE TABLE `insurance_companies` (
`inactive` int(1) NOT NULL DEFAULT '0',
`eligibility_id` VARCHAR(32) default NULL,
`x12_default_eligibility_id` INT(11) default NULL,
PRIMARY KEY (`id`)
PRIMARY KEY (`id`),
UNIQUE KEY `uuid` (`uuid`)
) ENGINE=InnoDB;

-- --------------------------------------------------------
Expand All @@ -2992,6 +2994,7 @@ CREATE TABLE `insurance_companies` (
DROP TABLE IF EXISTS `insurance_data`;
CREATE TABLE `insurance_data` (
`id` bigint(20) NOT NULL auto_increment,
`uuid` binary(16) DEFAULT NULL,
`type` enum('primary','secondary','tertiary') default NULL,
`provider` varchar(255) default NULL,
`plan_name` varchar(255) default NULL,
Expand Down Expand Up @@ -3022,6 +3025,7 @@ CREATE TABLE `insurance_data` (
`accept_assignment` varchar(5) NOT NULL DEFAULT 'TRUE',
`policy_type` varchar(25) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY `uuid` (`uuid`),
UNIQUE KEY `pid_type_date` (`pid`,`type`,`date`)
) ENGINE=InnoDB AUTO_INCREMENT=1;

Expand Down
72 changes: 72 additions & 0 deletions src/RestControllers/FHIR/FhirCoverageRestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace OpenEMR\RestControllers\FHIR;

use OpenEMR\Services\FHIR\FhirValidationService;
use OpenEMR\Services\FHIR\FhirCoverageService;
use OpenEMR\Services\FHIR\FhirResourcesService;
use OpenEMR\RestControllers\RestControllerHelper;
use OpenEMR\FHIR\R4\FHIRResource\FHIRBundle\FHIRBundleEntry;
use OpenEMR\Validators\ProcessingResult;

require_once(__DIR__ . '/../../../_rest_config.php');
/**
* FHIR Organization Service
*
* @coversDefaultClass OpenEMR\Services\FHIR\FhirOrganizationService
* @package OpenEMR
* @link http://www.open-emr.org
* @author Yash Bothra <yashrajbothra786@gmail.com>
* @copyright Copyright (c) 2020 Yash Bothra <yashrajbothra786@gmail.com>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*
*/
class FhirCoverageRestController
{
private $fhirCoverage;
private $fhirService;
private $fhirValidationService;

public function __construct()
{
$this->fhirService = new FhirResourcesService();
$this->fhirCoverage = new FhirCoverageService();
$this->fhirValidationService = new FhirValidationService();
}

/**
* Queries for FHIR Coverage resource using various search parameters.
* Search parameters include:
* - beneficiary
* - patient
* @return FHIR bundle with query results, if found
*/
public function getAll($searchParams)
{
$processingResult = $this->fhirCoverage->getAll($searchParams);
$bundleEntries = array();
foreach ($processingResult->getData() as $index => $searchResult) {
$bundleEntry = [
'fullUrl' => $GLOBALS['site_addr_oath'] . ($_SERVER['REDIRECT_URL'] ?? '') . '/' . $searchResult->getId(),
'resource' => $searchResult
];
$fhirBundleEntry = new FHIRBundleEntry($bundleEntry);
array_push($bundleEntries, $fhirBundleEntry);
}
$bundleSearchResult = $this->fhirService->createBundle('Coverage', $bundleEntries, false);
$searchResponseBody = RestControllerHelper::responseHandler($bundleSearchResult, null, 200);
return $searchResponseBody;
}


/**
* Queries for a single FHIR Coverage resource by FHIR id
* @param $fhirId The FHIR Coverage resource id (uuid)
* @returns 200 if the operation completes successfully
*/
public function getOne($fhirId)
{
$processingResult = $this->fhirCoverage->getOne($fhirId, true);
return RestControllerHelper::handleFhirProcessingResult($processingResult, 200);
}
}
2 changes: 1 addition & 1 deletion src/RestControllers/InsuranceCompanyRestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function getAll()

public function getOne($iid)
{
$serviceResult = $this->insuranceCompanyService->getOne($iid);
$serviceResult = $this->insuranceCompanyService->getOneById($iid);
return RestControllerHelper::responseHandler($serviceResult, null, 200);
}

Expand Down
2 changes: 1 addition & 1 deletion src/RestControllers/InsuranceRestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function getAll($pid)

public function getOne($pid, $type)
{
$serviceResult = $this->insuranceService->getOne($pid, $type);
$serviceResult = $this->insuranceService->getOneByPid($pid, $type);
return RestControllerHelper::responseHandler($serviceResult, null, 200);
}

Expand Down
Loading

0 comments on commit bc97754

Please sign in to comment.