Attempting to perform MDM on a new resource type
This commit is contained in:
parent
5d1612eef4
commit
331acc1b55
|
@ -156,6 +156,7 @@ public class EmpiLink {
|
|||
}
|
||||
|
||||
public EmpiLink setSourceResourcePid(Long theSourceResourcePid) {
|
||||
myPersonPid = theSourceResourcePid;
|
||||
mySourceResourcePid = theSourceResourcePid;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class EmpiControllerSvcImpl implements IEmpiControllerSvc {
|
|||
IEmpiLinkUpdaterSvc myIEmpiLinkUpdaterSvc;
|
||||
|
||||
@Override
|
||||
public IAnyResource mergePersons(String theFromPersonId, String theToPersonId, EmpiTransactionContext theEmpiTransactionContext) {
|
||||
public IAnyResource mergeGoldenResources(String theFromPersonId, String theToPersonId, EmpiTransactionContext theEmpiTransactionContext) {
|
||||
IAnyResource fromPerson = myEmpiControllerHelper.getLatestPersonFromIdOrThrowException(ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theFromPersonId);
|
||||
IAnyResource toPerson = myEmpiControllerHelper.getLatestPersonFromIdOrThrowException(ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, theToPersonId);
|
||||
myEmpiControllerHelper.validateMergeResources(fromPerson, toPerson);
|
||||
|
@ -75,7 +75,7 @@ public class EmpiControllerSvcImpl implements IEmpiControllerSvc {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Stream<EmpiLinkJson> getDuplicatePersons(EmpiTransactionContext theEmpiContext) {
|
||||
public Stream<EmpiLinkJson> getDuplicateGoldenResources(EmpiTransactionContext theEmpiContext) {
|
||||
return myEmpiLinkQuerySvc.getDuplicatePersons(theEmpiContext);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class EmpiControllerSvcImpl implements IEmpiControllerSvc {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void notDuplicatePerson(String thePersonId, String theTargetPersonId, EmpiTransactionContext theEmpiContext) {
|
||||
public void notDuplicateGoldenResource(String thePersonId, String theTargetPersonId, EmpiTransactionContext theEmpiContext) {
|
||||
IAnyResource person = myEmpiControllerHelper.getLatestPersonFromIdOrThrowException(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, thePersonId);
|
||||
IAnyResource target = myEmpiControllerHelper.getLatestPersonFromIdOrThrowException(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theTargetPersonId);
|
||||
|
||||
|
|
|
@ -62,13 +62,13 @@ public class EmpiLinkQuerySvcImpl implements IEmpiLinkQuerySvc {
|
|||
EmpiLinkJson retval = new EmpiLinkJson();
|
||||
String targetId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getTargetPid()).toVersionless().getValue();
|
||||
retval.setTargetId(targetId);
|
||||
String personId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourceResourcePid()).toVersionless().getValue();
|
||||
retval.setPersonId(personId);
|
||||
String goldenResourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourceResourcePid()).toVersionless().getValue();
|
||||
retval.setGoldenResourceId(goldenResourceId);
|
||||
retval.setCreated(theLink.getCreated());
|
||||
retval.setEidMatch(theLink.getEidMatch());
|
||||
retval.setLinkSource(theLink.getLinkSource());
|
||||
retval.setMatchResult(theLink.getMatchResult());
|
||||
retval.setNewPerson(theLink.getHadToCreateNewResource());
|
||||
retval.setLinkCreatedNewResource(theLink.getHadToCreateNewResource());
|
||||
retval.setScore(theLink.getScore());
|
||||
retval.setUpdated(theLink.getUpdated());
|
||||
retval.setVector(theLink.getVector());
|
||||
|
|
|
@ -135,19 +135,18 @@ public class EmpiLinkUpdaterSvcImpl implements IEmpiLinkUpdaterSvc {
|
|||
myEmpiLinkDaoSvc.save(empiLink);
|
||||
}
|
||||
|
||||
private void validateNotDuplicatePersonRequest(IAnyResource thePerson, IAnyResource theTarget) {
|
||||
String personType = myFhirContext.getResourceType(thePerson);
|
||||
/**
|
||||
* Ensure that the two resources are of the same type and both are managed by HAPI-EMPI.
|
||||
*/
|
||||
private void validateNotDuplicatePersonRequest(IAnyResource theGoldenResource, IAnyResource theTarget) {
|
||||
String goldenResourceType = myFhirContext.getResourceType(theGoldenResource);
|
||||
String targetType = myFhirContext.getResourceType(theTarget);
|
||||
if (!"Person".equals(personType)) {
|
||||
throw new InvalidRequestException("First argument to " + ProviderConstants.MDM_UPDATE_LINK + " must be a Person. Was " + personType);
|
||||
}
|
||||
if (!"Person".equals(targetType)) {
|
||||
throw new InvalidRequestException("Second argument to " + ProviderConstants.MDM_UPDATE_LINK + " must be a Person . Was " + targetType);
|
||||
if (!goldenResourceType.equalsIgnoreCase(targetType)) {
|
||||
throw new InvalidRequestException("First argument to " + ProviderConstants.MDM_UPDATE_LINK + " must be the same resource type as the second argument. Was " + goldenResourceType + "/" + targetType);
|
||||
}
|
||||
|
||||
if (!EmpiUtil.isEmpiManaged(thePerson) || !EmpiUtil.isEmpiManaged(theTarget)) {
|
||||
throw new InvalidRequestException("Only EMPI Managed Person resources may be updated via this operation. The Person resource provided is not tagged as managed by hapi-empi");
|
||||
if (!EmpiUtil.isEmpiManaged(theGoldenResource) || !EmpiUtil.isEmpiManaged(theTarget)) {
|
||||
throw new InvalidRequestException("Only EMPI Managed Golden Resources may be updated via this operation. The resource provided is not tagged as managed by hapi-empi");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ public class EmpiSubmitSvcImpl implements IEmpiSubmitSvc {
|
|||
@Transactional
|
||||
public long submitAllTargetTypesToEmpi(@Nullable String theCriteria) {
|
||||
long submittedCount = 0;
|
||||
submittedCount += submitPatientTypeToEmpi(theCriteria);
|
||||
submittedCount += submitPractitionerTypeToEmpi(theCriteria);
|
||||
submittedCount += submitPatientTypeToMdm(theCriteria);
|
||||
submittedCount += submitPractitionerTypeToMdm(theCriteria);
|
||||
return submittedCount;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ public class EmpiSubmitSvcImpl implements IEmpiSubmitSvc {
|
|||
total += loadPidsAndSubmitToEmpiChannel(theSearchBuilder, pidBatch);
|
||||
} while (query.hasNext());
|
||||
} catch (IOException theE) {
|
||||
throw new InternalErrorException("Failure while attempting to query resources for " + ProviderConstants.OPERATION_EMPI_SUBMIT, theE);
|
||||
throw new InternalErrorException("Failure while attempting to query resources for " + ProviderConstants.OPERATION_MDM_SUBMIT, theE);
|
||||
}
|
||||
ourLog.info("EMPI Submit complete. Submitted a total of {} resources.", total);
|
||||
return total;
|
||||
|
@ -123,19 +123,19 @@ public class EmpiSubmitSvcImpl implements IEmpiSubmitSvc {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public long submitPractitionerTypeToEmpi(@Nullable String theCriteria) {
|
||||
public long submitPractitionerTypeToMdm(@Nullable String theCriteria) {
|
||||
return submitTargetTypeToEmpi("Practitioner", theCriteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public long submitPatientTypeToEmpi(@Nullable String theCriteria) {
|
||||
public long submitPatientTypeToMdm(@Nullable String theCriteria) {
|
||||
return submitTargetTypeToEmpi("Patient", theCriteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public long submitTargetToEmpi(IIdType theId) {
|
||||
public long submitTargetToMdm(IIdType theId) {
|
||||
resolveTargetTypeOrThrowException(theId.getResourceType());
|
||||
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theId.getResourceType());
|
||||
IBaseResource read = resourceDao.read(theId);
|
||||
|
@ -145,7 +145,7 @@ public class EmpiSubmitSvcImpl implements IEmpiSubmitSvc {
|
|||
|
||||
private void resolveTargetTypeOrThrowException(String theResourceType) {
|
||||
if (!EmpiUtil.supportedTargetType(theResourceType)) {
|
||||
throw new InvalidRequestException(ProviderConstants.OPERATION_EMPI_SUBMIT + " does not support resource type: " + theResourceType);
|
||||
throw new InvalidRequestException(ProviderConstants.OPERATION_MDM_SUBMIT + " does not support resource type: " + theResourceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,8 +41,9 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.ContactPoint;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.Medication;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Person;
|
||||
import org.hl7.fhir.r4.model.Practitioner;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -85,6 +86,10 @@ abstract public class BaseEmpiR4Test extends BaseJpaR4Test {
|
|||
@Autowired
|
||||
protected IFhirResourceDao<Patient> myPatientDao;
|
||||
@Autowired
|
||||
protected IFhirResourceDao<Organization> myOrganizationDao;
|
||||
@Autowired
|
||||
protected IFhirResourceDao<Medication> myMedicationDao;
|
||||
@Autowired
|
||||
protected IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
protected EmpiResourceMatcherSvc myEmpiResourceMatcherSvc;
|
||||
|
@ -170,6 +175,16 @@ abstract public class BaseEmpiR4Test extends BaseJpaR4Test {
|
|||
Patient patient = (Patient) outcome.getResource();
|
||||
patient.setId(outcome.getId());
|
||||
return patient;
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected Medication createMedication(Medication theMedication) {
|
||||
//Note that since our empi-rules block on active=true, all patients must be active.
|
||||
DaoMethodOutcome outcome = myMedicationDao.create(theMedication);
|
||||
Medication medication = (Medication) outcome.getResource();
|
||||
medication.setId(outcome.getId());
|
||||
return medication;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -37,6 +37,7 @@ public abstract class BaseProviderR4Test extends BaseEmpiR4Test {
|
|||
Resource resource = resourceLoader.getResource(theString);
|
||||
String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8);
|
||||
myEmpiSettings.setScriptText(json);
|
||||
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
|
|
|
@ -25,8 +25,8 @@ public class EmpiProviderBatchR4Test extends BaseLinkR4Test {
|
|||
|
||||
protected Practitioner myPractitioner;
|
||||
protected StringType myPractitionerId;
|
||||
protected IAnyResource myPractitionerPerson;
|
||||
protected StringType myPractitionerPersonId;
|
||||
protected IAnyResource myGoldenPractitier;
|
||||
protected StringType myGoldenPractitionerId;
|
||||
|
||||
@Autowired
|
||||
IInterceptorService myInterceptorService;
|
||||
|
@ -38,8 +38,8 @@ public class EmpiProviderBatchR4Test extends BaseLinkR4Test {
|
|||
super.before();
|
||||
myPractitioner = createPractitionerAndUpdateLinks(buildPractitionerWithNameAndId("some_pract", "some_pract_id"));
|
||||
myPractitionerId = new StringType(myPractitioner.getIdElement().getValue());
|
||||
myPractitionerPerson = getSourceResourceFromTargetResource(myPractitioner);
|
||||
myPractitionerPersonId = new StringType(myPractitionerPerson.getIdElement().getValue());
|
||||
myGoldenPractitier = getSourceResourceFromTargetResource(myPractitioner);
|
||||
myGoldenPractitionerId = new StringType(myGoldenPractitier.getIdElement().getValue());
|
||||
myInterceptorService.registerAnonymousInterceptor(Pointcut.EMPI_AFTER_PERSISTED_RESOURCE_CHECKED, afterEmpiLatch);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,13 @@ package ca.uhn.fhir.jpa.empi.provider;
|
|||
import ca.uhn.fhir.empi.api.EmpiConstants;
|
||||
import com.google.common.collect.Ordering;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.Medication;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.codesystems.MatchGrade;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -15,7 +19,9 @@ import org.slf4j.LoggerFactory;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class EmpiProviderMatchR4Test extends BaseProviderR4Test {
|
||||
|
||||
|
@ -52,6 +58,63 @@ public class EmpiProviderMatchR4Test extends BaseProviderR4Test {
|
|||
assertEquals(MatchGrade.CERTAIN.toCode(), matchGradeExtension.getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMedicationMatch() throws Exception {
|
||||
Organization org = new Organization();
|
||||
org.setId("Organization/mfr");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
Medication medication = buildMedication();
|
||||
Medication createdMedication = createMedication(medication);
|
||||
Medication newMedication = buildMedication();
|
||||
|
||||
Bundle result = myEmpiProviderR4.serverMatch(newMedication, new StringType("Medication"));
|
||||
assertEquals(1, result.getEntry().size());
|
||||
|
||||
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
|
||||
assertEquals(createdMedication.getId(), entry0.getResource().getId());
|
||||
|
||||
Bundle.BundleEntrySearchComponent searchComponent = entry0.getSearch();
|
||||
assertEquals(Bundle.SearchEntryMode.MATCH, searchComponent.getMode());
|
||||
|
||||
assertEquals(2.0 / 3.0, searchComponent.getScore().doubleValue(), 0.01);
|
||||
Extension matchGradeExtension = searchComponent.getExtensionByUrl(EmpiConstants.FIHR_STRUCTURE_DEF_MATCH_GRADE_URL_NAMESPACE);
|
||||
assertNotNull(matchGradeExtension);
|
||||
assertEquals(MatchGrade.CERTAIN.toCode(), matchGradeExtension.getValue().toString());
|
||||
|
||||
}
|
||||
|
||||
private Medication buildMedication() {
|
||||
Medication medication = new Medication();
|
||||
medication.setManufacturer(new Reference("Organization/mfr"));
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
codeableConcept.addCoding().setSystem("zoop").setCode("boop");
|
||||
medication.setCode(codeableConcept);
|
||||
return medication;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerLevelMatch() throws Exception {
|
||||
Patient jane = buildJanePatient();
|
||||
jane.setActive(true);
|
||||
Patient createdJane = createPatient(jane);
|
||||
Patient newJane = buildJanePatient();
|
||||
|
||||
Bundle result = myEmpiProviderR4.serverMatch(newJane, new StringType("Patient"));
|
||||
assertEquals(1, result.getEntry().size());
|
||||
|
||||
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
|
||||
assertEquals(createdJane.getId(), entry0.getResource().getId());
|
||||
|
||||
Bundle.BundleEntrySearchComponent searchComponent = entry0.getSearch();
|
||||
assertEquals(Bundle.SearchEntryMode.MATCH, searchComponent.getMode());
|
||||
|
||||
assertEquals(2.0 / 3.0, searchComponent.getScore().doubleValue(), 0.01);
|
||||
Extension matchGradeExtension = searchComponent.getExtensionByUrl(EmpiConstants.FIHR_STRUCTURE_DEF_MATCH_GRADE_URL_NAMESPACE);
|
||||
assertNotNull(matchGradeExtension);
|
||||
assertEquals(MatchGrade.CERTAIN.toCode(), matchGradeExtension.getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchOrder() throws Exception {
|
||||
Patient jane0 = buildJanePatient();
|
||||
|
|
|
@ -82,7 +82,7 @@ public class EmpiProviderQueryLinkR4Test extends BaseLinkR4Test {
|
|||
|
||||
@Test
|
||||
public void testQueryPossibleDuplicates() {
|
||||
Parameters result = myEmpiProviderR4.getDuplicatePersons(myRequestDetails);
|
||||
Parameters result = myEmpiProviderR4.getDuplicateGoldenResources(myRequestDetails);
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(result));
|
||||
List<Parameters.ParametersParameterComponent> list = result.getParameter();
|
||||
assertThat(list, hasSize(1));
|
||||
|
@ -93,7 +93,7 @@ public class EmpiProviderQueryLinkR4Test extends BaseLinkR4Test {
|
|||
@Test
|
||||
public void testNotDuplicate() {
|
||||
{
|
||||
Parameters result = myEmpiProviderR4.getDuplicatePersons(myRequestDetails);
|
||||
Parameters result = myEmpiProviderR4.getDuplicateGoldenResources(myRequestDetails);
|
||||
List<Parameters.ParametersParameterComponent> list = result.getParameter();
|
||||
assertThat(list, hasSize(1));
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public class EmpiProviderQueryLinkR4Test extends BaseLinkR4Test {
|
|||
assertEquals("success", result.getParameterFirstRep().getName());
|
||||
assertTrue(((BooleanType) (result.getParameterFirstRep().getValue())).booleanValue());
|
||||
}
|
||||
Parameters result = myEmpiProviderR4.getDuplicatePersons(myRequestDetails);
|
||||
Parameters result = myEmpiProviderR4.getDuplicateGoldenResources(myRequestDetails);
|
||||
List<Parameters.ParametersParameterComponent> list = result.getParameter();
|
||||
assertThat(list, hasSize(0));
|
||||
}
|
||||
|
@ -120,9 +120,9 @@ public class EmpiProviderQueryLinkR4Test extends BaseLinkR4Test {
|
|||
|
||||
private void assertEmpiLink(int theExpectedSize, List<Parameters.ParametersParameterComponent> thePart, String thePersonId, String theTargetId, EmpiMatchResultEnum theMatchResult, String theEidMatch, String theNewPerson, String theScore) {
|
||||
assertThat(thePart, hasSize(theExpectedSize));
|
||||
assertThat(thePart.get(0).getName(), is("personId"));
|
||||
assertThat(thePart.get(0).getName(), is("goldenResourceId"));
|
||||
assertThat(thePart.get(0).getValue().toString(), is(removeVersion(thePersonId)));
|
||||
assertThat(thePart.get(1).getName(), is("targetId"));
|
||||
assertThat(thePart.get(1).getName(), is("targetResourceId"));
|
||||
assertThat(thePart.get(1).getValue().toString(), is(removeVersion(theTargetId)));
|
||||
if (theExpectedSize > 2) {
|
||||
assertThat(thePart.get(2).getName(), is("matchResult"));
|
||||
|
@ -133,7 +133,7 @@ public class EmpiProviderQueryLinkR4Test extends BaseLinkR4Test {
|
|||
assertThat(thePart.get(4).getName(), is("eidMatch"));
|
||||
assertThat(thePart.get(4).getValue().primitiveValue(), is(theEidMatch));
|
||||
|
||||
assertThat(thePart.get(5).getName(), is("newPerson"));
|
||||
assertThat(thePart.get(5).getName(), is("hadToCreateNewResource"));
|
||||
assertThat(thePart.get(5).getValue().primitiveValue(), is(theNewPerson));
|
||||
|
||||
assertThat(thePart.get(6).getName(), is("score"));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"version": "1",
|
||||
"mdmTypes": ["Patient", "Practitioner", "Medication"],
|
||||
"candidateSearchParams": [
|
||||
{
|
||||
"resourceType": "Patient",
|
||||
|
@ -13,6 +14,12 @@
|
|||
"identifier"
|
||||
]
|
||||
},
|
||||
{
|
||||
"resourceType": "Medication",
|
||||
"searchParams": [
|
||||
"manufacturer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"resourceType": "Patient",
|
||||
"searchParams": [
|
||||
|
@ -22,15 +29,30 @@
|
|||
],
|
||||
"candidateFilterSearchParams": [
|
||||
{
|
||||
"resourceType": "*",
|
||||
"resourceType": "Practitioner",
|
||||
"searchParam": "active",
|
||||
"fixedValue": "true"
|
||||
},
|
||||
{
|
||||
"resourceType": "Patient",
|
||||
"searchParam": "active",
|
||||
"fixedValue": "true"
|
||||
}
|
||||
],
|
||||
"matchFields": [
|
||||
{
|
||||
"name": "cosine-code",
|
||||
"resourceType": "Medication",
|
||||
"resourcePath": "code",
|
||||
"similarity": {
|
||||
"algorithm": "COSINE",
|
||||
"matchThreshold": 0.8,
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cosine-given-name",
|
||||
"resourceType": "*",
|
||||
"resourceType": "Patient",
|
||||
"resourcePath": "name.given",
|
||||
"similarity": {
|
||||
"algorithm": "COSINE",
|
||||
|
@ -40,7 +62,7 @@
|
|||
},
|
||||
{
|
||||
"name": "jaro-last-name",
|
||||
"resourceType": "*",
|
||||
"resourceType": "Patient",
|
||||
"resourcePath": "name.family",
|
||||
"similarity": {
|
||||
"algorithm": "JARO_WINKLER",
|
||||
|
@ -50,7 +72,36 @@
|
|||
},
|
||||
{
|
||||
"name": "medicare-id",
|
||||
"resourceType": "*",
|
||||
"resourceType": "Patient",
|
||||
"resourcePath": "identifier",
|
||||
"matcher": {
|
||||
"algorithm": "IDENTIFIER",
|
||||
"identifierSystem": "http://hl7.org/fhir/sid/us-medicare"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cosine-given-name-pract",
|
||||
"resourceType": "Practitioner",
|
||||
"resourcePath": "name.given",
|
||||
"similarity": {
|
||||
"algorithm": "COSINE",
|
||||
"matchThreshold": 0.8,
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "jaro-last-name-pract",
|
||||
"resourceType": "Practitioner",
|
||||
"resourcePath": "name.family",
|
||||
"similarity": {
|
||||
"algorithm": "JARO_WINKLER",
|
||||
"matchThreshold": 0.8,
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "medicare-id-pract",
|
||||
"resourceType": "Practitioner",
|
||||
"resourcePath": "identifier",
|
||||
"matcher": {
|
||||
"algorithm": "IDENTIFIER",
|
||||
|
@ -60,7 +111,10 @@
|
|||
],
|
||||
"matchResultMap": {
|
||||
"cosine-given-name": "POSSIBLE_MATCH",
|
||||
"cosine-given-name,jaro-last-name": "MATCH"
|
||||
"cosine-given-name,jaro-last-name": "MATCH",
|
||||
"cosine-given-name-pract": "POSSIBLE_MATCH",
|
||||
"cosine-given-name-pract,jaro-last-name-pract": "MATCH",
|
||||
"cosine-code": "MATCH"
|
||||
},
|
||||
"eidSystem": "http://company.io/fhir/NamingSystem/custom-eid-system"
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import java.util.Date;
|
||||
|
||||
public class EmpiLinkJson implements IModelJson {
|
||||
@JsonProperty("personId")
|
||||
private String myPersonId;
|
||||
@JsonProperty("goldenResourceId")
|
||||
private String myGoldenResourceId;
|
||||
|
||||
@JsonProperty("targetId")
|
||||
private String myTargetId;
|
||||
|
@ -52,8 +52,8 @@ public class EmpiLinkJson implements IModelJson {
|
|||
private Boolean myEidMatch;
|
||||
|
||||
/** This link created a new person **/
|
||||
@JsonProperty("newPerson")
|
||||
private Boolean myNewPerson;
|
||||
@JsonProperty("linkCreatedNewGoldenResource")
|
||||
private Boolean myLinkCreatedNewResource;
|
||||
|
||||
@JsonProperty("vector")
|
||||
private Long myVector;
|
||||
|
@ -61,12 +61,12 @@ public class EmpiLinkJson implements IModelJson {
|
|||
@JsonProperty("score")
|
||||
private Double myScore;
|
||||
|
||||
public String getPersonId() {
|
||||
return myPersonId;
|
||||
public String getGoldenResourceId() {
|
||||
return myGoldenResourceId;
|
||||
}
|
||||
|
||||
public EmpiLinkJson setPersonId(String thePersonId) {
|
||||
myPersonId = thePersonId;
|
||||
public EmpiLinkJson setGoldenResourceId(String theGoldenResourceId) {
|
||||
myGoldenResourceId = theGoldenResourceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -133,12 +133,12 @@ public class EmpiLinkJson implements IModelJson {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Boolean getNewPerson() {
|
||||
return myNewPerson;
|
||||
public Boolean getLinkCreatedNewResource() {
|
||||
return myLinkCreatedNewResource;
|
||||
}
|
||||
|
||||
public EmpiLinkJson setNewPerson(Boolean theNewPerson) {
|
||||
myNewPerson = theNewPerson;
|
||||
public EmpiLinkJson setLinkCreatedNewResource(Boolean theLinkCreatedNewResource) {
|
||||
myLinkCreatedNewResource = theLinkCreatedNewResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ import java.util.stream.Stream;
|
|||
|
||||
public interface IEmpiControllerSvc {
|
||||
Stream<EmpiLinkJson> queryLinks(@Nullable String thePersonId, @Nullable String theTargetId, @Nullable String theMatchResult, @Nullable String theLinkSource, EmpiTransactionContext theEmpiContext);
|
||||
Stream<EmpiLinkJson> getDuplicatePersons(EmpiTransactionContext theEmpiContext);
|
||||
void notDuplicatePerson(String thePersonId, String theTargetPersonId, EmpiTransactionContext theEmpiContext);
|
||||
IAnyResource mergePersons(String theFromPersonId, String theToPersonId, EmpiTransactionContext theEmpiTransactionContext);
|
||||
Stream<EmpiLinkJson> getDuplicateGoldenResources(EmpiTransactionContext theEmpiContext);
|
||||
void notDuplicateGoldenResource(String thePersonId, String theTargetPersonId, EmpiTransactionContext theEmpiContext);
|
||||
IAnyResource mergeGoldenResources(String theFromPersonId, String theToPersonId, EmpiTransactionContext theEmpiTransactionContext);
|
||||
IAnyResource updateLink(String thePersonId, String theTargetId, String theMatchResult, EmpiTransactionContext theEmpiContext);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public interface IEmpiSubmitSvc {
|
|||
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing.
|
||||
* @return the number of resources submitted for EMPI processing.
|
||||
*/
|
||||
long submitPractitionerTypeToEmpi(String theCriteria);
|
||||
long submitPractitionerTypeToMdm(String theCriteria);
|
||||
|
||||
/**
|
||||
* Convenience method that calls {@link #submitTargetTypeToEmpi(String, String)} with the type pre-populated.
|
||||
|
@ -61,13 +61,13 @@ public interface IEmpiSubmitSvc {
|
|||
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for EMPI processing.
|
||||
* @return the number of resources submitted for EMPI processing.
|
||||
*/
|
||||
long submitPatientTypeToEmpi(String theCriteria);
|
||||
long submitPatientTypeToMdm(String theCriteria);
|
||||
|
||||
/**
|
||||
* Given an ID and a target type valid for EMPI, manually submit the given ID for EMPI processing.
|
||||
* @param theId the ID of the resource to process for EMPI.
|
||||
* @return the constant `1`, as if this function returns successfully, it will have processed one resource for EMPI.
|
||||
*/
|
||||
long submitTargetToEmpi(IIdType theId);
|
||||
long submitTargetToMdm(IIdType theId);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class EmpiTransactionContext {
|
|||
SUBMIT_RESOURCE_TO_EMPI,
|
||||
QUERY_LINKS,
|
||||
UPDATE_LINK,
|
||||
DUPLICATE_PERSONS,
|
||||
DUPLICATE_GOLDEN_RESOURCES,
|
||||
NOT_DUPLICATE,
|
||||
MERGE_PERSONS
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@ public abstract class BaseEmpiProvider {
|
|||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
protected void validateMergeParameters(IPrimitiveType<String> theFromPersonId, IPrimitiveType<String> theToPersonId) {
|
||||
validateNotNull(ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theFromPersonId);
|
||||
validateNotNull(ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, theToPersonId);
|
||||
if (theFromPersonId.getValue().equals(theToPersonId.getValue())) {
|
||||
protected void validateMergeParameters(IPrimitiveType<String> theFromGoldenResourceId, IPrimitiveType<String> theToGoldenResourceId) {
|
||||
validateNotNull(ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, theFromGoldenResourceId);
|
||||
validateNotNull(ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, theToGoldenResourceId);
|
||||
if (theFromGoldenResourceId.getValue().equals(theToGoldenResourceId.getValue())) {
|
||||
throw new InvalidRequestException("fromPersonId must be different from toPersonId");
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,9 @@ public abstract class BaseEmpiProvider {
|
|||
}
|
||||
}
|
||||
|
||||
protected void validateUpdateLinkParameters(IPrimitiveType<String> thePersonId, IPrimitiveType<String> theTargetId, IPrimitiveType<String> theMatchResult) {
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, thePersonId);
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theTargetId);
|
||||
protected void validateUpdateLinkParameters(IPrimitiveType<String> theGoldenResourceId, IPrimitiveType<String> theResourceId, IPrimitiveType<String> theMatchResult) {
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theResourceId);
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_MATCH_RESULT, theMatchResult);
|
||||
EmpiMatchResultEnum matchResult = EmpiMatchResultEnum.valueOf(theMatchResult.getValue());
|
||||
switch (matchResult) {
|
||||
|
@ -72,12 +72,12 @@ public abstract class BaseEmpiProvider {
|
|||
}
|
||||
}
|
||||
|
||||
protected void validateNotDuplicateParameters(IPrimitiveType<String> thePersonId, IPrimitiveType<String> theTargetId) {
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, thePersonId);
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theTargetId);
|
||||
protected void validateNotDuplicateParameters(IPrimitiveType<String> theGoldenResourceId, IPrimitiveType<String> theResourceId) {
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
|
||||
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theResourceId);
|
||||
}
|
||||
|
||||
protected EmpiTransactionContext createEmpiContext(RequestDetails theRequestDetails, EmpiTransactionContext.OperationType theOperationType) {
|
||||
protected EmpiTransactionContext createMdmContext(RequestDetails theRequestDetails, EmpiTransactionContext.OperationType theOperationType) {
|
||||
TransactionLogMessages transactionLogMessages = TransactionLogMessages.createFromTransactionGuid(theRequestDetails.getTransactionGuid());
|
||||
return new EmpiTransactionContext(transactionLogMessages, theOperationType);
|
||||
}
|
||||
|
@ -94,17 +94,18 @@ public abstract class BaseEmpiProvider {
|
|||
|
||||
theEmpiLinkStream.forEach(empiLink -> {
|
||||
IBase resultPart = ParametersUtil.addParameterToParameters(myFhirContext, retval, "link");
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "personId", empiLink.getPersonId());
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "targetId", empiLink.getTargetId());
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "goldenResourceId", empiLink.getGoldenResourceId());
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "targetResourceId", empiLink.getTargetId());
|
||||
|
||||
if (includeResultAndSource) {
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "matchResult", empiLink.getMatchResult().name());
|
||||
ParametersUtil.addPartString(myFhirContext, resultPart, "linkSource", empiLink.getLinkSource().name());
|
||||
ParametersUtil.addPartBoolean(myFhirContext, resultPart, "eidMatch", empiLink.getEidMatch());
|
||||
ParametersUtil.addPartBoolean(myFhirContext, resultPart, "newPerson", empiLink.getNewPerson());
|
||||
ParametersUtil.addPartBoolean(myFhirContext, resultPart, "hadToCreateNewResource", empiLink.getLinkCreatedNewResource());
|
||||
ParametersUtil.addPartDecimal(myFhirContext, resultPart, "score", empiLink.getScore());
|
||||
}
|
||||
});
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class EmpiControllerHelper {
|
|||
}
|
||||
|
||||
public IAnyResource getLatestPersonFromIdOrThrowException(String theParamName, String theId) {
|
||||
IdDt personId = EmpiControllerUtil.getPersonIdDtOrThrowException(theParamName, theId);
|
||||
IdDt personId = EmpiControllerUtil.getGoldenIdDtOrThrowException(theParamName, theId);
|
||||
return loadResource(personId.toUnqualifiedVersionless());
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class EmpiControllerUtil {
|
|||
if (thePersonId == null) {
|
||||
return null;
|
||||
}
|
||||
return getPersonIdDtOrThrowException(theName, thePersonId);
|
||||
return getGoldenIdDtOrThrowException(theName, thePersonId);
|
||||
}
|
||||
|
||||
public static IIdType extractTargetIdDtOrNull(String theName, String theTargetId) {
|
||||
|
@ -56,13 +56,13 @@ public class EmpiControllerUtil {
|
|||
return getTargetIdDtOrThrowException(theName, theTargetId);
|
||||
}
|
||||
|
||||
static IdDt getPersonIdDtOrThrowException(String theParamName, String theId) {
|
||||
IdDt personId = new IdDt(theId);
|
||||
if (!"Person".equals(personId.getResourceType()) ||
|
||||
personId.getIdPart() == null) {
|
||||
throw new InvalidRequestException(theParamName + " is '" + theId + "'. must have form Person/<id> where <id> is the id of the person");
|
||||
static IdDt getGoldenIdDtOrThrowException(String theParamName, String theId) {
|
||||
IdDt goldenResourceId = new IdDt(theId);
|
||||
//TODO GGG MDM: maybe add a gate here to only consider resources that can possibly be EMPI'ed?
|
||||
if (goldenResourceId.getIdPart() == null) {
|
||||
throw new InvalidRequestException(theParamName + " is '" + theId + "'. must have form <resourceType>/<id> where <id> is the id of the resource");
|
||||
}
|
||||
return personId;
|
||||
return goldenResourceId;
|
||||
}
|
||||
|
||||
public static IIdType getTargetIdDtOrThrowException(String theParamName, String theId) {
|
||||
|
|
|
@ -49,8 +49,10 @@ import org.hl7.fhir.dstu3.model.Practitioner;
|
|||
import org.hl7.fhir.dstu3.model.Resource;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.dstu3.model.codesystems.MatchGrade;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
@ -77,33 +79,23 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_MATCH, type = Patient.class)
|
||||
public Bundle match(@OperationParam(name = ProviderConstants.EMPI_MATCH_RESOURCE, min = 1, max = 1) Patient thePatient) {
|
||||
public Bundle match(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) Patient thePatient) {
|
||||
if (thePatient == null) {
|
||||
throw new InvalidRequestException("resource may not be null");
|
||||
}
|
||||
|
||||
List<MatchedTarget> matches = myEmpiMatchFinderSvc.getMatchedTargets("Patient", thePatient);
|
||||
matches.sort(Comparator.comparing((MatchedTarget m) -> m.getMatchResult().getNormalizedScore()).reversed());
|
||||
return getMatchesAndPossibleMatchesForResource(thePatient, "Patient");
|
||||
}
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.setType(Bundle.BundleType.SEARCHSET);
|
||||
retVal.setId(UUID.randomUUID().toString());
|
||||
retVal.getMeta().setLastUpdatedElement(InstantType.now());
|
||||
|
||||
for (MatchedTarget next : matches) {
|
||||
boolean shouldKeepThisEntry = next.isMatch() || next.isPossibleMatch();
|
||||
if (!shouldKeepThisEntry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Bundle.BundleEntryComponent entry = new Bundle.BundleEntryComponent();
|
||||
entry.setResource((Resource) next.getTarget());
|
||||
entry.setSearch(toBundleEntrySearchComponent(next));
|
||||
|
||||
retVal.addEntry(entry);
|
||||
@Operation(name = ProviderConstants.MDM_MATCH)
|
||||
public Bundle serverMatch(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) IAnyResource theResource,
|
||||
@OperationParam(name = ProviderConstants.MDM_RESOURCE_TYPE, min = 1, max = 1) StringType theResourceType
|
||||
) {
|
||||
if (theResource == null) {
|
||||
throw new InvalidRequestException("resource may not be null");
|
||||
}
|
||||
return getMatchesAndPossibleMatchesForResource(theResource, theResourceType.getValueNotNull());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Bundle.BundleEntrySearchComponent toBundleEntrySearchComponent(MatchedTarget theMatchedTarget) {
|
||||
|
@ -111,12 +103,7 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
searchComponent.setMode(Bundle.SearchEntryMode.MATCH);
|
||||
searchComponent.setScore(theMatchedTarget.getMatchResult().getNormalizedScore());
|
||||
|
||||
MatchGrade matchGrade = MatchGrade.PROBABLE;
|
||||
if (theMatchedTarget.isMatch()) {
|
||||
matchGrade = MatchGrade.CERTAIN;
|
||||
} else if (theMatchedTarget.isPossibleMatch()) {
|
||||
matchGrade = MatchGrade.POSSIBLE;
|
||||
}
|
||||
MatchGrade matchGrade = getMatchGrade(theMatchedTarget);
|
||||
|
||||
searchComponent.addExtension(EmpiConstants.FIHR_STRUCTURE_DEF_MATCH_GRADE_URL_NAMESPACE, new CodeType(matchGrade.toCode()));
|
||||
return searchComponent;
|
||||
|
@ -128,7 +115,7 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
RequestDetails theRequestDetails) {
|
||||
validateMergeParameters(theFromPersonId, theToPersonId);
|
||||
|
||||
return (Person) myEmpiControllerSvc.mergePersons(theFromPersonId.getValue(), theToPersonId.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.MERGE_PERSONS));
|
||||
return (Person) myEmpiControllerSvc.mergeGoldenResources(theFromPersonId.getValue(), theToPersonId.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.MERGE_PERSONS));
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_UPDATE_LINK, type = Person.class)
|
||||
|
@ -139,7 +126,7 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
|
||||
validateUpdateLinkParameters(thePersonId, theTargetId, theMatchResult);
|
||||
|
||||
return (Person) myEmpiControllerSvc.updateLink(thePersonId.getValue(), theTargetId.getValue(), theMatchResult.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.UPDATE_LINK));
|
||||
return (Person) myEmpiControllerSvc.updateLink(thePersonId.getValue(), theTargetId.getValue(), theMatchResult.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.UPDATE_LINK));
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_QUERY_LINKS)
|
||||
|
@ -149,35 +136,35 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
@OperationParam(name=ProviderConstants.EMPI_QUERY_LINKS_MATCH_RESULT, min = 0, max = 1) StringType theLinkSource,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
Stream<EmpiLinkJson> empiLinkJson = myEmpiControllerSvc.queryLinks(extractStringOrNull(thePersonId), extractStringOrNull(theTargetId), extractStringOrNull(theMatchResult), extractStringOrNull(theLinkSource), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
Stream<EmpiLinkJson> empiLinkJson = myEmpiControllerSvc.queryLinks(extractStringOrNull(thePersonId), extractStringOrNull(theTargetId), extractStringOrNull(theMatchResult), extractStringOrNull(theLinkSource), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
return (Parameters) parametersFromEmpiLinks(empiLinkJson, true);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_DUPLICATE_PERSONS)
|
||||
@Operation(name = ProviderConstants.MDM_DUPLICATE_GOLDEN_RESOURCES)
|
||||
public Parameters getDuplicatePersons(ServletRequestDetails theRequestDetails) {
|
||||
Stream<EmpiLinkJson> possibleDuplicates = myEmpiControllerSvc.getDuplicatePersons(createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
Stream<EmpiLinkJson> possibleDuplicates = myEmpiControllerSvc.getDuplicateGoldenResources(createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
return (Parameters) parametersFromEmpiLinks(possibleDuplicates, false);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_NOT_DUPLICATE)
|
||||
@Operation(name = ProviderConstants.MDM_NOT_DUPLICATE)
|
||||
// TODO KHS can this return void?
|
||||
public Parameters notDuplicate(@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType thePersonId,
|
||||
@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 1, max = 1) StringType theTargetId,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
validateNotDuplicateParameters(thePersonId, theTargetId);
|
||||
myEmpiControllerSvc.notDuplicatePerson(thePersonId.getValue(), theTargetId.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.NOT_DUPLICATE));
|
||||
myEmpiControllerSvc.notDuplicateGoldenResource(thePersonId.getValue(), theTargetId.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.NOT_DUPLICATE));
|
||||
|
||||
Parameters retval = (Parameters) ParametersUtil.newInstance(myFhirContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myFhirContext, retval, "success", true);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type= DecimalType.class)
|
||||
})
|
||||
public Parameters empiBatchOnAllTargets(
|
||||
@OperationParam(name= ProviderConstants.EMPI_BATCH_RUN_CRITERIA,min = 0 , max = 1) StringType theCriteria,
|
||||
@OperationParam(name= ProviderConstants.MDM_BATCH_RUN_CRITERIA,min = 0 , max = 1) StringType theCriteria,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiBatchSvc.submitAllTargetTypesToEmpi(criteria);
|
||||
|
@ -205,45 +192,45 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = DecimalType.class)
|
||||
})
|
||||
public Parameters empiBatchPatientInstance(
|
||||
@IdParam IIdType theIdParam,
|
||||
RequestDetails theRequest) {
|
||||
long submittedCount = myEmpiBatchSvc.submitTargetToEmpi(theIdParam);
|
||||
long submittedCount = myEmpiBatchSvc.submitTargetToMdm(theIdParam);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = DecimalType.class)
|
||||
})
|
||||
public Parameters empiBatchPatientType(
|
||||
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
RequestDetails theRequest) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiBatchSvc.submitPatientTypeToEmpi(criteria);
|
||||
long submittedCount = myEmpiBatchSvc.submitPatientTypeToMdm(criteria);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = DecimalType.class)
|
||||
})
|
||||
public Parameters empiBatchPractitionerInstance(
|
||||
@IdParam IIdType theIdParam,
|
||||
RequestDetails theRequest) {
|
||||
long submittedCount = myEmpiBatchSvc.submitTargetToEmpi(theIdParam);
|
||||
long submittedCount = myEmpiBatchSvc.submitTargetToMdm(theIdParam);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = DecimalType.class)
|
||||
})
|
||||
public Parameters empiBatchPractitionerType(
|
||||
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
RequestDetails theRequest) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiBatchSvc.submitPractitionerTypeToEmpi(criteria);
|
||||
long submittedCount = myEmpiBatchSvc.submitPractitionerTypeToMdm(criteria);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
|
@ -257,4 +244,39 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
|
|||
.setValue(new DecimalType(theCount));
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private Bundle getMatchesAndPossibleMatchesForResource(IAnyResource theResource, String theResourceType) {
|
||||
List<MatchedTarget> matches = myEmpiMatchFinderSvc.getMatchedTargets(theResourceType, theResource);
|
||||
matches.sort(Comparator.comparing((MatchedTarget m) -> m.getMatchResult().getNormalizedScore()).reversed());
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.setType(Bundle.BundleType.SEARCHSET);
|
||||
retVal.setId(UUID.randomUUID().toString());
|
||||
retVal.getMeta().setLastUpdatedElement(InstantType.now());
|
||||
|
||||
for (MatchedTarget next : matches) {
|
||||
boolean shouldKeepThisEntry = next.isMatch() || next.isPossibleMatch();
|
||||
if (!shouldKeepThisEntry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Bundle.BundleEntryComponent entry = new Bundle.BundleEntryComponent();
|
||||
entry.setResource((Resource) next.getTarget());
|
||||
entry.setSearch(toBundleEntrySearchComponent(next));
|
||||
|
||||
retVal.addEntry(entry);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected MatchGrade getMatchGrade(MatchedTarget theTheMatchedTarget) {
|
||||
MatchGrade matchGrade = MatchGrade.PROBABLE;
|
||||
if (theTheMatchedTarget.isMatch()) {
|
||||
matchGrade = MatchGrade.CERTAIN;
|
||||
} else if (theTheMatchedTarget.isPossibleMatch()) {
|
||||
matchGrade = MatchGrade.POSSIBLE;
|
||||
}
|
||||
return matchGrade;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
|||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
|
@ -52,6 +53,7 @@ import org.hl7.fhir.r4.model.Resource;
|
|||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.codesystems.MatchGrade;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
@ -61,7 +63,7 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
|
|||
private final IEmpiControllerSvc myEmpiControllerSvc;
|
||||
private final IEmpiMatchFinderSvc myEmpiMatchFinderSvc;
|
||||
private final IEmpiExpungeSvc myMdmExpungeSvc;
|
||||
private final IEmpiSubmitSvc myEmpiSubmitSvc;
|
||||
private final IEmpiSubmitSvc myMdmSubmitSvc;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -69,21 +71,45 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
|
|||
* Note that this is not a spring bean. Any necessary injections should
|
||||
* happen in the constructor
|
||||
*/
|
||||
public EmpiProviderR4(FhirContext theFhirContext, IEmpiControllerSvc theEmpiControllerSvc, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiExpungeSvc theMdmExpungeSvc, IEmpiSubmitSvc theEmpiSubmitSvc) {
|
||||
public EmpiProviderR4(FhirContext theFhirContext, IEmpiControllerSvc theEmpiControllerSvc, IEmpiMatchFinderSvc theEmpiMatchFinderSvc, IEmpiExpungeSvc theMdmExpungeSvc, IEmpiSubmitSvc theMdmSubmitSvc) {
|
||||
super(theFhirContext);
|
||||
myEmpiControllerSvc = theEmpiControllerSvc;
|
||||
myEmpiMatchFinderSvc = theEmpiMatchFinderSvc;
|
||||
myMdmExpungeSvc = theMdmExpungeSvc;
|
||||
myEmpiSubmitSvc = theEmpiSubmitSvc;
|
||||
myMdmSubmitSvc = theMdmSubmitSvc;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_MATCH, type = Patient.class)
|
||||
public Bundle match(@OperationParam(name = ProviderConstants.EMPI_MATCH_RESOURCE, min = 1, max = 1) Patient thePatient) {
|
||||
public Bundle match(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) Patient thePatient) {
|
||||
if (thePatient == null) {
|
||||
throw new InvalidRequestException("resource may not be null");
|
||||
}
|
||||
Bundle retVal = getMatchesAndPossibleMatchesForResource(thePatient, "Patient");
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_MATCH)
|
||||
public Bundle serverMatch(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) IAnyResource theResource,
|
||||
@OperationParam(name = ProviderConstants.MDM_RESOURCE_TYPE, min = 1, max = 1) StringType theResourceType
|
||||
) {
|
||||
if (theResource == null) {
|
||||
throw new InvalidRequestException("resource may not be null");
|
||||
}
|
||||
Bundle retVal = getMatchesAndPossibleMatchesForResource(theResource, theResourceType.getValueNotNull());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which will return a bundle of all Matches and Possible Matches.
|
||||
* @param theResource
|
||||
* @param theTheValueNotNull
|
||||
* @return
|
||||
*/
|
||||
private Bundle getMatchesAndPossibleMatchesForResource(IAnyResource theResource, String theTheValueNotNull) {
|
||||
List<MatchedTarget> matches = myEmpiMatchFinderSvc.getMatchedTargets(theTheValueNotNull, theResource);
|
||||
|
||||
List<MatchedTarget> matches = myEmpiMatchFinderSvc.getMatchedTargets("Patient", thePatient);
|
||||
matches.sort(Comparator.comparing((MatchedTarget m) -> m.getMatchResult().getNormalizedScore()).reversed());
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
|
@ -103,45 +129,39 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
|
|||
|
||||
retVal.addEntry(entry);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private Bundle.BundleEntrySearchComponent toBundleEntrySearchComponent(MatchedTarget theMatchedTarget) {
|
||||
Bundle.BundleEntrySearchComponent searchComponent = new Bundle.BundleEntrySearchComponent();
|
||||
searchComponent.setMode(Bundle.SearchEntryMode.MATCH);
|
||||
searchComponent.setScore(theMatchedTarget.getMatchResult().getNormalizedScore());
|
||||
|
||||
MatchGrade matchGrade = MatchGrade.PROBABLE;
|
||||
if (theMatchedTarget.isMatch()) {
|
||||
matchGrade = MatchGrade.CERTAIN;
|
||||
} else if (theMatchedTarget.isPossibleMatch()) {
|
||||
matchGrade = MatchGrade.POSSIBLE;
|
||||
}
|
||||
MatchGrade matchGrade = getMatchGrade(theMatchedTarget);
|
||||
|
||||
searchComponent.addExtension(EmpiConstants.FIHR_STRUCTURE_DEF_MATCH_GRADE_URL_NAMESPACE, new CodeType(matchGrade.toCode()));
|
||||
return searchComponent;
|
||||
}
|
||||
|
||||
//TODO GGG ask ken, what is the best way to genericize this? Return
|
||||
@Operation(name = ProviderConstants.MDM_MERGE_GOLDEN_RESOURCES)
|
||||
public IBaseResource mergeGoldenResources(@OperationParam(name=ProviderConstants.MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType theFromGoldenResourceId,
|
||||
@OperationParam(name=ProviderConstants.MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType theToGoldenResourceId,
|
||||
RequestDetails theRequestDetails) {
|
||||
validateMergeParameters(theFromGoldenResourceId, theToGoldenResourceId);
|
||||
|
||||
return myEmpiControllerSvc.mergePersons(theFromGoldenResourceId.getValue(), theToGoldenResourceId.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.MERGE_PERSONS));
|
||||
return myEmpiControllerSvc.mergeGoldenResources(theFromGoldenResourceId.getValue(), theToGoldenResourceId.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.MERGE_PERSONS));
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_UPDATE_LINK)
|
||||
public IBaseResource updateLink(@OperationParam(name=ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType thePersonId,
|
||||
@OperationParam(name=ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, min = 1, max = 1) StringType theTargetId,
|
||||
public IBaseResource updateLink(@OperationParam(name=ProviderConstants.MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType theGoldenResourceId,
|
||||
@OperationParam(name=ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, min = 1, max = 1) StringType theResourceId,
|
||||
@OperationParam(name=ProviderConstants.MDM_UPDATE_LINK_MATCH_RESULT, min = 1, max = 1) StringType theMatchResult,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
validateUpdateLinkParameters(thePersonId, theTargetId, theMatchResult);
|
||||
validateUpdateLinkParameters(theGoldenResourceId, theResourceId, theMatchResult);
|
||||
|
||||
return myEmpiControllerSvc.updateLink(thePersonId.getValueNotNull(), theTargetId.getValue(), theMatchResult.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.UPDATE_LINK));
|
||||
return myEmpiControllerSvc.updateLink(theGoldenResourceId.getValueNotNull(), theResourceId.getValue(), theMatchResult.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.UPDATE_LINK));
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_CLEAR, returnParameters = {
|
||||
|
@ -163,100 +183,112 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
|
|||
|
||||
|
||||
@Operation(name = ProviderConstants.MDM_QUERY_LINKS, idempotent = true)
|
||||
public Parameters queryLinks(@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, min = 0, max = 1) StringType thePersonId,
|
||||
@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 0, max = 1) StringType theTargetId,
|
||||
public Parameters queryLinks(@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, min = 0, max = 1) StringType theGoldenResourceId,
|
||||
@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 0, max = 1) StringType theResourceId,
|
||||
@OperationParam(name=ProviderConstants.EMPI_QUERY_LINKS_MATCH_RESULT, min = 0, max = 1) StringType theMatchResult,
|
||||
@OperationParam(name=ProviderConstants.EMPI_QUERY_LINKS_LINK_SOURCE, min = 0, max = 1) StringType theLinkSource,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
Stream<EmpiLinkJson> empiLinkJson = myEmpiControllerSvc.queryLinks(extractStringOrNull(thePersonId), extractStringOrNull(theTargetId), extractStringOrNull(theMatchResult), extractStringOrNull(theLinkSource), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
Stream<EmpiLinkJson> empiLinkJson = myEmpiControllerSvc.queryLinks(extractStringOrNull(theGoldenResourceId), extractStringOrNull(theResourceId), extractStringOrNull(theMatchResult), extractStringOrNull(theLinkSource), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.QUERY_LINKS));
|
||||
return (Parameters) parametersFromEmpiLinks(empiLinkJson, true);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_DUPLICATE_PERSONS, idempotent = true)
|
||||
public Parameters getDuplicatePersons(ServletRequestDetails theRequestDetails) {
|
||||
Stream<EmpiLinkJson> possibleDuplicates = myEmpiControllerSvc.getDuplicatePersons(createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.DUPLICATE_PERSONS));
|
||||
@Operation(name = ProviderConstants.MDM_DUPLICATE_GOLDEN_RESOURCES, idempotent = true)
|
||||
public Parameters getDuplicateGoldenResources(ServletRequestDetails theRequestDetails) {
|
||||
Stream<EmpiLinkJson> possibleDuplicates = myEmpiControllerSvc.getDuplicateGoldenResources(createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.DUPLICATE_GOLDEN_RESOURCES));
|
||||
return (Parameters) parametersFromEmpiLinks(possibleDuplicates, false);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.EMPI_NOT_DUPLICATE)
|
||||
public Parameters notDuplicate(@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType thePersonId,
|
||||
@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 1, max = 1) StringType theTargetId,
|
||||
@Operation(name = ProviderConstants.MDM_NOT_DUPLICATE)
|
||||
public Parameters notDuplicate(@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, min = 1, max = 1) StringType theGoldenResourceId,
|
||||
@OperationParam(name=ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, min = 1, max = 1) StringType theResourceId,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
|
||||
validateNotDuplicateParameters(thePersonId, theTargetId);
|
||||
myEmpiControllerSvc.notDuplicatePerson(thePersonId.getValue(), theTargetId.getValue(), createEmpiContext(theRequestDetails, EmpiTransactionContext.OperationType.NOT_DUPLICATE));
|
||||
validateNotDuplicateParameters(theGoldenResourceId, theResourceId);
|
||||
myEmpiControllerSvc.notDuplicateGoldenResource(theGoldenResourceId.getValue(), theResourceId.getValue(), createMdmContext(theRequestDetails, EmpiTransactionContext.OperationType.NOT_DUPLICATE));
|
||||
|
||||
Parameters retval = (Parameters) ParametersUtil.newInstance(myFhirContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myFhirContext, retval, "success", true);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type= IntegerType.class)
|
||||
})
|
||||
public Parameters empiBatchOnAllTargets(
|
||||
@OperationParam(name= ProviderConstants.EMPI_BATCH_RUN_CRITERIA,min = 0 , max = 1) StringType theCriteria,
|
||||
//TODO GGG MDM: also have to take it an optional resourceType here, to clarify which resources should have MDM run on them.
|
||||
@OperationParam(name= ProviderConstants.MDM_BATCH_RUN_CRITERIA,min = 0 , max = 1) StringType theCriteria,
|
||||
ServletRequestDetails theRequestDetails) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiSubmitSvc.submitAllTargetTypesToEmpi(criteria);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
long submittedCount = myMdmSubmitSvc.submitAllTargetTypesToEmpi(criteria);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
private String convertCriteriaToString(StringType theCriteria) {
|
||||
return theCriteria == null ? null : theCriteria.getValueAsString();
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters empiBatchPatientInstance(
|
||||
@IdParam IIdType theIdParam,
|
||||
RequestDetails theRequest) {
|
||||
long submittedCount = myEmpiSubmitSvc.submitTargetToEmpi(theIdParam);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
long submittedCount = myMdmSubmitSvc.submitTargetToMdm(theIdParam);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Patient.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters empiBatchPatientType(
|
||||
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
RequestDetails theRequest) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiSubmitSvc.submitPatientTypeToEmpi(criteria);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
long submittedCount = myMdmSubmitSvc.submitPatientTypeToMdm(criteria);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters empiBatchPractitionerInstance(
|
||||
@IdParam IIdType theIdParam,
|
||||
RequestDetails theRequest) {
|
||||
long submittedCount = myEmpiSubmitSvc.submitTargetToEmpi(theIdParam);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
long submittedCount = myMdmSubmitSvc.submitTargetToMdm(theIdParam);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
@Operation(name = ProviderConstants.OPERATION_EMPI_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@Operation(name = ProviderConstants.OPERATION_MDM_SUBMIT, idempotent = false, type = Practitioner.class, returnParameters = {
|
||||
@OperationParam(name = ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters empiBatchPractitionerType(
|
||||
@OperationParam(name = ProviderConstants.EMPI_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA) StringType theCriteria,
|
||||
RequestDetails theRequest) {
|
||||
String criteria = convertCriteriaToString(theCriteria);
|
||||
long submittedCount = myEmpiSubmitSvc.submitPractitionerTypeToEmpi(criteria);
|
||||
return buildEmpiOutParametersWithCount(submittedCount);
|
||||
long submittedCount = myMdmSubmitSvc.submitPractitionerTypeToMdm(criteria);
|
||||
return buildMdmOutParametersWithCount(submittedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to build the out-parameters for all batch EMPI operations.
|
||||
*/
|
||||
private Parameters buildEmpiOutParametersWithCount(long theCount) {
|
||||
private Parameters buildMdmOutParametersWithCount(long theCount) {
|
||||
Parameters parameters = new Parameters();
|
||||
parameters.addParameter()
|
||||
.setName(ProviderConstants.OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT)
|
||||
.setValue(new DecimalType(theCount));
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected MatchGrade getMatchGrade(MatchedTarget theTheMatchedTarget) {
|
||||
MatchGrade matchGrade = MatchGrade.PROBABLE;
|
||||
if (theTheMatchedTarget.isMatch()) {
|
||||
matchGrade = MatchGrade.CERTAIN;
|
||||
} else if (theTheMatchedTarget.isPossibleMatch()) {
|
||||
matchGrade = MatchGrade.POSSIBLE;
|
||||
}
|
||||
return matchGrade;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.empi.rules.config;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.empi.api.EmpiConstants;
|
||||
import ca.uhn.fhir.empi.api.IEmpiRuleValidator;
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiFieldMatchJson;
|
||||
|
@ -41,6 +42,7 @@ import org.springframework.stereotype.Service;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
|
@ -63,11 +65,24 @@ public class EmpiRuleValidator implements IEmpiRuleValidator {
|
|||
}
|
||||
|
||||
public void validate(EmpiRulesJson theEmpiRulesJson) {
|
||||
validateMdmTypes(theEmpiRulesJson);
|
||||
validateSearchParams(theEmpiRulesJson);
|
||||
validateMatchFields(theEmpiRulesJson);
|
||||
validateSystemIsUri(theEmpiRulesJson);
|
||||
}
|
||||
|
||||
public void validateMdmTypes(EmpiRulesJson theEmpiRulesJson) {
|
||||
for (String resourceType: theEmpiRulesJson.getMdmTypes()) {
|
||||
validateTypeHasIdentifier(resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateTypeHasIdentifier(String theResourceType) {
|
||||
if (mySearchParamRetriever.getActiveSearchParam(theResourceType, "identifier") == null) {
|
||||
throw new ConfigurationException("Resource Type " + theResourceType + " is not supported, as it does not have an 'identifier' field, which is necessary for MDM workflow.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSearchParams(EmpiRulesJson theEmpiRulesJson) {
|
||||
for (EmpiResourceSearchParamJson searchParams : theEmpiRulesJson.getCandidateSearchParams()) {
|
||||
searchParams.iterator().forEachRemaining(
|
||||
|
@ -105,7 +120,7 @@ public class EmpiRuleValidator implements IEmpiRuleValidator {
|
|||
} else if (fieldMatch.getMatcher() == null) {
|
||||
throw new ConfigurationException("MatchField " + fieldMatch.getName() + " has neither a similarity nor a matcher. At least one must be present.");
|
||||
}
|
||||
validatePath(fieldMatch);
|
||||
validatePath(theEmpiRulesJson.getMdmTypes(), fieldMatch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,23 +131,29 @@ public class EmpiRuleValidator implements IEmpiRuleValidator {
|
|||
}
|
||||
}
|
||||
|
||||
private void validatePath(EmpiFieldMatchJson theFieldMatch) {
|
||||
private void validatePath(List<String> theMdmTypes, EmpiFieldMatchJson theFieldMatch) {
|
||||
String resourceType = theFieldMatch.getResourceType();
|
||||
|
||||
|
||||
if (EmpiConstants.ALL_RESOURCE_SEARCH_PARAM_TYPE.equals(resourceType)) {
|
||||
validatePatientPath(theFieldMatch);
|
||||
validatePractitionerPath(theFieldMatch);
|
||||
} else if ("Patient".equals(resourceType)) {
|
||||
validatePatientPath(theFieldMatch);
|
||||
} else if ("Practitioner".equals(resourceType)) {
|
||||
validatePractitionerPath(theFieldMatch);
|
||||
validateFieldPathForAllTypes(theMdmTypes, theFieldMatch);
|
||||
} else {
|
||||
throw new ConfigurationException("MatchField " + theFieldMatch.getName() + " has unknown resourceType " + resourceType);
|
||||
validateFieldPath(theFieldMatch);
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePatientPath(EmpiFieldMatchJson theFieldMatch) {
|
||||
private void validateFieldPathForAllTypes(List<String> theMdmResourceTypes, EmpiFieldMatchJson theFieldMatch) {
|
||||
|
||||
for (String resourceType: theMdmResourceTypes) {
|
||||
validateFieldPathForType(resourceType, theFieldMatch);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateFieldPathForType(String theResourceType, EmpiFieldMatchJson theFieldMatch) {
|
||||
try {
|
||||
myTerser.getDefinition(myPatientClass, "Patient." + theFieldMatch.getResourcePath());
|
||||
RuntimeResourceDefinition resourceDefinition = myFhirContext.getResourceDefinition(theResourceType);
|
||||
Class<? extends IBaseResource> implementingClass = resourceDefinition.getImplementingClass();
|
||||
myTerser.getDefinition(implementingClass, theResourceType + "." + theFieldMatch.getResourcePath());
|
||||
} catch (DataFormatException | ConfigurationException e) {
|
||||
throw new ConfigurationException("MatchField " +
|
||||
theFieldMatch.getName() +
|
||||
|
@ -140,20 +161,12 @@ public class EmpiRuleValidator implements IEmpiRuleValidator {
|
|||
theFieldMatch.getResourceType() +
|
||||
" has invalid path '" + theFieldMatch.getResourcePath() + "'. " +
|
||||
e.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePractitionerPath(EmpiFieldMatchJson theFieldMatch) {
|
||||
try {
|
||||
myTerser.getDefinition(myPractitionerClass, "Practitioner." + theFieldMatch.getResourcePath());
|
||||
} catch (DataFormatException e) {
|
||||
throw new ConfigurationException("MatchField " +
|
||||
theFieldMatch.getName() +
|
||||
" resourceType " +
|
||||
theFieldMatch.getResourceType() +
|
||||
" has invalid path '" + theFieldMatch.getResourcePath() + "'. " +
|
||||
e.getMessage());
|
||||
}
|
||||
private void validateFieldPath(EmpiFieldMatchJson theFieldMatch) {
|
||||
validateFieldPathForType(theFieldMatch.getResourceType(), theFieldMatch);
|
||||
}
|
||||
|
||||
private void validateSystemIsUri(EmpiRulesJson theEmpiRulesJson) {
|
||||
|
|
|
@ -49,6 +49,10 @@ public class EmpiRulesJson implements IModelJson {
|
|||
@JsonProperty(value = "eidSystem")
|
||||
String myEnterpriseEIDSystem;
|
||||
|
||||
|
||||
@JsonProperty(value = "mdmTypes")
|
||||
List<String> myMdmTypes;
|
||||
|
||||
transient VectorMatchResultMap myVectorMatchResultMap;
|
||||
|
||||
public void addMatchField(EmpiFieldMatchJson theMatchRuleName) {
|
||||
|
@ -174,4 +178,13 @@ public class EmpiRulesJson implements IModelJson {
|
|||
return theEmpiRulesJson;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getMdmTypes() {
|
||||
return myMdmTypes;
|
||||
}
|
||||
|
||||
public void setMdmTypes(List<String> theMdmTypes) {
|
||||
myMdmTypes = theMdmTypes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,12 +23,14 @@ package ca.uhn.fhir.empi.rules.svc;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.empi.api.EmpiMatchEvaluation;
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiFieldMatchJson;
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiRulesJson;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.empi.api.EmpiConstants.ALL_RESOURCE_SEARCH_PARAM_TYPE;
|
||||
|
||||
|
@ -40,12 +42,14 @@ public class EmpiResourceFieldMatcher {
|
|||
private final EmpiFieldMatchJson myEmpiFieldMatchJson;
|
||||
private final String myResourceType;
|
||||
private final String myResourcePath;
|
||||
private final EmpiRulesJson myEmpiRulesJson;
|
||||
|
||||
public EmpiResourceFieldMatcher(FhirContext theFhirContext, EmpiFieldMatchJson theEmpiFieldMatchJson) {
|
||||
public EmpiResourceFieldMatcher(FhirContext theFhirContext, EmpiFieldMatchJson theEmpiFieldMatchJson, EmpiRulesJson theEmpiRulesJson) {
|
||||
myFhirContext = theFhirContext;
|
||||
myEmpiFieldMatchJson = theEmpiFieldMatchJson;
|
||||
myResourceType = theEmpiFieldMatchJson.getResourceType();
|
||||
myResourcePath = theEmpiFieldMatchJson.getResourcePath();
|
||||
myEmpiRulesJson = theEmpiRulesJson;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,11 +92,20 @@ public class EmpiResourceFieldMatcher {
|
|||
private void validate(IBaseResource theResource) {
|
||||
String resourceType = myFhirContext.getResourceType(theResource);
|
||||
Validate.notNull(resourceType, "Resource type may not be null");
|
||||
|
||||
if (ALL_RESOURCE_SEARCH_PARAM_TYPE.equals(myResourceType)) {
|
||||
Validate.isTrue("Patient".equalsIgnoreCase(resourceType) || "Practitioner".equalsIgnoreCase(resourceType),
|
||||
"Expecting resource type Patient/Practitioner got resource type %s", resourceType);
|
||||
boolean isMdmType = myEmpiRulesJson.getMdmTypes().stream().anyMatch(mdmType -> mdmType.equalsIgnoreCase(resourceType));
|
||||
Validate.isTrue(isMdmType, "Expecting resource type %s, got resource type %s", myEmpiRulesJson.getMdmTypes().stream().collect(Collectors.joining(",")), resourceType);
|
||||
} else {
|
||||
Validate.isTrue(myResourceType.equals(resourceType), "Expecting resource type %s got resource type %s", myResourceType, resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return myResourceType;
|
||||
}
|
||||
|
||||
public String getResourcePath() {
|
||||
return myResourcePath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.stereotype.Service;
|
|||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The EmpiResourceComparator is in charge of performing actual comparisons between left and right records.
|
||||
|
@ -66,7 +67,7 @@ public class EmpiResourceMatcherSvc {
|
|||
throw new ConfigurationException("Failed to load EMPI Rules. If EMPI is enabled, then EMPI rules must be available in context.");
|
||||
}
|
||||
for (EmpiFieldMatchJson matchFieldJson : myEmpiRulesJson.getMatchFields()) {
|
||||
myFieldMatchers.add(new EmpiResourceFieldMatcher(myFhirContext, matchFieldJson));
|
||||
myFieldMatchers.add(new EmpiResourceFieldMatcher( myFhirContext, matchFieldJson, myEmpiRulesJson));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -116,9 +117,15 @@ public class EmpiResourceMatcherSvc {
|
|||
private EmpiMatchOutcome getMatchOutcome(IBaseResource theLeftResource, IBaseResource theRightResource) {
|
||||
long vector = 0;
|
||||
double score = 0.0;
|
||||
for (int i = 0; i < myFieldMatchers.size(); ++i) {
|
||||
//TODO GGG MDM: This grabs ALL comparators, not just the ones we care about (e.g. the ones for Medication)
|
||||
String resourceType = myFhirContext.getResourceType(theLeftResource);
|
||||
List<EmpiResourceFieldMatcher> resourceRelevantFieldMatchers = myFieldMatchers.stream()
|
||||
.filter(comp -> comp.getResourceType().equalsIgnoreCase("*") || comp.getResourceType().equalsIgnoreCase(resourceType))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (int i = 0; i < resourceRelevantFieldMatchers.size(); ++i) {
|
||||
//any that are not for the resourceType in question.
|
||||
EmpiResourceFieldMatcher fieldComparator = myFieldMatchers.get(i);
|
||||
EmpiResourceFieldMatcher fieldComparator = resourceRelevantFieldMatchers.get(i);
|
||||
EmpiMatchEvaluation matchEvaluation = fieldComparator.match(theLeftResource, theRightResource);
|
||||
if (matchEvaluation.match) {
|
||||
vector |= (1 << i);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.empi.rules.svc;
|
||||
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiFieldMatchJson;
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiRulesJson;
|
||||
import ca.uhn.fhir.empi.rules.json.EmpiSimilarityJson;
|
||||
import ca.uhn.fhir.empi.rules.similarity.EmpiSimilarityEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
@ -9,6 +10,8 @@ import org.hl7.fhir.r4.model.Patient;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.StringStartsWith.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -20,14 +23,17 @@ public class EmpiResourceFieldMatcherR4Test extends BaseEmpiRulesR4Test {
|
|||
protected EmpiResourceFieldMatcher myComparator;
|
||||
private Patient myJohn;
|
||||
private Patient myJohny;
|
||||
private EmpiRulesJson myEmpiRulesJson;
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
super.before();
|
||||
|
||||
|
||||
myComparator = new EmpiResourceFieldMatcher(ourFhirContext, myGivenNameMatchField);
|
||||
ArrayList<String> myLegalMdmTypes = new ArrayList<>();
|
||||
myLegalMdmTypes.add("Patient");
|
||||
myEmpiRulesJson.setMdmTypes(myLegalMdmTypes);
|
||||
myComparator = new EmpiResourceFieldMatcher(ourFhirContext, myGivenNameMatchField, myEmpiRulesJson);
|
||||
myJohn = buildJohn();
|
||||
myJohny = buildJohny();
|
||||
}
|
||||
|
@ -67,7 +73,7 @@ public class EmpiResourceFieldMatcherR4Test extends BaseEmpiRulesR4Test {
|
|||
.setResourceType("Patient")
|
||||
.setResourcePath("foo")
|
||||
.setSimilarity(new EmpiSimilarityJson().setAlgorithm(EmpiSimilarityEnum.COSINE).setMatchThreshold(NAME_THRESHOLD));
|
||||
EmpiResourceFieldMatcher comparator = new EmpiResourceFieldMatcher(ourFhirContext, matchField);
|
||||
EmpiResourceFieldMatcher comparator = new EmpiResourceFieldMatcher(ourFhirContext, matchField, myEmpiRulesJson);
|
||||
comparator.match(myJohn, myJohny);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
|
|
|
@ -64,31 +64,32 @@ public class ProviderConstants {
|
|||
public static final String EMPI_MATCH = "$match";
|
||||
//TODO GGG MDM: implement a server-level MDM match to complement the FHIR-spec $match for /Patient
|
||||
public static final String MDM_MATCH = "$mdm-match";
|
||||
public static final String EMPI_MATCH_RESOURCE = "resource";
|
||||
public static final String MDM_MATCH_RESOURCE = "resource";
|
||||
public static final String MDM_RESOURCE_TYPE = "resourceType";
|
||||
|
||||
//TODO GGG MDM: rename all these vars
|
||||
public static final String MDM_MERGE_GOLDEN_RESOURCES = "$empi-merge-golden-resources";
|
||||
public static final String MDM_MERGE_GOLDEN_RESOURCES = "$mdm-merge-golden-resources";
|
||||
public static final String MDM_MERGE_GR_FROM_GOLDEN_RESOURCE_ID = "fromGoldenResourceId";
|
||||
public static final String MDM_MERGE_GR_TO_GOLDEN_RESOURCE_ID = "toGoldenResourceId";
|
||||
|
||||
public static final String MDM_UPDATE_LINK = "$empi-update-link";
|
||||
public static final String MDM_UPDATE_LINK = "$mdm-update-link";
|
||||
public static final String MDM_UPDATE_LINK_GOLDEN_RESOURCE_ID = "goldenResourceId";
|
||||
public static final String MDM_UPDATE_LINK_RESOURCE_ID = "resourceId";
|
||||
public static final String MDM_UPDATE_LINK_MATCH_RESULT = "matchResult";
|
||||
|
||||
public static final String MDM_QUERY_LINKS = "$empi-query-links";
|
||||
public static final String MDM_QUERY_LINKS = "$mdm-query-links";
|
||||
public static final String MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID = "goldenResourceId";
|
||||
public static final String MDM_QUERY_LINKS_RESOURCE_ID = "resourceId";
|
||||
public static final String EMPI_QUERY_LINKS_MATCH_RESULT = "matchResult";
|
||||
public static final String EMPI_QUERY_LINKS_LINK_SOURCE = "linkSource";
|
||||
|
||||
public static final String EMPI_DUPLICATE_PERSONS = "$empi-duplicate-golden-resources";
|
||||
public static final String EMPI_NOT_DUPLICATE = "$empi-not-duplicate";
|
||||
public static final String MDM_DUPLICATE_GOLDEN_RESOURCES = "$empi-duplicate-golden-resources";
|
||||
public static final String MDM_NOT_DUPLICATE = "$empi-not-duplicate";
|
||||
|
||||
public static final String MDM_CLEAR = "$empi-clear";
|
||||
public static final String MDM_CLEAR = "$mdm-clear";
|
||||
public static final String MDM_CLEAR_TARGET_TYPE = "targetType";
|
||||
public static final String OPERATION_EMPI_SUBMIT = "$empi-submit";
|
||||
public static final String EMPI_BATCH_RUN_CRITERIA= "criteria" ;
|
||||
public static final String OPERATION_MDM_SUBMIT = "$mdm-submit";
|
||||
public static final String MDM_BATCH_RUN_CRITERIA = "criteria" ;
|
||||
public static final String OPERATION_MDM_BATCH_RUN_OUT_PARAM_SUBMIT_COUNT = "submitted" ;
|
||||
public static final String OPERATION_MDM_CLEAR_OUT_PARAM_DELETED_COUNT = "deleted";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue