Skip to content

Commit

Permalink
Feature/9943 update vaccination status if necessary after delete (SOR…
Browse files Browse the repository at this point in the history
…MAS-Foundation#10181)

* SORMAS-Foundation#9943 - update the vaccination status

* SORMAS-Foundation#9943 - refactoring

* SORMAS-Foundation#9943 - delete unused import

* SORMAS-Foundation#9943 - clean the code

* SORMAS-Foundation#9943 - reformat the code

* SORMAS-Foundation#9943 - fixes

* SORMAS-Foundation#9943 - fixes

* SORMAS-Foundation#9943 - changes

* SORMAS-Foundation#9943 - refactorings

* SORMAS-Foundation#9943 - refactorings, part 2

* SORMAS-Foundation#9943 - Filter cases in backend

* SORMAS-Foundation#9943 - add isVaccinationRelevant check to getRelevantCasesForVaccination method

* SORMAS-Foundation#9943 - unit test

* SORMAS-Foundation#9943 - unit test adjustment

Co-authored-by: Maté Strysewske <[email protected]>
  • Loading branch information
carina29 and MateStrysewske authored Aug 23, 2022
1 parent 84fd6e7 commit 14e7db0
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import de.symeda.sormas.api.utils.DataHelper.Pair;
import de.symeda.sormas.api.utils.SortProperty;
import de.symeda.sormas.api.utils.ValidationRuntimeException;
import de.symeda.sormas.api.vaccination.VaccinationDto;

@Remote
public interface CaseFacade extends CoreFacade<CaseDataDto, CaseIndexDto, CaseReferenceDto, CaseCriteria> {
Expand Down Expand Up @@ -220,6 +221,8 @@ void saveBulkEditWithFacilities(

List<CaseDataDto> getByExternalId(String externalId);

List<CaseDataDto> getRelevantCasesForVaccination(VaccinationDto vaccination);

void updateExternalData(@Valid List<ExternalDataDto> externalData) throws ExternalDataUpdateException;

int updateCompleteness();
Expand All @@ -233,5 +236,9 @@ void saveBulkEditWithFacilities(
void dearchive(List<String> entityUuids, String dearchiveReason, boolean includeContacts);

void setResultingCase(EventParticipantReferenceDto eventParticipantReferenceDto, CaseReferenceDto caseReferenceDto);

EditPermissionType isEditContactAllowed(String uuid);

boolean hasOtherValidVaccination(CaseDataDto caze, String vaccinationUuid);

}
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ public interface Captions {
String CaseData_trimester = "CaseData.trimester";
String CaseData_uuid = "CaseData.uuid";
String CaseData_vaccinationStatus = "CaseData.vaccinationStatus";
String CaseData_vaccinationStatusUpdate = "CaseData.vaccinationStatusUpdate";
String CaseData_visits = "CaseData.visits";
String CaseData_wasInQuarantineBeforeIsolation = "CaseData.wasInQuarantineBeforeIsolation";
String caseDataEnterHomeAddressNow = "caseDataEnterHomeAddressNow";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ public interface Strings {
String confirmationUnclearExternalMessage = "confirmationUnclearExternalMessage";
String confirmationUnlinkCaseFromEvent = "confirmationUnlinkCaseFromEvent";
String confirmationUpdateCompleteness = "confirmationUpdateCompleteness";
String confirmationVaccinationStatusUpdate = "confirmationVaccinationStatusUpdate";
String confirmExternalMessageCorrectionThrough = "confirmExternalMessageCorrectionThrough";
String confirmNetworkDiagramTooManyContacts = "confirmNetworkDiagramTooManyContacts";
String date = "date";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.fasterxml.jackson.databind.JsonNode;

import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.caze.CaseReferenceDto;
import de.symeda.sormas.api.common.DeletionDetails;
import de.symeda.sormas.api.contact.ContactReferenceDto;
Expand Down Expand Up @@ -64,6 +65,8 @@ VaccinationDto createWithImmunization(

List<VaccinationListEntryDto> getEntriesList(VaccinationListCriteria criteria, Integer first, Integer max, List<SortProperty> sortProperties);

List<VaccinationDto> getRelevantVaccinationsForCase(CaseDataDto cazeDto);

List<VaccinationListEntryDto> getEntriesListWithRelevance(
CaseReferenceDto caseReferenceDto,
VaccinationListCriteria criteria,
Expand Down Expand Up @@ -95,4 +98,6 @@ List<VaccinationListEntryDto> getEntriesListWithRelevance(
VaccinationDto getByUuid(String uuid);

VaccinationDto postUpdate(String uuid, JsonNode vaccinationDtoJson);

boolean isVaccinationRelevant(CaseDataDto caze, VaccinationDto vaccination);
}
1 change: 1 addition & 0 deletions sormas-api/src/main/resources/captions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ CaseData.smallpoxVaccinationReceived=Was a Smallpox vaccination received in the
CaseData.smallpoxVaccinationScar=Is a Smallpox vaccination scar present?
CaseData.smallpoxLastVaccinationDate=Date of last Smallpox vaccination
CaseData.vaccinationStatus=Vaccination status
CaseData.vaccinationStatusUpdate=Vaccination status update
CaseData.surveillanceOfficer=Responsible surveillance officer
CaseData.symptoms=Symptoms
CaseData.therapy=Therapy
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 @@ -236,6 +236,7 @@ confirmationRevokeSormasToSormasShareRequest = Are you sure you want to revoke t
confirmationSinceExternalMessages = This is the first time messages will be fetched. Do you want to select the start date from which to fetch messages? If you select no, all messages will be retrieved.
confirmationSeeAllPersons=Are you sure you want to search persons for all association types? This could result in a slow response.
confirmationExternalMessageCorrection = This message contains corrections to a previous one.<br/>Do you want process those corrections from this message?
confirmationVaccinationStatusUpdate = Deleting this vaccination has lead to at least one case no longer having a valid vaccination. Do you want to remove the vaccination status from all affected cases?
confirmExternalMessageCorrectionThrough = No other new or changed information could automatically be determined from the message. Do you want to manually add or edit more information?
confirmationDeleteCaseContacts = Do you also want to delete all contacts of this case?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
import de.symeda.sormas.api.utils.YesNoUnknown;
import de.symeda.sormas.api.utils.fieldaccess.checkers.UserRightFieldAccessChecker;
import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers;
import de.symeda.sormas.api.vaccination.VaccinationDto;
import de.symeda.sormas.api.visit.VisitDto;
import de.symeda.sormas.api.visit.VisitResultDto;
import de.symeda.sormas.api.visit.VisitStatus;
Expand Down Expand Up @@ -1388,6 +1389,34 @@ public List<CaseSelectionDto> getSimilarCases(CaseSimilarityCriteria criteria) {
return entries;
}

@Override
public List<CaseDataDto> getRelevantCasesForVaccination(VaccinationDto vaccinationDto) {
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Case> cq = cb.createQuery(Case.class);
final Root<Case> caze = cq.from(Case.class);
final CaseQueryContext caseQueryContext = new CaseQueryContext(cb, cq, caze);
final CaseJoins joins = caseQueryContext.getJoins();

Vaccination vaccination = vaccinationService.getByUuid(vaccinationDto.getUuid());
Join<Case, Person> person = joins.getPerson();
Join<Person, Immunization> immunizationJoin = person.join(Person.IMMUNIZATIONS, JoinType.LEFT);
Join<Immunization, Vaccination> vaccinationsJoin = immunizationJoin.join(Immunization.VACCINATIONS, JoinType.LEFT);

Predicate predicate = cb.in(vaccinationsJoin).value(vaccination);
cq.where(predicate);
cq.select(caze);

List<Case> cases = em.createQuery(cq).getResultList();
return cases.stream().filter(c -> vaccinationService.isVaccinationRelevant(c, vaccination)).map(this::toDto).collect(Collectors.toList());
}

@Override
public boolean hasOtherValidVaccination(CaseDataDto caze, String vaccinationUuid) {
List<VaccinationDto> relevantVaccinationsForCase = vaccinationFacade.getRelevantVaccinationsForCase(caze);
//checking if the vaccination selected for delete is in the relevant vaccinations of the case
return relevantVaccinationsForCase.stream().anyMatch(v -> !v.getUuid().equals(vaccinationUuid));
}

@Override
public List<CaseIndexDto[]> getCasesForDuplicateMerging(CaseCriteria criteria, boolean ignoreRegion) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.EntityDto;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.caze.CaseReferenceDto;
import de.symeda.sormas.api.caze.VaccinationStatus;
import de.symeda.sormas.api.caze.Vaccine;
Expand Down Expand Up @@ -290,6 +291,26 @@ private VaccinationListEntryDto toVaccinationListEntryDto(Vaccination vaccinatio
return dto;
}

@Override
public boolean isVaccinationRelevant(CaseDataDto cazeDto, VaccinationDto vaccinationDto) {
Case caze = caseService.getByUuid(cazeDto.getUuid());
Vaccination vaccination = vaccinationService.getByUuid(vaccinationDto.getUuid());
return vaccinationService.isVaccinationRelevant(caze, vaccination);
}

@Override
public List<VaccinationDto> getRelevantVaccinationsForCase(CaseDataDto cazeDto) {
Case caze = caseService.getByUuid(cazeDto.getUuid());
List<Vaccination> vaccinations = vaccinationService.getRelevantVaccinationsForCase(caze);
return convertToDtoList(vaccinations);
}

public List<VaccinationDto> convertToDtoList(List<Vaccination> vaccinations) {
Pseudonymizer defaultPseudonymizer = Pseudonymizer.getDefault(userService::hasRight);

return vaccinations.stream().map(v -> convertToDto(v, defaultPseudonymizer)).collect(Collectors.toList());
}

@Override
public List<VaccinationListEntryDto> getEntriesListWithRelevance(
CaseReferenceDto caseReferenceDto,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
import de.symeda.sormas.api.vaccination.VaccinationDto;
import de.symeda.sormas.api.vaccination.VaccinationListCriteria;
import de.symeda.sormas.backend.caze.Case;
import de.symeda.sormas.backend.caze.CaseJoins;
import de.symeda.sormas.backend.caze.CaseQueryContext;
import de.symeda.sormas.backend.common.AbstractDomainObject;
import de.symeda.sormas.backend.common.BaseAdoService;
import de.symeda.sormas.backend.common.CriteriaBuilderHelper;
Expand Down Expand Up @@ -244,6 +246,25 @@ private boolean isVaccinationRelevant(Vaccination vaccination, Date... relevance
return false;
}

public List<Vaccination> getRelevantVaccinationsForCase(Case caze) {
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Vaccination> cq = cb.createQuery(Vaccination.class);
final Root<Case> root = cq.from(Case.class);
final CaseQueryContext caseQueryContext = new CaseQueryContext(cb, cq, root);
final CaseJoins joins = caseQueryContext.getJoins();

Join<Case, Person> person = joins.getPerson();
Join<Person, Immunization> immunization = person.join(Person.IMMUNIZATIONS, JoinType.LEFT);
Join<Immunization, Vaccination> vaccination = immunization.join(Immunization.VACCINATIONS, JoinType.LEFT);

Predicate predicate = cb.in(root).value(caze);
cq.where(predicate);
cq.select(vaccination);

List<Vaccination> vaccinations = em.createQuery(cq).getResultList();
return vaccinations.stream().filter(v -> isVaccinationRelevant(caze, v)).collect(Collectors.toList());
}

public List<Vaccination> getRelevantSortedVaccinations(List<Vaccination> vaccinations, Date... relevanceFilterDates) {

return vaccinations.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,60 @@ public void testGetExportListNoDuplicates() {
assertTrue(exportDto.isTraveled());
}

@Test
public void testGeRelevantCasesForVaccination() {
RDCFEntities rdcfEntities = creator.createRDCFEntities("Region", "District", "Community", "Facility");
RDCF rdcf = new RDCF(rdcfEntities);
UserDto user = createUser(rdcfEntities);

PersonDto cazePerson1 = creator.createPerson("Case1", "Person1");
CaseDataDto caze1 = createCase(user, cazePerson1, rdcfEntities);

ImmunizationDto immunization = creator.createImmunization(
caze1.getDisease(),
caze1.getPerson(),
caze1.getReportingUser(),
ImmunizationStatus.ACQUIRED,
MeansOfImmunization.VACCINATION,
ImmunizationManagementStatus.COMPLETED,
rdcf,
DateHelper.subtractDays(new Date(), 10),
DateHelper.subtractDays(new Date(), 5),
DateHelper.subtractDays(new Date(), 1),
null);

VaccinationDto firstRelevantVaccinationForCase1 = creator.createVaccinationWithDetails(
caze1.getReportingUser(),
immunization.toReference(),
HealthConditionsDto.build(),
DateHelper.subtractDays(new Date(), 7),
Vaccine.OXFORD_ASTRA_ZENECA,
VaccineManufacturer.ASTRA_ZENECA,
VaccinationInfoSource.UNKNOWN,
"inn1",
"123",
"code123",
"3");

VaccinationDto notRelevantVaccinationForCase1 = creator.createVaccinationWithDetails(
caze1.getReportingUser(),
immunization.toReference(),
HealthConditionsDto.build(),
new Date(),
Vaccine.MRNA_1273,
VaccineManufacturer.MODERNA,
VaccinationInfoSource.UNKNOWN,
"inn2",
"456",
"code456",
"2");

List<CaseDataDto> cases1 = new ArrayList<>();
cases1.add(caze1);
assertEquals(getCaseFacade().getRelevantCasesForVaccination(firstRelevantVaccinationForCase1), cases1);
assertTrue(getCaseFacade().getRelevantCasesForVaccination(notRelevantVaccinationForCase1).isEmpty());
}

/**
* Test with {@link CaseExportType#CASE_MANAGEMENT} and full export columns.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@

package de.symeda.sormas.ui.vaccination;

import static de.symeda.sormas.api.FacadeProvider.getCaseFacade;

import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import com.vaadin.ui.Label;
import com.vaadin.ui.Window;

import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.FacadeProvider;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.i18n.Captions;
import de.symeda.sormas.api.i18n.I18nProperties;
import de.symeda.sormas.api.i18n.Strings;
Expand All @@ -31,6 +37,7 @@
import de.symeda.sormas.api.user.UserRight;
import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers;
import de.symeda.sormas.api.vaccination.VaccinationDto;
import de.symeda.sormas.ui.SormasUI;
import de.symeda.sormas.ui.UserProvider;
import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent;
import de.symeda.sormas.ui.utils.VaadinUiUtil;
Expand Down Expand Up @@ -129,6 +136,13 @@ public void edit(
createComponent.addDeleteWithReasonListener((deleteDetails) -> {
popupWindow.close();
if (doSave) {
List<CaseDataDto> cases = getCaseFacade().getRelevantCasesForVaccination(vaccination)
.stream()
.filter(c -> !getCaseFacade().hasOtherValidVaccination(c, vaccination.getUuid()))
.collect(Collectors.toList());
if (!cases.isEmpty()) {
showUpdateStatusConfirmationPopup(cases);
}
FacadeProvider.getVaccinationFacade().deleteWithImmunization(vaccination.getUuid(), deleteDetails);
}
if (deleteCallback != null) {
Expand All @@ -138,6 +152,26 @@ public void edit(
}
}

public static void showUpdateStatusConfirmationPopup(List<CaseDataDto> cases) {
VaadinUiUtil.showConfirmationPopup(
I18nProperties.getCaption(Captions.CaseData_vaccinationStatusUpdate),
new Label(I18nProperties.getString(Strings.confirmationVaccinationStatusUpdate)),
I18nProperties.getString(Strings.yes),
I18nProperties.getString(Strings.no),
600,
confirmedVaccinationStatusUpdate -> {
if (confirmedVaccinationStatusUpdate) {
cases.forEach(VaccinationController::updateVaccinationStatus);
SormasUI.refreshView();
} ;
});
}

public static void updateVaccinationStatus(CaseDataDto caseDataDto) {
caseDataDto.setVaccinationStatus(null);
getCaseFacade().save(caseDataDto);
}

public CommitDiscardWrapperComponent<VaccinationEditForm> getVaccinationEditComponent(
VaccinationDto vaccination,
Disease disease,
Expand Down

0 comments on commit 14e7db0

Please sign in to comment.