Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

#13181 - Enhance National Health ID Search Functionality Across Modules and Address Duplication Issues #13201

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ public interface Strings {
String headingShowExternalMessage = "headingShowExternalMessage";
String headingSignsAndSymptoms = "headingSignsAndSymptoms";
String headingSimilarImmunization = "headingSimilarImmunization";
String headingSimilarPerson = "headingSimilarPerson";
String headingSomeCasesAlreadyInEvent = "headingSomeCasesAlreadyInEvent";
String headingSomeCasesNotRestored = "headingSomeCasesNotRestored";
String headingSomeContactsAlreadyInEvent = "headingSomeContactsAlreadyInEvent";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class PersonSimilarityCriteria extends BaseCriteria implements Cloneable
private String passportNumber;
private String nationalHealthId;
private String nameUuidExternalIdExternalTokenLike;
private boolean checkOnlyForNationalHealthId;
/**
* If true, compare the name of the person only to the first and last name fields of the database; if false, compare the
* name of the person to other fields like UUID and external ID as well.
Expand Down Expand Up @@ -106,6 +107,14 @@ public PersonSimilarityCriteria nationalHealthId(String nationalHealthId) {
return this;
}

public boolean isCheckOnlyForNationalHealthId() {
return checkOnlyForNationalHealthId;
}

public void setCheckOnlyForNationalHealthId(boolean checkOnlyForNationalHealthId) {
this.checkOnlyForNationalHealthId = checkOnlyForNationalHealthId;
}

public String getNameUuidExternalIdExternalTokenLike() {
return nameUuidExternalIdExternalTokenLike;
}
Expand Down Expand Up @@ -140,22 +149,27 @@ public void setBirthdateDD(Integer birthdateDD) {
}

public static PersonSimilarityCriteria forPerson(PersonDto person) {
return forPerson(person, false);
return forPerson(person, false, false);
}

public static PersonSimilarityCriteria forPerson(PersonDto person, boolean checkOnlyForNationalHealthId){
return forPerson(person, false, checkOnlyForNationalHealthId);
}

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

PersonSimilarityCriteria personSimilarityCriteria = new PersonSimilarityCriteria().sex(person.getSex())
.birthdateDD(person.getBirthdateDD())
.birthdateMM(person.getBirthdateMM())
.birthdateYYYY(person.getBirthdateYYYY())
.passportNumber(person.getPassportNumber())
.nationalHealthId(person.getNationalHealthId());
personSimilarityCriteria.setCheckOnlyForNationalHealthId(checkOnlyForNationalHealthId);
if (strictNameComparison) {
personSimilarityCriteria.firstName(person.getFirstName()).lastName(person.getLastName()).strictNameComparison(Boolean.TRUE);
} else {
Expand Down
1 change: 1 addition & 0 deletions sormas-api/src/main/resources/strings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ headingShowExternalMessage = Message
headingSelfReportSideComponent = Self reports
headingSignsAndSymptoms = Clinical Signs and Symptoms
headingSimilarImmunization = Similar immunizaton
headingSimilarPerson = There are other persons with similar national health Id
headingSyncUsers = Sync Users
headingTasksDeleted = Tasks deleted
headingTasksNotDeleted = None of the tasks were deleted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import de.symeda.sormas.backend.person.Person;
import org.apache.commons.lang3.StringUtils;

import de.symeda.sormas.api.ReferenceDto;
Expand Down Expand Up @@ -123,6 +124,7 @@ public Predicate buildCriteriaFilter(CriteriaBuilder cb, Root<ExternalMessage> l
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.UUID), textFilter),
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.PERSON_FIRST_NAME), textFilter),
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.PERSON_LAST_NAME), textFilter),
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.PERSON_NATIONAL_HEALTH_ID), textFilter),
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.PERSON_POSTAL_CODE), textFilter),
CriteriaBuilderHelper.unaccentedIlike(cb, labMessage.get(ExternalMessage.REPORTER_NAME), textFilter),
CriteriaBuilderHelper.ilike(cb, labMessage.get(ExternalMessage.REPORTER_POSTAL_CODE), textFilter));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ protected void handlePickOrCreatePerson(PersonDto person, HandlerCallback<Entity
callback.cancel();
}
} else {
PersonSimilarityCriteria similarityCriteria = PersonSimilarityCriteria.forPerson(person, true);
PersonSimilarityCriteria similarityCriteria = PersonSimilarityCriteria.forPerson(person, true, false);
if (personFacade.checkMatchingNameInDatabase(user.toReference(), similarityCriteria)) {
logger.debug("[MESSAGE PROCESSING] Similar persons found in the database. Canceling processing.");
callback.cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,16 +353,16 @@ private Predicate createAssociationPredicate(@NotNull PersonQueryContext queryCo
eventParticipantService.createDefaultFilter(cb, joins.getEventParticipant()));
break;
case IMMUNIZATION:
associationPredicate = CriteriaBuilderHelper.and(
cb,
immunizationService.createUserFilter(new ImmunizationQueryContext(cb, cq, joins.getImmunizationJoins())),
immunizationService.createDefaultFilter(cb, joins.getImmunization()));
associationPredicate = CriteriaBuilderHelper.and(
cb,
immunizationService.createUserFilter(new ImmunizationQueryContext(cb, cq, joins.getImmunizationJoins())),
immunizationService.createDefaultFilter(cb, joins.getImmunization()));
break;
case TRAVEL_ENTRY:
associationPredicate = CriteriaBuilderHelper.and(
cb,
travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntryJoins())),
travelEntryService.createDefaultFilter(cb, joins.getTravelEntry()));
associationPredicate = CriteriaBuilderHelper.and(
cb,
travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntryJoins())),
travelEntryService.createDefaultFilter(cb, joins.getTravelEntry()));
break;
case ALL:
default:
Expand Down Expand Up @@ -408,7 +408,8 @@ public Predicate buildCriteriaFilter(PersonCriteria personCriteria, PersonQueryC
CriteriaBuilderHelper.ilike(cb, location.get(Location.POSTAL_CODE), textFilter),
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.INTERNAL_TOKEN), textFilter),
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_ID), textFilter),
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_TOKEN), textFilter));
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.EXTERNAL_TOKEN), textFilter),
CriteriaBuilderHelper.ilike(cb, personFrom.get(Person.NATIONAL_HEALTH_ID), textFilter));
filter = CriteriaBuilderHelper.and(cb, filter, likeFilters);
}
}
Expand Down Expand Up @@ -924,7 +925,8 @@ public Predicate buildSimilarityCriteriaFilter(PersonSimilarityCriteria criteria
}
}

if (configFacade.isDuplicateChecksNationalHealthIdOverridesCriteria() && StringUtils.isNotBlank(criteria.getNationalHealthId())) {
if (StringUtils.isNotBlank(criteria.getNationalHealthId())
&& (configFacade.isDuplicateChecksNationalHealthIdOverridesCriteria() || criteria.isCheckOnlyForNationalHealthId())) {
filter = or(cb, filter, cb.equal(personFrom.get(Person.NATIONAL_HEALTH_ID), criteria.getNationalHealthId()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,7 @@ public Predicate buildCriteriaFilter(SampleCriteria criteria, SampleQueryContext
CriteriaBuilderHelper.ilike(cb, joins.getCaze().get(Case.UUID), textFilter),
CriteriaBuilderHelper.unaccentedIlike(cb, joins.getCasePerson().get(Person.FIRST_NAME), textFilter),
CriteriaBuilderHelper.unaccentedIlike(cb, joins.getCasePerson().get(Person.LAST_NAME), textFilter),
CriteriaBuilderHelper.ilike(cb, joins.getCasePerson().get(Person.NATIONAL_HEALTH_ID), textFilter),
CriteriaBuilderHelper.ilike(cb, joins.getCaze().get(Case.EPID_NUMBER), textFilter),
//contact
CriteriaBuilderHelper.ilike(cb, joins.getContact().get(Contact.UUID), textFilter),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ public void testGetSimilarPersonDtos() {
tmpPerson.setSex(Sex.UNKNOWN);
criteria = PersonSimilarityCriteria.forPerson(tmpPerson);
assertEquals(1, getPersonFacade().getSimilarPersonDtos(criteria).size());
criteria = PersonSimilarityCriteria.forPerson(tmpPerson, true);
criteria = PersonSimilarityCriteria.forPerson(tmpPerson, true, false);
assertEquals(0, getPersonFacade().getSimilarPersonDtos(criteria).size());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ && permitted(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, UserR
}

if (permitted(FeatureType.TRAVEL_ENTRIES, UserRight.TRAVEL_ENTRY_MANAGEMENT_ACCESS)
&& FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)) {
&& FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_GERMANY)) {
ControllerProvider.getTravelEntryController().registerViews(navigator);
menu.addView(
TravelEntriesView.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
import de.symeda.sormas.ui.externalsurveillanceservice.ExternalSurveillanceServiceGateway;
import de.symeda.sormas.ui.hospitalization.HospitalizationForm;
import de.symeda.sormas.ui.hospitalization.HospitalizationView;
import de.symeda.sormas.ui.person.PersonSelectionGrid;
import de.symeda.sormas.ui.symptoms.SymptomsForm;
import de.symeda.sormas.ui.therapy.TherapyView;
import de.symeda.sormas.ui.utils.AbstractView;
Expand All @@ -151,6 +152,9 @@

public class CaseController {

private CommitDiscardWrapperComponent<CaseCreateForm> caseCreateComponent;
private boolean caseSaveTriggered;

public CaseController() {

}
Expand Down Expand Up @@ -187,7 +191,7 @@ public void registerViews(Navigator navigator) {
}

public void create() {
CommitDiscardWrapperComponent<CaseCreateForm> caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false);
caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false);
VaadinUiUtil.showModalPopupWindow(caseCreateComponent, I18nProperties.getString(Strings.headingCreateNewCase));
}

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

caseSaveTriggered = false;
editView.addCommitListener(() -> {
if (!createForm.getFieldGroup().isModified()) {
final CaseDataDto dto = createForm.getValue();
Expand Down Expand Up @@ -835,25 +840,55 @@ public CommitDiscardWrapperComponent<CaseCreateForm> getCaseCreateComponent(
} else {
// look for potential duplicate
final PersonDto duplicatePerson = PersonDto.build();
transferDataToPerson(createForm, duplicatePerson);
ControllerProvider.getPersonController()
.selectOrCreatePerson(
duplicatePerson,
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
selectedPerson -> {
if (selectedPerson != null) {
dto.setPerson(selectedPerson);
selectOrCreateCase(createForm, dto, selectedPerson);
}
},
true);

if (createForm.getWarningSimilarPersons() != null) {
CommitDiscardWrapperComponent<PersonSelectionGrid> warningPopUpDuplicatePerson =
(CommitDiscardWrapperComponent<PersonSelectionGrid>) editView.getWrappedComponent()
.getWarningSimilarPersons()
.getContent();

warningPopUpDuplicatePerson.getDiscardButton().setVisible(true);
warningPopUpDuplicatePerson.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionContinue));
warningPopUpDuplicatePerson.addDoneListener(() -> {
if (!caseSaveTriggered) {
VaadinUiUtil.showModalPopupWindow(caseCreateComponent, I18nProperties.getString(Strings.headingCreateNewCase));
}
});
warningPopUpDuplicatePerson.addCommitListener(() -> {
caseSaveTriggered = true;
transferDataToPerson(createForm, duplicatePerson);
ControllerProvider.getPersonController()
.selectOrCreatePerson(
duplicatePerson,
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
selectedPerson -> {
if (selectedPerson != null) {
dto.setPerson(selectedPerson);
selectOrCreateCase(createForm, dto, selectedPerson);
}
},
true);
});
} else {
transferDataToPerson(createForm, duplicatePerson);
ControllerProvider.getPersonController()
.selectOrCreatePerson(
duplicatePerson,
I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase),
selectedPerson -> {
if (selectedPerson != null) {
dto.setPerson(selectedPerson);
selectOrCreateCase(createForm, dto, selectedPerson);
}
},
true);
}
}
}
}
});

return editView;

}

private void selectOrCreateCase(CaseCreateForm createForm, CaseDataDto dto, PersonReferenceDto selectedPerson) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import com.google.common.collect.Sets;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
import com.vaadin.v7.data.util.converter.Converter;
import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode;
Expand Down Expand Up @@ -72,6 +73,7 @@
import de.symeda.sormas.ui.UiUtil;
import de.symeda.sormas.ui.location.LocationEditForm;
import de.symeda.sormas.ui.person.PersonCreateForm;
import de.symeda.sormas.ui.person.PersonFormHelper;
import de.symeda.sormas.ui.utils.AbstractEditForm;
import de.symeda.sormas.ui.utils.ComboBoxHelper;
import de.symeda.sormas.ui.utils.CssStyles;
Expand Down Expand Up @@ -111,6 +113,7 @@ public class CaseCreateForm extends AbstractEditForm<CaseDataDto> {
private NullableOptionGroup ogCaseOrigin;

private PersonCreateForm personCreateForm;
private Window warningSimilarPersons;

private final boolean showHomeAddressForm;
private final boolean showPersonSearchButton;
Expand Down Expand Up @@ -209,6 +212,11 @@ protected void addFields() {
personCreateForm.setWidth(100, Unit.PERCENTAGE);
getContent().addComponent(personCreateForm, CaseDataDto.PERSON);

personCreateForm.getNationalHealthIdField().addTextFieldValueChangeListener(e -> {
warningSimilarPersons = PersonFormHelper
.warningSimilarPersons(personCreateForm.getNationalHealthIdField().getValue(), null, () -> warningSimilarPersons = null);
});

// Jurisdiction fields
Label jurisdictionHeadingLabel = new Label(I18nProperties.getString(Strings.headingCaseResponsibleJurisidction));
jurisdictionHeadingLabel.addStyleName(H3);
Expand Down Expand Up @@ -730,4 +738,8 @@ public void setValue(CaseDataDto caseDataDto) throws com.vaadin.v7.data.Property
public void setSearchedPerson(PersonDto searchedPerson) {
personCreateForm.setSearchedPerson(searchedPerson);
}

public Window getWarningSimilarPersons() {
return warningSimilarPersons;
}
}
Loading
Loading