Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FHIR Coverage Resource Added #4164

Merged
merged 30 commits into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6749f87
Merge pull request #1 from openemr/master
vishnuyar Dec 29, 2020
63e04de
Merge pull request #2 from openemr/master
vishnuyar Dec 31, 2020
bd3dd1b
Merge pull request #3 from openemr/master
vishnuyar Jan 4, 2021
e874a33
FHIR Coverage Resource added and associated changes
vishnuyar Jan 6, 2021
9338f43
style fixes
vishnuyar Jan 6, 2021
3ac2602
add OrganizationService API
vishnuyar Jan 7, 2021
12cdce5
add uuid column to insurance_companies and insurance_data
vishnuyar Jan 7, 2021
7b909af
PSR12 fixes
vishnuyar Jan 7, 2021
3de6432
add insert update to Organization Service
vishnuyar Jan 7, 2021
6ab5e8c
add FHIR Coverage route
vishnuyar Jan 7, 2021
5cb31e3
add orgtype while parsing resource
vishnuyar Jan 7, 2021
d475121
bug fix
vishnuyar Jan 7, 2021
8f50fc2
remove orgType
vishnuyar Jan 7, 2021
bffd64d
fixed handling errors
vishnuyar Jan 7, 2021
a38095b
add validation messages
vishnuyar Jan 7, 2021
6dbd6cd
modular functions
vishnuyar Jan 7, 2021
6121ecb
moved from 6.0.0 to 6.0.1
vishnuyar Jan 7, 2021
7498ef1
style fixes
vishnuyar Jan 7, 2021
027d0f1
handling old api services data
vishnuyar Jan 8, 2021
b5e752e
fixed review suggestions
vishnuyar Jan 8, 2021
752d8a8
bug fix for php7.4+
vishnuyar Jan 8, 2021
b3daabb
bug fix for php7.4
vishnuyar Jan 8, 2021
ae7f9b9
bug fix for php7.4
vishnuyar Jan 8, 2021
9815306
bug fix for php7.4
vishnuyar Jan 8, 2021
f3afe10
add getOneById and getOneByPid functions
vishnuyar Jan 10, 2021
dc35de7
styling fix
vishnuyar Jan 10, 2021
e4370f9
some more fixes
vishnuyar Jan 11, 2021
d958941
add insurance organization identifier
vishnuyar Jan 11, 2021
344d402
checking for empty results fix
vishnuyar Jan 12, 2021
5f9ba95
alphatize Coverage
vishnuyar Jan 12, 2021
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
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 @@ -162,6 +163,7 @@ This is a listing of scopes:
- `api:fhir` (user fhir which are the /fhir/ endpoints)
- `user/AllergyIntolerance.read`
- `user/CareTeam.read`
- `user/Coverage.read`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd usually let this go, but since there's another minor change to do, might as well alphabetize (place below Condition) this as well :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hoping that my next PR will have less of these kind of mistakes :)

- `user/Condition.read`
- `user/Encounter.read`
- `user/Immunization.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)

This comment was marked as resolved.

This comment was marked as resolved.

- [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;

This comment was marked as resolved.

This comment was marked as resolved.

}
);

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding a uuid in the upgrade, it should folllow the three steps (showing example of prior entry for users uuid):

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

#IfUuidNeedUpdate users
#EndIf

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

steps:

  1. add column
  2. populate uuids (this is just to avoid a super long uuid population when a user first uses the api call)
  3. add index

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


#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);
Copy link
Member

@bradymiller bradymiller Jan 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rest controllers should not be changed (the rest endpoints will use uuid then)
Just need to ensure all the other placed in codebase that use the service are changed
(grep insuranceCompanyService and change the getOne to getOneById where used outside fhir/rest)

Copy link
Member

@bradymiller bradymiller Jan 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just checked and otherwise looks good in codebase (just need to change this back to getOne() )
And then need to update lines 1479 and 1484 in API_README.md to show use of uuid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, that is a put. agree best thing to do here is to keep as is (changing to uuid for this restcontroller will require a bunch more more). so keep the getOneById call :)

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);
Copy link
Member

@bradymiller bradymiller Jan 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rest controllers should not be changed (the rest endpoints will use uuid then)
Just need to ensure all the other placed in codebase that use the service are changed
(grep insuranceService and change the getOne to getOneByPid where used outside fhir/rest)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, this is more complicated since the endpoint takes in pid and type. let me look into that to see best strategy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO for me: see above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, lets also keep this as is (getOneByPid). And just need to change one more instance of getOne (to getOneByPid) use in the interface/billing/sl_eob_process.php

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the functionname in interface/billing/sl_eob_process.php

return RestControllerHelper::responseHandler($serviceResult, null, 200);
}

Expand Down
Loading