Skip to content

Commit b83a604

Browse files
Merge pull request #13201 from SORMAS-Foundation/change-13181_enhance_national_ID_search_functionality
#13181 - Enhance National Health ID Search Functionality Across Modules and Address Duplication Issues
2 parents bac6746 + 6c9f438 commit b83a604

File tree

25 files changed

+426
-72
lines changed

25 files changed

+426
-72
lines changed

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ public interface Strings {
825825
String headingShowExternalMessage = "headingShowExternalMessage";
826826
String headingSignsAndSymptoms = "headingSignsAndSymptoms";
827827
String headingSimilarImmunization = "headingSimilarImmunization";
828+
String headingSimilarPerson = "headingSimilarPerson";
828829
String headingSomeCasesAlreadyInEvent = "headingSomeCasesAlreadyInEvent";
829830
String headingSomeCasesNotRestored = "headingSomeCasesNotRestored";
830831
String headingSomeContactsAlreadyInEvent = "headingSomeContactsAlreadyInEvent";

sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class PersonSimilarityCriteria extends BaseCriteria implements Cloneable
2020
private String passportNumber;
2121
private String nationalHealthId;
2222
private String nameUuidExternalIdExternalTokenLike;
23+
private boolean checkOnlyForNationalHealthId;
2324
/**
2425
* If true, compare the name of the person only to the first and last name fields of the database; if false, compare the
2526
* name of the person to other fields like UUID and external ID as well.
@@ -106,6 +107,14 @@ public PersonSimilarityCriteria nationalHealthId(String nationalHealthId) {
106107
return this;
107108
}
108109

110+
public boolean isCheckOnlyForNationalHealthId() {
111+
return checkOnlyForNationalHealthId;
112+
}
113+
114+
public void setCheckOnlyForNationalHealthId(boolean checkOnlyForNationalHealthId) {
115+
this.checkOnlyForNationalHealthId = checkOnlyForNationalHealthId;
116+
}
117+
109118
public String getNameUuidExternalIdExternalTokenLike() {
110119
return nameUuidExternalIdExternalTokenLike;
111120
}
@@ -140,22 +149,27 @@ public void setBirthdateDD(Integer birthdateDD) {
140149
}
141150

142151
public static PersonSimilarityCriteria forPerson(PersonDto person) {
143-
return forPerson(person, false);
152+
return forPerson(person, false, false);
153+
}
154+
155+
public static PersonSimilarityCriteria forPerson(PersonDto person, boolean checkOnlyForNationalHealthId){
156+
return forPerson(person, false, checkOnlyForNationalHealthId);
144157
}
145158

146159
/**
147160
* @param strictNameComparison
148161
* If true, compares the name of the person only to the first and last name fields of the database; if false, compares the
149162
* name of the person to other fields like UUID and external ID as well.
150163
*/
151-
public static PersonSimilarityCriteria forPerson(PersonDto person, boolean strictNameComparison) {
164+
public static PersonSimilarityCriteria forPerson(PersonDto person, boolean strictNameComparison, boolean checkOnlyForNationalHealthId) {
152165

153166
PersonSimilarityCriteria personSimilarityCriteria = new PersonSimilarityCriteria().sex(person.getSex())
154167
.birthdateDD(person.getBirthdateDD())
155168
.birthdateMM(person.getBirthdateMM())
156169
.birthdateYYYY(person.getBirthdateYYYY())
157170
.passportNumber(person.getPassportNumber())
158171
.nationalHealthId(person.getNationalHealthId());
172+
personSimilarityCriteria.setCheckOnlyForNationalHealthId(checkOnlyForNationalHealthId);
159173
if (strictNameComparison) {
160174
personSimilarityCriteria.firstName(person.getFirstName()).lastName(person.getLastName()).strictNameComparison(Boolean.TRUE);
161175
} else {

sormas-api/src/main/resources/strings.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ headingShowExternalMessage = Message
697697
headingSelfReportSideComponent = Self reports
698698
headingSignsAndSymptoms = Clinical Signs and Symptoms
699699
headingSimilarImmunization = Similar immunizaton
700+
headingSimilarPerson = There are other persons with similar national health Id
700701
headingSyncUsers = Sync Users
701702
headingTasksDeleted = Tasks deleted
702703
headingTasksNotDeleted = None of the tasks were deleted

sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import javax.persistence.criteria.Predicate;
1919
import javax.persistence.criteria.Root;
2020

21+
import de.symeda.sormas.backend.person.Person;
2122
import org.apache.commons.lang3.StringUtils;
2223

2324
import de.symeda.sormas.api.ReferenceDto;
@@ -123,6 +124,7 @@ public Predicate buildCriteriaFilter(CriteriaBuilder cb, Root<ExternalMessage> l
123124
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.UUID), textFilter),
124125
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.PERSON_FIRST_NAME), textFilter),
125126
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.PERSON_LAST_NAME), textFilter),
127+
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.PERSON_NATIONAL_HEALTH_ID), textFilter),
126128
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.PERSON_POSTAL_CODE), textFilter),
127129
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.REPORTER_NAME), textFilter),
128130
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.REPORTER_POSTAL_CODE), textFilter));

sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ protected void handlePickOrCreatePerson(PersonDto person, HandlerCallback<Entity
149149
callback.cancel();
150150
}
151151
} else {
152-
PersonSimilarityCriteria similarityCriteria = PersonSimilarityCriteria.forPerson(person, true);
152+
PersonSimilarityCriteria similarityCriteria = PersonSimilarityCriteria.forPerson(person, true, false);
153153
if (personFacade.checkMatchingNameInDatabase(user.toReference(), similarityCriteria)) {
154154
logger.debug("[MESSAGE PROCESSING] Similar persons found in the database. Canceling processing.");
155155
callback.cancel();

sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -353,16 +353,16 @@ private Predicate createAssociationPredicate(@NotNull PersonQueryContext queryCo
353353
eventParticipantService.createDefaultFilter(cb, joins.getEventParticipant()));
354354
break;
355355
case IMMUNIZATION:
356-
associationPredicate = CriteriaBuilderHelper.and(
357-
cb,
358-
immunizationService.createUserFilter(new ImmunizationQueryContext(cb, cq, joins.getImmunizationJoins())),
359-
immunizationService.createDefaultFilter(cb, joins.getImmunization()));
356+
associationPredicate = CriteriaBuilderHelper.and(
357+
cb,
358+
immunizationService.createUserFilter(new ImmunizationQueryContext(cb, cq, joins.getImmunizationJoins())),
359+
immunizationService.createDefaultFilter(cb, joins.getImmunization()));
360360
break;
361361
case TRAVEL_ENTRY:
362-
associationPredicate = CriteriaBuilderHelper.and(
363-
cb,
364-
travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntryJoins())),
365-
travelEntryService.createDefaultFilter(cb, joins.getTravelEntry()));
362+
associationPredicate = CriteriaBuilderHelper.and(
363+
cb,
364+
travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntryJoins())),
365+
travelEntryService.createDefaultFilter(cb, joins.getTravelEntry()));
366366
break;
367367
case ALL:
368368
default:
@@ -408,7 +408,8 @@ public Predicate buildCriteriaFilter(PersonCriteria personCriteria, PersonQueryC
408408
CriteriaBuilderHelper.ilike(cb, location.get(Location.POSTAL_CODE), textFilter),
409409
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.INTERNAL_TOKEN), textFilter),
410410
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_ID), textFilter),
411-
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_TOKEN), textFilter));
411+
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_TOKEN), textFilter),
412+
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.NATIONAL_HEALTH_ID), textFilter));
412413
filter = CriteriaBuilderHelper.and(cb, filter, likeFilters);
413414
}
414415
}
@@ -924,7 +925,8 @@ public Predicate buildSimilarityCriteriaFilter(PersonSimilarityCriteria criteria
924925
}
925926
}
926927

927-
if (configFacade.isDuplicateChecksNationalHealthIdOverridesCriteria() && StringUtils.isNotBlank(criteria.getNationalHealthId())) {
928+
if (StringUtils.isNotBlank(criteria.getNationalHealthId())
929+
&& (configFacade.isDuplicateChecksNationalHealthIdOverridesCriteria() || criteria.isCheckOnlyForNationalHealthId())) {
928930
filter = or(cb, filter, cb.equal(personFrom.get(Person.NATIONAL_HEALTH_ID), criteria.getNationalHealthId()));
929931
}
930932

sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,7 @@ public Predicate buildCriteriaFilter(SampleCriteria criteria, SampleQueryContext
924924
CriteriaBuilderHelper.ilike(cb, joins.getCaze().get(Case.UUID), textFilter),
925925
CriteriaBuilderHelper.unaccentedIlike(cb, joins.getCasePerson().get(Person.FIRST_NAME), textFilter),
926926
CriteriaBuilderHelper.unaccentedIlike(cb, joins.getCasePerson().get(Person.LAST_NAME), textFilter),
927+
CriteriaBuilderHelper.ilike(cb, joins.getCasePerson().get(Person.NATIONAL_HEALTH_ID), textFilter),
927928
CriteriaBuilderHelper.ilike(cb, joins.getCaze().get(Case.EPID_NUMBER), textFilter),
928929
//contact
929930
CriteriaBuilderHelper.ilike(cb, joins.getContact().get(Contact.UUID), textFilter),

sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ public void testGetSimilarPersonDtos() {
369369
tmpPerson.setSex(Sex.UNKNOWN);
370370
criteria = PersonSimilarityCriteria.forPerson(tmpPerson);
371371
assertEquals(1, getPersonFacade().getSimilarPersonDtos(criteria).size());
372-
criteria = PersonSimilarityCriteria.forPerson(tmpPerson, true);
372+
criteria = PersonSimilarityCriteria.forPerson(tmpPerson, true, false);
373373
assertEquals(0, getPersonFacade().getSimilarPersonDtos(criteria).size());
374374
}
375375

sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ && permitted(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, UserR
315315
}
316316

317317
if (permitted(FeatureType.TRAVEL_ENTRIES, UserRight.TRAVEL_ENTRY_MANAGEMENT_ACCESS)
318-
&& FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)) {
318+
&& FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_GERMANY)) {
319319
ControllerProvider.getTravelEntryController().registerViews(navigator);
320320
menu.addView(
321321
TravelEntriesView.class,

sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
import de.symeda.sormas.ui.externalsurveillanceservice.ExternalSurveillanceServiceGateway;
131131
import de.symeda.sormas.ui.hospitalization.HospitalizationForm;
132132
import de.symeda.sormas.ui.hospitalization.HospitalizationView;
133+
import de.symeda.sormas.ui.person.PersonSelectionGrid;
133134
import de.symeda.sormas.ui.symptoms.SymptomsForm;
134135
import de.symeda.sormas.ui.therapy.TherapyView;
135136
import de.symeda.sormas.ui.utils.AbstractView;
@@ -151,6 +152,9 @@
151152

152153
public class CaseController {
153154

155+
private CommitDiscardWrapperComponent<CaseCreateForm> caseCreateComponent;
156+
private boolean caseSaveTriggered;
157+
154158
public CaseController() {
155159

156160
}
@@ -187,7 +191,7 @@ public void registerViews(Navigator navigator) {
187191
}
188192

189193
public void create() {
190-
CommitDiscardWrapperComponent<CaseCreateForm> caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false);
194+
caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false);
191195
VaadinUiUtil.showModalPopupWindow(caseCreateComponent, I18nProperties.getString(Strings.headingCreateNewCase));
192196
}
193197

@@ -718,6 +722,7 @@ public CommitDiscardWrapperComponent<CaseCreateForm> getCaseCreateComponent(
718722
editView.addFieldGroups(createForm.getHomeAddressForm().getFieldGroup());
719723
}
720724

725+
caseSaveTriggered = false;
721726
editView.addCommitListener(() -> {
722727
if (!createForm.getFieldGroup().isModified()) {
723728
final CaseDataDto dto = createForm.getValue();
@@ -835,25 +840,55 @@ public CommitDiscardWrapperComponent<CaseCreateForm> getCaseCreateComponent(
835840
} else {
836841
// look for potential duplicate
837842
final PersonDto duplicatePerson = PersonDto.build();
838-
transferDataToPerson(createForm, duplicatePerson);
839-
ControllerProvider.getPersonController()
840-
.selectOrCreatePerson(
841-
duplicatePerson,
842-
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
843-
selectedPerson -> {
844-
if (selectedPerson != null) {
845-
dto.setPerson(selectedPerson);
846-
selectOrCreateCase(createForm, dto, selectedPerson);
847-
}
848-
},
849-
true);
843+
844+
if (createForm.getWarningSimilarPersons() != null) {
845+
CommitDiscardWrapperComponent<PersonSelectionGrid> warningPopUpDuplicatePerson =
846+
(CommitDiscardWrapperComponent<PersonSelectionGrid>) editView.getWrappedComponent()
847+
.getWarningSimilarPersons()
848+
.getContent();
849+
850+
warningPopUpDuplicatePerson.getDiscardButton().setVisible(true);
851+
warningPopUpDuplicatePerson.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionContinue));
852+
warningPopUpDuplicatePerson.addDoneListener(() -> {
853+
if (!caseSaveTriggered) {
854+
VaadinUiUtil.showModalPopupWindow(caseCreateComponent, I18nProperties.getString(Strings.headingCreateNewCase));
855+
}
856+
});
857+
warningPopUpDuplicatePerson.addCommitListener(() -> {
858+
caseSaveTriggered = true;
859+
transferDataToPerson(createForm, duplicatePerson);
860+
ControllerProvider.getPersonController()
861+
.selectOrCreatePerson(
862+
duplicatePerson,
863+
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
864+
selectedPerson -> {
865+
if (selectedPerson != null) {
866+
dto.setPerson(selectedPerson);
867+
selectOrCreateCase(createForm, dto, selectedPerson);
868+
}
869+
},
870+
true);
871+
});
872+
} else {
873+
transferDataToPerson(createForm, duplicatePerson);
874+
ControllerProvider.getPersonController()
875+
.selectOrCreatePerson(
876+
duplicatePerson,
877+
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
878+
selectedPerson -> {
879+
if (selectedPerson != null) {
880+
dto.setPerson(selectedPerson);
881+
selectOrCreateCase(createForm, dto, selectedPerson);
882+
}
883+
},
884+
true);
885+
}
850886
}
851887
}
852888
}
853889
});
854890

855891
return editView;
856-
857892
}
858893

859894
private void selectOrCreateCase(CaseCreateForm createForm, CaseDataDto dto, PersonReferenceDto selectedPerson) {

0 commit comments

Comments
 (0)