From 9f6bc94a6cd64308401b5f180a4d3368dbca2edd Mon Sep 17 00:00:00 2001 From: Raghunath Sandilya Date: Tue, 3 May 2022 12:41:46 +0530 Subject: [PATCH 1/6] Initial Commit of MAL --- mal/Dockerfile | 3 + mal/README.md | 24 + mal/pom.xml | 111 +++ .../org/hl7/davinci/atr/server/MALConfig.java | 37 + .../hl7/davinci/atr/server/MALProvider.java | 86 ++ .../atr/server/service/MALService.java | 778 ++++++++++++++++++ .../hl7/davinci/atr/server/util/FhirUtil.java | 335 ++++++++ .../atr/server/util/TextConstants.java | 53 ++ .../main/resources/META-INF/spring.factories | 2 + mal/src/main/resources/application.yaml | 3 + pom.xml | 1 + server/pom.xml | 6 + server/src/main/resources/application.yaml | 13 +- 13 files changed, 1446 insertions(+), 6 deletions(-) create mode 100644 mal/Dockerfile create mode 100644 mal/README.md create mode 100644 mal/pom.xml create mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java create mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java create mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java create mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java create mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java create mode 100644 mal/src/main/resources/META-INF/spring.factories create mode 100644 mal/src/main/resources/application.yaml diff --git a/mal/Dockerfile b/mal/Dockerfile new file mode 100644 index 000000000..2a736e70c --- /dev/null +++ b/mal/Dockerfile @@ -0,0 +1,3 @@ +FROM contentgroup/cqf-ruler:latest + +COPY ./target/cqf-ruler-*.jar plugin diff --git a/mal/README.md b/mal/README.md new file mode 100644 index 000000000..89a5877c0 --- /dev/null +++ b/mal/README.md @@ -0,0 +1,24 @@ +# Plugin + +This is a sample project demonstrating how to create a cqf-ruler plugin. + +## Setup + +cqf-ruler plugins rely heavily on Spring auto-configuration. On startup the server looks for the `resources/META_INF/spring.factories` file in all the jars on the classpath. The contents of that file point to a root Spring configuration class that defines all the beans for the plugin. For example: + +```ini +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.example.HelloWorldConfig +``` + +This tells Spring to load the config described in the HelloWorldConfig class. The cqf-ruler then loads and registers Providers, Interceptors, and Metadata extenders as built by the Spring config. It's possible to create other Beans as well. + +The `pom.xml` file in this project describes the minimal set of dependencies to get a plugin going. Any dependency provided by the base server needs to be scoped `provided` so that it's not duplicated. + +This system is very basic. It does not support runtime addition or removal of plugins, or plugin versions, or any sort of conflict resolution. Plugins are expected to be well-behaved in that they will only create Beans appropriate for the server configuration that is running. For example, a plugin will not create a DSTU3-only bean when the server is running in R4 mode. Please use conditional Bean creation to ensure this behavior. There is no guaranteed order of loading plugins, so they should not overlap or conflict in functionality or errors may result. + +NOTE: This plugin is for demonstration purposes only. It's never intended to be published + +## Docker + +The Dockerfile builds on top of the base cqf-ruler image and simply copies the jar into the `plugin` directory of the image. diff --git a/mal/pom.xml b/mal/pom.xml new file mode 100644 index 000000000..6b6065a8a --- /dev/null +++ b/mal/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + + org.hl7.davinci.atr.server + cqf-ruler-plugin-mal + 1.0.0 + + + UTF-8 + UTF-8 + 2.5.12 + + + + + + ca.uhn.hapi.fhir + hapi-fhir-bom + 5.5.3 + pom + import + + + org.junit + junit-bom + 5.8.1 + pom + import + + + + + + org.opencds.cqf.ruler + cqf-ruler-core + 0.5.0-SNAPSHOT + provided + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.opencds.cqf.ruler + cqf-ruler-test + 0.5.0-SNAPSHOT + test + + + org.springframework.boot + spring-boot-starter + ${spring_boot_version} + test + + + org.springframework.boot + spring-boot-starter-web + ${spring_boot_version} + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + true + true + + -Xlint:all + + -Xlint:-processing + + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.0.0-M1 + + true + + + + + + diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java b/mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java new file mode 100644 index 000000000..f00bf4e02 --- /dev/null +++ b/mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java @@ -0,0 +1,37 @@ +package org.hl7.davinci.atr.server; + +import org.hl7.davinci.atr.server.service.MALService; +import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.external.annotations.OnR4Condition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + + +/** + * The Class MALConfig. + */ +@Configuration +public class MALConfig { + + /** + * Member add provider. + * + * @return the operation provider + */ + @Bean + @Conditional(OnR4Condition.class) + public OperationProvider memberAddProvider() { + return new MALProvider(); + } + + /** + * Mal service. + * + * @return the MAL service + */ + @Bean + public MALService malService() { + return new MALService(); + } +} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java b/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java new file mode 100644 index 000000000..edb8ed268 --- /dev/null +++ b/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java @@ -0,0 +1,86 @@ +package org.hl7.davinci.atr.server; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.hl7.davinci.atr.server.service.MALService; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Parameters; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; + +/** + * The Class MALProvider. + */ +public class MALProvider extends DaoRegistryOperationProvider{ + + /** The Constant logger. */ + private static final Logger logger = LoggerFactory.getLogger(MALProvider.class); + + /** The group dao. */ + @Autowired + private IFhirResourceDao groupDao; + + @Autowired + private MALService malService; + + /** + * Member add. + * + * @param groupId the group id + * @param requestDetails the request details + * @param request the request + * @param response the response + */ + @Description(shortDefinition = "Add new Member to the Group", value = "Implements the $member-add operation") + @Operation(idempotent = true, name = "$member-add",type = Group.class,manualResponse=true, manualRequest=true) + public MethodOutcome memberAdd(@IdParam IdType groupId,@ResourceParam Parameters theParameters, RequestDetails requestDetails, HttpServletRequest request, + HttpServletResponse response) { + MethodOutcome retVal = new MethodOutcome(); + if (request.getHeader("Content-Type") != null + && request.getHeader("Content-Type").equals("application/fhir+json")) { + Group updatedGroup = malService.processAddMemberToGroup(theParameters, groupId,requestDetails); + if (updatedGroup != null) { + response.setStatus(201); + retVal.setId(new IdType("Group", updatedGroup.getIdElement().getIdPart(), + updatedGroup.getMeta().getVersionId())); + } + } else { + throw new UnprocessableEntityException("Invalid header values!"); + } + return retVal; + } + + + + @Description(shortDefinition = "Add new Member to the Group", value = "Implements the $member-add operation") + @Operation(idempotent = true, name = "$member-remove",type = Group.class,manualResponse=true, manualRequest=true) + public MethodOutcome memberRemove(@IdParam IdType groupId,@ResourceParam Parameters theParameters, RequestDetails requestDetails, HttpServletRequest request, + HttpServletResponse response) { + MethodOutcome retVal = new MethodOutcome(); + if (request.getHeader("Content-Type") != null + && request.getHeader("Content-Type").equals("application/fhir+json")) { + Group updatedGroup = malService.processRemoveMemberToGroup(theParameters, groupId.getIdPart()); + if (updatedGroup != null) { + response.setStatus(201); + retVal.setId(new IdType("Group", updatedGroup.getIdElement().getIdPart(), + updatedGroup.getMeta().getVersionId())); + } + } else { + throw new UnprocessableEntityException("Invalid header values!"); + } + return retVal; + } +} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java b/mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java new file mode 100644 index 000000000..dd2600191 --- /dev/null +++ b/mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java @@ -0,0 +1,778 @@ +package org.hl7.davinci.atr.server.service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.hl7.davinci.atr.server.util.FhirUtil; +import org.hl7.davinci.atr.server.util.TextConstants; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coverage; +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Period; +import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Group.GroupMemberComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; + +/** + * The Class MALService. + */ +@Service +public class MALService { + + /** The patient dao. */ + @Autowired + private IFhirResourceDao patientDao; + + /** The coverage dao. */ + @Autowired + private IFhirResourceDao coverageDao; + + /** The practitioner dao. */ + @Autowired + private IFhirResourceDao practitionerDao; + + /** The practitioner role dao. */ + @Autowired + private IFhirResourceDao practitionerRoleDao; + + /** The organization dao. */ + @Autowired + private IFhirResourceDao organizationDao; + + /** The group dao. */ + @Autowired + private IFhirResourceDao groupDao; + + /** The fhir context. */ + @Autowired + FhirContext fhirContext; + + /** The Constant logger. */ + private static final Logger logger = LoggerFactory.getLogger(MALService.class); + + /** + * Process add member to group. + * + * @param theParameters the the parameters + * @param theId the the id + * @param requestDetails the request details + * @return the group + */ + public Group processAddMemberToGroup(Parameters theParameters, IdType theId, RequestDetails requestDetails) { + + logger.info("In ProcessAdd member to Group Method"); + logger.info("RequestURL:::::{}", requestDetails.getFhirServerBase()); + String patientId = null; + String attributeProviderId = null; + String attributeProviderReferenceResource = null; + String coverageId = null; + Period attributionPeriod = null; + + Group group = groupDao.read(theId); + if (theParameters.getParameter("memberId") != null && theParameters.getParameter("providerNpi") != null) { + // Creating the TokenAndListParam object to add into the SearchParamMap + SearchParameterMap patientParamMap = new SearchParameterMap(); + TokenAndListParam tokenParam = FhirUtil.createTokenAndListParam(theParameters, "memberId"); + patientParamMap.add(Patient.SP_IDENTIFIER, tokenParam); + // Invoking the Patient Search Dao API. + IBundleProvider bundle = patientDao.search(patientParamMap); + logger.info("Received Bundle with Size:::::{}", bundle.getAllResources().size()); + for (IBaseResource iBaseResource : bundle.getAllResources()) { + Resource resource = (Resource) iBaseResource; + if (resource.fhirType().equals("Patient")) { + logger.info("patientId::::::" + resource.getIdElement().getIdPart()); + patientId = resource.getIdElement().getIdPart(); + } + } + + // Get Practitioner Id using the NPI details from received Parameters. + // Creating the TokenAndListParam object to add into the SearchParamMap + Map providerMap = findProviderIdByIdentifier(theParameters); + if (providerMap != null && !providerMap.isEmpty()) { + for (Map.Entry entry : providerMap.entrySet()) { + attributeProviderId = entry.getValue(); + attributeProviderReferenceResource = entry.getKey(); + } + } + + // Get Coverage Id using the MemberId details from received Parameters. + // Creating the TokenAndListParam object to add into the SearchParamMap + SearchParameterMap coverageParamMap = new SearchParameterMap(); + coverageParamMap.add(Coverage.SP_IDENTIFIER, tokenParam); + // Invoking the Patient Search Dao API. + IBundleProvider coverageBundle = coverageDao.search(coverageParamMap); + logger.info("Received Bundle with Size:::::{}", coverageBundle.getAllResources().size()); + for (IBaseResource iBaseResource : coverageBundle.getAllResources()) { + Resource resource = (Resource) iBaseResource; + if (resource.fhirType().equals("Coverage")) { + logger.info("coverageId::::::{}", resource.getIdElement().getIdPart()); + coverageId = resource.getIdElement().getIdPart(); + } + } + + if (theParameters.getParameter("attributionPeriod") != null) { + attributionPeriod = (Period) theParameters.getParameter("attributionPeriod"); + } + + } else if (theParameters.getParameter(TextConstants.PATIENT_REFERENCE) != null + && theParameters.getParameter(TextConstants.PROVIDER_REFERENCE) != null) { + String patientMemberId = findPatientIdByReference(theParameters); + if (StringUtils.isNotBlank(patientMemberId)) { + patientId = patientMemberId; + Map providerMap = findProviderIdByReference(theParameters); + if (providerMap != null && !providerMap.isEmpty()) { + for (Map.Entry entry : providerMap.entrySet()) { + attributeProviderId = entry.getValue(); + attributeProviderReferenceResource = entry.getKey(); + } + } else { + throw new ResourceNotFoundException("Couldn't find any Providers with given providerReference"); + } + String coverageResourceId = findCoverageIdByPatientId(patientId); + if (StringUtils.isNotBlank(coverageResourceId)) { + coverageId = coverageResourceId; + } + } else { + throw new ResourceNotFoundException("Couldn't find any Patient with given patientReference"); + } + } else { + throw new UnprocessableEntityException( + "Please provide memberId + providerNpi or patientReference + providerReference to $member-add."); + } + + if (patientId != null && attributeProviderId != null) { + logger.info(" patientMemberId :: " + patientId); + logger.info(" attributePeriod :: " + attributionPeriod); + logger.info(" attributeProviderReferenceResource :: " + attributeProviderReferenceResource); + logger.info(" attributeProviderId :: " + attributeProviderId); + logger.info(" coverageReference :: " + coverageId); + if (attributionPeriod != null) { + logger.info(" attributionPeriod.getStart() :: " + attributionPeriod.getStart()); + logger.info(" attributionPeriod.getEnd() :: " + attributionPeriod.getEnd()); + } + addMemberToGroup(group, patientId, attributeProviderId, attributeProviderReferenceResource, coverageId, + attributionPeriod); + logger.info("After adding Member::::{}", fhirContext.newJsonParser().encodeResourceToString(group)); + groupDao.update(group); + if (group == null) { + throw new UnprocessableEntityException("Error while adding member to group"); + } + } else { + throw new ResourceNotFoundException( + "No Patient or Provider found. Please provide valid Patient/Provider"); + } + return group; + } + + /** + * Find coverage id by patient id. + * + * @param id the id + * @return the string + */ + private String findCoverageIdByPatientId(String id) { + String coverageId = null; + Coverage coverage = coverageDao.read(new IdType(id)); + if (coverage != null) { + coverageId = coverage.getIdElement().getIdPart(); + } + return coverageId; + } + + /** + * Find patient id by reference. + * + * @param theParameters the the parameters + * @return the string + */ + private String findPatientIdByReference(Parameters theParameters) { + String patientId = null; + Reference patientReference = (Reference) theParameters.getParameter(TextConstants.PATIENT_REFERENCE); + System.out.println(" patientReference.getReferenceElement().getIdPart() " + + patientReference.getReferenceElement().getIdPart()); + System.out.println(" patientReference.getReference() " + patientReference.getReference()); + + Patient patient = patientDao.read(patientReference.getReferenceElement()); + if (patient != null) { + patientId = patient.getIdElement().getIdPart(); + } + return patientId; + } + + /** + * Find provider id by reference. + * + * @param theParameters the the parameters + * @return the map + */ + private Map findProviderIdByReference(Parameters theParameters) { + Map providerMap = new HashMap<>(); + Reference providerReference = (Reference) theParameters.getParameter(TextConstants.PROVIDER_REFERENCE); + String providerReferenceResource = providerReference.getReferenceElement().getResourceType(); + if (StringUtils.isNotBlank(providerReferenceResource) + && providerReferenceResource.equalsIgnoreCase("Practitioner")) { + Practitioner practitioner = practitionerDao.read(providerReference.getReferenceElement()); + if (practitioner != null && !practitioner.isEmpty()) { + providerMap.put("Practitioner", practitioner.getIdElement().getIdPart()); + } + } else if (StringUtils.isNotBlank(providerReferenceResource) + && providerReferenceResource.equalsIgnoreCase("PractitionerRole")) { + PractitionerRole practitionerRole = practitionerRoleDao.read(providerReference.getReferenceElement()); + if (practitionerRole != null && !practitionerRole.isEmpty()) { + providerMap.put("PractitionerRole", practitionerRole.getIdElement().getIdPart()); + } + } else if (StringUtils.isNotBlank(providerReferenceResource) + && providerReferenceResource.equalsIgnoreCase("Organization")) { + Organization organization = organizationDao.read(providerReference.getReferenceElement()); + if (organization != null && !organization.isEmpty()) { + providerMap.put("Organization", organization.getIdElement().getIdPart()); + } + } + return providerMap; + } + + /** + * Find provider id by identifier. + * + * @param theParameters the the parameters + * @return the map + */ + private Map findProviderIdByIdentifier(Parameters theParameters) { + Map providerMap = new HashMap<>(); + SearchParameterMap attrProviderParamMap = new SearchParameterMap(); + TokenAndListParam pracitionerTokenParam = FhirUtil.createTokenAndListParam(theParameters, "providerNpi"); + attrProviderParamMap.add("identifier", pracitionerTokenParam); + IBundleProvider practitionerBundle = practitionerDao.search(attrProviderParamMap); + if (practitionerBundle.getAllResources().isEmpty()) { + IBundleProvider practitionerRoleBundle = practitionerRoleDao.search(attrProviderParamMap); + if (practitionerRoleBundle.getAllResources().isEmpty()) { + IBundleProvider organizationBundle = organizationDao.search(attrProviderParamMap); + if (!organizationBundle.isEmpty()) { + providerMap = addToMap(organizationBundle, providerMap); + } + } else { + providerMap = addToMap(practitionerRoleBundle, providerMap); + } + } else { + providerMap = addToMap(practitionerBundle, providerMap); + } + return providerMap; + } + + /** + * Adds the to map. + * + * @param bundle the bundle + * @param providerMap the provider map + * @return the map + */ + private Map addToMap(IBundleProvider bundle, Map providerMap) { + for (IBaseResource iBaseResource : bundle.getAllResources()) { + Resource resource = (Resource) iBaseResource; + if (resource.fhirType().equals("Organization")) { + providerMap.put("Organization", resource.getIdElement().getIdPart()); + } + if (resource.fhirType().equals("Practitioner")) { + providerMap.put("Practitioner", resource.getIdElement().getIdPart()); + } + if (resource.fhirType().equals("PractitionerRole")) { + providerMap.put("PractitionerRole", resource.getIdElement().getIdPart()); + } + } + return providerMap; + } + + /** + * Adds the member to group. + * + * @param group the group + * @param patientMemberId the patient member id + * @param providerId the provider id + * @param attrProviderResourceName the attr provider resource name + * @param coverageId the coverage id + * @param attributionPeriod the attribution period + */ + private void addMemberToGroup(Group group, String patientMemberId, String providerId, + String attrProviderResourceName, String coverageId, Period attributionPeriod) { + try { + List memberList = new ArrayList<>(); + boolean isAttributionCoverageFound = false; + boolean isMemberFound = false; + if (group.hasMember()) { + memberList = group.getMember(); + for (GroupMemberComponent memberGroup : new ArrayList(memberList)) { + // GroupMemberComponent memberGroup = iterator.next(); + String entityId = getEntityIdFromGroupMemberComponent(memberGroup); + String attributeProviderId = getAttributeProviderIdFromGroupMemberComponent(memberGroup); + if (entityId != null && attributeProviderId != null) { + if (patientMemberId.equalsIgnoreCase(entityId) + && providerId.equalsIgnoreCase(attributeProviderId)) { + isMemberFound = true; + if (coverageId != null) { + isAttributionCoverageFound = updateGroupMemberComponentCoverageReferenceExtension( + memberGroup, coverageId, isAttributionCoverageFound); + } + if (attributionPeriod != null) { + updateGroupMemberComponentAttributionPeriod(memberGroup, isAttributionCoverageFound, + attributionPeriod); + } + } + } + } + if (!isMemberFound) { + GroupMemberComponent theGroupMemberComponent = FhirUtil.getGroupMemberComponent(patientMemberId, + providerId, attrProviderResourceName, coverageId, attributionPeriod); + if (theGroupMemberComponent != null) { + memberList.add(theGroupMemberComponent); + logger.info(" :: Adding one new GroupMemberComponent :: "); + group.setMember(memberList); + } + } + } else { + List newGroupMemberComponentList = null; + GroupMemberComponent newGroupMemberComponent = FhirUtil.getGroupMemberComponent(patientMemberId, + providerId, attrProviderResourceName, coverageId, attributionPeriod); + if (newGroupMemberComponent != null && !newGroupMemberComponent.isEmpty()) { + newGroupMemberComponentList = new ArrayList<>(); + newGroupMemberComponentList.add(newGroupMemberComponent); + logger.info(" :: Adding new Member for first time for group :: "); + group.setMember(newGroupMemberComponentList); + } + } + if (group.hasMeta()) { + if (group.getMeta().hasVersionId()) { + String versionId = group.getMeta().getVersionId(); + int version = Integer.parseInt(versionId); + version = version + 1; + group.getMeta().setVersionId(String.valueOf(version)); + + } else { + group.getMeta().setVersionId("1"); + } + } else { + Meta meta = new Meta(); + meta.setVersionId("1"); + group.setMeta(meta); + } + } catch (Exception e) { + logger.error("Exception in addMemberToGroup of GroupServiceImpl ", e); + } + } + + /** + * Gets the group member component. + * + * @param patientMemberId the patient member id + * @param providerId the provider id + * @param providerReference the provider reference + * @param coverageReference the coverage reference + * @param attributionPeriod the attribution period + * @return the group member component + */ + public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, String providerId, + String providerReference, String coverageReference, Period attributionPeriod) { + GroupMemberComponent theGroupMemberComponent = new GroupMemberComponent(); + List theMembeEextensionList = null; + try { + if (StringUtils.isNotBlank(patientMemberId)) { + Reference theReference = FhirUtil.getReference(patientMemberId, "Patient"); + if (theReference != null) { + theGroupMemberComponent.setEntity(theReference); + BooleanType theBoolean = FhirUtil.getBooleanType(false); + theGroupMemberComponent.setInactiveElement(theBoolean); + } + } + theMembeEextensionList = FhirUtil.getGroupMemberComponentExtension(providerId, providerReference, + coverageReference, TextConstants.NEW_TYPE); + if (theMembeEextensionList != null && !theMembeEextensionList.isEmpty()) { + theGroupMemberComponent.setExtension(theMembeEextensionList); + } + if (attributionPeriod != null) { + Period thePeriod = FhirUtil.getPeriod(attributionPeriod.getStartElement(), + attributionPeriod.getEndElement()); + theGroupMemberComponent.setPeriod(thePeriod); + } + } catch (Exception ex) { + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + } + return theGroupMemberComponent; + } + + /** + * Gets the entity id from group member component. + * + * @param memberGroup the member group + * @return the entity id from group member component + */ + private String getEntityIdFromGroupMemberComponent(GroupMemberComponent memberGroup) { + String entityId = null; + try { + if (memberGroup.hasEntity() && memberGroup.getEntity().hasReferenceElement()) { + entityId = memberGroup.getEntity().getReferenceElement().getIdPart(); + } + } catch (Exception e) { + logger.info("Exception in getEntityIdFromGroupMemberComponent of GroupServiceImpl ", e); + } + return entityId; + } + + /** + * Gets the attribute provider id from group member component. + * + * @param memberGroup the member group + * @return the attribute provider id from group member component + */ + private String getAttributeProviderIdFromGroupMemberComponent(GroupMemberComponent memberGroup) { + String attributeProviderId = null; + try { + if (memberGroup.hasExtension(TextConstants.MEMBER_PROVIDER_SYSTEM)) { + if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).hasValue()) { + Reference reference = (Reference) memberGroup + .getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).getValue(); + attributeProviderId = reference.getReferenceElement().getIdPart(); + } + } + } catch (Exception e) { + logger.info("Exception in getAttributeProviderIdFromGroupMemberComponent of GroupServiceImpl ", e); + } + return attributeProviderId; + } + + /** + * Update group member component coverage reference extension. + * + * @param memberGroup the member group + * @param coverageId the coverage id + * @param isAttributionCoverageFound the is attribution coverage found + * @return true, if successful + */ + private boolean updateGroupMemberComponentCoverageReferenceExtension(GroupMemberComponent memberGroup, + String coverageId, boolean isAttributionCoverageFound) { + try { + if (StringUtils.isNotBlank(coverageId)) { + if (memberGroup.hasExtension(TextConstants.MEMBER_COVERAGE_SYSTEM)) { + if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM).hasValue()) { + Reference reference = (Reference) memberGroup + .getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM).getValue(); + if (!coverageId.equalsIgnoreCase(reference.getReferenceElement().getIdPart())) { + Reference coverageReference = FhirUtil.getReference(coverageId, "Coverage"); + memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) + .setValue(coverageReference); + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + isAttributionCoverageFound = true; + } else { + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.NOCHANGE_TYPE); + logger.info(" Coverage nochange "); + isAttributionCoverageFound = false; + } + } else { + Reference coverageReference = FhirUtil.getReference(coverageId, "Coverage"); + memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM).setValue(coverageReference); + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + isAttributionCoverageFound = true; + } + } else { + if (memberGroup.hasExtension()) { + List extensionList = memberGroup.getExtension(); + Extension coverageExtension = FhirUtil.getExtensionForReference(coverageId, "Coverage", + TextConstants.MEMBER_COVERAGE_SYSTEM); + if (coverageExtension != null && !coverageExtension.isEmpty()) { + extensionList.add(coverageExtension); + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + isAttributionCoverageFound = true; + } + } + } + } + } catch (Exception e) { + logger.error("Exception in updateGroupMemberComponentCoverageReferenceExtension of GroupServiceImpl ", e); + } + return isAttributionCoverageFound; + } + + /** + * Update group member component change type extension. + * + * @param memberGroup the member group + * @param changeCode the change code + */ + private void updateGroupMemberComponentChangeTypeExtension(GroupMemberComponent memberGroup, String changeCode) { + try { + if (StringUtils.isNotBlank(changeCode)) { + if (memberGroup.hasExtension(TextConstants.MEMBER_CHANGETYPE_SYSTEM)) { + CodeType codeType = FhirUtil.getCodeType(changeCode); + memberGroup.getExtensionByUrl(TextConstants.MEMBER_CHANGETYPE_SYSTEM).setValue(codeType); + } else { + if (memberGroup.hasExtension()) { + List extensionList = memberGroup.getExtension(); + Extension codeExtension = FhirUtil.getExtensionForCodeType(changeCode); + if (codeExtension != null && !codeExtension.isEmpty()) { + extensionList.add(codeExtension); + } + } + } + } + } catch (Exception e) { + logger.error("Exception in updateGroupMemberComponentChangeTypeExtension of GroupServiceImpl ", e); + } + } + + /** + * Update group member component attribution period. + * + * @param memberGroup the member group + * @param isAttributionCoverageFound the is attribution coverage found + * @param attributionPeriod the attribution period + */ + private void updateGroupMemberComponentAttributionPeriod(GroupMemberComponent memberGroup, + boolean isAttributionCoverageFound, Period attributionPeriod) { + try { + if (attributionPeriod != null) { + Date startOne = null; + Date endOne = null; + Date memberStart = null; + Date memberEnd = null; + if (attributionPeriod.hasStart()) { + startOne = attributionPeriod.getStart(); + } + if (attributionPeriod.hasEnd()) { + endOne = attributionPeriod.getEnd(); + } + if (memberGroup.hasPeriod()) { + Period memberPeriod = memberGroup.getPeriod(); + if (memberPeriod.hasStart()) { + memberStart = memberPeriod.getStart(); + } + if (memberPeriod.hasEnd()) { + memberEnd = memberPeriod.getEnd(); + } + if (!startOne.equals(memberStart) || !endOne.equals(memberEnd)) { + memberGroup.setPeriod(attributionPeriod); + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + } else if (!isAttributionCoverageFound) { + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.NOCHANGE_TYPE); + } + } else { + memberGroup.setPeriod(attributionPeriod); + updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + } + } + } catch (Exception e) { + logger.error("Exception in updateGroupMemberComponentAttributionPeriod of GroupServiceImpl ", e); + } + } + + public Group processRemoveMemberToGroup(Parameters theParameters, String groupId){ + String patientMemberId = null; + String attributeProviderId = null; + String attributeProviderReferenceResource = null; + String coverageReference = null; + Period attributionPeriod = null; + Group group = groupDao.read(new IdType(groupId)); + if (group != null && !group.isEmpty() && theParameters != null && !theParameters.isEmpty()) { + if (theParameters.getParameter(TextConstants.MEMBER_ID) != null) { + // Creating the TokenAndListParam object to add into the SearchParamMap + SearchParameterMap patientParamMap = new SearchParameterMap(); + TokenAndListParam tokenParam = FhirUtil.createTokenAndListParam(theParameters, "memberId"); + patientParamMap.add(Patient.SP_IDENTIFIER, tokenParam); + // Invoking the Patient Search Dao API. + IBundleProvider bundle = patientDao.search(patientParamMap); + logger.info("Received Bundle with Size:::::{}", bundle.getAllResources().size()); + for (IBaseResource iBaseResource : bundle.getAllResources()) { + Resource resource = (Resource) iBaseResource; + if (resource.fhirType().equals("Patient")) { + logger.info("patientId::::::" + resource.getIdElement().getIdPart()); + patientMemberId = resource.getIdElement().getIdPart(); + } + } + if (patientMemberId == null) { + throw new ResourceNotFoundException("Couldn't find any Patient with given memberId"); + } + + // Get Practitioner Id using the NPI details from received Parameters. + // Creating the TokenAndListParam object to add into the SearchParamMap + Map providerMap = findProviderIdByIdentifier(theParameters); + if (providerMap != null && !providerMap.isEmpty()) { + for (Map.Entry entry : providerMap.entrySet()) { + attributeProviderId = entry.getValue(); + attributeProviderReferenceResource = entry.getKey(); + } + } + if (providerMap.isEmpty()) { + throw new ResourceNotFoundException("Couldn't find any Providers with given providerNpi"); + } + } else if (theParameters.getParameter(TextConstants.PATIENT_REFERENCE) != null) { + String patientId = findPatientIdByReference(theParameters); + if (StringUtils.isNotBlank(patientId)) { + patientMemberId = patientId; + if (theParameters.getParameter(TextConstants.PROVIDER_REFERENCE) != null) { + Map providerMap = findProviderIdByReference(theParameters); + if (providerMap != null && !providerMap.isEmpty()) { + for (Map.Entry entry : providerMap.entrySet()) { + attributeProviderId = entry.getValue(); + attributeProviderReferenceResource = entry.getKey(); + } + } else { + throw new ResourceNotFoundException( + "Couldn't find any Providers with given providerReference"); + } + } + String coverageId = findCoverageIdByPatientId(patientId); + if (StringUtils.isNotBlank(coverageId)) { + coverageReference = coverageId; + } + } else { + throw new ResourceNotFoundException("Couldn't find any Patient with given patientReference"); + } + } else { + throw new UnprocessableEntityException( + "Please provide memberId + providerNpi or patientReference + providerReference to $member-add."); + } + if (theParameters.getParameter(TextConstants.ATTRIBUTION_PERIOD) != null) { + attributionPeriod = (Period) theParameters.getParameter(TextConstants.ATTRIBUTION_PERIOD); + } + if (StringUtils.isNotBlank(patientMemberId)) { + logger.info(" patientMemberId :: " + patientMemberId); + logger.info(" attributeProviderId :: " + attributeProviderId); + logger.info(" attributeProviderReferenceResource :: " + attributeProviderReferenceResource); + logger.info(" coverageReference :: " + coverageReference); + if (attributionPeriod != null) { + logger.info(" attributionPeriod.getStart() :: " + attributionPeriod.getStart()); + logger.info(" attributionPeriod.getEnd() :: " + attributionPeriod.getEnd()); + } + removeMemberFromGroup(group, patientMemberId, attributeProviderId, attributeProviderReferenceResource, + coverageReference, attributionPeriod); + + groupDao.update(group); + + } else { + throw new ResourceNotFoundException("No patient found "); + } + } else { + throw new UnprocessableEntityException("No Parameters/Group Not found!"); + } + return group; + } + + public void removeMemberFromGroup(Group group, String patientMemberId, String providerId, + String providerReferenceResource, String coverageId, Period attributionPeriod){ + logger.info(" patientMemberId :: " + patientMemberId); + logger.info(" providerId :: " + providerId); + logger.info(" providerReferenceResource :: " + providerReferenceResource); + logger.info(" coverageId :: " + coverageId); + List memberList = new ArrayList<>(); + boolean isGroupMemberRemoved = false; + if (group.hasMember()) { + memberList = group.getMember(); + for (GroupMemberComponent memberGroup : new ArrayList(memberList)) { + // GroupMemberComponent memberGroup = iterator.next(); + if (memberGroup.hasEntity() && memberGroup.getEntity().hasReferenceElement()) { + String entityId = memberGroup.getEntity().getReferenceElement().getIdPart(); + logger.info(" entityId :: " + entityId); + if (patientMemberId.equalsIgnoreCase(entityId)) { + if (StringUtils.isNotBlank(providerId) && StringUtils.isNotBlank(providerReferenceResource)) { + if (memberGroup.hasExtension(TextConstants.MEMBER_PROVIDER_SYSTEM)) { + if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).hasValue()) { + Reference reference = (Reference) memberGroup + .getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).getValue(); + if (providerId.equalsIgnoreCase(reference.getReferenceElement().getIdPart()) + && providerReferenceResource.equalsIgnoreCase( + reference.getReferenceElement().getResourceType())) { + if (StringUtils.isNotBlank(coverageId)) { + if (memberGroup.hasExtension(TextConstants.MEMBER_COVERAGE_SYSTEM)) { + if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) + .hasValue()) { + Reference coverageReference = (Reference) memberGroup + .getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) + .getValue(); + if (coverageId.equalsIgnoreCase( + coverageReference.getReferenceElement().getIdPart())) { + memberList.remove(memberGroup); + isGroupMemberRemoved = true; + logger.info( + " Removing member from Group.member for memberId+providerNpi+attributionPeriod / " + + "patientReference+providerReference+attributionPeriod. patientMemberId: " + + patientMemberId + " providerId: " + providerId + + " coverageId : " + coverageId); + } else { + throw new ResourceNotFoundException( + " No coverage found for given attributionPeriod " + + coverageId); + } + } + } + } else { + memberList.remove(memberGroup); + isGroupMemberRemoved = true; + logger.info(" Removing member from Group.member for memberId+providerNpi / " + + "patientReference+providerReference. patientMemberId: " + + patientMemberId + " providerId: " + providerId); + } + } else { + throw new ResourceNotFoundException( + " No provider found for given provider " + providerId); + } + } + } + } else { + memberList.remove(memberGroup); + isGroupMemberRemoved = true; + logger.info( + " Removing member from Group.member for memberId/patientReference. patientMemberId : " + + patientMemberId); + } + break; + } + } + } + } else { + logger.error(" :: Group doesn't have any members "); + } + if (isGroupMemberRemoved) { + if (group.hasMeta()) { + if (group.getMeta().hasVersionId()) { + String versionId = group.getMeta().getVersionId(); + int version = Integer.parseInt(versionId); + version = version + 1; + group.getMeta().setVersionId(String.valueOf(version)); + + } else { + group.getMeta().setVersionId("1"); + } + } else { + Meta meta = new Meta(); + meta.setVersionId("1"); + group.setMeta(meta); + } + } else { + throw new UnprocessableEntityException("Group doesn't contain given memberId/patientReference"); + } + } +} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java b/mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java new file mode 100644 index 000000000..653d04044 --- /dev/null +++ b/mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java @@ -0,0 +1,335 @@ +package org.hl7.davinci.atr.server.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Period; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.UriType; +import org.hl7.fhir.r4.model.Group.GroupMemberComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.param.TokenParam; + +// TODO: Auto-generated Javadoc +/** + * The Class FhirUtil. + */ +public class FhirUtil { + + /** The Constant logger. */ + private static final Logger logger = LoggerFactory.getLogger(FhirUtil.class); + + /** + * Creates the token and list param. + * + * @param theParameters the the parameters + * @param parameterName the parameter name + * @return the token and list param + */ + public static TokenAndListParam createTokenAndListParam(Parameters theParameters, String parameterName) { + TokenAndListParam tokenParam = new TokenAndListParam(); + + TokenOrListParam tokenOrParam = new TokenOrListParam(); + + + Identifier memberIdentifier = (Identifier) theParameters.getParameter(parameterName); + TokenParam param = new TokenParam(); + param.setSystem(memberIdentifier.getSystem()); + param.setValue(memberIdentifier.getValue()); + tokenOrParam.add(param); + tokenParam.addValue(tokenOrParam); + + return tokenParam; + } + + + /** + * Gets the reference. + * + * @param theId the the id + * @param resourceType the resource type + * @return the reference + */ + public static Reference getReference(String theId, String resourceType) { + Reference theReference = null; + try { + if(StringUtils.isNotBlank(theId) && StringUtils.isNotBlank(resourceType)) { + StringBuilder reference = new StringBuilder(); + reference.append(resourceType); + reference.append(TextConstants.SINGLE_FORWORD_SLASH); + reference.append(theId); + theReference = initReference(theReference); + theReference.setReference(reference.toString()); + } + }catch(Exception ex) { + logger.error("\n Exception while setting getReference in FhirUtils class ", ex); + } + return theReference; + } + + /** + * Inits the reference. + * + * @param theReference the the reference + * @return the reference + */ + private static Reference initReference(Reference theReference){ + if(theReference == null) { + return new Reference(); + } + else { + return theReference; + } + } + + + /** + * Gets the code type. + * + * @param theValue the the value + * @return the code type + */ + public static CodeType getCodeType(String theValue) { + CodeType codeType = null; + try { + if(StringUtils.isNotBlank(theValue)) { + codeType = new CodeType(); + codeType.setValue(theValue); + } + }catch (Exception e) { + logger.error("Exception in getCodeType of FhirUtility ", e); + } + return codeType; + } + + + /** + * Gets the extension for code type. + * + * @param typeText the type text + * @return the extension for code type + */ + public static Extension getExtensionForCodeType(String typeText) { + Extension theExtension = null; + try { + if(StringUtils.isNotBlank(typeText)) { + theExtension = new Extension(); + UriType uri = getUriType(TextConstants.MEMBER_CHANGETYPE_SYSTEM); + theExtension.setUrlElement(uri); + CodeType theCode = getCodeType(typeText); + theExtension.setValue(theCode); + } + }catch(Exception ex) { + logger.error("\n Exception while setting getExtensionForCodeType in FhirUtility class ", ex); + } + return theExtension; + } + + /** + * Gets the extension for reference. + * + * @param id the id + * @param resourceType the resource type + * @param system the system + * @return the extension for reference + */ + public static Extension getExtensionForReference(String id, String resourceType, String system) { + Extension theExtension = null; + try { + if(StringUtils.isNotBlank(id) && StringUtils.isNotBlank(resourceType)) { + theExtension = new Extension(); + UriType uri = getUriType(system); + theExtension.setUrlElement(uri); + Reference theReference = getReference(id, resourceType); + theExtension.setValue(theReference); + } + }catch(Exception ex) { + logger.error("\n Exception while setting getExtensionForReference in FhirUtility class ", ex); + } + return theExtension; + } + + + /** + * Gets the uri type. + * + * @param theValue the the value + * @return the uri type + */ + public static UriType getUriType(String theValue) { + UriType uriType = null; + try { + if(StringUtils.isNotBlank(theValue)) { + uriType = new UriType(); + uriType.setValue(theValue); + } + }catch (Exception e) { + logger.error("Exception in getUriType of FhirUtility ", e); + } + return uriType; + } + + + /** + * Gets the boolean type. + * + * @param data the data + * @return the boolean type + */ + public static BooleanType getBooleanType(boolean data) { + BooleanType booleanType = null; + try { + booleanType = new BooleanType(); + booleanType.setValue(data); + }catch (Exception e) { + logger.error("Exception in getBooleanType of FhirUtility ", e); + } + return booleanType; + } + + + /** + * Gets the period. + * + * @param start the start + * @param end the end + * @return the period + */ + public static Period getPeriod(DateTimeType start, DateTimeType end) { + Period thePeriod = null; + try { + if(start != null) { + thePeriod=initPeriod(thePeriod); + thePeriod.setStartElement(start); + } + if(end != null) { + thePeriod=initPeriod(thePeriod); + thePeriod.setEndElement(end); + } + }catch(Exception ex) { + logger.error("\n Exception while setting getPeriod in FhirUtils class ", ex); + } + return thePeriod; + } + + + /** + * Inits the period. + * + * @param thePeriod the the period + * @return the period + */ + private static Period initPeriod(Period thePeriod){ + if(thePeriod == null) { + return new Period(); + } + else { + return thePeriod; + } + } + + + /** + * Inits the extension list. + * + * @param extensionList the extension list + * @return the list + */ + public static List initExtensionList(List extensionList) { + if(extensionList == null) { + return new ArrayList(); + } + else { + return extensionList; + } + } + + /** + * Gets the group member component. + * + * @param patientMemberId the patient member id + * @param providerId the provider id + * @param providerReference the provider reference + * @param coverageReference the coverage reference + * @param attributionPeriod the attribution period + * @return the group member component + */ + public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, String providerId, String providerReference, String coverageReference, Period attributionPeriod) { + GroupMemberComponent theGroupMemberComponent = new GroupMemberComponent(); + List theMembeEextensionList = null; + try { + if(StringUtils.isNotBlank(patientMemberId)) { + Reference theReference = getReference(patientMemberId, "Patient"); + if(theReference != null) { + theGroupMemberComponent.setEntity(theReference); + BooleanType theBoolean = getBooleanType(false); + theGroupMemberComponent.setInactiveElement(theBoolean); + } + } + theMembeEextensionList = getGroupMemberComponentExtension(providerId, providerReference, coverageReference, TextConstants.NEW_TYPE); + if(theMembeEextensionList != null && !theMembeEextensionList.isEmpty()) { + theGroupMemberComponent.setExtension(theMembeEextensionList); + } + if(attributionPeriod != null) { + Period thePeriod = getPeriod(attributionPeriod.getStartElement(), attributionPeriod.getEndElement()); + theGroupMemberComponent.setPeriod(thePeriod); + } + }catch(Exception ex) { + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + } + return theGroupMemberComponent; + } + + + /** + * Gets the group member component extension. + * + * @param providerId the provider id + * @param providerReference the provider reference + * @param coverageReference the coverage reference + * @param changeCode the change code + * @return the group member component extension + */ + public static List getGroupMemberComponentExtension(String providerId, String providerReference, + String coverageReference, String changeCode) { + List theMembeEextensionList = null; + try { + if(StringUtils.isNotBlank(changeCode)) { + Extension codeExtension = FhirUtil.getExtensionForCodeType(changeCode); + if(codeExtension != null) { + theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); + theMembeEextensionList.add(codeExtension); + } + } + if(StringUtils.isNotBlank(coverageReference)) { + Extension coverageExtension = FhirUtil.getExtensionForReference(coverageReference, "Coverage", TextConstants.MEMBER_COVERAGE_SYSTEM); + if(coverageExtension != null) { + theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); + theMembeEextensionList.add(coverageExtension); + } + } + if(StringUtils.isNotBlank(providerId) && StringUtils.isNotBlank(providerReference)) { + Extension providerExtension = FhirUtil.getExtensionForReference(providerId, providerReference, TextConstants.MEMBER_PROVIDER_SYSTEM); + if(providerExtension != null) { + theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); + theMembeEextensionList.add(providerExtension); + } + } + }catch(Exception ex) { + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + } + return theMembeEextensionList; + } + +} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java b/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java new file mode 100644 index 000000000..19a6a25e9 --- /dev/null +++ b/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java @@ -0,0 +1,53 @@ +package org.hl7.davinci.atr.server.util; + +// TODO: Auto-generated Javadoc +/** + * The Class TextConstants. + */ +public final class TextConstants { + + /** + * Instantiates a new text constants. + */ + private TextConstants(){ + } + + /** The Constant SINGLE_FORWORD_SLASH. */ + public static final String SINGLE_FORWORD_SLASH="/"; + + /** The Constant MEMBER_ID. */ + public static final String MEMBER_ID="memberId"; + + /** The Constant PROVIDER_NPI. */ + public static final String PROVIDER_NPI="providerNpi"; + + /** The Constant PATIENT_REFERENCE. */ + public static final String PATIENT_REFERENCE="patientReference"; + + /** The Constant PROVIDER_REFERENCE. */ + public static final String PROVIDER_REFERENCE="providerReference"; + + /** The Constant ATTRIBUTION_PERIOD. */ + public static final String ATTRIBUTION_PERIOD="attributionPeriod"; + + /** The Constant MEMBER_CHANGETYPE_SYSTEM. */ + public static final String MEMBER_CHANGETYPE_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-changeType"; + + /** The Constant MEMBER_COVERAGE_SYSTEM. */ + public static final String MEMBER_COVERAGE_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-coverageReference"; + + /** The Constant MEMBER_PROVIDER_SYSTEM. */ + public static final String MEMBER_PROVIDER_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-attributedProvider"; + + /** The Constant NEW_TYPE. */ + public static final String NEW_TYPE="new"; + + /** The Constant CHANGE_TYPE. */ + public static final String CHANGE_TYPE="change"; + + /** The Constant NOCHANGE_TYPE. */ + public static final String NOCHANGE_TYPE="nochange"; + + /** The Constant HTTP_POST. */ + public static final String HTTP_POST="POST"; +} diff --git a/mal/src/main/resources/META-INF/spring.factories b/mal/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..7c49745fc --- /dev/null +++ b/mal/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.hl7.davinci.atr.server.MALConfig diff --git a/mal/src/main/resources/application.yaml b/mal/src/main/resources/application.yaml new file mode 100644 index 000000000..8eb127206 --- /dev/null +++ b/mal/src/main/resources/application.yaml @@ -0,0 +1,3 @@ +hello: + world: + message: Hello \ No newline at end of file diff --git a/pom.xml b/pom.xml index cdf298d96..dc99eb98f 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ example + mal external test core diff --git a/server/pom.xml b/server/pom.xml index 9b41ec5b5..fb5c383b9 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -277,6 +277,12 @@ 0.5.0-SNAPSHOT runtime + + org.hl7.davinci.atr.server + cqf-ruler-plugin-mal + 1.0.0 + runtime + org.opencds.cqf.ruler cqf-ruler-ra diff --git a/server/src/main/resources/application.yaml b/server/src/main/resources/application.yaml index 920976c08..962140dd7 100644 --- a/server/src/main/resources/application.yaml +++ b/server/src/main/resources/application.yaml @@ -3,18 +3,19 @@ spring: main: allow-bean-definition-overriding: true datasource: - url: "jdbc:h2:file:./target/database/h2" + url: "jdbc:postgresql://localhost:5432/hapi_r4" #url: jdbc:h2:mem:test_mem - username: sa - password: null - driverClassName: org.h2.Driver + username: postgres + password: postgres + driverClassName: org.postgresql.Driver max-active: 15 jpa: properties: hibernate.format_sql: false hibernate.show_sql: false + #hibernate.packages-Scan: org.hl7.davinci.atr.server.model # hibernate.dialect: org.hibernate.dialect.h2dialect - # hibernate.hbm2ddl.auto: update + #hibernate.hbm2ddl.auto: create # hibernate.jdbc.batch_size: 20 # hibernate.cache.use_query_cache: false # hibernate.cache.use_second_level_cache: false @@ -117,7 +118,7 @@ hapi: # requests_enabled: true # responses_enabled: true # binary_storage_enabled: true - # bulk_export_enabled: true + bulk_export_enabled: true # subscription: # resthook_enabled: false # websocket_enabled: false From e4f324719ec28f6d485bf6b4a0271d4352c8228f Mon Sep 17 00:00:00 2001 From: Raghunath Sandilya Date: Tue, 3 May 2022 15:30:22 +0530 Subject: [PATCH 2/6] Added Postman Collection --- mal/MAL-API's.postman_collection.json | 248 +++++++++++++++++++++ mal/README.md | 17 +- server/src/main/resources/application.yaml | 10 +- 3 files changed, 257 insertions(+), 18 deletions(-) create mode 100644 mal/MAL-API's.postman_collection.json diff --git a/mal/MAL-API's.postman_collection.json b/mal/MAL-API's.postman_collection.json new file mode 100644 index 000000000..9507e3cb4 --- /dev/null +++ b/mal/MAL-API's.postman_collection.json @@ -0,0 +1,248 @@ +{ + "info": { + "_postman_id": "aaf26af2-af7c-415a-b535-d0d938b5d838", + "name": "MAL-API's", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "POST Bundle", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceType\": \"Bundle\",\r\n \"id\": \"member-attribution-bundle\",\r\n \"type\": \"transaction\",\r\n \"entry\": [\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Patient\",\r\n \"id\": \"denom-EXM130\",\r\n \"meta\": {\r\n \"versionId\": \"3\",\r\n \"lastUpdated\": \"2019-04-23T10:30:54.819-04:00\",\r\n \"tag\": [\r\n {\r\n \"system\": \"https://smarthealthit.org/tags\",\r\n \"code\": \"smart-7-2017\"\r\n }\r\n ]\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
Dominique369 Ledner144
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MC\",\r\n \"display\": \"Patient's Medicare number\"\r\n }\r\n ],\r\n \"text\": \"Patient's Medicare number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"12345\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MA\",\r\n \"display\": \"Patient Medicaid number\"\r\n }\r\n ],\r\n \"text\": \"Patient Medicaid number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"67890\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MR\",\r\n \"display\": \"Medical record number\"\r\n }\r\n ],\r\n \"text\": \"Medical record number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"55555\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ],\r\n \"text\": \"Member Number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"13579\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"SS\",\r\n \"display\": \"Social Security number\"\r\n }\r\n ],\r\n \"text\": \"Social Security number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"99999\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Ledner144\",\r\n \"given\": [\r\n \"Dominique369\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"800-504-7344\",\r\n \"use\": \"home\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"brian.gracia@example.com\"\r\n }\r\n ],\r\n \"gender\": \"female\",\r\n \"birthDate\": \"1965-06-22\",\r\n \"deceasedBoolean\": false,\r\n \"address\": [\r\n {\r\n \"use\": \"home\",\r\n \"line\": [\r\n \"25 Church St\"\r\n ],\r\n \"city\": \"Bixby\",\r\n \"state\": \"OK\",\r\n \"postalCode\": \"74008\",\r\n \"country\": \"USA\"\r\n }\r\n ],\r\n \"maritalStatus\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://snomed.info/sct\",\r\n \"code\": \"36629006\",\r\n \"display\": \"Legally married\"\r\n },\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-MaritalStatus\",\r\n \"code\": \"M\"\r\n }\r\n ]\r\n },\r\n \"communication\": [\r\n {\r\n \"language\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"urn:ietf:bcp:47\",\r\n \"code\": \"nl-NL\",\r\n \"display\": \"Dutch\"\r\n }\r\n ]\r\n },\r\n \"preferred\": true\r\n }\r\n ],\r\n \"generalPractitioner\": [\r\n {\r\n \"reference\": \"Practitioner/9bf77508-42d8-420f-a371-88ec287cc55d\"\r\n }\r\n ],\r\n \"managingOrganization\": {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\",\r\n \"display\": \"ACME Healthcare, Inc\"\r\n }\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Patient/denom-EXM130\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Patient\",\r\n \"id\": \"5f355ff8-9f2d-4047-b3dd-91a9a5e75bd8\",\r\n \"meta\": {\r\n \"versionId\": \"2\",\r\n \"lastUpdated\": \"2018-04-25T02:41:21.772-04:00\",\r\n \"tag\": [\r\n {\r\n \"system\": \"https://smarthealthit.org/tags\",\r\n \"code\": \"smart-7-2017\"\r\n }\r\n ]\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
Emilie407 Cole117
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MC\",\r\n \"display\": \"Patient's Medicare number\"\r\n }\r\n ],\r\n \"text\": \"Patient's Medicare number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"54321\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MA\",\r\n \"display\": \"Patient Medicaid number\"\r\n }\r\n ],\r\n \"text\": \"Patient Medicaid number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"09876\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MR\",\r\n \"display\": \"Medical record number\"\r\n }\r\n ],\r\n \"text\": \"Medical record number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"56565\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ],\r\n \"text\": \"Member Number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"909012\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"SS\",\r\n \"display\": \"Social Security number\"\r\n }\r\n ],\r\n \"text\": \"Social Security number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"321456\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Cole117\",\r\n \"given\": [\r\n \"Emilie407\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"31612345678\",\r\n \"use\": \"mobile\"\r\n },\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"31201234567\",\r\n \"use\": \"home\"\r\n }\r\n ],\r\n \"gender\": \"male\",\r\n \"birthDate\": \"1950-07-06\",\r\n \"deceasedBoolean\": false,\r\n \"address\": [\r\n {\r\n \"use\": \"home\",\r\n \"line\": [\r\n \"Bos en Lommerplein 280\"\r\n ],\r\n \"city\": \"Amsterdam\",\r\n \"state\": \"RJ\",\r\n \"postalCode\": \"1055\",\r\n \"country\": \"NLD\"\r\n }\r\n ],\r\n \"maritalStatus\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://snomed.info/sct\",\r\n \"code\": \"36629006\",\r\n \"display\": \"Legally married\"\r\n },\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-MaritalStatus\",\r\n \"code\": \"M\"\r\n }\r\n ]\r\n },\r\n \"communication\": [\r\n {\r\n \"language\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"urn:ietf:bcp:47\",\r\n \"code\": \"nl\",\r\n \"display\": \"Dutch\"\r\n }\r\n ],\r\n \"text\": \"Nederlands\"\r\n },\r\n \"preferred\": true\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Patient/5f355ff8-9f2d-4047-b3dd-91a9a5e75bd8\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Patient\",\r\n \"id\": \"d3457d45-9085-4572-a78d-ed69c35d0d13\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2018-04-25T02:41:22.204-04:00\",\r\n \"tag\": [\r\n {\r\n \"system\": \"https://smarthealthit.org/tags\",\r\n \"code\": \"smart-7-2017\"\r\n }\r\n ]\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
Malcolm243 Erdman779
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MC\",\r\n \"display\": \"Patient's Medicare number\"\r\n }\r\n ],\r\n \"text\": \"Patient's Medicare number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"907861\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MA\",\r\n \"display\": \"Patient Medicaid number\"\r\n }\r\n ],\r\n \"text\": \"Patient Medicaid number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"786543\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MR\",\r\n \"display\": \"Medical record number\"\r\n }\r\n ],\r\n \"text\": \"Medical record number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"765432\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ],\r\n \"text\": \"Member Number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"786778\"\r\n },\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"SS\",\r\n \"display\": \"Social Security number\"\r\n }\r\n ],\r\n \"text\": \"Social Security number\"\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"451231\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Erdman779\",\r\n \"given\": [\r\n \"Malcolm243\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"800-613-1713\",\r\n \"use\": \"mobile\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"carol.allen@example.com\"\r\n }\r\n ],\r\n \"gender\": \"female\",\r\n \"birthDate\": \"1963-12-26\",\r\n \"deceasedBoolean\": false,\r\n \"address\": [\r\n {\r\n \"use\": \"home\",\r\n \"line\": [\r\n \"67 Meadow St\"\r\n ],\r\n \"city\": \"Sapulpa\",\r\n \"state\": \"OK\",\r\n \"postalCode\": \"74066\",\r\n \"country\": \"USA\"\r\n }\r\n ],\r\n \"maritalStatus\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-MaritalStatus\",\r\n \"code\": \"M\",\r\n \"display\": \"Married\"\r\n }\r\n ],\r\n \"text\": \"Getrouwd\"\r\n },\r\n \"communication\": [\r\n {\r\n \"language\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"urn:ietf:bcp:47\",\r\n \"code\": \"nl-NL\",\r\n \"display\": \"Dutch\"\r\n }\r\n ]\r\n },\r\n \"preferred\": true\r\n }\r\n ],\r\n \"managingOrganization\": {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\",\r\n \"display\": \"ACME Healthcare, Inc\"\r\n }\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Patient/d3457d45-9085-4572-a78d-ed69c35d0d13\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Practitioner\",\r\n \"id\": \"9bf77508-42d8-420f-a371-88ec287cc55d\",\r\n \"meta\": {\r\n \"versionId\": \"4\",\r\n \"lastUpdated\": \"2019-03-06T03:07:57.933-05:00\",\r\n \"tag\": [\r\n {\r\n \"system\": \"https://smarthealthit.org/tags\",\r\n \"code\": \"smart-7-2017\"\r\n }\r\n ]\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
Joseph Nichols
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://hl7.org/fhir/identifier-type\",\r\n \"code\": \"SB\",\r\n \"display\": \"Social Beneficiary Identifier\"\r\n }\r\n ],\r\n \"text\": \"US Social Security Number\"\r\n },\r\n \"system\": \"http://hl7.org/fhir/sid/us-ssn\",\r\n \"value\": \"000-00-0004\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Nichols\",\r\n \"given\": [\r\n \"Joseph\",\r\n \"P\"\r\n ],\r\n \"suffix\": [\r\n \"MD\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"800-277-1993\",\r\n \"use\": \"mobile\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"joseph.shaw@example.com\"\r\n }\r\n ],\r\n \"address\": [\r\n {\r\n \"use\": \"home\",\r\n \"line\": [\r\n \"53 Sunset AveApt 9\"\r\n ],\r\n \"city\": \"Tulsa\",\r\n \"state\": \"OK\",\r\n \"postalCode\": \"74126\",\r\n \"country\": \"USA\"\r\n }\r\n ],\r\n \"gender\": \"male\",\r\n \"birthDate\": \"1963-12-14\"\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Practitioner/9bf77508-42d8-420f-a371-88ec287cc55d\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"RelatedPerson\",\r\n \"id\": \"b2cf72e8-62c2-4a61-a2b9-dcf90094aae7\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-04-23T10:30:54.819-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
NameB�n�dicte du March�
Address43, Place du March� Sainte Catherine, 75004 Paris, France
ContactsPhone: +33 (237) 998327
\\n
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"NPI\",\r\n \"display\": \"National Provider Identifier\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"1256\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"patient\": {\r\n \"reference\": \"Patient/d3457d45-9085-4572-a78d-ed69c35d0d13\"\r\n },\r\n \"relationship\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0131\",\r\n \"code\": \"N\",\r\n \"display\": \"Next-of-Kin\"\r\n },\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-RoleCode\",\r\n \"code\": \"WIFE\",\r\n \"display\": \"wife\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Notsowell\",\r\n \"given\": [\r\n \"Simon\"\r\n ],\r\n \"prefix\": [\r\n \"Mr.\"\r\n ],\r\n \"suffix\": [\r\n \"MSc\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"+33 (237) 998327\"\r\n }\r\n ],\r\n \"gender\": \"female\",\r\n \"address\": [\r\n {\r\n \"line\": [\r\n \"43, Place du March� Sainte Catherine\"\r\n ],\r\n \"city\": \"Paris\",\r\n \"postalCode\": \"75004\",\r\n \"country\": \"FRA\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"RelatedPerson/b2cf72e8-62c2-4a61-a2b9-dcf90094aae7\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"RelatedPerson\",\r\n \"id\": \"65b8aaa8-697a-43a9-8f6e-5615ecad344a\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-04-23T10:30:54.819-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
NameB�n�dicte du March�
Address43, Place du March� Sainte Catherine, 75004 Paris, France
ContactsPhone: +33 (237) 998327
\\n
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"NPI\",\r\n \"display\": \"National Provider Identifier\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"5678\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"patient\": {\r\n \"reference\": \"Patient/5f355ff8-9f2d-4047-b3dd-91a9a5e75bd8\"\r\n },\r\n \"relationship\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0131\",\r\n \"code\": \"N\",\r\n \"display\": \"Next-of-Kin\"\r\n },\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-RoleCode\",\r\n \"code\": \"WIFE\",\r\n \"display\": \"wife\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Duck\",\r\n \"given\": [\r\n \"Donald\"\r\n ],\r\n \"prefix\": [\r\n \"Mr.\"\r\n ],\r\n \"suffix\": [\r\n \"MSc\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"+33 (237) 998327\"\r\n }\r\n ],\r\n \"gender\": \"female\",\r\n \"address\": [\r\n {\r\n \"line\": [\r\n \"43, Place du March� Sainte Catherine\"\r\n ],\r\n \"city\": \"Paris\",\r\n \"postalCode\": \"75004\",\r\n \"country\": \"FRA\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"RelatedPerson/65b8aaa8-697a-43a9-8f6e-5615ecad344a\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"RelatedPerson\",\r\n \"id\": \"074c4667-06e5-409b-a4ae-335c83fe6ed5\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-04-23T10:30:54.819-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
NameB�n�dicte du March�
Address43, Place du March� Sainte Catherine, 75004 Paris, France
ContactsPhone: +33 (237) 998327
\\n
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"NPI\",\r\n \"display\": \"National Provider Identifier\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"1234\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"patient\": {\r\n \"reference\": \"Patient/denom-EXM130\"\r\n },\r\n \"relationship\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0131\",\r\n \"code\": \"N\",\r\n \"display\": \"Next-of-Kin\"\r\n },\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v3-RoleCode\",\r\n \"code\": \"WIFE\",\r\n \"display\": \"wife\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"name\": [\r\n {\r\n \"use\": \"official\",\r\n \"family\": \"Douglas\",\r\n \"given\": [\r\n \"Bradly\"\r\n ],\r\n \"prefix\": [\r\n \"Mr.\"\r\n ],\r\n \"suffix\": [\r\n \"MSc\"\r\n ]\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"+33 (237) 998327\"\r\n }\r\n ],\r\n \"gender\": \"female\",\r\n \"address\": [\r\n {\r\n \"line\": [\r\n \"43, Place du March� Sainte Catherine\"\r\n ],\r\n \"city\": \"Paris\",\r\n \"postalCode\": \"75004\",\r\n \"country\": \"FRA\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"RelatedPerson/074c4667-06e5-409b-a4ae-335c83fe6ed5\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Coverage\",\r\n \"id\": \"c8e3f0b5-0599-43ba-ab90-792c127819a1\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-05-06T03:04:12.348-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
A human-readable rendering of the coverage
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ]\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"786778\"\r\n }\r\n ],\r\n \"status\": \"active\",\r\n \"policyHolder\": {\r\n \"reference\": \"RelatedPerson/b2cf72e8-62c2-4a61-a2b9-dcf90094aae7\"\r\n },\r\n \"subscriber\": {\r\n \"reference\": \"Patient/d3457d45-9085-4572-a78d-ed69c35d0d13\"\r\n },\r\n \"subscriberId\": \"AB3658\",\r\n \"beneficiary\": {\r\n \"reference\": \"Patient/d3457d45-9085-4572-a78d-ed69c35d0d13\"\r\n },\r\n \"dependent\": \"0\",\r\n \"relationship\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/subscriber-relationship\",\r\n \"code\": \"self\",\r\n \"display\": \"Self\"\r\n }\r\n ]\r\n },\r\n \"period\": {\r\n \"start\": \"2013-05-23\",\r\n \"end\": \"2014-05-23\"\r\n },\r\n \"payor\": [\r\n {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\"\r\n }\r\n ],\r\n \"class\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/coverage-class\",\r\n \"code\": \"plan\"\r\n }\r\n ]\r\n },\r\n \"value\": \"B37FC\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Coverage/074c4667-06e5-409b-a4ae-335c83fe6ed5\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Coverage\",\r\n \"id\": \"9bf7ab75-3ead-4a90-8409-eade27aa9008\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-04-06T03:04:12.348-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
A human-readable rendering of the coverage
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ]\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"909012\"\r\n }\r\n ],\r\n \"status\": \"active\",\r\n \"policyHolder\": {\r\n \"reference\": \"RelatedPerson/65b8aaa8-697a-43a9-8f6e-5615ecad344a\"\r\n },\r\n \"subscriber\": {\r\n \"reference\": \"Patient/5f355ff8-9f2d-4047-b3dd-91a9a5e75bd8\"\r\n },\r\n \"subscriberId\": \"AB3999\",\r\n \"beneficiary\": {\r\n \"reference\": \"Patient/5f355ff8-9f2d-4047-b3dd-91a9a5e75bd8\"\r\n },\r\n \"dependent\": \"0\",\r\n \"relationship\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/subscriber-relationship\",\r\n \"code\": \"self\",\r\n \"display\": \"Self\"\r\n }\r\n ]\r\n },\r\n \"period\": {\r\n \"start\": \"2012-05-23\",\r\n \"end\": \"2013-05-23\"\r\n },\r\n \"payor\": [\r\n {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\"\r\n }\r\n ],\r\n \"class\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/coverage-class\",\r\n \"code\": \"plan\"\r\n }\r\n ]\r\n },\r\n \"value\": \"B37FC\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Coverage/9bf7ab75-3ead-4a90-8409-eade27aa9008\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Coverage\",\r\n \"id\": \"b66b770a-66da-4330-8463-cd0e93ef6626\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-06-06T03:04:12.348-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
A human-readable rendering of the coverage
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"MB\",\r\n \"display\": \"Member Number\"\r\n }\r\n ]\r\n },\r\n \"system\": \"http://hospital.smarthealthit.org\",\r\n \"value\": \"13579\"\r\n }\r\n ],\r\n \"status\": \"active\",\r\n \"policyHolder\": {\r\n \"reference\": \"RelatedPerson/074c4667-06e5-409b-a4ae-335c83fe6ed5\"\r\n },\r\n \"subscriber\": {\r\n \"reference\": \"Patient/denom-EXM130\"\r\n },\r\n \"subscriberId\": \"AB3658\",\r\n \"beneficiary\": {\r\n \"reference\": \"Patient/denom-EXM130\"\r\n },\r\n \"dependent\": \"0\",\r\n \"relationship\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/subscriber-relationship\",\r\n \"code\": \"self\",\r\n \"display\": \"Self\"\r\n }\r\n ]\r\n },\r\n \"period\": {\r\n \"start\": \"2011-05-23\",\r\n \"end\": \"2012-05-23\"\r\n },\r\n \"payor\": [\r\n {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\"\r\n }\r\n ],\r\n \"class\": [\r\n {\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/coverage-class\",\r\n \"code\": \"plan\"\r\n }\r\n ]\r\n },\r\n \"value\": \"B37FC\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Coverage/b66b770a-66da-4330-8463-cd0e93ef6626\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Location\",\r\n \"id\": \"66584742-6b72-432c-9439-1478434607fa\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-06-06T03:04:12.348-04:00\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"PIN\",\r\n \"display\": \"Premises Identifier Number\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"1233\"\r\n }\r\n ],\r\n \"status\": \"active\",\r\n \"operationalStatus\": {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0116\",\r\n \"code\": \"H\",\r\n \"display\": \"Housekeeping\"\r\n },\r\n \"name\": \"South Wing, second floor\",\r\n \"alias\": [\r\n \"BU MC, SW, F2\",\r\n \"Burgers University Medical Center, South Wing, second floor\"\r\n ],\r\n \"description\": \"Second floor of the Old South Wing, formerly in use by Psychiatry\",\r\n \"mode\": \"instance\",\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"2328\",\r\n \"use\": \"work\"\r\n },\r\n {\r\n \"system\": \"fax\",\r\n \"value\": \"2329\",\r\n \"use\": \"work\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"second wing admissions\"\r\n },\r\n {\r\n \"system\": \"url\",\r\n \"value\": \"http://sampleorg.com/southwing\",\r\n \"use\": \"work\"\r\n }\r\n ],\r\n \"address\": {\r\n \"use\": \"work\",\r\n \"line\": [\r\n \"Galapagosweg 91, Building A\"\r\n ],\r\n \"city\": \"Den Burg\",\r\n \"state\": \"MD\",\r\n \"postalCode\": \"9105 PZ\",\r\n \"country\": \"NLD\"\r\n },\r\n \"physicalType\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/location-physical-type\",\r\n \"code\": \"wi\",\r\n \"display\": \"Wing\"\r\n }\r\n ]\r\n },\r\n \"position\": {\r\n \"longitude\": -83.6945691,\r\n \"latitude\": 42.25475478,\r\n \"altitude\": 0\r\n },\r\n \"managingOrganization\": {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\"\r\n },\r\n \"endpoint\": [\r\n {\r\n \"reference\": \"Endpoint/example\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Location/66584742-6b72-432c-9439-1478434607fa\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"PractitionerRole\",\r\n \"id\": \"c6e70834-8d30-419e-b7c5-7150a9e9127e\",\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
\\n\\t\\t\\t

\\n\\t\\t\\t\\tDr Adam Careful is a Referring Practitioner for Acme Hospital from 1-Jan 2012 to 31-Mar\\n\\t\\t\\t\\t2012\\n\\t\\t\\t

\\n\\t\\t
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"system\": \"http://www.acme.org/practitioners\",\r\n \"value\": \"23\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"period\": {\r\n \"start\": \"2012-01-01\",\r\n \"end\": \"2012-03-31\"\r\n },\r\n \"practitioner\": {\r\n \"reference\": \"Practitioner/9bf77508-42d8-420f-a371-88ec287cc55d\",\r\n \"display\": \"Dr Adam Careful\"\r\n },\r\n \"organization\": {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\"\r\n },\r\n \"code\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0286\",\r\n \"code\": \"RP\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"specialty\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://snomed.info/sct\",\r\n \"code\": \"408443003\",\r\n \"display\": \"General medical practice\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"location\": [\r\n {\r\n \"reference\": \"Location/66584742-6b72-432c-9439-1478434607fa\",\r\n \"display\": \"South Wing, second floor\"\r\n }\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"(03) 5555 6473\",\r\n \"use\": \"work\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"adam.southern@example.org\",\r\n \"use\": \"work\"\r\n }\r\n ],\r\n \"availableTime\": [\r\n {\r\n \"daysOfWeek\": [\r\n \"mon\",\r\n \"tue\",\r\n \"wed\"\r\n ],\r\n \"availableStartTime\": \"09:00:00\",\r\n \"availableEndTime\": \"16:30:00\"\r\n },\r\n {\r\n \"daysOfWeek\": [\r\n \"thu\",\r\n \"fri\"\r\n ],\r\n \"availableStartTime\": \"09:00:00\",\r\n \"availableEndTime\": \"12:00:00\"\r\n }\r\n ],\r\n \"notAvailable\": [\r\n {\r\n \"description\": \"Adam will be on extended leave during May 2017\",\r\n \"during\": {\r\n \"start\": \"2017-05-01\",\r\n \"end\": \"2017-05-20\"\r\n }\r\n }\r\n ],\r\n \"availabilityExceptions\": \"Adam is generally unavailable on public holidays and during the Christmas/New Year break\",\r\n \"endpoint\": [\r\n {\r\n \"reference\": \"Endpoint/example\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"PractitionerRole/c6e70834-8d30-419e-b7c5-7150a9e9127e\"\r\n }\r\n },\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Organization\",\r\n \"id\": \"9118ee2c-9f6d-4a40-9988-4f26ff766864\",\r\n \"meta\": {\r\n \"versionId\": \"1\"\r\n },\r\n \"text\": {\r\n \"status\": \"generated\",\r\n \"div\": \"
\\n Health Level Seven International\\n
\\n\\t\\t\\t\\t3300 Washtenaw Avenue, Suite 227\\n
\\n\\t\\t\\t\\tAnn Arbor, MI 48104\\n
\\n\\t\\t\\t\\tUSA\\n
\\n\\t\\t\\t\\t(+1) 734-677-7777 (phone)\\n
\\n\\t\\t\\t\\t(+1) 734-677-6622 (fax)\\n
\\n\\t\\t\\t\\tE-mail: \\n hq@HL7.org\\n \\n
\"\r\n },\r\n \"identifier\": [\r\n {\r\n \"system\": \"http://www.acme.org.au/units\",\r\n \"value\": \"ClinLab\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"type\": [\r\n {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/organization-type\",\r\n \"code\": \"dept\",\r\n \"display\": \"Hospital Department\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"name\": \"Health Level Seven International\",\r\n \"alias\": [\r\n \"HL7 International\"\r\n ],\r\n \"telecom\": [\r\n {\r\n \"system\": \"phone\",\r\n \"value\": \"(+1) 734-677-7777\"\r\n },\r\n {\r\n \"system\": \"fax\",\r\n \"value\": \"(+1) 734-677-6622\"\r\n },\r\n {\r\n \"system\": \"email\",\r\n \"value\": \"hq@HL7.org\"\r\n }\r\n ],\r\n \"address\": [\r\n {\r\n \"line\": [\r\n \"3300 Washtenaw Avenue, Suite 227\"\r\n ],\r\n \"district\": \"Ann Arbor\",\r\n \"state\": \"MI\",\r\n \"postalCode\": \"48104\",\r\n \"country\": \"USA\"\r\n }\r\n ],\r\n \"endpoint\": [\r\n {\r\n \"reference\": \"Endpoint/example\"\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Organization/9118ee2c-9f6d-4a40-9988-4f26ff766864\"\r\n }\r\n }\r\n ]\r\n}" + }, + "url": { + "raw": "http://localhost:8080/fhir", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir" + ] + } + }, + "response": [] + }, + { + "name": "POST Group", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceType\": \"Bundle\",\r\n \"id\": \"member-attribution-group\",\r\n \"type\": \"transaction\",\r\n \"entry\": [\r\n {\r\n \"resource\": {\r\n \"resourceType\": \"Group\",\r\n \"id\": \"atr-group\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2019-06-06T03:04:12.348-04:00\"\r\n },\r\n \"text\": {\r\n \"status\": \"additional\",\r\n \"div\": \"
\\n

Selected Patients

\\n
    \\n
  • Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321
  • \\n
  • Patient Donald D DUCK @ Acme Healthcare, Inc. MR = 123456
  • \\n
  • Patient Simon Notsowell @ Acme Healthcare, Inc. MR = 123457, DECEASED
  • \\n
  • Patient Sandy Notsowell @ Acme Healthcare, Inc. MR = 123458, DECEASED
  • \\n
\\n
\"\r\n },\r\n \"extension\": [\r\n {\r\n \"url\": \"http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-membershipValidityPeriod\",\r\n \"valuePeriod\": {\r\n \"start\": \"2020-07-25\",\r\n \"end\": \"2021-06-24\"\r\n }\r\n }\r\n ],\r\n \"identifier\": [\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"NPI\",\r\n \"display\": \"National Provider Identifier\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"1316206220\"\r\n },\r\n {\r\n \"use\": \"official\",\r\n \"type\": {\r\n \"coding\": [\r\n {\r\n \"system\": \"http://terminology.hl7.org/CodeSystem/v2-0203\",\r\n \"code\": \"TAX\",\r\n \"display\": \"Tax ID Number\"\r\n }\r\n ]\r\n },\r\n \"system\": \"https://sitenv.org\",\r\n \"value\": \"789456231\"\r\n }\r\n ],\r\n \"active\": true,\r\n \"type\": \"person\",\r\n \"actual\": true,\r\n \"name\": \"Test Group 3\",\r\n \"managingEntity\": {\r\n \"reference\": \"Organization/6c9380b5-2d9d-4675-89a1-f7048486a2f4\",\r\n \"display\": \"Healthcare related organization\"\r\n },\r\n \"characteristic\": [\r\n {\r\n \"code\": {\r\n \"text\": \"gender\"\r\n },\r\n \"valueReference\": {\r\n \"reference\": \"Organzation/6c9380b5-2d9d-4675-89a1-f7048486a2f4\",\r\n \"display\": \"Healthcare related organization\"\r\n },\r\n \"exclude\": false\r\n }\r\n ]\r\n },\r\n \"request\": {\r\n \"method\": \"PUT\",\r\n \"url\": \"Group/atr-group\"\r\n }\r\n }\r\n ]\r\n}" + }, + "url": { + "raw": "http://localhost:8080/fhir", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir" + ] + } + }, + "response": [] + }, + { + "name": "Group Member Add", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/fhir+json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n\t\"resourceType\": \"Parameters\",\r\n\t\"parameter\": [{\r\n\t\t\"name\": \"memberId\",\r\n\t\t\"valueIdentifier\": {\r\n\t\t\t\"system\": \"http://hospital.smarthealthit.org\",\r\n\t\t\t\"value\": \"13579\"\r\n\t\t}\r\n\t}, {\r\n\t\t\"name\": \"providerNpi\",\r\n\t\t\"valueIdentifier\": {\r\n\t\t\t\"system\": \"http://hl7.org/fhir/sid/us-ssn\",\r\n\t\t\t\"value\": \"000-00-0004\"\r\n\t\t}\r\n\t}, {\r\n\t\t\"name\": \"attributionPeriod\",\r\n\t\t\"valuePeriod\": {\r\n\t\t\t\"start\": \"2014-10-08T07:06:17+00:00\",\r\n\t\t\t\"end\": \"2025-10-08T07:06:17+00:00\"\r\n\t\t}\r\n\t}]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/fhir/Group/atr-group/$member-add", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir", + "Group", + "atr-group", + "$member-add" + ] + } + }, + "response": [] + }, + { + "name": "Group Member Remove", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/fhir+json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n\t\"resourceType\": \"Parameters\",\r\n\t\"parameter\": [{\r\n\t\t\"name\": \"memberId\",\r\n\t\t\"valueIdentifier\": {\r\n\t\t\t\"system\": \"http://hospital.smarthealthit.org\",\r\n\t\t\t\"value\": \"786778\"\r\n\t\t}\r\n\t}, {\r\n\t\t\"name\": \"providerNpi\",\r\n\t\t\"valueIdentifier\": {\r\n\t\t\t\"system\": \"http://hl7.org/fhir/sid/us-ssn\",\r\n\t\t\t\"value\": \"000-00-0004\"\r\n\t\t}\r\n\t}, {\r\n\t\t\"name\": \"attributionPeriod\",\r\n\t\t\"valuePeriod\": {\r\n\t\t\t\"start\": \"2016-09-02T07:06:17+00:00\",\r\n\t\t\t\"end\": \"2022-05-10T07:06:17+00:00\"\r\n\t\t}\r\n\t}]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/fhir/Group/atr-group/$member-remove", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir", + "Group", + "atr-group", + "$member-remove" + ] + } + }, + "response": [] + }, + { + "name": "Group-Export", + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/fhir+json", + "type": "text" + }, + { + "key": "Prefer", + "value": "respond-async", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8080/fhir/Group/atr-group/$export?_type=Patient,Coverage,RelatedPerson", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir", + "Group", + "atr-group", + "$export" + ], + "query": [ + { + "key": "_type", + "value": "Patient,Coverage,RelatedPerson" + } + ] + } + }, + "response": [] + }, + { + "name": "Polling-Location", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/fhir/$export-poll-status?_jobId=0c52c5d4-475e-48b3-8296-e059a60dcd00", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir", + "$export-poll-status" + ], + "query": [ + { + "key": "_jobId", + "value": "0c52c5d4-475e-48b3-8296-e059a60dcd00" + } + ] + } + }, + "response": [] + }, + { + "name": "Download-NDJSON", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/fhir/Binary/17", + "protocol": "http", + "host": [ + "52", + "70", + "192", + "201" + ], + "port": "8080", + "path": [ + "fhir", + "Binary", + "17" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/mal/README.md b/mal/README.md index 89a5877c0..14349bb02 100644 --- a/mal/README.md +++ b/mal/README.md @@ -1,23 +1,14 @@ # Plugin -This is a sample project demonstrating how to create a cqf-ruler plugin. +This is the repository for reference implementation of the DaVinci Risk Based Contracts Member Attribution List project. ## Setup -cqf-ruler plugins rely heavily on Spring auto-configuration. On startup the server looks for the `resources/META_INF/spring.factories` file in all the jars on the classpath. The contents of that file point to a root Spring configuration class that defines all the beans for the plugin. For example: +To setup the project follow the instructions mentioned [here](https://github.com/DBCG/cqf-ruler#development) -```ini -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.example.HelloWorldConfig -``` +## Usage -This tells Spring to load the config described in the HelloWorldConfig class. The cqf-ruler then loads and registers Providers, Interceptors, and Metadata extenders as built by the Spring config. It's possible to create other Beans as well. - -The `pom.xml` file in this project describes the minimal set of dependencies to get a plugin going. Any dependency provided by the base server needs to be scoped `provided` so that it's not duplicated. - -This system is very basic. It does not support runtime addition or removal of plugins, or plugin versions, or any sort of conflict resolution. Plugins are expected to be well-behaved in that they will only create Beans appropriate for the server configuration that is running. For example, a plugin will not create a DSTU3-only bean when the server is running in R4 mode. Please use conditional Bean creation to ensure this behavior. There is no guaranteed order of loading plugins, so they should not overlap or conflict in functionality or errors may result. - -NOTE: This plugin is for demonstration purposes only. It's never intended to be published +To use the Member Attribution List API's load the Postman collection into your Postman client. ## Docker diff --git a/server/src/main/resources/application.yaml b/server/src/main/resources/application.yaml index 962140dd7..caedfc1fa 100644 --- a/server/src/main/resources/application.yaml +++ b/server/src/main/resources/application.yaml @@ -3,11 +3,11 @@ spring: main: allow-bean-definition-overriding: true datasource: - url: "jdbc:postgresql://localhost:5432/hapi_r4" + url: "jdbc:h2:file:./target/database/h2" #url: jdbc:h2:mem:test_mem - username: postgres - password: postgres - driverClassName: org.postgresql.Driver + username: sa + password: null + driverClassName: org.h2.Driver max-active: 15 jpa: properties: @@ -15,7 +15,7 @@ spring: hibernate.show_sql: false #hibernate.packages-Scan: org.hl7.davinci.atr.server.model # hibernate.dialect: org.hibernate.dialect.h2dialect - #hibernate.hbm2ddl.auto: create + # hibernate.hbm2ddl.auto: update # hibernate.jdbc.batch_size: 20 # hibernate.cache.use_query_cache: false # hibernate.cache.use_second_level_cache: false From 9e84856b1f4136e6531babc29f1739af13a663e2 Mon Sep 17 00:00:00 2001 From: Raghunath Sandilya Date: Tue, 3 May 2022 15:48:12 +0530 Subject: [PATCH 3/6] Updates to Readme file --- mal/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mal/README.md b/mal/README.md index 14349bb02..deb6e9f0a 100644 --- a/mal/README.md +++ b/mal/README.md @@ -8,7 +8,18 @@ To setup the project follow the instructions mentioned [here](https://github.com ## Usage -To use the Member Attribution List API's load the Postman collection into your Postman client. +To use the Member Attribution List API's import the Postman collection added as part of this plugin into the Postman client. + +### Instructions to test the MAL API's +1. Create a Bundle of type transaction and add Patient, Coverage, RelatedPerson, Practitioner, PractitionerRole, Organization, Location resources as bundle entries. +2. Use the POST Bundle request from postman collection to save all the resources into database. +3. Create a Group resource and use POST Group request from postman collection to save the Group resource into database. +4. Use Group Member add request from postman collection to add a new member into the `Group.member` data element. +5. Use Group Member remove request from postman collection to remove a member from the `Group.member` data element. +6. Use Group Export request from postman collection to initiate the request to export all the members data. +7. Use the Polling Location endpoint received in the response headers of Group Export Operation call to know the status of export operation. +8. Use the links received in the response body for each resource to download the data from Binary resource. + ## Docker From bdc278bf2e8d6e93bbc5573e3cc0c53f17f7a3a7 Mon Sep 17 00:00:00 2001 From: Raghunath Sandilya Date: Tue, 3 May 2022 15:49:07 +0530 Subject: [PATCH 4/6] Update README.md --- mal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mal/README.md b/mal/README.md index deb6e9f0a..29c76720a 100644 --- a/mal/README.md +++ b/mal/README.md @@ -8,7 +8,7 @@ To setup the project follow the instructions mentioned [here](https://github.com ## Usage -To use the Member Attribution List API's import the Postman collection added as part of this plugin into the Postman client. +To use the Member Attribution List API's import the [Postman collection](https://github.com/DBCG/cqf-ruler/blob/feature-mal/mal/MAL-API's.postman_collection.json) added as part of this plugin into the Postman client. ### Instructions to test the MAL API's 1. Create a Bundle of type transaction and add Patient, Coverage, RelatedPerson, Practitioner, PractitionerRole, Organization, Location resources as bundle entries. From 3925ae62b08cbcf92d6c05cdab0b8089d2ac46e1 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Tue, 7 Jun 2022 10:31:48 -0600 Subject: [PATCH 5/6] Move classes to plugin, move packages to one we have rights for, coding convention cleanup --- .vscode/settings.json | 3 + core/pom.xml | 12 +- .../java/org/opencds/cqf/ruler/Server.java | 49 +-- .../cqf/ruler/behavior/DaoRegistryUser.java | 1 - mal/Dockerfile | 3 - mal/pom.xml | 111 ------ .../hl7/davinci/atr/server/MALProvider.java | 86 ----- .../atr/server/util/TextConstants.java | 53 --- .../atr}/MAL-API's.postman_collection.json | 0 {mal => plugin/atr}/README.md | 0 plugin/atr/pom.xml | 20 + .../org/opencds/cqf/ruler/atr/AtrConfig.java | 15 +- .../opencds/cqf/ruler/atr/MalProvider.java | 44 +++ .../cqf/ruler/atr/service/MalService.java | 341 ++++++++++-------- .../opencds/cqf/ruler/atr}/util/FhirUtil.java | 177 ++++----- .../cqf/ruler/atr/util/TextConstants.java | 36 ++ .../main/resources/META-INF/spring.factories | 0 .../atr}/src/main/resources/application.yaml | 0 plugin/pom.xml | 28 +- server/pom.xml | 6 +- 20 files changed, 428 insertions(+), 557 deletions(-) delete mode 100644 mal/Dockerfile delete mode 100644 mal/pom.xml delete mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java delete mode 100644 mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java rename {mal => plugin/atr}/MAL-API's.postman_collection.json (100%) rename {mal => plugin/atr}/README.md (100%) create mode 100644 plugin/atr/pom.xml rename mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java => plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/AtrConfig.java (70%) create mode 100644 plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/MalProvider.java rename mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java => plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/service/MalService.java (72%) rename {mal/src/main/java/org/hl7/davinci/atr/server => plugin/atr/src/main/java/org/opencds/cqf/ruler/atr}/util/FhirUtil.java (76%) create mode 100644 plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/TextConstants.java rename {mal => plugin/atr}/src/main/resources/META-INF/spring.factories (100%) rename {mal => plugin/atr}/src/main/resources/application.yaml (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 945641d64..c8d51043d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "java.test.defaultConfig": "test-config", "java.checkstyle.configuration": "${workspaceFolder}/config/checkstyle/checkstyle.xml", "java.checkstyle.version": "9.2.1", + "java.format.settings.url": "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml", "cSpell.enabledLanguageIds": [ "java", "json", @@ -34,6 +35,7 @@ "autoconfigure", "BCSEHEDISMY", "CAREGAP", + "cdshooks", "Checkstyle", "classpath", "Codeable", @@ -50,6 +52,7 @@ "mgsc", "multiversion", "mvnw", + "NOCHANGE", "numer", "opencds", "pdmp", diff --git a/core/pom.xml b/core/pom.xml index 9bac98dc7..52926f91c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -117,4 +118,13 @@
+ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + diff --git a/core/src/main/java/org/opencds/cqf/ruler/Server.java b/core/src/main/java/org/opencds/cqf/ruler/Server.java index 81b39b948..10c5fdecf 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/Server.java +++ b/core/src/main/java/org/opencds/cqf/ruler/Server.java @@ -1,13 +1,10 @@ package org.opencds.cqf.ruler; import static com.google.common.base.MoreObjects.firstNonNull; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; - import javax.servlet.ServletException; - import org.hl7.fhir.dstu3.model.CapabilityStatement; import org.hl7.fhir.instance.model.api.IBaseConformance; import org.opencds.cqf.ruler.api.Interceptor; @@ -23,7 +20,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; - import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.jpa.api.config.DaoConfig; @@ -67,7 +63,7 @@ public Server() { } @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) protected void initialize() throws ServletException { super.initialize(); @@ -76,7 +72,8 @@ protected void initialize() throws ServletException { this.registerProvider(valueSetOperationProvider); log.info("Loading operation providers from plugins"); - Map providers = applicationContext.getBeansOfType(OperationProvider.class); + Map providers = + applicationContext.getBeansOfType(OperationProvider.class); for (OperationProvider o : providers.values()) { log.info("Registering {}", o.getClass().getName()); this.registerProvider(o); @@ -88,9 +85,10 @@ protected void initialize() throws ServletException { log.info("Registering {} interceptor", o.getClass().getName()); this.registerInterceptor(o); } - + log.info("Loading metadata extenders from plugins"); - Map extenders = applicationContext.getBeansOfType(MetadataExtender.class); + Map extenders = + applicationContext.getBeansOfType(MetadataExtender.class); for (MetadataExtender o : extenders.values()) { log.info("Found {} extender", o.getClass().getName()); } @@ -101,38 +99,43 @@ protected void initialize() throws ServletException { if (fhirVersion == FhirVersionEnum.DSTU2) { List> extenderList = extenders.values().stream() .map(x -> (MetadataExtender) x).collect(Collectors.toList()); - ExtensibleJpaConformanceProviderDstu2 confProvider = new ExtensibleJpaConformanceProviderDstu2(this, - myFhirSystemDao, - myDaoConfig, extenderList); - confProvider.setImplementationDescription(firstNonNull(implementationDescription, "CQF RULER DSTU2 Server")); + ExtensibleJpaConformanceProviderDstu2 confProvider = + new ExtensibleJpaConformanceProviderDstu2(this, myFhirSystemDao, myDaoConfig, + extenderList); + confProvider.setImplementationDescription( + firstNonNull(implementationDescription, "CQF RULER DSTU2 Server")); setServerConformanceProvider(confProvider); } else { if (fhirVersion == FhirVersionEnum.DSTU3) { List> extenderList = extenders.values().stream() .map(x -> (MetadataExtender) x).collect(Collectors.toList()); - ExtensibleJpaConformanceProviderDstu3 confProvider = new ExtensibleJpaConformanceProviderDstu3(this, - myFhirSystemDao, myDaoConfig, mySearchParamRegistry, extenderList); - confProvider - .setImplementationDescription(firstNonNull(implementationDescription, "CQF RULER DSTU3 Server")); + ExtensibleJpaConformanceProviderDstu3 confProvider = + new ExtensibleJpaConformanceProviderDstu3(this, myFhirSystemDao, myDaoConfig, + mySearchParamRegistry, extenderList); + confProvider.setImplementationDescription( + firstNonNull(implementationDescription, "CQF RULER DSTU3 Server")); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R4) { List> extenderList = extenders.values().stream() .map(x -> (MetadataExtender) x).collect(Collectors.toList()); - ExtensibleJpaCapabilityStatementProvider confProvider = new ExtensibleJpaCapabilityStatementProvider(this, - myFhirSystemDao, myDaoConfig, mySearchParamRegistry, myValidationSupport, extenderList); - confProvider.setImplementationDescription(firstNonNull(implementationDescription, "CQF RULER R4 Server")); + ExtensibleJpaCapabilityStatementProvider confProvider = + new ExtensibleJpaCapabilityStatementProvider(this, myFhirSystemDao, myDaoConfig, + mySearchParamRegistry, myValidationSupport, extenderList); + confProvider.setImplementationDescription( + firstNonNull(implementationDescription, "CQF RULER R4 Server")); setServerConformanceProvider(confProvider); } else if (fhirVersion == FhirVersionEnum.R5) { List> extenderList = extenders.values().stream() .map(x -> (MetadataExtender) x).collect(Collectors.toList()); - ExtensibleJpaCapabilityStatementProvider confProvider = new ExtensibleJpaCapabilityStatementProvider(this, - myFhirSystemDao, myDaoConfig, mySearchParamRegistry, myValidationSupport, extenderList); - confProvider.setImplementationDescription(firstNonNull(implementationDescription, "CQF RULER R5 Server")); + ExtensibleJpaCapabilityStatementProvider confProvider = + new ExtensibleJpaCapabilityStatementProvider(this, myFhirSystemDao, myDaoConfig, + mySearchParamRegistry, myValidationSupport, extenderList); + confProvider.setImplementationDescription( + firstNonNull(implementationDescription, "CQF RULER R5 Server")); setServerConformanceProvider(confProvider); } else { throw new IllegalStateException(); } } - } } diff --git a/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java index f45418632..901d4d0f3 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java @@ -13,7 +13,6 @@ import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; /** * Simulate FhirDal operations until that's fully baked. This interface is diff --git a/mal/Dockerfile b/mal/Dockerfile deleted file mode 100644 index 2a736e70c..000000000 --- a/mal/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM contentgroup/cqf-ruler:latest - -COPY ./target/cqf-ruler-*.jar plugin diff --git a/mal/pom.xml b/mal/pom.xml deleted file mode 100644 index 6b6065a8a..000000000 --- a/mal/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - 4.0.0 - - org.hl7.davinci.atr.server - cqf-ruler-plugin-mal - 1.0.0 - - - UTF-8 - UTF-8 - 2.5.12 - - - - - - ca.uhn.hapi.fhir - hapi-fhir-bom - 5.5.3 - pom - import - - - org.junit - junit-bom - 5.8.1 - pom - import - - - - - - org.opencds.cqf.ruler - cqf-ruler-core - 0.5.0-SNAPSHOT - provided - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.opencds.cqf.ruler - cqf-ruler-test - 0.5.0-SNAPSHOT - test - - - org.springframework.boot - spring-boot-starter - ${spring_boot_version} - test - - - org.springframework.boot - spring-boot-starter-web - ${spring_boot_version} - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.apache.commons - commons-lang3 - 3.12.0 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - true - true - - -Xlint:all - - -Xlint:-processing - - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M1 - - true - - - - - - diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java b/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java deleted file mode 100644 index edb8ed268..000000000 --- a/mal/src/main/java/org/hl7/davinci/atr/server/MALProvider.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.hl7.davinci.atr.server; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.hl7.davinci.atr.server.service.MALService; -import org.hl7.fhir.r4.model.Group; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Parameters; -import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; -import ca.uhn.fhir.model.api.annotation.Description; -import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.ResourceParam; -import ca.uhn.fhir.rest.api.MethodOutcome; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; - -/** - * The Class MALProvider. - */ -public class MALProvider extends DaoRegistryOperationProvider{ - - /** The Constant logger. */ - private static final Logger logger = LoggerFactory.getLogger(MALProvider.class); - - /** The group dao. */ - @Autowired - private IFhirResourceDao groupDao; - - @Autowired - private MALService malService; - - /** - * Member add. - * - * @param groupId the group id - * @param requestDetails the request details - * @param request the request - * @param response the response - */ - @Description(shortDefinition = "Add new Member to the Group", value = "Implements the $member-add operation") - @Operation(idempotent = true, name = "$member-add",type = Group.class,manualResponse=true, manualRequest=true) - public MethodOutcome memberAdd(@IdParam IdType groupId,@ResourceParam Parameters theParameters, RequestDetails requestDetails, HttpServletRequest request, - HttpServletResponse response) { - MethodOutcome retVal = new MethodOutcome(); - if (request.getHeader("Content-Type") != null - && request.getHeader("Content-Type").equals("application/fhir+json")) { - Group updatedGroup = malService.processAddMemberToGroup(theParameters, groupId,requestDetails); - if (updatedGroup != null) { - response.setStatus(201); - retVal.setId(new IdType("Group", updatedGroup.getIdElement().getIdPart(), - updatedGroup.getMeta().getVersionId())); - } - } else { - throw new UnprocessableEntityException("Invalid header values!"); - } - return retVal; - } - - - - @Description(shortDefinition = "Add new Member to the Group", value = "Implements the $member-add operation") - @Operation(idempotent = true, name = "$member-remove",type = Group.class,manualResponse=true, manualRequest=true) - public MethodOutcome memberRemove(@IdParam IdType groupId,@ResourceParam Parameters theParameters, RequestDetails requestDetails, HttpServletRequest request, - HttpServletResponse response) { - MethodOutcome retVal = new MethodOutcome(); - if (request.getHeader("Content-Type") != null - && request.getHeader("Content-Type").equals("application/fhir+json")) { - Group updatedGroup = malService.processRemoveMemberToGroup(theParameters, groupId.getIdPart()); - if (updatedGroup != null) { - response.setStatus(201); - retVal.setId(new IdType("Group", updatedGroup.getIdElement().getIdPart(), - updatedGroup.getMeta().getVersionId())); - } - } else { - throw new UnprocessableEntityException("Invalid header values!"); - } - return retVal; - } -} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java b/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java deleted file mode 100644 index 19a6a25e9..000000000 --- a/mal/src/main/java/org/hl7/davinci/atr/server/util/TextConstants.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.hl7.davinci.atr.server.util; - -// TODO: Auto-generated Javadoc -/** - * The Class TextConstants. - */ -public final class TextConstants { - - /** - * Instantiates a new text constants. - */ - private TextConstants(){ - } - - /** The Constant SINGLE_FORWORD_SLASH. */ - public static final String SINGLE_FORWORD_SLASH="/"; - - /** The Constant MEMBER_ID. */ - public static final String MEMBER_ID="memberId"; - - /** The Constant PROVIDER_NPI. */ - public static final String PROVIDER_NPI="providerNpi"; - - /** The Constant PATIENT_REFERENCE. */ - public static final String PATIENT_REFERENCE="patientReference"; - - /** The Constant PROVIDER_REFERENCE. */ - public static final String PROVIDER_REFERENCE="providerReference"; - - /** The Constant ATTRIBUTION_PERIOD. */ - public static final String ATTRIBUTION_PERIOD="attributionPeriod"; - - /** The Constant MEMBER_CHANGETYPE_SYSTEM. */ - public static final String MEMBER_CHANGETYPE_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-changeType"; - - /** The Constant MEMBER_COVERAGE_SYSTEM. */ - public static final String MEMBER_COVERAGE_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-coverageReference"; - - /** The Constant MEMBER_PROVIDER_SYSTEM. */ - public static final String MEMBER_PROVIDER_SYSTEM = "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-attributedProvider"; - - /** The Constant NEW_TYPE. */ - public static final String NEW_TYPE="new"; - - /** The Constant CHANGE_TYPE. */ - public static final String CHANGE_TYPE="change"; - - /** The Constant NOCHANGE_TYPE. */ - public static final String NOCHANGE_TYPE="nochange"; - - /** The Constant HTTP_POST. */ - public static final String HTTP_POST="POST"; -} diff --git a/mal/MAL-API's.postman_collection.json b/plugin/atr/MAL-API's.postman_collection.json similarity index 100% rename from mal/MAL-API's.postman_collection.json rename to plugin/atr/MAL-API's.postman_collection.json diff --git a/mal/README.md b/plugin/atr/README.md similarity index 100% rename from mal/README.md rename to plugin/atr/README.md diff --git a/plugin/atr/pom.xml b/plugin/atr/pom.xml new file mode 100644 index 000000000..5903728c2 --- /dev/null +++ b/plugin/atr/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + org.opencds.cqf.ruler + cqf-ruler-plugin + 0.5.0-SNAPSHOT + + + cqf-ruler-atr + + + org.opencds.cqf.ruler + cqf-ruler-test + 0.5.0-SNAPSHOT + test + + + diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/AtrConfig.java similarity index 70% rename from mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java rename to plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/AtrConfig.java index f00bf4e02..7d11c4cc9 100644 --- a/mal/src/main/java/org/hl7/davinci/atr/server/MALConfig.java +++ b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/AtrConfig.java @@ -1,7 +1,7 @@ -package org.hl7.davinci.atr.server; +package org.opencds.cqf.ruler.atr; -import org.hl7.davinci.atr.server.service.MALService; import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.atr.service.MalService; import org.opencds.cqf.ruler.external.annotations.OnR4Condition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -12,7 +12,7 @@ * The Class MALConfig. */ @Configuration -public class MALConfig { +public class AtrConfig { /** * Member add provider. @@ -22,16 +22,17 @@ public class MALConfig { @Bean @Conditional(OnR4Condition.class) public OperationProvider memberAddProvider() { - return new MALProvider(); + return new MalProvider(); } - + /** * Mal service. * * @return the MAL service */ @Bean - public MALService malService() { - return new MALService(); + @Conditional(OnR4Condition.class) + public MalService malService() { + return new MalService(); } } diff --git a/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/MalProvider.java b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/MalProvider.java new file mode 100644 index 000000000..803ac863d --- /dev/null +++ b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/MalProvider.java @@ -0,0 +1,44 @@ +package org.opencds.cqf.ruler.atr; + +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Parameters; +import org.opencds.cqf.ruler.atr.service.MalService; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; +import org.springframework.beans.factory.annotation.Autowired; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; + + +public class MalProvider extends DaoRegistryOperationProvider { + @Autowired + private MalService malService; + + /** + * Member add. + * + * @param groupId the group id + * @param requestDetails the request details + * @param request the request + * @param response the response + */ + @Description(shortDefinition = "Add new Member to the Group", + value = "Implements the $member-add operation") + @Operation(idempotent = true, name = "$member-add", type = Group.class) + public Group memberAdd(@IdParam IdType groupId, @ResourceParam Parameters theParameters, + RequestDetails requestDetails) { + return malService.processAddMemberToGroup(theParameters, groupId, requestDetails); + } + + + @Description(shortDefinition = "Remove Member from the Group", + value = "Implements the $member-remove operation") + @Operation(idempotent = true, name = "$member-remove") + public Group memberRemove(@IdParam IdType groupId, @ResourceParam Parameters theParameters, + RequestDetails requestDetails) { + return malService.processRemoveMemberToGroup(theParameters, groupId.getIdPart()); + } +} diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/service/MalService.java similarity index 72% rename from mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java rename to plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/service/MalService.java index dd2600191..bed81d2cc 100644 --- a/mal/src/main/java/org/hl7/davinci/atr/server/service/MALService.java +++ b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/service/MalService.java @@ -1,20 +1,18 @@ -package org.hl7.davinci.atr.server.service; +package org.opencds.cqf.ruler.atr.service; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.apache.commons.lang3.StringUtils; -import org.hl7.davinci.atr.server.util.FhirUtil; -import org.hl7.davinci.atr.server.util.TextConstants; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.Coverage; import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.Group.GroupMemberComponent; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Meta; import org.hl7.fhir.r4.model.Organization; @@ -25,12 +23,13 @@ import org.hl7.fhir.r4.model.PractitionerRole; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; -import org.hl7.fhir.r4.model.Group.GroupMemberComponent; +import org.hl7.fhir.r4.model.ResourceType; +import org.opencds.cqf.ruler.atr.util.FhirUtil; +import org.opencds.cqf.ruler.atr.util.TextConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; @@ -40,55 +39,42 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; -/** - * The Class MALService. - */ @Service -public class MALService { - - /** The patient dao. */ +public class MalService { @Autowired private IFhirResourceDao patientDao; - /** The coverage dao. */ @Autowired private IFhirResourceDao coverageDao; - /** The practitioner dao. */ @Autowired private IFhirResourceDao practitionerDao; - /** The practitioner role dao. */ @Autowired private IFhirResourceDao practitionerRoleDao; - /** The organization dao. */ @Autowired private IFhirResourceDao organizationDao; - /** The group dao. */ @Autowired private IFhirResourceDao groupDao; - /** The fhir context. */ @Autowired FhirContext fhirContext; - /** The Constant logger. */ - private static final Logger logger = LoggerFactory.getLogger(MALService.class); + private static final Logger logger = LoggerFactory.getLogger(MalService.class); /** * Process add member to group. * - * @param theParameters the the parameters - * @param theId the the id + * @param theParameters the the parameters + * @param theId the the id * @param requestDetails the request details * @return the group */ - public Group processAddMemberToGroup(Parameters theParameters, IdType theId, RequestDetails requestDetails) { - - logger.info("In ProcessAdd member to Group Method"); - logger.info("RequestURL:::::{}", requestDetails.getFhirServerBase()); + public Group processAddMemberToGroup(Parameters theParameters, IdType theId, + RequestDetails requestDetails) { + logger.info("RequestURL: {}", requestDetails.getFhirServerBase()); String patientId = null; String attributeProviderId = null; String attributeProviderReferenceResource = null; @@ -96,18 +82,19 @@ public Group processAddMemberToGroup(Parameters theParameters, IdType theId, Req Period attributionPeriod = null; Group group = groupDao.read(theId); - if (theParameters.getParameter("memberId") != null && theParameters.getParameter("providerNpi") != null) { + if (theParameters.getParameter("memberId") != null + && theParameters.getParameter("providerNpi") != null) { // Creating the TokenAndListParam object to add into the SearchParamMap SearchParameterMap patientParamMap = new SearchParameterMap(); TokenAndListParam tokenParam = FhirUtil.createTokenAndListParam(theParameters, "memberId"); patientParamMap.add(Patient.SP_IDENTIFIER, tokenParam); // Invoking the Patient Search Dao API. IBundleProvider bundle = patientDao.search(patientParamMap); - logger.info("Received Bundle with Size:::::{}", bundle.getAllResources().size()); + logger.info("Received Bundle with Size: {}", bundle.getAllResources().size()); for (IBaseResource iBaseResource : bundle.getAllResources()) { Resource resource = (Resource) iBaseResource; - if (resource.fhirType().equals("Patient")) { - logger.info("patientId::::::" + resource.getIdElement().getIdPart()); + if (resource.getResourceType().equals(ResourceType.Patient)) { + logger.info("patientId: {}", resource.getIdElement().getIdPart()); patientId = resource.getIdElement().getIdPart(); } } @@ -128,11 +115,11 @@ public Group processAddMemberToGroup(Parameters theParameters, IdType theId, Req coverageParamMap.add(Coverage.SP_IDENTIFIER, tokenParam); // Invoking the Patient Search Dao API. IBundleProvider coverageBundle = coverageDao.search(coverageParamMap); - logger.info("Received Bundle with Size:::::{}", coverageBundle.getAllResources().size()); + logger.info("Received Bundle with Size: {}", coverageBundle.getAllResources().size()); for (IBaseResource iBaseResource : coverageBundle.getAllResources()) { Resource resource = (Resource) iBaseResource; - if (resource.fhirType().equals("Coverage")) { - logger.info("coverageId::::::{}", resource.getIdElement().getIdPart()); + if (resource.getResourceType().equals(ResourceType.Coverage)) { + logger.info("coverageId: {}", resource.getIdElement().getIdPart()); coverageId = resource.getIdElement().getIdPart(); } } @@ -140,7 +127,7 @@ public Group processAddMemberToGroup(Parameters theParameters, IdType theId, Req if (theParameters.getParameter("attributionPeriod") != null) { attributionPeriod = (Period) theParameters.getParameter("attributionPeriod"); } - + } else if (theParameters.getParameter(TextConstants.PATIENT_REFERENCE) != null && theParameters.getParameter(TextConstants.PROVIDER_REFERENCE) != null) { String patientMemberId = findPatientIdByReference(theParameters); @@ -153,33 +140,36 @@ public Group processAddMemberToGroup(Parameters theParameters, IdType theId, Req attributeProviderReferenceResource = entry.getKey(); } } else { - throw new ResourceNotFoundException("Couldn't find any Providers with given providerReference"); + throw new ResourceNotFoundException( + "Couldn't find any Providers with given providerReference"); } String coverageResourceId = findCoverageIdByPatientId(patientId); if (StringUtils.isNotBlank(coverageResourceId)) { coverageId = coverageResourceId; } } else { - throw new ResourceNotFoundException("Couldn't find any Patient with given patientReference"); + throw new ResourceNotFoundException( + "Couldn't find any Patient with given patientReference"); } } else { throw new UnprocessableEntityException( "Please provide memberId + providerNpi or patientReference + providerReference to $member-add."); } - + if (patientId != null && attributeProviderId != null) { - logger.info(" patientMemberId :: " + patientId); - logger.info(" attributePeriod :: " + attributionPeriod); - logger.info(" attributeProviderReferenceResource :: " + attributeProviderReferenceResource); - logger.info(" attributeProviderId :: " + attributeProviderId); - logger.info(" coverageReference :: " + coverageId); + logger.info("patientMemberId: {}", patientId); + logger.info("attributePeriod: {}", attributionPeriod); + logger.info("attributeProviderReferenceResource: {}", attributeProviderReferenceResource); + logger.info("attributeProviderId: {}", attributeProviderId); + logger.info("coverageReference: {}", coverageId); if (attributionPeriod != null) { - logger.info(" attributionPeriod.getStart() :: " + attributionPeriod.getStart()); - logger.info(" attributionPeriod.getEnd() :: " + attributionPeriod.getEnd()); + logger.info("attributionPeriod.getStart(): {}", attributionPeriod.getStart()); + logger.info("attributionPeriod.getEnd(): {}", attributionPeriod.getEnd()); } - addMemberToGroup(group, patientId, attributeProviderId, attributeProviderReferenceResource, coverageId, - attributionPeriod); - logger.info("After adding Member::::{}", fhirContext.newJsonParser().encodeResourceToString(group)); + addMemberToGroup(group, patientId, attributeProviderId, attributeProviderReferenceResource, + coverageId, attributionPeriod); + logger.info("After adding Member: {}", + fhirContext.newJsonParser().encodeResourceToString(group)); groupDao.update(group); if (group == null) { throw new UnprocessableEntityException("Error while adding member to group"); @@ -214,10 +204,8 @@ private String findCoverageIdByPatientId(String id) { */ private String findPatientIdByReference(Parameters theParameters) { String patientId = null; - Reference patientReference = (Reference) theParameters.getParameter(TextConstants.PATIENT_REFERENCE); - System.out.println(" patientReference.getReferenceElement().getIdPart() " - + patientReference.getReferenceElement().getIdPart()); - System.out.println(" patientReference.getReference() " + patientReference.getReference()); + Reference patientReference = + (Reference) theParameters.getParameter(TextConstants.PATIENT_REFERENCE); Patient patient = patientDao.read(patientReference.getReferenceElement()); if (patient != null) { @@ -234,7 +222,8 @@ private String findPatientIdByReference(Parameters theParameters) { */ private Map findProviderIdByReference(Parameters theParameters) { Map providerMap = new HashMap<>(); - Reference providerReference = (Reference) theParameters.getParameter(TextConstants.PROVIDER_REFERENCE); + Reference providerReference = + (Reference) theParameters.getParameter(TextConstants.PROVIDER_REFERENCE); String providerReferenceResource = providerReference.getReferenceElement().getResourceType(); if (StringUtils.isNotBlank(providerReferenceResource) && providerReferenceResource.equalsIgnoreCase("Practitioner")) { @@ -244,7 +233,8 @@ private Map findProviderIdByReference(Parameters theParameters) } } else if (StringUtils.isNotBlank(providerReferenceResource) && providerReferenceResource.equalsIgnoreCase("PractitionerRole")) { - PractitionerRole practitionerRole = practitionerRoleDao.read(providerReference.getReferenceElement()); + PractitionerRole practitionerRole = + practitionerRoleDao.read(providerReference.getReferenceElement()); if (practitionerRole != null && !practitionerRole.isEmpty()) { providerMap.put("PractitionerRole", practitionerRole.getIdElement().getIdPart()); } @@ -267,21 +257,22 @@ private Map findProviderIdByReference(Parameters theParameters) private Map findProviderIdByIdentifier(Parameters theParameters) { Map providerMap = new HashMap<>(); SearchParameterMap attrProviderParamMap = new SearchParameterMap(); - TokenAndListParam pracitionerTokenParam = FhirUtil.createTokenAndListParam(theParameters, "providerNpi"); - attrProviderParamMap.add("identifier", pracitionerTokenParam); + TokenAndListParam practitionerTokenParam = + FhirUtil.createTokenAndListParam(theParameters, "providerNpi"); + attrProviderParamMap.add("identifier", practitionerTokenParam); IBundleProvider practitionerBundle = practitionerDao.search(attrProviderParamMap); if (practitionerBundle.getAllResources().isEmpty()) { IBundleProvider practitionerRoleBundle = practitionerRoleDao.search(attrProviderParamMap); if (practitionerRoleBundle.getAllResources().isEmpty()) { IBundleProvider organizationBundle = organizationDao.search(attrProviderParamMap); if (!organizationBundle.isEmpty()) { - providerMap = addToMap(organizationBundle, providerMap); + addToMap(organizationBundle, providerMap); } } else { - providerMap = addToMap(practitionerRoleBundle, providerMap); + addToMap(practitionerRoleBundle, providerMap); } } else { - providerMap = addToMap(practitionerBundle, providerMap); + addToMap(practitionerBundle, providerMap); } return providerMap; } @@ -289,7 +280,7 @@ private Map findProviderIdByIdentifier(Parameters theParameters) /** * Adds the to map. * - * @param bundle the bundle + * @param bundle the bundle * @param providerMap the provider map * @return the map */ @@ -312,57 +303,60 @@ private Map addToMap(IBundleProvider bundle, Map /** * Adds the member to group. * - * @param group the group - * @param patientMemberId the patient member id - * @param providerId the provider id + * @param group the group + * @param patientMemberId the patient member id + * @param providerId the provider id * @param attrProviderResourceName the attr provider resource name - * @param coverageId the coverage id - * @param attributionPeriod the attribution period + * @param coverageId the coverage id + * @param attributionPeriod the attribution period */ private void addMemberToGroup(Group group, String patientMemberId, String providerId, String attrProviderResourceName, String coverageId, Period attributionPeriod) { try { - List memberList = new ArrayList<>(); boolean isAttributionCoverageFound = false; boolean isMemberFound = false; if (group.hasMember()) { - memberList = group.getMember(); - for (GroupMemberComponent memberGroup : new ArrayList(memberList)) { - // GroupMemberComponent memberGroup = iterator.next(); + List memberList = group.getMember(); + for (GroupMemberComponent memberGroup : new ArrayList( + memberList)) { String entityId = getEntityIdFromGroupMemberComponent(memberGroup); - String attributeProviderId = getAttributeProviderIdFromGroupMemberComponent(memberGroup); + String attributeProviderId = + getAttributeProviderIdFromGroupMemberComponent(memberGroup); if (entityId != null && attributeProviderId != null) { if (patientMemberId.equalsIgnoreCase(entityId) && providerId.equalsIgnoreCase(attributeProviderId)) { isMemberFound = true; if (coverageId != null) { - isAttributionCoverageFound = updateGroupMemberComponentCoverageReferenceExtension( - memberGroup, coverageId, isAttributionCoverageFound); + isAttributionCoverageFound = + updateGroupMemberComponentCoverageReferenceExtension(memberGroup, + coverageId, isAttributionCoverageFound); } if (attributionPeriod != null) { - updateGroupMemberComponentAttributionPeriod(memberGroup, isAttributionCoverageFound, - attributionPeriod); + updateGroupMemberComponentAttributionPeriod(memberGroup, + isAttributionCoverageFound, attributionPeriod); } } } } if (!isMemberFound) { - GroupMemberComponent theGroupMemberComponent = FhirUtil.getGroupMemberComponent(patientMemberId, - providerId, attrProviderResourceName, coverageId, attributionPeriod); + GroupMemberComponent theGroupMemberComponent = + FhirUtil.getGroupMemberComponent(patientMemberId, providerId, + attrProviderResourceName, coverageId, attributionPeriod); if (theGroupMemberComponent != null) { memberList.add(theGroupMemberComponent); - logger.info(" :: Adding one new GroupMemberComponent :: "); + logger.info("Adding one new GroupMemberComponent"); group.setMember(memberList); } } } else { List newGroupMemberComponentList = null; - GroupMemberComponent newGroupMemberComponent = FhirUtil.getGroupMemberComponent(patientMemberId, - providerId, attrProviderResourceName, coverageId, attributionPeriod); + GroupMemberComponent newGroupMemberComponent = + FhirUtil.getGroupMemberComponent(patientMemberId, providerId, + attrProviderResourceName, coverageId, attributionPeriod); if (newGroupMemberComponent != null && !newGroupMemberComponent.isEmpty()) { newGroupMemberComponentList = new ArrayList<>(); newGroupMemberComponentList.add(newGroupMemberComponent); - logger.info(" :: Adding new Member for first time for group :: "); + logger.info("Adding new Member for first time for group"); group.setMember(newGroupMemberComponentList); } } @@ -389,17 +383,18 @@ private void addMemberToGroup(Group group, String patientMemberId, String provid /** * Gets the group member component. * - * @param patientMemberId the patient member id - * @param providerId the provider id + * @param patientMemberId the patient member id + * @param providerId the provider id * @param providerReference the provider reference * @param coverageReference the coverage reference * @param attributionPeriod the attribution period * @return the group member component */ - public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, String providerId, - String providerReference, String coverageReference, Period attributionPeriod) { + public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, + String providerId, String providerReference, String coverageReference, + Period attributionPeriod) { GroupMemberComponent theGroupMemberComponent = new GroupMemberComponent(); - List theMembeEextensionList = null; + List theMemberExtensionList = null; try { if (StringUtils.isNotBlank(patientMemberId)) { Reference theReference = FhirUtil.getReference(patientMemberId, "Patient"); @@ -409,10 +404,10 @@ public static GroupMemberComponent getGroupMemberComponent(String patientMemberI theGroupMemberComponent.setInactiveElement(theBoolean); } } - theMembeEextensionList = FhirUtil.getGroupMemberComponentExtension(providerId, providerReference, - coverageReference, TextConstants.NEW_TYPE); - if (theMembeEextensionList != null && !theMembeEextensionList.isEmpty()) { - theGroupMemberComponent.setExtension(theMembeEextensionList); + theMemberExtensionList = FhirUtil.getGroupMemberComponentExtension(providerId, + providerReference, coverageReference, TextConstants.NEW_TYPE); + if (theMemberExtensionList != null && !theMemberExtensionList.isEmpty()) { + theGroupMemberComponent.setExtension(theMemberExtensionList); } if (attributionPeriod != null) { Period thePeriod = FhirUtil.getPeriod(attributionPeriod.getStartElement(), @@ -420,7 +415,8 @@ public static GroupMemberComponent getGroupMemberComponent(String patientMemberI theGroupMemberComponent.setPeriod(thePeriod); } } catch (Exception ex) { - logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", + ex); } return theGroupMemberComponent; } @@ -460,7 +456,9 @@ private String getAttributeProviderIdFromGroupMemberComponent(GroupMemberCompone } } } catch (Exception e) { - logger.info("Exception in getAttributeProviderIdFromGroupMemberComponent of GroupServiceImpl ", e); + logger.info( + "Exception in getAttributeProviderIdFromGroupMemberComponent of GroupServiceImpl ", + e); } return attributeProviderId; } @@ -468,13 +466,13 @@ private String getAttributeProviderIdFromGroupMemberComponent(GroupMemberCompone /** * Update group member component coverage reference extension. * - * @param memberGroup the member group - * @param coverageId the coverage id + * @param memberGroup the member group + * @param coverageId the coverage id * @param isAttributionCoverageFound the is attribution coverage found * @return true, if successful */ - private boolean updateGroupMemberComponentCoverageReferenceExtension(GroupMemberComponent memberGroup, - String coverageId, boolean isAttributionCoverageFound) { + private boolean updateGroupMemberComponentCoverageReferenceExtension( + GroupMemberComponent memberGroup, String coverageId, boolean isAttributionCoverageFound) { try { if (StringUtils.isNotBlank(coverageId)) { if (memberGroup.hasExtension(TextConstants.MEMBER_COVERAGE_SYSTEM)) { @@ -485,34 +483,41 @@ private boolean updateGroupMemberComponentCoverageReferenceExtension(GroupMember Reference coverageReference = FhirUtil.getReference(coverageId, "Coverage"); memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) .setValue(coverageReference); - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.CHANGE_TYPE); isAttributionCoverageFound = true; } else { - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.NOCHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.NOCHANGE_TYPE); logger.info(" Coverage nochange "); isAttributionCoverageFound = false; } } else { Reference coverageReference = FhirUtil.getReference(coverageId, "Coverage"); - memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM).setValue(coverageReference); - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) + .setValue(coverageReference); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.CHANGE_TYPE); isAttributionCoverageFound = true; } } else { if (memberGroup.hasExtension()) { List extensionList = memberGroup.getExtension(); - Extension coverageExtension = FhirUtil.getExtensionForReference(coverageId, "Coverage", - TextConstants.MEMBER_COVERAGE_SYSTEM); + Extension coverageExtension = FhirUtil.getExtensionForReference(coverageId, + "Coverage", TextConstants.MEMBER_COVERAGE_SYSTEM); if (coverageExtension != null && !coverageExtension.isEmpty()) { extensionList.add(coverageExtension); - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.CHANGE_TYPE); isAttributionCoverageFound = true; } } } } } catch (Exception e) { - logger.error("Exception in updateGroupMemberComponentCoverageReferenceExtension of GroupServiceImpl ", e); + logger.error( + "Exception in updateGroupMemberComponentCoverageReferenceExtension of GroupServiceImpl ", + e); } return isAttributionCoverageFound; } @@ -521,14 +526,16 @@ private boolean updateGroupMemberComponentCoverageReferenceExtension(GroupMember * Update group member component change type extension. * * @param memberGroup the member group - * @param changeCode the change code + * @param changeCode the change code */ - private void updateGroupMemberComponentChangeTypeExtension(GroupMemberComponent memberGroup, String changeCode) { + private void updateGroupMemberComponentChangeTypeExtension(GroupMemberComponent memberGroup, + String changeCode) { try { if (StringUtils.isNotBlank(changeCode)) { if (memberGroup.hasExtension(TextConstants.MEMBER_CHANGETYPE_SYSTEM)) { CodeType codeType = FhirUtil.getCodeType(changeCode); - memberGroup.getExtensionByUrl(TextConstants.MEMBER_CHANGETYPE_SYSTEM).setValue(codeType); + memberGroup.getExtensionByUrl(TextConstants.MEMBER_CHANGETYPE_SYSTEM) + .setValue(codeType); } else { if (memberGroup.hasExtension()) { List extensionList = memberGroup.getExtension(); @@ -540,16 +547,18 @@ private void updateGroupMemberComponentChangeTypeExtension(GroupMemberComponent } } } catch (Exception e) { - logger.error("Exception in updateGroupMemberComponentChangeTypeExtension of GroupServiceImpl ", e); + logger.error( + "Exception in updateGroupMemberComponentChangeTypeExtension of GroupServiceImpl ", + e); } } /** * Update group member component attribution period. * - * @param memberGroup the member group + * @param memberGroup the member group * @param isAttributionCoverageFound the is attribution coverage found - * @param attributionPeriod the attribution period + * @param attributionPeriod the attribution period */ private void updateGroupMemberComponentAttributionPeriod(GroupMemberComponent memberGroup, boolean isAttributionCoverageFound, Period attributionPeriod) { @@ -575,21 +584,25 @@ private void updateGroupMemberComponentAttributionPeriod(GroupMemberComponent me } if (!startOne.equals(memberStart) || !endOne.equals(memberEnd)) { memberGroup.setPeriod(attributionPeriod); - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.CHANGE_TYPE); } else if (!isAttributionCoverageFound) { - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.NOCHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.NOCHANGE_TYPE); } } else { memberGroup.setPeriod(attributionPeriod); - updateGroupMemberComponentChangeTypeExtension(memberGroup, TextConstants.CHANGE_TYPE); + updateGroupMemberComponentChangeTypeExtension(memberGroup, + TextConstants.CHANGE_TYPE); } } } catch (Exception e) { - logger.error("Exception in updateGroupMemberComponentAttributionPeriod of GroupServiceImpl ", e); + logger.error( + "Exception in updateGroupMemberComponentAttributionPeriod of GroupServiceImpl ", e); } } - public Group processRemoveMemberToGroup(Parameters theParameters, String groupId){ + public Group processRemoveMemberToGroup(Parameters theParameters, String groupId) { String patientMemberId = null; String attributeProviderId = null; String attributeProviderReferenceResource = null; @@ -600,15 +613,16 @@ public Group processRemoveMemberToGroup(Parameters theParameters, String groupId if (theParameters.getParameter(TextConstants.MEMBER_ID) != null) { // Creating the TokenAndListParam object to add into the SearchParamMap SearchParameterMap patientParamMap = new SearchParameterMap(); - TokenAndListParam tokenParam = FhirUtil.createTokenAndListParam(theParameters, "memberId"); + TokenAndListParam tokenParam = + FhirUtil.createTokenAndListParam(theParameters, "memberId"); patientParamMap.add(Patient.SP_IDENTIFIER, tokenParam); // Invoking the Patient Search Dao API. IBundleProvider bundle = patientDao.search(patientParamMap); - logger.info("Received Bundle with Size:::::{}", bundle.getAllResources().size()); + logger.info("Received Bundle with Size: {}", bundle.getAllResources().size()); for (IBaseResource iBaseResource : bundle.getAllResources()) { Resource resource = (Resource) iBaseResource; if (resource.fhirType().equals("Patient")) { - logger.info("patientId::::::" + resource.getIdElement().getIdPart()); + logger.info("patientId: {}", resource.getIdElement().getIdPart()); patientMemberId = resource.getIdElement().getIdPart(); } } @@ -619,14 +633,15 @@ public Group processRemoveMemberToGroup(Parameters theParameters, String groupId // Get Practitioner Id using the NPI details from received Parameters. // Creating the TokenAndListParam object to add into the SearchParamMap Map providerMap = findProviderIdByIdentifier(theParameters); - if (providerMap != null && !providerMap.isEmpty()) { + if (!providerMap.isEmpty()) { for (Map.Entry entry : providerMap.entrySet()) { attributeProviderId = entry.getValue(); attributeProviderReferenceResource = entry.getKey(); } } if (providerMap.isEmpty()) { - throw new ResourceNotFoundException("Couldn't find any Providers with given providerNpi"); + throw new ResourceNotFoundException( + "Couldn't find any Providers with given providerNpi"); } } else if (theParameters.getParameter(TextConstants.PATIENT_REFERENCE) != null) { String patientId = findPatientIdByReference(theParameters); @@ -649,29 +664,32 @@ public Group processRemoveMemberToGroup(Parameters theParameters, String groupId coverageReference = coverageId; } } else { - throw new ResourceNotFoundException("Couldn't find any Patient with given patientReference"); + throw new ResourceNotFoundException( + "Couldn't find any Patient with given patientReference"); } } else { throw new UnprocessableEntityException( "Please provide memberId + providerNpi or patientReference + providerReference to $member-add."); } if (theParameters.getParameter(TextConstants.ATTRIBUTION_PERIOD) != null) { - attributionPeriod = (Period) theParameters.getParameter(TextConstants.ATTRIBUTION_PERIOD); + attributionPeriod = + (Period) theParameters.getParameter(TextConstants.ATTRIBUTION_PERIOD); } if (StringUtils.isNotBlank(patientMemberId)) { - logger.info(" patientMemberId :: " + patientMemberId); - logger.info(" attributeProviderId :: " + attributeProviderId); - logger.info(" attributeProviderReferenceResource :: " + attributeProviderReferenceResource); - logger.info(" coverageReference :: " + coverageReference); + logger.info("patientMemberId: {}", patientMemberId); + logger.info("attributeProviderId: {}", attributeProviderId); + logger.info("attributeProviderReferenceResource: {}", + attributeProviderReferenceResource); + logger.info("coverageReference: {}", coverageReference); if (attributionPeriod != null) { - logger.info(" attributionPeriod.getStart() :: " + attributionPeriod.getStart()); - logger.info(" attributionPeriod.getEnd() :: " + attributionPeriod.getEnd()); + logger.info("attributionPeriod.getStart(): {}", attributionPeriod.getStart()); + logger.info("attributionPeriod.getEnd(): {}", attributionPeriod.getEnd()); } - removeMemberFromGroup(group, patientMemberId, attributeProviderId, attributeProviderReferenceResource, - coverageReference, attributionPeriod); - + removeMemberFromGroup(group, patientMemberId, attributeProviderId, + attributeProviderReferenceResource, coverageReference, attributionPeriod); + groupDao.update(group); - + } else { throw new ResourceNotFoundException("No patient found "); } @@ -682,45 +700,49 @@ public Group processRemoveMemberToGroup(Parameters theParameters, String groupId } public void removeMemberFromGroup(Group group, String patientMemberId, String providerId, - String providerReferenceResource, String coverageId, Period attributionPeriod){ - logger.info(" patientMemberId :: " + patientMemberId); - logger.info(" providerId :: " + providerId); - logger.info(" providerReferenceResource :: " + providerReferenceResource); - logger.info(" coverageId :: " + coverageId); - List memberList = new ArrayList<>(); + String providerReferenceResource, String coverageId, Period attributionPeriod) { + logger.info("patientMemberId: {}", patientMemberId); + logger.info("providerId: {}", providerId); + logger.info("providerReferenceResource: {}", providerReferenceResource); + logger.info("coverageId: {}", coverageId); boolean isGroupMemberRemoved = false; if (group.hasMember()) { - memberList = group.getMember(); + List memberList = new ArrayList<>(); for (GroupMemberComponent memberGroup : new ArrayList(memberList)) { - // GroupMemberComponent memberGroup = iterator.next(); if (memberGroup.hasEntity() && memberGroup.getEntity().hasReferenceElement()) { String entityId = memberGroup.getEntity().getReferenceElement().getIdPart(); - logger.info(" entityId :: " + entityId); + logger.info("entityId: {}", entityId); if (patientMemberId.equalsIgnoreCase(entityId)) { - if (StringUtils.isNotBlank(providerId) && StringUtils.isNotBlank(providerReferenceResource)) { + if (StringUtils.isNotBlank(providerId) + && StringUtils.isNotBlank(providerReferenceResource)) { if (memberGroup.hasExtension(TextConstants.MEMBER_PROVIDER_SYSTEM)) { - if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).hasValue()) { + if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM) + .hasValue()) { Reference reference = (Reference) memberGroup - .getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM).getValue(); - if (providerId.equalsIgnoreCase(reference.getReferenceElement().getIdPart()) + .getExtensionByUrl(TextConstants.MEMBER_PROVIDER_SYSTEM) + .getValue(); + if (providerId + .equalsIgnoreCase(reference.getReferenceElement().getIdPart()) && providerReferenceResource.equalsIgnoreCase( reference.getReferenceElement().getResourceType())) { if (StringUtils.isNotBlank(coverageId)) { - if (memberGroup.hasExtension(TextConstants.MEMBER_COVERAGE_SYSTEM)) { - if (memberGroup.getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) + if (memberGroup + .hasExtension(TextConstants.MEMBER_COVERAGE_SYSTEM)) { + if (memberGroup + .getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) .hasValue()) { - Reference coverageReference = (Reference) memberGroup - .getExtensionByUrl(TextConstants.MEMBER_COVERAGE_SYSTEM) - .getValue(); + Reference coverageReference = + (Reference) memberGroup + .getExtensionByUrl( + TextConstants.MEMBER_COVERAGE_SYSTEM) + .getValue(); if (coverageId.equalsIgnoreCase( coverageReference.getReferenceElement().getIdPart())) { memberList.remove(memberGroup); isGroupMemberRemoved = true; logger.info( - " Removing member from Group.member for memberId+providerNpi+attributionPeriod / " - + "patientReference+providerReference+attributionPeriod. patientMemberId: " - + patientMemberId + " providerId: " + providerId - + " coverageId : " + coverageId); + " Removing member from Group.member for memberId+providerNpi+attributionPeriod / patientReference+providerReference+attributionPeriod. patientMemberId: {}, providerId: {}, coverageId: {}", + patientMemberId, providerId, coverageId); } else { throw new ResourceNotFoundException( " No coverage found for given attributionPeriod " @@ -731,9 +753,9 @@ public void removeMemberFromGroup(Group group, String patientMemberId, String pr } else { memberList.remove(memberGroup); isGroupMemberRemoved = true; - logger.info(" Removing member from Group.member for memberId+providerNpi / " - + "patientReference+providerReference. patientMemberId: " - + patientMemberId + " providerId: " + providerId); + logger.info( + "Removing member from Group.member for memberId+providerNpi / patientReference+providerReference. patientMemberId: {} providerId: {}", + patientMemberId, providerId); } } else { throw new ResourceNotFoundException( @@ -745,15 +767,15 @@ public void removeMemberFromGroup(Group group, String patientMemberId, String pr memberList.remove(memberGroup); isGroupMemberRemoved = true; logger.info( - " Removing member from Group.member for memberId/patientReference. patientMemberId : " - + patientMemberId); + "Removing member from Group.member for memberId/patientReference. patientMemberId : {}", + patientMemberId); } break; } } } } else { - logger.error(" :: Group doesn't have any members "); + logger.error("Group doesn't have any members"); } if (isGroupMemberRemoved) { if (group.hasMeta()) { @@ -772,7 +794,8 @@ public void removeMemberFromGroup(Group group, String patientMemberId, String pr group.setMeta(meta); } } else { - throw new UnprocessableEntityException("Group doesn't contain given memberId/patientReference"); + throw new UnprocessableEntityException( + "Group doesn't contain given memberId/patientReference"); } } } diff --git a/mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/FhirUtil.java similarity index 76% rename from mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java rename to plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/FhirUtil.java index 653d04044..889e4255f 100644 --- a/mal/src/main/java/org/hl7/davinci/atr/server/util/FhirUtil.java +++ b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/FhirUtil.java @@ -1,22 +1,20 @@ -package org.hl7.davinci.atr.server.util; +package org.opencds.cqf.ruler.atr.util; import java.util.ArrayList; import java.util.List; - import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Group.GroupMemberComponent; import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.UriType; -import org.hl7.fhir.r4.model.Group.GroupMemberComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import ca.uhn.fhir.rest.param.TokenAndListParam; import ca.uhn.fhir.rest.param.TokenOrListParam; import ca.uhn.fhir.rest.param.TokenParam; @@ -26,10 +24,12 @@ * The Class FhirUtil. */ public class FhirUtil { - + + private FhirUtil() {} + /** The Constant logger. */ - private static final Logger logger = LoggerFactory.getLogger(FhirUtil.class); - + private static final Logger logger = LoggerFactory.getLogger(FhirUtil.class); + /** * Creates the token and list param. * @@ -37,23 +37,23 @@ public class FhirUtil { * @param parameterName the parameter name * @return the token and list param */ - public static TokenAndListParam createTokenAndListParam(Parameters theParameters, String parameterName) { - TokenAndListParam tokenParam = new TokenAndListParam(); - + public static TokenAndListParam createTokenAndListParam(Parameters theParameters, + String parameterName) { + TokenAndListParam tokenParam = new TokenAndListParam(); + TokenOrListParam tokenOrParam = new TokenOrListParam(); - - + Identifier memberIdentifier = (Identifier) theParameters.getParameter(parameterName); TokenParam param = new TokenParam(); param.setSystem(memberIdentifier.getSystem()); param.setValue(memberIdentifier.getValue()); tokenOrParam.add(param); tokenParam.addValue(tokenOrParam); - + return tokenParam; } - - + + /** * Gets the reference. * @@ -64,36 +64,35 @@ public static TokenAndListParam createTokenAndListParam(Parameters theParameters public static Reference getReference(String theId, String resourceType) { Reference theReference = null; try { - if(StringUtils.isNotBlank(theId) && StringUtils.isNotBlank(resourceType)) { + if (StringUtils.isNotBlank(theId) && StringUtils.isNotBlank(resourceType)) { StringBuilder reference = new StringBuilder(); reference.append(resourceType); - reference.append(TextConstants.SINGLE_FORWORD_SLASH); + reference.append(TextConstants.SINGLE_FORWARD_SLASH); reference.append(theId); theReference = initReference(theReference); theReference.setReference(reference.toString()); } - }catch(Exception ex) { + } catch (Exception ex) { logger.error("\n Exception while setting getReference in FhirUtils class ", ex); } return theReference; } - + /** * Inits the reference. * * @param theReference the the reference * @return the reference */ - private static Reference initReference(Reference theReference){ - if(theReference == null) { + private static Reference initReference(Reference theReference) { + if (theReference == null) { return new Reference(); - } - else { + } else { return theReference; } } - - + + /** * Gets the code type. * @@ -103,17 +102,17 @@ private static Reference initReference(Reference theReference){ public static CodeType getCodeType(String theValue) { CodeType codeType = null; try { - if(StringUtils.isNotBlank(theValue)) { + if (StringUtils.isNotBlank(theValue)) { codeType = new CodeType(); codeType.setValue(theValue); } - }catch (Exception e) { + } catch (Exception e) { logger.error("Exception in getCodeType of FhirUtility ", e); } return codeType; } - - + + /** * Gets the extension for code type. * @@ -123,15 +122,16 @@ public static CodeType getCodeType(String theValue) { public static Extension getExtensionForCodeType(String typeText) { Extension theExtension = null; try { - if(StringUtils.isNotBlank(typeText)) { + if (StringUtils.isNotBlank(typeText)) { theExtension = new Extension(); UriType uri = getUriType(TextConstants.MEMBER_CHANGETYPE_SYSTEM); theExtension.setUrlElement(uri); CodeType theCode = getCodeType(typeText); theExtension.setValue(theCode); } - }catch(Exception ex) { - logger.error("\n Exception while setting getExtensionForCodeType in FhirUtility class ", ex); + } catch (Exception ex) { + logger.error("\n Exception while setting getExtensionForCodeType in FhirUtility class ", + ex); } return theExtension; } @@ -147,20 +147,21 @@ public static Extension getExtensionForCodeType(String typeText) { public static Extension getExtensionForReference(String id, String resourceType, String system) { Extension theExtension = null; try { - if(StringUtils.isNotBlank(id) && StringUtils.isNotBlank(resourceType)) { + if (StringUtils.isNotBlank(id) && StringUtils.isNotBlank(resourceType)) { theExtension = new Extension(); UriType uri = getUriType(system); theExtension.setUrlElement(uri); Reference theReference = getReference(id, resourceType); theExtension.setValue(theReference); } - }catch(Exception ex) { - logger.error("\n Exception while setting getExtensionForReference in FhirUtility class ", ex); + } catch (Exception ex) { + logger.error("\n Exception while setting getExtensionForReference in FhirUtility class ", + ex); } return theExtension; } - - + + /** * Gets the uri type. * @@ -170,17 +171,17 @@ public static Extension getExtensionForReference(String id, String resourceType, public static UriType getUriType(String theValue) { UriType uriType = null; try { - if(StringUtils.isNotBlank(theValue)) { + if (StringUtils.isNotBlank(theValue)) { uriType = new UriType(); uriType.setValue(theValue); } - }catch (Exception e) { + } catch (Exception e) { logger.error("Exception in getUriType of FhirUtility ", e); } return uriType; } - - + + /** * Gets the boolean type. * @@ -192,13 +193,13 @@ public static BooleanType getBooleanType(boolean data) { try { booleanType = new BooleanType(); booleanType.setValue(data); - }catch (Exception e) { + } catch (Exception e) { logger.error("Exception in getBooleanType of FhirUtility ", e); } return booleanType; } - - + + /** * Gets the period. * @@ -209,37 +210,36 @@ public static BooleanType getBooleanType(boolean data) { public static Period getPeriod(DateTimeType start, DateTimeType end) { Period thePeriod = null; try { - if(start != null) { - thePeriod=initPeriod(thePeriod); + if (start != null) { + thePeriod = initPeriod(thePeriod); thePeriod.setStartElement(start); } - if(end != null) { - thePeriod=initPeriod(thePeriod); + if (end != null) { + thePeriod = initPeriod(thePeriod); thePeriod.setEndElement(end); - } - }catch(Exception ex) { + } + } catch (Exception ex) { logger.error("\n Exception while setting getPeriod in FhirUtils class ", ex); } return thePeriod; } - - + + /** * Inits the period. * * @param thePeriod the the period * @return the period */ - private static Period initPeriod(Period thePeriod){ - if(thePeriod == null) { + private static Period initPeriod(Period thePeriod) { + if (thePeriod == null) { return new Period(); - } - else { + } else { return thePeriod; } } - - + + /** * Inits the extension list. * @@ -247,14 +247,13 @@ private static Period initPeriod(Period thePeriod){ * @return the list */ public static List initExtensionList(List extensionList) { - if(extensionList == null) { + if (extensionList == null) { return new ArrayList(); - } - else { + } else { return extensionList; } } - + /** * Gets the group member component. * @@ -265,33 +264,38 @@ public static List initExtensionList(List extensionList) { * @param attributionPeriod the attribution period * @return the group member component */ - public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, String providerId, String providerReference, String coverageReference, Period attributionPeriod) { + public static GroupMemberComponent getGroupMemberComponent(String patientMemberId, + String providerId, String providerReference, String coverageReference, + Period attributionPeriod) { GroupMemberComponent theGroupMemberComponent = new GroupMemberComponent(); List theMembeEextensionList = null; try { - if(StringUtils.isNotBlank(patientMemberId)) { + if (StringUtils.isNotBlank(patientMemberId)) { Reference theReference = getReference(patientMemberId, "Patient"); - if(theReference != null) { + if (theReference != null) { theGroupMemberComponent.setEntity(theReference); BooleanType theBoolean = getBooleanType(false); theGroupMemberComponent.setInactiveElement(theBoolean); } } - theMembeEextensionList = getGroupMemberComponentExtension(providerId, providerReference, coverageReference, TextConstants.NEW_TYPE); - if(theMembeEextensionList != null && !theMembeEextensionList.isEmpty()) { + theMembeEextensionList = getGroupMemberComponentExtension(providerId, providerReference, + coverageReference, TextConstants.NEW_TYPE); + if (theMembeEextensionList != null && !theMembeEextensionList.isEmpty()) { theGroupMemberComponent.setExtension(theMembeEextensionList); } - if(attributionPeriod != null) { - Period thePeriod = getPeriod(attributionPeriod.getStartElement(), attributionPeriod.getEndElement()); + if (attributionPeriod != null) { + Period thePeriod = + getPeriod(attributionPeriod.getStartElement(), attributionPeriod.getEndElement()); theGroupMemberComponent.setPeriod(thePeriod); } - }catch(Exception ex) { - logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + } catch (Exception ex) { + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", + ex); } return theGroupMemberComponent; } - - + + /** * Gets the group member component extension. * @@ -301,33 +305,36 @@ public static GroupMemberComponent getGroupMemberComponent(String patientMemberI * @param changeCode the change code * @return the group member component extension */ - public static List getGroupMemberComponentExtension(String providerId, String providerReference, - String coverageReference, String changeCode) { + public static List getGroupMemberComponentExtension(String providerId, + String providerReference, String coverageReference, String changeCode) { List theMembeEextensionList = null; try { - if(StringUtils.isNotBlank(changeCode)) { + if (StringUtils.isNotBlank(changeCode)) { Extension codeExtension = FhirUtil.getExtensionForCodeType(changeCode); - if(codeExtension != null) { + if (codeExtension != null) { theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); theMembeEextensionList.add(codeExtension); } } - if(StringUtils.isNotBlank(coverageReference)) { - Extension coverageExtension = FhirUtil.getExtensionForReference(coverageReference, "Coverage", TextConstants.MEMBER_COVERAGE_SYSTEM); - if(coverageExtension != null) { + if (StringUtils.isNotBlank(coverageReference)) { + Extension coverageExtension = FhirUtil.getExtensionForReference(coverageReference, + "Coverage", TextConstants.MEMBER_COVERAGE_SYSTEM); + if (coverageExtension != null) { theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); theMembeEextensionList.add(coverageExtension); } } - if(StringUtils.isNotBlank(providerId) && StringUtils.isNotBlank(providerReference)) { - Extension providerExtension = FhirUtil.getExtensionForReference(providerId, providerReference, TextConstants.MEMBER_PROVIDER_SYSTEM); - if(providerExtension != null) { + if (StringUtils.isNotBlank(providerId) && StringUtils.isNotBlank(providerReference)) { + Extension providerExtension = FhirUtil.getExtensionForReference(providerId, + providerReference, TextConstants.MEMBER_PROVIDER_SYSTEM); + if (providerExtension != null) { theMembeEextensionList = FhirUtil.initExtensionList(theMembeEextensionList); theMembeEextensionList.add(providerExtension); } } - }catch(Exception ex) { - logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", ex); + } catch (Exception ex) { + logger.error("\n Exception while setting getGroupMemberComponent in FhirUtility class ", + ex); } return theMembeEextensionList; } diff --git a/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/TextConstants.java b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/TextConstants.java new file mode 100644 index 000000000..68d748300 --- /dev/null +++ b/plugin/atr/src/main/java/org/opencds/cqf/ruler/atr/util/TextConstants.java @@ -0,0 +1,36 @@ +package org.opencds.cqf.ruler.atr.util; + +public final class TextConstants { + + private TextConstants() {} + + public static final String SINGLE_FORWARD_SLASH = "/"; + + public static final String MEMBER_ID = "memberId"; + + public static final String PROVIDER_NPI = "providerNpi"; + + public static final String PATIENT_REFERENCE = "patientReference"; + + public static final String PROVIDER_REFERENCE = "providerReference"; + + public static final String ATTRIBUTION_PERIOD = "attributionPeriod"; + + public static final String MEMBER_CHANGETYPE_SYSTEM = + "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-changeType"; + + public static final String MEMBER_COVERAGE_SYSTEM = + "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-coverageReference"; + + public static final String MEMBER_PROVIDER_SYSTEM = + "http://hl7.org/fhir/us/davinci-atr/StructureDefinition/ext-attributedProvider"; + + public static final String NEW_TYPE = "new"; + + public static final String CHANGE_TYPE = "change"; + + public static final String NOCHANGE_TYPE = "nochange"; + + /** The Constant HTTP_POST. */ + public static final String HTTP_POST = "POST"; +} diff --git a/mal/src/main/resources/META-INF/spring.factories b/plugin/atr/src/main/resources/META-INF/spring.factories similarity index 100% rename from mal/src/main/resources/META-INF/spring.factories rename to plugin/atr/src/main/resources/META-INF/spring.factories diff --git a/mal/src/main/resources/application.yaml b/plugin/atr/src/main/resources/application.yaml similarity index 100% rename from mal/src/main/resources/application.yaml rename to plugin/atr/src/main/resources/application.yaml diff --git a/plugin/pom.xml b/plugin/pom.xml index 8600d3160..16c86c819 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -11,6 +12,7 @@ pom + atr cds-hooks cpg case-reporting @@ -65,30 +67,6 @@ org.apache.maven.plugins maven-checkstyle-plugin - - diff --git a/server/pom.xml b/server/pom.xml index 42d66038c..4d981a041 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -272,9 +272,9 @@ runtime - org.hl7.davinci.atr.server - cqf-ruler-plugin-mal - 1.0.0 + org.opencds.cqf.ruler + cqf-ruler-atr + 0.5.0-SNAPSHOT runtime From 37b39c979a6f6c19bdfc62d3c7275e13619d2a3b Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Tue, 7 Jun 2022 10:34:29 -0600 Subject: [PATCH 6/6] Reset bulk export default --- server/src/main/resources/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/resources/application.yaml b/server/src/main/resources/application.yaml index 4c54807ba..087f97d89 100644 --- a/server/src/main/resources/application.yaml +++ b/server/src/main/resources/application.yaml @@ -130,7 +130,7 @@ hapi: # requests_enabled: true # responses_enabled: true # binary_storage_enabled: true - bulk_export_enabled: true + # bulk_export_enabled: true # subscription: # resthook_enabled: false # websocket_enabled: false