diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 3096708844c..8c30a302954 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java index a27d409517e..415200b29e2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java @@ -161,4 +161,6 @@ public interface ConfigFacade { CaseClassificationCalculationMode getCaseClassificationCalculationMode(Disease disease); boolean isAnyCaseClassificationCalculationEnabled(); + + Integer getNegaiveCovidTestsMaxAgeDays(); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java b/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java index e1c5c9f7349..f257bcbe37b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/Disease.java @@ -69,8 +69,9 @@ public enum Disease YAWS_ENDEMIC_SYPHILIS(true, false, false, true, false, 0, true, false, false), MATERNAL_DEATHS(true, false, false, true, false, 0, true, false, false), PERINATAL_DEATHS(true, false, false, true, false, 0, true, false, false), - INFLUENZA_A(true, false, true, false, false, 0, true, false, false), - INFLUENZA_B(true, false, true, false, false, 0, true, false, false), + INFLUENZA(true, true, true, false, false, 0, true, false, false), + INFLUENZA_A(false, false, true, false, false, 0, true, false, false), + INFLUENZA_B(false, false, true, false, false, 0, true, false, false), H_METAPNEUMOVIRUS(true, false, true, false, false, 0, true, false, false), RESPIRATORY_SYNCYTIAL_VIRUS(true, false, true, false, false, 0, true, false, false), PARAINFLUENZA_1_4(true, false, true, false, false, 0, true, false, false), diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java index e731a9dd8e0..bf85edda351 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java @@ -19,6 +19,8 @@ import javax.naming.NamingException; import de.symeda.sormas.api.action.ActionFacade; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiFacade; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationFacade; import de.symeda.sormas.api.audit.AuditLoggerFacade; import de.symeda.sormas.api.bagexport.BAGExportFacade; import de.symeda.sormas.api.campaign.CampaignFacade; @@ -38,6 +40,7 @@ import de.symeda.sormas.api.contact.ContactFacade; import de.symeda.sormas.api.customizableenum.CustomizableEnumFacade; import de.symeda.sormas.api.dashboard.DashboardFacade; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiDashboardFacade; import de.symeda.sormas.api.dashboard.sample.SampleDashboardFacade; import de.symeda.sormas.api.deletionconfiguration.DeletionConfigurationFacade; import de.symeda.sormas.api.disease.DiseaseConfigurationFacade; @@ -148,6 +151,14 @@ public static ImmunizationFacade getImmunizationFacade() { return get().lookupEjbRemote(ImmunizationFacade.class); } + public static AefiFacade getAefiFacade() { + return get().lookupEjbRemote(AefiFacade.class); + } + + public static AefiInvestigationFacade getAefiInvestigationFacade() { + return get().lookupEjbRemote(AefiInvestigationFacade.class); + } + public static VaccinationFacade getVaccinationFacade() { return get().lookupEjbRemote(VaccinationFacade.class); } @@ -320,6 +331,10 @@ public static SampleDashboardFacade getSampleDashboardFacade() { return get().lookupEjbRemote(SampleDashboardFacade.class); } + public static AefiDashboardFacade getAefiDashboardFacade() { + return get().lookupEjbRemote(AefiDashboardFacade.class); + } + public static DiseaseConfigurationFacade getDiseaseConfigurationFacade() { return get().lookupEjbRemote(DiseaseConfigurationFacade.class); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventState.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventState.java new file mode 100644 index 00000000000..73d64393393 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventState.java @@ -0,0 +1,33 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AdverseEventState { + + YES, + NO, + UNKNOWN; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventsDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventsDto.java new file mode 100644 index 00000000000..94551919c89 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AdverseEventsDto.java @@ -0,0 +1,186 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.DependingOnFeatureType; +import de.symeda.sormas.api.utils.Order; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableDto; + +@DependingOnFeatureType(featureType = { + FeatureType.IMMUNIZATION_MANAGEMENT, + FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT }) +public class AdverseEventsDto extends PseudonymizableDto { + + private static final long serialVersionUID = 8081578717541472008L; + + public static final String I18N_PREFIX = "AdverseEvents"; + + public static final String SEVERE_LOCAL_REACTION = "severeLocalReaction"; + public static final String SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS = "severeLocalReactionMoreThanThreeDays"; + public static final String SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT = "severeLocalReactionBeyondNearestJoint"; + public static final String SEIZURES = "seizures"; + public static final String SEIZURE_TYPE = "seizureType"; + public static final String ABSCESS = "abscess"; + public static final String SEPSIS = "sepsis"; + public static final String ENCEPHALOPATHY = "encephalopathy"; + public static final String TOXIC_SHOCK_SYNDROME = "toxicShockSyndrome"; + public static final String THROMBOCYTOPENIA = "thrombocytopenia"; + public static final String ANAPHYLAXIS = "anaphylaxis"; + public static final String FEVERISH_FEELING = "feverishFeeling"; + public static final String OTHER_ADVERSE_EVENT_DETAILS = "otherAdverseEventDetails"; + + private AdverseEventState severeLocalReaction; + private boolean severeLocalReactionMoreThanThreeDays; + private boolean severeLocalReactionBeyondNearestJoint; + private AdverseEventState seizures; + private SeizureType seizureType; + private AdverseEventState abscess; + private AdverseEventState sepsis; + private AdverseEventState encephalopathy; + private AdverseEventState toxicShockSyndrome; + private AdverseEventState thrombocytopenia; + private AdverseEventState anaphylaxis; + private AdverseEventState feverishFeeling; + private String otherAdverseEventDetails; + + public static AdverseEventsDto build() { + AdverseEventsDto adverseEvents = new AdverseEventsDto(); + adverseEvents.setUuid(DataHelper.createUuid()); + return adverseEvents; + } + + @Order(1) + public AdverseEventState getSevereLocalReaction() { + return severeLocalReaction; + } + + public void setSevereLocalReaction(AdverseEventState severeLocalReaction) { + this.severeLocalReaction = severeLocalReaction; + } + + @Order(2) + public boolean isSevereLocalReactionMoreThanThreeDays() { + return severeLocalReactionMoreThanThreeDays; + } + + public void setSevereLocalReactionMoreThanThreeDays(boolean severeLocalReactionMoreThanThreeDays) { + this.severeLocalReactionMoreThanThreeDays = severeLocalReactionMoreThanThreeDays; + } + + @Order(3) + public boolean isSevereLocalReactionBeyondNearestJoint() { + return severeLocalReactionBeyondNearestJoint; + } + + public void setSevereLocalReactionBeyondNearestJoint(boolean severeLocalReactionBeyondNearestJoint) { + this.severeLocalReactionBeyondNearestJoint = severeLocalReactionBeyondNearestJoint; + } + + @Order(4) + public AdverseEventState getSeizures() { + return seizures; + } + + public void setSeizures(AdverseEventState seizures) { + this.seizures = seizures; + } + + @Order(5) + public SeizureType getSeizureType() { + return seizureType; + } + + public void setSeizureType(SeizureType seizureType) { + this.seizureType = seizureType; + } + + @Order(6) + public AdverseEventState getAbscess() { + return abscess; + } + + public void setAbscess(AdverseEventState abscess) { + this.abscess = abscess; + } + + @Order(7) + public AdverseEventState getSepsis() { + return sepsis; + } + + public void setSepsis(AdverseEventState sepsis) { + this.sepsis = sepsis; + } + + @Order(7) + public AdverseEventState getEncephalopathy() { + return encephalopathy; + } + + public void setEncephalopathy(AdverseEventState encephalopathy) { + this.encephalopathy = encephalopathy; + } + + @Order(8) + public AdverseEventState getToxicShockSyndrome() { + return toxicShockSyndrome; + } + + public void setToxicShockSyndrome(AdverseEventState toxicShockSyndrome) { + this.toxicShockSyndrome = toxicShockSyndrome; + } + + @Order(9) + public AdverseEventState getThrombocytopenia() { + return thrombocytopenia; + } + + public void setThrombocytopenia(AdverseEventState thrombocytopenia) { + this.thrombocytopenia = thrombocytopenia; + } + + @Order(10) + public AdverseEventState getAnaphylaxis() { + return anaphylaxis; + } + + public void setAnaphylaxis(AdverseEventState anaphylaxis) { + this.anaphylaxis = anaphylaxis; + } + + @Order(11) + public AdverseEventState getFeverishFeeling() { + return feverishFeeling; + } + + public void setFeverishFeeling(AdverseEventState feverishFeeling) { + this.feverishFeeling = feverishFeeling; + } + + @Order(12) + public String getOtherAdverseEventDetails() { + return otherAdverseEventDetails; + } + + public void setOtherAdverseEventDetails(String otherAdverseEventDetails) { + this.otherAdverseEventDetails = otherAdverseEventDetails; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiAgeGroup.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiAgeGroup.java new file mode 100644 index 00000000000..4e57132ea70 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiAgeGroup.java @@ -0,0 +1,35 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiAgeGroup { + + ZERO_TO_ONE, + ONE_TO_FIVE, + FIVE_TO_EIGHTEEN, + EIGHTEEN_TO_SIXTY, + SIXY_AND_ABOVE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCausality.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCausality.java new file mode 100644 index 00000000000..c29b81af2a7 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCausality.java @@ -0,0 +1,29 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiCausality { + + CONFIRMED, + INCONCLUSIVE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassification.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassification.java new file mode 100644 index 00000000000..8f8771c4c18 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassification.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiClassification { + + RELATED_TO_VACCINE_OR_VACCINATION, + COINCIDENTAL_ADVERSE_EVENT, + UNDETERMINED; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassificationSubType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassificationSubType.java new file mode 100644 index 00000000000..e94d6a7010b --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiClassificationSubType.java @@ -0,0 +1,39 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification.RELATED_TO_VACCINE_OR_VACCINATION; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiClassificationSubType { + + VACCINE_PRODUCT_RELATED(RELATED_TO_VACCINE_OR_VACCINATION), + VACCINE_QUALITY_DEFECT_RELATED(RELATED_TO_VACCINE_OR_VACCINATION), + IMMUNIZATION_ERROR_RELATED(RELATED_TO_VACCINE_OR_VACCINATION), + IMMUNIZATION_ANXIETY_RELATED(RELATED_TO_VACCINE_OR_VACCINATION); + + private AefiClassification aefiClassification; + + AefiClassificationSubType(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCriteria.java new file mode 100644 index 00000000000..4edcde120d6 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiCriteria.java @@ -0,0 +1,229 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.caze.VaccineManufacturer; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityType; +import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.utils.DateFilterOption; +import de.symeda.sormas.api.utils.criteria.BaseCriteria; + +public class AefiCriteria extends BaseCriteria implements Serializable { + + public static final String I18N_PREFIX = "AefiCriteria"; + + public static final String DISEASE = "disease"; + public static final String PERSON_LIKE = "personLike"; + public static final String AEFI_TYPE = "aefiType"; + public static final String VACCINE_NAME = "vaccineName"; + public static final String VACCINE_MANUFACTURER = "vaccineManufacturer"; + public static final String REGION = "region"; + public static final String DISTRICT = "district"; + public static final String COMMUNITY = "community"; + public static final String OUTCOME = "outcome"; + public static final String FACILITY_TYPE_GROUP = "facilityTypeGroup"; + public static final String FACILITY_TYPE = "facilityType"; + public static final String HEALTH_FACILITY = "healthFacility"; + public static final String DATE_FILTER_OPTION = "dateFilterOption"; + public static final String AEFI_DATE_TYPE = "aefiDateType"; + public static final String FROM_DATE = "fromDate"; + public static final String TO_DATE = "toDate"; + public static final String RELEVANCE_STATUS = "relevanceStatus"; + + private Disease disease; + private String personLike; + private AefiType aefiType; + private Vaccine vaccineName; + private VaccineManufacturer vaccineManufacturer; + private RegionReferenceDto region; + private DistrictReferenceDto district; + private CommunityReferenceDto community; + private AefiOutcome outcome; + private FacilityTypeGroup facilityTypeGroup; + private FacilityType facilityType; + private FacilityReferenceDto healthFacility; + private DateFilterOption dateFilterOption = DateFilterOption.DATE; + private AefiDateType aefiDateType; + private Date fromDate; + private Date toDate; + private EntityRelevanceStatus relevanceStatus; + + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + public String getPersonLike() { + return personLike; + } + + public void setPersonLike(String personLike) { + this.personLike = personLike; + } + + public AefiType getAefiType() { + return aefiType; + } + + public void setAefiType(AefiType aefiType) { + this.aefiType = aefiType; + } + + public Vaccine getVaccineName() { + return vaccineName; + } + + public void setVaccineName(Vaccine vaccineName) { + this.vaccineName = vaccineName; + } + + public VaccineManufacturer getVaccineManufacturer() { + return vaccineManufacturer; + } + + public void setVaccineManufacturer(VaccineManufacturer vaccineManufacturer) { + this.vaccineManufacturer = vaccineManufacturer; + } + + public RegionReferenceDto getRegion() { + return region; + } + + public void setRegion(RegionReferenceDto region) { + this.region = region; + } + + public DistrictReferenceDto getDistrict() { + return district; + } + + public void setDistrict(DistrictReferenceDto district) { + this.district = district; + } + + public CommunityReferenceDto getCommunity() { + return community; + } + + public void setCommunity(CommunityReferenceDto community) { + this.community = community; + } + + public AefiOutcome getOutcome() { + return outcome; + } + + public void setOutcome(AefiOutcome outcome) { + this.outcome = outcome; + } + + public FacilityTypeGroup getFacilityTypeGroup() { + return facilityTypeGroup; + } + + public void setFacilityTypeGroup(FacilityTypeGroup facilityTypeGroup) { + this.facilityTypeGroup = facilityTypeGroup; + } + + public FacilityType getFacilityType() { + return facilityType; + } + + public void setFacilityType(FacilityType facilityType) { + this.facilityType = facilityType; + } + + public FacilityReferenceDto getHealthFacility() { + return healthFacility; + } + + public void setHealthFacility(FacilityReferenceDto healthFacility) { + this.healthFacility = healthFacility; + } + + public DateFilterOption getDateFilterOption() { + return dateFilterOption; + } + + public void setDateFilterOption(DateFilterOption dateFilterOption) { + this.dateFilterOption = dateFilterOption; + } + + public AefiDateType getAefiDateType() { + return aefiDateType; + } + + public void setAefiDateType(AefiDateType aefiDateType) { + this.aefiDateType = aefiDateType; + } + + public Date getFromDate() { + return fromDate; + } + + public void setFromDate(Date fromDate) { + this.fromDate = fromDate; + } + + public Date getToDate() { + return toDate; + } + + public void setToDate(Date toDate) { + this.toDate = toDate; + } + + public EntityRelevanceStatus getRelevanceStatus() { + return relevanceStatus; + } + + public void setRelevanceStatus(EntityRelevanceStatus relevanceStatus) { + this.relevanceStatus = relevanceStatus; + } + + public AefiCriteria disease(Disease disease) { + this.disease = disease; + return this; + } + + public AefiCriteria region(RegionReferenceDto region) { + this.region = region; + return this; + } + + public AefiCriteria district(DistrictReferenceDto district) { + this.district = district; + return this; + } + + public AefiCriteria aefiType(AefiType aefiType) { + this.aefiType = aefiType; + return this; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDashboardFilterDateType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDashboardFilterDateType.java new file mode 100644 index 00000000000..984641a06e5 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDashboardFilterDateType.java @@ -0,0 +1,32 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiDashboardFilterDateType { + + REPORT_DATE, + START_DATE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDateType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDateType.java new file mode 100644 index 00000000000..9eef385ce9c --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDateType.java @@ -0,0 +1,33 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiDateType { + + REPORT_DATE, + START_DATE, + VACCINATION_DATE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDto.java new file mode 100644 index 00000000000..e98c7ca0d9e --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiDto.java @@ -0,0 +1,611 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import de.symeda.sormas.api.caze.Trimester; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.immunization.ImmunizationReferenceDto; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.country.CountryReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.location.LocationDto; +import de.symeda.sormas.api.person.PersonReferenceDto; +import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.DependingOnFeatureType; +import de.symeda.sormas.api.utils.FieldConstraints; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableDto; +import de.symeda.sormas.api.vaccination.VaccinationDto; + +@DependingOnFeatureType(featureType = { + FeatureType.IMMUNIZATION_MANAGEMENT, + FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT }) +public class AefiDto extends PseudonymizableDto { + + private static final long serialVersionUID = 5023410664970514090L; + + public static final long APPROXIMATE_JSON_SIZE_IN_BYTES = 25455; + + public static final String I18N_PREFIX = "Aefi"; + + public static final String IMMUNIZATION = "immunization"; + public static final String ADDRESS = "address"; + public static final String VACCINATIONS = "vaccinations"; + public static final String PRIMARY_SUSPECT_VACCINE = "primarySuspectVaccine"; + public static final String ADVERSE_EVENTS = "adverseEvents"; + public static final String PERSON = "person"; + public static final String REPORT_DATE = "reportDate"; + public static final String REPORTING_USER = "reportingUser"; + public static final String EXTERNAL_ID = "externalId"; + public static final String RESPONSIBLE_REGION = "responsibleRegion"; + public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict"; + public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity"; + public static final String COUNTRY = "country"; + public static final String REPORTING_ID_NUMBER = "reportingIdNumber"; + public static final String PHONE_NUMBER = "phoneNumber"; + public static final String PREGNANT = "pregnant"; + public static final String TRIMESTER = "trimester"; + public static final String LACTATING = "lactating"; + public static final String ONSET_AGE_YEARS = "onsetAgeYears"; + public static final String ONSET_AGE_MONTHS = "onsetAgeMonths"; + public static final String ONSET_AGE_DAYS = "onsetAgeDays"; + public static final String AGE_GROUP = "ageGroup"; + public static final String HEALTH_FACILITY = "healthFacility"; + public static final String HEALTH_FACILITY_DETAILS = "healthFacilityDetails"; + public static final String REPORTING_OFFICER_NAME = "reportingOfficerName"; + public static final String REPORTING_OFFICER_FACILITY = "reportingOfficerFacility"; + public static final String REPORTING_OFFICER_DESIGNATION = "reportingOfficerDesignation"; + public static final String REPORTING_OFFICER_DEPARTMENT = "reportingOfficerDepartment"; + public static final String REPORTING_OFFICER_ADDRESS = "reportingOfficerAddress"; + public static final String REPORTING_OFFICER_PHONE_NUMBER = "reportingOfficerPhoneNumber"; + public static final String REPORTING_OFFICER_EMAIL = "reportingOfficerEmail"; + public static final String TODAYS_DATE = "todaysDate"; + public static final String START_DATE_TIME = "startDateTime"; + public static final String AEFI_DESCRIPTION = "aefiDescription"; + public static final String SERIOUS = "serious"; + public static final String SERIOUS_REASON = "seriousReason"; + public static final String SERIOUS_REASON_DETAILS = "seriousReasonDetails"; + public static final String OUTCOME = "outcome"; + public static final String DEATH_DATE = "deathDate"; + public static final String AUTOPSY_DONE = "autopsyDone"; + public static final String PAST_MEDICAL_HISTORY = "pastMedicalHistory"; + public static final String INVESTIGATION_NEEDED = "investigationNeeded"; + public static final String INVESTIGATION_PLANNED_DATE = "investigationPlannedDate"; + public static final String RECEIVED_AT_NATIONAL_LEVEL_DATE = "receivedAtNationalLevelDate"; + public static final String WORLD_WIDE_ID = "worldwideId"; + public static final String NATIONAL_LEVEL_COMMENT = "nationalLevelComment"; + public static final String DELETION_REASON = "deletionReason"; + public static final String OTHER_DELETION_REASON = "otherDeletionReason"; + + @NotNull(message = Validations.validImmunization) + private ImmunizationReferenceDto immunization; + private PersonReferenceDto person; + private LocationDto address; + @NotEmpty(message = Validations.aefiWithoutSuspectVaccines) + private List vaccinations = new ArrayList<>(); + @NotNull(message = Validations.aefiWithoutPrimarySuspectVaccine) + private VaccinationDto primarySuspectVaccine; + @NotNull(message = Validations.aefiWithoutAdverseEvents) + private AdverseEventsDto adverseEvents; + @NotNull(message = Validations.validReportDateTime) + private Date reportDate; + private UserReferenceDto reportingUser; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String externalId; + private RegionReferenceDto responsibleRegion; + private DistrictReferenceDto responsibleDistrict; + private CommunityReferenceDto responsibleCommunity; + private CountryReferenceDto country; + @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) + private String reportingIdNumber; + private String phoneNumber; + private YesNoUnknown pregnant; + private Trimester trimester; + private YesNoUnknown lactating; + private Integer onsetAgeYears; + private Integer onsetAgeMonths; + private Integer onsetAgeDays; + private AefiAgeGroup ageGroup; + private FacilityReferenceDto healthFacility; + @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) + private String healthFacilityDetails; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String reportingOfficerName; + private FacilityReferenceDto reportingOfficerFacility; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String reportingOfficerDesignation; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String reportingOfficerDepartment; + private LocationDto reportingOfficerAddress; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String reportingOfficerPhoneNumber; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String reportingOfficerEmail; + private Date todaysDate; + private Date startDateTime; + @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) + private String aefiDescription; + private YesNoUnknown serious; + private SeriousAefiReason seriousReason; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String seriousReasonDetails; + private AefiOutcome outcome; + private Date deathDate; + private YesNoUnknown autopsyDone; + @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) + private String pastMedicalHistory; + private YesNoUnknown investigationNeeded; + private Date investigationPlannedDate; + private Date receivedAtNationalLevelDate; + @Size(max = FieldConstraints.CHARACTER_LIMIT_SMALL, message = Validations.textTooLong) + private String worldwideId; + @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) + private String nationalLevelComment; + private boolean archived; + private boolean deleted; + private DeletionReason deletionReason; + @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) + private String otherDeletionReason; + + public static AefiDto build(UserReferenceDto user) { + + final AefiDto aefiDto = new AefiDto(); + aefiDto.setUuid(DataHelper.createUuid()); + aefiDto.setReportingUser(user); + aefiDto.setReportDate(new Date()); + aefiDto.setAdverseEvents(AdverseEventsDto.build()); + + return aefiDto; + } + + public static AefiDto build(ImmunizationReferenceDto immunization) { + + final AefiDto aefiDto = new AefiDto(); + aefiDto.setUuid(DataHelper.createUuid()); + aefiDto.setImmunization(immunization); + aefiDto.setReportDate(new Date()); + aefiDto.setAdverseEvents(AdverseEventsDto.build()); + + return aefiDto; + } + + public static AefiDto build(AefiReferenceDto aefiReferenceDto) { + + final AefiDto aefiDto = new AefiDto(); + aefiDto.setUuid(aefiReferenceDto.getUuid()); + aefiDto.setReportDate(new Date()); + aefiDto.setAdverseEvents(AdverseEventsDto.build()); + + return aefiDto; + } + + public AefiReferenceDto toReference() { + return new AefiReferenceDto(getUuid(), getExternalId()); + } + + public ImmunizationReferenceDto getImmunization() { + return immunization; + } + + public void setImmunization(ImmunizationReferenceDto immunization) { + this.immunization = immunization; + } + + public PersonReferenceDto getPerson() { + return person; + } + + public void setPerson(PersonReferenceDto person) { + this.person = person; + } + + public LocationDto getAddress() { + return address; + } + + public void setAddress(LocationDto address) { + this.address = address; + } + + public List getVaccinations() { + return vaccinations; + } + + public void setVaccinations(List vaccinations) { + this.vaccinations = vaccinations; + } + + public AdverseEventsDto getAdverseEvents() { + return adverseEvents; + } + + public VaccinationDto getPrimarySuspectVaccine() { + return primarySuspectVaccine; + } + + public void setPrimarySuspectVaccine(VaccinationDto primarySuspectVaccine) { + this.primarySuspectVaccine = primarySuspectVaccine; + } + + public void setAdverseEvents(AdverseEventsDto adverseEvents) { + this.adverseEvents = adverseEvents; + } + + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + public UserReferenceDto getReportingUser() { + return reportingUser; + } + + public void setReportingUser(UserReferenceDto reportingUser) { + this.reportingUser = reportingUser; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public RegionReferenceDto getResponsibleRegion() { + return responsibleRegion; + } + + public void setResponsibleRegion(RegionReferenceDto responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + public DistrictReferenceDto getResponsibleDistrict() { + return responsibleDistrict; + } + + public void setResponsibleDistrict(DistrictReferenceDto responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + public CommunityReferenceDto getResponsibleCommunity() { + return responsibleCommunity; + } + + public void setResponsibleCommunity(CommunityReferenceDto responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + public CountryReferenceDto getCountry() { + return country; + } + + public void setCountry(CountryReferenceDto country) { + this.country = country; + } + + public String getReportingIdNumber() { + return reportingIdNumber; + } + + public void setReportingIdNumber(String reportingIdNumber) { + this.reportingIdNumber = reportingIdNumber; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public YesNoUnknown getPregnant() { + return pregnant; + } + + public void setPregnant(YesNoUnknown pregnant) { + this.pregnant = pregnant; + } + + public Trimester getTrimester() { + return trimester; + } + + public void setTrimester(Trimester trimester) { + this.trimester = trimester; + } + + public YesNoUnknown getLactating() { + return lactating; + } + + public void setLactating(YesNoUnknown lactating) { + this.lactating = lactating; + } + + public Integer getOnsetAgeYears() { + return onsetAgeYears; + } + + public void setOnsetAgeYears(Integer onsetAgeYears) { + this.onsetAgeYears = onsetAgeYears; + } + + public Integer getOnsetAgeMonths() { + return onsetAgeMonths; + } + + public void setOnsetAgeMonths(Integer onsetAgeMonths) { + this.onsetAgeMonths = onsetAgeMonths; + } + + public Integer getOnsetAgeDays() { + return onsetAgeDays; + } + + public void setOnsetAgeDays(Integer onsetAgeDays) { + this.onsetAgeDays = onsetAgeDays; + } + + public AefiAgeGroup getAgeGroup() { + return ageGroup; + } + + public void setAgeGroup(AefiAgeGroup ageGroup) { + this.ageGroup = ageGroup; + } + + public FacilityReferenceDto getHealthFacility() { + return healthFacility; + } + + public void setHealthFacility(FacilityReferenceDto healthFacility) { + this.healthFacility = healthFacility; + } + + public String getHealthFacilityDetails() { + return healthFacilityDetails; + } + + public void setHealthFacilityDetails(String healthFacilityDetails) { + this.healthFacilityDetails = healthFacilityDetails; + } + + public String getReportingOfficerName() { + return reportingOfficerName; + } + + public void setReportingOfficerName(String reportingOfficerName) { + this.reportingOfficerName = reportingOfficerName; + } + + public FacilityReferenceDto getReportingOfficerFacility() { + return reportingOfficerFacility; + } + + public void setReportingOfficerFacility(FacilityReferenceDto reportingOfficerFacility) { + this.reportingOfficerFacility = reportingOfficerFacility; + } + + public String getReportingOfficerDesignation() { + return reportingOfficerDesignation; + } + + public void setReportingOfficerDesignation(String reportingOfficerDesignation) { + this.reportingOfficerDesignation = reportingOfficerDesignation; + } + + public String getReportingOfficerDepartment() { + return reportingOfficerDepartment; + } + + public void setReportingOfficerDepartment(String reportingOfficerDepartment) { + this.reportingOfficerDepartment = reportingOfficerDepartment; + } + + public LocationDto getReportingOfficerAddress() { + return reportingOfficerAddress; + } + + public void setReportingOfficerAddress(LocationDto reportingOfficerAddress) { + this.reportingOfficerAddress = reportingOfficerAddress; + } + + public String getReportingOfficerPhoneNumber() { + return reportingOfficerPhoneNumber; + } + + public void setReportingOfficerPhoneNumber(String reportingOfficerPhoneNumber) { + this.reportingOfficerPhoneNumber = reportingOfficerPhoneNumber; + } + + public String getReportingOfficerEmail() { + return reportingOfficerEmail; + } + + public void setReportingOfficerEmail(String reportingOfficerEmail) { + this.reportingOfficerEmail = reportingOfficerEmail; + } + + public Date getTodaysDate() { + return todaysDate; + } + + public void setTodaysDate(Date todaysDate) { + this.todaysDate = todaysDate; + } + + public Date getStartDateTime() { + return startDateTime; + } + + public void setStartDateTime(Date startDateTime) { + this.startDateTime = startDateTime; + } + + public String getAefiDescription() { + return aefiDescription; + } + + public void setAefiDescription(String aefiDescription) { + this.aefiDescription = aefiDescription; + } + + public YesNoUnknown getSerious() { + return serious; + } + + public void setSerious(YesNoUnknown serious) { + this.serious = serious; + } + + public SeriousAefiReason getSeriousReason() { + return seriousReason; + } + + public void setSeriousReason(SeriousAefiReason seriousReason) { + this.seriousReason = seriousReason; + } + + public String getSeriousReasonDetails() { + return seriousReasonDetails; + } + + public void setSeriousReasonDetails(String seriousReasonDetails) { + this.seriousReasonDetails = seriousReasonDetails; + } + + public AefiOutcome getOutcome() { + return outcome; + } + + public void setOutcome(AefiOutcome outcome) { + this.outcome = outcome; + } + + public Date getDeathDate() { + return deathDate; + } + + public void setDeathDate(Date deathDate) { + this.deathDate = deathDate; + } + + public YesNoUnknown getAutopsyDone() { + return autopsyDone; + } + + public void setAutopsyDone(YesNoUnknown autopsyDone) { + this.autopsyDone = autopsyDone; + } + + public String getPastMedicalHistory() { + return pastMedicalHistory; + } + + public void setPastMedicalHistory(String pastMedicalHistory) { + this.pastMedicalHistory = pastMedicalHistory; + } + + public YesNoUnknown getInvestigationNeeded() { + return investigationNeeded; + } + + public void setInvestigationNeeded(YesNoUnknown investigationNeeded) { + this.investigationNeeded = investigationNeeded; + } + + public Date getInvestigationPlannedDate() { + return investigationPlannedDate; + } + + public void setInvestigationPlannedDate(Date investigationPlannedDate) { + this.investigationPlannedDate = investigationPlannedDate; + } + + public Date getReceivedAtNationalLevelDate() { + return receivedAtNationalLevelDate; + } + + public void setReceivedAtNationalLevelDate(Date receivedAtNationalLevelDate) { + this.receivedAtNationalLevelDate = receivedAtNationalLevelDate; + } + + public String getWorldwideId() { + return worldwideId; + } + + public void setWorldwideId(String worldwideId) { + this.worldwideId = worldwideId; + } + + public String getNationalLevelComment() { + return nationalLevelComment; + } + + public void setNationalLevelComment(String nationalLevelComment) { + this.nationalLevelComment = nationalLevelComment; + } + + public boolean isArchived() { + return archived; + } + + public void setArchived(boolean archived) { + this.archived = archived; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public DeletionReason getDeletionReason() { + return deletionReason; + } + + public void setDeletionReason(DeletionReason deletionReason) { + this.deletionReason = deletionReason; + } + + public String getOtherDeletionReason() { + return otherDeletionReason; + } + + public void setOtherDeletionReason(String otherDeletionReason) { + this.otherDeletionReason = otherDeletionReason; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiExportDto.java new file mode 100644 index 00000000000..2c41a8827ac --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiExportDto.java @@ -0,0 +1,568 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; + +import de.symeda.sormas.api.caze.BirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.caze.VaccineManufacturer; +import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.Order; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableIndexDto; + +public class AefiExportDto extends PseudonymizableIndexDto implements Serializable { + + private static final long serialVersionUID = 4568112808032880384L; + + public static final String I18N_PREFIX = "AefiExport"; + + public static final String RECEIVED_AT_NATIONAL_LEVEL_DATE = "receivedAtNationalLevelDate"; + public static final String VACCINATION_FACILITY_NAME = "vaccinationFacilityName"; + public static final String VACCINATION_FACILITY_REGION = "vaccinationFacilityRegion"; + public static final String VACCINATION_FACILITY_DISTRICT = "vaccinationFacilityDistrict"; + public static final String VACCINATION_FACILITY_COMMUNITY = "vaccinationFacilityCommunity"; + public static final String REPORTING_OFFICER_ADDRESS_COUNTRY_NAME = "reportingOfficerAddressCountryName"; + public static final String PATIENT_ADDRESS_REGION = "patientAddressRegion"; + public static final String PATIENT_ADDRESS_DISTRICT = "patientAddressDistrict"; + public static final String PATIENT_ADDRESS_COMMUNITY = "patientAddressCommunity"; + public static final String PATIENT_ADDRESS_DETAILS = "patientAddressDetails"; + public static final String REPORTING_ID_NUMBER = "reportingIdNumber"; + public static final String WORLDWIDE_ID = "worldWideId"; + public static final String FIRST_NAME = "firstName"; + public static final String LAST_NAME = "lastName"; + public static final String BIRTH_DATE = "birthDate"; + public static final String ONSET_AGE_YEARS = "onsetAgeYears"; + public static final String ONSET_AGE_MONTHS = "onsetAgeMonths"; + public static final String ONSET_AGE_DAYS = "onsetAgeDays"; + public static final String ONSET_AGE_GROUP = "onsetAgeGroup"; + public static final String SEX = "sex"; + public static final String AEFI_DESCRIPTION = "aefiDescription"; + public static final String PRIMARY_SUSPECT_VACCINE_NAME = "primarySuspectVaccineName"; + public static final String PRIMARY_SUSPECT_VACCINE_OTHER_NAME = "primarySuspectVaccineOtherName"; + public static final String PRIMARY_SUSPECT_VACCINE_BRAND = "primarySuspectVaccineBrand"; + public static final String PRIMARY_SUSPECT_VACCINE_MANUFACTURER = "primarySuspectVaccineManufacturer"; + public static final String PRIMARY_SUSPECT_VACCINE_BATCH_NUMBER = "primarySuspectVaccineBatchNumber"; + public static final String PRIMARY_SUSPECT_VACCINE_DOSE = "primarySuspectVaccineDose"; + public static final String PRIMARY_SUSPECT_VACCINE_DILUENT_BATCH_NUMBER = "primarySuspectVaccineDiluentBatchNumber"; + public static final String PRIMARY_SUSPECT_VACCINE_VACCINATION_DATE = "primarySuspectVaccineVaccinationDate"; + public static final String START_DATE_TIME = "startDateTime"; + public static final String SEVERE_LOCAL_REACTION = "severeLocalReaction"; + public static final String SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS = "severeLocalReactionMoreThanThreeDays"; + public static final String SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT = "severeLocalReactionBeyondNearestJoint"; + public static final String SEIZURES = "seizures"; + public static final String SEIZURE_TYPE = "seizureType"; + public static final String ABSCESS = "abscess"; + public static final String SEPSIS = "sepsis"; + public static final String ENCEPHALOPATHY = "encephalopathy"; + public static final String TOXIC_SHOCK_SYNDROME = "toxicShockSyndrome"; + public static final String THROMBOCYTOPENIA = "thrombocytopenia"; + public static final String ANAPHYLAXIS = "anaphylaxis"; + public static final String FEVERISH_FEELING = "feverishFeeling"; + public static final String OTHER_ADVERSE_EVENT_DETAILS = "otherAdverseEventDetails"; + public static final String OUTCOME = "outcome"; + public static final String SERIOUS = "serious"; + public static final String REPORTING_OFFICER_NAME = "reportingOfficerName"; + public static final String REPORTING_OFFICER_FACILITY_NAME = "reportingOfficerFacilityName"; + public static final String REPORTING_OFFICER_FACILITY_REGION = "reportingOfficerFacilityRegion"; + public static final String REPORTING_OFFICER_FACILITY_DISTRICT = "reportingOfficerFacilityDistrict"; + public static final String REPORTING_OFFICER_FACILITY_COMMUNITY = "reportingOfficerFacilityCommunity"; + public static final String REPORTING_OFFICER_DESIGNATION = "reportingOfficerDesignation"; + public static final String REPORTING_OFFICER_DEPARTMENT = "reportingOfficerDepartment"; + public static final String REPORTING_OFFICER_EMAIL = "reportingOfficerEmail"; + public static final String REPORTING_OFFICER_PHONE_NUMBER = "reportingOfficerPhoneNumber"; + public static final String REPORT_DATE = "reportDate"; + public static final String NATIONAL_LEVEL_COMMENT = "nationalLevelComment"; + + private Date receivedAtNationalLevelDate; + private String vaccinationFacilityName; + private String vaccinationFacilityRegion; + private String vaccinationFacilityDistrict; + private String vaccinationFacilityCommunity; + private String reportingOfficerAddressCountryName; + private String patientAddressRegion; + private String patientAddressDistrict; + private String patientAddressCommunity; + private String patientAddressDetails; + private String reportingIdNumber; + private String worldWideId; + private String firstName; + private String lastName; + private BirthDateDto birthDate; + private Integer onsetAgeYears; + private Integer onsetAgeMonths; + private Integer onsetAgeDays; + private AefiAgeGroup onsetAgeGroup; + private Sex sex; + private String aefiDescription; + private Vaccine primarySuspectVaccineName; + private String primarySuspectVaccineOtherName; + private String primarySuspectVaccineBrandName; + private VaccineManufacturer primarySuspectVaccineManufacturer; + private String primarySuspectVaccineBatchNumber; + private String primarySuspectVaccineDose; + private String primarySuspectVaccineDiluentBatchNumber; + private Date primarySuspectVaccineVaccinationDate; + private Date startDateTime; + private AdverseEventState severeLocalReaction; + private boolean severeLocalReactionMoreThanThreeDays; + private boolean severeLocalReactionBeyondNearestJoint; + private AdverseEventState seizures; + private SeizureType seizureType; + private AdverseEventState abscess; + private AdverseEventState sepsis; + private AdverseEventState encephalopathy; + private AdverseEventState toxicShockSyndrome; + private AdverseEventState thrombocytopenia; + private AdverseEventState anaphylaxis; + private AdverseEventState feverishFeeling; + private String otherAdverseEventDetails; + private AefiOutcome outcome; + private YesNoUnknown serious; + private String reportingOfficerName; + private String reportingOfficerFacilityName; + private String reportingOfficerFacilityRegion; + private String reportingOfficerFacilityDistrict; + private String reportingOfficerFacilityCommunity; + private String reportingOfficerDesignation; + private String reportingOfficerDepartment; + private String reportingOfficerEmail; + private String reportingOfficerPhoneNumber; + private Date reportDate; + private String nationalLevelComment; + private Boolean isInJurisdiction; + + public AefiExportDto( + String uuid, + Date receivedAtNationalLevelDate, + String vaccinationFacilityName, + String vaccinationFacilityRegion, + String vaccinationFacilityDistrict, + String vaccinationFacilityCommunity, + String reportingOfficerAddressCountryName, + String patientAddressRegion, + String patientAddressDistrict, + String patientAddressCommunity, + String street, + String houseNumber, + String postalCode, + String city, + String reportingIdNumber, + String worldWideId, + String firstName, + String lastName, + Integer birthdateDD, + Integer birthdateMM, + Integer birthdateYYYY, + Integer onsetAgeYears, + Integer onsetAgeMonths, + Integer onsetAgeDays, + AefiAgeGroup onsetAgeGroup, + Sex sex, + String aefiDescription, + Vaccine primarySuspectVaccineName, + String primarySuspectVaccineOtherName, + VaccineManufacturer primarySuspectVaccineManufacturer, + String primarySuspectVaccineBatchNumber, + String primarySuspectVaccineDose, + Date primarySuspectVaccineVaccinationDate, + Date startDateTime, + AdverseEventState severeLocalReaction, + boolean severeLocalReactionMoreThanThreeDays, + boolean severeLocalReactionBeyondNearestJoint, + AdverseEventState seizures, + SeizureType seizureType, + AdverseEventState abscess, + AdverseEventState sepsis, + AdverseEventState encephalopathy, + AdverseEventState toxicShockSyndrome, + AdverseEventState thrombocytopenia, + AdverseEventState anaphylaxis, + AdverseEventState feverishFeeling, + String otherAdverseEventDetails, + AefiOutcome outcome, + YesNoUnknown serious, + String reportingOfficerFirstName, + String reportingOfficerLastName, + String reportingOfficerFacilityName, + String reportingOfficerFacilityRegion, + String reportingOfficerFacilityDistrict, + String reportingOfficerFacilityCommunity, + String reportingOfficerEmail, + String reportingOfficerPhoneNumber, + Date reportDate, + String nationalLevelComment, + boolean isInJurisdiction) { + super(uuid); + this.receivedAtNationalLevelDate = receivedAtNationalLevelDate; + this.vaccinationFacilityName = vaccinationFacilityName; + this.vaccinationFacilityRegion = vaccinationFacilityRegion; + this.vaccinationFacilityDistrict = vaccinationFacilityDistrict; + this.vaccinationFacilityCommunity = vaccinationFacilityCommunity; + this.reportingOfficerAddressCountryName = reportingOfficerAddressCountryName; + this.patientAddressRegion = patientAddressRegion; + this.patientAddressDistrict = patientAddressDistrict; + this.patientAddressCommunity = patientAddressCommunity; + + StringBuilder patientAddressBuilder = new StringBuilder(); + if (!StringUtils.isBlank(houseNumber)) { + patientAddressBuilder.append(houseNumber); + } + if (!StringUtils.isBlank(street)) { + patientAddressBuilder.append(", ").append(street); + } + if (!StringUtils.isBlank(postalCode)) { + patientAddressBuilder.append(", ").append(postalCode); + } + if (!StringUtils.isBlank(city)) { + patientAddressBuilder.append(", ").append(city); + } + + this.patientAddressDetails = patientAddressBuilder.toString(); + + this.reportingIdNumber = reportingIdNumber; + this.worldWideId = worldWideId; + this.firstName = firstName; + this.lastName = lastName; + this.birthDate = new BirthDateDto(birthdateDD, birthdateMM, birthdateYYYY); + this.onsetAgeYears = onsetAgeYears; + this.onsetAgeMonths = onsetAgeMonths; + this.onsetAgeDays = onsetAgeDays; + this.onsetAgeGroup = onsetAgeGroup; + this.sex = sex; + this.aefiDescription = aefiDescription; + this.primarySuspectVaccineName = primarySuspectVaccineName; + this.primarySuspectVaccineOtherName = primarySuspectVaccineOtherName; + this.primarySuspectVaccineManufacturer = primarySuspectVaccineManufacturer; + this.primarySuspectVaccineBatchNumber = primarySuspectVaccineBatchNumber; + this.primarySuspectVaccineDose = primarySuspectVaccineDose; + this.primarySuspectVaccineVaccinationDate = primarySuspectVaccineVaccinationDate; + this.startDateTime = startDateTime; + this.severeLocalReaction = severeLocalReaction; + this.severeLocalReactionMoreThanThreeDays = severeLocalReactionMoreThanThreeDays; + this.severeLocalReactionBeyondNearestJoint = severeLocalReactionBeyondNearestJoint; + this.seizures = seizures; + this.seizureType = seizureType; + this.abscess = abscess; + this.sepsis = sepsis; + this.encephalopathy = encephalopathy; + this.toxicShockSyndrome = toxicShockSyndrome; + this.thrombocytopenia = thrombocytopenia; + this.anaphylaxis = anaphylaxis; + this.feverishFeeling = feverishFeeling; + this.otherAdverseEventDetails = otherAdverseEventDetails; + this.outcome = outcome; + this.serious = serious; + this.reportingOfficerName = reportingOfficerFirstName + " " + reportingOfficerLastName; + this.reportingOfficerFacilityName = reportingOfficerFacilityName; + this.reportingOfficerFacilityRegion = reportingOfficerFacilityRegion; + this.reportingOfficerFacilityDistrict = reportingOfficerFacilityDistrict; + this.reportingOfficerFacilityCommunity = reportingOfficerFacilityCommunity; + this.reportingOfficerEmail = reportingOfficerEmail; + this.reportingOfficerPhoneNumber = reportingOfficerPhoneNumber; + this.reportDate = reportDate; + this.nationalLevelComment = nationalLevelComment; + this.isInJurisdiction = isInJurisdiction; + } + + @Order(0) + public Date getReceivedAtNationalLevelDate() { + return receivedAtNationalLevelDate; + } + + @Order(1) + public String getVaccinationFacilityName() { + return vaccinationFacilityName; + } + + @Order(2) + public String getVaccinationFacilityRegion() { + return vaccinationFacilityRegion; + } + + @Order(3) + public String getVaccinationFacilityDistrict() { + return vaccinationFacilityDistrict; + } + + @Order(4) + public String getVaccinationFacilityCommunity() { + return vaccinationFacilityCommunity; + } + + @Order(5) + public String getReportingOfficerAddressCountryName() { + return reportingOfficerAddressCountryName; + } + + @Order(6) + public String getPatientAddressRegion() { + return patientAddressRegion; + } + + @Order(7) + public String getPatientAddressDistrict() { + return patientAddressDistrict; + } + + @Order(8) + public String getPatientAddressCommunity() { + return patientAddressCommunity; + } + + @Order(9) + public String getPatientAddressDetails() { + return patientAddressDetails; + } + + @Order(10) + public String getReportingIdNumber() { + return reportingIdNumber; + } + + @Order(11) + public String getWorldWideId() { + return worldWideId; + } + + @Order(12) + public String getFirstName() { + return firstName; + } + + @Order(13) + public String getLastName() { + return lastName; + } + + @Order(14) + public BirthDateDto getBirthDate() { + return birthDate; + } + + @Order(15) + public Integer getOnsetAgeYears() { + return onsetAgeYears; + } + + @Order(16) + public Integer getOnsetAgeMonths() { + return onsetAgeMonths; + } + + @Order(17) + public Integer getOnsetAgeDays() { + return onsetAgeDays; + } + + @Order(18) + public AefiAgeGroup getOnsetAgeGroup() { + return onsetAgeGroup; + } + + @Order(19) + public Sex getSex() { + return sex; + } + + @Order(20) + public String getAefiDescription() { + return aefiDescription; + } + + @Order(21) + public Vaccine getPrimarySuspectVaccineName() { + return primarySuspectVaccineName; + } + + @Order(22) + public String getPrimarySuspectVaccineOtherName() { + return primarySuspectVaccineOtherName; + } + + @Order(23) + public String getPrimarySuspectVaccineBrandName() { + return primarySuspectVaccineBrandName; + } + + @Order(24) + public VaccineManufacturer getPrimarySuspectVaccineManufacturer() { + return primarySuspectVaccineManufacturer; + } + + @Order(25) + public String getPrimarySuspectVaccineBatchNumber() { + return primarySuspectVaccineBatchNumber; + } + + @Order(26) + public String getPrimarySuspectVaccineDose() { + return primarySuspectVaccineDose; + } + + @Order(27) + public String getPrimarySuspectVaccineDiluentBatchNumber() { + return primarySuspectVaccineDiluentBatchNumber; + } + + @Order(28) + public Date getPrimarySuspectVaccineVaccinationDate() { + return primarySuspectVaccineVaccinationDate; + } + + @Order(29) + public Date getStartDateTime() { + return startDateTime; + } + + @Order(30) + public AdverseEventState getSevereLocalReaction() { + return severeLocalReaction; + } + + @Order(31) + public boolean isSevereLocalReactionMoreThanThreeDays() { + return severeLocalReactionMoreThanThreeDays; + } + + @Order(32) + public boolean isSevereLocalReactionBeyondNearestJoint() { + return severeLocalReactionBeyondNearestJoint; + } + + @Order(33) + public AdverseEventState getSeizures() { + return seizures; + } + + @Order(34) + public SeizureType getSeizureType() { + return seizureType; + } + + @Order(35) + public AdverseEventState getAbscess() { + return abscess; + } + + @Order(36) + public AdverseEventState getSepsis() { + return sepsis; + } + + @Order(37) + public AdverseEventState getEncephalopathy() { + return encephalopathy; + } + + @Order(38) + public AdverseEventState getToxicShockSyndrome() { + return toxicShockSyndrome; + } + + @Order(39) + public AdverseEventState getThrombocytopenia() { + return thrombocytopenia; + } + + @Order(40) + public AdverseEventState getAnaphylaxis() { + return anaphylaxis; + } + + @Order(41) + public AdverseEventState getFeverishFeeling() { + return feverishFeeling; + } + + @Order(42) + public String getOtherAdverseEventDetails() { + return otherAdverseEventDetails; + } + + @Order(43) + public AefiOutcome getOutcome() { + return outcome; + } + + @Order(44) + public YesNoUnknown getSerious() { + return serious; + } + + @Order(45) + public String getReportingOfficerName() { + return reportingOfficerName; + } + + @Order(46) + public String getReportingOfficerFacilityName() { + return reportingOfficerFacilityName; + } + + @Order(47) + public String getReportingOfficerFacilityRegion() { + return reportingOfficerFacilityRegion; + } + + @Order(48) + public String getReportingOfficerFacilityDistrict() { + return reportingOfficerFacilityDistrict; + } + + @Order(49) + public String getReportingOfficerFacilityCommunity() { + return reportingOfficerFacilityCommunity; + } + + @Order(50) + public String getReportingOfficerDesignation() { + return reportingOfficerDesignation; + } + + @Order(51) + public String getReportingOfficerDepartment() { + return reportingOfficerDepartment; + } + + @Order(52) + public String getReportingOfficerEmail() { + return reportingOfficerEmail; + } + + @Order(53) + public String getReportingOfficerPhoneNumber() { + return reportingOfficerPhoneNumber; + } + + @Order(54) + public Date getReportDate() { + return reportDate; + } + + @Order(55) + public String getNationalLevelComment() { + return nationalLevelComment; + } + + public Boolean getInJurisdiction() { + return isInJurisdiction; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiFacade.java new file mode 100644 index 00000000000..a7ed73ac4bb --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiFacade.java @@ -0,0 +1,31 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.util.Collection; +import java.util.List; + +import javax.ejb.Remote; + +import de.symeda.sormas.api.CoreFacade; + +@Remote +public interface AefiFacade extends CoreFacade { + + List getEntriesList(AefiListCriteria criteria, Integer first, Integer max); + + List getExportList(AefiCriteria criteria, Collection selectedRows, int first, int max); +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiHelper.java new file mode 100644 index 00000000000..2d4d2b80395 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiHelper.java @@ -0,0 +1,127 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.util.ArrayList; +import java.util.List; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public final class AefiHelper { + + private AefiHelper() { + + } + + public static String buildAdverseEventsString(AdverseEventsDto adverseEventsDto) { + + List adverseEventsList = new ArrayList<>(); + + if (adverseEventsDto.getSevereLocalReaction() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEVERE_LOCAL_REACTION)); + } + + if (adverseEventsDto.getSeizures() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEIZURES)); + } + + if (adverseEventsDto.getAbscess() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ABSCESS)); + } + + if (adverseEventsDto.getSepsis() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEPSIS)); + } + + if (adverseEventsDto.getEncephalopathy() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ENCEPHALOPATHY)); + } + + if (adverseEventsDto.getToxicShockSyndrome() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.TOXIC_SHOCK_SYNDROME)); + } + + if (adverseEventsDto.getThrombocytopenia() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.THROMBOCYTOPENIA)); + } + + if (adverseEventsDto.getAnaphylaxis() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ANAPHYLAXIS)); + } + + if (adverseEventsDto.getFeverishFeeling() == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.FEVERISH_FEELING)); + } + + return String.join(", ", adverseEventsList); + } + + public static String buildAdverseEventsString( + AdverseEventState severeLocalReaction, + boolean severeLocalReactionMoreThanThreeDays, + boolean severeLocalReactionBeyondNearestJoint, + AdverseEventState seizures, + SeizureType seizureType, + AdverseEventState abscess, + AdverseEventState sepsis, + AdverseEventState encephalopathy, + AdverseEventState toxicShockSyndrome, + AdverseEventState thrombocytopenia, + AdverseEventState anaphylaxis, + AdverseEventState feverishFeeling, + String otherAdverseEventDetails) { + + List adverseEventsList = new ArrayList<>(); + + if (severeLocalReaction == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEVERE_LOCAL_REACTION)); + } + + if (seizures == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEIZURES)); + } + + if (abscess == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ABSCESS)); + } + + if (sepsis == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.SEPSIS)); + } + + if (encephalopathy == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ENCEPHALOPATHY)); + } + + if (toxicShockSyndrome == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.TOXIC_SHOCK_SYNDROME)); + } + + if (thrombocytopenia == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.THROMBOCYTOPENIA)); + } + + if (anaphylaxis == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.ANAPHYLAXIS)); + } + + if (feverishFeeling == AdverseEventState.YES) { + adverseEventsList.add(I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, AdverseEventsDto.FEVERISH_FEELING)); + } + + return String.join(", ", adverseEventsList); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiImmunizationPeriod.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiImmunizationPeriod.java new file mode 100644 index 00000000000..e8e943fe41d --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiImmunizationPeriod.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiImmunizationPeriod { + + WITHIN_FIRST_VACCINATIONS, + WITHIN_LAST_VACCINATIONS, + UNKNOWN; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiIndexDto.java new file mode 100644 index 00000000000..ad982aeff95 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiIndexDto.java @@ -0,0 +1,287 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.PersonalData; +import de.symeda.sormas.api.utils.SensitiveData; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableIndexDto; + +public class AefiIndexDto extends PseudonymizableIndexDto implements Serializable, Cloneable { + + private static final long serialVersionUID = 2873180122463056859L; + + public static final String I18N_PREFIX = "AefiIndex"; + + public static final String UUID = "uuid"; + public static final String IMMUNIZATION_UUID = "immunizationUuid"; + public static final String PERSON_UUID = "personUuid"; + public static final String PERSON_FIRST_NAME = "personFirstName"; + public static final String PERSON_LAST_NAME = "personLastName"; + public static final String REPORT_DATE = "reportDate"; + public static final String DISEASE = "disease"; + public static final String AGE_AND_BIRTH_DATE = "ageAndBirthDate"; + public static final String SEX = "sex"; + public static final String REGION = "region"; + public static final String DISTRICT = "district"; + public static final String SERIOUS = "serious"; + public static final String PRIMARY_VACCINE_NAME = "primaryVaccine"; + public static final String OUTCOME = "outcome"; + public static final String VACCINATION_DATE = "vaccinationDate"; + public static final String START_DATE_TIME = "startDateTime"; + public static final String ADVERSE_EVENTS = "adverseEvents"; + + private String immunizationUuid; + private String personUuid; + @PersonalData + @SensitiveData + private String personFirstName; + @PersonalData + @SensitiveData + private String personLastName; + private Date reportDate; + private Disease disease; + private AgeAndBirthDateDto ageAndBirthDate; + private Sex sex; + private String region; + private String district; + private YesNoUnknown serious; + private Vaccine primaryVaccine; + private String primaryVaccineDetails; + private AefiOutcome outcome; + private Date vaccinationDate; + private Date startDateTime; + private String adverseEvents; + private DeletionReason deletionReason; + private String otherDeletionReason; + private boolean isInJurisdiction; + + public AefiIndexDto( + String uuid, + String immunizationUuid, + String personUuid, + String personFirstName, + String personLastName, + Disease disease, + AgeAndBirthDateDto ageAndBirthDate, + Sex sex, + String region, + String district, + YesNoUnknown serious, + Vaccine primaryVaccine, + String primaryVaccineDetails, + AefiOutcome outcome, + Date vaccinationDate, + Date reportDate, + Date startDateTime, + String adverseEvents, + DeletionReason deletionReason, + String otherDeletionReason, + boolean isInJurisdiction) { + + super(uuid); + this.immunizationUuid = immunizationUuid; + this.personUuid = personUuid; + this.personFirstName = personFirstName; + this.personLastName = personLastName; + this.disease = disease; + this.ageAndBirthDate = ageAndBirthDate; + this.sex = sex; + this.region = region; + this.district = district; + this.serious = serious; + this.primaryVaccine = primaryVaccine; + this.primaryVaccineDetails = primaryVaccineDetails; + this.outcome = outcome; + this.vaccinationDate = vaccinationDate; + this.reportDate = reportDate; + this.startDateTime = startDateTime; + this.adverseEvents = adverseEvents; + this.deletionReason = deletionReason; + this.otherDeletionReason = otherDeletionReason; + this.isInJurisdiction = isInJurisdiction; + } + + public String getImmunizationUuid() { + return immunizationUuid; + } + + public void setImmunizationUuid(String immunizationUuid) { + this.immunizationUuid = immunizationUuid; + } + + public String getPersonUuid() { + return personUuid; + } + + public void setPersonUuid(String personUuid) { + this.personUuid = personUuid; + } + + public String getPersonFirstName() { + return personFirstName; + } + + public void setPersonFirstName(String personFirstName) { + this.personFirstName = personFirstName; + } + + public String getPersonLastName() { + return personLastName; + } + + public void setPersonLastName(String personLastName) { + this.personLastName = personLastName; + } + + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + public AgeAndBirthDateDto getAgeAndBirthDate() { + return ageAndBirthDate; + } + + public void setAgeAndBirthDate(AgeAndBirthDateDto ageAndBirthDate) { + this.ageAndBirthDate = ageAndBirthDate; + } + + public Sex getSex() { + return sex; + } + + public void setSex(Sex sex) { + this.sex = sex; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } + + public YesNoUnknown getSerious() { + return serious; + } + + public void setSerious(YesNoUnknown serious) { + this.serious = serious; + } + + public Vaccine getPrimaryVaccine() { + return primaryVaccine; + } + + public void setPrimaryVaccine(Vaccine primaryVaccine) { + this.primaryVaccine = primaryVaccine; + } + + public String getPrimaryVaccineDetails() { + return primaryVaccineDetails; + } + + public void setPrimaryVaccineDetails(String primaryVaccineDetails) { + this.primaryVaccineDetails = primaryVaccineDetails; + } + + public AefiOutcome getOutcome() { + return outcome; + } + + public void setOutcome(AefiOutcome outcome) { + this.outcome = outcome; + } + + public Date getVaccinationDate() { + return vaccinationDate; + } + + public void setVaccinationDate(Date vaccinationDate) { + this.vaccinationDate = vaccinationDate; + } + + public Date getStartDateTime() { + return startDateTime; + } + + public void setStartDateTime(Date startDateTime) { + this.startDateTime = startDateTime; + } + + public String getAdverseEvents() { + return adverseEvents; + } + + public void setAdverseEvents(String adverseEvents) { + this.adverseEvents = adverseEvents; + } + + public DeletionReason getDeletionReason() { + return deletionReason; + } + + public void setDeletionReason(DeletionReason deletionReason) { + this.deletionReason = deletionReason; + } + + public String getOtherDeletionReason() { + return otherDeletionReason; + } + + public void setOtherDeletionReason(String otherDeletionReason) { + this.otherDeletionReason = otherDeletionReason; + } + + @Override + public boolean isInJurisdiction() { + return isInJurisdiction; + } + + @Override + public void setInJurisdiction(boolean inJurisdiction) { + isInJurisdiction = inJurisdiction; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationCriteria.java new file mode 100644 index 00000000000..f54efee9f85 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationCriteria.java @@ -0,0 +1,240 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.caze.VaccineManufacturer; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityType; +import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.utils.DateFilterOption; +import de.symeda.sormas.api.utils.criteria.BaseCriteria; + +public class AefiInvestigationCriteria extends BaseCriteria implements Serializable { + + private static final long serialVersionUID = 6520144798481981253L; + + public static final String I18N_PREFIX = "AefiInvestigationCriteria"; + public static final String AEFI_REPORT_LIKE = "aefiReportLike"; + public static final String INVESTIGATION_CASE_ID = "investigationCaseId"; + public static final String DISEASE = "disease"; + public static final String PERSON_LIKE = "personLike"; + public static final String AEFI_TYPE = "aefiType"; + public static final String VACCINE_NAME = "vaccineName"; + public static final String VACCINE_MANUFACTURER = "vaccineManufacturer"; + public static final String REGION = "region"; + public static final String DISTRICT = "district"; + public static final String COMMUNITY = "community"; + public static final String STATUS_ON_DATE_OF_INVESTIGATION = "statusAtAefiInvestigation"; + public static final String AEFI_CLASSIFICATION = "aefiClassification"; + public static final String FACILITY_TYPE_GROUP = "facilityTypeGroup"; + public static final String FACILITY_TYPE = "facilityType"; + public static final String HEALTH_FACILITY = "healthFacility"; + public static final String DATE_FILTER_OPTION = "dateFilterOption"; + public static final String AEFI_DATE_TYPE = "aefiDateType"; + public static final String FROM_DATE = "fromDate"; + public static final String TO_DATE = "toDate"; + public static final String RELEVANCE_STATUS = "relevanceStatus"; + + private String aefiReportLike; + private String investigationCaseId; + private Disease disease; + private String personLike; + private AefiType aefiType; + private Vaccine vaccineName; + private VaccineManufacturer vaccineManufacturer; + private RegionReferenceDto region; + private DistrictReferenceDto district; + private CommunityReferenceDto community; + private PatientStatusAtAefiInvestigation statusAtAefiInvestigation; + private AefiClassification aefiClassification; + private FacilityTypeGroup facilityTypeGroup; + private FacilityType facilityType; + private FacilityReferenceDto healthFacility; + private DateFilterOption dateFilterOption = DateFilterOption.DATE; + private AefiInvestigationDateType aefiInvestigationDateType; + private Date fromDate; + private Date toDate; + private EntityRelevanceStatus relevanceStatus; + + public String getAefiReportLike() { + return aefiReportLike; + } + + public void setAefiReportLike(String aefiReportLike) { + this.aefiReportLike = aefiReportLike; + } + + public String getInvestigationCaseId() { + return investigationCaseId; + } + + public void setInvestigationCaseId(String investigationCaseId) { + this.investigationCaseId = investigationCaseId; + } + + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + public String getPersonLike() { + return personLike; + } + + public void setPersonLike(String personLike) { + this.personLike = personLike; + } + + public AefiType getAefiType() { + return aefiType; + } + + public void setAefiType(AefiType aefiType) { + this.aefiType = aefiType; + } + + public Vaccine getVaccineName() { + return vaccineName; + } + + public void setVaccineName(Vaccine vaccineName) { + this.vaccineName = vaccineName; + } + + public VaccineManufacturer getVaccineManufacturer() { + return vaccineManufacturer; + } + + public void setVaccineManufacturer(VaccineManufacturer vaccineManufacturer) { + this.vaccineManufacturer = vaccineManufacturer; + } + + public RegionReferenceDto getRegion() { + return region; + } + + public void setRegion(RegionReferenceDto region) { + this.region = region; + } + + public DistrictReferenceDto getDistrict() { + return district; + } + + public void setDistrict(DistrictReferenceDto district) { + this.district = district; + } + + public CommunityReferenceDto getCommunity() { + return community; + } + + public void setCommunity(CommunityReferenceDto community) { + this.community = community; + } + + public PatientStatusAtAefiInvestigation getStatusAtAefiInvestigation() { + return statusAtAefiInvestigation; + } + + public void setStatusAtAefiInvestigation(PatientStatusAtAefiInvestigation statusAtAefiInvestigation) { + this.statusAtAefiInvestigation = statusAtAefiInvestigation; + } + + public AefiClassification getAefiClassification() { + return aefiClassification; + } + + public void setAefiClassification(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } + + public FacilityTypeGroup getFacilityTypeGroup() { + return facilityTypeGroup; + } + + public void setFacilityTypeGroup(FacilityTypeGroup facilityTypeGroup) { + this.facilityTypeGroup = facilityTypeGroup; + } + + public FacilityType getFacilityType() { + return facilityType; + } + + public void setFacilityType(FacilityType facilityType) { + this.facilityType = facilityType; + } + + public FacilityReferenceDto getHealthFacility() { + return healthFacility; + } + + public void setHealthFacility(FacilityReferenceDto healthFacility) { + this.healthFacility = healthFacility; + } + + public DateFilterOption getDateFilterOption() { + return dateFilterOption; + } + + public void setDateFilterOption(DateFilterOption dateFilterOption) { + this.dateFilterOption = dateFilterOption; + } + + public AefiInvestigationDateType getAefiInvestigationDateType() { + return aefiInvestigationDateType; + } + + public void setAefiInvestigationDateType(AefiInvestigationDateType aefiInvestigationDateType) { + this.aefiInvestigationDateType = aefiInvestigationDateType; + } + + public Date getFromDate() { + return fromDate; + } + + public void setFromDate(Date fromDate) { + this.fromDate = fromDate; + } + + public Date getToDate() { + return toDate; + } + + public void setToDate(Date toDate) { + this.toDate = toDate; + } + + public EntityRelevanceStatus getRelevanceStatus() { + return relevanceStatus; + } + + public void setRelevanceStatus(EntityRelevanceStatus relevanceStatus) { + this.relevanceStatus = relevanceStatus; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDateType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDateType.java new file mode 100644 index 00000000000..7d1fb23e605 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDateType.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiInvestigationDateType { + + REPORT_DATE, + INVESTIGATION_DATE, + VACCINATION_DATE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDto.java new file mode 100644 index 00000000000..29e8ddd4cb4 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationDto.java @@ -0,0 +1,1684 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.country.CountryReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.location.LocationDto; +import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.DependingOnFeatureType; +import de.symeda.sormas.api.utils.FieldConstraints; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableDto; +import de.symeda.sormas.api.vaccination.VaccinationDto; + +@DependingOnFeatureType(featureType = { + FeatureType.IMMUNIZATION_MANAGEMENT, + FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT }) +public class AefiInvestigationDto extends PseudonymizableDto { + + private static final long serialVersionUID = 7811960334585576774L; + + public static final long APPROXIMATE_JSON_SIZE_IN_BYTES = 25455; + + public static final String I18N_PREFIX = "AefiInvestigation"; + + public static final String AEFI_REPORT = "aefiReport"; + public static final String ADDRESS = "address"; + public static final String VACCINATIONS = "vaccinations"; + public static final String PRIMARY_SUSPECT_VACCINE = "primarySuspectVaccine"; + public static final String REPORT_DATE = "reportDate"; + public static final String REPORTING_USER = "reportingUser"; + public static final String EXTERNAL_ID = "externalId"; + public static final String RESPONSIBLE_REGION = "responsibleRegion"; + public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict"; + public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity"; + public static final String COUNTRY = "country"; + public static final String INVESTIGATION_CASE_ID = "investigationCaseId"; + public static final String PLACE_OF_VACCINATION = "placeOfVaccination"; + public static final String PLACE_OF_VACCINATION_DETAILS = "placeOfVaccinationDetails"; + public static final String VACCINATION_ACTIVITY = "vaccinationActivity"; + public static final String VACCINATION_ACTIVITY_DETAILS = "vaccinationActivityDetails"; + public static final String VACCINATION_FACILITY = "vaccinationFacility"; + public static final String VACCINATION_FACILITY_DETAILS = "vaccinationFacilityDetails"; + public static final String REPORTING_OFFICER_NAME = "reportingOfficerName"; + public static final String REPORTING_OFFICER_FACILITY = "reportingOfficerFacility"; + public static final String REPORTING_OFFICER_FACILITY_DETAILS = "reportingOfficerFacilityDetails"; + public static final String REPORTING_OFFICER_DESIGNATION = "reportingOfficerDesignation"; + public static final String REPORTING_OFFICER_DEPARTMENT = "reportingOfficerDepartment"; + public static final String REPORTING_OFFICER_ADDRESS = "reportingOfficerAddress"; + public static final String REPORTING_OFFICER_LANDLINE_PHONE_NUMBER = "reportingOfficerLandlinePhoneNumber"; + public static final String REPORTING_OFFICER_MOBILE_PHONE_NUMBER = "reportingOfficerMobilePhoneNumber"; + public static final String REPORTING_OFFICER_EMAIL = "reportingOfficerEmail"; + public static final String INVESTIGATION_DATE = "investigationDate"; + public static final String FORM_COMPLETION_DATE = "formCompletionDate"; + public static final String INVESTIGATION_STAGE = "investigationStage"; + public static final String TYPE_OF_SITE = "typeOfSite"; + public static final String TYPE_OF_SITE_DETAILS = "typeOfSiteDetails"; + public static final String KEY_SYMPTOM_DATE_TIME = "keySymptomDateTime"; + public static final String HOSPITALIZATION_DATE = "hospitalizationDate"; + public static final String REPORTED_TO_HEALTH_AUTHORITY_DATE = "reportedToHealthAuthorityDate"; + public static final String STATUS_ON_DATE_OF_INVESTIGATION = "statusOnDateOfInvestigation"; + public static final String DEATH_DATE_TIME = "deathDateTime"; + public static final String AUTOPSY_DONE = "autopsyDone"; + public static final String AUTOPSY_DATE = "autopsyDate"; + public static final String AUTOPSY_PLANNED_DATE_TIME = "autopsyPlannedDateTime"; + public static final String PAST_HISTORY_OF_SIMILAR_EVENT = "pastHistoryOfSimilarEvent"; + public static final String PAST_HISTORY_OF_SIMILAR_EVENT_DETAILS = "pastHistoryOfSimilarEventDetails"; + public static final String ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS = "adverseEventAfterPreviousVaccinations"; + public static final String ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS_DETAILS = "adverseEventAfterPreviousVaccinationsDetails"; + public static final String HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD = "historyOfAllergyToVaccineDrugOrFood"; + public static final String HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD_DETAILS = "historyOfAllergyToVaccineDrugOrFoodDetails"; + public static final String PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER = "preExistingIllnessThirtyDaysOrCongenitalDisorder"; + public static final String PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER_DETAILS = + "preExistingIllnessThirtyDaysOrCongenitalDisorderDetails"; + public static final String HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE = "historyOfHospitalizationInLastThirtyDaysWithCause"; + public static final String HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE_DETAILS = + "historyOfHospitalizationInLastThirtyDaysWithCauseDetails"; + public static final String CURRENTLY_ON_CONCOMITANT_MEDICATION = "currentlyOnConcomitantMedication"; + public static final String CURRENTLY_ON_CONCOMITANT_MEDICATION_DETAILS = "currentlyOnConcomitantMedicationDetails"; + public static final String FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY = "familyHistoryOfDiseaseOrAllergy"; + public static final String FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY_DETAILS = "familyHistoryOfDiseaseOrAllergyDetails"; + public static final String NUMBER_OF_WEEKS_PREGNANT = "numberOfWeeksPregnant"; + public static final String BIRTH_TERM = "birthTerm"; + public static final String BIRTH_WEIGHT = "birthWeight"; + public static final String DELIVERY_PROCEDURE = "deliveryProcedure"; + public static final String DELIVERY_PROCEDURE_DETAILS = "deliveryProcedureDetails"; + public static final String SERIOUS_AEFI_INFO_SOURCE = "seriousAefiInfoSource"; + public static final String SERIOUS_AEFI_INFO_SOURCE_DETAILS = "seriousAefiInfoSourceDetails"; + public static final String SERIOUS_AEFI_VERBAL_AUTOPSY_INFO_SOURCE_DETAILS = "seriousAefiVerbalAutopsyInfoSourceDetails"; + public static final String FIRST_CAREGIVERS_NAME = "firstCaregiversName"; + public static final String OTHER_CAREGIVERS_NAMES = "otherCaregiversNames"; + public static final String OTHER_SOURCES_WHO_PROVIDED_INFO = "otherSourcesWhoProvidedInfo"; + public static final String SIGNS_AND_SYMPTOMS_FROM_TIME_OF_VACCINATION = "signsAndSymptomsFromTimeOfVaccination"; + public static final String CLINICAL_DETAILS_OFFICER_NAME = "clinicalDetailsOfficerName"; + public static final String CLINICAL_DETAILS_OFFICER_PHONE_NUMBER = "clinicalDetailsOfficerPhoneNumber"; + public static final String CLINICAL_DETAILS_OFFICER_EMAIL = "clinicalDetailsOfficerEmail"; + public static final String CLINICAL_DETAILS_OFFICER_DESIGNATION = "clinicalDetailsOfficerDesignation"; + public static final String CLINICAL_DETAILS_DATE_TIME = "clinicalDetailsDateTime"; + public static final String PATIENT_RECEIVED_MEDICAL_CARE = "patientReceivedMedicalCare"; + public static final String PATIENT_RECEIVED_MEDICAL_CARE_DETAILS = "patientReceivedMedicalCareDetails"; + public static final String PROVISIONAL_OR_FINAL_DIAGNOSIS = "provisionalOrFinalDiagnosis"; + public static final String PATIENT_IMMUNIZED_PERIOD = "patientImmunizedPeriod"; + public static final String PATIENT_IMMUNIZED_PERIOD_DETAILS = "patientImmunizedPeriodDetails"; + public static final String VACCINE_GIVEN_PERIOD = "vaccineGivenPeriod"; + public static final String VACCINE_GIVEN_PERIOD_DETAILS = "vaccineGivenPeriodDetails"; + public static final String ERROR_PRESCRIBING_VACCINE = "errorPrescribingVaccine"; + public static final String ERROR_PRESCRIBING_VACCINE_DETAILS = "errorPrescribingVaccineDetails"; + public static final String VACCINE_COULD_HAVE_BEEN_UNSTERILE = "vaccineCouldHaveBeenUnSterile"; + public static final String VACCINE_COULD_HAVE_BEEN_UNSTERILE_DETAILS = "vaccineCouldHaveBeenUnSterileDetails"; + public static final String VACCINE_PHYSICAL_CONDITION_ABNORMAL = "vaccinePhysicalConditionAbnormal"; + public static final String VACCINE_PHYSICAL_CONDITION_ABNORMAL_DETAILS = "vaccinePhysicalConditionAbnormalDetails"; + public static final String ERROR_IN_VACCINE_RECONSTITUTION = "errorInVaccineReconstitution"; + public static final String ERROR_IN_VACCINE_RECONSTITUTION_DETAILS = "errorInVaccineReconstitutionDetails"; + public static final String ERROR_IN_VACCINE_HANDLING = "errorInVaccineHandling"; + public static final String ERROR_IN_VACCINE_HANDLING_DETAILS = "errorInVaccineHandlingDetails"; + public static final String VACCINE_ADMINISTERED_INCORRECTLY = "vaccineAdministeredIncorrectly"; + public static final String VACCINE_ADMINISTERED_INCORRECTLY_DETAILS = "vaccineAdministeredIncorrectlyDetails"; + public static final String NUMBER_IMMUNIZED_FROM_CONCERNED_VACCINE_VIAL = "numberImmunizedFromConcernedVaccineVial"; + public static final String NUMBER_IMMUNIZED_WITH_CONCERNED_VACCINE_IN_SAME_SESSION = "numberImmunizedWithConcernedVaccineInSameSession"; + public static final String NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_OTHER_LOCATIONS = + "numberImmunizedConcernedVaccineSameBatchNumberOtherLocations"; + public static final String NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_LOCATION_DETAILS = + "numberImmunizedConcernedVaccineSameBatchNumberLocationDetails"; + public static final String VACCINE_HAS_QUALITY_DEFECT = "vaccineHasQualityDefect"; + public static final String VACCINE_HAS_QUALITY_DEFECT_DETAILS = "vaccineHasQualityDefectDetails"; + public static final String EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION = "eventIsAStressResponseRelatedToImmunization"; + public static final String EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION_DETAILS = "eventIsAStressResponseRelatedToImmunizationDetails"; + public static final String CASE_IS_PART_OF_A_CLUSTER = "caseIsPartOfACluster"; + public static final String CASE_IS_PART_OF_A_CLUSTER_DETAILS = "caseIsPartOfAClusterDetails"; + public static final String NUMBER_OF_CASES_DETECTED_IN_CLUSTER = "numberOfCasesDetectedInCluster"; + public static final String ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL = "allCasesInClusterReceivedVaccineFromSameVial"; + public static final String ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL_DETAILS = "allCasesInClusterReceivedVaccineFromSameVialDetails"; + public static final String NUMBER_OF_VIALS_USED_IN_CLUSTER = "numberOfVialsUsedInCluster"; + public static final String NUMBER_OF_VIALS_USED_IN_CLUSTER_DETAILS = "numberOfVialsUsedInClusterDetails"; + public static final String AD_SYRINGES_USED_FOR_IMMUNIZATION = "adSyringesUsedForImmunization"; + public static final String TYPE_OF_SYRINGES_USED = "typeOfSyringesUsed"; + public static final String TYPE_OF_SYRINGES_USED_DETAILS = "typeOfSyringesUsedDetails"; + public static final String SYRINGES_USED_ADDITIONAL_DETAILS = "syringesUsedAdditionalDetails"; + public static final String SAME_RECONSTITUTION_SYRINGE_USED_FOR_MULTIPLE_VIALS_OF_SAME_VACCINE = + "sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine"; + public static final String SAME_RECONSTITUTION_SYRINGE_USED_FOR_RECONSTITUTING_DIFFERENT_VACCINES = + "sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines"; + public static final String SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINE_VIAL = "sameReconstitutionSyringeForEachVaccineVial"; + public static final String SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINATION = "sameReconstitutionSyringeForEachVaccination"; + public static final String VACCINES_AND_DILUENTS_USED_RECOMMENDED_BY_MANUFACTURER = "vaccinesAndDiluentsUsedRecommendedByManufacturer"; + public static final String RECONSTITUTION_ADDITIONAL_DETAILS = "reconstitutionAdditionalDetails"; + public static final String CORRECT_DOSE_OR_ROUTE = "correctDoseOrRoute"; + public static final String TIME_OF_RECONSTITUTION_MENTIONED_ON_THE_VIAL = "timeOfReconstitutionMentionedOnTheVial"; + public static final String NON_TOUCH_TECHNIQUE_FOLLOWED = "nonTouchTechniqueFollowed"; + public static final String CONTRAINDICATION_SCREENED_PRIOR_TO_VACCINATION = "contraIndicationScreenedPriorToVaccination"; + public static final String NUMBER_OF_AEFI_REPORTED_FROM_VACCINE_DISTRIBUTION_CENTER_LAST_THIRTY_DAYS = + "numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays"; + public static final String TRAINING_RECEIVED_BY_VACCINATOR = "trainingReceivedByVaccinator"; + public static final String LAST_TRAINING_RECEIVED_BY_VACCINATOR_DATE = "lastTrainingReceivedByVaccinatorDate"; + public static final String INJECTION_TECHNIQUE_ADDITIONAL_DETAILS = "injectionTechniqueAdditionalDetails"; + public static final String VACCINE_STORAGE_REFRIGERATOR_TEMPERATURE_MONITORED = "vaccineStorageRefrigeratorTemperatureMonitored"; + public static final String ANY_STORAGE_TEMPERATURE_DEVIATION_OUTSIDE_TWO_TO_EIGHT_DEGREES = + "anyStorageTemperatureDeviationOutsideTwoToEightDegrees"; + public static final String STORAGE_TEMPERATURE_MONITORING_ADDITIONAL_DETAILS = "storageTemperatureMonitoringAdditionalDetails"; + public static final String CORRECT_PROCEDURE_FOR_STORAGE_FOLLOWED = "correctProcedureForStorageFollowed"; + public static final String ANY_OTHER_ITEM_IN_REFRIGERATOR = "anyOtherItemInRefrigerator"; + public static final String PARTIALLY_USED_RECONSTITUTED_VACCINES_IN_REFRIGERATOR = "partiallyUsedReconstitutedVaccinesInRefrigerator"; + public static final String UNUSABLE_VACCINES_IN_REFRIGERATOR = "unusableVaccinesInRefrigerator"; + public static final String UNUSABLE_DILUENTS_IN_STORE = "unusableDiluentsInStore"; + public static final String VACCINE_STORAGE_POINT_ADDITIONAL_DETAILS = "vaccineStoragePointAdditionalDetails"; + public static final String VACCINE_CARRIER_TYPE = "vaccineCarrierType"; + public static final String VACCINE_CARRIER_TYPE_DETAILS = "vaccineCarrierTypeDetails"; + public static final String VACCINE_CARRIER_SENT_TO_SITE_ON_SAME_DATE_AS_VACCINATION = "vaccineCarrierSentToSiteOnSameDateAsVaccination"; + public static final String VACCINE_CARRIER_RETURNED_FROM_SITE_ON_SAME_DATE_AS_VACCINATION = + "vaccineCarrierReturnedFromSiteOnSameDateAsVaccination"; + public static final String CONDITIONED_ICE_PACK_USED = "conditionedIcepackUsed"; + public static final String VACCINE_TRANSPORTATION_ADDITIONAL_DETAILS = "vaccineTransportationAdditionalDetails"; + public static final String SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY = "similarEventsReportedSamePeriodAndLocality"; + public static final String SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS = "similarEventsReportedSamePeriodAndLocalityDetails"; + public static final String NUMBER_OF_SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY = "numberOfSimilarEventsReportedSamePeriodAndLocality"; + public static final String NUMBER_OF_THOSE_AFFECTED_VACCINATED = "numberOfThoseAffectedVaccinated"; + public static final String NUMBER_OF_THOSE_AFFECTED_NOT_VACCINATED = "numberOfThoseAffectedNotVaccinated"; + public static final String NUMBER_OF_THOSE_AFFECTED_VACCINATED_UNKNOWN = "numberOfThoseAffectedVaccinatedUnknown"; + public static final String COMMUNITY_INVESTIGATION_ADDITIONAL_DETAILS = "communityInvestigationAdditionalDetails"; + public static final String OTHER_INVESTIGATION_FINDINGS = "otherInvestigationFindings"; + public static final String INVESTIGATION_STATUS = "investigationStatus"; + public static final String INVESTIGATION_STATUS_DETAILS = "investigationStatusDetails"; + public static final String AEFI_CLASSIFICATION = "aefiClassification"; + public static final String AEFI_CLASSIFICATION_SUB_TYPE = "aefiClassificationSubType"; + public static final String AEFI_CLASSIFICATION_DETAILS = "aefiClassificationDetails"; + public static final String CAUSALITY = "causality"; + public static final String CAUSALITY_DETAILS = "causalityDetails"; + public static final String INVESTIGATION_COMPLETION_DATE = "investigationCompletionDate"; + public static final String DELETION_REASON = "deletionReason"; + public static final String OTHER_DELETION_REASON = "otherDeletionReason"; + + @NotNull(message = Validations.validAefiReport) + private AefiReferenceDto aefiReport; + private LocationDto address; + @NotEmpty(message = Validations.aefiInvestigationWithoutSuspectVaccines) + private List vaccinations = new ArrayList<>(); + private VaccinationDto primarySuspectVaccine; + private Date reportDate; + private UserReferenceDto reportingUser; + private String externalId; + private RegionReferenceDto responsibleRegion; + private DistrictReferenceDto responsibleDistrict; + private CommunityReferenceDto responsibleCommunity; + private CountryReferenceDto country; + private String investigationCaseId; + private PlaceOfVaccination placeOfVaccination; + private String placeOfVaccinationDetails; + private VaccinationActivity vaccinationActivity; + private String vaccinationActivityDetails; + private FacilityReferenceDto vaccinationFacility; + private String vaccinationFacilityDetails; + private String reportingOfficerName; + private FacilityReferenceDto reportingOfficerFacility; + private String reportingOfficerFacilityDetails; + private String reportingOfficerDesignation; + private String reportingOfficerDepartment; + private LocationDto reportingOfficerAddress; + private String reportingOfficerLandlinePhoneNumber; + private String reportingOfficerMobilePhoneNumber; + private String reportingOfficerEmail; + private Date investigationDate; + private Date formCompletionDate; + private AefiInvestigationStage investigationStage; + private VaccinationSite typeOfSite; + private String typeOfSiteDetails; + private Date keySymptomDateTime; + private Date hospitalizationDate; + private Date reportedToHealthAuthorityDate; + private PatientStatusAtAefiInvestigation statusOnDateOfInvestigation; + private Date deathDateTime; + private YesNoUnknown autopsyDone; + private Date autopsyDate; + private Date autopsyPlannedDateTime; + private YesNoUnknown pastHistoryOfSimilarEvent; + private String pastHistoryOfSimilarEventDetails; + private YesNoUnknown adverseEventAfterPreviousVaccinations; + private String adverseEventAfterPreviousVaccinationsDetails; + private YesNoUnknown historyOfAllergyToVaccineDrugOrFood; + private String historyOfAllergyToVaccineDrugOrFoodDetails; + private YesNoUnknown preExistingIllnessThirtyDaysOrCongenitalDisorder; + private String preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + private YesNoUnknown historyOfHospitalizationInLastThirtyDaysWithCause; + private String historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + private YesNoUnknown currentlyOnConcomitantMedication; + private String currentlyOnConcomitantMedicationDetails; + private YesNoUnknown familyHistoryOfDiseaseOrAllergy; + private String familyHistoryOfDiseaseOrAllergyDetails; + private Integer numberOfWeeksPregnant; + private BirthTerm birthTerm; + private Float birthWeight; + private DeliveryProcedure deliveryProcedure; + private String deliveryProcedureDetails; + private Set seriousAefiInfoSource; + private String seriousAefiInfoSourceDetails; + private String seriousAefiVerbalAutopsyInfoSourceDetails; + private String firstCaregiversName; + private String otherCaregiversNames; + private String otherSourcesWhoProvidedInfo; + private String signsAndSymptomsFromTimeOfVaccination; + private String clinicalDetailsOfficerName; + private String clinicalDetailsOfficerPhoneNumber; + private String clinicalDetailsOfficerEmail; + private String clinicalDetailsOfficerDesignation; + private Date clinicalDetailsDateTime; + private YesNoUnknown patientReceivedMedicalCare; + private String patientReceivedMedicalCareDetails; + private String provisionalOrFinalDiagnosis; + private AefiImmunizationPeriod patientImmunizedPeriod; + private String patientImmunizedPeriodDetails; + private AefiVaccinationPeriod vaccineGivenPeriod; + private String vaccineGivenPeriodDetails; + private YesNoUnknown errorPrescribingVaccine; + private String errorPrescribingVaccineDetails; + private YesNoUnknown vaccineCouldHaveBeenUnSterile; + private String vaccineCouldHaveBeenUnSterileDetails; + private YesNoUnknown vaccinePhysicalConditionAbnormal; + private String vaccinePhysicalConditionAbnormalDetails; + private YesNoUnknown errorInVaccineReconstitution; + private String errorInVaccineReconstitutionDetails; + private YesNoUnknown errorInVaccineHandling; + private String errorInVaccineHandlingDetails; + private YesNoUnknown vaccineAdministeredIncorrectly; + private String vaccineAdministeredIncorrectlyDetails; + private Integer numberImmunizedFromConcernedVaccineVial; + private Integer numberImmunizedWithConcernedVaccineInSameSession; + private Integer numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + private String numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + private YesNoUnknown vaccineHasQualityDefect; + private String vaccineHasQualityDefectDetails; + private YesNoUnknown eventIsAStressResponseRelatedToImmunization; + private String eventIsAStressResponseRelatedToImmunizationDetails; + private YesNoUnknown caseIsPartOfACluster; + private String caseIsPartOfAClusterDetails; + private Integer numberOfCasesDetectedInCluster; + private YesNoUnknown allCasesInClusterReceivedVaccineFromSameVial; + private String allCasesInClusterReceivedVaccineFromSameVialDetails; + private Integer numberOfVialsUsedInCluster; + private String numberOfVialsUsedInClusterDetails; + private YesNoUnknown adSyringesUsedForImmunization; + private SyringeType typeOfSyringesUsed; + private String typeOfSyringesUsedDetails; + private String syringesUsedAdditionalDetails; + private YesNoUnknown sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + private YesNoUnknown sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + private YesNoUnknown sameReconstitutionSyringeForEachVaccineVial; + private YesNoUnknown sameReconstitutionSyringeForEachVaccination; + private YesNoUnknown vaccinesAndDiluentsUsedRecommendedByManufacturer; + private String reconstitutionAdditionalDetails; + private YesNoUnknown correctDoseOrRoute; + private YesNoUnknown timeOfReconstitutionMentionedOnTheVial; + private YesNoUnknown nonTouchTechniqueFollowed; + private YesNoUnknown contraIndicationScreenedPriorToVaccination; + private Integer numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + private YesNoUnknown trainingReceivedByVaccinator; + private Date lastTrainingReceivedByVaccinatorDate; + private String injectionTechniqueAdditionalDetails; + private YesNoUnknown vaccineStorageRefrigeratorTemperatureMonitored; + private YesNoUnknown anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + private String storageTemperatureMonitoringAdditionalDetails; + private YesNoUnknown correctProcedureForStorageFollowed; + private YesNoUnknown anyOtherItemInRefrigerator; + private YesNoUnknown partiallyUsedReconstitutedVaccinesInRefrigerator; + private YesNoUnknown unusableVaccinesInRefrigerator; + private YesNoUnknown unusableDiluentsInStore; + private String vaccineStoragePointAdditionalDetails; + private VaccineCarrier vaccineCarrierType; + private String vaccineCarrierTypeDetails; + private YesNoUnknown vaccineCarrierSentToSiteOnSameDateAsVaccination; + private YesNoUnknown vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + private YesNoUnknown conditionedIcepackUsed; + private String vaccineTransportationAdditionalDetails; + private YesNoUnknown similarEventsReportedSamePeriodAndLocality; + private String similarEventsReportedSamePeriodAndLocalityDetails; + private Integer numberOfSimilarEventsReportedSamePeriodAndLocality; + private Integer numberOfThoseAffectedVaccinated; + private Integer numberOfThoseAffectedNotVaccinated; + private Integer numberOfThoseAffectedVaccinatedUnknown; + private String communityInvestigationAdditionalDetails; + private String otherInvestigationFindings; + private AefiInvestigationStatus investigationStatus; + private String investigationStatusDetails; + private AefiClassification aefiClassification; + private AefiClassificationSubType aefiClassificationSubType; + private String aefiClassificationDetails; + private AefiCausality causality; + private String causalityDetails; + private Date investigationCompletionDate; + private boolean archived; + private boolean deleted; + private DeletionReason deletionReason; + @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) + private String otherDeletionReason; + + public static AefiInvestigationDto build(UserReferenceDto user) { + + final AefiInvestigationDto aefiInvestigationDto = new AefiInvestigationDto(); + aefiInvestigationDto.setUuid(DataHelper.createUuid()); + aefiInvestigationDto.setReportingUser(user); + aefiInvestigationDto.setReportDate(new Date()); + + return aefiInvestigationDto; + } + + public static AefiInvestigationDto build(AefiReferenceDto aefiReferenceDto) { + + final AefiInvestigationDto aefiInvestigationDto = new AefiInvestigationDto(); + aefiInvestigationDto.setUuid(DataHelper.createUuid()); + aefiInvestigationDto.setAefiReport(aefiReferenceDto); + aefiInvestigationDto.setReportDate(new Date()); + + return aefiInvestigationDto; + } + + public static AefiInvestigationDto build(AefiInvestigationReferenceDto aefiInvestigationReferenceDto) { + + final AefiInvestigationDto aefiInvestigationDto = new AefiInvestigationDto(); + aefiInvestigationDto.setUuid(aefiInvestigationReferenceDto.getUuid()); + aefiInvestigationDto.setReportDate(new Date()); + + return aefiInvestigationDto; + } + + public AefiInvestigationReferenceDto toReference() { + return new AefiInvestigationReferenceDto(getUuid(), getExternalId()); + } + + public AefiReferenceDto getAefiReport() { + return aefiReport; + } + + public void setAefiReport(AefiReferenceDto aefiReport) { + this.aefiReport = aefiReport; + } + + public LocationDto getAddress() { + return address; + } + + public void setAddress(LocationDto address) { + this.address = address; + } + + public List getVaccinations() { + return vaccinations; + } + + public void setVaccinations(List vaccinations) { + this.vaccinations = vaccinations; + } + + public VaccinationDto getPrimarySuspectVaccine() { + return primarySuspectVaccine; + } + + public void setPrimarySuspectVaccine(VaccinationDto primarySuspectVaccine) { + this.primarySuspectVaccine = primarySuspectVaccine; + } + + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + public UserReferenceDto getReportingUser() { + return reportingUser; + } + + public void setReportingUser(UserReferenceDto reportingUser) { + this.reportingUser = reportingUser; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public RegionReferenceDto getResponsibleRegion() { + return responsibleRegion; + } + + public void setResponsibleRegion(RegionReferenceDto responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + public DistrictReferenceDto getResponsibleDistrict() { + return responsibleDistrict; + } + + public void setResponsibleDistrict(DistrictReferenceDto responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + public CommunityReferenceDto getResponsibleCommunity() { + return responsibleCommunity; + } + + public void setResponsibleCommunity(CommunityReferenceDto responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + public CountryReferenceDto getCountry() { + return country; + } + + public void setCountry(CountryReferenceDto country) { + this.country = country; + } + + public String getInvestigationCaseId() { + return investigationCaseId; + } + + public void setInvestigationCaseId(String investigationCaseId) { + this.investigationCaseId = investigationCaseId; + } + + public PlaceOfVaccination getPlaceOfVaccination() { + return placeOfVaccination; + } + + public void setPlaceOfVaccination(PlaceOfVaccination placeOfVaccination) { + this.placeOfVaccination = placeOfVaccination; + } + + public String getPlaceOfVaccinationDetails() { + return placeOfVaccinationDetails; + } + + public void setPlaceOfVaccinationDetails(String placeOfVaccinationDetails) { + this.placeOfVaccinationDetails = placeOfVaccinationDetails; + } + + public VaccinationActivity getVaccinationActivity() { + return vaccinationActivity; + } + + public void setVaccinationActivity(VaccinationActivity vaccinationActivity) { + this.vaccinationActivity = vaccinationActivity; + } + + public String getVaccinationActivityDetails() { + return vaccinationActivityDetails; + } + + public void setVaccinationActivityDetails(String vaccinationActivityDetails) { + this.vaccinationActivityDetails = vaccinationActivityDetails; + } + + public FacilityReferenceDto getVaccinationFacility() { + return vaccinationFacility; + } + + public void setVaccinationFacility(FacilityReferenceDto vaccinationFacility) { + this.vaccinationFacility = vaccinationFacility; + } + + public String getVaccinationFacilityDetails() { + return vaccinationFacilityDetails; + } + + public void setVaccinationFacilityDetails(String vaccinationFacilityDetails) { + this.vaccinationFacilityDetails = vaccinationFacilityDetails; + } + + public String getReportingOfficerName() { + return reportingOfficerName; + } + + public void setReportingOfficerName(String reportingOfficerName) { + this.reportingOfficerName = reportingOfficerName; + } + + public FacilityReferenceDto getReportingOfficerFacility() { + return reportingOfficerFacility; + } + + public void setReportingOfficerFacility(FacilityReferenceDto reportingOfficerFacility) { + this.reportingOfficerFacility = reportingOfficerFacility; + } + + public String getReportingOfficerFacilityDetails() { + return reportingOfficerFacilityDetails; + } + + public void setReportingOfficerFacilityDetails(String reportingOfficerFacilityDetails) { + this.reportingOfficerFacilityDetails = reportingOfficerFacilityDetails; + } + + public String getReportingOfficerDesignation() { + return reportingOfficerDesignation; + } + + public void setReportingOfficerDesignation(String reportingOfficerDesignation) { + this.reportingOfficerDesignation = reportingOfficerDesignation; + } + + public String getReportingOfficerDepartment() { + return reportingOfficerDepartment; + } + + public void setReportingOfficerDepartment(String reportingOfficerDepartment) { + this.reportingOfficerDepartment = reportingOfficerDepartment; + } + + public LocationDto getReportingOfficerAddress() { + return reportingOfficerAddress; + } + + public void setReportingOfficerAddress(LocationDto reportingOfficerAddress) { + this.reportingOfficerAddress = reportingOfficerAddress; + } + + public String getReportingOfficerLandlinePhoneNumber() { + return reportingOfficerLandlinePhoneNumber; + } + + public void setReportingOfficerLandlinePhoneNumber(String reportingOfficerLandlinePhoneNumber) { + this.reportingOfficerLandlinePhoneNumber = reportingOfficerLandlinePhoneNumber; + } + + public String getReportingOfficerMobilePhoneNumber() { + return reportingOfficerMobilePhoneNumber; + } + + public void setReportingOfficerMobilePhoneNumber(String reportingOfficerMobilePhoneNumber) { + this.reportingOfficerMobilePhoneNumber = reportingOfficerMobilePhoneNumber; + } + + public String getReportingOfficerEmail() { + return reportingOfficerEmail; + } + + public void setReportingOfficerEmail(String reportingOfficerEmail) { + this.reportingOfficerEmail = reportingOfficerEmail; + } + + public Date getInvestigationDate() { + return investigationDate; + } + + public void setInvestigationDate(Date investigationDate) { + this.investigationDate = investigationDate; + } + + public Date getFormCompletionDate() { + return formCompletionDate; + } + + public void setFormCompletionDate(Date formCompletionDate) { + this.formCompletionDate = formCompletionDate; + } + + public AefiInvestigationStage getInvestigationStage() { + return investigationStage; + } + + public void setInvestigationStage(AefiInvestigationStage investigationStage) { + this.investigationStage = investigationStage; + } + + public VaccinationSite getTypeOfSite() { + return typeOfSite; + } + + public void setTypeOfSite(VaccinationSite typeOfSite) { + this.typeOfSite = typeOfSite; + } + + public String getTypeOfSiteDetails() { + return typeOfSiteDetails; + } + + public void setTypeOfSiteDetails(String typeOfSiteDetails) { + this.typeOfSiteDetails = typeOfSiteDetails; + } + + public Date getKeySymptomDateTime() { + return keySymptomDateTime; + } + + public void setKeySymptomDateTime(Date keySymptomDateTime) { + this.keySymptomDateTime = keySymptomDateTime; + } + + public Date getHospitalizationDate() { + return hospitalizationDate; + } + + public void setHospitalizationDate(Date hospitalizationDate) { + this.hospitalizationDate = hospitalizationDate; + } + + public Date getReportedToHealthAuthorityDate() { + return reportedToHealthAuthorityDate; + } + + public void setReportedToHealthAuthorityDate(Date reportedToHealthAuthorityDate) { + this.reportedToHealthAuthorityDate = reportedToHealthAuthorityDate; + } + + public PatientStatusAtAefiInvestigation getStatusOnDateOfInvestigation() { + return statusOnDateOfInvestigation; + } + + public void setStatusOnDateOfInvestigation(PatientStatusAtAefiInvestigation statusOnDateOfInvestigation) { + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + } + + public Date getDeathDateTime() { + return deathDateTime; + } + + public void setDeathDateTime(Date deathDateTime) { + this.deathDateTime = deathDateTime; + } + + public YesNoUnknown getAutopsyDone() { + return autopsyDone; + } + + public void setAutopsyDone(YesNoUnknown autopsyDone) { + this.autopsyDone = autopsyDone; + } + + public Date getAutopsyDate() { + return autopsyDate; + } + + public void setAutopsyDate(Date autopsyDate) { + this.autopsyDate = autopsyDate; + } + + public Date getAutopsyPlannedDateTime() { + return autopsyPlannedDateTime; + } + + public void setAutopsyPlannedDateTime(Date autopsyPlannedDateTime) { + this.autopsyPlannedDateTime = autopsyPlannedDateTime; + } + + public YesNoUnknown getPastHistoryOfSimilarEvent() { + return pastHistoryOfSimilarEvent; + } + + public void setPastHistoryOfSimilarEvent(YesNoUnknown pastHistoryOfSimilarEvent) { + this.pastHistoryOfSimilarEvent = pastHistoryOfSimilarEvent; + } + + public String getPastHistoryOfSimilarEventDetails() { + return pastHistoryOfSimilarEventDetails; + } + + public void setPastHistoryOfSimilarEventDetails(String pastHistoryOfSimilarEventDetails) { + this.pastHistoryOfSimilarEventDetails = pastHistoryOfSimilarEventDetails; + } + + public YesNoUnknown getAdverseEventAfterPreviousVaccinations() { + return adverseEventAfterPreviousVaccinations; + } + + public void setAdverseEventAfterPreviousVaccinations(YesNoUnknown adverseEventAfterPreviousVaccinations) { + this.adverseEventAfterPreviousVaccinations = adverseEventAfterPreviousVaccinations; + } + + public String getAdverseEventAfterPreviousVaccinationsDetails() { + return adverseEventAfterPreviousVaccinationsDetails; + } + + public void setAdverseEventAfterPreviousVaccinationsDetails(String adverseEventAfterPreviousVaccinationsDetails) { + this.adverseEventAfterPreviousVaccinationsDetails = adverseEventAfterPreviousVaccinationsDetails; + } + + public YesNoUnknown getHistoryOfAllergyToVaccineDrugOrFood() { + return historyOfAllergyToVaccineDrugOrFood; + } + + public void setHistoryOfAllergyToVaccineDrugOrFood(YesNoUnknown historyOfAllergyToVaccineDrugOrFood) { + this.historyOfAllergyToVaccineDrugOrFood = historyOfAllergyToVaccineDrugOrFood; + } + + public String getHistoryOfAllergyToVaccineDrugOrFoodDetails() { + return historyOfAllergyToVaccineDrugOrFoodDetails; + } + + public void setHistoryOfAllergyToVaccineDrugOrFoodDetails(String historyOfAllergyToVaccineDrugOrFoodDetails) { + this.historyOfAllergyToVaccineDrugOrFoodDetails = historyOfAllergyToVaccineDrugOrFoodDetails; + } + + public YesNoUnknown getPreExistingIllnessThirtyDaysOrCongenitalDisorder() { + return preExistingIllnessThirtyDaysOrCongenitalDisorder; + } + + public void setPreExistingIllnessThirtyDaysOrCongenitalDisorder(YesNoUnknown preExistingIllnessThirtyDaysOrCongenitalDisorder) { + this.preExistingIllnessThirtyDaysOrCongenitalDisorder = preExistingIllnessThirtyDaysOrCongenitalDisorder; + } + + public String getPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails() { + return preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + } + + public void setPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails(String preExistingIllnessThirtyDaysOrCongenitalDisorderDetails) { + this.preExistingIllnessThirtyDaysOrCongenitalDisorderDetails = preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + } + + public YesNoUnknown getHistoryOfHospitalizationInLastThirtyDaysWithCause() { + return historyOfHospitalizationInLastThirtyDaysWithCause; + } + + public void setHistoryOfHospitalizationInLastThirtyDaysWithCause(YesNoUnknown historyOfHospitalizationInLastThirtyDaysWithCause) { + this.historyOfHospitalizationInLastThirtyDaysWithCause = historyOfHospitalizationInLastThirtyDaysWithCause; + } + + public String getHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails() { + return historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + } + + public void setHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails(String historyOfHospitalizationInLastThirtyDaysWithCauseDetails) { + this.historyOfHospitalizationInLastThirtyDaysWithCauseDetails = historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + } + + public YesNoUnknown getCurrentlyOnConcomitantMedication() { + return currentlyOnConcomitantMedication; + } + + public void setCurrentlyOnConcomitantMedication(YesNoUnknown currentlyOnConcomitantMedication) { + this.currentlyOnConcomitantMedication = currentlyOnConcomitantMedication; + } + + public String getCurrentlyOnConcomitantMedicationDetails() { + return currentlyOnConcomitantMedicationDetails; + } + + public void setCurrentlyOnConcomitantMedicationDetails(String currentlyOnConcomitantMedicationDetails) { + this.currentlyOnConcomitantMedicationDetails = currentlyOnConcomitantMedicationDetails; + } + + public YesNoUnknown getFamilyHistoryOfDiseaseOrAllergy() { + return familyHistoryOfDiseaseOrAllergy; + } + + public void setFamilyHistoryOfDiseaseOrAllergy(YesNoUnknown familyHistoryOfDiseaseOrAllergy) { + this.familyHistoryOfDiseaseOrAllergy = familyHistoryOfDiseaseOrAllergy; + } + + public String getFamilyHistoryOfDiseaseOrAllergyDetails() { + return familyHistoryOfDiseaseOrAllergyDetails; + } + + public void setFamilyHistoryOfDiseaseOrAllergyDetails(String familyHistoryOfDiseaseOrAllergyDetails) { + this.familyHistoryOfDiseaseOrAllergyDetails = familyHistoryOfDiseaseOrAllergyDetails; + } + + public Integer getNumberOfWeeksPregnant() { + return numberOfWeeksPregnant; + } + + public void setNumberOfWeeksPregnant(Integer numberOfWeeksPregnant) { + this.numberOfWeeksPregnant = numberOfWeeksPregnant; + } + + public BirthTerm getBirthTerm() { + return birthTerm; + } + + public void setBirthTerm(BirthTerm birthTerm) { + this.birthTerm = birthTerm; + } + + public Float getBirthWeight() { + return birthWeight; + } + + public void setBirthWeight(Float birthWeight) { + this.birthWeight = birthWeight; + } + + public DeliveryProcedure getDeliveryProcedure() { + return deliveryProcedure; + } + + public void setDeliveryProcedure(DeliveryProcedure deliveryProcedure) { + this.deliveryProcedure = deliveryProcedure; + } + + public String getDeliveryProcedureDetails() { + return deliveryProcedureDetails; + } + + public void setDeliveryProcedureDetails(String deliveryProcedureDetails) { + this.deliveryProcedureDetails = deliveryProcedureDetails; + } + + public Set getSeriousAefiInfoSource() { + return seriousAefiInfoSource; + } + + public void setSeriousAefiInfoSource(Set seriousAefiInfoSource) { + this.seriousAefiInfoSource = seriousAefiInfoSource; + } + + public String getSeriousAefiInfoSourceDetails() { + return seriousAefiInfoSourceDetails; + } + + public void setSeriousAefiInfoSourceDetails(String seriousAefiInfoSourceDetails) { + this.seriousAefiInfoSourceDetails = seriousAefiInfoSourceDetails; + } + + public String getSeriousAefiVerbalAutopsyInfoSourceDetails() { + return seriousAefiVerbalAutopsyInfoSourceDetails; + } + + public void setSeriousAefiVerbalAutopsyInfoSourceDetails(String seriousAefiVerbalAutopsyInfoSourceDetails) { + this.seriousAefiVerbalAutopsyInfoSourceDetails = seriousAefiVerbalAutopsyInfoSourceDetails; + } + + public String getFirstCaregiversName() { + return firstCaregiversName; + } + + public void setFirstCaregiversName(String firstCaregiversName) { + this.firstCaregiversName = firstCaregiversName; + } + + public String getOtherCaregiversNames() { + return otherCaregiversNames; + } + + public void setOtherCaregiversNames(String otherCaregiversNames) { + this.otherCaregiversNames = otherCaregiversNames; + } + + public String getOtherSourcesWhoProvidedInfo() { + return otherSourcesWhoProvidedInfo; + } + + public void setOtherSourcesWhoProvidedInfo(String otherSourcesWhoProvidedInfo) { + this.otherSourcesWhoProvidedInfo = otherSourcesWhoProvidedInfo; + } + + public String getSignsAndSymptomsFromTimeOfVaccination() { + return signsAndSymptomsFromTimeOfVaccination; + } + + public void setSignsAndSymptomsFromTimeOfVaccination(String signsAndSymptomsFromTimeOfVaccination) { + this.signsAndSymptomsFromTimeOfVaccination = signsAndSymptomsFromTimeOfVaccination; + } + + public String getClinicalDetailsOfficerName() { + return clinicalDetailsOfficerName; + } + + public void setClinicalDetailsOfficerName(String clinicalDetailsOfficerName) { + this.clinicalDetailsOfficerName = clinicalDetailsOfficerName; + } + + public String getClinicalDetailsOfficerPhoneNumber() { + return clinicalDetailsOfficerPhoneNumber; + } + + public void setClinicalDetailsOfficerPhoneNumber(String clinicalDetailsOfficerPhoneNumber) { + this.clinicalDetailsOfficerPhoneNumber = clinicalDetailsOfficerPhoneNumber; + } + + public String getClinicalDetailsOfficerEmail() { + return clinicalDetailsOfficerEmail; + } + + public void setClinicalDetailsOfficerEmail(String clinicalDetailsOfficerEmail) { + this.clinicalDetailsOfficerEmail = clinicalDetailsOfficerEmail; + } + + public String getClinicalDetailsOfficerDesignation() { + return clinicalDetailsOfficerDesignation; + } + + public void setClinicalDetailsOfficerDesignation(String clinicalDetailsOfficerDesignation) { + this.clinicalDetailsOfficerDesignation = clinicalDetailsOfficerDesignation; + } + + public Date getClinicalDetailsDateTime() { + return clinicalDetailsDateTime; + } + + public void setClinicalDetailsDateTime(Date clinicalDetailsDateTime) { + this.clinicalDetailsDateTime = clinicalDetailsDateTime; + } + + public YesNoUnknown getPatientReceivedMedicalCare() { + return patientReceivedMedicalCare; + } + + public void setPatientReceivedMedicalCare(YesNoUnknown patientReceivedMedicalCare) { + this.patientReceivedMedicalCare = patientReceivedMedicalCare; + } + + public String getPatientReceivedMedicalCareDetails() { + return patientReceivedMedicalCareDetails; + } + + public void setPatientReceivedMedicalCareDetails(String patientReceivedMedicalCareDetails) { + this.patientReceivedMedicalCareDetails = patientReceivedMedicalCareDetails; + } + + public String getProvisionalOrFinalDiagnosis() { + return provisionalOrFinalDiagnosis; + } + + public void setProvisionalOrFinalDiagnosis(String provisionalOrFinalDiagnosis) { + this.provisionalOrFinalDiagnosis = provisionalOrFinalDiagnosis; + } + + public AefiImmunizationPeriod getPatientImmunizedPeriod() { + return patientImmunizedPeriod; + } + + public void setPatientImmunizedPeriod(AefiImmunizationPeriod patientImmunizedPeriod) { + this.patientImmunizedPeriod = patientImmunizedPeriod; + } + + public String getPatientImmunizedPeriodDetails() { + return patientImmunizedPeriodDetails; + } + + public void setPatientImmunizedPeriodDetails(String patientImmunizedPeriodDetails) { + this.patientImmunizedPeriodDetails = patientImmunizedPeriodDetails; + } + + public AefiVaccinationPeriod getVaccineGivenPeriod() { + return vaccineGivenPeriod; + } + + public void setVaccineGivenPeriod(AefiVaccinationPeriod vaccineGivenPeriod) { + this.vaccineGivenPeriod = vaccineGivenPeriod; + } + + public String getVaccineGivenPeriodDetails() { + return vaccineGivenPeriodDetails; + } + + public void setVaccineGivenPeriodDetails(String vaccineGivenPeriodDetails) { + this.vaccineGivenPeriodDetails = vaccineGivenPeriodDetails; + } + + public YesNoUnknown getErrorPrescribingVaccine() { + return errorPrescribingVaccine; + } + + public void setErrorPrescribingVaccine(YesNoUnknown errorPrescribingVaccine) { + this.errorPrescribingVaccine = errorPrescribingVaccine; + } + + public String getErrorPrescribingVaccineDetails() { + return errorPrescribingVaccineDetails; + } + + public void setErrorPrescribingVaccineDetails(String errorPrescribingVaccineDetails) { + this.errorPrescribingVaccineDetails = errorPrescribingVaccineDetails; + } + + public YesNoUnknown getVaccineCouldHaveBeenUnSterile() { + return vaccineCouldHaveBeenUnSterile; + } + + public void setVaccineCouldHaveBeenUnSterile(YesNoUnknown vaccineCouldHaveBeenUnSterile) { + this.vaccineCouldHaveBeenUnSterile = vaccineCouldHaveBeenUnSterile; + } + + public String getVaccineCouldHaveBeenUnSterileDetails() { + return vaccineCouldHaveBeenUnSterileDetails; + } + + public void setVaccineCouldHaveBeenUnSterileDetails(String vaccineCouldHaveBeenUnSterileDetails) { + this.vaccineCouldHaveBeenUnSterileDetails = vaccineCouldHaveBeenUnSterileDetails; + } + + public YesNoUnknown getVaccinePhysicalConditionAbnormal() { + return vaccinePhysicalConditionAbnormal; + } + + public void setVaccinePhysicalConditionAbnormal(YesNoUnknown vaccinePhysicalConditionAbnormal) { + this.vaccinePhysicalConditionAbnormal = vaccinePhysicalConditionAbnormal; + } + + public String getVaccinePhysicalConditionAbnormalDetails() { + return vaccinePhysicalConditionAbnormalDetails; + } + + public void setVaccinePhysicalConditionAbnormalDetails(String vaccinePhysicalConditionAbnormalDetails) { + this.vaccinePhysicalConditionAbnormalDetails = vaccinePhysicalConditionAbnormalDetails; + } + + public YesNoUnknown getErrorInVaccineReconstitution() { + return errorInVaccineReconstitution; + } + + public void setErrorInVaccineReconstitution(YesNoUnknown errorInVaccineReconstitution) { + this.errorInVaccineReconstitution = errorInVaccineReconstitution; + } + + public String getErrorInVaccineReconstitutionDetails() { + return errorInVaccineReconstitutionDetails; + } + + public void setErrorInVaccineReconstitutionDetails(String errorInVaccineReconstitutionDetails) { + this.errorInVaccineReconstitutionDetails = errorInVaccineReconstitutionDetails; + } + + public YesNoUnknown getErrorInVaccineHandling() { + return errorInVaccineHandling; + } + + public void setErrorInVaccineHandling(YesNoUnknown errorInVaccineHandling) { + this.errorInVaccineHandling = errorInVaccineHandling; + } + + public String getErrorInVaccineHandlingDetails() { + return errorInVaccineHandlingDetails; + } + + public void setErrorInVaccineHandlingDetails(String errorInVaccineHandlingDetails) { + this.errorInVaccineHandlingDetails = errorInVaccineHandlingDetails; + } + + public YesNoUnknown getVaccineAdministeredIncorrectly() { + return vaccineAdministeredIncorrectly; + } + + public void setVaccineAdministeredIncorrectly(YesNoUnknown vaccineAdministeredIncorrectly) { + this.vaccineAdministeredIncorrectly = vaccineAdministeredIncorrectly; + } + + public String getVaccineAdministeredIncorrectlyDetails() { + return vaccineAdministeredIncorrectlyDetails; + } + + public void setVaccineAdministeredIncorrectlyDetails(String vaccineAdministeredIncorrectlyDetails) { + this.vaccineAdministeredIncorrectlyDetails = vaccineAdministeredIncorrectlyDetails; + } + + public Integer getNumberImmunizedFromConcernedVaccineVial() { + return numberImmunizedFromConcernedVaccineVial; + } + + public void setNumberImmunizedFromConcernedVaccineVial(Integer numberImmunizedFromConcernedVaccineVial) { + this.numberImmunizedFromConcernedVaccineVial = numberImmunizedFromConcernedVaccineVial; + } + + public Integer getNumberImmunizedWithConcernedVaccineInSameSession() { + return numberImmunizedWithConcernedVaccineInSameSession; + } + + public void setNumberImmunizedWithConcernedVaccineInSameSession(Integer numberImmunizedWithConcernedVaccineInSameSession) { + this.numberImmunizedWithConcernedVaccineInSameSession = numberImmunizedWithConcernedVaccineInSameSession; + } + + public Integer getNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations() { + return numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + } + + public void setNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations( + Integer numberImmunizedConcernedVaccineSameBatchNumberOtherLocations) { + this.numberImmunizedConcernedVaccineSameBatchNumberOtherLocations = numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + } + + public String getNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails() { + return numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + } + + public void setNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails( + String numberImmunizedConcernedVaccineSameBatchNumberLocationDetails) { + this.numberImmunizedConcernedVaccineSameBatchNumberLocationDetails = numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + } + + public YesNoUnknown getVaccineHasQualityDefect() { + return vaccineHasQualityDefect; + } + + public void setVaccineHasQualityDefect(YesNoUnknown vaccineHasQualityDefect) { + this.vaccineHasQualityDefect = vaccineHasQualityDefect; + } + + public String getVaccineHasQualityDefectDetails() { + return vaccineHasQualityDefectDetails; + } + + public void setVaccineHasQualityDefectDetails(String vaccineHasQualityDefectDetails) { + this.vaccineHasQualityDefectDetails = vaccineHasQualityDefectDetails; + } + + public YesNoUnknown getEventIsAStressResponseRelatedToImmunization() { + return eventIsAStressResponseRelatedToImmunization; + } + + public void setEventIsAStressResponseRelatedToImmunization(YesNoUnknown eventIsAStressResponseRelatedToImmunization) { + this.eventIsAStressResponseRelatedToImmunization = eventIsAStressResponseRelatedToImmunization; + } + + public String getEventIsAStressResponseRelatedToImmunizationDetails() { + return eventIsAStressResponseRelatedToImmunizationDetails; + } + + public void setEventIsAStressResponseRelatedToImmunizationDetails(String eventIsAStressResponseRelatedToImmunizationDetails) { + this.eventIsAStressResponseRelatedToImmunizationDetails = eventIsAStressResponseRelatedToImmunizationDetails; + } + + public YesNoUnknown getCaseIsPartOfACluster() { + return caseIsPartOfACluster; + } + + public void setCaseIsPartOfACluster(YesNoUnknown caseIsPartOfACluster) { + this.caseIsPartOfACluster = caseIsPartOfACluster; + } + + public String getCaseIsPartOfAClusterDetails() { + return caseIsPartOfAClusterDetails; + } + + public void setCaseIsPartOfAClusterDetails(String caseIsPartOfAClusterDetails) { + this.caseIsPartOfAClusterDetails = caseIsPartOfAClusterDetails; + } + + public Integer getNumberOfCasesDetectedInCluster() { + return numberOfCasesDetectedInCluster; + } + + public void setNumberOfCasesDetectedInCluster(Integer numberOfCasesDetectedInCluster) { + this.numberOfCasesDetectedInCluster = numberOfCasesDetectedInCluster; + } + + public YesNoUnknown getAllCasesInClusterReceivedVaccineFromSameVial() { + return allCasesInClusterReceivedVaccineFromSameVial; + } + + public void setAllCasesInClusterReceivedVaccineFromSameVial(YesNoUnknown allCasesInClusterReceivedVaccineFromSameVial) { + this.allCasesInClusterReceivedVaccineFromSameVial = allCasesInClusterReceivedVaccineFromSameVial; + } + + public String getAllCasesInClusterReceivedVaccineFromSameVialDetails() { + return allCasesInClusterReceivedVaccineFromSameVialDetails; + } + + public void setAllCasesInClusterReceivedVaccineFromSameVialDetails(String allCasesInClusterReceivedVaccineFromSameVialDetails) { + this.allCasesInClusterReceivedVaccineFromSameVialDetails = allCasesInClusterReceivedVaccineFromSameVialDetails; + } + + public Integer getNumberOfVialsUsedInCluster() { + return numberOfVialsUsedInCluster; + } + + public void setNumberOfVialsUsedInCluster(Integer numberOfVialsUsedInCluster) { + this.numberOfVialsUsedInCluster = numberOfVialsUsedInCluster; + } + + public String getNumberOfVialsUsedInClusterDetails() { + return numberOfVialsUsedInClusterDetails; + } + + public void setNumberOfVialsUsedInClusterDetails(String numberOfVialsUsedInClusterDetails) { + this.numberOfVialsUsedInClusterDetails = numberOfVialsUsedInClusterDetails; + } + + public YesNoUnknown getAdSyringesUsedForImmunization() { + return adSyringesUsedForImmunization; + } + + public void setAdSyringesUsedForImmunization(YesNoUnknown adSyringesUsedForImmunization) { + this.adSyringesUsedForImmunization = adSyringesUsedForImmunization; + } + + public SyringeType getTypeOfSyringesUsed() { + return typeOfSyringesUsed; + } + + public void setTypeOfSyringesUsed(SyringeType typeOfSyringesUsed) { + this.typeOfSyringesUsed = typeOfSyringesUsed; + } + + public String getTypeOfSyringesUsedDetails() { + return typeOfSyringesUsedDetails; + } + + public void setTypeOfSyringesUsedDetails(String typeOfSyringesUsedDetails) { + this.typeOfSyringesUsedDetails = typeOfSyringesUsedDetails; + } + + public String getSyringesUsedAdditionalDetails() { + return syringesUsedAdditionalDetails; + } + + public void setSyringesUsedAdditionalDetails(String syringesUsedAdditionalDetails) { + this.syringesUsedAdditionalDetails = syringesUsedAdditionalDetails; + } + + public YesNoUnknown getSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine() { + return sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + } + + public void setSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine( + YesNoUnknown sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine) { + this.sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine = sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + } + + public YesNoUnknown getSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines() { + return sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + } + + public void setSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines( + YesNoUnknown sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines) { + this.sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines = sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + } + + public YesNoUnknown getSameReconstitutionSyringeForEachVaccineVial() { + return sameReconstitutionSyringeForEachVaccineVial; + } + + public void setSameReconstitutionSyringeForEachVaccineVial(YesNoUnknown sameReconstitutionSyringeForEachVaccineVial) { + this.sameReconstitutionSyringeForEachVaccineVial = sameReconstitutionSyringeForEachVaccineVial; + } + + public YesNoUnknown getSameReconstitutionSyringeForEachVaccination() { + return sameReconstitutionSyringeForEachVaccination; + } + + public void setSameReconstitutionSyringeForEachVaccination(YesNoUnknown sameReconstitutionSyringeForEachVaccination) { + this.sameReconstitutionSyringeForEachVaccination = sameReconstitutionSyringeForEachVaccination; + } + + public YesNoUnknown getVaccinesAndDiluentsUsedRecommendedByManufacturer() { + return vaccinesAndDiluentsUsedRecommendedByManufacturer; + } + + public void setVaccinesAndDiluentsUsedRecommendedByManufacturer(YesNoUnknown vaccinesAndDiluentsUsedRecommendedByManufacturer) { + this.vaccinesAndDiluentsUsedRecommendedByManufacturer = vaccinesAndDiluentsUsedRecommendedByManufacturer; + } + + public String getReconstitutionAdditionalDetails() { + return reconstitutionAdditionalDetails; + } + + public void setReconstitutionAdditionalDetails(String reconstitutionAdditionalDetails) { + this.reconstitutionAdditionalDetails = reconstitutionAdditionalDetails; + } + + public YesNoUnknown getCorrectDoseOrRoute() { + return correctDoseOrRoute; + } + + public void setCorrectDoseOrRoute(YesNoUnknown correctDoseOrRoute) { + this.correctDoseOrRoute = correctDoseOrRoute; + } + + public YesNoUnknown getTimeOfReconstitutionMentionedOnTheVial() { + return timeOfReconstitutionMentionedOnTheVial; + } + + public void setTimeOfReconstitutionMentionedOnTheVial(YesNoUnknown timeOfReconstitutionMentionedOnTheVial) { + this.timeOfReconstitutionMentionedOnTheVial = timeOfReconstitutionMentionedOnTheVial; + } + + public YesNoUnknown getNonTouchTechniqueFollowed() { + return nonTouchTechniqueFollowed; + } + + public void setNonTouchTechniqueFollowed(YesNoUnknown nonTouchTechniqueFollowed) { + this.nonTouchTechniqueFollowed = nonTouchTechniqueFollowed; + } + + public YesNoUnknown getContraIndicationScreenedPriorToVaccination() { + return contraIndicationScreenedPriorToVaccination; + } + + public void setContraIndicationScreenedPriorToVaccination(YesNoUnknown contraIndicationScreenedPriorToVaccination) { + this.contraIndicationScreenedPriorToVaccination = contraIndicationScreenedPriorToVaccination; + } + + public Integer getNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays() { + return numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + } + + public void setNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays( + Integer numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays) { + this.numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays = numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + } + + public YesNoUnknown getTrainingReceivedByVaccinator() { + return trainingReceivedByVaccinator; + } + + public void setTrainingReceivedByVaccinator(YesNoUnknown trainingReceivedByVaccinator) { + this.trainingReceivedByVaccinator = trainingReceivedByVaccinator; + } + + public Date getLastTrainingReceivedByVaccinatorDate() { + return lastTrainingReceivedByVaccinatorDate; + } + + public void setLastTrainingReceivedByVaccinatorDate(Date lastTrainingReceivedByVaccinatorDate) { + this.lastTrainingReceivedByVaccinatorDate = lastTrainingReceivedByVaccinatorDate; + } + + public String getInjectionTechniqueAdditionalDetails() { + return injectionTechniqueAdditionalDetails; + } + + public void setInjectionTechniqueAdditionalDetails(String injectionTechniqueAdditionalDetails) { + this.injectionTechniqueAdditionalDetails = injectionTechniqueAdditionalDetails; + } + + public YesNoUnknown getVaccineStorageRefrigeratorTemperatureMonitored() { + return vaccineStorageRefrigeratorTemperatureMonitored; + } + + public void setVaccineStorageRefrigeratorTemperatureMonitored(YesNoUnknown vaccineStorageRefrigeratorTemperatureMonitored) { + this.vaccineStorageRefrigeratorTemperatureMonitored = vaccineStorageRefrigeratorTemperatureMonitored; + } + + public YesNoUnknown getAnyStorageTemperatureDeviationOutsideTwoToEightDegrees() { + return anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + } + + public void setAnyStorageTemperatureDeviationOutsideTwoToEightDegrees(YesNoUnknown anyStorageTemperatureDeviationOutsideTwoToEightDegrees) { + this.anyStorageTemperatureDeviationOutsideTwoToEightDegrees = anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + } + + public String getStorageTemperatureMonitoringAdditionalDetails() { + return storageTemperatureMonitoringAdditionalDetails; + } + + public void setStorageTemperatureMonitoringAdditionalDetails(String storageTemperatureMonitoringAdditionalDetails) { + this.storageTemperatureMonitoringAdditionalDetails = storageTemperatureMonitoringAdditionalDetails; + } + + public YesNoUnknown getCorrectProcedureForStorageFollowed() { + return correctProcedureForStorageFollowed; + } + + public void setCorrectProcedureForStorageFollowed(YesNoUnknown correctProcedureForStorageFollowed) { + this.correctProcedureForStorageFollowed = correctProcedureForStorageFollowed; + } + + public YesNoUnknown getAnyOtherItemInRefrigerator() { + return anyOtherItemInRefrigerator; + } + + public void setAnyOtherItemInRefrigerator(YesNoUnknown anyOtherItemInRefrigerator) { + this.anyOtherItemInRefrigerator = anyOtherItemInRefrigerator; + } + + public YesNoUnknown getPartiallyUsedReconstitutedVaccinesInRefrigerator() { + return partiallyUsedReconstitutedVaccinesInRefrigerator; + } + + public void setPartiallyUsedReconstitutedVaccinesInRefrigerator(YesNoUnknown partiallyUsedReconstitutedVaccinesInRefrigerator) { + this.partiallyUsedReconstitutedVaccinesInRefrigerator = partiallyUsedReconstitutedVaccinesInRefrigerator; + } + + public YesNoUnknown getUnusableVaccinesInRefrigerator() { + return unusableVaccinesInRefrigerator; + } + + public void setUnusableVaccinesInRefrigerator(YesNoUnknown unusableVaccinesInRefrigerator) { + this.unusableVaccinesInRefrigerator = unusableVaccinesInRefrigerator; + } + + public YesNoUnknown getUnusableDiluentsInStore() { + return unusableDiluentsInStore; + } + + public void setUnusableDiluentsInStore(YesNoUnknown unusableDiluentsInStore) { + this.unusableDiluentsInStore = unusableDiluentsInStore; + } + + public String getVaccineStoragePointAdditionalDetails() { + return vaccineStoragePointAdditionalDetails; + } + + public void setVaccineStoragePointAdditionalDetails(String vaccineStoragePointAdditionalDetails) { + this.vaccineStoragePointAdditionalDetails = vaccineStoragePointAdditionalDetails; + } + + public VaccineCarrier getVaccineCarrierType() { + return vaccineCarrierType; + } + + public void setVaccineCarrierType(VaccineCarrier vaccineCarrierType) { + this.vaccineCarrierType = vaccineCarrierType; + } + + public String getVaccineCarrierTypeDetails() { + return vaccineCarrierTypeDetails; + } + + public void setVaccineCarrierTypeDetails(String vaccineCarrierTypeDetails) { + this.vaccineCarrierTypeDetails = vaccineCarrierTypeDetails; + } + + public YesNoUnknown getVaccineCarrierSentToSiteOnSameDateAsVaccination() { + return vaccineCarrierSentToSiteOnSameDateAsVaccination; + } + + public void setVaccineCarrierSentToSiteOnSameDateAsVaccination(YesNoUnknown vaccineCarrierSentToSiteOnSameDateAsVaccination) { + this.vaccineCarrierSentToSiteOnSameDateAsVaccination = vaccineCarrierSentToSiteOnSameDateAsVaccination; + } + + public YesNoUnknown getVaccineCarrierReturnedFromSiteOnSameDateAsVaccination() { + return vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + } + + public void setVaccineCarrierReturnedFromSiteOnSameDateAsVaccination(YesNoUnknown vaccineCarrierReturnedFromSiteOnSameDateAsVaccination) { + this.vaccineCarrierReturnedFromSiteOnSameDateAsVaccination = vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + } + + public YesNoUnknown getConditionedIcepackUsed() { + return conditionedIcepackUsed; + } + + public void setConditionedIcepackUsed(YesNoUnknown conditionedIcepackUsed) { + this.conditionedIcepackUsed = conditionedIcepackUsed; + } + + public String getVaccineTransportationAdditionalDetails() { + return vaccineTransportationAdditionalDetails; + } + + public void setVaccineTransportationAdditionalDetails(String vaccineTransportationAdditionalDetails) { + this.vaccineTransportationAdditionalDetails = vaccineTransportationAdditionalDetails; + } + + public YesNoUnknown getSimilarEventsReportedSamePeriodAndLocality() { + return similarEventsReportedSamePeriodAndLocality; + } + + public void setSimilarEventsReportedSamePeriodAndLocality(YesNoUnknown similarEventsReportedSamePeriodAndLocality) { + this.similarEventsReportedSamePeriodAndLocality = similarEventsReportedSamePeriodAndLocality; + } + + public String getSimilarEventsReportedSamePeriodAndLocalityDetails() { + return similarEventsReportedSamePeriodAndLocalityDetails; + } + + public void setSimilarEventsReportedSamePeriodAndLocalityDetails(String similarEventsReportedSamePeriodAndLocalityDetails) { + this.similarEventsReportedSamePeriodAndLocalityDetails = similarEventsReportedSamePeriodAndLocalityDetails; + } + + public Integer getNumberOfSimilarEventsReportedSamePeriodAndLocality() { + return numberOfSimilarEventsReportedSamePeriodAndLocality; + } + + public void setNumberOfSimilarEventsReportedSamePeriodAndLocality(Integer numberOfSimilarEventsReportedSamePeriodAndLocality) { + this.numberOfSimilarEventsReportedSamePeriodAndLocality = numberOfSimilarEventsReportedSamePeriodAndLocality; + } + + public Integer getNumberOfThoseAffectedVaccinated() { + return numberOfThoseAffectedVaccinated; + } + + public void setNumberOfThoseAffectedVaccinated(Integer numberOfThoseAffectedVaccinated) { + this.numberOfThoseAffectedVaccinated = numberOfThoseAffectedVaccinated; + } + + public Integer getNumberOfThoseAffectedNotVaccinated() { + return numberOfThoseAffectedNotVaccinated; + } + + public void setNumberOfThoseAffectedNotVaccinated(Integer numberOfThoseAffectedNotVaccinated) { + this.numberOfThoseAffectedNotVaccinated = numberOfThoseAffectedNotVaccinated; + } + + public Integer getNumberOfThoseAffectedVaccinatedUnknown() { + return numberOfThoseAffectedVaccinatedUnknown; + } + + public void setNumberOfThoseAffectedVaccinatedUnknown(Integer numberOfThoseAffectedVaccinatedUnknown) { + this.numberOfThoseAffectedVaccinatedUnknown = numberOfThoseAffectedVaccinatedUnknown; + } + + public String getCommunityInvestigationAdditionalDetails() { + return communityInvestigationAdditionalDetails; + } + + public void setCommunityInvestigationAdditionalDetails(String communityInvestigationAdditionalDetails) { + this.communityInvestigationAdditionalDetails = communityInvestigationAdditionalDetails; + } + + public String getOtherInvestigationFindings() { + return otherInvestigationFindings; + } + + public void setOtherInvestigationFindings(String otherInvestigationFindings) { + this.otherInvestigationFindings = otherInvestigationFindings; + } + + public AefiInvestigationStatus getInvestigationStatus() { + return investigationStatus; + } + + public void setInvestigationStatus(AefiInvestigationStatus investigationStatus) { + this.investigationStatus = investigationStatus; + } + + public String getInvestigationStatusDetails() { + return investigationStatusDetails; + } + + public void setInvestigationStatusDetails(String investigationStatusDetails) { + this.investigationStatusDetails = investigationStatusDetails; + } + + public AefiClassification getAefiClassification() { + return aefiClassification; + } + + public void setAefiClassification(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } + + public AefiClassificationSubType getAefiClassificationSubType() { + return aefiClassificationSubType; + } + + public void setAefiClassificationSubType(AefiClassificationSubType aefiClassificationSubType) { + this.aefiClassificationSubType = aefiClassificationSubType; + } + + public String getAefiClassificationDetails() { + return aefiClassificationDetails; + } + + public void setAefiClassificationDetails(String aefiClassificationDetails) { + this.aefiClassificationDetails = aefiClassificationDetails; + } + + public AefiCausality getCausality() { + return causality; + } + + public void setCausality(AefiCausality causality) { + this.causality = causality; + } + + public String getCausalityDetails() { + return causalityDetails; + } + + public void setCausalityDetails(String causalityDetails) { + this.causalityDetails = causalityDetails; + } + + public Date getInvestigationCompletionDate() { + return investigationCompletionDate; + } + + public void setInvestigationCompletionDate(Date investigationCompletionDate) { + this.investigationCompletionDate = investigationCompletionDate; + } + + public boolean isArchived() { + return archived; + } + + public void setArchived(boolean archived) { + this.archived = archived; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public DeletionReason getDeletionReason() { + return deletionReason; + } + + public void setDeletionReason(DeletionReason deletionReason) { + this.deletionReason = deletionReason; + } + + public String getOtherDeletionReason() { + return otherDeletionReason; + } + + public void setOtherDeletionReason(String otherDeletionReason) { + this.otherDeletionReason = otherDeletionReason; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationFacade.java new file mode 100644 index 00000000000..1fff4591f78 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationFacade.java @@ -0,0 +1,29 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.util.List; + +import javax.ejb.Remote; + +import de.symeda.sormas.api.CoreFacade; + +@Remote +public interface AefiInvestigationFacade + extends CoreFacade { + + List getEntriesList(AefiInvestigationListCriteria criteria, Integer first, Integer max); +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationIndexDto.java new file mode 100644 index 00000000000..635e82c75da --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationIndexDto.java @@ -0,0 +1,372 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.PersonalData; +import de.symeda.sormas.api.utils.SensitiveData; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableIndexDto; + +public class AefiInvestigationIndexDto extends PseudonymizableIndexDto implements Serializable, Cloneable { + + private static final long serialVersionUID = 5659752736289073666L; + + public static final String I18N_PREFIX = "AefiInvestigationIndex"; + + public static final String UUID = "uuid"; + public static final String AEFI_REPORT_UUID = "aefiReportUuid"; + public static final String INVESTIGATION_CASE_ID = "investigationCaseId"; + public static final String DISEASE = "disease"; + public static final String PERSON_FIRST_NAME = "personFirstName"; + public static final String PERSON_LAST_NAME = "personLastName"; + public static final String AGE_AND_BIRTH_DATE = "ageAndBirthDate"; + public static final String SEX = "sex"; + public static final String REGION = "region"; + public static final String DISTRICT = "district"; + public static final String PLACE_OF_VACCINATION = "placeOfVaccination"; + public static final String VACCINATION_ACTIVITY = "vaccinationActivity"; + public static final String ADVERSE_EVENT_REPORT_DATE = "adverseEventReportDate"; + public static final String REPORT_DATE = "reportDate"; + public static final String INVESTIGATION_DATE = "investigationDate"; + public static final String INVESTIGATION_STAGE = "investigationStage"; + public static final String TYPE_OF_SITE = "typeOfSite"; + public static final String KEY_SYMPTOM_DATE_TIME = "keySymptomDateTime"; + public static final String HOSPITALIZATION_DATE = "hospitalizationDate"; + public static final String REPORTED_TO_HEALTH_AUTHORITY_DATE = "reportedToHealthAuthorityDate"; + public static final String STATUS_ON_DATE_OF_INVESTIGATION = "statusOnDateOfInvestigation"; + public static final String PRIMARY_VACCINE_NAME = "primaryVaccine"; + public static final String PRIMARY_VACCINE_DETAILS = "primaryVaccineDetails"; + public static final String INVESTIGATION_STATUS = "investigationStatus"; + public static final String AEFI_CLASSIFICATION = "aefiClassification"; + public static final String DELETION_REASON = "deletionReason"; + + private String aefiReportUuid; + private String investigationCaseId; + private Disease disease; + @PersonalData + @SensitiveData + private String personFirstName; + @PersonalData + @SensitiveData + private String personLastName; + private AgeAndBirthDateDto ageAndBirthDate; + private Sex sex; + private String region; + private String district; + private PlaceOfVaccination placeOfVaccination; + private VaccinationActivity vaccinationActivity; + private Date aefiReportDate; + private Date reportDate; + private Date investigationDate; + private AefiInvestigationStage investigationStage; + private VaccinationSite typeOfSite; + private Date keySymptomDateTime; + private Date hospitalizationDate; + private Date reportedToHealthAuthorityDate; + private PatientStatusAtAefiInvestigation statusOnDateOfInvestigation; + private Vaccine primaryVaccine; + private String primaryVaccineDetails; + private AefiInvestigationStatus investigationStatus; + private AefiClassification aefiClassification; + private DeletionReason deletionReason; + private String otherDeletionReason; + private boolean isInJurisdiction; + + public AefiInvestigationIndexDto( + String uuid, + String aefiReportUuid, + String investigationCaseId, + Disease disease, + String personFirstName, + String personLastName, + AgeAndBirthDateDto ageAndBirthDate, + Sex sex, + String region, + String district, + PlaceOfVaccination placeOfVaccination, + VaccinationActivity vaccinationActivity, + Date aefiReportDate, + Date reportDate, + Date investigationDate, + AefiInvestigationStage investigationStage, + VaccinationSite typeOfSite, + Date keySymptomDateTime, + Date hospitalizationDate, + Date reportedToHealthAuthorityDate, + PatientStatusAtAefiInvestigation statusOnDateOfInvestigation, + Vaccine primaryVaccine, + String primaryVaccineDetails, + AefiInvestigationStatus investigationStatus, + AefiClassification aefiClassification, + DeletionReason deletionReason, + String otherDeletionReason, + boolean isInJurisdiction) { + + super(uuid); + this.aefiReportUuid = aefiReportUuid; + this.investigationCaseId = investigationCaseId; + this.disease = disease; + this.personFirstName = personFirstName; + this.personLastName = personLastName; + this.ageAndBirthDate = ageAndBirthDate; + this.sex = sex; + this.region = region; + this.district = district; + this.placeOfVaccination = placeOfVaccination; + this.vaccinationActivity = vaccinationActivity; + this.aefiReportDate = aefiReportDate; + this.reportDate = reportDate; + this.investigationDate = investigationDate; + this.investigationStage = investigationStage; + this.typeOfSite = typeOfSite; + this.keySymptomDateTime = keySymptomDateTime; + this.hospitalizationDate = hospitalizationDate; + this.reportedToHealthAuthorityDate = reportedToHealthAuthorityDate; + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + this.primaryVaccine = primaryVaccine; + this.primaryVaccineDetails = primaryVaccineDetails; + this.investigationStatus = investigationStatus; + this.aefiClassification = aefiClassification; + this.deletionReason = deletionReason; + this.otherDeletionReason = otherDeletionReason; + this.isInJurisdiction = isInJurisdiction; + } + + public String getAefiReportUuid() { + return aefiReportUuid; + } + + public void setAefiReportUuid(String aefiReportUuid) { + this.aefiReportUuid = aefiReportUuid; + } + + public String getInvestigationCaseId() { + return investigationCaseId; + } + + public void setInvestigationCaseId(String investigationCaseId) { + this.investigationCaseId = investigationCaseId; + } + + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + public String getPersonFirstName() { + return personFirstName; + } + + public void setPersonFirstName(String personFirstName) { + this.personFirstName = personFirstName; + } + + public String getPersonLastName() { + return personLastName; + } + + public void setPersonLastName(String personLastName) { + this.personLastName = personLastName; + } + + public AgeAndBirthDateDto getAgeAndBirthDate() { + return ageAndBirthDate; + } + + public void setAgeAndBirthDate(AgeAndBirthDateDto ageAndBirthDate) { + this.ageAndBirthDate = ageAndBirthDate; + } + + public Sex getSex() { + return sex; + } + + public void setSex(Sex sex) { + this.sex = sex; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } + + public PlaceOfVaccination getPlaceOfVaccination() { + return placeOfVaccination; + } + + public void setPlaceOfVaccination(PlaceOfVaccination placeOfVaccination) { + this.placeOfVaccination = placeOfVaccination; + } + + public VaccinationActivity getVaccinationActivity() { + return vaccinationActivity; + } + + public void setVaccinationActivity(VaccinationActivity vaccinationActivity) { + this.vaccinationActivity = vaccinationActivity; + } + + public Date getAefiReportDate() { + return aefiReportDate; + } + + public void setAefiReportDate(Date aefiReportDate) { + this.aefiReportDate = aefiReportDate; + } + + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + public Date getInvestigationDate() { + return investigationDate; + } + + public void setInvestigationDate(Date investigationDate) { + this.investigationDate = investigationDate; + } + + public AefiInvestigationStage getInvestigationStage() { + return investigationStage; + } + + public void setInvestigationStage(AefiInvestigationStage investigationStage) { + this.investigationStage = investigationStage; + } + + public VaccinationSite getTypeOfSite() { + return typeOfSite; + } + + public void setTypeOfSite(VaccinationSite typeOfSite) { + this.typeOfSite = typeOfSite; + } + + public Date getKeySymptomDateTime() { + return keySymptomDateTime; + } + + public void setKeySymptomDateTime(Date keySymptomDateTime) { + this.keySymptomDateTime = keySymptomDateTime; + } + + public Date getHospitalizationDate() { + return hospitalizationDate; + } + + public void setHospitalizationDate(Date hospitalizationDate) { + this.hospitalizationDate = hospitalizationDate; + } + + public Date getReportedToHealthAuthorityDate() { + return reportedToHealthAuthorityDate; + } + + public void setReportedToHealthAuthorityDate(Date reportedToHealthAuthorityDate) { + this.reportedToHealthAuthorityDate = reportedToHealthAuthorityDate; + } + + public PatientStatusAtAefiInvestigation getStatusOnDateOfInvestigation() { + return statusOnDateOfInvestigation; + } + + public void setStatusOnDateOfInvestigation(PatientStatusAtAefiInvestigation statusOnDateOfInvestigation) { + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + } + + public Vaccine getPrimaryVaccine() { + return primaryVaccine; + } + + public void setPrimaryVaccine(Vaccine primaryVaccine) { + this.primaryVaccine = primaryVaccine; + } + + public String getPrimaryVaccineDetails() { + return primaryVaccineDetails; + } + + public void setPrimaryVaccineDetails(String primaryVaccineDetails) { + this.primaryVaccineDetails = primaryVaccineDetails; + } + + public AefiInvestigationStatus getInvestigationStatus() { + return investigationStatus; + } + + public void setInvestigationStatus(AefiInvestigationStatus investigationStatus) { + this.investigationStatus = investigationStatus; + } + + public AefiClassification getAefiClassification() { + return aefiClassification; + } + + public void setAefiClassification(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } + + public DeletionReason getDeletionReason() { + return deletionReason; + } + + public void setDeletionReason(DeletionReason deletionReason) { + this.deletionReason = deletionReason; + } + + public String getOtherDeletionReason() { + return otherDeletionReason; + } + + public void setOtherDeletionReason(String otherDeletionReason) { + this.otherDeletionReason = otherDeletionReason; + } + + @Override + public boolean isInJurisdiction() { + return isInJurisdiction; + } + + @Override + public void setInJurisdiction(boolean inJurisdiction) { + isInJurisdiction = inJurisdiction; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListCriteria.java new file mode 100644 index 00000000000..c150fb25e81 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListCriteria.java @@ -0,0 +1,44 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.utils.criteria.BaseCriteria; + +public class AefiInvestigationListCriteria extends BaseCriteria { + + private final AefiReferenceDto aefiReport; + + public static class Builder { + + private final AefiReferenceDto aefiReferenceDto; + + public Builder(AefiReferenceDto aefiReferenceDto) { + this.aefiReferenceDto = aefiReferenceDto; + } + + public AefiInvestigationListCriteria build() { + return new AefiInvestigationListCriteria(this); + } + } + + private AefiInvestigationListCriteria(AefiInvestigationListCriteria.Builder builder) { + this.aefiReport = builder.aefiReferenceDto; + } + + public AefiReferenceDto getAefiReport() { + return aefiReport; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListEntryDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListEntryDto.java new file mode 100644 index 00000000000..7282075e79a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationListEntryDto.java @@ -0,0 +1,156 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableIndexDto; + +public class AefiInvestigationListEntryDto extends PseudonymizableIndexDto implements Serializable, Cloneable { + + public static final String I18N_PREFIX = "AefiInvestigationListEntry"; + + public static final String UUID = "uuid"; + public static final String INVESTIGATION_CASE_ID = "investigationCaseId"; + public static final String INVESTIGATION_DATE = "investigationDate"; + public static final String INVESTIGATION_STAGE = "investigationStage"; + public static final String STATUS_ON_DATE_OF_INVESTIGATION = "statusOnDateOfInvestigation"; + public static final String PRIMARY_VACCINE_NAME = "primaryVaccine"; + public static final String PRIMARY_VACCINE_DETAILS = "primaryVaccineDetails"; + public static final String PRIMARY_VACCINE_DOSE = "primaryVaccineDose"; + public static final String PRIMARY_VACCINE_VACCINATION_DATE = "primaryVaccineVaccinationDate"; + public static final String INVESTIGATION_STATUS = "investigationStatus"; + public static final String AEFI_CLASSIFICATION = "aefiClassification"; + + private String investigationCaseId; + private Date investigationDate; + private AefiInvestigationStage investigationStage; + private PatientStatusAtAefiInvestigation statusOnDateOfInvestigation; + private Vaccine primaryVaccine; + private String primaryVaccineDetails; + private String primaryVaccineDose; + private Date primaryVaccineVaccinationDate; + private AefiInvestigationStatus investigationStatus; + private AefiClassification aefiClassification; + + public AefiInvestigationListEntryDto( + String uuid, + String investigationCaseId, + Date investigationDate, + AefiInvestigationStage investigationStage, + PatientStatusAtAefiInvestigation statusOnDateOfInvestigation, + Vaccine primaryVaccine, + String primaryVaccineDetails, + String primaryVaccineDose, + Date primaryVaccineVaccinationDate, + AefiInvestigationStatus investigationStatus, + AefiClassification aefiClassification) { + + super(uuid); + this.investigationCaseId = investigationCaseId; + this.investigationDate = investigationDate; + this.investigationStage = investigationStage; + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + this.primaryVaccine = primaryVaccine; + this.primaryVaccineDetails = primaryVaccineDetails; + this.primaryVaccineDose = primaryVaccineDose; + this.primaryVaccineVaccinationDate = primaryVaccineVaccinationDate; + this.investigationStatus = investigationStatus; + this.aefiClassification = aefiClassification; + } + + public String getInvestigationCaseId() { + return investigationCaseId; + } + + public void setInvestigationCaseId(String investigationCaseId) { + this.investigationCaseId = investigationCaseId; + } + + public Date getInvestigationDate() { + return investigationDate; + } + + public void setInvestigationDate(Date investigationDate) { + this.investigationDate = investigationDate; + } + + public AefiInvestigationStage getInvestigationStage() { + return investigationStage; + } + + public void setInvestigationStage(AefiInvestigationStage investigationStage) { + this.investigationStage = investigationStage; + } + + public PatientStatusAtAefiInvestigation getStatusOnDateOfInvestigation() { + return statusOnDateOfInvestigation; + } + + public void setStatusOnDateOfInvestigation(PatientStatusAtAefiInvestigation statusOnDateOfInvestigation) { + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + } + + public Vaccine getPrimaryVaccine() { + return primaryVaccine; + } + + public void setPrimaryVaccine(Vaccine primaryVaccine) { + this.primaryVaccine = primaryVaccine; + } + + public String getPrimaryVaccineDetails() { + return primaryVaccineDetails; + } + + public void setPrimaryVaccineDetails(String primaryVaccineDetails) { + this.primaryVaccineDetails = primaryVaccineDetails; + } + + public String getPrimaryVaccineDose() { + return primaryVaccineDose; + } + + public void setPrimaryVaccineDose(String primaryVaccineDose) { + this.primaryVaccineDose = primaryVaccineDose; + } + + public Date getPrimaryVaccineVaccinationDate() { + return primaryVaccineVaccinationDate; + } + + public void setPrimaryVaccineVaccinationDate(Date primaryVaccineVaccinationDate) { + this.primaryVaccineVaccinationDate = primaryVaccineVaccinationDate; + } + + public AefiInvestigationStatus getInvestigationStatus() { + return investigationStatus; + } + + public void setInvestigationStatus(AefiInvestigationStatus investigationStatus) { + this.investigationStatus = investigationStatus; + } + + public AefiClassification getAefiClassification() { + return aefiClassification; + } + + public void setAefiClassification(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationReferenceDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationReferenceDto.java new file mode 100644 index 00000000000..10d9c77a3a5 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationReferenceDto.java @@ -0,0 +1,42 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.utils.DependingOnFeatureType; + +@DependingOnFeatureType(featureType = FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT) +public class AefiInvestigationReferenceDto extends ReferenceDto { + + private String externalId; + + public AefiInvestigationReferenceDto() { + } + + public AefiInvestigationReferenceDto(String uuid, String externalId) { + super(uuid); + this.externalId = externalId; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStage.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStage.java new file mode 100644 index 00000000000..e6a8d26526e --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStage.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiInvestigationStage { + + FIRST, + INTERIM, + FINAL; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStatus.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStatus.java new file mode 100644 index 00000000000..1506a3c1138 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiInvestigationStatus.java @@ -0,0 +1,33 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiInvestigationStatus { + + DONE, + DISCARDED; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } + + public String toShortString() { + return I18nProperties.getEnumCaptionShort(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListCriteria.java new file mode 100644 index 00000000000..80ae6536c0a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListCriteria.java @@ -0,0 +1,48 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.immunization.ImmunizationReferenceDto; +import de.symeda.sormas.api.utils.criteria.BaseCriteria; + +public class AefiListCriteria extends BaseCriteria { + + private final ImmunizationReferenceDto immunizationReferenceDto; + + public static class Builder { + + private final ImmunizationReferenceDto immunizationReferenceDto; + + public Builder(ImmunizationReferenceDto immunizationReferenceDto) { + this.immunizationReferenceDto = immunizationReferenceDto; + } + + public AefiListCriteria build() { + return new AefiListCriteria(this); + } + } + + private AefiListCriteria(Builder builder) { + this.immunizationReferenceDto = builder.immunizationReferenceDto; + } + + public ImmunizationReferenceDto getImmunization() { + return immunizationReferenceDto; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListEntryDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListEntryDto.java new file mode 100644 index 00000000000..706e97da2b2 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiListEntryDto.java @@ -0,0 +1,97 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.Date; + +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableIndexDto; + +public class AefiListEntryDto extends PseudonymizableIndexDto implements Serializable, Cloneable { + + public static final String I18N_PREFIX = "Aefi"; + + public static final String UUID = "uuid"; + public static final String SERIOUS = "serious"; + public static final String PRIMARY_VACCINE_NAME = "primaryVaccineName"; + public static final String PRIMARY_VACCINE_DOSE = "primaryVaccineDose"; + public static final String PRIMARY_VACCINE_VACCINATION_DATE = "primaryVaccineVaccinationDate"; + private String ADVERSE_EVENTS = "adverseEvents"; + + private YesNoUnknown serious; + private Vaccine primaryVaccineName; + private String primaryVaccineDose; + private Date primaryVaccineVaccinationDate; + private String adverseEvents; + + public AefiListEntryDto( + String uuid, + YesNoUnknown serious, + Vaccine primaryVaccineName, + String primaryVaccineDose, + Date primaryVaccineVaccinationDate, + String adverseEvents) { + + super(uuid); + this.serious = serious; + this.primaryVaccineName = primaryVaccineName; + this.primaryVaccineDose = primaryVaccineDose; + this.primaryVaccineVaccinationDate = primaryVaccineVaccinationDate; + this.adverseEvents = adverseEvents; + } + + public YesNoUnknown getSerious() { + return serious; + } + + public void setSerious(YesNoUnknown serious) { + this.serious = serious; + } + + public Vaccine getPrimaryVaccineName() { + return primaryVaccineName; + } + + public void setPrimaryVaccineName(Vaccine primaryVaccineName) { + this.primaryVaccineName = primaryVaccineName; + } + + public String getPrimaryVaccineDose() { + return primaryVaccineDose; + } + + public void setPrimaryVaccineDose(String primaryVaccineDose) { + this.primaryVaccineDose = primaryVaccineDose; + } + + public Date getPrimaryVaccineVaccinationDate() { + return primaryVaccineVaccinationDate; + } + + public void setPrimaryVaccineVaccinationDate(Date primaryVaccineVaccinationDate) { + this.primaryVaccineVaccinationDate = primaryVaccineVaccinationDate; + } + + public String getAdverseEvents() { + return adverseEvents; + } + + public void setAdverseEvents(String adverseEvents) { + this.adverseEvents = adverseEvents; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiOutcome.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiOutcome.java new file mode 100644 index 00000000000..20d22beacbe --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiOutcome.java @@ -0,0 +1,36 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiOutcome { + + RECOVERING, + RECOVERED, + RECOVERED_WITH_SEQUELAE, + NOT_RECOVERED, + UNKNOWN, + DIED; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiReferenceDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiReferenceDto.java new file mode 100644 index 00000000000..9f992ad8963 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiReferenceDto.java @@ -0,0 +1,42 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.utils.DependingOnFeatureType; + +@DependingOnFeatureType(featureType = FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT) +public class AefiReferenceDto extends ReferenceDto { + + private String externalId; + + public AefiReferenceDto() { + } + + public AefiReferenceDto(String uuid, String externalId) { + super(uuid); + this.externalId = externalId; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiType.java new file mode 100644 index 00000000000..952eb1bc1cd --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiType.java @@ -0,0 +1,41 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.utils.YesNoUnknown; + +public enum AefiType { + + SERIOUS, + NON_SERIOUS; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } + + public static String toString(YesNoUnknown serious) { + if (serious == YesNoUnknown.YES) { + return AefiType.SERIOUS.toString(); + } else { + return AefiType.NON_SERIOUS.toString(); + } + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiVaccinationPeriod.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiVaccinationPeriod.java new file mode 100644 index 00000000000..67bee292daa --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/AefiVaccinationPeriod.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum AefiVaccinationPeriod { + + WITHIN_FIRST_FEW_DOSES, + WITHIN_LAST_DOSES, + UNKNOWN; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/BirthTerm.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/BirthTerm.java new file mode 100644 index 00000000000..11abb53e8d8 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/BirthTerm.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum BirthTerm { + + FULL_TERM, + PRE_TERM, + POST_TERM; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/DeliveryProcedure.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/DeliveryProcedure.java new file mode 100644 index 00000000000..998861a1e6a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/DeliveryProcedure.java @@ -0,0 +1,31 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum DeliveryProcedure { + + NORMAL, + CAESAREAN, + ASSISTED, + WITH_COMPLICATION; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PatientStatusAtAefiInvestigation.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PatientStatusAtAefiInvestigation.java new file mode 100644 index 00000000000..6067cb39260 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PatientStatusAtAefiInvestigation.java @@ -0,0 +1,32 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum PatientStatusAtAefiInvestigation { + + DIED, + DISABLED, + RECOVERED, + RECOVERED_COMPLETELY, + UNKNOWN; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PlaceOfVaccination.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PlaceOfVaccination.java new file mode 100644 index 00000000000..772ca5641a1 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/PlaceOfVaccination.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum PlaceOfVaccination { + + GOVERNMENT_HEALTH_FACILITY, + PRIVATE_HEALTH_FACILITY, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeizureType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeizureType.java new file mode 100644 index 00000000000..d5abb2d27ce --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeizureType.java @@ -0,0 +1,32 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum SeizureType { + + FEBRILE, + AFEBRILE; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiInfoSource.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiInfoSource.java new file mode 100644 index 00000000000..aa21ff6588d --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiInfoSource.java @@ -0,0 +1,31 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum SeriousAefiInfoSource { + + EXAMINATION, + DOCUMENTS, + VERBAL_AUTOPSY, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiReason.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiReason.java new file mode 100644 index 00000000000..17156c90bbd --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SeriousAefiReason.java @@ -0,0 +1,36 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum SeriousAefiReason { + + DEATH, + LIFE_THREATENING, + DISABILITY, + HOSPITALIZATION, + CONGENITAL_ANOMALY, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SyringeType.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SyringeType.java new file mode 100644 index 00000000000..a8161b6c21a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/SyringeType.java @@ -0,0 +1,31 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum SyringeType { + + GLASS, + DISPOSABLE, + RECYCLED_DISPOSABLE, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationActivity.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationActivity.java new file mode 100644 index 00000000000..d7724fb2fc8 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationActivity.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum VaccinationActivity { + + CAMPAIGN, + ROUTINE, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationSite.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationSite.java new file mode 100644 index 00000000000..c4625e1ceed --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccinationSite.java @@ -0,0 +1,32 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum VaccinationSite { + + FIXED, + MOBILE, + OUTREACH, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } + +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccineCarrier.java b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccineCarrier.java new file mode 100644 index 00000000000..86ebe5d47ab --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/adverseeventsfollowingimmunization/VaccineCarrier.java @@ -0,0 +1,30 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.adverseeventsfollowingimmunization; + +import de.symeda.sormas.api.i18n.I18nProperties; + +public enum VaccineCarrier { + + SHORT_RANGE, + LONG_RANGE, + OTHER; + + @Override + public String toString() { + return I18nProperties.getEnumCaption(this); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportCaseDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportCaseDto.java index fc62080b4ef..b7ed1d30462 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportCaseDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportCaseDto.java @@ -24,6 +24,7 @@ import de.symeda.sormas.api.contact.QuarantineType; import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.person.OccupationType; +import de.symeda.sormas.api.person.OccupationTypeConverter; import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; @@ -32,6 +33,7 @@ import de.symeda.sormas.api.utils.YesNoUnknown; public class BAGExportCaseDto implements Serializable { + private Integer caseIdIsm; private Long caseId; private Long personId; @@ -124,7 +126,7 @@ public BAGExportCaseDto(Integer caseIdIsm, Long caseId, Long personId, String homeAddressStreet, String homeAddressHouseNumber, String homeAddressCity, String homeAddressPostalCode, String homeAddressCountry, String phoneNumber, String mobileNumber, String emailAddress, Sex sex, Integer birthdateDD, Integer birthdateMM, Integer birthdateYYYY, - OccupationType occupationType, + String occupationType, boolean symptomatic, Date symptomOnsetDate, String activityMappingYn, Date contactTracingContactDate, @@ -148,7 +150,7 @@ public BAGExportCaseDto(Integer caseIdIsm, Long caseId, Long personId, this.emailAddress = emailAddress; this.sex = sex; this.birthDate = new BirthDateDto(birthdateDD, birthdateMM, birthdateYYYY); - this.occupationType = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationType); this.symptomatic = symptomatic ? YesNoUnknown.YES : YesNoUnknown.NO; this.symptomOnsetDate = symptomOnsetDate; this.activityMappingYn = activityMappingYn; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportContactDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportContactDto.java index bc097ab09e4..f6a08ab2dac 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportContactDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/bagexport/BAGExportContactDto.java @@ -23,6 +23,7 @@ import de.symeda.sormas.api.contact.QuarantineType; import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.person.OccupationType; +import de.symeda.sormas.api.person.OccupationTypeConverter; import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; @@ -91,7 +92,7 @@ public BAGExportContactDto(Long contactId, Long personId, String lastName, Strin String homeAddressStreet, String homeAddressHouseNumber, String homeAddressCity, String homeAddressPostalCode, String phoneNumber, String mobileNumber, Sex sex, Integer birthdateDD, Integer birthdateMM, Integer birthdateYYYY, - OccupationType occupationType, + String occupationType, QuarantineType quarantineType, String quarantineDetails, Integer caseLinkCaseIdIsm, Long caseLinkCaseId, Date caseLinkContactDate, Date startOfQuarantineDate, Date endOfQuarantineDate, EndOfQuarantineReason endOfQuarantineReason, String endOfQuarantineReasonDetails @@ -112,7 +113,7 @@ public BAGExportContactDto(Long contactId, Long personId, String lastName, Strin this.mobileNumber = mobileNumber; this.sex = sex; this.birthDate = new BirthDateDto(birthdateDD, birthdateMM, birthdateYYYY); - this.occupationType = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationType); this.quarantineType = quarantineType; this.quarantineDetails = quarantineDetails; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseCriteria.java index 7e6e398c3d9..0920c1f4874 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseCriteria.java @@ -106,6 +106,9 @@ public class CaseCriteria extends CriteriaWithDateType implements ExternalShareC private Date newCaseDateTo; private Date creationDateFrom; private Date creationDateTo; + private Date birthdateFrom; + private Date birthdateTo; + private boolean includePartialMatch; private CriteriaDateType newCaseDateType; // Used to re-construct whether users have filtered by epi weeks or dates private DateFilterOption dateFilterOption = DateFilterOption.DATE; @@ -552,6 +555,31 @@ public CaseCriteria creationDateTo(Date creationDateTo) { return this; } + public Date getBirthdateFrom() { + return birthdateFrom; + } + + public void setBirthdateFrom(Date birthdateFrom) { + this.birthdateFrom = birthdateFrom; + } + + public Date getBirthdateTo() { + return birthdateTo; + } + + public void setBirthdateTo(Date birthdateTo) { + this.birthdateTo = birthdateTo; + } + + @IgnoreForUrl + public boolean isIncludePartialMatch() { + return includePartialMatch; + } + + public void setIncludePartialMatch(boolean includePartialMatch) { + this.includePartialMatch = includePartialMatch; + } + public Date getQuarantineTo() { return quarantineTo; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index 8500490afa3..34b1a8d986a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -283,16 +283,20 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase { COUNTRY_CODE_SWITZERLAND }) private Date districtLevelDate; @Outbreaks + @Diseases(value = Disease.RESPIRATORY_SYNCYTIAL_VIRUS, hide = true) private CaseClassification caseClassification; @HideForCountriesExcept private CaseIdentificationSource caseIdentificationSource; @HideForCountriesExcept private ScreeningType screeningType; @Outbreaks + @Diseases(value = Disease.RESPIRATORY_SYNCYTIAL_VIRUS, hide = true) private UserReferenceDto classificationUser; @Outbreaks + @Diseases(value = Disease.RESPIRATORY_SYNCYTIAL_VIRUS, hide = true) private Date classificationDate; @Outbreaks + @Diseases(value = Disease.RESPIRATORY_SYNCYTIAL_VIRUS, hide = true) @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String classificationComment; @@ -346,6 +350,7 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase { @Valid @EmbeddedPersonalData @EmbeddedSensitiveData + @SensitiveData private HealthConditionsDto healthConditions; private YesNoUnknown pregnant; @@ -360,6 +365,7 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase { Disease.UNSPECIFIED_VHF, Disease.ANTHRAX, Disease.CORONAVIRUS, + Disease.RESPIRATORY_SYNCYTIAL_VIRUS, Disease.OTHER }) @Outbreaks private VaccinationStatus vaccinationStatus; @@ -509,7 +515,9 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase { COUNTRY_CODE_GERMANY, COUNTRY_CODE_SWITZERLAND }) private Date quarantineOfficialOrderSentDate; + @SensitiveData private YesNoUnknown postpartum; + @SensitiveData private Trimester trimester; private FollowUpStatus followUpStatus; @SensitiveData @@ -567,21 +575,32 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase { private YesNoUnknown bloodOrganOrTissueDonated; @HideForCountriesExcept + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) private boolean notACaseReasonNegativeTest; @HideForCountriesExcept + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) private boolean notACaseReasonPhysicianInformation; @HideForCountriesExcept + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) private boolean notACaseReasonDifferentPathogen; @HideForCountriesExcept + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) private boolean notACaseReasonOther; @HideForCountriesExcept @SensitiveData + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) private String notACaseReasonDetails; + private Date followUpStatusChangeDate; private UserReferenceDto followUpStatusChangeUser; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java index 16265e06647..8a2d221a6db 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java @@ -28,6 +28,7 @@ import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.contact.QuarantineType; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.event.EventStatus; import de.symeda.sormas.api.feature.FeatureType; @@ -49,6 +50,7 @@ import de.symeda.sormas.api.person.BurialConductor; import de.symeda.sormas.api.person.EducationType; import de.symeda.sormas.api.person.OccupationType; +import de.symeda.sormas.api.person.OccupationTypeConverter; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PresentCondition; import de.symeda.sormas.api.person.Salutation; @@ -263,6 +265,7 @@ public class CaseExportDto extends AbstractUuidDto implements IsCase { private String vaccineBatchNumber; private String vaccineUniiCode; private String vaccineAtcCode; + @SensitiveData private HealthConditionsDto healthConditions; private int numberOfPrescriptions; private int numberOfTreatments; @@ -361,7 +364,7 @@ public class CaseExportDto extends AbstractUuidDto implements IsCase { @SuppressWarnings("unchecked") public CaseExportDto(long id, long personId, Double personAddressLatitude, Double personAddressLongitude, Float personAddressLatLonAcc, long epiDataId, long symptomsId, long hospitalizationId, long healthConditionsId, String uuid, String epidNumber, - Disease disease, DiseaseVariant diseaseVariant, String diseaseDetails, String diseaseVariantDetails, + Disease disease, String diseaseVariant, String diseaseDetails, String diseaseVariantDetails, String personUuid, String firstName, String lastName, Salutation salutation, String otherSalutation, Sex sex, YesNoUnknown pregnant, Integer approximateAge, ApproximateAgeType approximateAgeType, Integer birthdateDD, Integer birthdateMM, Integer birthdateYYYY, Date reportDate, String region, String district, String community, @@ -388,7 +391,7 @@ public CaseExportDto(long id, long personId, Double personAddressLatitude, Doubl String addressRegion, String addressDistrict, String addressCommunity, String city, String street, String houseNumber, String additionalInformation, String postalCode, String facility, String facilityUuid, String facilityDetails, String phone, String phoneOwner, String emailAddress, String otherContactDetails, EducationType educationType, String educationDetails, - OccupationType occupationType, String occupationDetails, ArmedForcesRelationType ArmedForcesRelationType, YesNoUnknown contactWithSourceCaseKnown, + String occupationType, String occupationDetails, ArmedForcesRelationType ArmedForcesRelationType, YesNoUnknown contactWithSourceCaseKnown, //Date onsetDate, VaccinationStatus vaccinationStatus, YesNoUnknown postpartum, Trimester trimester, long eventCount, Long prescriptionCount, Long treatmentCount, Long clinicalVisitCount, @@ -418,7 +421,7 @@ public CaseExportDto(long id, long personId, Double personAddressLatitude, Doubl this.armedForcesRelationType = ArmedForcesRelationType; this.disease = disease; this.diseaseDetails = diseaseDetails; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.diseaseVariantDetails = diseaseVariantDetails; this.personUuid = personUuid; this.firstName = firstName; @@ -500,7 +503,7 @@ public CaseExportDto(long id, long personId, Double personAddressLatitude, Doubl this.otherContactDetails = otherContactDetails; this.educationType = educationType; this.educationDetails = educationDetails; - this.occupationType = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationType); this.occupationDetails = occupationDetails; this.contactWithSourceCaseKnown = contactWithSourceCaseKnown; // this.onsetDate = onsetDate; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDetailedDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDetailedDto.java index b1575091f22..1774a17d66a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDetailedDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDetailedDto.java @@ -75,7 +75,7 @@ public class CaseIndexDetailedDto extends CaseIndexDto { //@formatter:off public CaseIndexDetailedDto(long id, String uuid, String epidNumber, String externalID, String externalToken, String internalToken,String caseReferenceNumber, String personUuid, String personFirstName, String personLastName, - Disease disease, DiseaseVariant diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, + Disease disease, String diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, PresentCondition presentCondition, Date reportDate, Date creationDate, String regionUuid, String districtUuid, String healthFacilityUuid, String healthFacilityName, String healthFacilityDetails, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDto.java index 6ab5de5d058..9f1831345e2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseIndexDto.java @@ -25,6 +25,7 @@ import de.symeda.sormas.api.common.DeletionReason; import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.infrastructure.InfrastructureHelper; import de.symeda.sormas.api.infrastructure.facility.FacilityHelper; import de.symeda.sormas.api.person.ApproximateAgeType; @@ -141,7 +142,7 @@ public class CaseIndexDto extends PseudonymizableIndexDto implements MergeableIn //@formatter:off public CaseIndexDto(long id, String uuid, String epidNumber, String externalID, String externalToken, String internalToken, String caseReferenceNumber, String personUuid, String personFirstName, String personLastName, Disease disease, - DiseaseVariant diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, + String diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, PresentCondition presentCondition, Date reportDate, Date creationDate, String regionUuid, String districtUuid, String healthFacilityUuid, String healthFacilityName, String healthFacilityDetails, String pointOfEntryUuid, String pointOfEntryName, String pointOfEntryDetails, String surveillanceOfficerUuid, CaseOutcome outcome, @@ -166,7 +167,7 @@ public CaseIndexDto(long id, String uuid, String epidNumber, String externalID, this.personFirstName = personFirstName; this.personLastName = personLastName; this.disease = disease; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.diseaseDetails = diseaseDetails; this.caseClassification = caseClassification; this.investigationStatus = investigationStatus; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseMergeIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseMergeIndexDto.java index c00c3d5f593..5beb43b4936 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseMergeIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseMergeIndexDto.java @@ -21,7 +21,7 @@ public class CaseMergeIndexDto extends CaseIndexDto { //@formatter:off public CaseMergeIndexDto( long id, String uuid, String epidNumber, String externalID, String externalToken, String internalToken, String caseReferenceNumber, String personUuid, String personFirstName, String personLastName, Disease disease, - DiseaseVariant diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, + String diseaseVariant, String diseaseDetails, CaseClassification caseClassification, InvestigationStatus investigationStatus, PresentCondition presentCondition, Date reportDate, Date creationDate, String regionUuid, String districtUuid, String healthFacilityUuid, String healthFacilityName, String healthFacilityDetails, String pointOfEntryUuid, String pointOfEntryName, String pointOfEntryDetails, String surveillanceOfficerUuid, CaseOutcome outcome, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/PreviousCaseDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/PreviousCaseDto.java index 2e1b5e21c74..59e960bd5ce 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/PreviousCaseDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/PreviousCaseDto.java @@ -17,7 +17,9 @@ import java.util.Date; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.uuid.AbstractUuidDto; public class PreviousCaseDto extends AbstractUuidDto { @@ -29,11 +31,11 @@ public class PreviousCaseDto extends AbstractUuidDto { private final DiseaseVariant diseaseVariant; private final Date onsetDate; - public PreviousCaseDto(String uuid, Date reportDate, String externalToken, DiseaseVariant diseaseVariant, Date onsetDate) { + public PreviousCaseDto(String uuid, Date reportDate, String externalToken, Disease disease, String diseaseVariant, Date onsetDate) { super(uuid); this.reportDate = reportDate; this.externalToken = externalToken; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.onsetDate = onsetDate; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java index d1a41a5e01b..9071192bc8d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/Vaccine.java @@ -59,6 +59,18 @@ public enum Vaccine { @Diseases(value = { Disease.CORONAVIRUS }) SANOFI_GSK(VaccineManufacturer.SANOFI_GSK), + @Diseases(value = { + Disease.CSM }) + MenABCWY(VaccineManufacturer.PFIZER), + @Diseases(value = { + Disease.MONKEYPOX }) + ACAM2000(VaccineManufacturer.SANOFI_PASTEUR_BIOLOGICS), + @Diseases(value = { + Disease.MONKEYPOX }) + LC_16(VaccineManufacturer.KM_BIOLOGICS), + @Diseases(value = { + Disease.MONKEYPOX }) + MVA_BN(VaccineManufacturer.BAVARIAN_NORDIC), UNKNOWN, OTHER; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java index 9d384da94a7..286293d076b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/VaccineManufacturer.java @@ -24,6 +24,12 @@ public enum VaccineManufacturer { @Diseases(value = { Disease.CORONAVIRUS }) BIONTECH_PFIZER, + @Diseases(value = { + Disease.CSM }) + PFIZER, + @Diseases(value = { + Disease.MONKEYPOX }) + BAVARIAN_NORDIC, @Diseases(value = { Disease.CORONAVIRUS }) MODERNA, @@ -33,12 +39,18 @@ public enum VaccineManufacturer { @Diseases(value = { Disease.CORONAVIRUS }) JOHNSON_JOHNSON, + @Diseases(value = { + Disease.MONKEYPOX }) + KM_BIOLOGICS, @Diseases(value = { Disease.CORONAVIRUS }) NOVAVAX, @Diseases(value = { Disease.CORONAVIRUS }) SANOFI_GSK, + @Diseases(value = { + Disease.MONKEYPOX }) + SANOFI_PASTEUR_BIOLOGICS, VALNEVA, UNKNOWN, OTHER; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/common/DeletableEntityType.java b/sormas-api/src/main/java/de/symeda/sormas/api/common/DeletableEntityType.java index 0d01e715da0..0e3a694ec31 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/common/DeletableEntityType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/common/DeletableEntityType.java @@ -23,6 +23,7 @@ public enum DeletableEntityType { EVENT, EVENT_PARTICIPANT, IMMUNIZATION, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION, TRAVEL_ENTRY, CAMPAIGN, SAMPLE, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactCriteria.java index 6f1086e30ea..c96d4349842 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactCriteria.java @@ -136,6 +136,9 @@ public class ContactCriteria extends BaseCriteria implements Serializable { private Boolean onlyContactsFromOtherInstances; private Date creationDateFrom; private Date creationDateTo; + private Date birthdateFrom; + private Date birthdateTo; + private boolean includePartialMatch; private String reportingUserLike; private String personLike; private boolean excludeLimitedSyncRestrictions; @@ -665,6 +668,31 @@ public ContactCriteria creationDateTo(Date creationDateTo) { return this; } + public Date getBirthdateFrom() { + return birthdateFrom; + } + + public void setBirthdateFrom(Date birthdateFrom) { + this.birthdateFrom = birthdateFrom; + } + + public Date getBirthdateTo() { + return birthdateTo; + } + + public void setBirthdateTo(Date birthdateTo) { + this.birthdateTo = birthdateTo; + } + + @IgnoreForUrl + public boolean isIncludePartialMatch() { + return includePartialMatch; + } + + public void setIncludePartialMatch(boolean includePartialMatch) { + this.includePartialMatch = includePartialMatch; + } + public String getReportingUserLike() { return reportingUserLike; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java index fc7e25b832b..615d81675fc 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactDto.java @@ -312,6 +312,7 @@ public class ContactDto extends SormasToSormasShareableDto implements IsContact @Valid private EpiDataDto epiData; @Valid + @SensitiveData private HealthConditionsDto healthConditions; private YesNoUnknown returningTraveler; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactExportDto.java index 36f4dbe34a2..33f49816dbe 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactExportDto.java @@ -46,6 +46,7 @@ import de.symeda.sormas.api.person.ApproximateAgeType.ApproximateAgeHelper; import de.symeda.sormas.api.person.ArmedForcesRelationType; import de.symeda.sormas.api.person.OccupationType; +import de.symeda.sormas.api.person.OccupationTypeConverter; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PresentCondition; import de.symeda.sormas.api.person.Salutation; @@ -259,7 +260,7 @@ public ContactExportDto(long id, long personId, String uuid, String sourceCaseUu PresentCondition presentCondition, Date deathDate, String addressRegion, String addressDistrict, String addressCommunity, String city, String street, String houseNumber, String additionalInformation, String postalCode, String facility, String facilityUuid, String facilityDetails, - String phone, String phoneOwner, String emailAddress, String otherContactDetails, OccupationType occupationType, String occupationDetails, ArmedForcesRelationType armedForcesRelationType, + String phone, String phoneOwner, String emailAddress, String otherContactDetails, String occupationType, String occupationDetails, ArmedForcesRelationType armedForcesRelationType, String region, String district, String community, long epiDataId, YesNoUnknown contactWithSourceCaseKnown, YesNoUnknown returningTraveler, VaccinationStatus vaccinationStatus, String externalID, String externalToken, String internalToken, String caseReferenceNumber, @@ -337,7 +338,7 @@ public ContactExportDto(long id, long personId, String uuid, String sourceCaseUu // this.otherContactDetails += this.otherContactDetails.equals("") ? otherContactDetail : ", " + otherContactDetail; // } this.otherContactDetails = otherContactDetails; - this.occupationType = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationType); this.occupationDetails = occupationDetails; this.armedForcesRelationType = armedForcesRelationType; this.region = region; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java b/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumConverter.java similarity index 81% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java rename to sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumConverter.java index 37ed910f221..3a7ecfd3f88 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumConverter.java @@ -13,17 +13,14 @@ * along with this program. If not, see . */ -package de.symeda.sormas.backend.customizableenum; +package de.symeda.sormas.api.customizableenum; import javax.naming.InitialContext; import javax.naming.NamingException; -import javax.persistence.AttributeConverter; import org.apache.commons.lang3.StringUtils; -import de.symeda.sormas.api.customizableenum.CustomizableEnum; -import de.symeda.sormas.api.customizableenum.CustomizableEnumFacade; -import de.symeda.sormas.api.customizableenum.CustomizableEnumType; +import de.symeda.sormas.api.Disease; /** * JPA Converter that converts a JSON String stored in the database to an instance of {@link CustomizableEnum} and vice versa. @@ -36,7 +33,7 @@ * @param * The specific extension of {@link CustomizableEnum} for type safety */ -public abstract class CustomizableEnumConverter implements AttributeConverter { +public abstract class CustomizableEnumConverter { private final Class enumClass; private CustomizableEnumFacade customizableEnumFacade; @@ -45,13 +42,11 @@ public CustomizableEnumConverter(Class enumClass) { this.enumClass = enumClass; } - @Override public String convertToDatabaseColumn(T enumValue) { return enumValue != null ? enumValue.getValue() : null; } - @Override - public T convertToEntityAttribute(String enumString) { + public T convertToEntityAttribute(Disease disease, String enumString) { if (StringUtils.isBlank(enumString)) { return null; } @@ -66,7 +61,11 @@ public T convertToEntityAttribute(String enumString) { throw new RuntimeException("No CustomizableEnumType for given enumClass " + enumClass + "found"); } - return customizableEnumFacade.getEnumValue(CustomizableEnumType.getByEnumClass(enumClass), enumString); + T enumValue = customizableEnumFacade.getEnumValue(enumType, disease, enumString); + if (enumValue == null && disease != null) { + enumValue = customizableEnumFacade.getEnumValue(enumType, null, enumString); + } + return enumValue; } catch (NamingException e) { throw new RuntimeException(e); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumFacade.java index 9cf74c08a5b..6db95dfd48d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/customizableenum/CustomizableEnumFacade.java @@ -46,11 +46,11 @@ public interface CustomizableEnumFacade * The specific extension of {@link CustomizableEnum} for type safety * @return The enum instance containing its value, internationalized caption, and optional properties */ - T getEnumValue(CustomizableEnumType type, String value); + T getEnumValue(CustomizableEnumType type, Disease disease, String value); /** * Works similar to the {@link CustomizableEnumFacade#getEnumValues(CustomizableEnumType, Disease)}, but looks up a specific value. - * Unlike the {@link CustomizableEnumFacade#getEnumValue(CustomizableEnumType, String)}, this method does not throw a RuntimeException + * Unlike the {@link CustomizableEnumFacade#getEnumValue(CustomizableEnumType, Disease, String)}, this method does not throw a RuntimeException * when an enum can not be found. * * @param type @@ -106,7 +106,7 @@ public interface CustomizableEnumFacade /** * Clears the caches and reloads the customizable enum values from the database. Does not load enum values by language - * or disease as those are retrieved on demand by using {@link #getEnumValue(CustomizableEnumType, String)} and + * or disease as those are retrieved on demand by using {@link #getEnumValue(CustomizableEnumType, Disease, String)} and * {@link #getEnumValues(CustomizableEnumType, Disease)}. Exposed to this facade to allow reloading the caches without * having to restart the server. */ diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/AefiDashboardCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/AefiDashboardCriteria.java new file mode 100644 index 00000000000..cf245b5a25a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/AefiDashboardCriteria.java @@ -0,0 +1,49 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.dashboard; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDashboardFilterDateType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; + +public class AefiDashboardCriteria extends BaseDashboardCriteria { + + private AefiDashboardFilterDateType aefiDashboardFilterDateType; + private AefiType aefiType; + + public AefiDashboardCriteria() { + super(AefiDashboardCriteria.class); + } + + public AefiDashboardFilterDateType getAefiDashboardFilterDateType() { + return aefiDashboardFilterDateType; + } + + public AefiType getAefiType() { + return aefiType; + } + + public AefiDashboardCriteria aefiDashboardDateType(AefiDashboardFilterDateType aefiDashboardFilterDateType) { + this.aefiDashboardFilterDateType = aefiDashboardFilterDateType; + + return self; + } + + public AefiDashboardCriteria aefiType(AefiType aefiType) { + this.aefiType = aefiType; + + return self; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartData.java b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartData.java new file mode 100644 index 00000000000..b6190530a39 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartData.java @@ -0,0 +1,58 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import de.symeda.sormas.api.audit.AuditedClass; + +@AuditedClass +public class AefiChartData implements Serializable { + + private static final long serialVersionUID = 3538219674050390425L; + + private List xAxisCategories = new ArrayList<>(); + private List series = new ArrayList<>(); + + public AefiChartData() { + } + + public List getxAxisCategories() { + return xAxisCategories; + } + + public void setxAxisCategories(List xAxisCategories) { + this.xAxisCategories = xAxisCategories; + } + + public List getSeries() { + return series; + } + + public void setSeries(List series) { + this.series = series; + } + + public void addXAxisCategory(Object category) { + xAxisCategories.add(category); + } + + public void addSeries(AefiChartSeries chartSeries) { + series.add(chartSeries); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartSeries.java b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartSeries.java new file mode 100644 index 00000000000..67824645c4e --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiChartSeries.java @@ -0,0 +1,61 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class AefiChartSeries implements Serializable { + + private static final long serialVersionUID = 8537929721515000783L; + + private Object name; + private String color; + private List seriesData = new ArrayList<>(); + + public AefiChartSeries(Object name) { + this.name = name; + } + + public Object getName() { + return name; + } + + public void setName(Object name) { + this.name = name; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public List getSeriesData() { + return seriesData; + } + + public void setSeriesData(List seriesData) { + this.seriesData = seriesData; + } + + public void addData(String data) { + seriesData.add(data); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacade.java new file mode 100644 index 00000000000..2e6e9c7a087 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacade.java @@ -0,0 +1,47 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Remote; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; + +@Remote +public interface AefiDashboardFacade { + + Map getAefiCountsByType(AefiDashboardCriteria dashboardCriteria); + + Map> getAefiInvestigationCountsByInvestigationStatus(AefiDashboardCriteria dashboardCriteria); + + Map> getAefiInvestigationCountsByAefiClassification(AefiDashboardCriteria dashboardCriteria); + + Map> getAefiCountsByVaccine(AefiDashboardCriteria dashboardCriteria); + + AefiChartData getAefiByVaccineDoseChartData(AefiDashboardCriteria dashboardCriteria); + + AefiChartData getAefiEventsByGenderChartData(AefiDashboardCriteria dashboardCriteria); + + Long countAefiForMap(AefiDashboardCriteria criteria); + + List getAefiForMap(AefiDashboardCriteria criteria); +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/MapAefiDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/MapAefiDto.java new file mode 100644 index 00000000000..66b1f573c05 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/dashboard/adverseeventsfollowingimmunization/MapAefiDto.java @@ -0,0 +1,78 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization; + +import java.io.Serializable; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.utils.YesNoUnknown; + +public class MapAefiDto implements Serializable { + + private static final long serialVersionUID = -7323648840592752250L; + + private Double latitude; + private Double longitude; + + private AefiType aefiType; + + public MapAefiDto(Double longitude, Double latitude, Double associatedEntityLongitude, Double associatedEntityLatitude) { + if (!setLatLonIfPresent(longitude, latitude, null)) + setLatLonIfPresent(associatedEntityLongitude, associatedEntityLatitude, null); + } + + public MapAefiDto( + Double aefiLon, + Double aefiLat, + Double immunizationFacilityLon, + Double immunizationFacilityLat, + Double immunizationPersonLon, + Double immunizationPersonLat, + YesNoUnknown serious) { + + aefiType = serious == YesNoUnknown.YES ? AefiType.SERIOUS : AefiType.NON_SERIOUS; + if (!setLatLonIfPresent(aefiLon, aefiLat, aefiType)) + if (!setLatLonIfPresent(immunizationFacilityLon, immunizationFacilityLat, aefiType)) + setLatLonIfPresent(immunizationPersonLon, immunizationPersonLat, aefiType); + } + + private boolean setLatLonIfPresent(Double longitude, Double latitude, AefiType aefiType) { + if (longitude != null && latitude != null) { + this.longitude = longitude; + this.latitude = latitude; + this.aefiType = aefiType; + + return true; + } + + return false; + } + + public Double getLatitude() { + return latitude; + } + + public Double getLongitude() { + return longitude; + } + + public AefiType getAefiType() { + return aefiType; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseVariantConverter.java b/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseVariantConverter.java similarity index 85% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseVariantConverter.java rename to sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseVariantConverter.java index b94fecb9c6f..d89ffd0d523 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseVariantConverter.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseVariantConverter.java @@ -13,10 +13,9 @@ * along with this program. If not, see . */ -package de.symeda.sormas.backend.disease; +package de.symeda.sormas.api.disease; -import de.symeda.sormas.api.disease.DiseaseVariant; -import de.symeda.sormas.backend.customizableenum.CustomizableEnumConverter; +import de.symeda.sormas.api.customizableenum.CustomizableEnumConverter; public class DiseaseVariantConverter extends CustomizableEnumConverter { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/PathogenConverter.java b/sormas-api/src/main/java/de/symeda/sormas/api/disease/PathogenConverter.java similarity index 89% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/disease/PathogenConverter.java rename to sormas-api/src/main/java/de/symeda/sormas/api/disease/PathogenConverter.java index 92aca033266..43533256f88 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/PathogenConverter.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/disease/PathogenConverter.java @@ -13,10 +13,10 @@ * along with this program. If not, see . */ -package de.symeda.sormas.backend.disease; +package de.symeda.sormas.api.disease; import de.symeda.sormas.api.environment.environmentsample.Pathogen; -import de.symeda.sormas.backend.customizableenum.CustomizableEnumConverter; +import de.symeda.sormas.api.customizableenum.CustomizableEnumConverter; public class PathogenConverter extends CustomizableEnumConverter { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateDto.java new file mode 100644 index 00000000000..9f2e999960a --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateDto.java @@ -0,0 +1,84 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.docgeneneration; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityDto; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.FieldConstraints; + +public class DocumentTemplateDto extends EntityDto { + + private static final long serialVersionUID = 8591649635400893169L; + + public static final String I18N_PREFIX = "DocumentTemplate"; + public static final String DISEASE = "disease"; + public static final String FILE_NAME = "fileName"; + + @NotNull + private DocumentWorkflow workflow; + private Disease disease; + @Size(max = FieldConstraints.CHARACTER_LIMIT_BIG, message = Validations.textTooLong) + private String fileName; + + public static DocumentTemplateDto build(DocumentWorkflow documentWorkflow, String fileName) { + DocumentTemplateDto dto = new DocumentTemplateDto(); + dto.setUuid(DataHelper.createUuid()); + dto.setWorkflow(documentWorkflow); + dto.setFileName(fileName); + + return dto; + } + + public static DocumentTemplateDto build(DocumentWorkflow documentWorkflow, String fileName, Disease disease) { + DocumentTemplateDto dto = build(documentWorkflow, fileName); + dto.setDisease(disease); + + return dto; + } + + public DocumentWorkflow getWorkflow() { + return workflow; + } + + public void setWorkflow(DocumentWorkflow workflow) { + this.workflow = workflow; + } + + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public DocumentTemplateReferenceDto toReference() { + return new DocumentTemplateReferenceDto(getUuid(), fileName); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateFacade.java index ed431525eb3..fff4aca3ad9 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateFacade.java @@ -5,32 +5,33 @@ import javax.ejb.Remote; +import de.symeda.sormas.api.Disease; + @Remote public interface DocumentTemplateFacade { byte[] generateDocumentDocxFromEntities( - DocumentWorkflow documentWorkflow, - String templateName, + DocumentTemplateReferenceDto templateReference, DocumentTemplateEntities entities, Properties extraProperties) throws DocumentTemplateException; String generateDocumentTxtFromEntities( - DocumentWorkflow documentWorkflow, - String templateName, + DocumentTemplateReferenceDto templateReference, DocumentTemplateEntities entities, Properties extraProperties) throws DocumentTemplateException; - List getAvailableTemplates(DocumentWorkflow documentWorkflow); + List getAvailableTemplates(DocumentWorkflow documentWorkflow, Disease disease); - DocumentVariables getDocumentVariables(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException; + boolean isExistingTemplateFile(DocumentWorkflow documentWorkflow, Disease disease, String templateName); - boolean isExistingTemplate(DocumentWorkflow documentWorkflow, String templateName); + DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException; - void writeDocumentTemplate(DocumentWorkflow documentWorkflow, String templateName, byte[] document) throws DocumentTemplateException; + DocumentTemplateDto saveDocumentTemplate(DocumentTemplateDto template, byte[] document) + throws DocumentTemplateException; - boolean deleteDocumentTemplate(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException; + boolean deleteDocumentTemplate(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException; - byte[] getDocumentTemplate(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException; + byte[] getDocumentTemplateContent(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateReferenceDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateReferenceDto.java new file mode 100644 index 00000000000..f3ae8bdbe52 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentTemplateReferenceDto.java @@ -0,0 +1,25 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.docgeneneration; + +import de.symeda.sormas.api.ReferenceDto; + +public class DocumentTemplateReferenceDto extends ReferenceDto { + + public DocumentTemplateReferenceDto(String uuid, String caption) { + super(uuid, caption); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/EventDocumentFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/EventDocumentFacade.java index 3d323c795f8..13971a70757 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/EventDocumentFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/EventDocumentFacade.java @@ -21,23 +21,28 @@ import javax.ejb.Remote; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.event.EventReferenceDto; @Remote public interface EventDocumentFacade { - String getGeneratedDocument(String templateName, EventReferenceDto eventReference, Properties extraProperties, Boolean shouldUploadGeneratedDoc) + String getGeneratedDocument( + DocumentTemplateReferenceDto templateReferenceDto, + EventReferenceDto eventReference, + Properties extraProperties, + Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException; Map getGeneratedDocuments( - String templateName, + DocumentTemplateReferenceDto templateReference, List eventReferences, Properties extraProperties, Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException; - List getAvailableTemplates(); + List getAvailableTemplates(Disease disease); - DocumentVariables getDocumentVariables(String templateName) throws DocumentTemplateException; + DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderDocumentOptionsDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderDocumentOptionsDto.java index dd7e406c78a..6e17f81dbcf 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderDocumentOptionsDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderDocumentOptionsDto.java @@ -1,16 +1,15 @@ package de.symeda.sormas.api.docgeneneration; +import java.io.Serializable; +import java.util.Properties; + import de.symeda.sormas.api.sample.PathogenTestReferenceDto; import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.vaccination.VaccinationReferenceDto; -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.util.Properties; - public class QuarantineOrderDocumentOptionsDto implements Serializable { - private String templateFile; + private DocumentTemplateReferenceDto template; private SampleReferenceDto sample; private PathogenTestReferenceDto pathogenTest; private VaccinationReferenceDto vaccinationReference; @@ -19,12 +18,12 @@ public class QuarantineOrderDocumentOptionsDto implements Serializable { private DocumentWorkflow documentWorkflow; - public String getTemplateFile() { - return templateFile; + public DocumentTemplateReferenceDto getTemplate() { + return template; } - public void setTemplateFile(String templateFile) { - this.templateFile = templateFile; + public void setTemplate(DocumentTemplateReferenceDto template) { + this.template = template; } public SampleReferenceDto getSample() { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderFacade.java index dfda902b11d..66ee00927d3 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/QuarantineOrderFacade.java @@ -32,8 +32,7 @@ public interface QuarantineOrderFacade { byte[] getGeneratedDocument( - String templateName, - DocumentWorkflow workflow, + DocumentTemplateReferenceDto templateReference, RootEntityType rootEntityType, ReferenceDto rootEntityReference, SampleReferenceDto sampleReference, @@ -44,22 +43,21 @@ byte[] getGeneratedDocument( throws DocumentTemplateException; Map getGeneratedDocuments( - String templateName, - DocumentWorkflow workflow, + DocumentTemplateReferenceDto templateReference, List rootEntityReferences, Properties extraProperties, Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException; Map getGeneratedDocumentsForEventParticipants( - String templateName, - List rootEntityReferences, - Disease eventDisease, - Properties extraProperties, - Boolean shouldUploadGeneratedDoc) - throws DocumentTemplateException; + DocumentTemplateReferenceDto templateReference, + List rootEntityReferences, + Disease eventDisease, + Properties extraProperties, + Boolean shouldUploadGeneratedDoc) + throws DocumentTemplateException; - List getAvailableTemplates(DocumentWorkflow workflow); + List getAvailableTemplates(DocumentWorkflow workflow, Disease disease); - DocumentVariables getDocumentVariables(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException; + DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionExportDto.java index f10a26d6eb8..147c45813bd 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionExportDto.java @@ -25,6 +25,7 @@ import de.symeda.sormas.api.action.ActionPriority; import de.symeda.sormas.api.action.ActionStatus; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.importexport.format.ExportFormat; import de.symeda.sormas.api.importexport.format.ImportExportFormat; import de.symeda.sormas.api.user.UserReferenceDto; @@ -64,7 +65,7 @@ public EventActionExportDto( String eventUuid, String eventTitle, Disease eventDisease, - DiseaseVariant eventDiseaseVariant, + String eventDiseaseVariant, String eventDiseaseDetails, String eventDesc, EventIdentificationSource eventIdentificationSource, @@ -98,7 +99,7 @@ public EventActionExportDto( this.eventUuid = eventUuid; this.eventTitle = eventTitle; this.eventDisease = eventDisease; - this.eventDiseaseVariant = eventDiseaseVariant; + this.eventDiseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(eventDisease, eventDiseaseVariant); this.eventDiseaseDetails = eventDiseaseDetails; this.eventDesc = eventDesc; this.eventIdentificationSource = eventIdentificationSource; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionIndexDto.java index 0250bb7708f..6317fec5e5b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventActionIndexDto.java @@ -25,6 +25,7 @@ import de.symeda.sormas.api.action.ActionStatus; import de.symeda.sormas.api.common.DeletionReason; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.user.UserReferenceDto; public class EventActionIndexDto implements Serializable { @@ -87,7 +88,7 @@ public EventActionIndexDto( String eventUuid, String eventTitle, Disease eventDisease, - DiseaseVariant eventDiseaseVariant, + String eventDiseaseVariant, String eventDiseaseDetails, EventIdentificationSource eventIdentificationSource, Date eventStartDate, @@ -113,7 +114,7 @@ public EventActionIndexDto( this.eventUuid = eventUuid; this.eventTitle = eventTitle; this.eventDisease = eventDisease; - this.eventDiseaseVariant = eventDiseaseVariant; + this.eventDiseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(eventDisease, eventDiseaseVariant); this.eventDiseaseDetails = eventDiseaseDetails; this.eventIdentificationSource = eventIdentificationSource; this.eventStartDate = eventStartDate; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java index 6db5fa85872..648098f13be 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventDto.java @@ -167,12 +167,16 @@ public class EventDto extends SormasToSormasShareableDto { private InstitutionalPartnerType srcInstitutionalPartnerType; @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String srcInstitutionalPartnerTypeDetails; + @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String srcFirstName; + @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String srcLastName; + @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String srcTelNo; + @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String srcEmail; @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventExportDto.java index 7ef44af77cf..1c5450ac12a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventExportDto.java @@ -19,6 +19,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.importexport.ExportEntity; import de.symeda.sormas.api.importexport.ExportGroup; import de.symeda.sormas.api.importexport.ExportGroupType; @@ -105,12 +106,12 @@ public EventExportDto( String internalToken, EventStatus eventStatus, RiskLevel riskLevel, - SpecificRisk specificRisk, + String specificRisk, EventInvestigationStatus eventInvestigationStatus, Date eventInvestigationStartDate, Date eventInvestigationEndDate, Disease disease, - DiseaseVariant diseaseVariant, + String diseaseVariant, String diseaseDetails, String diseaseVariantDetails, Date startDate, @@ -160,12 +161,12 @@ public EventExportDto( this.internalToken = internalToken; this.eventStatus = eventStatus; this.riskLevel = riskLevel; - this.specificRisk = specificRisk; + this.specificRisk = new SpecificRiskConverter().convertToEntityAttribute(disease, specificRisk); this.eventInvestigationStatus = eventInvestigationStatus; this.eventInvestigationStartDate = eventInvestigationStartDate; this.eventInvestigationEndDate = eventInvestigationEndDate; this.disease = disease; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.diseaseDetails = diseaseDetails; this.diseaseVariantDetails = diseaseVariantDetails; this.startDate = startDate; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventIndexDto.java index 1f92791d04f..5e2d2031767 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventIndexDto.java @@ -21,6 +21,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.DeletionReason; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.location.LocationReferenceDto; import de.symeda.sormas.api.share.ExternalShareStatus; import de.symeda.sormas.api.user.UserReferenceDto; @@ -129,11 +130,11 @@ public EventIndexDto( String internalToken, EventStatus eventStatus, RiskLevel riskLevel, - SpecificRisk specificRisk, + String specificRisk, EventInvestigationStatus eventInvestigationStatus, EventManagementStatus eventManagementStatus, Disease disease, - DiseaseVariant diseaseVariant, + String diseaseVariant, String diseaseDetails, Date startDate, Date endDate, @@ -174,11 +175,11 @@ public EventIndexDto( this.internalToken = internalToken; this.eventStatus = eventStatus; this.riskLevel = riskLevel; - this.specificRisk = specificRisk; + this.specificRisk = new SpecificRiskConverter().convertToEntityAttribute(disease, specificRisk); this.eventInvestigationStatus = eventInvestigationStatus; this.eventManagementStatus = eventManagementStatus; this.disease = disease; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.diseaseDetails = diseaseDetails; this.startDate = startDate; this.endDate = endDate; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/SpecificRiskConverter.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/SpecificRiskConverter.java similarity index 85% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/event/SpecificRiskConverter.java rename to sormas-api/src/main/java/de/symeda/sormas/api/event/SpecificRiskConverter.java index 58e2f5067f3..789ebdb8f3e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/SpecificRiskConverter.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/SpecificRiskConverter.java @@ -13,10 +13,9 @@ * along with this program. If not, see . */ -package de.symeda.sormas.backend.event; +package de.symeda.sormas.api.event; -import de.symeda.sormas.api.event.SpecificRisk; -import de.symeda.sormas.backend.customizableenum.CustomizableEnumConverter; +import de.symeda.sormas.api.customizableenum.CustomizableEnumConverter; public class SpecificRiskConverter extends CustomizableEnumConverter { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailFacade.java index 127e707212d..c45aa09a2c4 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailFacade.java @@ -24,6 +24,7 @@ import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.common.progress.ProcessedEntity; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.document.DocumentReferenceDto; @@ -33,7 +34,7 @@ @Remote public interface ExternalEmailFacade { - List getTemplateNames(DocumentWorkflow documentWorkflow); + List getTemplates(DocumentWorkflow documentWorkflow); List getAttachableDocuments(DocumentWorkflow documentWorkflow, String relatedEntityUuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsDto.java index 64d40170261..48599792a4a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsDto.java @@ -23,6 +23,7 @@ import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.audit.AuditedClass; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.QuarantineOrderDocumentOptionsDto; import de.symeda.sormas.api.docgeneneration.RootEntityType; @@ -36,7 +37,7 @@ public class ExternalEmailOptionsDto implements Serializable { public static final String I18N_PREFIX = "ExternalEmailOptions"; - public static final String TEMPLATE_NAME = "templateName"; + public static final String TEMPLATE = "template"; public static final String RECIPIENT_EMAIL = "recipientEmail"; public static final String ATTACHED_DOCUMENTS = "attachedDocuments"; @@ -47,8 +48,7 @@ public class ExternalEmailOptionsDto implements Serializable { @NotNull(message = Validations.requiredField) private ReferenceDto rootEntityReference; @NotNull(message = Validations.requiredField) - @Size(min = 1, message = Validations.requiredField) - private String templateName; + private DocumentTemplateReferenceDto template; @NotNull(message = Validations.requiredField) @Size(min = 1, message = Validations.requiredField) private String recipientEmail; @@ -78,12 +78,12 @@ public void setRootEntityReference(ReferenceDto rootEntityReference) { this.rootEntityReference = rootEntityReference; } - public String getTemplateName() { - return templateName; + public DocumentTemplateReferenceDto getTemplate() { + return template; } - public void setTemplateName(String templateName) { - this.templateName = templateName; + public void setTemplate(DocumentTemplateReferenceDto template) { + this.template = template; } public String getRecipientEmail() { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsWithAttachmentsDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsWithAttachmentsDto.java index 366a1e86b8a..1e2e3cee2eb 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsWithAttachmentsDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalemail/ExternalEmailOptionsWithAttachmentsDto.java @@ -21,14 +21,12 @@ package de.symeda.sormas.api.externalemail; import java.io.Serializable; -import java.util.Properties; import java.util.Set; -import javax.validation.Valid; import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import de.symeda.sormas.api.audit.AuditedClass; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EmailAttachementDto; import de.symeda.sormas.api.docgeneneration.QuarantineOrderDocumentOptionsDto; @@ -51,8 +49,7 @@ public class ExternalEmailOptionsWithAttachmentsDto implements Serializable { @NotNull(message = Validations.requiredField) private final RootEntityType rootEntityType; @NotNull(message = Validations.requiredField) - @Size(min = 1, message = Validations.requiredField) - private String templateName; + private DocumentTemplateReferenceDto template; private Set attachedDocuments; private QuarantineOrderDocumentOptionsDto quarantineOrderDocumentOptionsDto; @@ -70,12 +67,12 @@ public RootEntityType getRootEntityType() { return rootEntityType; } - public String getTemplateName() { - return templateName; + public DocumentTemplateReferenceDto getTemplate() { + return template; } - public void setTemplateName(String templateName) { - this.templateName = templateName; + public void setTemplate(DocumentTemplateReferenceDto template) { + this.template = template; } public Set getAttachedDocuments() { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageDto.java index 207ec0ae899..ecd24b99bee 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageDto.java @@ -25,6 +25,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.audit.AuditIncludeProperty; import de.symeda.sormas.api.audit.AuditedClass; +import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.caze.surveillancereport.SurveillanceReportReferenceDto; import de.symeda.sormas.api.disease.DiseaseVariant; import de.symeda.sormas.api.externalmessage.labmessage.SampleReportDto; @@ -41,6 +42,7 @@ import de.symeda.sormas.api.utils.DependingOnFeatureType; import de.symeda.sormas.api.utils.FieldConstraints; import de.symeda.sormas.api.utils.HideForCountriesExcept; +import de.symeda.sormas.api.utils.YesNoUnknown; @AuditedClass @DependingOnFeatureType(featureType = FeatureType.EXTERNAL_MESSAGES) @@ -161,6 +163,10 @@ public class ExternalMessageDto extends SormasToSormasShareableDto { @Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong) private String personAdditionalDetails; + private VaccinationStatus vaccinationStatus; + + private YesNoUnknown admittedToHealthFacility; + public ExternalMessageType getType() { return type; } @@ -433,6 +439,22 @@ public void setSurveillanceReport(SurveillanceReportReferenceDto surveillanceRep this.surveillanceReport = surveillanceReport; } + public VaccinationStatus getVaccinationStatus() { + return vaccinationStatus; + } + + public void setVaccinationStatus(VaccinationStatus vaccinationStatus) { + this.vaccinationStatus = vaccinationStatus; + } + + public YesNoUnknown getAdmittedToHealthFacility() { + return admittedToHealthFacility; + } + + public void setAdmittedToHealthFacility(YesNoUnknown admittedToHealthFacility) { + this.admittedToHealthFacility = admittedToHealthFacility; + } + public static ExternalMessageDto build() { ExternalMessageDto message = new ExternalMessageDto(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageIndexDto.java index 215f48d46d0..c5118d94782 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageIndexDto.java @@ -20,6 +20,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.uuid.AbstractUuidDto; @@ -60,7 +61,7 @@ public ExternalMessageIndexDto( String reporterName, String reporterPostalCode, Disease disease, - DiseaseVariant diseaseVariant, + String diseaseVariant, String personFirstName, String personLastName, Integer personBirthDateYYYY, @@ -78,7 +79,7 @@ public ExternalMessageIndexDto( this.reporterName = reporterName; this.reporterPostalCode = reporterPostalCode; this.disease = disease; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.personFirstName = personFirstName; this.personLastName = personLastName; this.personPostalCode = personPostalCode; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/AbstractProcessingFlow.java b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/AbstractProcessingFlow.java index fefeb32f8ab..5fc5b5bf63f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/AbstractProcessingFlow.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/AbstractProcessingFlow.java @@ -175,6 +175,9 @@ protected CaseDataDto buildCase(PersonDto person, ExternalMessageDto externalMes caseDto.setHealthFacility(processingFacade.getFacilityReferenceByUuid(FacilityDto.NONE_FACILITY_UUID)); } + caseDto.setVaccinationStatus(externalMessageDto.getVaccinationStatus()); + caseDto.getHospitalization().setAdmittedToHealthFacility(externalMessageDto.getAdmittedToHealthFacility()); + return caseDto; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/feature/FeatureType.java b/sormas-api/src/main/java/de/symeda/sormas/api/feature/FeatureType.java index bd3180491d4..ca44b364a12 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/feature/FeatureType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/feature/FeatureType.java @@ -69,6 +69,7 @@ public enum FeatureType { TASK_MANAGEMENT(true, true, null, null, ImmutableMap.of(FeatureTypeProperty.ALLOW_FREE_EDITING, Boolean.FALSE)), WEEKLY_REPORTING(true, true, null, null, null), IMMUNIZATION_MANAGEMENT(true, true, null, null, ImmutableMap.of(FeatureTypeProperty.REDUCED, Boolean.FALSE)), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT(true, false, null, null, ImmutableMap.of(FeatureTypeProperty.REDUCED, Boolean.FALSE)), TRAVEL_ENTRIES(true, false, null, null, null), DASHBOARD_SURVEILLANCE(true, true, null, null, null), diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java index de514090097..1862ce0ba60 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java @@ -40,6 +40,8 @@ public interface Captions { String Action_title = "Action.title"; String actionAccept = "actionAccept"; String actionAdjustChanges = "actionAdjustChanges"; + String actionAefiAssignNewReportingIdNumber = "actionAefiAssignNewReportingIdNumber"; + String actionAefiSelectPrimarySuspectVaccination = "actionAefiSelectPrimarySuspectVaccination"; String actionApply = "actionApply"; String actionApplyDateFilter = "actionApplyDateFilter"; String actionApplyFilters = "actionApplyFilters"; @@ -177,6 +179,348 @@ public interface Captions { String address = "address"; String adoptHomeAddressOfCasePerson = "adoptHomeAddressOfCasePerson"; String adoptHomeAddressOfCasePersonIfRelationMatches = "adoptHomeAddressOfCasePersonIfRelationMatches"; + String AdverseEvents_abscess = "AdverseEvents.abscess"; + String AdverseEvents_anaphylaxis = "AdverseEvents.anaphylaxis"; + String AdverseEvents_encephalopathy = "AdverseEvents.encephalopathy"; + String AdverseEvents_feverishFeeling = "AdverseEvents.feverishFeeling"; + String AdverseEvents_otherAdverseEventDetails = "AdverseEvents.otherAdverseEventDetails"; + String AdverseEvents_seizures = "AdverseEvents.seizures"; + String AdverseEvents_seizureType = "AdverseEvents.seizureType"; + String AdverseEvents_sepsis = "AdverseEvents.sepsis"; + String AdverseEvents_severeLocalReaction = "AdverseEvents.severeLocalReaction"; + String AdverseEvents_severeLocalReactionBeyondNearestJoint = "AdverseEvents.severeLocalReactionBeyondNearestJoint"; + String AdverseEvents_severeLocalReactionMoreThanThreeDays = "AdverseEvents.severeLocalReactionMoreThanThreeDays"; + String AdverseEvents_thrombocytopenia = "AdverseEvents.thrombocytopenia"; + String AdverseEvents_toxicShockSyndrome = "AdverseEvents.toxicShockSyndrome"; + String Aefi_aefiDescription = "Aefi.aefiDescription"; + String Aefi_ageGroup = "Aefi.ageGroup"; + String Aefi_autopsyDone = "Aefi.autopsyDone"; + String Aefi_changeDate = "Aefi.changeDate"; + String Aefi_country = "Aefi.country"; + String Aefi_creationDate = "Aefi.creationDate"; + String Aefi_deathDate = "Aefi.deathDate"; + String Aefi_deletionReason = "Aefi.deletionReason"; + String Aefi_externalId = "Aefi.externalId"; + String Aefi_healthFacility = "Aefi.healthFacility"; + String Aefi_healthFacilityDetails = "Aefi.healthFacilityDetails"; + String Aefi_investigationNeeded = "Aefi.investigationNeeded"; + String Aefi_investigationPlannedDate = "Aefi.investigationPlannedDate"; + String Aefi_lactating = "Aefi.lactating"; + String Aefi_nationalLevelComment = "Aefi.nationalLevelComment"; + String Aefi_onsetAgeDays = "Aefi.onsetAgeDays"; + String Aefi_onsetAgeMonths = "Aefi.onsetAgeMonths"; + String Aefi_onsetAgeYears = "Aefi.onsetAgeYears"; + String Aefi_otherDeletionReason = "Aefi.otherDeletionReason"; + String Aefi_outcome = "Aefi.outcome"; + String Aefi_pastMedicalHistory = "Aefi.pastMedicalHistory"; + String Aefi_pregnant = "Aefi.pregnant"; + String Aefi_primaryVaccineVaccinationDate = "Aefi.primaryVaccineVaccinationDate"; + String Aefi_receivedAtNationalLevelDate = "Aefi.receivedAtNationalLevelDate"; + String Aefi_reportDate = "Aefi.reportDate"; + String Aefi_reporterDepartment = "Aefi.reporterDepartment"; + String Aefi_reporterDesignation = "Aefi.reporterDesignation"; + String Aefi_reporterEmail = "Aefi.reporterEmail"; + String Aefi_reporterInstitution = "Aefi.reporterInstitution"; + String Aefi_reporterName = "Aefi.reporterName"; + String Aefi_reporterPhone = "Aefi.reporterPhone"; + String Aefi_reportingIdNumber = "Aefi.reportingIdNumber"; + String Aefi_reportingUser = "Aefi.reportingUser"; + String Aefi_responsibleCommunity = "Aefi.responsibleCommunity"; + String Aefi_responsibleDistrict = "Aefi.responsibleDistrict"; + String Aefi_responsibleRegion = "Aefi.responsibleRegion"; + String Aefi_serious = "Aefi.serious"; + String Aefi_seriousReason = "Aefi.seriousReason"; + String Aefi_seriousReasonDetails = "Aefi.seriousReasonDetails"; + String Aefi_startDateTime = "Aefi.startDateTime"; + String Aefi_todaysDate = "Aefi.todaysDate"; + String Aefi_trimester = "Aefi.trimester"; + String Aefi_uuid = "Aefi.uuid"; + String Aefi_worldwideId = "Aefi.worldwideId"; + String aefiActiveAdverseEvents = "aefiActiveAdverseEvents"; + String aefiActiveInvestigations = "aefiActiveInvestigations"; + String aefiAefiDataView = "aefiAefiDataView"; + String aefiAefiInvestigationDataView = "aefiAefiInvestigationDataView"; + String aefiAefiInvestigationList = "aefiAefiInvestigationList"; + String aefiAefiList = "aefiAefiList"; + String aefiAllActiveAndArchivedAdverseEvents = "aefiAllActiveAndArchivedAdverseEvents"; + String aefiAllActiveAndArchivedInvestigations = "aefiAllActiveAndArchivedInvestigations"; + String aefiArchivedAdverseEvents = "aefiArchivedAdverseEvents"; + String aefiArchivedInvestigations = "aefiArchivedInvestigations"; + String AefiCriteria_aefiType = "AefiCriteria.aefiType"; + String AefiCriteria_outcome = "AefiCriteria.outcome"; + String AefiCriteria_vaccineManufacturer = "AefiCriteria.vaccineManufacturer"; + String AefiCriteria_vaccineName = "AefiCriteria.vaccineName"; + String aefiDashboardAefiClassificationCoincidentalAdverseEvent = "aefiDashboardAefiClassificationCoincidentalAdverseEvent"; + String aefiDashboardAefiClassificationRelatedToVaccination = "aefiDashboardAefiClassificationRelatedToVaccination"; + String aefiDashboardAefiClassificationUndetermined = "aefiDashboardAefiClassificationUndetermined"; + String aefiDashboardAefiInvestigationDiscarded = "aefiDashboardAefiInvestigationDiscarded"; + String aefiDashboardAefiInvestigationDone = "aefiDashboardAefiInvestigationDone"; + String aefiDashboardAllAefi = "aefiDashboardAllAefi"; + String aefiDashboardAllAefiInvestigation = "aefiDashboardAllAefiInvestigation"; + String aefiDashboardNonSerious = "aefiDashboardNonSerious"; + String aefiDashboardNonSeriousAefi = "aefiDashboardNonSeriousAefi"; + String aefiDashboardSerious = "aefiDashboardSerious"; + String aefiDashboardSeriousAefi = "aefiDashboardSeriousAefi"; + String aefiDashboardShowNonSeriousAefi = "aefiDashboardShowNonSeriousAefi"; + String aefiDashboardShowSeriousAefi = "aefiDashboardShowSeriousAefi"; + String aefiDeletedAdverseEvents = "aefiDeletedAdverseEvents"; + String aefiDeletedInvestigations = "aefiDeletedInvestigations"; + String AefiExport_aefiDescription = "AefiExport.aefiDescription"; + String AefiExport_birthDate = "AefiExport.birthDate"; + String AefiExport_firstName = "AefiExport.firstName"; + String AefiExport_lastName = "AefiExport.lastName"; + String AefiExport_nationalLevelComment = "AefiExport.nationalLevelComment"; + String AefiExport_onsetAgeDays = "AefiExport.onsetAgeDays"; + String AefiExport_onsetAgeGroup = "AefiExport.onsetAgeGroup"; + String AefiExport_onsetAgeMonths = "AefiExport.onsetAgeMonths"; + String AefiExport_onsetAgeYears = "AefiExport.onsetAgeYears"; + String AefiExport_outcome = "AefiExport.outcome"; + String AefiExport_patientAddressCommunity = "AefiExport.patientAddressCommunity"; + String AefiExport_patientAddressDetails = "AefiExport.patientAddressDetails"; + String AefiExport_patientAddressDistrict = "AefiExport.patientAddressDistrict"; + String AefiExport_patientAddressRegion = "AefiExport.patientAddressRegion"; + String AefiExport_primarySuspectVaccineBatchNumber = "AefiExport.primarySuspectVaccineBatchNumber"; + String AefiExport_primarySuspectVaccineBrand = "AefiExport.primarySuspectVaccineBrand"; + String AefiExport_primarySuspectVaccineDiluentBatchNumber = "AefiExport.primarySuspectVaccineDiluentBatchNumber"; + String AefiExport_primarySuspectVaccineDose = "AefiExport.primarySuspectVaccineDose"; + String AefiExport_primarySuspectVaccineManufacturer = "AefiExport.primarySuspectVaccineManufacturer"; + String AefiExport_primarySuspectVaccineName = "AefiExport.primarySuspectVaccineName"; + String AefiExport_primarySuspectVaccineOtherName = "AefiExport.primarySuspectVaccineOtherName"; + String AefiExport_primarySuspectVaccineVaccinationDate = "AefiExport.primarySuspectVaccineVaccinationDate"; + String AefiExport_receivedAtNationalLevelDate = "AefiExport.receivedAtNationalLevelDate"; + String AefiExport_reportDate = "AefiExport.reportDate"; + String AefiExport_reportingIdNumber = "AefiExport.reportingIdNumber"; + String AefiExport_reportingOfficerAddressCountryName = "AefiExport.reportingOfficerAddressCountryName"; + String AefiExport_reportingOfficerDepartment = "AefiExport.reportingOfficerDepartment"; + String AefiExport_reportingOfficerDesignation = "AefiExport.reportingOfficerDesignation"; + String AefiExport_reportingOfficerEmail = "AefiExport.reportingOfficerEmail"; + String AefiExport_reportingOfficerFacilityCommunity = "AefiExport.reportingOfficerFacilityCommunity"; + String AefiExport_reportingOfficerFacilityDistrict = "AefiExport.reportingOfficerFacilityDistrict"; + String AefiExport_reportingOfficerFacilityName = "AefiExport.reportingOfficerFacilityName"; + String AefiExport_reportingOfficerFacilityRegion = "AefiExport.reportingOfficerFacilityRegion"; + String AefiExport_reportingOfficerName = "AefiExport.reportingOfficerName"; + String AefiExport_reportingOfficerPhoneNumber = "AefiExport.reportingOfficerPhoneNumber"; + String AefiExport_serious = "AefiExport.serious"; + String AefiExport_sex = "AefiExport.sex"; + String AefiExport_startDateTime = "AefiExport.startDateTime"; + String AefiExport_vaccinationFacilityCommunity = "AefiExport.vaccinationFacilityCommunity"; + String AefiExport_vaccinationFacilityDistrict = "AefiExport.vaccinationFacilityDistrict"; + String AefiExport_vaccinationFacilityName = "AefiExport.vaccinationFacilityName"; + String AefiExport_vaccinationFacilityRegion = "AefiExport.vaccinationFacilityRegion"; + String AefiExport_worldWideId = "AefiExport.worldWideId"; + String AefiIndex_adverseEvents = "AefiIndex.adverseEvents"; + String AefiIndex_ageAndBirthDate = "AefiIndex.ageAndBirthDate"; + String AefiIndex_disease = "AefiIndex.disease"; + String AefiIndex_district = "AefiIndex.district"; + String AefiIndex_immunizationUuid = "AefiIndex.immunizationUuid"; + String AefiIndex_outcome = "AefiIndex.outcome"; + String AefiIndex_personFirstName = "AefiIndex.personFirstName"; + String AefiIndex_personLastName = "AefiIndex.personLastName"; + String AefiIndex_personUuid = "AefiIndex.personUuid"; + String AefiIndex_primaryVaccine = "AefiIndex.primaryVaccine"; + String AefiIndex_region = "AefiIndex.region"; + String AefiIndex_reportDate = "AefiIndex.reportDate"; + String AefiIndex_serious = "AefiIndex.serious"; + String AefiIndex_sex = "AefiIndex.sex"; + String AefiIndex_startDateTime = "AefiIndex.startDateTime"; + String AefiIndex_uuid = "AefiIndex.uuid"; + String AefiIndex_vaccinationDate = "AefiIndex.vaccinationDate"; + String AefiInvestigation_adSyringesUsedForImmunization = "AefiInvestigation.adSyringesUsedForImmunization"; + String AefiInvestigation_adverseEventAfterPreviousVaccinations = "AefiInvestigation.adverseEventAfterPreviousVaccinations"; + String AefiInvestigation_adverseEventAfterPreviousVaccinationsDetails = "AefiInvestigation.adverseEventAfterPreviousVaccinationsDetails"; + String AefiInvestigation_aefiClassification = "AefiInvestigation.aefiClassification"; + String AefiInvestigation_aefiClassificationDetails = "AefiInvestigation.aefiClassificationDetails"; + String AefiInvestigation_aefiClassificationSubType = "AefiInvestigation.aefiClassificationSubType"; + String AefiInvestigation_allCasesInClusterReceivedVaccineFromSameVial = "AefiInvestigation.allCasesInClusterReceivedVaccineFromSameVial"; + String AefiInvestigation_allCasesInClusterReceivedVaccineFromSameVialDetails = "AefiInvestigation.allCasesInClusterReceivedVaccineFromSameVialDetails"; + String AefiInvestigation_anyOtherItemInRefrigerator = "AefiInvestigation.anyOtherItemInRefrigerator"; + String AefiInvestigation_anyStorageTemperatureDeviationOutsideTwoToEightDegrees = "AefiInvestigation.anyStorageTemperatureDeviationOutsideTwoToEightDegrees"; + String AefiInvestigation_autopsyDate = "AefiInvestigation.autopsyDate"; + String AefiInvestigation_autopsyDone = "AefiInvestigation.autopsyDone"; + String AefiInvestigation_autopsyPlannedDateTime = "AefiInvestigation.autopsyPlannedDateTime"; + String AefiInvestigation_birthTerm = "AefiInvestigation.birthTerm"; + String AefiInvestigation_birthWeight = "AefiInvestigation.birthWeight"; + String AefiInvestigation_caseIsPartOfACluster = "AefiInvestigation.caseIsPartOfACluster"; + String AefiInvestigation_caseIsPartOfAClusterDetails = "AefiInvestigation.caseIsPartOfAClusterDetails"; + String AefiInvestigation_causality = "AefiInvestigation.causality"; + String AefiInvestigation_causalityDetails = "AefiInvestigation.causalityDetails"; + String AefiInvestigation_changeDate = "AefiInvestigation.changeDate"; + String AefiInvestigation_clinicalDetailsDateTime = "AefiInvestigation.clinicalDetailsDateTime"; + String AefiInvestigation_clinicalDetailsOfficerDesignation = "AefiInvestigation.clinicalDetailsOfficerDesignation"; + String AefiInvestigation_clinicalDetailsOfficerEmail = "AefiInvestigation.clinicalDetailsOfficerEmail"; + String AefiInvestigation_clinicalDetailsOfficerName = "AefiInvestigation.clinicalDetailsOfficerName"; + String AefiInvestigation_clinicalDetailsOfficerPhoneNumber = "AefiInvestigation.clinicalDetailsOfficerPhoneNumber"; + String AefiInvestigation_communityInvestigationAdditionalDetails = "AefiInvestigation.communityInvestigationAdditionalDetails"; + String AefiInvestigation_conditionedIcepackUsed = "AefiInvestigation.conditionedIcepackUsed"; + String AefiInvestigation_contraIndicationScreenedPriorToVaccination = "AefiInvestigation.contraIndicationScreenedPriorToVaccination"; + String AefiInvestigation_correctDoseOrRoute = "AefiInvestigation.correctDoseOrRoute"; + String AefiInvestigation_correctProcedureForStorageFollowed = "AefiInvestigation.correctProcedureForStorageFollowed"; + String AefiInvestigation_country = "AefiInvestigation.country"; + String AefiInvestigation_creationDate = "AefiInvestigation.creationDate"; + String AefiInvestigation_currentlyOnConcomitantMedication = "AefiInvestigation.currentlyOnConcomitantMedication"; + String AefiInvestigation_currentlyOnConcomitantMedicationDetails = "AefiInvestigation.currentlyOnConcomitantMedicationDetails"; + String AefiInvestigation_deathDateTime = "AefiInvestigation.deathDateTime"; + String AefiInvestigation_deletionReason = "AefiInvestigation.deletionReason"; + String AefiInvestigation_deliveryProcedure = "AefiInvestigation.deliveryProcedure"; + String AefiInvestigation_deliveryProcedureDetails = "AefiInvestigation.deliveryProcedureDetails"; + String AefiInvestigation_errorInVaccineHandling = "AefiInvestigation.errorInVaccineHandling"; + String AefiInvestigation_errorInVaccineHandlingDetails = "AefiInvestigation.errorInVaccineHandlingDetails"; + String AefiInvestigation_errorInVaccineReconstitution = "AefiInvestigation.errorInVaccineReconstitution"; + String AefiInvestigation_errorInVaccineReconstitutionDetails = "AefiInvestigation.errorInVaccineReconstitutionDetails"; + String AefiInvestigation_errorPrescribingVaccine = "AefiInvestigation.errorPrescribingVaccine"; + String AefiInvestigation_errorPrescribingVaccineDetails = "AefiInvestigation.errorPrescribingVaccineDetails"; + String AefiInvestigation_eventIsAStressResponseRelatedToImmunization = "AefiInvestigation.eventIsAStressResponseRelatedToImmunization"; + String AefiInvestigation_eventIsAStressResponseRelatedToImmunizationDetails = "AefiInvestigation.eventIsAStressResponseRelatedToImmunizationDetails"; + String AefiInvestigation_externalId = "AefiInvestigation.externalId"; + String AefiInvestigation_familyHistoryOfDiseaseOrAllergy = "AefiInvestigation.familyHistoryOfDiseaseOrAllergy"; + String AefiInvestigation_familyHistoryOfDiseaseOrAllergyDetails = "AefiInvestigation.familyHistoryOfDiseaseOrAllergyDetails"; + String AefiInvestigation_firstCaregiversName = "AefiInvestigation.firstCaregiversName"; + String AefiInvestigation_formCompletionDate = "AefiInvestigation.formCompletionDate"; + String AefiInvestigation_historyOfAllergyToVaccineDrugOrFood = "AefiInvestigation.historyOfAllergyToVaccineDrugOrFood"; + String AefiInvestigation_historyOfAllergyToVaccineDrugOrFoodDetails = "AefiInvestigation.historyOfAllergyToVaccineDrugOrFoodDetails"; + String AefiInvestigation_historyOfHospitalizationInLastThirtyDaysWithCause = "AefiInvestigation.historyOfHospitalizationInLastThirtyDaysWithCause"; + String AefiInvestigation_historyOfHospitalizationInLastThirtyDaysWithCauseDetails = "AefiInvestigation.historyOfHospitalizationInLastThirtyDaysWithCauseDetails"; + String AefiInvestigation_hospitalizationDate = "AefiInvestigation.hospitalizationDate"; + String AefiInvestigation_injectionTechniqueAdditionalDetails = "AefiInvestigation.injectionTechniqueAdditionalDetails"; + String AefiInvestigation_investigationCaseId = "AefiInvestigation.investigationCaseId"; + String AefiInvestigation_investigationCompletionDate = "AefiInvestigation.investigationCompletionDate"; + String AefiInvestigation_investigationDate = "AefiInvestigation.investigationDate"; + String AefiInvestigation_investigationStage = "AefiInvestigation.investigationStage"; + String AefiInvestigation_investigationStatus = "AefiInvestigation.investigationStatus"; + String AefiInvestigation_investigationStatusDetails = "AefiInvestigation.investigationStatusDetails"; + String AefiInvestigation_keySymptomDateTime = "AefiInvestigation.keySymptomDateTime"; + String AefiInvestigation_lastTrainingReceivedByVaccinatorDate = "AefiInvestigation.lastTrainingReceivedByVaccinatorDate"; + String AefiInvestigation_nonTouchTechniqueFollowed = "AefiInvestigation.nonTouchTechniqueFollowed"; + String AefiInvestigation_numberImmunizedConcernedVaccineSameBatchNumberLocationDetails = "AefiInvestigation.numberImmunizedConcernedVaccineSameBatchNumberLocationDetails"; + String AefiInvestigation_numberImmunizedConcernedVaccineSameBatchNumberOtherLocations = "AefiInvestigation.numberImmunizedConcernedVaccineSameBatchNumberOtherLocations"; + String AefiInvestigation_numberImmunizedFromConcernedVaccineVial = "AefiInvestigation.numberImmunizedFromConcernedVaccineVial"; + String AefiInvestigation_numberImmunizedWithConcernedVaccineInSameSession = "AefiInvestigation.numberImmunizedWithConcernedVaccineInSameSession"; + String AefiInvestigation_numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays = "AefiInvestigation.numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays"; + String AefiInvestigation_numberOfCasesDetectedInCluster = "AefiInvestigation.numberOfCasesDetectedInCluster"; + String AefiInvestigation_numberOfSimilarEventsReportedSamePeriodAndLocality = "AefiInvestigation.numberOfSimilarEventsReportedSamePeriodAndLocality"; + String AefiInvestigation_numberOfThoseAffectedNotVaccinated = "AefiInvestigation.numberOfThoseAffectedNotVaccinated"; + String AefiInvestigation_numberOfThoseAffectedVaccinated = "AefiInvestigation.numberOfThoseAffectedVaccinated"; + String AefiInvestigation_numberOfThoseAffectedVaccinatedUnknown = "AefiInvestigation.numberOfThoseAffectedVaccinatedUnknown"; + String AefiInvestigation_numberOfVialsUsedInCluster = "AefiInvestigation.numberOfVialsUsedInCluster"; + String AefiInvestigation_numberOfVialsUsedInClusterDetails = "AefiInvestigation.numberOfVialsUsedInClusterDetails"; + String AefiInvestigation_numberOfWeeksPregnant = "AefiInvestigation.numberOfWeeksPregnant"; + String AefiInvestigation_otherCaregiversNames = "AefiInvestigation.otherCaregiversNames"; + String AefiInvestigation_otherDeletionReason = "AefiInvestigation.otherDeletionReason"; + String AefiInvestigation_otherInvestigationFindings = "AefiInvestigation.otherInvestigationFindings"; + String AefiInvestigation_otherSourcesWhoProvidedInfo = "AefiInvestigation.otherSourcesWhoProvidedInfo"; + String AefiInvestigation_partiallyUsedReconstitutedVaccinesInRefrigerator = "AefiInvestigation.partiallyUsedReconstitutedVaccinesInRefrigerator"; + String AefiInvestigation_pastHistoryOfSimilarEvent = "AefiInvestigation.pastHistoryOfSimilarEvent"; + String AefiInvestigation_pastHistoryOfSimilarEventDetails = "AefiInvestigation.pastHistoryOfSimilarEventDetails"; + String AefiInvestigation_patientImmunizedPeriod = "AefiInvestigation.patientImmunizedPeriod"; + String AefiInvestigation_patientImmunizedPeriodDetails = "AefiInvestigation.patientImmunizedPeriodDetails"; + String AefiInvestigation_patientReceivedMedicalCare = "AefiInvestigation.patientReceivedMedicalCare"; + String AefiInvestigation_patientReceivedMedicalCareDetails = "AefiInvestigation.patientReceivedMedicalCareDetails"; + String AefiInvestigation_placeOfVaccination = "AefiInvestigation.placeOfVaccination"; + String AefiInvestigation_placeOfVaccinationDetails = "AefiInvestigation.placeOfVaccinationDetails"; + String AefiInvestigation_preExistingIllnessThirtyDaysOrCongenitalDisorder = "AefiInvestigation.preExistingIllnessThirtyDaysOrCongenitalDisorder"; + String AefiInvestigation_preExistingIllnessThirtyDaysOrCongenitalDisorderDetails = "AefiInvestigation.preExistingIllnessThirtyDaysOrCongenitalDisorderDetails"; + String AefiInvestigation_provisionalOrFinalDiagnosis = "AefiInvestigation.provisionalOrFinalDiagnosis"; + String AefiInvestigation_reconstitutionAdditionalDetails = "AefiInvestigation.reconstitutionAdditionalDetails"; + String AefiInvestigation_reportDate = "AefiInvestigation.reportDate"; + String AefiInvestigation_reportedToHealthAuthorityDate = "AefiInvestigation.reportedToHealthAuthorityDate"; + String AefiInvestigation_reportingOfficerAddress = "AefiInvestigation.reportingOfficerAddress"; + String AefiInvestigation_reportingOfficerDepartment = "AefiInvestigation.reportingOfficerDepartment"; + String AefiInvestigation_reportingOfficerDesignation = "AefiInvestigation.reportingOfficerDesignation"; + String AefiInvestigation_reportingOfficerEmail = "AefiInvestigation.reportingOfficerEmail"; + String AefiInvestigation_reportingOfficerFacility = "AefiInvestigation.reportingOfficerFacility"; + String AefiInvestigation_reportingOfficerFacilityDetails = "AefiInvestigation.reportingOfficerFacilityDetails"; + String AefiInvestigation_reportingOfficerLandlinePhoneNumber = "AefiInvestigation.reportingOfficerLandlinePhoneNumber"; + String AefiInvestigation_reportingOfficerMobilePhoneNumber = "AefiInvestigation.reportingOfficerMobilePhoneNumber"; + String AefiInvestigation_reportingOfficerName = "AefiInvestigation.reportingOfficerName"; + String AefiInvestigation_reportingUser = "AefiInvestigation.reportingUser"; + String AefiInvestigation_responsibleCommunity = "AefiInvestigation.responsibleCommunity"; + String AefiInvestigation_responsibleDistrict = "AefiInvestigation.responsibleDistrict"; + String AefiInvestigation_responsibleRegion = "AefiInvestigation.responsibleRegion"; + String AefiInvestigation_sameReconstitutionSyringeForEachVaccination = "AefiInvestigation.sameReconstitutionSyringeForEachVaccination"; + String AefiInvestigation_sameReconstitutionSyringeForEachVaccineVial = "AefiInvestigation.sameReconstitutionSyringeForEachVaccineVial"; + String AefiInvestigation_sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine = "AefiInvestigation.sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine"; + String AefiInvestigation_sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines = "AefiInvestigation.sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines"; + String AefiInvestigation_seriousAefiInfoSource = "AefiInvestigation.seriousAefiInfoSource"; + String AefiInvestigation_seriousAefiInfoSourceDetails = "AefiInvestigation.seriousAefiInfoSourceDetails"; + String AefiInvestigation_seriousAefiVerbalAutopsyInfoSourceDetails = "AefiInvestigation.seriousAefiVerbalAutopsyInfoSourceDetails"; + String AefiInvestigation_signsAndSymptomsFromTimeOfVaccination = "AefiInvestigation.signsAndSymptomsFromTimeOfVaccination"; + String AefiInvestigation_similarEventsReportedSamePeriodAndLocality = "AefiInvestigation.similarEventsReportedSamePeriodAndLocality"; + String AefiInvestigation_similarEventsReportedSamePeriodAndLocalityDetails = "AefiInvestigation.similarEventsReportedSamePeriodAndLocalityDetails"; + String AefiInvestigation_statusOnDateOfInvestigation = "AefiInvestigation.statusOnDateOfInvestigation"; + String AefiInvestigation_storageTemperatureMonitoringAdditionalDetails = "AefiInvestigation.storageTemperatureMonitoringAdditionalDetails"; + String AefiInvestigation_syringesUsedAdditionalDetails = "AefiInvestigation.syringesUsedAdditionalDetails"; + String AefiInvestigation_timeOfReconstitutionMentionedOnTheVial = "AefiInvestigation.timeOfReconstitutionMentionedOnTheVial"; + String AefiInvestigation_trainingReceivedByVaccinator = "AefiInvestigation.trainingReceivedByVaccinator"; + String AefiInvestigation_typeOfSite = "AefiInvestigation.typeOfSite"; + String AefiInvestigation_typeOfSiteDetails = "AefiInvestigation.typeOfSiteDetails"; + String AefiInvestigation_typeOfSyringesUsed = "AefiInvestigation.typeOfSyringesUsed"; + String AefiInvestigation_typeOfSyringesUsedDetails = "AefiInvestigation.typeOfSyringesUsedDetails"; + String AefiInvestigation_unusableDiluentsInStore = "AefiInvestigation.unusableDiluentsInStore"; + String AefiInvestigation_unusableVaccinesInRefrigerator = "AefiInvestigation.unusableVaccinesInRefrigerator"; + String AefiInvestigation_uuid = "AefiInvestigation.uuid"; + String AefiInvestigation_vaccinationActivity = "AefiInvestigation.vaccinationActivity"; + String AefiInvestigation_vaccinationActivityDetails = "AefiInvestigation.vaccinationActivityDetails"; + String AefiInvestigation_vaccinationFacility = "AefiInvestigation.vaccinationFacility"; + String AefiInvestigation_vaccinationFacilityDetails = "AefiInvestigation.vaccinationFacilityDetails"; + String AefiInvestigation_vaccineAdministeredIncorrectly = "AefiInvestigation.vaccineAdministeredIncorrectly"; + String AefiInvestigation_vaccineAdministeredIncorrectlyDetails = "AefiInvestigation.vaccineAdministeredIncorrectlyDetails"; + String AefiInvestigation_vaccineCarrierReturnedFromSiteOnSameDateAsVaccination = "AefiInvestigation.vaccineCarrierReturnedFromSiteOnSameDateAsVaccination"; + String AefiInvestigation_vaccineCarrierSentToSiteOnSameDateAsVaccination = "AefiInvestigation.vaccineCarrierSentToSiteOnSameDateAsVaccination"; + String AefiInvestigation_vaccineCarrierType = "AefiInvestigation.vaccineCarrierType"; + String AefiInvestigation_vaccineCarrierTypeDetails = "AefiInvestigation.vaccineCarrierTypeDetails"; + String AefiInvestigation_vaccineCouldHaveBeenUnSterile = "AefiInvestigation.vaccineCouldHaveBeenUnSterile"; + String AefiInvestigation_vaccineCouldHaveBeenUnSterileDetails = "AefiInvestigation.vaccineCouldHaveBeenUnSterileDetails"; + String AefiInvestigation_vaccineGivenPeriod = "AefiInvestigation.vaccineGivenPeriod"; + String AefiInvestigation_vaccineGivenPeriodDetails = "AefiInvestigation.vaccineGivenPeriodDetails"; + String AefiInvestigation_vaccineHasQualityDefect = "AefiInvestigation.vaccineHasQualityDefect"; + String AefiInvestigation_vaccineHasQualityDefectDetails = "AefiInvestigation.vaccineHasQualityDefectDetails"; + String AefiInvestigation_vaccinePhysicalConditionAbnormal = "AefiInvestigation.vaccinePhysicalConditionAbnormal"; + String AefiInvestigation_vaccinePhysicalConditionAbnormalDetails = "AefiInvestigation.vaccinePhysicalConditionAbnormalDetails"; + String AefiInvestigation_vaccinesAndDiluentsUsedRecommendedByManufacturer = "AefiInvestigation.vaccinesAndDiluentsUsedRecommendedByManufacturer"; + String AefiInvestigation_vaccineStoragePointAdditionalDetails = "AefiInvestigation.vaccineStoragePointAdditionalDetails"; + String AefiInvestigation_vaccineStorageRefrigeratorTemperatureMonitored = "AefiInvestigation.vaccineStorageRefrigeratorTemperatureMonitored"; + String AefiInvestigation_vaccineTransportationAdditionalDetails = "AefiInvestigation.vaccineTransportationAdditionalDetails"; + String aefiInvestigationClinicalDetailsOfficer = "aefiInvestigationClinicalDetailsOfficer"; + String AefiInvestigationCriteria_aefiClassification = "AefiInvestigationCriteria.aefiClassification"; + String AefiInvestigationCriteria_statusAtAefiInvestigation = "AefiInvestigationCriteria.statusAtAefiInvestigation"; + String AefiInvestigationCriteria_vaccineManufacturer = "AefiInvestigationCriteria.vaccineManufacturer"; + String AefiInvestigationCriteria_vaccineName = "AefiInvestigationCriteria.vaccineName"; + String aefiInvestigationForAdultWomen = "aefiInvestigationForAdultWomen"; + String aefiInvestigationForInfants = "aefiInvestigationForInfants"; + String AefiInvestigationIndex_aefiClassification = "AefiInvestigationIndex.aefiClassification"; + String AefiInvestigationIndex_aefiReportUuid = "AefiInvestigationIndex.aefiReportUuid"; + String AefiInvestigationIndex_ageAndBirthDate = "AefiInvestigationIndex.ageAndBirthDate"; + String AefiInvestigationIndex_disease = "AefiInvestigationIndex.disease"; + String AefiInvestigationIndex_district = "AefiInvestigationIndex.district"; + String AefiInvestigationIndex_investigationCaseId = "AefiInvestigationIndex.investigationCaseId"; + String AefiInvestigationIndex_investigationDate = "AefiInvestigationIndex.investigationDate"; + String AefiInvestigationIndex_investigationStatus = "AefiInvestigationIndex.investigationStatus"; + String AefiInvestigationIndex_personFirstName = "AefiInvestigationIndex.personFirstName"; + String AefiInvestigationIndex_personLastName = "AefiInvestigationIndex.personLastName"; + String AefiInvestigationIndex_primaryVaccine = "AefiInvestigationIndex.primaryVaccine"; + String AefiInvestigationIndex_region = "AefiInvestigationIndex.region"; + String AefiInvestigationIndex_reportDate = "AefiInvestigationIndex.reportDate"; + String AefiInvestigationIndex_sex = "AefiInvestigationIndex.sex"; + String AefiInvestigationIndex_statusOnDateOfInvestigation = "AefiInvestigationIndex.statusOnDateOfInvestigation"; + String AefiInvestigationIndex_uuid = "AefiInvestigationIndex.uuid"; + String AefiInvestigationListEntry_aefiClassification = "AefiInvestigationListEntry.aefiClassification"; + String AefiInvestigationListEntry_investigationDate = "AefiInvestigationListEntry.investigationDate"; + String AefiInvestigationListEntry_investigationStage = "AefiInvestigationListEntry.investigationStage"; + String AefiInvestigationListEntry_statusOnDateOfInvestigation = "AefiInvestigationListEntry.statusOnDateOfInvestigation"; + String aefiInvestigationMedicalCareDetailsInstruction = "aefiInvestigationMedicalCareDetailsInstruction"; + String aefiInvestigationOfThoseAffected = "aefiInvestigationOfThoseAffected"; + String aefiInvestigationReconstitutionProcedure = "aefiInvestigationReconstitutionProcedure"; + String aefiInvestigationSourceOfInformation = "aefiInvestigationSourceOfInformation"; + String aefiNewAdverseEvent = "aefiNewAdverseEvent"; + String aefiNewAefiInvestigation = "aefiNewAefiInvestigation"; + String aefiNewAefiInvestigationStageTitle = "aefiNewAefiInvestigationStageTitle"; + String aefiVaccinationsDiluentBatchLotNumber = "aefiVaccinationsDiluentBatchLotNumber"; + String aefiVaccinationsDiluentExpiryDate = "aefiVaccinationsDiluentExpiryDate"; + String aefiVaccinationsDiluentInformation = "aefiVaccinationsDiluentInformation"; + String aefiVaccinationsDiluentTimeOfReconstitution = "aefiVaccinationsDiluentTimeOfReconstitution"; + String aefiVaccinationsPrimaryVaccine = "aefiVaccinationsPrimaryVaccine"; + String aefiVaccinationsVaccineDetails = "aefiVaccinationsVaccineDetails"; + String aefiVaccinationsVaccineInformation = "aefiVaccinationsVaccineInformation"; String AggregateReport_deaths = "AggregateReport.deaths"; String AggregateReport_disease = "AggregateReport.disease"; String AggregateReport_grouping = "AggregateReport.grouping"; @@ -914,6 +1258,7 @@ public interface Captions { String dashboardNotVisitedFor = "dashboardNotVisitedFor"; String dashboardNotYetClassified = "dashboardNotYetClassified"; String dashboardNotYetClassifiedOnly = "dashboardNotYetClassifiedOnly"; + String dashboardNumberOfAdverseEvents = "dashboardNumberOfAdverseEvents"; String dashboardNumberOfCases = "dashboardNumberOfCases"; String dashboardNumberOfContacts = "dashboardNumberOfContacts"; String dashboardNumberOfSamples = "dashboardNumberOfSamples"; @@ -1049,6 +1394,7 @@ public interface Captions { String documentNoDocuments = "documentNoDocuments"; String DocumentTemplate = "DocumentTemplate"; String DocumentTemplate_buttonUploadTemplate = "DocumentTemplate.buttonUploadTemplate"; + String DocumentTemplate_disease = "DocumentTemplate.disease"; String DocumentTemplate_documentTemplateGuide = "DocumentTemplate.documentTemplateGuide"; String DocumentTemplate_documentUploadWarning = "DocumentTemplate.documentUploadWarning"; String DocumentTemplate_EventHandout = "DocumentTemplate.EventHandout"; @@ -1062,6 +1408,7 @@ public interface Captions { String DocumentTemplate_exampleTemplateEventParticipants = "DocumentTemplate.exampleTemplateEventParticipants"; String DocumentTemplate_exampleTemplateTravelEntries = "DocumentTemplate.exampleTemplateTravelEntries"; String DocumentTemplate_exampleTemplateTravelEntryEmail = "DocumentTemplate.exampleTemplateTravelEntryEmail"; + String DocumentTemplate_fileName = "DocumentTemplate.fileName"; String DocumentTemplate_fileTooBig = "DocumentTemplate.fileTooBig"; String DocumentTemplate_notUploaded = "DocumentTemplate.notUploaded"; String DocumentTemplate_plural = "DocumentTemplate.plural"; @@ -1076,6 +1423,19 @@ public interface Captions { String edit = "edit"; String endDateTime = "endDateTime"; String endOfProcessingDate = "endOfProcessingDate"; + String EntityColumn_CAPTION = "EntityColumn.CAPTION"; + String EntityColumn_DATA_PROTECTION = "EntityColumn.DATA_PROTECTION"; + String EntityColumn_DESCRIPTION = "EntityColumn.DESCRIPTION"; + String EntityColumn_DISEASES = "EntityColumn.DISEASES"; + String EntityColumn_ENTITY = "EntityColumn.ENTITY"; + String EntityColumn_EXCLUSIVE_COUNTRIES = "EntityColumn.EXCLUSIVE_COUNTRIES"; + String EntityColumn_FIELD = "EntityColumn.FIELD"; + String EntityColumn_FIELD_ID = "EntityColumn.FIELD_ID"; + String EntityColumn_IGNORED_COUNTRIES = "EntityColumn.IGNORED_COUNTRIES"; + String EntityColumn_NEW_DISEASE = "EntityColumn.NEW_DISEASE"; + String EntityColumn_OUTBREAKS = "EntityColumn.OUTBREAKS"; + String EntityColumn_REQUIRED = "EntityColumn.REQUIRED"; + String EntityColumn_TYPE = "EntityColumn.TYPE"; String Environment = "Environment"; String Environment_description = "Environment.description"; String Environment_environmentMedia = "Environment.environmentMedia"; @@ -1633,6 +1993,7 @@ public interface Captions { String importSkips = "importSkips"; String importValueSeparator = "importValueSeparator"; String inaccessibleValue = "inaccessibleValue"; + String includePartialBirthdates = "includePartialBirthdates"; String info = "info"; String infrastructureImportAllowOverwrite = "infrastructureImportAllowOverwrite"; String lastName = "lastName"; @@ -1690,6 +2051,7 @@ public interface Captions { String LoginSidebar_outbreakResponse = "LoginSidebar.outbreakResponse"; String LoginSidebar_poweredBy = "LoginSidebar.poweredBy"; String mainMenuAbout = "mainMenuAbout"; + String mainMenuAdverseEvents = "mainMenuAdverseEvents"; String mainMenuAggregateReports = "mainMenuAggregateReports"; String mainMenuCampaigns = "mainMenuCampaigns"; String mainMenuCases = "mainMenuCases"; @@ -1914,6 +2276,7 @@ public interface Captions { String personCreateNew = "personCreateNew"; String personDistrictPrompt = "personDistrictPrompt"; String personFindMatching = "personFindMatching"; + String personFullName = "personFullName"; String personLinkToCases = "personLinkToCases"; String personLinkToContacts = "personLinkToContacts"; String personLinkToEvents = "personLinkToEvents"; @@ -2590,6 +2953,23 @@ public interface Captions { String TestReport_testLabPostalCode = "TestReport.testLabPostalCode"; String TestReport_testResult = "TestReport.testResult"; String TestReport_testType = "TestReport.testType"; + String titleAefiInvestigationBasicDetails = "titleAefiInvestigationBasicDetails"; + String titleAefiInvestigationColdChainAndTransport = "titleAefiInvestigationColdChainAndTransport"; + String titleAefiInvestigationColdChainAndTransportLastVaccineStoragePoint = "titleAefiInvestigationColdChainAndTransportLastVaccineStoragePoint"; + String titleAefiInvestigationColdChainAndTransportSubTitle = "titleAefiInvestigationColdChainAndTransportSubTitle"; + String titleAefiInvestigationColdChainAndTransportVaccineTransportation = "titleAefiInvestigationColdChainAndTransportVaccineTransportation"; + String titleAefiInvestigationCommunityInvestigation = "titleAefiInvestigationCommunityInvestigation"; + String titleAefiInvestigationCommunityInvestigationThoseAffected = "titleAefiInvestigationCommunityInvestigationThoseAffected"; + String titleAefiInvestigationFirstExaminationDetails = "titleAefiInvestigationFirstExaminationDetails"; + String titleAefiInvestigationImmunizationPractices = "titleAefiInvestigationImmunizationPractices"; + String titleAefiInvestigationImmunizationPracticesInjectionTechnique = "titleAefiInvestigationImmunizationPracticesInjectionTechnique"; + String titleAefiInvestigationImmunizationPracticesReconstitution = "titleAefiInvestigationImmunizationPracticesReconstitution"; + String titleAefiInvestigationImmunizationPracticesSubTitle = "titleAefiInvestigationImmunizationPracticesSubTitle"; + String titleAefiInvestigationImmunizationPracticesSyringesAndNeedlesUsed = "titleAefiInvestigationImmunizationPracticesSyringesAndNeedlesUsed"; + String titleAefiInvestigationInvestigationStatus = "titleAefiInvestigationInvestigationStatus"; + String titleAefiInvestigationOtherFindings = "titleAefiInvestigationOtherFindings"; + String titleAefiInvestigationRelevantPatientInformation = "titleAefiInvestigationRelevantPatientInformation"; + String titleAefiInvestigationVaccinesDetails = "titleAefiInvestigationVaccinesDetails"; String to = "to"; String total = "total"; String travelEntriesNoTravelEntriesForPerson = "travelEntriesNoTravelEntriesForPerson"; @@ -2748,6 +3128,8 @@ public interface Captions { String versionIsMissing = "versionIsMissing"; String view = "view"; String View_actions = "View.actions"; + String View_adverseevents = "View.adverseevents"; + String View_adverseevents_investigations = "View.adverseevents.investigations"; String View_aggregatereports = "View.aggregatereports"; String View_aggregatereports_aggregatereporting = "View.aggregatereports.aggregatereporting"; String View_aggregatereports_reportdata = "View.aggregatereports.reportdata"; @@ -2821,6 +3203,7 @@ public interface Captions { String View_contacts_person = "View.contacts.person"; String View_contacts_sub = "View.contacts.sub"; String View_contacts_visits = "View.contacts.visits"; + String View_dashboard_adverseevents = "View.dashboard.adverseevents"; String View_dashboard_campaigns = "View.dashboard.campaigns"; String View_dashboard_contacts = "View.dashboard.contacts"; String View_dashboard_samples = "View.dashboard.samples"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Descriptions.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Descriptions.java index 2b093c11be0..52a5bfebaef 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Descriptions.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Descriptions.java @@ -10,6 +10,10 @@ public interface Descriptions { * 1. java:S115: Violation of name convention for constants of this class is accepted: Close as false positive. */ + String aefiDashboardDiseaseFilter = "aefiDashboardDiseaseFilter"; + String aefiDashboardDistrictFilter = "aefiDashboardDistrictFilter"; + String aefiDashboardRegionFilter = "aefiDashboardRegionFilter"; + String birthdateFilterPartialMatchDescription = "birthdateFilterPartialMatchDescription"; String Campaign_calculatedBasedOn = "Campaign.calculatedBasedOn"; String Campaign_campaignPhase = "Campaign.campaignPhase"; String CaseData_caseClassification = "CaseData.caseClassification"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index ed87fae2ee3..20a31f30878 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -53,6 +53,8 @@ public interface Strings { String close = "close"; String comparedTo = "comparedTo"; String confirmationAlsoAdjustQuarantine = "confirmationAlsoAdjustQuarantine"; + String confirmationArchiveAdverseEvent = "confirmationArchiveAdverseEvent"; + String confirmationArchiveAdverseEventInvestigation = "confirmationArchiveAdverseEventInvestigation"; String confirmationArchiveArea = "confirmationArchiveArea"; String confirmationArchiveAreas = "confirmationArchiveAreas"; String confirmationArchiveCampaign = "confirmationArchiveCampaign"; @@ -96,6 +98,8 @@ public interface Strings { String confirmationCancelFollowUp = "confirmationCancelFollowUp"; String confirmationChangeCaseDisease = "confirmationChangeCaseDisease"; String confirmationContactSourceCaseDiscardUnsavedChanges = "confirmationContactSourceCaseDiscardUnsavedChanges"; + String confirmationDearchiveAdverseEvent = "confirmationDearchiveAdverseEvent"; + String confirmationDearchiveAdverseEventInvestigation = "confirmationDearchiveAdverseEventInvestigation"; String confirmationDearchiveArea = "confirmationDearchiveArea"; String confirmationDearchiveAreas = "confirmationDearchiveAreas"; String confirmationDearchiveCampaign = "confirmationDearchiveCampaign"; @@ -217,6 +221,10 @@ public interface Strings { String entityActivityAsCase = "entityActivityAsCase"; String entityAdditionalTest = "entityAdditionalTest"; String entityAdditionalTests = "entityAdditionalTests"; + String entityAdverseEvent = "entityAdverseEvent"; + String entityAdverseEventInvestigation = "entityAdverseEventInvestigation"; + String entityAdverseEventInvestigations = "entityAdverseEventInvestigations"; + String entityAdverseEvents = "entityAdverseEvents"; String entityAggregateReports = "entityAggregateReports"; String entityAreas = "entityAreas"; String entityAutomaticSoftDeletion = "entityAutomaticSoftDeletion"; @@ -298,6 +306,8 @@ public interface Strings { String entityWeeklyReports = "entityWeeklyReports"; String epiWeek = "epiWeek"; String errorAccessDenied = "errorAccessDenied"; + String errorAdverseEventInvestigationNotEditable = "errorAdverseEventInvestigationNotEditable"; + String errorAdverseEventNotEditable = "errorAdverseEventNotEditable"; String errorCampaignDiagramTotalsCalculationError = "errorCampaignDiagramTotalsCalculationError"; String errorCampaignNotEditable = "errorCampaignNotEditable"; String errorCaseDuplicateDeletion = "errorCaseDuplicateDeletion"; @@ -315,6 +325,7 @@ public interface Strings { String errorDeletingDocumentTemplate = "errorDeletingDocumentTemplate"; String errorDocumentGeneration = "errorDocumentGeneration"; String errorDocumentGenerationMultipleDiseasses = "errorDocumentGenerationMultipleDiseasses"; + String errorDocumentTemplateWorkflowChangeNotAllowed = "errorDocumentTemplateWorkflowChangeNotAllowed"; String errorEntityNotEditable = "errorEntityNotEditable"; String errorEntityOutdated = "errorEntityOutdated"; String errorEnvironmentSampleNoDispatchRight = "errorEnvironmentSampleNoDispatchRight"; @@ -412,9 +423,25 @@ public interface Strings { String headingActivityAsCaseDetails = "headingActivityAsCaseDetails"; String headingAdditionalTests = "headingAdditionalTests"; String headingAdjustQuarantine = "headingAdjustQuarantine"; + String headingAefiAdverseEvents = "headingAefiAdverseEvents"; + String headingAefiDashboardEpiCurve = "headingAefiDashboardEpiCurve"; + String headingAefiDashboardMap = "headingAefiDashboardMap"; + String headingAefiFirstDecisionLevel = "headingAefiFirstDecisionLevel"; + String headingAefiInvestigationFormSubHeading = "headingAefiInvestigationFormSubHeading"; + String headingAefiInvestigationSelectConcernedVaccine = "headingAefiInvestigationSelectConcernedVaccine"; + String headingAefiNationalDecisionLevel = "headingAefiNationalDecisionLevel"; + String headingAefiPatientsAgeAtOnset = "headingAefiPatientsAgeAtOnset"; + String headingAefiPatientsIdentification = "headingAefiPatientsIdentification"; + String headingAefiReportersInformation = "headingAefiReportersInformation"; + String headingAefiReportingInformation = "headingAefiReportingInformation"; + String headingAefiReportInvestigations = "headingAefiReportInvestigations"; + String headingAefiSelectPrimarySuspectVaccine = "headingAefiSelectPrimarySuspectVaccine"; + String headingAefiVaccinations = "headingAefiVaccinations"; String headingAllContacts = "headingAllContacts"; String headingAnimalContactDetails = "headingAnimalContactDetails"; String headingAnimalContacts = "headingAnimalContacts"; + String headingArchiveAdverseEvent = "headingArchiveAdverseEvent"; + String headingArchiveAdverseEventInvestigation = "headingArchiveAdverseEventInvestigation"; String headingArchiveCampaign = "headingArchiveCampaign"; String headingArchiveCase = "headingArchiveCase"; String headingArchiveContact = "headingArchiveContact"; @@ -535,6 +562,8 @@ public interface Strings { String headingCustomizableEnumConfigurationInfo = "headingCustomizableEnumConfigurationInfo"; String headingDatabaseExportFailed = "headingDatabaseExportFailed"; String headingDataImport = "headingDataImport"; + String headingDearchiveAdverseEvent = "headingDearchiveAdverseEvent"; + String headingDearchiveAdverseEventInvestigation = "headingDearchiveAdverseEventInvestigation"; String headingDearchiveCampaign = "headingDearchiveCampaign"; String headingDearchiveCase = "headingDearchiveCase"; String headingDearchiveContact = "headingDearchiveContact"; @@ -644,6 +673,7 @@ public interface Strings { String headingHospitalization = "headingHospitalization"; String headingHowToMergeCases = "headingHowToMergeCases"; String headingHowToMergeContacts = "headingHowToMergeContacts"; + String headingImmunizationAdverseEvents = "headingImmunizationAdverseEvents"; String headingImmunizationsDeleted = "headingImmunizationsDeleted"; String headingImmunizationsNotDeleted = "headingImmunizationsNotDeleted"; String headingImmunizationsNotRestored = "headingImmunizationsNotRestored"; @@ -675,6 +705,7 @@ public interface Strings { String headingImportSelfReports = "headingImportSelfReports"; String headingImportSubcontinents = "headingImportSubcontinents"; String headingImportTravelEntries = "headingImportTravelEntries"; + String headingIncorrectDateRange = "headingIncorrectDateRange"; String headingInformationSource = "headingInformationSource"; String headingInfrastructureLocked = "headingInfrastructureLocked"; String headingIntroduction = "headingIntroduction"; @@ -795,6 +826,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"; @@ -874,6 +906,8 @@ public interface Strings { String inColumn = "inColumn"; String infoActivityAsCaseInvestigation = "infoActivityAsCaseInvestigation"; String infoAddTestsToSample = "infoAddTestsToSample"; + String infoAefiSelectPrimarySuspectVaccine = "infoAefiSelectPrimarySuspectVaccine"; + String infoArchivedAefiEntries = "infoArchivedAefiEntries"; String infoArchivedCases = "infoArchivedCases"; String infoArchivedContacts = "infoArchivedContacts"; String infoArchivedEventParticipants = "infoArchivedEventParticipants"; @@ -929,6 +963,7 @@ public interface Strings { String infoCountryNotEditableEventParticipantsWithoutJurisdiction = "infoCountryNotEditableEventParticipantsWithoutJurisdiction"; String infoCreateEntry = "infoCreateEntry"; String infoCreateNewContactDiscardsChanges = "infoCreateNewContactDiscardsChanges"; + String infoCreateNewSampleDiscardsChangesCase = "infoCreateNewSampleDiscardsChangesCase"; String infoCreateNewSampleDiscardsChangesContact = "infoCreateNewSampleDiscardsChangesContact"; String infoCreateNewSampleDiscardsChangesEventParticipant = "infoCreateNewSampleDiscardsChangesEventParticipant"; String infoCustomExport = "infoCustomExport"; @@ -967,6 +1002,7 @@ public interface Strings { String infoExposuresRiskAreaHint = "infoExposuresRiskAreaHint"; String infoFacilityCsvImport = "infoFacilityCsvImport"; String infoFacilityNeedsDistrict = "infoFacilityNeedsDistrict"; + String infoHeadingAefiDashboardMap = "infoHeadingAefiDashboardMap"; String infoHeadingEnvironmentSampleDashboardMap = "infoHeadingEnvironmentSampleDashboardMap"; String infoHeadingSampleDashboardMap = "infoHeadingSampleDashboardMap"; String infoHowToMergeCases = "infoHowToMergeCases"; @@ -993,11 +1029,13 @@ public interface Strings { String infoMoreDetailsAboutHospitalization = "infoMoreDetailsAboutHospitalization"; String infoNoAccessToPersonEntities = "infoNoAccessToPersonEntities"; String infoNoAdditionalTests = "infoNoAdditionalTests"; + String infoNoAefiInvestigations = "infoNoAefiInvestigations"; String infoNoCasesFoundStatistics = "infoNoCasesFoundStatistics"; String infoNoCustomizableEnumTranslations = "infoNoCustomizableEnumTranslations"; String infoNoDiseaseSelected = "infoNoDiseaseSelected"; String infoNoEnvironmentSamples = "infoNoEnvironmentSamples"; String infoNoEventGroups = "infoNoEventGroups"; + String infoNoImmunizationAdverseEvents = "infoNoImmunizationAdverseEvents"; String infoNoNetworkDiagram = "infoNoNetworkDiagram"; String infoNoPathogenTests = "infoNoPathogenTests"; String infoNoSourceCase = "infoNoSourceCase"; @@ -1095,6 +1133,12 @@ public interface Strings { String messageActivateAccount = "messageActivateAccount"; String messageAdditionalTestDeleted = "messageAdditionalTestDeleted"; String messageAdditionalTestSaved = "messageAdditionalTestSaved"; + String messageAdverseEventArchived = "messageAdverseEventArchived"; + String messageAdverseEventDearchived = "messageAdverseEventDearchived"; + String messageAdverseEventInvestigationArchived = "messageAdverseEventInvestigationArchived"; + String messageAdverseEventInvestigationDearchived = "messageAdverseEventInvestigationDearchived"; + String messageAdverseEventInvestigationSaved = "messageAdverseEventInvestigationSaved"; + String messageAdverseEventSaved = "messageAdverseEventSaved"; String messageAggregatedReportEpiWeekFilterNotFilled = "messageAggregatedReportEpiWeekFilterNotFilled"; String messageAggregateReportDelete = "messageAggregateReportDelete"; String messageAggregateReportExpiredAgeGroups = "messageAggregateReportExpiredAgeGroups"; @@ -1247,6 +1291,7 @@ public interface Strings { String messageCountImmunizationsNotRestored = "messageCountImmunizationsNotRestored"; String messageCountriesArchived = "messageCountriesArchived"; String messageCountriesDearchived = "messageCountriesDearchived"; + String messageCountriesExcludedFromDataProtection = "messageCountriesExcludedFromDataProtection"; String messageCountryArchived = "messageCountryArchived"; String messageCountryDearchived = "messageCountryDearchived"; String messageCountryDearchivingNotPossible = "messageCountryDearchivingNotPossible"; @@ -1375,6 +1420,7 @@ public interface Strings { String messageImportSuccessful = "messageImportSuccessful"; String messageImportSuccessfulWithSkips = "messageImportSuccessfulWithSkips"; String messageIncompleteGpsCoordinates = "messageIncompleteGpsCoordinates"; + String messageIncorrectDateRange = "messageIncorrectDateRange"; String messageInfrastructureLocked = "messageInfrastructureLocked"; String messageInvalidDatesLineListing = "messageInvalidDatesLineListing"; String messageLaboratoriesArchived = "messageLaboratoriesArchived"; @@ -1618,11 +1664,26 @@ public interface Strings { String promptActionDateTo = "promptActionDateTo"; String promptActionEpiWeekFrom = "promptActionEpiWeekFrom"; String promptActionEpiWeekTo = "promptActionEpiWeekTo"; + String promptAefiDashboardFilterDateType = "promptAefiDashboardFilterDateType"; + String promptAefiDateFrom = "promptAefiDateFrom"; + String promptAefiDateTo = "promptAefiDateTo"; + String promptAefiDateType = "promptAefiDateType"; + String promptAefiEpiWeekFrom = "promptAefiEpiWeekFrom"; + String promptAefiEpiWeekTo = "promptAefiEpiWeekTo"; + String promptAefiInvestigationDateFrom = "promptAefiInvestigationDateFrom"; + String promptAefiInvestigationDateTo = "promptAefiInvestigationDateTo"; + String promptAefiInvestigationDateType = "promptAefiInvestigationDateType"; + String promptAefiInvestigationEpiWeekFrom = "promptAefiInvestigationEpiWeekFrom"; + String promptAefiInvestigationEpiWeekTo = "promptAefiInvestigationEpiWeekTo"; + String promptAefiInvestigationValidFrom = "promptAefiInvestigationValidFrom"; + String promptAefiValidFrom = "promptAefiValidFrom"; String promptAllAreas = "promptAllAreas"; String promptAllCommunities = "promptAllCommunities"; String promptAllDistricts = "promptAllDistricts"; String promptAllRegions = "promptAllRegions"; String promptArea = "promptArea"; + String promptBirthdateFrom = "promptBirthdateFrom"; + String promptBirthdateTo = "promptBirthdateTo"; String promptCampaign = "promptCampaign"; String promptCampaignSearch = "promptCampaignSearch"; String promptCaseOrContactEventSearchField = "promptCaseOrContactEventSearchField"; @@ -1643,6 +1704,7 @@ public interface Strings { String promptDateTo = "promptDateTo"; String promptDisease = "promptDisease"; String promptDistrict = "promptDistrict"; + String promptEmail = "promptEmail"; String promptEnvironmentDateFrom = "promptEnvironmentDateFrom"; String promptEnvironmentDateTo = "promptEnvironmentDateTo"; String promptEnvironmentEpiWeekFrom = "promptEnvironmentEpiWeekFrom"; @@ -1705,6 +1767,7 @@ public interface Strings { String promptPrescriptionTextFilter = "promptPrescriptionTextFilter"; String promptRegion = "promptRegion"; String promptRelatedPersonLikeField = "promptRelatedPersonLikeField"; + String promptRemarks = "promptRemarks"; String promptSampleDashboardFilterDateType = "promptSampleDashboardFilterDateType"; String promptSampleDateFrom = "promptSampleDateFrom"; String promptSampleDateTo = "promptSampleDateTo"; @@ -1724,6 +1787,7 @@ public interface Strings { String promptTaskEpiWeekFrom = "promptTaskEpiWeekFrom"; String promptTaskEpiWeekTo = "promptTaskEpiWeekTo"; String promptTaskSearchField = "promptTaskSearchField"; + String promptTelephoneNumber = "promptTelephoneNumber"; String promptTravelEntryDateFrom = "promptTravelEntryDateFrom"; String promptTravelEntryDateTo = "promptTravelEntryDateTo"; String promptTravelEntryEpiWeekFrom = "promptTravelEntryEpiWeekFrom"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Validations.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Validations.java index b4b553421e9..acf04abd059 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Validations.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Validations.java @@ -10,6 +10,11 @@ public interface Validations { * 1. java:S115: Violation of name convention for constants of this class is accepted: Close as false positive. */ + String aefiInvestigationWithoutPrimarySuspectVaccine = "aefiInvestigationWithoutPrimarySuspectVaccine"; + String aefiInvestigationWithoutSuspectVaccines = "aefiInvestigationWithoutSuspectVaccines"; + String aefiWithoutAdverseEvents = "aefiWithoutAdverseEvents"; + String aefiWithoutPrimarySuspectVaccine = "aefiWithoutPrimarySuspectVaccine"; + String aefiWithoutSuspectVaccines = "aefiWithoutSuspectVaccines"; String afterDate = "afterDate"; String afterDateSoft = "afterDateSoft"; String afterDateWithDate = "afterDateWithDate"; @@ -263,6 +268,7 @@ public interface Validations { String userNameNotUnique = "userNameNotUnique"; String uuidPatternNotMatching = "uuidPatternNotMatching"; String vaccineDosesFormat = "vaccineDosesFormat"; + String validAefiReport = "validAefiReport"; String validCaseContactOrEventParticipant = "validCaseContactOrEventParticipant"; String validCommunity = "validCommunity"; String validDateOfArrival = "validDateOfArrival"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/DatabaseTable.java b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/DatabaseTable.java index 63f15937443..171ad6e8303 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/DatabaseTable.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/DatabaseTable.java @@ -68,6 +68,14 @@ public enum DatabaseTable { IMMUNIZATIONS(DatabaseTableType.SORMAS, "immunizations", dependingOnFeature(FeatureType.IMMUNIZATION_MANAGEMENT)), VACCINATIONS(DatabaseTableType.SORMAS, IMMUNIZATIONS, "vaccinations"), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATIONS(DatabaseTableType.SORMAS, + "adverse_events_following_immunizations", + dependingOnFeature(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT)), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_INVESTIGATIONS(DatabaseTableType.SORMAS, + "adverse_events_following_immunization_investigations", + dependingOnFeature(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT)), + ADVERSE_EVENTS(DatabaseTableType.SORMAS, "adverse_events", dependingOnFeature(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT)), + SAMPLES(DatabaseTableType.SORMAS, "samples", dependingOnFeature(FeatureType.SAMPLES_LAB)), PATHOGEN_TESTS(DatabaseTableType.SORMAS, SAMPLES, "pathogen_tests"), ADDITIONAL_TESTS(DatabaseTableType.SORMAS, SAMPLES, "additional_tests", dependingOnFeature(FeatureType.ADDITIONAL_TESTS)), diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java index 576e6085873..5f146a7bf22 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/location/LocationDto.java @@ -101,8 +101,10 @@ public class LocationDto extends PseudonymizableDto { CountryHelper.COUNTRY_CODE_GERMANY, CountryHelper.COUNTRY_CODE_FRANCE }) private String details; - @PersonalData - @SensitiveData + @PersonalData(excludeForCountries = { + CountryHelper.COUNTRY_CODE_LUXEMBOURG }) + @SensitiveData(excludeForCountries = { + CountryHelper.COUNTRY_CODE_LUXEMBOURG }) @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String city; @PersonalData diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/OccupationTypeConverter.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/OccupationTypeConverter.java new file mode 100644 index 00000000000..b718749a878 --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/OccupationTypeConverter.java @@ -0,0 +1,10 @@ +package de.symeda.sormas.api.person; + +import de.symeda.sormas.api.customizableenum.CustomizableEnumConverter; + +public class OccupationTypeConverter extends CustomizableEnumConverter { + + public OccupationTypeConverter() { + super(OccupationType.class); + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonCriteria.java index 0ef155b8d25..a78d4eadbef 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonCriteria.java @@ -1,5 +1,6 @@ package de.symeda.sormas.api.person; +import java.util.Date; import java.util.Set; import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; @@ -37,6 +38,9 @@ public class PersonCriteria extends BaseCriteria implements Cloneable { private CommunityReferenceDto community; private PersonAssociation personAssociation; private Set uuids; + private Date birthdateFrom; + private Date birthdateTo; + private boolean includePartialMatch; public PersonCriteria() { @@ -127,6 +131,31 @@ public PersonCriteria personAssociation(PersonAssociation personAssociation) { return this; } + public Date getBirthdateFrom() { + return birthdateFrom; + } + + public void setBirthdateFrom(Date birthdateFrom) { + this.birthdateFrom = birthdateFrom; + } + + public Date getBirthdateTo() { + return birthdateTo; + } + + public void setBirthdateTo(Date birthdateTo) { + this.birthdateTo = birthdateTo; + } + + @IgnoreForUrl + public boolean isIncludePartialMatch() { + return includePartialMatch; + } + + public void setIncludePartialMatch(boolean includePartialMatch) { + this.includePartialMatch = includePartialMatch; + } + @IgnoreForUrl public Set getUuids() { return uuids; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java index 27363cfeeed..a4895af076b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java @@ -195,6 +195,8 @@ public class PersonDto extends PseudonymizableDto implements IsPerson { @SensitiveData private Integer birthdateDD; @Outbreaks + @PersonalData + @SensitiveData private Integer birthdateMM; @Outbreaks private Integer birthdateYYYY; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonExportDto.java index 7fd3b5506c3..4361cc8e3ed 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonExportDto.java @@ -194,7 +194,7 @@ public PersonExportDto( String otherContactDetails, EducationType educationType, String educationDetails, - OccupationType occupationType, + String occupationType, String occupationDetails, ArmedForcesRelationType armedForcesRelationType, String passportNumber, @@ -247,7 +247,7 @@ public PersonExportDto( this.otherContactDetails = otherContactDetails; this.educationType = educationType; this.educationDetails = educationDetails; - this.occupationType = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationType); this.occupationDetails = occupationDetails; this.armedForcesRelationType = armedForcesRelationType; this.passportNumber = passportNumber; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java index fd0ca37565c..e782b271914 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java @@ -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. @@ -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; } @@ -140,7 +149,11 @@ 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); } /** @@ -148,7 +161,7 @@ public static PersonSimilarityCriteria forPerson(PersonDto person) { * 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()) @@ -156,6 +169,7 @@ public static PersonSimilarityCriteria forPerson(PersonDto person, boolean stric .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 { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestCriteria.java index a9f9a1ac789..fad0fb4236f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestCriteria.java @@ -21,4 +21,9 @@ public SampleReferenceDto getSample() { public void setSample(SampleReferenceDto sample) { this.sample = sample; } + + public PathogenTestCriteria sample(SampleReferenceDto sample) { + this.sample = sample; + return this; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java index b06c250f0b3..0eb491c7c4d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java @@ -24,38 +24,62 @@ public enum PathogenTestType { + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) ANTIBODY_DETECTION, ANTIGEN_DETECTION, RAPID_TEST, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) CULTURE, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) HISTOPATHOLOGY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) ISOLATION, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) IGM_SERUM_ANTIBODY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) IGG_SERUM_ANTIBODY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) IGA_SERUM_ANTIBODY, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) INCUBATION_TIME, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) INDIRECT_FLUORESCENT_ANTIBODY, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) DIRECT_FLUORESCENT_ANTIBODY, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) MICROSCOPY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) NEUTRALIZING_ANTIBODIES, PCR_RT_PCR, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) GRAM_STAIN, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) LATEX_AGGLUTINATION, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) CQ_VALUE_DETECTION, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) SEQUENCING, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) DNA_MICROARRAY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) TMA, OTHER; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java index 7369d33bf82..4ec4e3fbd1e 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java @@ -24,44 +24,68 @@ public enum SampleMaterial { + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) BLOOD, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) SERA, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) STOOL, NASAL_SWAB, THROAT_SWAB, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) NP_SWAB, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) RECTAL_SWAB, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) CEREBROSPINAL_FLUID, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) CRUST, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) TISSUE, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) URINE, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) CORNEA_PM, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) SALIVA, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) URINE_PM, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) NUCHAL_SKIN_BIOPSY, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) SPUTUM, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) ENDOTRACHEAL_ASPIRATE, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) BRONCHOALVEOLAR_LAVAGE, @Diseases(value = { - Disease.CORONAVIRUS }, hide = true) + Disease.CORONAVIRUS, Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) BRAIN_TISSUE, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) ANTERIOR_NARES_SWAB, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) OP_ASPIRATE, NP_ASPIRATE, + @Diseases(value = { + Disease.RESPIRATORY_SYNCYTIAL_VIRUS }, hide = true) PLEURAL_FLUID, OTHER; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/selfreport/SelfReportExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/selfreport/SelfReportExportDto.java index 951673427b4..ee28381144f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/selfreport/SelfReportExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/selfreport/SelfReportExportDto.java @@ -6,6 +6,7 @@ import de.symeda.sormas.api.caze.BirthDateDto; import de.symeda.sormas.api.common.DeletionReason; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.utils.Order; @@ -79,7 +80,7 @@ public SelfReportExportDto( String caseReference, Disease disease, String diseaseDetails, - DiseaseVariant diseaseVariant, + String diseaseVariant, String diseaseVariantDetails, String firstName, String lastName, @@ -111,7 +112,7 @@ public SelfReportExportDto( this.caseReference = caseReference; this.disease = disease; this.diseaseDetails = diseaseDetails; - this.diseaseVariant = diseaseVariant; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariant); this.diseaseVariantDetails = diseaseVariantDetails; this.firstName = firstName; this.lastName = lastName; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/DefaultUserRole.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/DefaultUserRole.java index 5e7a2fc06ab..b91d28b515b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/DefaultUserRole.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/DefaultUserRole.java @@ -304,6 +304,13 @@ public Set getDefaultUserRights() { IMMUNIZATION_DELETE, IMMUNIZATION_ARCHIVE, IMMUNIZATION_VIEW_ARCHIVED, + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT, PERSON_VIEW, PERSON_EDIT, PERSON_DELETE, @@ -1315,6 +1322,13 @@ public Set getDefaultUserRights() { IMMUNIZATION_CREATE, IMMUNIZATION_EDIT, IMMUNIZATION_DELETE, + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT, PERSON_VIEW, PERSON_EDIT, PERSON_DELETE, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java index 9d43f73733f..806a73d1cb6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java @@ -63,6 +63,13 @@ public enum UserRight { IMMUNIZATION_ARCHIVE(UserRightGroup.IMMUNIZATION, UserRight._IMMUNIZATION_VIEW), IMMUNIZATION_VIEW_ARCHIVED(UserRightGroup.IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT(UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION), + PERSON_VIEW(UserRightGroup.PERSON), PERSON_EDIT(UserRightGroup.PERSON, UserRight._PERSON_VIEW), PERSON_DELETE(UserRightGroup.PERSON, UserRight._PERSON_VIEW, UserRight._VISIT_DELETE), @@ -169,6 +176,7 @@ public enum UserRight { DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS(UserRightGroup.DASHBOARD, UserRight._DASHBOARD_CONTACT_VIEW), DASHBOARD_CAMPAIGNS_VIEW(UserRightGroup.DASHBOARD, UserRight._CAMPAIGN_VIEW), DASHBOARD_SAMPLES_VIEW(UserRightGroup.DASHBOARD, UserRight._SAMPLE_VIEW), + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW(UserRightGroup.DASHBOARD, UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW), CASE_CLINICIAN_VIEW(UserRightGroup.CASE_MANAGEMENT, UserRight._CASE_VIEW), @@ -324,6 +332,12 @@ public enum UserRight { public static final String _IMMUNIZATION_EDIT = "IMMUNIZATION_EDIT"; public static final String _IMMUNIZATION_DELETE = "IMMUNIZATION_DELETE"; public static final String _IMMUNIZATION_ARCHIVE = "IMMUNIZATION_ARCHIVE"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE"; + public static final String _ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT = "ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT"; public static final String _PERSON_VIEW = "PERSON_VIEW"; public static final String _PERSON_EDIT = "PERSON_EDIT"; public static final String _PERSON_DELETE = "PERSON_DELETE"; @@ -419,6 +433,7 @@ public enum UserRight { public static final String _DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = "DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS"; public static final String _DASHBOARD_CAMPAIGNS_VIEW = "DASHBOARD_CAMPAIGNS_VIEW"; public static final String _DASHBOARD_SAMPLES_VIEW = "DASHBOARD_SAMPLES_VIEW"; + public static final String _DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW = "DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW"; public static final String _CASE_CLINICIAN_VIEW = "CASE_CLINICIAN_VIEW"; public static final String _THERAPY_VIEW = "THERAPY_VIEW"; public static final String _PRESCRIPTION_CREATE = "PRESCRIPTION_CREATE"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRightGroup.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRightGroup.java index ece02973739..7fa2dd34069 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRightGroup.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRightGroup.java @@ -35,6 +35,7 @@ public enum UserRightGroup { EVENT, SAMPLE, IMMUNIZATION, + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION, TRAVEL_ENTRY, CAMPAIGN, ENVIRONMENT, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/PersonalData.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/PersonalData.java index c96ed3e9295..4d81471a021 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/PersonalData.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/PersonalData.java @@ -27,4 +27,6 @@ public @interface PersonalData { boolean mandatoryField() default false; + + String[] excludeForCountries() default {}; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/SensitiveData.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/SensitiveData.java index 6ce06fd20d8..9602b676142 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/SensitiveData.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/SensitiveData.java @@ -1,19 +1,16 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System * Copyright © 2016-2020 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ package de.symeda.sormas.api.utils; @@ -28,4 +25,6 @@ public @interface SensitiveData { boolean mandatoryField() default false; + + String[] excludeForCountries() default {}; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/UiFieldAccessCheckers.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/UiFieldAccessCheckers.java index 26c1b2e5c9f..555e1913608 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/UiFieldAccessCheckers.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/UiFieldAccessCheckers.java @@ -48,41 +48,44 @@ public static UiFieldAccessCheckers getNoop() { return new UiFieldAccessCheckers<>(); } - public static UiFieldAccessCheckers getDefault(boolean isPseudonymized) { + public static UiFieldAccessCheckers getDefault(boolean isPseudonymized, String serverCountry) { UiFieldAccessCheckers fieldAccessCheckers = new UiFieldAccessCheckers<>(); - fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forPersonalData(isPseudonymized)) - .add(PseudonymizedFieldAccessChecker.forSensitiveData(isPseudonymized)); + fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forPersonalData(isPseudonymized, serverCountry)) + .add(PseudonymizedFieldAccessChecker.forSensitiveData(isPseudonymized, serverCountry)); return fieldAccessCheckers; } - public static UiFieldAccessCheckers forPersonalData(boolean isPseudonymized) { + public static UiFieldAccessCheckers forPersonalData(boolean isPseudonymized, String serverCountry) { UiFieldAccessCheckers fieldAccessCheckers = new UiFieldAccessCheckers<>(); - fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forPersonalData(isPseudonymized)); + fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forPersonalData(isPseudonymized, serverCountry)); return fieldAccessCheckers; } - public static UiFieldAccessCheckers forSensitiveData(boolean isPseudonymized) { + public static UiFieldAccessCheckers forSensitiveData(boolean isPseudonymized, String serverCountry) { UiFieldAccessCheckers fieldAccessCheckers = new UiFieldAccessCheckers<>(); - fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forSensitiveData(isPseudonymized)); + fieldAccessCheckers.add(PseudonymizedFieldAccessChecker.forSensitiveData(isPseudonymized, serverCountry)); return fieldAccessCheckers; } - public static UiFieldAccessCheckers forDataAccessLevel(PseudonymizableDataAccessLevel accessLevel, boolean isPseudonymized) { + public static UiFieldAccessCheckers forDataAccessLevel( + PseudonymizableDataAccessLevel accessLevel, + boolean isPseudonymized, + String serverCountry) { switch (accessLevel) { case ALL: case NONE: - return getDefault(isPseudonymized); + return getDefault(isPseudonymized, serverCountry); case PERSONAL: - return forSensitiveData(isPseudonymized); + return forSensitiveData(isPseudonymized, serverCountry); case SENSITIVE: - return forPersonalData(isPseudonymized); + return forPersonalData(isPseudonymized, serverCountry); default: throw new IllegalArgumentException(accessLevel.name()); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/AnnotationBasedFieldAccessChecker.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/AnnotationBasedFieldAccessChecker.java index 402ac5219da..d87b4038db4 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/AnnotationBasedFieldAccessChecker.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/AnnotationBasedFieldAccessChecker.java @@ -22,7 +22,7 @@ public abstract class AnnotationBasedFieldAccessChecker implements FieldAccessChecker { - private final Class fieldAnnotation; + protected final Class fieldAnnotation; private final Class embeddedAnnotation; private final boolean hasRight; private final SpecialAccessCheck specialAccessCheck; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PersonalDataFieldAccessChecker.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PersonalDataFieldAccessChecker.java index be838b8a0eb..cc38ed1c6f5 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PersonalDataFieldAccessChecker.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PersonalDataFieldAccessChecker.java @@ -18,6 +18,7 @@ package de.symeda.sormas.api.utils.fieldaccess.checkers; import java.lang.reflect.Field; +import java.util.Arrays; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.EmbeddedPersonalData; @@ -25,20 +26,32 @@ public final class PersonalDataFieldAccessChecker extends AnnotationBasedFieldAccessChecker { - private PersonalDataFieldAccessChecker(final boolean hasRight, SpecialAccessCheck specialAccessCheck) { + private final String serverCountry; + + private PersonalDataFieldAccessChecker(final boolean hasRight, SpecialAccessCheck specialAccessCheck, String serverCountry) { super(PersonalData.class, EmbeddedPersonalData.class, hasRight, specialAccessCheck); + this.serverCountry = serverCountry; } - public static PersonalDataFieldAccessChecker inJurisdiction(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { - return new PersonalDataFieldAccessChecker<>(rightCheck.check(UserRight.SEE_PERSONAL_DATA_IN_JURISDICTION), specialAccessCheck); + public static PersonalDataFieldAccessChecker inJurisdiction( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return new PersonalDataFieldAccessChecker<>(rightCheck.check(UserRight.SEE_PERSONAL_DATA_IN_JURISDICTION), specialAccessCheck, serverCountry); } - public static PersonalDataFieldAccessChecker outsideJurisdiction(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { - return new PersonalDataFieldAccessChecker<>(rightCheck.check(UserRight.SEE_PERSONAL_DATA_OUTSIDE_JURISDICTION), specialAccessCheck); + public static PersonalDataFieldAccessChecker outsideJurisdiction( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return new PersonalDataFieldAccessChecker<>( + rightCheck.check(UserRight.SEE_PERSONAL_DATA_OUTSIDE_JURISDICTION), + specialAccessCheck, + serverCountry); } public static PersonalDataFieldAccessChecker forcedNoAccess() { - return new PersonalDataFieldAccessChecker<>(false, t -> false); + return new PersonalDataFieldAccessChecker<>(false, t -> false, null); } @Override @@ -46,6 +59,23 @@ protected boolean isAnnotatedFieldMandatory(Field annotatedField) { return annotatedField.getAnnotation(PersonalData.class).mandatoryField(); } + @Override + public boolean isConfiguredForCheck(Field field, boolean withMandatory) { + boolean annotationPresent = field.isAnnotationPresent(fieldAnnotation); + + if (annotationPresent) { + String[] excludeForCountries = field.getAnnotation(PersonalData.class).excludeForCountries(); + if (Arrays.asList(excludeForCountries).contains(serverCountry)) { + return false; + } + } + + if (!annotationPresent || withMandatory) { + return annotationPresent; + } + return !isAnnotatedFieldMandatory(field); + } + public interface RightCheck { boolean check(UserRight userRight); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PseudonymizedFieldAccessChecker.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PseudonymizedFieldAccessChecker.java index 28605b139fa..c88550f853c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PseudonymizedFieldAccessChecker.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/PseudonymizedFieldAccessChecker.java @@ -17,6 +17,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.util.Arrays; import de.symeda.sormas.api.utils.EmbeddedPersonalData; import de.symeda.sormas.api.utils.EmbeddedSensitiveData; @@ -24,15 +25,16 @@ import de.symeda.sormas.api.utils.SensitiveData; import de.symeda.sormas.api.utils.fieldaccess.FieldAccessChecker; -public final class PseudonymizedFieldAccessChecker implements FieldAccessChecker { +public abstract class PseudonymizedFieldAccessChecker implements FieldAccessChecker { private final WrappedFieldAccessChecker wrapped; - public PseudonymizedFieldAccessChecker( + private PseudonymizedFieldAccessChecker( Class annotation, Class embeddedAnnotation, - boolean isPseudonymized) { - this.wrapped = new WrappedFieldAccessChecker(annotation, embeddedAnnotation, isPseudonymized); + boolean isPseudonymized, + String serverCountry) { + this.wrapped = new WrappedFieldAccessChecker(annotation, embeddedAnnotation, isPseudonymized, serverCountry); } @Override @@ -56,24 +58,52 @@ public boolean hasRight(T object) { private final class WrappedFieldAccessChecker extends AnnotationBasedFieldAccessChecker { + private final String serverCountry; + private WrappedFieldAccessChecker( Class annotation, Class embeddedAnnotation, - boolean isPseudonymized) { + boolean isPseudonymized, + String serverCountry) { super(annotation, embeddedAnnotation, !isPseudonymized, t -> false); + this.serverCountry = serverCountry; } @Override protected boolean isAnnotatedFieldMandatory(Field annotatedField) { return false; } + + @Override + public boolean isConfiguredForCheck(Field field, boolean withMandatory) { + if (isExcludedForCountry(field, serverCountry)) { + return false; + } + return super.isConfiguredForCheck(field, withMandatory); + } } - public static PseudonymizedFieldAccessChecker forPersonalData(boolean isPseudonymized) { - return new PseudonymizedFieldAccessChecker<>(PersonalData.class, EmbeddedPersonalData.class, isPseudonymized); + protected abstract boolean isExcludedForCountry(Field field, String serverCountry); + + public static PseudonymizedFieldAccessChecker forPersonalData(boolean isPseudonymized, String serverCountry) { + return new PseudonymizedFieldAccessChecker<>(PersonalData.class, EmbeddedPersonalData.class, isPseudonymized, serverCountry) { + + @Override + protected boolean isExcludedForCountry(Field field, String serverCountry) { + return field.getAnnotation(PersonalData.class) != null + && Arrays.asList(field.getAnnotation(PersonalData.class).excludeForCountries()).contains(serverCountry); + } + }; } - public static PseudonymizedFieldAccessChecker forSensitiveData(boolean isPseudonymized) { - return new PseudonymizedFieldAccessChecker<>(SensitiveData.class, EmbeddedSensitiveData.class, isPseudonymized); + public static PseudonymizedFieldAccessChecker forSensitiveData(boolean isPseudonymized, String serverCountry) { + return new PseudonymizedFieldAccessChecker<>(SensitiveData.class, EmbeddedSensitiveData.class, isPseudonymized, serverCountry) { + + @Override + protected boolean isExcludedForCountry(Field field, String serverCountry) { + return field.getAnnotation(SensitiveData.class) != null + && Arrays.asList(field.getAnnotation(SensitiveData.class).excludeForCountries()).contains(serverCountry); + } + }; } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/SensitiveDataFieldAccessChecker.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/SensitiveDataFieldAccessChecker.java index fb0c1f68005..d5b716c26a3 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/SensitiveDataFieldAccessChecker.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/checkers/SensitiveDataFieldAccessChecker.java @@ -16,6 +16,7 @@ package de.symeda.sormas.api.utils.fieldaccess.checkers; import java.lang.reflect.Field; +import java.util.Arrays; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.EmbeddedSensitiveData; @@ -23,20 +24,35 @@ public final class SensitiveDataFieldAccessChecker extends AnnotationBasedFieldAccessChecker { - private SensitiveDataFieldAccessChecker(final boolean hasRight, SpecialAccessCheck specialAccessCheck) { + private final String serverCountry; + + private SensitiveDataFieldAccessChecker(final boolean hasRight, SpecialAccessCheck specialAccessCheck, String serverCountry) { super(SensitiveData.class, EmbeddedSensitiveData.class, hasRight, specialAccessCheck); + this.serverCountry = serverCountry; } - public static SensitiveDataFieldAccessChecker inJurisdiction(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { - return new SensitiveDataFieldAccessChecker<>(rightCheck.check(UserRight.SEE_SENSITIVE_DATA_IN_JURISDICTION), specialAccessCheck); + public static SensitiveDataFieldAccessChecker inJurisdiction( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return new SensitiveDataFieldAccessChecker<>( + rightCheck.check(UserRight.SEE_SENSITIVE_DATA_IN_JURISDICTION), + specialAccessCheck, + serverCountry); } - public static SensitiveDataFieldAccessChecker outsideJurisdiction(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { - return new SensitiveDataFieldAccessChecker<>(rightCheck.check(UserRight.SEE_SENSITIVE_DATA_OUTSIDE_JURISDICTION), specialAccessCheck); + public static SensitiveDataFieldAccessChecker outsideJurisdiction( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return new SensitiveDataFieldAccessChecker<>( + rightCheck.check(UserRight.SEE_SENSITIVE_DATA_OUTSIDE_JURISDICTION), + specialAccessCheck, + serverCountry); } public static SensitiveDataFieldAccessChecker forcedNoAccess() { - return new SensitiveDataFieldAccessChecker<>(false, t -> false); + return new SensitiveDataFieldAccessChecker<>(false, t -> false, null); } @Override @@ -44,6 +60,23 @@ protected boolean isAnnotatedFieldMandatory(Field annotatedField) { return annotatedField.getAnnotation(SensitiveData.class).mandatoryField(); } + @Override + public boolean isConfiguredForCheck(Field field, boolean withMandatory) { + boolean annotationPresent = field.isAnnotationPresent(fieldAnnotation); + + if (annotationPresent) { + String[] excludeForCountries = field.getAnnotation(SensitiveData.class).excludeForCountries(); + if (Arrays.asList(excludeForCountries).contains(serverCountry)) { + return false; + } + } + + if (!annotationPresent || withMandatory) { + return annotationPresent; + } + return !isAnnotatedFieldMandatory(field); + } + public interface RightCheck { boolean check(UserRight userRight); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/vaccination/VaccinationDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/vaccination/VaccinationDto.java index 8e82f5a4397..2954ad1a01f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/vaccination/VaccinationDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/vaccination/VaccinationDto.java @@ -69,6 +69,7 @@ public class VaccinationDto extends PseudonymizableDto { @DependingOnFeatureType(featureType = FeatureType.IMMUNIZATION_MANAGEMENT, properties = @FeatureProperty(property = FeatureTypeProperty.REDUCED, value = "true"), hide = true) + @SensitiveData private HealthConditionsDto healthConditions; @NotNull(message = Validations.validReportDateTime) private Date reportDate; diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index a2fdb57909f..815de5ffe31 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -52,6 +52,7 @@ creationDate=Creation date changeDate=Date of last change notAvailableShort=NA inaccessibleValue=Confidential +includePartialBirthdates = Include partial birthdates numberOfCharacters=Number of characters: %d / %d remove=Remove notTestedYet=Not tested yet @@ -195,6 +196,8 @@ actionOkAndGoToPersonDirectory = Okay, and continue to person directory actionExecuteAutomaticDeletion = Execute automatic deletion actionDone = Done actionConfirmAction = Confirm action +actionAefiSelectPrimarySuspectVaccination = Select Suspect Vaccination +actionAefiAssignNewReportingIdNumber = "Assign New AEFI ID" activityAsCaseFlightNumber=Flight number ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity @@ -1003,6 +1006,7 @@ dashboardAggregatedNumber=Count dashboardProportion=Proportion (%) dashboardViewAsColumnChart=View as Column Chart dashboardViewAsBarChart=View as Bar Chart +dashboardNumberOfAdverseEvents=Number of Adverse Events #SampleDashboard sampleDashboardAllSamples=All Samples sampleDashboardFinalLabResults=Final Laboratory Results @@ -1018,6 +1022,21 @@ sampleDashboardShowCaseSamples=Show Case Samples sampleDashboardShowContactSamples=Show Contact Samples sampleDashboardShowEventParticipantSamples=Show Event Participant Samples sampleDashboardShowEnvironmentSamples=Show Environment Samples +#AefiDashboard +aefiDashboardAllAefi=AEFI +aefiDashboardSerious=Serious +aefiDashboardNonSerious=Non Serious +aefiDashboardSeriousAefi=Serious AEFI +aefiDashboardNonSeriousAefi=Non-Serious AEFI +aefiDashboardShowSeriousAefi=Show Serious AEFI +aefiDashboardShowNonSeriousAefi=Show Non-Serious AEFI +aefiDashboardAllAefiInvestigation=Investigations +aefiDashboardAefiInvestigationDone=Investigation Done +aefiDashboardAefiInvestigationDiscarded=Investigation Discarded +aefiDashboardAefiClassificationRelatedToVaccination=Related to vaccine or vaccination +aefiDashboardAefiClassificationCoincidentalAdverseEvent=Coincidental adverse event +aefiDashboardAefiClassificationUndetermined=Undetermined + captionDefault=Default defaultRegion=Default Region defaultDistrict=Default District @@ -1109,6 +1128,8 @@ documentNoDocuments=There are no documents for this %s bulkActionCreatDocuments=Create quarantine order documents # DocumentTemplate DocumentTemplate=Document Template +DocumentTemplate.fileName=File name +DocumentTemplate.disease=Disease DocumentTemplate.buttonUploadTemplate=Upload Template DocumentTemplate.documentTemplateGuide=Document Template Guide DocumentTemplate.plural=Document Templates @@ -1134,6 +1155,21 @@ DocumentTemplate.documentUploadWarning=Document upload warning DocumentTemplate.fileTooBig=The documents were successfully generated, but at least one document could not be uploaded to its entity because its file size exceeds the specified file size limit of %dMB DocumentTemplate.notUploaded=Documents could not be uploaded to the following entities: +# Entity columns +EntityColumn.ENTITY = Entity +EntityColumn.FIELD_ID = Field ID +EntityColumn.FIELD = Field +EntityColumn.TYPE = Type +EntityColumn.DATA_PROTECTION = Data protection +EntityColumn.CAPTION = Caption +EntityColumn.DESCRIPTION = Description +EntityColumn.REQUIRED = Required +EntityColumn.NEW_DISEASE = New disease +EntityColumn.DISEASES = Diseases +EntityColumn.OUTBREAKS = Outbreaks +EntityColumn.IGNORED_COUNTRIES = Ignored countries +EntityColumn.EXCLUSIVE_COUNTRIES = Exclusive countries + # Environment Environment=Environment Environment.uuid=Environment ID @@ -1697,6 +1733,7 @@ mainMenuEntries=Entries mainMenuEvents=Events mainMenuExternalMessages=Messages mainMenuImmunizations=Immunizations +mainMenuAdverseEvents=Adverse Events mainMenuReports=Reports mainMenuSamples=Samples mainMenuEnvironments=Environments @@ -1794,6 +1831,7 @@ personFindMatching=Find matching persons personSelect=Select a matching person personSearchAndSelect=Select a different person personAgeAndBirthdate=Age and birth date +personFullName=Full name personNoEventParticipantLinkedToPerson=No event participant linked to person personNoCaseLinkedToPerson=No case linked to person personNoContactLinkedToPerson=No contact linked to person @@ -2228,6 +2266,361 @@ immunizationOnlyPersonsWithOverdueImmunization=Only show persons with overdue im immunizationOverwriteImmunization=Overwrite the existing immunization with this data immunizationCreateNewImmunization=Create the new immunization anyway immunizationNoImmunizationsForPerson=There are no immunizations for this person +# Adverse Events Following Immunization +Aefi.primaryVaccineVaccinationDate=Vaccination date +Aefi.uuid=Adverse event UUID +Aefi.reportDate=Date of report +Aefi.reportingUser=Reporting user +Aefi.externalId=External ID +Aefi.responsibleRegion=Responsible region +Aefi.responsibleDistrict=Responsible district +Aefi.responsibleCommunity=Responsible community +Aefi.country=Country +Aefi.reportingIdNumber=Reporting ID Number +Aefi.pregnant=Pregnant +Aefi.trimester=Trimester +Aefi.lactating=Lactating +Aefi.onsetAgeYears=Years +Aefi.onsetAgeMonths=Months +Aefi.onsetAgeDays=Days +Aefi.ageGroup=Age group +Aefi.healthFacility=Facility +Aefi.healthFacilityDetails=Facility name & description +Aefi.reporterName=Name +Aefi.reporterInstitution=Insitution +Aefi.reporterDesignation=Designation +Aefi.reporterDepartment=Department +Aefi.reporterPhone=Phone number +Aefi.reporterEmail=Email +Aefi.todaysDate=Today's date +Aefi.startDateTime=Date and time AEFI started +Aefi.aefiDescription=Describe AEFI (Signs and symptoms) +Aefi.serious=Serious +Aefi.seriousReason=Reason for serious +Aefi.seriousReasonDetails=Reason for serious details +Aefi.outcome=Outcome +Aefi.deathDate=Date of death +Aefi.autopsyDone=Autopsy done +Aefi.pastMedicalHistory=Past medical history +Aefi.investigationNeeded=Investigation needed +Aefi.investigationPlannedDate=Date investigation planned +Aefi.receivedAtNationalLevelDate=Date received at national +Aefi.worldwideId=AEFI worldwide unique ID +Aefi.nationalLevelComment=Comment +Aefi.deletionReason=Reason for deletion +Aefi.otherDeletionReason=Reason for deletion details +Aefi.creationDate=Creation date +Aefi.changeDate=Date of last change +aefiNewAdverseEvent=New Adverse Event +aefiAefiList=Adverse Events List +aefiAefiDataView=Adverse Event +aefiVaccinationsVaccineInformation=Vaccine Information +aefiVaccinationsPrimaryVaccine=Primary +aefiVaccinationsVaccineDetails=Vaccine details +aefiVaccinationsDiluentInformation=Diluent Information +aefiVaccinationsDiluentBatchLotNumber=Batch/Lot number +aefiVaccinationsDiluentExpiryDate=Expiry date +aefiVaccinationsDiluentTimeOfReconstitution=Reconstitution time +aefiActiveAdverseEvents = Active adverse events +aefiArchivedAdverseEvents = Archived adverse events +aefiAllActiveAndArchivedAdverseEvents = All active and archived adverse events +aefiDeletedAdverseEvents = Deleted adverse events +# Adverse Events +AdverseEvents.severeLocalReaction=Severe local reaction +AdverseEvents.severeLocalReactionMoreThanThreeDays=>3 days +AdverseEvents.severeLocalReactionBeyondNearestJoint=Beyond nearest joint +AdverseEvents.seizures=Seizures +AdverseEvents.seizureType=Seizure type +AdverseEvents.abscess=Abscess +AdverseEvents.sepsis=Sepsis +AdverseEvents.encephalopathy=Encephalopathy +AdverseEvents.toxicShockSyndrome=Toxic shock syndrome +AdverseEvents.thrombocytopenia=Thrombocytopenia +AdverseEvents.anaphylaxis=Anaphylaxis +AdverseEvents.feverishFeeling=Fever >38degC +AdverseEvents.otherAdverseEventDetails=Other (specify) +# Adverse Events Index +AefiIndex.uuid=AEFI ID +AefiIndex.immunizationUuid=Immunization ID +AefiIndex.personUuid=Person ID +AefiIndex.personFirstName=First Name +AefiIndex.personLastName=Last Name +AefiIndex.reportDate=Date of report +AefiIndex.disease=Disease +AefiIndex.ageAndBirthDate=Age and birth date +AefiIndex.sex=Sex +AefiIndex.region=Region +AefiIndex.district=District +AefiIndex.serious=Serious +AefiIndex.primaryVaccine=Suspect Vaccine +AefiIndex.outcome=Outcome +AefiIndex.vaccinationDate=Date of vaccination +AefiIndex.startDateTime=Date of AEFI onset +AefiIndex.adverseEvents=Adverse events +# Adverse Events Export +AefiExport.receivedAtNationalLevelDate=Date AEFI report first received at national centre +AefiExport.vaccinationFacilityName=Place of vaccination +AefiExport.vaccinationFacilityRegion=Place of vaccination region +AefiExport.vaccinationFacilityDistrict=Place of vaccination district +AefiExport.vaccinationFacilityCommunity=Place of vaccination community +AefiExport.reportingOfficerAddressCountryName=Country where this AEFI reported +AefiExport.patientAddressRegion=Location (address) region +AefiExport.patientAddressDistrict=Location (address) district +AefiExport.patientAddressCommunity=Location (address) community +AefiExport.patientAddressDetails=Location (address) +AefiExport.reportingIdNumber=AEFI reporting id number +AefiExport.worldWideId=Worldwide unique number +AefiExport.firstName=Patient identifier (First Name) +AefiExport.lastName=Patient identifier (Last Name) +AefiExport.birthDate=Date of birth +AefiExport.onsetAgeYears=Age (years) at time of onset +AefiExport.onsetAgeMonths=Age (months) at time of onset +AefiExport.onsetAgeDays=Age (days) at time of onset +AefiExport.onsetAgeGroup=Age group at onset +AefiExport.sex=Sex +AefiExport.aefiDescription=History of Event +AefiExport.primarySuspectVaccineName=Primary suspect vaccine name (generic) +AefiExport.primarySuspectVaccineOtherName=Other primary suspect vaccine name (generic) +AefiExport.primarySuspectVaccineBrand=Primary suspect vaccine name (brand) +AefiExport.primarySuspectVaccineManufacturer=Primary suspect vaccine name (manufacturer) +AefiExport.primarySuspectVaccineBatchNumber=Primary supect vaccine batch number +AefiExport.primarySuspectVaccineDose=Primary suspect vaccine dose number for this particular vaccinee +AefiExport.primarySuspectVaccineDiluentBatchNumber=Diluent batch/ lot number +AefiExport.primarySuspectVaccineVaccinationDate=Date and time of primary vaccination +AefiExport.startDateTime=Date and time of AEFI onset +AefiExport.outcome=Outcome of AEFI +AefiExport.serious=Serious +AefiExport.reportingOfficerName=Name of first reporter of AEFI +AefiExport.reportingOfficerFacilityName=Institution/location +AefiExport.reportingOfficerFacilityRegion=Reporter institution/location region +AefiExport.reportingOfficerFacilityDistrict=Reporter institution/location district +AefiExport.reportingOfficerFacilityCommunity=Reporter institution/location community +AefiExport.reportingOfficerDesignation=Position +AefiExport.reportingOfficerDepartment=Department +AefiExport.reportingOfficerEmail=E-mail Id +AefiExport.reportingOfficerPhoneNumber=Telephone number +AefiExport.reportDate=Date of report +AefiExport.nationalLevelComment=Comments (if any) +# Adverse Events Criteria +AefiCriteria.aefiType=AEFI Type +AefiCriteria.outcome=Outcome +AefiCriteria.vaccineName=Vaccine +AefiCriteria.vaccineManufacturer=Manufacturer +# Adverse Events List Entry +AefiInvestigationListEntry.investigationDate=Investigation Date +AefiInvestigationListEntry.investigationStage=Stage +AefiInvestigationListEntry.statusOnDateOfInvestigation=Status +AefiInvestigationListEntry.aefiClassification=Classification +# Adverse Events Following Immunization Investigations +AefiInvestigation.uuid=AEFI Investigation UUID +AefiInvestigation.reportDate=Date of report +AefiInvestigation.reportingUser=Reporting user +AefiInvestigation.externalId=External ID +AefiInvestigation.responsibleRegion=Responsible region +AefiInvestigation.responsibleDistrict=Responsible district +AefiInvestigation.responsibleCommunity=Responsible community +AefiInvestigation.country=Country +AefiInvestigation.investigationCaseId=Investigation Case ID +AefiInvestigation.placeOfVaccination=Place of vaccination +AefiInvestigation.placeOfVaccinationDetails=Place of vaccination details +AefiInvestigation.vaccinationActivity=Vaccination in +AefiInvestigation.vaccinationActivityDetails=Vaccination activity details +AefiInvestigation.vaccinationFacility=Facility +AefiInvestigation.vaccinationFacilityDetails=Facility name & description +AefiInvestigation.reportingOfficerName=Name of reporting officer +AefiInvestigation.reportingOfficerFacility=Facility +AefiInvestigation.reportingOfficerFacilityDetails=Facility name & description +AefiInvestigation.reportingOfficerDesignation=Designation / Position +AefiInvestigation.reportingOfficerDepartment=Department +AefiInvestigation.reportingOfficerAddress=Address of reporting officer +AefiInvestigation.reportingOfficerLandlinePhoneNumber=Telephone # landline (with code): +AefiInvestigation.reportingOfficerMobilePhoneNumber=Mobile +AefiInvestigation.reportingOfficerEmail=E-mail +AefiInvestigation.investigationDate=Date of investigation +AefiInvestigation.formCompletionDate=Date of filling this form +AefiInvestigation.investigationStage=This report is +AefiInvestigation.typeOfSite=Type of site +AefiInvestigation.typeOfSiteDetails=Type of site details +AefiInvestigation.keySymptomDateTime=Date & time of first/key symptom +AefiInvestigation.hospitalizationDate=Date of hospitalization +AefiInvestigation.reportedToHealthAuthorityDate=Date first reported to the health authority +AefiInvestigation.statusOnDateOfInvestigation=Status on the date of investigation +AefiInvestigation.deathDateTime=Date and time of death +AefiInvestigation.autopsyDone=Autopsy done? +AefiInvestigation.autopsyDate=Autopsy date +AefiInvestigation.autopsyPlannedDateTime=Autopsy planned on +AefiInvestigation.pastHistoryOfSimilarEvent=Past history of similar event +AefiInvestigation.pastHistoryOfSimilarEventDetails=Additional information +AefiInvestigation.adverseEventAfterPreviousVaccinations=Adverse event after previous vaccination(s) +AefiInvestigation.adverseEventAfterPreviousVaccinationsDetails=Additional information +AefiInvestigation.historyOfAllergyToVaccineDrugOrFood=History of allergy to vaccine, drug or food +AefiInvestigation.historyOfAllergyToVaccineDrugOrFoodDetails=Additional information +AefiInvestigation.preExistingIllnessThirtyDaysOrCongenitalDisorder=Pre-existing illness (30 days) / congenital disorder +AefiInvestigation.preExistingIllnessThirtyDaysOrCongenitalDisorderDetails=Additional information +AefiInvestigation.historyOfHospitalizationInLastThirtyDaysWithCause=History of hospitalization in last 30 days, with cause +AefiInvestigation.historyOfHospitalizationInLastThirtyDaysWithCauseDetails=Additional information +AefiInvestigation.currentlyOnConcomitantMedication=Patient currently on concomitant medication? +AefiInvestigation.currentlyOnConcomitantMedicationDetails=Additional information +AefiInvestigation.familyHistoryOfDiseaseOrAllergy=Family history of any disease (relevant to AEFI) or allergy +AefiInvestigation.familyHistoryOfDiseaseOrAllergyDetails=Additional information +AefiInvestigation.numberOfWeeksPregnant=Number of weeks pregnant +AefiInvestigation.birthTerm=The birth was +AefiInvestigation.birthWeight=Birth weight: +AefiInvestigation.deliveryProcedure=Delivery procedure +AefiInvestigation.deliveryProcedureDetails=Delivery procedure details +AefiInvestigation.seriousAefiInfoSource=Source of information +AefiInvestigation.seriousAefiInfoSourceDetails=Other source of information details +AefiInvestigation.seriousAefiVerbalAutopsyInfoSourceDetails=Please mention verbal autopsy source +AefiInvestigation.firstCaregiversName=Name of the person who first examined/treated the patient +AefiInvestigation.otherCaregiversNames=Name of other persons treating the patient +AefiInvestigation.otherSourcesWhoProvidedInfo=Other sources who provided information +AefiInvestigation.signsAndSymptomsFromTimeOfVaccination=Signs and symptoms in chronological order from the time of vaccination +AefiInvestigation.clinicalDetailsOfficerName=Name of person completing these clinical details +AefiInvestigation.clinicalDetailsOfficerPhoneNumber=Phone number +AefiInvestigation.clinicalDetailsOfficerEmail=E-mail +AefiInvestigation.clinicalDetailsOfficerDesignation=Designation +AefiInvestigation.clinicalDetailsDateTime=Date/time +AefiInvestigation.patientReceivedMedicalCare=Patient has received medical care +AefiInvestigation.patientReceivedMedicalCareDetails=Complete additional medical care information NOT AVAILABLE in existing documents +AefiInvestigation.provisionalOrFinalDiagnosis=Provisional / Final diagnosis +AefiInvestigation.patientImmunizedPeriod=When was the patient immunized? +AefiInvestigation.patientImmunizedPeriodDetails=Additional information +AefiInvestigation.vaccineGivenPeriod=In case of multidose vials, was the vaccine given +AefiInvestigation.vaccineGivenPeriodDetails=Additional information +AefiInvestigation.errorPrescribingVaccine=Was there an error in prescribing or non-adherence to recommendations for use of this vaccine? +AefiInvestigation.errorPrescribingVaccineDetails=Additional information +AefiInvestigation.vaccineCouldHaveBeenUnSterile=Based on your investigation, do you feel that the vaccine (ingredients) administered could have been unsterile? +AefiInvestigation.vaccineCouldHaveBeenUnSterileDetails=Additional information +AefiInvestigation.vaccinePhysicalConditionAbnormal=Based on your investigation, do you feel that the vaccine's physical condition (e.g. colour, turbidity, foreign substances etc.) was abnormal at the time of administration? +AefiInvestigation.vaccinePhysicalConditionAbnormalDetails=Additional information +AefiInvestigation.errorInVaccineReconstitution=Based on your investigation, do you feel that there was an error in vaccine reconstitution/preparation by the vaccinator (e.g. wrong product, wrong diluent, improper mixing, improper syringe filling etc.)? +AefiInvestigation.errorInVaccineReconstitutionDetails=Additional information +AefiInvestigation.errorInVaccineHandling=Based on your investigation, do you feel that there was an error in vaccine handling (e.g. break in cold chain during transport, storage and/or immunization session etc.)? +AefiInvestigation.errorInVaccineHandlingDetails=Additional information +AefiInvestigation.vaccineAdministeredIncorrectly=Based on your investigation, do you feel that the vaccine was administered incorrectly (e.g. wrong dose, site or route of administration, wrong needle size, not following good injection practice etc.)? +AefiInvestigation.vaccineAdministeredIncorrectlyDetails=Additional information +AefiInvestigation.numberImmunizedFromConcernedVaccineVial=Number immunized from the concerned vaccine vial/ampoule +AefiInvestigation.numberImmunizedWithConcernedVaccineInSameSession=Number immunized with the concerned vaccine in the same session +AefiInvestigation.numberImmunizedConcernedVaccineSameBatchNumberOtherLocations=Number immunized with the concerned vaccine having the same batch number in other locations +AefiInvestigation.numberImmunizedConcernedVaccineSameBatchNumberLocationDetails=Specify locations +AefiInvestigation.vaccineHasQualityDefect=Could the vaccine given to this patient have a quality defect or is substandard or falsified? +AefiInvestigation.vaccineHasQualityDefectDetails=Additional information +AefiInvestigation.eventIsAStressResponseRelatedToImmunization=Could this event be a stress response related to immunization (e.g. acute stress response, vasovagal reaction, hyperventilation, dissociative neurological symptom reaction etc.)? +AefiInvestigation.eventIsAStressResponseRelatedToImmunizationDetails=Additional information +AefiInvestigation.caseIsPartOfACluster=Is this case a part of a cluster? +AefiInvestigation.caseIsPartOfAClusterDetails=Additional information +AefiInvestigation.numberOfCasesDetectedInCluster=How many other cases have been detected in the cluster? +AefiInvestigation.allCasesInClusterReceivedVaccineFromSameVial=Did all the cases in the cluster receive vaccine from the same vial? +AefiInvestigation.allCasesInClusterReceivedVaccineFromSameVialDetails=Additional information +AefiInvestigation.numberOfVialsUsedInCluster=Number of vials used in the cluster +AefiInvestigation.numberOfVialsUsedInClusterDetails=Number of vials used in the cluster details +AefiInvestigation.adSyringesUsedForImmunization=Are AD syringes used for immunization? +AefiInvestigation.typeOfSyringesUsed=Type of syringes used +AefiInvestigation.typeOfSyringesUsedDetails=Additional information +AefiInvestigation.syringesUsedAdditionalDetails=Specific key findings/additional observations and comments +AefiInvestigation.sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine=Same reconstitution syringe used for multiple vials of same vaccine? +AefiInvestigation.sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines=Same reconstitution syringe used for reconstituting different vaccines? +AefiInvestigation.sameReconstitutionSyringeForEachVaccineVial=Separate reconstitution syringe for each vaccine vial? +AefiInvestigation.sameReconstitutionSyringeForEachVaccination=Separate reconstitution syringe for each vaccination? +AefiInvestigation.vaccinesAndDiluentsUsedRecommendedByManufacturer=Are the vaccines and diluents used the same as those recommended by the manufacturer? +AefiInvestigation.reconstitutionAdditionalDetails=Specific key findings/additional observations and comments +AefiInvestigation.correctDoseOrRoute=Correct dose and route? +AefiInvestigation.timeOfReconstitutionMentionedOnTheVial=Time of reconstitution mentioned on the vial? (in case of freeze dried vaccines) +AefiInvestigation.nonTouchTechniqueFollowed=Non-touch technique followed? +AefiInvestigation.contraIndicationScreenedPriorToVaccination=Contraindications screened prior to vaccination? +AefiInvestigation.numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays=How many AEFI were reported from the centre that distributed the vaccine in the last 30 days? +AefiInvestigation.trainingReceivedByVaccinator=Training received by the vaccinator? +AefiInvestigation.lastTrainingReceivedByVaccinatorDate=Date of last training +AefiInvestigation.injectionTechniqueAdditionalDetails=Specific key findings/ additional observations and comments? +AefiInvestigation.vaccineStorageRefrigeratorTemperatureMonitored=Is the temperature of the vaccine storage refrigerator monitored? +AefiInvestigation.anyStorageTemperatureDeviationOutsideTwoToEightDegrees=Was there any deviation outside of 2-8 (degrees C) after the vaccine was placed inside? +AefiInvestigation.storageTemperatureMonitoringAdditionalDetails=Provide details of monitoring separately +AefiInvestigation.correctProcedureForStorageFollowed=Was the correct procedure for storing vaccines, diluents and syringes followed? +AefiInvestigation.anyOtherItemInRefrigerator=Was any other item (other than EPI vaccines and diluents) in the refrigerator or freezer? +AefiInvestigation.partiallyUsedReconstitutedVaccinesInRefrigerator=Were any partially used reconstituted vaccines in the refrigerator? +AefiInvestigation.unusableVaccinesInRefrigerator=Were any unusable vaccines (expired, no label, VVM at stages 3 or 4, frozen) in the refrigerator? +AefiInvestigation.unusableDiluentsInStore=Were any unusable diluents (expired, manufacturer not matched, cracked, dirty ampoule) in the store? +AefiInvestigation.vaccineStoragePointAdditionalDetails=Specific key findings/additional observations and comments: +AefiInvestigation.vaccineCarrierType=Type of vaccine carrier used +AefiInvestigation.vaccineCarrierTypeDetails=Additional information +AefiInvestigation.vaccineCarrierSentToSiteOnSameDateAsVaccination=Was the vaccine carrier sent to the site on the same day as vaccination? +AefiInvestigation.vaccineCarrierReturnedFromSiteOnSameDateAsVaccination=Was the vaccine carrier returned from the site on the same day as vaccination? +AefiInvestigation.conditionedIcepackUsed=Was a conditioned ice-pack used? +AefiInvestigation.vaccineTransportationAdditionalDetails=Specific key findings/additional observations and comments +AefiInvestigation.similarEventsReportedSamePeriodAndLocality=Were any similar events reported within a time period similar to when the adverse event occurred and in the same locality? +AefiInvestigation.similarEventsReportedSamePeriodAndLocalityDetails=Additional information +AefiInvestigation.numberOfSimilarEventsReportedSamePeriodAndLocality=How many events/episodes? +AefiInvestigation.numberOfThoseAffectedVaccinated=Vaccinated +AefiInvestigation.numberOfThoseAffectedNotVaccinated=Not vaccinated +AefiInvestigation.numberOfThoseAffectedVaccinatedUnknown=Unknown +AefiInvestigation.communityInvestigationAdditionalDetails=Other comments: +AefiInvestigation.otherInvestigationFindings=Other findings/observations/comments +AefiInvestigation.investigationStatus=Investigation status +AefiInvestigation.investigationStatusDetails=Investigation status details +AefiInvestigation.aefiClassification=Classification of AEFI +AefiInvestigation.aefiClassificationSubType=Reason for classification +AefiInvestigation.aefiClassificationDetails=Classification of AEFI details +AefiInvestigation.causality=Causality +AefiInvestigation.causalityDetails=Causality details +AefiInvestigation.investigationCompletionDate=Date investigation completed +AefiInvestigation.deletionReason=Reason for deletion +AefiInvestigation.otherDeletionReason=Reason for deletion details +AefiInvestigation.creationDate=Creation date +AefiInvestigation.changeDate=Date of last change +aefiInvestigationForAdultWomen=For adult women +aefiInvestigationForInfants=For infants +aefiInvestigationSourceOfInformation=Source of information +aefiInvestigationClinicalDetailsOfficer=Clinical Details Officer +aefiInvestigationMedicalCareDetailsInstruction=**Instructions ? Attach copies of ALL available documents (including case sheet, discharge summary, case notes, laboratory reports and autopsy reports) and then complete additional information NOT AVAILABLE in existing documents, +aefiInvestigationReconstitutionProcedure=Reconstitution procedure +aefiInvestigationOfThoseAffected=Of those effected, how many are +aefiAefiInvestigationList=Adverse Event Investigations +aefiNewAefiInvestigation = New Investigation +aefiAefiInvestigationDataView=Adverse Event Investigation +aefiNewAefiInvestigationStageTitle=Investigation +aefiActiveInvestigations = Active AEFI investigations +aefiArchivedInvestigations = Archived AEFI investigations +aefiAllActiveAndArchivedInvestigations = All active and archived AEFI investigations +aefiDeletedInvestigations = Deleted AEFI investigations +titleAefiInvestigationBasicDetails=Section A: Basic details +titleAefiInvestigationRelevantPatientInformation=Section B: Relevant patient information prior to immunization +titleAefiInvestigationFirstExaminationDetails=Section C: Details of first examination** of serious AEFI case +titleAefiInvestigationVaccinesDetails=Section D: Details of vaccines provided at the site linked to AEFI on the corresponding day +titleAefiInvestigationImmunizationPractices=Section E: Immunization practices at the place(s) where concerned vaccine was used +titleAefiInvestigationImmunizationPracticesSubTitle=(Complete this section by asking and/or observing practice) +titleAefiInvestigationImmunizationPracticesSyringesAndNeedlesUsed=Syringes and needles used +titleAefiInvestigationImmunizationPracticesReconstitution=Reconstitution: (complete only if applicable) +titleAefiInvestigationImmunizationPracticesInjectionTechnique=Injection technique in vaccinator(s): (Observe another session in the same locality ? same or different place) +titleAefiInvestigationColdChainAndTransport=Section F: Cold chain and transport +titleAefiInvestigationColdChainAndTransportSubTitle=(Complete this section by asking and/or observing practice) +titleAefiInvestigationColdChainAndTransportLastVaccineStoragePoint=Last vaccine storage point +titleAefiInvestigationColdChainAndTransportVaccineTransportation=Vaccine transportation +titleAefiInvestigationCommunityInvestigation=Section G: Community investigation (Please visit locality and interview parents/others) +titleAefiInvestigationCommunityInvestigationThoseAffected=Of those effected, how many are +titleAefiInvestigationOtherFindings=Section H: Other findings/observations/comments +titleAefiInvestigationInvestigationStatus=Section I: Investigation Status +# Adverse Events Investigation Criteria +AefiInvestigationCriteria.statusAtAefiInvestigation=Patient status +AefiInvestigationCriteria.aefiClassification=Classification +AefiInvestigationCriteria.vaccineName=Vaccine +AefiInvestigationCriteria.vaccineManufacturer=Manufacturer +# Adverse Events Investigation Index +AefiInvestigationIndex.uuid=Investigation ID +AefiInvestigationIndex.aefiReportUuid=AEFI ID +AefiInvestigationIndex.investigationCaseId=Case ID +AefiInvestigationIndex.personFirstName=First Name +AefiInvestigationIndex.personLastName=Last Name +AefiInvestigationIndex.reportDate=Date of report +AefiInvestigationIndex.investigationDate=Date of investigation +AefiInvestigationIndex.disease=Disease +AefiInvestigationIndex.ageAndBirthDate=Age and birth date +AefiInvestigationIndex.sex=Sex +AefiInvestigationIndex.region=Region +AefiInvestigationIndex.district=District +AefiInvestigationIndex.primaryVaccine=Concerned Vaccine +AefiInvestigationIndex.statusOnDateOfInvestigation=Patient Status +AefiInvestigationIndex.investigationStatus=Status +AefiInvestigationIndex.aefiClassification=Classification # Statistics statisticsAddFilter=Add filter statisticsAttribute=Attribute @@ -2712,6 +3105,7 @@ View.dashboard.contacts=Contacts Dashboard View.dashboard.surveillance=Surveillance Dashboard View.dashboard.campaigns=Campaigns Dashboard View.dashboard.samples=Samples Dashboard +View.dashboard.adverseevents=Adverse Events Dashboard View.events=Event Directory View.events.archive=Event Archive View.events.data=Event Information @@ -2728,6 +3122,8 @@ View.samples.data=Sample Information View.samples.sub= View.travelEntries=Travel Entries Directory View.immunizations=Immunization Directory +View.adverseevents=Adverse Events Directory +View.adverseevents.investigations=AEFI Investigations Directory View.statistics=Statistics View.statistics.database-export=Database export View.tasks=Task Management diff --git a/sormas-api/src/main/resources/descriptions.properties b/sormas-api/src/main/resources/descriptions.properties index 74693af7bd6..7ecec3129c4 100644 --- a/sormas-api/src/main/resources/descriptions.properties +++ b/sormas-api/src/main/resources/descriptions.properties @@ -80,6 +80,7 @@ descContactOnlyWithReducedQuarantine = Only list contacts whose quarantine perio descContactIncludeContactsFromOtherJurisdictions = Include all contacts from other jurisdictions that you have access to, e.g. because you created them or their source case is in your jurisdiction descGdpr = Reminder: All comments entered must comply with GDPR rules as described during connection. discardDescription = Discards any unsaved changes +birthdateFilterPartialMatchDescription = If checked the search will include also the persons that have incomplete birthdate and have only higher level match eg. only year or only year and month # EpiData EpiData.bats = Did you have contact with live or dead bats or their excreta during the incubation period? @@ -232,4 +233,8 @@ sampleDashboardRegionFilter= The region of the associated Case/Contact/Event par sampleDashboardDistrictFilter= The district of the associated Case/Contact/Event participant sampleDashboardDiseaseFilter= The disease of the associated Case/Contact/Event participant's event sampleDashboardCountsByShipmentStatus=Only samples with the purpose external lab testing are considered -sampleDashboardCountsBySpecimenCondition=Only samples received and with the purpose external lab testing are considered \ No newline at end of file +sampleDashboardCountsBySpecimenCondition=Only samples received and with the purpose external lab testing are considered + +aefiDashboardRegionFilter= The region of the associated immunization +aefiDashboardDistrictFilter= The district of the associated immunization +aefiDashboardDiseaseFilter= The disease of the associated immunization \ No newline at end of file diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index 5f40f0c4d24..7908fc14d84 100644 Binary files a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx and b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx differ diff --git a/sormas-api/src/main/resources/doc/SORMAS_User_Roles.xlsx b/sormas-api/src/main/resources/doc/SORMAS_User_Roles.xlsx index c473ed74db7..cb90708708e 100644 Binary files a/sormas-api/src/main/resources/doc/SORMAS_User_Roles.xlsx and b/sormas-api/src/main/resources/doc/SORMAS_User_Roles.xlsx differ diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index 35fa86fe9f5..f9ed852643b 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -291,6 +291,7 @@ CustomizableEnumType.PATHOGEN = Pathogen DashboardType.CONTACTS = Contacts DashboardType.SURVEILLANCE = Surveillance DashboardType.CAMPAIGNS = Campaigns +DashboardType.ADVERSE_EVENTS = Adverse Events # DatabaseTable DatabaseTable.ACTIONS = Actions @@ -500,6 +501,7 @@ Disease.YAWS_ENDEMIC_SYPHILIS = Yaws and Endemic Syphilis Disease.MATERNAL_DEATHS = Maternal Deaths Disease.PERINATAL_DEATHS = Perinatal Deaths Disease.CORONAVIRUS = COVID-19 +Disease.INFLUENZA=Influenza Disease.INFLUENZA_A = Influenza A Disease.INFLUENZA_B = Influenza B Disease.H_METAPNEUMOVIRUS = H.metapneumovirus @@ -1550,6 +1552,12 @@ UserRight.IMMUNIZATION_CREATE = Create new immunizations and vaccinations UserRight.IMMUNIZATION_EDIT = Edit existing immunizations and vaccinations UserRight.IMMUNIZATION_DELETE = Delete immunizations and vaccinations from the system UserRight.IMMUNIZATION_ARCHIVE = Archive immunizations +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW = View existing adverse events following immunization +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE = Create new adverse event following immunization +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT = Edit existing adverse event following immunization +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE = Delete adverse events following immunization from the system +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE = Archive adverse events following immunization +UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT = Export adverse events following immunization UserRight.PERSON_EXPORT = Export persons UserRight.CONTACT_MERGE = Merge contacts UserRight.EVENTGROUP_CREATE = Create new event groups @@ -1768,6 +1776,12 @@ UserRight.Desc.IMMUNIZATION_CREATE = Able to create new immunizations and vaccin UserRight.Desc.IMMUNIZATION_EDIT = Able to edit existing immunizations and vaccinations UserRight.Desc.IMMUNIZATION_DELETE = Able to delete immunizations and vaccinations from the system UserRight.Desc.IMMUNIZATION_ARCHIVE = Able to archive immunizations +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW = Able to view existing adverse events following immunization +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE = Able to create new adverse event following immunization +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT = Able to edit existing adverse events following immunization +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE = Able to delete adverse events following immunization from the system +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE = Able to archive adverse events following immunization +UserRight.Desc.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT = Able to export adverse events following immunization UserRight.Desc.PERSON_EXPORT = Able to export persons UserRight.Desc.CONTACT_MERGE = Able to merge contacts UserRight.Desc.EVENTGROUP_CREATE = Able to create new event groups @@ -1838,6 +1852,7 @@ UserRightGroup.CONTACT = Contact Surveillance UserRightGroup.VISIT = Follow-Up UserRightGroup.SAMPLE = Sample Testing UserRightGroup.IMMUNIZATION = Immunization +UserRightGroup.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION = Adverse Events Following Immunization UserRightGroup.TRAVEL_ENTRY = Travel Entries UserRightGroup.TASK = Tasks UserRightGroup.EVENT = Events @@ -2061,16 +2076,24 @@ Vaccine.VALNEVA=inactivated (Valneva) Vaccine.NUVAXOVID=protein-based, recombinant (Novavax) Vaccine.MRNA_BIVALENT_BA_4_5_BIONTECH_PFIZER=mRNA/bivalent BA.4/5 (BioNTech/Pfizer) Vaccine.MRNA_BIVALENT_BA_4_5_MODERNA=mRNA/bivalent BA.4/5 (Moderna) +Vaccine.MenABCWY=PENBRAYA +Vaccine.ACAM2000=ACAM2000 +Vaccine.LC_16=LC-16 +Vaccine.MVA_BN=JYNNEOS Vaccine.UNKNOWN=Unknown Vaccine.OTHER=Other # VaccineManufacturer VaccineManufacturer.BIONTECH_PFIZER=BioNTech/Pfizer +VaccineManufacturer.PFIZER=Pfizer +VaccineManufacturer.BAVARIAN_NORDIC=Bavarian Nordic VaccineManufacturer.MODERNA=Moderna VaccineManufacturer.ASTRA_ZENECA=AstraZeneca VaccineManufacturer.JOHNSON_JOHNSON=Johnson & Johnson +VaccineManufacturer.KM_BIOLOGICS=KM Biologics VaccineManufacturer.NOVAVAX=Novavax VaccineManufacturer.SANOFI_GSK=Sanofi-GSK +VaccineManufacturer.SANOFI_PASTEUR_BIOLOGICS=Sanofi Pasteur Biologics VaccineManufacturer.ASTRA_ZENECA_BIONTECH_PFIZER=AstraZeneca & BioNTech/Pfizer VaccineManufacturer.ASTRA_ZENECA_MODERNA=AstraZeneca & Moderna VaccineManufacturer.VALNEVA=Valneva @@ -2181,21 +2204,6 @@ MeansOfImmunization.RECOVERY = Recovery MeansOfImmunization.VACCINATION_RECOVERY = Vaccination/Recovery MeansOfImmunization.OTHER = Other -#EntityColumn -EntityColumn.ENTITY = Entity -EntityColumn.FIELD_ID = Field ID -EntityColumn.FIELD = Field -EntityColumn.TYPE = Type -EntityColumn.DATA_PROTECTION = Data protection -EntityColumn.CAPTION = Caption -EntityColumn.DESCRIPTION = Description -EntityColumn.REQUIRED = Required -EntityColumn.NEW_DISEASE = New disease -EntityColumn.DISEASES = Diseases -EntityColumn.OUTBREAKS = Outbreaks -EntityColumn.IGNORED_COUNTRIES = Ignored countries -EntityColumn.EXCLUSIVE_COUNTRIES = Exclusive countries - #EnumColumn EnumColumn.TYPE = Type EnumColumn.VALUE = Value @@ -2333,3 +2341,133 @@ SelfReportInvestigationStatus.REJECTED=Rejected # SelfReportProcessingStatus SelfReportProcessingStatus.UNPROCESSED=Unprocessed SelfReportProcessingStatus.PROCESSED=Processed + +# AefiAgeGroup +AefiAgeGroup.ZERO_TO_ONE = 0 < 1 year +AefiAgeGroup.ONE_TO_FIVE = 1- 5 years +AefiAgeGroup.FIVE_TO_EIGHTEEN = > 5 years - 18 years +AefiAgeGroup.EIGHTEEN_TO_SIXTY = > 18 years - 60 years +AefiAgeGroup.SIXY_AND_ABOVE = > 60 years + +# SeizureType +SeizureType.FEBRILE=Febrile +SeizureType.AFEBRILE=Afebrile + +# SeriousAefiReason +SeriousAefiReason.DEATH=Death +SeriousAefiReason.LIFE_THREATENING=Life threatening +SeriousAefiReason.DISABILITY=Disability +SeriousAefiReason.HOSPITALIZATION=Hospitalization +SeriousAefiReason.CONGENITAL_ANOMALY=Congenital anomaly +SeriousAefiReason.OTHER=Other + +# AefiOutcome +AefiOutcome.RECOVERING=Recovering +AefiOutcome.RECOVERED=Recovered +AefiOutcome.RECOVERED_WITH_SEQUELAE=Recovered with sequelae +AefiOutcome.NOT_RECOVERED=Not Recovered +AefiOutcome.UNKNOWN=Unknown +AefiOutcome.DIED=Died + +# AefiType +AefiType.SERIOUS=Serious +AefiType.NON_SERIOUS=Non-serious + +# AefiDateType +AefiDateType.REPORT_DATE=Date of report +AefiDateType.START_DATE=Date of onset +AefiDateType.VACCINATION_DATE=Date of vaccination + +# AefiDashboardFilterDateType +AefiDashboardFilterDateType.REPORT_DATE=Date of report +AefiDashboardFilterDateType.START_DATE=Date of onset + +# AefiInvestigationDateType +AefiInvestigationDateType.REPORT_DATE=Date of report +AefiInvestigationDateType.INVESTIGATION_DATE=Date of investigation +AefiInvestigationDateType.VACCINATION_DATE=Date of vaccination + +# PlaceOfVaccination +PlaceOfVaccination.GOVERNMENT_HEALTH_FACILITY=Government health facility +PlaceOfVaccination.PRIVATE_HEALTH_FACILITY=Private health facility +PlaceOfVaccination.OTHER=Other + +# VaccinationActivity +VaccinationActivity.CAMPAIGN=Campaign +VaccinationActivity.ROUTINE=Routine +VaccinationActivity.OTHER=Other + +# AefiInvestigationStage +AefiInvestigationStage.FIRST=First +AefiInvestigationStage.INTERIM=Interim +AefiInvestigationStage.FINAL=Final + +# VaccinationSite +VaccinationSite.FIXED=Fixed +VaccinationSite.MOBILE=Mobile +VaccinationSite.OUTREACH=Outreach +VaccinationSite.OTHER=Other + +# PatientStatusAtAefiInvestigation +PatientStatusAtAefiInvestigation.DIED=Died +PatientStatusAtAefiInvestigation.DISABLED=Disabled +PatientStatusAtAefiInvestigation.RECOVERED=Recovering +PatientStatusAtAefiInvestigation.RECOVERED_COMPLETELY=Recovered completely +PatientStatusAtAefiInvestigation.UNKNOWN=Unknown + +# BirthTerm +BirthTerm.FULL_TERM=Full-term +BirthTerm.PRE_TERM=Pre-term +BirthTerm.POST_TERM=Post-term + +# DeliveryProcedure +DeliveryProcedure.NORMAL=Normal +DeliveryProcedure.CAESAREAN=Caesarean +DeliveryProcedure.ASSISTED=Assisted (forceps, vacuum etc.) +DeliveryProcedure.WITH_COMPLICATION=with complication + +# SeriousAefiInfoSource +SeriousAefiInfoSource.EXAMINATION=Examination by the investigator +SeriousAefiInfoSource.DOCUMENTS=Documents +SeriousAefiInfoSource.VERBAL_AUTOPSY=Verbal autopsy +SeriousAefiInfoSource.OTHER=Other + +# AefiImmunizationPeriod +AefiImmunizationPeriod.WITHIN_FIRST_VACCINATIONS=Within the first vaccinations of the session +AefiImmunizationPeriod.WITHIN_LAST_VACCINATIONS=Within the last vaccinations of the session +AefiImmunizationPeriod.UNKNOWN=Unknown + +# AefiVaccinationPeriod +AefiVaccinationPeriod.WITHIN_FIRST_FEW_DOSES=Within the first few doses of the vial administered +AefiVaccinationPeriod.WITHIN_LAST_DOSES=Within the last doses of the vial administered +AefiVaccinationPeriod.UNKNOWN=Unknown + +# SyringeType +SyringeType.GLASS=Glass +SyringeType.DISPOSABLE=Disposable +SyringeType.RECYCLED_DISPOSABLE=Recycled disposable +SyringeType.OTHER=Other + +# VaccineCarrier +VaccineCarrier.SHORT_RANGE=Short range +VaccineCarrier.LONG_RANGE=Long range +VaccineCarrier.OTHER=Other + +# AefiInvestigationStatus +AefiInvestigationStatus.DONE=Done +AefiInvestigationStatus.DISCARDED=Discarded + +# AefiCausality +AefiCausality.CONFIRMED=Confirmed +AefiCausality.INCONCLUSIVE=Inconclusive + +# AefiClassification +AefiClassification.RELATED_TO_VACCINE_OR_VACCINATION=Related to vaccine or vaccination +AefiClassification.COINCIDENTAL_ADVERSE_EVENT=Coincidental adverse event +AefiClassification.UNDETERMINED=Undetermined + +# AefiClassificationSubType +AefiClassificationSubType.VACCINE_PRODUCT_RELATED=Vaccine product related +AefiClassificationSubType.VACCINE_QUALITY_DEFECT_RELATED=Vaccine quality defect related +AefiClassificationSubType.IMMUNIZATION_ERROR_RELATED=Immunization error related +AefiClassificationSubType.IMMUNIZATION_ANXIETY_RELATED=Immunization anxiety related \ No newline at end of file diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index fc1854df695..b091bed4353 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -136,6 +136,8 @@ confirmationArchiveEvent = Are you sure you want to archive this event? This wil confirmationArchiveEvents = Are you sure you want to archive all %d selected events? confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. +confirmationArchiveAdverseEvent = Are you sure you want to archive this adverse event? This will not remove it from the system or any statistics, but only hide it from the normal adverse events directory. +confirmationArchiveAdverseEventInvestigation = Are you sure you want to archive this adverse event investigation? This will not remove it from the system or any statistics, but only hide it from the normal adverse events investigation directory. confirmationArchiveTask = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. confirmationArchiveTasks = Are you sure you want to archive all %d selected tasks? confirmationArchiveTravelEntry = Are you sure you want to archive this travel entry? This will not remove it from the system or any statistics, but only hide it from the normal travel entry directory. @@ -217,6 +219,8 @@ confirmationDearchiveCommunities = Are you sure you want to de-archive all %d se confirmationArchiveFacilities = Are you sure you want to archive all %d selected facilities? confirmationDearchiveFacilities = Are you sure you want to de-archive all %d selected facilities? confirmationDearchiveImmunization = Are you sure you want to de-archive this immunization? This will make it appear in the normal immunization directory again. +confirmationDearchiveAdverseEvent = Are you sure you want to de-archive this adverse event? This will make it appear in the normal adverse events directory again. +confirmationDearchiveAdverseEventInvestigation = Are you sure you want to de-archive this adverse event investigation? This will make it appear in the normal adverse events investigation directory again. confirmationArchiveLaboratories = Are you sure you want to archive all %d selected laboratories? confirmationDearchiveLaboratories = Are you sure you want to de-archive all %d selected laboratories? confirmationDearchiveTask = Are you sure you want to de-archive this task? This will make it appear in the normal task directory again. @@ -339,6 +343,14 @@ entityUsers = Users entityVaccinations = Vaccinations entityVisits = Visits entityWeeklyReports = Weekly reports +entityOutbreaks = Outbreaks +entityCustomizableEnumValues = Customizable enum values +entityCampaignFormMeta = Campaign form meta +entityCampaignFormData = Campaign form data +entityAdverseEvent = Adverse event +entityAdverseEvents = Adverse events +entityAdverseEventInvestigation = Adverse event investigation +entityAdverseEventInvestigations = Adverse event investigations # Error Messages errorAccessDenied=You do not have the required rights to view this page. @@ -426,7 +438,10 @@ errorEnvironmentSampleNoDispatchRight = You do not have the necessary user right errorEnvironmentSampleNoReceivalRight = You do not have the necessary user right to change the receival status of this environment sample errorSendingExternalEmail = Email could not be sent. Please contact an admin and notify them about this problem. errorExternalEmailAttachmentCannotEncrypt=Can't send email with attachments. The person has no national health id or primary phone number to send the password to or the SMS service is not set up in the system. +errorAdverseEventNotEditable = This adverse event is not editable anymore +errorAdverseEventInvestigationNotEditable = This adverse event investigation is not editable anymore errorExternalEmailMissingPersonEmailAddress=This person does not have an email address +errorDocumentTemplateWorkflowChangeNotAllowed=The workflow of this document template cannot be changed. # headings headingAccessDenied = Access denied @@ -442,6 +457,8 @@ headingArchiveEvent = Archive event headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization +headingArchiveAdverseEvent = Archive adverse event +headingArchiveAdverseEventInvestigation = Archive adverse event investigation headingArchiveTravelEntry = Archive travel entry headingCampaignBasics = Campaign basics headingCampaignData = Campaign data @@ -517,6 +534,8 @@ headingDearchiveEvent = De-Archive event headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization +headingDearchiveAdverseEvent = De-Archive adverse event +headingDearchiveAdverseEventInvestigation = De-Archive adverse event investigation headingDearchiveTravelEntry = De-Archive travel entry headingDefineOutbreakDistricts = Define which districts currently are affected by an outbreak. headingDeleteConfirmation = Confirm deletion @@ -601,6 +620,7 @@ headingImportRegions= Import Regions headingImportTravelEntries = Import Travel Entries headingImportEnvironments = Import Environments headingImportSelfReports = Import Self Reports +headingIncorrectDateRange = Incorrect date range headingInformationSource = Source of Information headingInfrastructureLocked = Infrastructure locked headingIntroduction = Introduction @@ -678,6 +698,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 @@ -873,6 +894,21 @@ headingLimitedDiseases=Disease restrictions headingExternalEmailSend=Send email headingExternalEmailDetails=Email details headingCustomizableEnumConfigurationInfo=Customizable enum configuration +headingImmunizationAdverseEvents=Adverse events +headingAefiDashboardEpiCurve=Adverse Events Type Chart +headingAefiDashboardMap=Adverse Events Status Map +headingAefiReportingInformation=Reporting information +headingAefiPatientsIdentification=Patients identification +headingAefiPatientsAgeAtOnset=Age at onset +headingAefiVaccinations=Vaccinations +headingAefiAdverseEvents=Adverse events +headingAefiFirstDecisionLevel=First decision Level +headingAefiNationalDecisionLevel=National Decision Level +headingAefiReportersInformation=Reporter's information +headingAefiSelectPrimarySuspectVaccine=Select primary suspect vaccine +headingAefiReportInvestigations=Investigations +headingAefiInvestigationSelectConcernedVaccine=Select concerned vaccine +headingAefiInvestigationFormSubHeading=(Only for Serious Adverse Events Following Immunization ? Death / Disability / Hospitalization / Cluster) # Info texts infoActivityAsCaseInvestigation = Please document ALL relevant activities after infection: @@ -1032,6 +1068,7 @@ infoContactsViewRegionDistrictFilter = When you select a region and/or district infoDeveloperOptions = You can use the controls below to generate dummy cases and contacts based on the selected restraints. Please note that generating a lot of data at once might take some time.
Generated data is neither fully deterministic, nor fully random, and intended for testing and demonstration purposes only. infoDeveloperOptionsContactGeneration = When generating contacts, the generator will pick random existing cases as source. Please make sure the case database is not empty before generating contacts. infoDeveloperOptionsSeedUsage = Using the seed will create identical datasets, provided the starting conditions (configuration & database) are also identical +infoCreateNewSampleDiscardsChangesCase = Creating a new sample will discard all unsaved changes made to this case infoCreateNewSampleDiscardsChangesContact = Creating a new sample will discard all unsaved changes made to this contact infoCreateNewSampleDiscardsChangesEventParticipant = Creating a new sample will discard all unsaved changes made to this event participant infoUsageOfEditableCampaignGrids = You can edit the campaign data and dashboard definitions by clicking inside one of the cells in the grid, and you can reorder the dashboard elements by dragging and dropping the grid rows @@ -1074,6 +1111,11 @@ infoNoEnvironmentSamples = No samples have been created for this environment infoRestrictDiseasesDescription=Mark all diseases that the user is supposed to have access to infoNoCustomizableEnumTranslations = Click on the + button below to add translations to this customizable enum value. infoCustomizableEnumConfigurationInfo = Customizable enums are value sets that can be customized in order to react to the individual needs of your country or a specific epidemiological situation. The table on this screen contains all customizable enum values in the database. Each value is associated with a data type, e.g. disease variants or occupation types. Some of these data types have default values that are automatically added to the database when SORMAS is set up or new data types are added to the system.

You can add new enum values or edit existing ones, add translations for languages supported by SORMAS, select the diseases that the value should be visible for (by default, customizable enum values are visible for all diseases), and configure additional properties.

Properties are used to further control the behaviour of customizable enum values. E.g. the "has details" property that is supported by most enum values toggles whether selecting this enum value would bring up an additional text field that users can add more information to. +infoNoImmunizationAdverseEvents = No adverse events have been created for this immunization +infoAefiSelectPrimarySuspectVaccine = The list below contains all vaccinations of the immunization. Please select the suspect vaccination related to this adverse event. +infoArchivedAefiEntries = Adverse event entries are automatically archived after %d days without changes to the data. +infoNoAefiInvestigations = No investigations have been created for this adverse event +infoHeadingAefiDashboardMap=Adverse events are shown using the GPS coordinate of the facility or person's home address. # Messages messageActionOutsideJurisdictionDeletionDenied = The action outside user's jurisdiction cannot be deleted @@ -1255,6 +1297,10 @@ messageImmunizationDearchived = Immunization has been de-archived messageImmunizationOutsideJurisdictionDeletionDenied = The immunization outside user's jurisdiction cannot be deleted messageImmunizationSaved = Immunization data saved. messageImmunizationSavedVaccinationStatusUpdated = Immunization data saved. The vaccination status of matching cases, contacts, and event participants of the immunization person has been updated to vaccinated. +messageAdverseEventArchived = Adverse event has been archived +messageAdverseEventDearchived = Adverse event has been de-archived +messageAdverseEventInvestigationArchived = Adverse event investigation has been archived +messageAdverseEventInvestigationDearchived = Adverse event investigation has been de-archived messageImportCanceled = Import canceled!
The import has been canceled. All already processed rows have been successfully imported. You can now close this window. messageImportCanceledErrors = Import canceled!
The import has been canceled. Some of the already processed rows could not be imported due to malformed data.
Please close this window and download the error report. messageImportError = Could not import file. @@ -1269,6 +1315,7 @@ messageImportSuccessful = Import successful!
All rows have been impor messageImportSuccessfulWithSkips = Import successful!
The import has been successful, but some of the rows were skipped. You can now close this window. messageUploadSuccessful = Upload successful! You can now close this window. messageIncompleteGpsCoordinates = GPS coordinates are incomplete +messageIncorrectDateRange = Date from is after date to messageExternalMessagesAssigned = The assignee has been changed for all selected messages messageLoginFailed = Please check your username and password and try again messageMissingCases = Please generate some cases before generating contacts @@ -1520,8 +1567,11 @@ messageExternalEmailNoAttachments=No attachments messageCustomizableEnumValueSaved = Customizable enum value saved messageExternalEmailAttachmentPassword=Please use this password to open the documents sent to you via email from SORMAS: %s messageExternalEmailAttachmentNotAvailableInfo=Attaching documents is disabled because encryption would not be possible. To encrypt documents, the person needs to have either a national health ID specified, or a primary mobile phone number set with SMS sending set up on this system. +messageAdverseEventSaved=Adverse event saved +messageAdverseEventInvestigationSaved=Adverse event investigation saved messagePersonNationalHealthIdInvalid=The entered national health ID does not seem to be correct messageSyncUsersFromAuthProviderConfigurationError=Syncing users from authentication provider is not possible because the configuration is incorrect. Please contact an admin and inform them about this issue. +messageCountriesExcludedFromDataProtection=Countries excluded from data protection for this field: # Notifications notificationCaseClassificationChanged = The classification of case %s has changed to %s. @@ -1603,6 +1653,8 @@ promptActionChangeDateFrom = Date of action change from... promptActionChangeDateTo = ... to promptActionChangeEpiWeekFrom = Date of action change from epi week... promptActionChangeEpiWeekTo = ... to epi week +promptBirthdateFrom = Birthdate from +promptBirthdateTo = ... to promptCampaignSearch = ID, name promptCasesDateFrom = New cases from... promptCasesEpiWeekFrom = New cases from epi week... @@ -1642,6 +1694,7 @@ promptImmunizationDateFrom = New immunizations from... promptImmunizationDateTo = ... to promptImmunizationEpiWeekFrom = New immunizations from epi week... promptImmunizationEpiWeekTo = ... to epi week +promptEmail = Email: promptExternalMessagesSearchField = UUID, name, postal code, reporter name, reporter postal code promptExternalMessagesContentSearchField = External message content promptExternalMessagesDateFrom = Message date from... @@ -1660,6 +1713,7 @@ promptSampleEpiWeekTo = ... to epi week promtSampleDataType = Sample reference date promptSearch = Search... promptTaskSearchField = Case or contact ID/name, Event ID/title +promptTelephoneNumber = Phone number: promptTaskDateType = Task reference date promptTaskDateFrom = Tasks from... promptTaskDateTo = ... to @@ -1685,7 +1739,21 @@ promptAllDistricts=All districts promptAllCommunities=All communities promptExternalIdExternalSurveillanceTool=Will adopt external reporting tool GUID promptExternalJournalForceDeletion=Do you want to force the cancellation in SORMAS? This would mark the person as deleted from the external journal in SORMAS, while there is a high probability of personal data still remaining in the external journal. -promptPersonDuplicateSearchIdExternalId=First Name, Last Name, ID, External ID, External token +promptPersonDuplicateSearchIdExternalId=First Name, Last Name, ID, External ID, External token +promptAefiDashboardFilterDateType=AEFI reference date +promptAefiDateType = Aefi reference date +promptAefiValidFrom = New adverse events valid from... +promptAefiDateFrom = New adverse events from... +promptAefiDateTo = ... to +promptAefiEpiWeekFrom = New adverse events from epi week... +promptAefiEpiWeekTo = ... to epi week +promptAefiInvestigationDateType = Aefi investigation reference date +promptAefiInvestigationValidFrom = New Aefi investigations valid from... +promptAefiInvestigationDateFrom = New Aefi investigations from... +promptAefiInvestigationDateTo = ... to +promptAefiInvestigationEpiWeekFrom = New Aefi investigations from epi week... +promptAefiInvestigationEpiWeekTo = ... to epi week +promptRemarks = Remarks #DiseaseNetworkDiagram DiseaseNetworkDiagram.Classification.HEALTHY = Healthy DiseaseNetworkDiagram.heading = Disease network diagram diff --git a/sormas-api/src/main/resources/validations.properties b/sormas-api/src/main/resources/validations.properties index 2e875813934..f1030a60038 100644 --- a/sormas-api/src/main/resources/validations.properties +++ b/sormas-api/src/main/resources/validations.properties @@ -297,6 +297,12 @@ customizableEnumValueEmptyTranslations = Please select languages and enter capti customizableEnumValueDuplicateLanguage = Please only add one translation per language. customizableEnumValueDuplicateValue = The value %s already exists for data type %s. Enum values have to be unique. attachedDocumentNotRelatedToEntity=The attached document is not related to the entity. +aefiWithoutSuspectVaccines=You have to select at least one suspect vaccine +aefiWithoutPrimarySuspectVaccine=You have to select the primary suspect vaccine +aefiWithoutAdverseEvents=You have to select at least one adverse event +validAefiReport=You have to link a valid adverse event report +aefiInvestigationWithoutSuspectVaccines=You have to select at least one suspect vaccine +aefiInvestigationWithoutPrimarySuspectVaccine=You have to select the concerned suspect vaccine invalidNationalHealthId=This value does not seem to be a correct national health ID invalidSelfReportType = Invalid SelfReport type selfReportAlreadyProcessedError = The self report was processed by another user in the meantime. diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/campaign/edit/CampaignFormMetaDialog.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/campaign/edit/CampaignFormMetaDialog.java index 29673179c3b..27e92f75b31 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/campaign/edit/CampaignFormMetaDialog.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/campaign/edit/CampaignFormMetaDialog.java @@ -30,6 +30,7 @@ import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.campaign.Campaign; import de.symeda.sormas.app.backend.campaign.form.CampaignFormMeta; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.component.dialog.FormDialog; import de.symeda.sormas.app.component.validation.FragmentValidator; import de.symeda.sormas.app.core.notification.NotificationHelper; @@ -51,7 +52,7 @@ public CampaignFormMetaDialog(final FragmentActivity activity, Campaign campaign R.layout.dialog_root_two_button_panel_layout, R.string.heading_campaign_form_meta_select, -1, - UiFieldAccessCheckers.forSensitiveData(campaign.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(campaign.isPseudonymized(), ConfigProvider.getServerCountryCode())); this.campaign = campaign; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditFragment.java index a745274ebc9..7824dbb0fb1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditFragment.java @@ -130,7 +130,7 @@ public static CaseEditFragment newInstance(Case activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); caseEditFragment.differentPlaceOfStayJurisdiction = activityRootData.getRegion() != null || activityRootData.getDistrict() != null || activityRootData.getCommunity() != null; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java index ce6f13e5bfa..3e44e0f4300 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java @@ -33,7 +33,7 @@ public static CaseEditHealthConditionsFragment newInstance(Case activityRootData activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHospitalizationFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHospitalizationFragment.java index 40412340395..4b6aa3afcb1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHospitalizationFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHospitalizationFragment.java @@ -33,6 +33,7 @@ import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.hospitalization.Hospitalization; import de.symeda.sormas.app.backend.hospitalization.PreviousHospitalization; import de.symeda.sormas.app.component.Item; @@ -57,7 +58,7 @@ public static CaseEditHospitalizationFragment newInstance(Case activityRootData) null, activityRootData, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Instance methods diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditMaternalHistoryFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditMaternalHistoryFragment.java index 68fdfac57af..da101799ed6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditMaternalHistoryFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditMaternalHistoryFragment.java @@ -25,6 +25,7 @@ import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.caze.maternalhistory.MaternalHistory; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.component.Item; import de.symeda.sormas.app.databinding.FragmentCaseEditMaternalHistoryLayoutBinding; import de.symeda.sormas.app.util.InfrastructureDaoHelper; @@ -44,7 +45,7 @@ public static CaseEditMaternalHistoryFragment newInstance(Case activityRootData) null, activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Overrides diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/PreviousHospitalizationDialog.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/PreviousHospitalizationDialog.java index e7eba2bdd69..affbc8e7b06 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/PreviousHospitalizationDialog.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/PreviousHospitalizationDialog.java @@ -30,6 +30,7 @@ import de.symeda.sormas.api.utils.ValidationException; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.app.R; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.hospitalization.PreviousHospitalization; import de.symeda.sormas.app.backend.infrastructure.InfrastructureHelper; import de.symeda.sormas.app.component.Item; @@ -60,7 +61,7 @@ public class PreviousHospitalizationDialog extends FormDialog { R.layout.dialog_root_three_button_panel_layout, R.string.heading_previous_hospitalization, -1, - UiFieldAccessCheckers.forSensitiveData(previousHospitalization.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(previousHospitalization.isPseudonymized(), ConfigProvider.getServerCountryCode())); this.data = previousHospitalization; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadFragment.java index 077d9d9aaa3..4bd14c8f7d8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadFragment.java @@ -61,7 +61,7 @@ public static CaseReadFragment newInstance(Case activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); return caseReadFragment; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHospitalizationFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHospitalizationFragment.java index 4564ed6e324..979c4da09d7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHospitalizationFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHospitalizationFragment.java @@ -28,6 +28,7 @@ import de.symeda.sormas.app.BaseReadFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.hospitalization.Hospitalization; import de.symeda.sormas.app.backend.hospitalization.PreviousHospitalization; import de.symeda.sormas.app.databinding.FragmentCaseReadHospitalizationLayoutBinding; @@ -48,7 +49,7 @@ public static CaseReadHospitalizationFragment newInstance(Case activityRootData) null, activityRootData, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Overrides diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/clinicalcourse/edit/ClinicalVisitEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/clinicalcourse/edit/ClinicalVisitEditFragment.java index 08890964398..14f2cdd48d9 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/clinicalcourse/edit/ClinicalVisitEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/clinicalcourse/edit/ClinicalVisitEditFragment.java @@ -20,6 +20,7 @@ import de.symeda.sormas.app.BaseEditFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.clinicalcourse.ClinicalVisit; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.databinding.FragmentClinicalVisitEditLayoutBinding; public class ClinicalVisitEditFragment extends BaseEditFragment { @@ -32,7 +33,7 @@ public static ClinicalVisitEditFragment newInstance(ClinicalVisit activityRootDa null, activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/edit/ContactEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/edit/ContactEditFragment.java index aa7562c8386..25cc150e405 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/edit/ContactEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/edit/ContactEditFragment.java @@ -85,7 +85,7 @@ public static ContactEditFragment newInstance(Contact activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } private void setUpControlListeners(FragmentContactEditLayoutBinding contentBinding) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/environment/read/EnvironmentReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/environment/read/EnvironmentReadFragment.java index e867e084bf2..2b8552be226 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/environment/read/EnvironmentReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/environment/read/EnvironmentReadFragment.java @@ -27,7 +27,7 @@ public static EnvironmentReadFragment newInstance(Environment activityRootData) null, activityRootData, FieldVisibilityCheckers.getNoop(), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); return environmentReadFragment; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/environmentsample/edit/EnvironmentSampleEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/environmentsample/edit/EnvironmentSampleEditFragment.java index 43962036f0a..62779c16cfe 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/environmentsample/edit/EnvironmentSampleEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/environmentsample/edit/EnvironmentSampleEditFragment.java @@ -68,7 +68,7 @@ public static EnvironmentSampleEditFragment newInstance(EnvironmentSample activi null, activityRootData, FieldVisibilityCheckers.withCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized()), + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode()), UserRight.ENVIRONMENT_SAMPLE_EDIT); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ActivityAsCaseDialog.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ActivityAsCaseDialog.java index b8cad52e02e..3677e6d4042 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ActivityAsCaseDialog.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ActivityAsCaseDialog.java @@ -60,7 +60,7 @@ public class ActivityAsCaseDialog extends FormDialog { R.string.heading_activityAsCase, -1, false, - UiFieldAccessCheckers.forSensitiveData(activityAsCase.isPseudonymized()), + UiFieldAccessCheckers.forSensitiveData(activityAsCase.isPseudonymized(), ConfigProvider.getServerCountryCode()), FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(activityRootData)).andWithCountry(ConfigProvider.getServerCountryCode())); this.data = activityAsCase; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataEditFragment.java index d07c6db21d6..c4a422a7db1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataEditFragment.java @@ -41,6 +41,7 @@ import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.common.PseudonymizableAdo; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.contact.Contact; import de.symeda.sormas.app.backend.epidata.EpiData; import de.symeda.sormas.app.backend.exposure.Exposure; @@ -65,7 +66,7 @@ public static EpidemiologicalDataEditFragment newInstance(PseudonymizableAdo act null, activityRootData, FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(activityRootData)), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } private void setUpControlListeners(final FragmentEditEpidLayoutBinding contentBinding) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataReadFragment.java index bf56e2d4d13..8dd77dc8803 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpidemiologicalDataReadFragment.java @@ -69,7 +69,7 @@ public static EpidemiologicalDataReadFragment newInstance(Case activityRootData) null, activityRootData, FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(activityRootData)).andWithCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static EpidemiologicalDataReadFragment newInstance(Contact activityRootData) { @@ -78,7 +78,7 @@ public static EpidemiologicalDataReadFragment newInstance(Contact activityRootDa null, activityRootData, FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(activityRootData)).andWithCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } private void setUpControlListeners() { @@ -107,7 +107,7 @@ private void setUpControlListeners() { ExposureDto.class, (ViewGroup) infoDialog.getBinding().getRoot(), FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(getActivityRootData())), - UiFieldAccessCheckers.forSensitiveData(((PseudonymizableAdo) getActivityRootData()).isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(((PseudonymizableAdo) getActivityRootData()).isPseudonymized(), ConfigProvider.getServerCountryCode())); infoDialog.show(); }; @@ -141,7 +141,7 @@ private void setUpControlListeners() { (ViewGroup) infoDialog.getBinding().getRoot(), FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(getActivityRootData())) .andWithCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(((PseudonymizableAdo) getActivityRootData()).isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(((PseudonymizableAdo) getActivityRootData()).isPseudonymized(), ConfigProvider.getServerCountryCode())); infoDialog.show(); }; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ExposureDialog.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ExposureDialog.java index b7125090159..69e91abd80c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ExposureDialog.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/ExposureDialog.java @@ -58,7 +58,7 @@ public class ExposureDialog extends FormDialog { R.string.heading_exposure, -1, false, - UiFieldAccessCheckers.forSensitiveData(exposure.isPseudonymized()), + UiFieldAccessCheckers.forSensitiveData(exposure.isPseudonymized(), ConfigProvider.getServerCountryCode()), FieldVisibilityCheckers.withDisease(getDiseaseOfCaseOrContact(activityRootData)).andWithCountry(ConfigProvider.getServerCountryCode())); this.data = exposure; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/edit/EventEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/edit/EventEditFragment.java index 846c622e9db..cb4c79e2c80 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/edit/EventEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/edit/EventEditFragment.java @@ -101,7 +101,7 @@ public static EventEditFragment newInstance(Event activityRootData) { null, activityRootData, FieldVisibilityCheckers.withCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); fragment.isMultiDayEvent = activityRootData.getEndDate() != null; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/edit/EventParticipantEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/edit/EventParticipantEditFragment.java index 9e501d2d93d..8843394a6a0 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/edit/EventParticipantEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/edit/EventParticipantEditFragment.java @@ -27,6 +27,7 @@ import de.symeda.sormas.app.BaseEditFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.event.EventParticipant; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.caze.edit.CaseNewActivity; @@ -50,7 +51,7 @@ public static EventParticipantEditFragment newInstance(EventParticipant activity null, activityRootData, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Instance methods diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/read/EventParticipantReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/read/EventParticipantReadFragment.java index 81c805acd9c..310496bb817 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/read/EventParticipantReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/eventparticipant/read/EventParticipantReadFragment.java @@ -25,6 +25,7 @@ import de.symeda.sormas.app.BaseReadFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.event.EventParticipant; import de.symeda.sormas.app.caze.read.CaseReadActivity; import de.symeda.sormas.app.databinding.FragmentEventParticipantReadLayoutBinding; @@ -41,7 +42,7 @@ public static EventParticipantReadFragment newInstance(EventParticipant activity null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getEvent().getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Instance methods diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/read/EventReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/read/EventReadFragment.java index e7d2419f264..7fce89cb3de 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/read/EventReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/read/EventReadFragment.java @@ -56,7 +56,7 @@ public static EventReadFragment newInstance(Event activityRootData) { null, activityRootData, FieldVisibilityCheckers.withCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Overrides diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/edit/ImmunizationEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/edit/ImmunizationEditFragment.java index 8d6c55f3ef9..3d9827e5c54 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/edit/ImmunizationEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/edit/ImmunizationEditFragment.java @@ -89,7 +89,7 @@ public static ImmunizationEditFragment newInstance(Immunization activityRootData activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); immunizationEditFragment.setMeansOfImmunizationChange(meansOfImmunizationChange); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/read/ImmunizationReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/read/ImmunizationReadFragment.java index b3d0dab8cf8..c407adf7c0f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/read/ImmunizationReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/read/ImmunizationReadFragment.java @@ -47,7 +47,7 @@ public static ImmunizationReadFragment newInstance(Immunization activityRootData activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); return immunizationReadFragment; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditFragment.java index 27bc4b6aa33..c7aa6016a3d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditFragment.java @@ -57,7 +57,7 @@ public static VaccinationEditFragment newInstance(Vaccination activityRootData) null, activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditHealthConditionsFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditHealthConditionsFragment.java index aa00912d6f5..3bfe576d255 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditHealthConditionsFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/immunization/vaccination/VaccinationEditHealthConditionsFragment.java @@ -33,7 +33,7 @@ public static VaccinationEditHealthConditionsFragment newInstance(Vaccination ac activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getImmunization().getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/edit/PathogenTestEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/edit/PathogenTestEditFragment.java index e090db0d7ba..007abe578d4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/edit/PathogenTestEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/edit/PathogenTestEditFragment.java @@ -75,7 +75,7 @@ public static PathogenTestEditFragment newInstance(PathogenTest activityRootData null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getTestedDisease()).andWithCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Overrides diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/read/PathogenTestReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/read/PathogenTestReadFragment.java index 28bece5d2cc..9a85f3ee6d3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/read/PathogenTestReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/pathogentest/read/PathogenTestReadFragment.java @@ -44,7 +44,7 @@ public static PathogenTestReadFragment newInstance(PathogenTest activityRootData null, activityRootData, FieldVisibilityCheckers.withCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Overrides diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/edit/PersonEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/edit/PersonEditFragment.java index 263e3de8287..7de84d96b90 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/edit/PersonEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/edit/PersonEditFragment.java @@ -101,7 +101,7 @@ public static PersonEditFragment newInstance(Case activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonEditFragment newInstance(Contact activityRootData) { @@ -111,7 +111,7 @@ public static PersonEditFragment newInstance(Contact activityRootData) { null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonEditFragment newInstance(Immunization activityRootData) { @@ -121,7 +121,7 @@ public static PersonEditFragment newInstance(Immunization activityRootData) { null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonEditFragment newInstance(EventParticipant activityRootData) { @@ -131,7 +131,7 @@ public static PersonEditFragment newInstance(EventParticipant activityRootData) null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getEvent().getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } private void setUpLayoutBinding(final BaseEditFragment fragment, final Person record, final FragmentPersonEditLayoutBinding contentBinding) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/read/PersonReadFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/read/PersonReadFragment.java index 7422906c113..bae6e313cb4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/read/PersonReadFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/read/PersonReadFragment.java @@ -70,7 +70,7 @@ public static PersonReadFragment newInstance(Case activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonReadFragment newInstance(Contact activityRootData) { @@ -79,7 +79,7 @@ public static PersonReadFragment newInstance(Contact activityRootData) { null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonReadFragment newInstance(Immunization activityRootData) { @@ -88,7 +88,7 @@ public static PersonReadFragment newInstance(Immunization activityRootData) { null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static PersonReadFragment newInstance(EventParticipant activityRootData) { @@ -97,7 +97,7 @@ public static PersonReadFragment newInstance(EventParticipant activityRootData) null, activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getEvent().getDisease()), - UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.getDefault(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } private void setUpControlListeners() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/edit/SampleEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/edit/SampleEditFragment.java index 2c594ecf493..08d8db7b61b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/edit/SampleEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/edit/SampleEditFragment.java @@ -85,7 +85,7 @@ public static SampleEditFragment newInstance(Sample activityRootData) { null, activityRootData, FieldVisibilityCheckers.withDisease(getDiseaseOfAssociatedEntity(activityRootData)).andWithCountry(ConfigProvider.getServerCountryCode()), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized()), + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode()), UserRight.SAMPLE_EDIT); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/symptoms/SymptomsEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/symptoms/SymptomsEditFragment.java index 093b827d26f..fbdf67b65b0 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/symptoms/SymptomsEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/symptoms/SymptomsEditFragment.java @@ -84,7 +84,7 @@ public static SymptomsEditFragment newInstance(Case activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static SymptomsEditFragment newInstance(Visit activityRootData) { @@ -94,7 +94,7 @@ public static SymptomsEditFragment newInstance(Visit activityRootData) { activityRootData, FieldVisibilityCheckers.withDisease(activityRootData.getDisease()) .add(new CountryFieldVisibilityChecker(ConfigProvider.getServerLocale())), - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } public static SymptomsEditFragment newInstance(ClinicalVisit activityRootData, String caseUuid) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/PrescriptionEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/PrescriptionEditFragment.java index f34a8e10ecc..d179737e7df 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/PrescriptionEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/PrescriptionEditFragment.java @@ -53,7 +53,7 @@ public static PrescriptionEditFragment newInstance(Prescription activityRootData null, activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Instance methods diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/TreatmentEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/TreatmentEditFragment.java index 199558ec248..147b1bb3dfc 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/TreatmentEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/therapy/edit/TreatmentEditFragment.java @@ -27,6 +27,7 @@ import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.app.BaseEditFragment; import de.symeda.sormas.app.R; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.therapy.Treatment; import de.symeda.sormas.app.component.Item; import de.symeda.sormas.app.databinding.FragmentTreatmentEditLayoutBinding; @@ -51,7 +52,7 @@ public static TreatmentEditFragment newInstance(Treatment activityRootData) { null, activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } // Instance methods diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/edit/VisitEditFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/edit/VisitEditFragment.java index d6d5bc548ed..4377301a9ae 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/edit/VisitEditFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/edit/VisitEditFragment.java @@ -27,6 +27,7 @@ import de.symeda.sormas.app.BaseEditFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.contact.Contact; import de.symeda.sormas.app.backend.visit.Visit; import de.symeda.sormas.app.databinding.FragmentVisitEditLayoutBinding; @@ -44,7 +45,7 @@ public static VisitEditFragment newInstance(Visit activityRootData, String conta new Bundler().setContactUuid(contactUuid).get(), activityRootData, null, - UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized())); + UiFieldAccessCheckers.forSensitiveData(activityRootData.isPseudonymized(), ConfigProvider.getServerCountryCode())); } @Override diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index f64314439ef..523596b5398 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index ca267b688bf..b79abebdcb8 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/action/ActionService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/action/ActionService.java index 12698b51144..a134f99bc0c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/action/ActionService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/action/ActionService.java @@ -312,7 +312,7 @@ public List getEventActionIndexList(EventCriteria criteria, event.get(Event.UUID), event.get(Event.EVENT_TITLE), event.get(Event.DISEASE), - event.get(Event.DISEASE_VARIANT), + event.get(Event.DISEASE_VARIANT_VALUE), event.get(Event.DISEASE_DETAILS), event.get(Event.EVENT_IDENTIFICATION_SOURCE), event.get(Event.START_DATE), @@ -427,7 +427,7 @@ private List getOrderList(List sortProperties, ActionQueryC expression = event.get(Event.DISEASE); break; case EventActionIndexDto.EVENT_DISEASE_VARIANT: - expression = event.get(Event.DISEASE_VARIANT); + expression = event.get(Event.DISEASE_VARIANT_VALUE); break; case EventActionIndexDto.EVENT_IDENTIFICATION_SOURCE: expression = event.get(Event.EVENT_IDENTIFICATION_SOURCE); @@ -523,7 +523,7 @@ public List getEventActionExportList(EventCriteria criteri event.get(Event.UUID), event.get(Event.EVENT_TITLE), event.get(Event.DISEASE), - event.get(Event.DISEASE_VARIANT), + event.get(Event.DISEASE_VARIANT_VALUE), event.get(Event.DISEASE_DETAILS), event.get(Event.EVENT_DESC), event.get(Event.EVENT_IDENTIFICATION_SOURCE), @@ -612,11 +612,12 @@ public long countActions(ActionCriteria actionCriteria) { } @Override - public void deletePermanent(Action action) { + public boolean deletePermanent(Action action) { documentService.getRelatedToEntity(DocumentRelatedEntityType.ACTION, action.getUuid()).forEach(d -> documentService.markAsDeleted(d)); super.deletePermanent(action); + return false; } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/action/EventActionIndexDtoReasultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/action/EventActionIndexDtoReasultTransformer.java index c24f8fa8d8d..21f0efa3fc1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/action/EventActionIndexDtoReasultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/action/EventActionIndexDtoReasultTransformer.java @@ -32,7 +32,7 @@ public Object transformTuple(Object[] objects, String[] strings) { (String) objects[1], (String) objects[2], (Disease) objects[3], - (DiseaseVariant) objects[4], + (String) objects[4], (String) objects[5], (EventIdentificationSource) objects[6], (Date) objects[7], diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AdverseEventsMapper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AdverseEventsMapper.java new file mode 100644 index 00000000000..24b4abb88ea --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AdverseEventsMapper.java @@ -0,0 +1,82 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.validation.constraints.NotNull; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AdverseEvents; +import de.symeda.sormas.backend.util.DtoHelper; + +@LocalBean +@Stateless(name = "AdverseEventsMapper") +public class AdverseEventsMapper { + + public static AdverseEventsDto toDto(AdverseEvents source) { + + if (source == null) { + return null; + } + + AdverseEventsDto target = new AdverseEventsDto(); + DtoHelper.fillDto(target, source); + + target.setSevereLocalReaction(source.getSevereLocalReaction()); + target.setSevereLocalReactionMoreThanThreeDays(source.isSevereLocalReactionMoreThanThreeDays()); + target.setSevereLocalReactionBeyondNearestJoint(source.isSevereLocalReactionBeyondNearestJoint()); + target.setSeizures(source.getSeizures()); + target.setSeizureType(source.getSeizureType()); + target.setAbscess(source.getAbscess()); + target.setSepsis(source.getSepsis()); + target.setEncephalopathy(source.getEncephalopathy()); + target.setToxicShockSyndrome(source.getToxicShockSyndrome()); + target.setThrombocytopenia(source.getThrombocytopenia()); + target.setAnaphylaxis(source.getAnaphylaxis()); + target.setFeverishFeeling(source.getFeverishFeeling()); + target.setOtherAdverseEventDetails(source.getOtherAdverseEventDetails()); + + return target; + } + + public AdverseEvents fillOrBuildEntity(@NotNull AdverseEventsDto source, AdverseEvents target, boolean checkChangeDate) { + if (source == null) { + return null; + } + + target = DtoHelper.fillOrBuildEntity(source, target, AdverseEvents::new, checkChangeDate); + + target.setSevereLocalReaction(source.getSevereLocalReaction()); + target.setSevereLocalReactionMoreThanThreeDays(source.isSevereLocalReactionMoreThanThreeDays()); + target.setSevereLocalReactionBeyondNearestJoint(source.isSevereLocalReactionBeyondNearestJoint()); + target.setSeizures(source.getSeizures()); + target.setSeizureType(source.getSeizureType()); + target.setAbscess(source.getAbscess()); + target.setSepsis(source.getSepsis()); + target.setEncephalopathy(source.getEncephalopathy()); + target.setToxicShockSyndrome(source.getToxicShockSyndrome()); + target.setThrombocytopenia(source.getThrombocytopenia()); + target.setAnaphylaxis(source.getAnaphylaxis()); + target.setFeverishFeeling(source.getFeverishFeeling()); + target.setOtherAdverseEventDetails(source.getOtherAdverseEventDetails()); + + return target; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiFacadeEjb.java new file mode 100644 index 00000000000..672edfd0f34 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiFacadeEjb.java @@ -0,0 +1,467 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiExportDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiFacade; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiReferenceDto; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.common.DeletionDetails; +import de.symeda.sormas.api.common.progress.ProcessedEntity; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.AccessDeniedException; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.SortProperty; +import de.symeda.sormas.api.utils.ValidationRuntimeException; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.backend.FacadeHelper; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; +import de.symeda.sormas.backend.immunization.ImmunizationFacadeEjb; +import de.symeda.sormas.backend.immunization.ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal; +import de.symeda.sormas.backend.immunization.ImmunizationService; +import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; +import de.symeda.sormas.backend.infrastructure.community.CommunityService; +import de.symeda.sormas.backend.infrastructure.country.CountryFacadeEjb; +import de.symeda.sormas.backend.infrastructure.country.CountryService; +import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; +import de.symeda.sormas.backend.infrastructure.district.DistrictService; +import de.symeda.sormas.backend.infrastructure.facility.FacilityFacadeEjb; +import de.symeda.sormas.backend.infrastructure.facility.FacilityService; +import de.symeda.sormas.backend.infrastructure.region.RegionFacadeEjb; +import de.symeda.sormas.backend.infrastructure.region.RegionService; +import de.symeda.sormas.backend.location.LocationFacadeEjb; +import de.symeda.sormas.backend.location.LocationFacadeEjb.LocationFacadeEjbLocal; +import de.symeda.sormas.backend.person.PersonFacadeEjb; +import de.symeda.sormas.backend.person.PersonService; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserFacadeEjb; +import de.symeda.sormas.backend.util.DtoHelper; +import de.symeda.sormas.backend.util.Pseudonymizer; +import de.symeda.sormas.backend.util.RightsAllowed; +import de.symeda.sormas.backend.vaccination.Vaccination; +import de.symeda.sormas.backend.vaccination.VaccinationFacadeEjb; +import de.symeda.sormas.backend.vaccination.VaccinationFacadeEjb.VaccinationFacadeEjbLocal; +import de.symeda.sormas.backend.vaccination.VaccinationService; + +@Stateless(name = "AefiFacade") +@RightsAllowed(UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW) +public class AefiFacadeEjb extends AbstractCoreFacadeEjb + implements AefiFacade { + + private final Logger logger = LoggerFactory.getLogger(AefiFacadeEjb.class); + + @EJB + private ImmunizationFacadeEjbLocal immunizationFacade; + @EJB + private ImmunizationService immunizationService; + @EJB + private PersonService personService; + @EJB + private LocationFacadeEjbLocal locationFacade; + @EJB + private VaccinationFacadeEjbLocal vaccinationFacade; + @EJB + private VaccinationService vaccinationService; + @EJB + private RegionService regionService; + @EJB + private DistrictService districtService; + @EJB + private CommunityService communityService; + @EJB + private FacilityService facilityService; + @EJB + private CountryService countryService; + @EJB + private AdverseEventsMapper adverseEventsMapper; + + public AefiFacadeEjb() { + } + + @Inject + public AefiFacadeEjb(AefiService service) { + super(Aefi.class, AefiDto.class, service); + } + + @Override + @RightsAllowed({ + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT }) + public AefiDto save(@Valid @NotNull AefiDto dto) { + return save(dto, true, true); + } + + @RightsAllowed({ + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT }) + public AefiDto save(@Valid @NotNull AefiDto dto, boolean checkChangeDate, boolean internal) { + Aefi existingAefi = service.getByUuid(dto.getUuid()); + + FacadeHelper.checkCreateAndEditRights( + existingAefi, + userService, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT); + + if (internal && existingAefi != null && !service.isEditAllowed(existingAefi)) { + throw new AccessDeniedException(I18nProperties.getString(Strings.errorAdverseEventNotEditable)); + } + + AefiDto existingDto = toDto(existingAefi); + + Pseudonymizer pseudonymizer = createPseudonymizer(existingAefi); + restorePseudonymizedDto(dto, existingDto, existingAefi, pseudonymizer); + + validate(dto); + + Aefi aefi = fillOrBuildEntity(dto, existingAefi, checkChangeDate); + + service.ensurePersisted(aefi); + + return toPseudonymizedDto(aefi, pseudonymizer); + } + + @Override + public long count(AefiCriteria criteria) { + return service.count(criteria); + } + + @Override + public List getIndexList(AefiCriteria criteria, Integer first, Integer max, List sortProperties) { + List resultsList = service.getIndexList(criteria, first, max, sortProperties); + Pseudonymizer pseudonymizer = createGenericPlaceholderPseudonymizer(); + pseudonymizer.pseudonymizeDtoCollection(AefiIndexDto.class, resultsList, AefiIndexDto::isInJurisdiction, null); + return resultsList; + } + + @Override + @RightsAllowed(UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT) + public List getExportList(AefiCriteria criteria, Collection selectedRows, int first, int max) { + List resultsList = service.getExportList(criteria, selectedRows, first, max); + Pseudonymizer pseudonymizer = createGenericPlaceholderPseudonymizer(); + pseudonymizer.pseudonymizeDtoCollection(AefiExportDto.class, resultsList, AefiExportDto::getInJurisdiction, null); + return resultsList; + } + + @Override + public List getEntriesList(AefiListCriteria criteria, Integer first, Integer max) { + Long immunizationId = immunizationService.getIdByUuid(criteria.getImmunization().getUuid()); + return service.getEntriesList(immunizationId, first, max); + } + + @Override + public void validate(AefiDto aefiDto) throws ValidationRuntimeException { + if (DateHelper.isDateAfter(aefiDto.getStartDateTime(), aefiDto.getReportDate())) { + String validationError = String.format( + I18nProperties.getValidationError(Validations.afterDate), + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, AefiDto.START_DATE_TIME), + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, AefiDto.REPORT_DATE)); + throw new ValidationRuntimeException(validationError); + } + + // Check whether any required field that does not have a not null constraint in the database is empty + if (aefiDto.getImmunization() == null) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validImmunization)); + } + + if (aefiDto.getPrimarySuspectVaccine() == null) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.aefiWithoutPrimarySuspectVaccine)); + } + + AdverseEventsDto adverseEvents = aefiDto.getAdverseEvents(); + if (adverseEvents == null) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.aefiWithoutAdverseEvents)); + } else { + if (adverseEvents.getSevereLocalReaction() == null + && adverseEvents.getSeizures() == null + && adverseEvents.getAbscess() == null + && adverseEvents.getSepsis() == null + && adverseEvents.getEncephalopathy() == null + && adverseEvents.getToxicShockSyndrome() == null + && adverseEvents.getThrombocytopenia() == null + && adverseEvents.getAnaphylaxis() == null + && adverseEvents.getFeverishFeeling() == null + && StringUtils.isBlank(adverseEvents.getOtherAdverseEventDetails())) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.aefiWithoutAdverseEvents)); + } + + boolean adverseEventSelected = adverseEvents.getSevereLocalReaction() == AdverseEventState.YES + || adverseEvents.getSeizures() == AdverseEventState.YES + || adverseEvents.getAbscess() == AdverseEventState.YES + || adverseEvents.getSepsis() == AdverseEventState.YES + || adverseEvents.getEncephalopathy() == AdverseEventState.YES + || adverseEvents.getToxicShockSyndrome() == AdverseEventState.YES + || adverseEvents.getThrombocytopenia() == AdverseEventState.YES + || adverseEvents.getAnaphylaxis() == AdverseEventState.YES + || adverseEvents.getFeverishFeeling() == AdverseEventState.YES + || !StringUtils.isBlank(adverseEvents.getOtherAdverseEventDetails()); + + if (!adverseEventSelected) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.aefiWithoutAdverseEvents)); + } + } + + if (aefiDto.getReportingUser() == null && !aefiDto.isPseudonymized()) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validReportingUser)); + } + } + + @Override + public List getArchivedUuidsSince(Date since) { + return null; + } + + @Override + public List delete(List uuids, DeletionDetails deletionDetails) { + return null; + } + + @Override + public List restore(List uuids) { + return null; + } + + @Override + protected Aefi fillOrBuildEntity(AefiDto source, Aefi target, boolean checkChangeDate) { + return fillOrBuildEntity(source, target, checkChangeDate, false); + } + + protected Aefi fillOrBuildEntity(@NotNull AefiDto source, Aefi target, boolean checkChangeDate, boolean includeVaccinations) { + + target = DtoHelper.fillOrBuildEntity(source, target, Aefi::build, checkChangeDate); + + target.setImmunization(immunizationService.getByReferenceDto(source.getImmunization())); + target.setPerson(personService.getByReferenceDto(source.getPerson())); + target.setAddress(locationFacade.fillOrBuildEntity(source.getAddress(), target.getAddress(), checkChangeDate)); + + if (includeVaccinations) { + List vaccinationEntities = new ArrayList<>(); + for (VaccinationDto vaccinationDto : source.getVaccinations()) { + Vaccination vaccination = vaccinationService.getByUuid(vaccinationDto.getUuid()); + vaccination = vaccinationFacade.fillOrBuildEntity(vaccinationDto, vaccination, checkChangeDate); + vaccinationEntities.add(vaccination); + } + target.getVaccinations().clear(); + target.getVaccinations().addAll(vaccinationEntities); + } + + target.setPrimarySuspectVaccine(vaccinationService.getByUuid(source.getPrimarySuspectVaccine().getUuid())); + target.setAdverseEvents(adverseEventsMapper.fillOrBuildEntity(source.getAdverseEvents(), target.getAdverseEvents(), checkChangeDate)); + target.setReportDate(source.getReportDate()); + target.setReportingUser(userService.getByReferenceDto(source.getReportingUser())); + target.setExternalId(source.getExternalId()); + target.setResponsibleRegion(regionService.getByReferenceDto(source.getResponsibleRegion())); + target.setResponsibleDistrict(districtService.getByReferenceDto(source.getResponsibleDistrict())); + target.setResponsibleCommunity(communityService.getByReferenceDto(source.getResponsibleCommunity())); + target.setCountry(countryService.getByReferenceDto(source.getCountry())); + target.setReportingIdNumber(source.getReportingIdNumber()); + target.setPhoneNumber(source.getPhoneNumber()); + target.setPregnant(source.getPregnant()); + target.setTrimester(source.getTrimester()); + target.setLactating(source.getLactating()); + target.setOnsetAgeYears(source.getOnsetAgeYears()); + target.setOnsetAgeMonths(source.getOnsetAgeMonths()); + target.setOnsetAgeDays(source.getOnsetAgeDays()); + target.setAgeGroup(source.getAgeGroup()); + target.setHealthFacility(facilityService.getByReferenceDto(source.getHealthFacility())); + target.setHealthFacilityDetails(source.getHealthFacilityDetails()); + target.setReportingOfficerName(source.getReportingOfficerName()); + target.setReportingOfficerFacility(facilityService.getByReferenceDto(source.getReportingOfficerFacility())); + target.setReportingOfficerDesignation(source.getReportingOfficerDesignation()); + target.setReportingOfficerDepartment(source.getReportingOfficerDepartment()); + target.setReportingOfficerAddress( + locationFacade.fillOrBuildEntity(source.getReportingOfficerAddress(), target.getReportingOfficerAddress(), checkChangeDate)); + target.setReportingOfficerPhoneNumber(source.getReportingOfficerPhoneNumber()); + target.setReportingOfficerEmail(source.getReportingOfficerEmail()); + target.setTodaysDate(source.getTodaysDate()); + target.setStartDateTime(source.getStartDateTime()); + target.setAefiDescription(source.getAefiDescription()); + target.setSerious(source.getSerious()); + target.setSeriousReason(source.getSeriousReason()); + target.setSeriousReasonDetails(source.getSeriousReasonDetails()); + target.setOutcome(source.getOutcome()); + target.setDeathDate(source.getDeathDate()); + target.setAutopsyDone(source.getAutopsyDone()); + target.setPastMedicalHistory(source.getPastMedicalHistory()); + target.setInvestigationNeeded(source.getInvestigationNeeded()); + target.setInvestigationPlannedDate(source.getInvestigationPlannedDate()); + target.setReceivedAtNationalLevelDate(source.getReceivedAtNationalLevelDate()); + target.setWorldwideId(source.getWorldwideId()); + target.setNationalLevelComment(source.getNationalLevelComment()); + target.setArchived(source.isArchived()); + target.setDeleted(source.isDeleted()); + target.setDeletionReason(source.getDeletionReason()); + target.setOtherDeletionReason(source.getOtherDeletionReason()); + + return target; + } + + @Override + protected AefiDto toDto(Aefi entity) { + return toAefiDto(entity); + } + + public static AefiDto toAefiDto(Aefi entity) { + + if (entity == null) { + return null; + } + AefiDto dto = new AefiDto(); + DtoHelper.fillDto(dto, entity); + + dto.setImmunization(ImmunizationFacadeEjb.toReferenceDto(entity.getImmunization())); + dto.setPerson(PersonFacadeEjb.toReferenceDto(entity.getPerson())); + dto.setAddress(LocationFacadeEjb.toDto(entity.getAddress())); + + List vaccinationDtos = new ArrayList<>(); + for (Vaccination vaccination : entity.getImmunization().getVaccinations()) { + VaccinationDto vaccinationDto = VaccinationFacadeEjb.toVaccinationDto(vaccination); + vaccinationDtos.add(vaccinationDto); + } + dto.setVaccinations(vaccinationDtos); + + dto.setPrimarySuspectVaccine(VaccinationFacadeEjb.toVaccinationDto(entity.getPrimarySuspectVaccine())); + dto.setAdverseEvents(AdverseEventsMapper.toDto(entity.getAdverseEvents())); + dto.setReportDate(entity.getReportDate()); + dto.setReportingUser(UserFacadeEjb.toReferenceDto(entity.getReportingUser())); + dto.setExternalId(entity.getExternalId()); + dto.setResponsibleRegion(RegionFacadeEjb.toReferenceDto(entity.getResponsibleRegion())); + dto.setResponsibleDistrict(DistrictFacadeEjb.toReferenceDto(entity.getResponsibleDistrict())); + dto.setResponsibleCommunity(CommunityFacadeEjb.toReferenceDto(entity.getResponsibleCommunity())); + dto.setCountry(CountryFacadeEjb.toReferenceDto(entity.getCountry())); + dto.setReportingIdNumber(entity.getReportingIdNumber()); + dto.setPhoneNumber(entity.getPhoneNumber()); + dto.setPregnant(entity.getPregnant()); + dto.setTrimester(entity.getTrimester()); + dto.setLactating(entity.getLactating()); + dto.setOnsetAgeYears(entity.getOnsetAgeYears()); + dto.setOnsetAgeMonths(entity.getOnsetAgeMonths()); + dto.setOnsetAgeDays(entity.getOnsetAgeDays()); + dto.setAgeGroup(entity.getAgeGroup()); + dto.setHealthFacility(FacilityFacadeEjb.toReferenceDto(entity.getHealthFacility())); + dto.setHealthFacilityDetails(entity.getHealthFacilityDetails()); + dto.setReportingOfficerName(entity.getReportingOfficerName()); + dto.setReportingOfficerFacility(FacilityFacadeEjb.toReferenceDto(entity.getReportingOfficerFacility())); + dto.setReportingOfficerDesignation(entity.getReportingOfficerDesignation()); + dto.setReportingOfficerDepartment(entity.getReportingOfficerDepartment()); + dto.setReportingOfficerAddress(LocationFacadeEjb.toDto(entity.getReportingOfficerAddress())); + dto.setReportingOfficerPhoneNumber(entity.getReportingOfficerPhoneNumber()); + dto.setReportingOfficerEmail(entity.getReportingOfficerEmail()); + dto.setTodaysDate(entity.getTodaysDate()); + dto.setStartDateTime(entity.getStartDateTime()); + dto.setAefiDescription(entity.getAefiDescription()); + dto.setSerious(entity.getSerious()); + dto.setSeriousReason(entity.getSeriousReason()); + dto.setSeriousReasonDetails(entity.getSeriousReasonDetails()); + dto.setOutcome(entity.getOutcome()); + dto.setDeathDate(entity.getDeathDate()); + dto.setAutopsyDone(entity.getAutopsyDone()); + dto.setPastMedicalHistory(entity.getPastMedicalHistory()); + dto.setInvestigationNeeded(entity.getInvestigationNeeded()); + dto.setInvestigationPlannedDate(entity.getInvestigationPlannedDate()); + dto.setReceivedAtNationalLevelDate(entity.getReceivedAtNationalLevelDate()); + dto.setWorldwideId(entity.getWorldwideId()); + dto.setNationalLevelComment(entity.getNationalLevelComment()); + dto.setArchived(entity.isArchived()); + dto.setDeleted(entity.isDeleted()); + dto.setDeletionReason(entity.getDeletionReason()); + dto.setOtherDeletionReason(entity.getOtherDeletionReason()); + + return dto; + } + + @Override + protected AefiReferenceDto toRefDto(Aefi aefi) { + return toReferenceDto(aefi); + } + + public static AefiReferenceDto toReferenceDto(Aefi entity) { + + if (entity == null) { + return null; + } + + return new AefiReferenceDto(entity.getUuid(), ""); + } + + @Override + protected void pseudonymizeDto(Aefi source, AefiDto dto, Pseudonymizer pseudonymizer, boolean inJurisdiction) { + + if (dto != null) { + pseudonymizer.pseudonymizeDto(AefiDto.class, dto, inJurisdiction, c -> { + pseudonymizer.pseudonymizeUser(source.getReportingUser(), userService.getCurrentUser(), dto::setReportingUser, dto); + }); + } + } + + @Override + protected void restorePseudonymizedDto(AefiDto dto, AefiDto existingDto, Aefi entity, Pseudonymizer pseudonymizer) { + + if (existingDto != null) { + final boolean inJurisdiction = service.inJurisdictionOrOwned(entity); + final User currentUser = userService.getCurrentUser(); + pseudonymizer.restoreUser(entity.getReportingUser(), currentUser, dto, dto::setReportingUser); + pseudonymizer.restorePseudonymizedValues(AefiDto.class, dto, existingDto, inJurisdiction); + } + } + + @Override + protected DeletableEntityType getDeletableEntityType() { + return null; + } + + @LocalBean + @Stateless + public static class AefiFacadeEjbLocal extends AefiFacadeEjb { + + public AefiFacadeEjbLocal() { + super(); + } + + @Inject + public AefiFacadeEjbLocal(AefiService service) { + super(service); + } + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationFacadeEjb.java new file mode 100644 index 00000000000..8cef80f6506 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationFacadeEjb.java @@ -0,0 +1,641 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationFacade; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationReferenceDto; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.common.DeletionDetails; +import de.symeda.sormas.api.common.progress.ProcessedEntity; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.AccessDeniedException; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.SortProperty; +import de.symeda.sormas.api.utils.ValidationRuntimeException; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.backend.FacadeHelper; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; +import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; +import de.symeda.sormas.backend.infrastructure.community.CommunityService; +import de.symeda.sormas.backend.infrastructure.country.CountryFacadeEjb; +import de.symeda.sormas.backend.infrastructure.country.CountryService; +import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; +import de.symeda.sormas.backend.infrastructure.district.DistrictService; +import de.symeda.sormas.backend.infrastructure.facility.FacilityFacadeEjb; +import de.symeda.sormas.backend.infrastructure.facility.FacilityService; +import de.symeda.sormas.backend.infrastructure.region.RegionFacadeEjb; +import de.symeda.sormas.backend.infrastructure.region.RegionService; +import de.symeda.sormas.backend.location.LocationFacadeEjb; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserFacadeEjb; +import de.symeda.sormas.backend.util.DtoHelper; +import de.symeda.sormas.backend.util.Pseudonymizer; +import de.symeda.sormas.backend.util.RightsAllowed; +import de.symeda.sormas.backend.vaccination.Vaccination; +import de.symeda.sormas.backend.vaccination.VaccinationFacadeEjb; +import de.symeda.sormas.backend.vaccination.VaccinationService; + +@Stateless(name = "AefiInvestigationFacade") +@RightsAllowed(UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW) +public class AefiInvestigationFacadeEjb + extends + AbstractCoreFacadeEjb + implements AefiInvestigationFacade { + + private final Logger logger = LoggerFactory.getLogger(AefiInvestigationFacadeEjb.class); + + @EJB + private AefiService aefiService; + @EJB + private LocationFacadeEjb.LocationFacadeEjbLocal locationFacade; + @EJB + private VaccinationFacadeEjb.VaccinationFacadeEjbLocal vaccinationFacade; + @EJB + private VaccinationService vaccinationService; + @EJB + private RegionService regionService; + @EJB + private DistrictService districtService; + @EJB + private CommunityService communityService; + @EJB + private FacilityService facilityService; + @EJB + private CountryService countryService; + + public AefiInvestigationFacadeEjb() { + } + + @Inject + public AefiInvestigationFacadeEjb(AefiInvestigationService service) { + super(AefiInvestigation.class, AefiInvestigationDto.class, service); + } + + @Override + @RightsAllowed({ + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT }) + public AefiInvestigationDto save(@Valid @NotNull AefiInvestigationDto dto) { + return save(dto, true, true); + } + + @RightsAllowed({ + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight._ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT }) + public AefiInvestigationDto save(@Valid @NotNull AefiInvestigationDto dto, boolean checkChangeDate, boolean internal) { + AefiInvestigation existingAefiInvestigation = service.getByUuid(dto.getUuid()); + + FacadeHelper.checkCreateAndEditRights( + existingAefiInvestigation, + userService, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT); + + if (internal && existingAefiInvestigation != null && !service.isEditAllowed(existingAefiInvestigation)) { + throw new AccessDeniedException(I18nProperties.getString(Strings.errorAdverseEventInvestigationNotEditable)); + } + + AefiInvestigationDto existingDto = toDto(existingAefiInvestigation); + + Pseudonymizer pseudonymizer = createPseudonymizer(existingAefiInvestigation); + restorePseudonymizedDto(dto, existingDto, existingAefiInvestigation, pseudonymizer); + + validate(dto); + + AefiInvestigation aefiInvestigation = fillOrBuildEntity(dto, existingAefiInvestigation, checkChangeDate); + + service.ensurePersisted(aefiInvestigation); + + return toPseudonymizedDto(aefiInvestigation, pseudonymizer); + } + + @Override + public long count(AefiInvestigationCriteria criteria) { + return service.count(criteria); + } + + @Override + public List getIndexList( + AefiInvestigationCriteria criteria, + Integer first, + Integer max, + List sortProperties) { + List resultsList = service.getIndexList(criteria, first, max, sortProperties); + Pseudonymizer pseudonymizer = createGenericPlaceholderPseudonymizer(); + pseudonymizer.pseudonymizeDtoCollection(AefiInvestigationIndexDto.class, resultsList, AefiInvestigationIndexDto::isInJurisdiction, null); + return resultsList; + } + + @Override + public List getEntriesList(AefiInvestigationListCriteria criteria, Integer first, Integer max) { + Long aefiId = aefiService.getIdByUuid(criteria.getAefiReport().getUuid()); + return service.getEntriesList(aefiId, first, max); + } + + @Override + public void validate(AefiInvestigationDto aefiInvestigationDto) throws ValidationRuntimeException { + if (DateHelper.isDateAfter(aefiInvestigationDto.getInvestigationDate(), aefiInvestigationDto.getReportDate())) { + String validationError = String.format( + I18nProperties.getValidationError(Validations.afterDate), + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, AefiInvestigationDto.INVESTIGATION_DATE), + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, AefiInvestigationDto.REPORT_DATE)); + throw new ValidationRuntimeException(validationError); + } + + // Check whether any required field that does not have a not null constraint in the database is empty + if (aefiInvestigationDto.getAefiReport() == null) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validAefiReport)); + } + + /* + * if (aefiInvestigationDto.getPrimarySuspectVaccine() == null) { + * throw new + * ValidationRuntimeException(I18nProperties.getValidationError(Validations.aefiInvestigationWithoutPrimarySuspectVaccine)); + * } + */ + + if (aefiInvestigationDto.getReportingUser() == null && !aefiInvestigationDto.isPseudonymized()) { + throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validReportingUser)); + } + } + + @Override + public List getArchivedUuidsSince(Date since) { + return null; + } + + @Override + public List delete(List uuids, DeletionDetails deletionDetails) { + return null; + } + + @Override + public List restore(List uuids) { + return null; + } + + @Override + protected AefiInvestigation fillOrBuildEntity(AefiInvestigationDto source, AefiInvestigation target, boolean checkChangeDate) { + return fillOrBuildEntity(source, target, checkChangeDate, false); + } + + protected AefiInvestigation fillOrBuildEntity( + @NotNull AefiInvestigationDto source, + AefiInvestigation target, + boolean checkChangeDate, + boolean includeVaccinations) { + + target = DtoHelper.fillOrBuildEntity(source, target, AefiInvestigation::build, checkChangeDate); + + target.setAefiReport(aefiService.getByReferenceDto(source.getAefiReport())); + target.setAddress(locationFacade.fillOrBuildEntity(source.getAddress(), target.getAddress(), checkChangeDate)); + + if (includeVaccinations) { + List vaccinationEntities = new ArrayList<>(); + for (VaccinationDto vaccinationDto : source.getVaccinations()) { + Vaccination vaccination = vaccinationService.getByUuid(vaccinationDto.getUuid()); + vaccination = vaccinationFacade.fillOrBuildEntity(vaccinationDto, vaccination, checkChangeDate); + vaccinationEntities.add(vaccination); + } + target.getVaccinations().clear(); + target.getVaccinations().addAll(vaccinationEntities); + } + + if (source.getPrimarySuspectVaccine() != null) { + target.setPrimarySuspectVaccine(vaccinationService.getByUuid(source.getPrimarySuspectVaccine().getUuid())); + } + + target.setReportDate(source.getReportDate()); + target.setReportingUser(userService.getByReferenceDto(source.getReportingUser())); + target.setExternalId(source.getExternalId()); + target.setResponsibleRegion(regionService.getByReferenceDto(source.getResponsibleRegion())); + target.setResponsibleDistrict(districtService.getByReferenceDto(source.getResponsibleDistrict())); + target.setResponsibleCommunity(communityService.getByReferenceDto(source.getResponsibleCommunity())); + target.setCountry(countryService.getByReferenceDto(source.getCountry())); + target.setInvestigationCaseId(source.getInvestigationCaseId()); + target.setPlaceOfVaccination(source.getPlaceOfVaccination()); + target.setPlaceOfVaccinationDetails(source.getPlaceOfVaccinationDetails()); + target.setVaccinationActivity(source.getVaccinationActivity()); + target.setVaccinationActivityDetails(source.getVaccinationActivityDetails()); + target.setVaccinationFacility(facilityService.getByReferenceDto(source.getVaccinationFacility())); + target.setVaccinationFacilityDetails(source.getVaccinationFacilityDetails()); + target.setReportingOfficerName(source.getReportingOfficerName()); + target.setReportingOfficerFacility(facilityService.getByReferenceDto(source.getReportingOfficerFacility())); + target.setReportingOfficerFacilityDetails(source.getReportingOfficerFacilityDetails()); + target.setReportingOfficerDesignation(source.getReportingOfficerDesignation()); + target.setReportingOfficerDepartment(source.getReportingOfficerDepartment()); + target.setReportingOfficerAddress( + locationFacade.fillOrBuildEntity(source.getReportingOfficerAddress(), target.getReportingOfficerAddress(), checkChangeDate)); + target.setReportingOfficerLandlinePhoneNumber(source.getReportingOfficerLandlinePhoneNumber()); + target.setReportingOfficerEmail(source.getReportingOfficerEmail()); + target.setReportingOfficerEmail(source.getReportingOfficerEmail()); + target.setInvestigationDate(source.getInvestigationDate()); + target.setFormCompletionDate(source.getFormCompletionDate()); + target.setInvestigationStage(source.getInvestigationStage()); + target.setTypeOfSite(source.getTypeOfSite()); + target.setTypeOfSiteDetails(source.getTypeOfSiteDetails()); + target.setKeySymptomDateTime(source.getKeySymptomDateTime()); + target.setHospitalizationDate(source.getHospitalizationDate()); + target.setReportedToHealthAuthorityDate(source.getReportedToHealthAuthorityDate()); + target.setStatusOnDateOfInvestigation(source.getStatusOnDateOfInvestigation()); + target.setDeathDateTime(source.getDeathDateTime()); + target.setAutopsyDone(source.getAutopsyDone()); + target.setAutopsyPlannedDateTime(source.getAutopsyPlannedDateTime()); + target.setPastHistoryOfSimilarEvent(source.getPastHistoryOfSimilarEvent()); + target.setPastHistoryOfSimilarEventDetails(source.getPastHistoryOfSimilarEventDetails()); + target.setAdverseEventAfterPreviousVaccinations(source.getAdverseEventAfterPreviousVaccinations()); + target.setAdverseEventAfterPreviousVaccinationsDetails(source.getAdverseEventAfterPreviousVaccinationsDetails()); + target.setHistoryOfAllergyToVaccineDrugOrFood(source.getHistoryOfAllergyToVaccineDrugOrFood()); + target.setHistoryOfAllergyToVaccineDrugOrFoodDetails(source.getHistoryOfAllergyToVaccineDrugOrFoodDetails()); + target.setPreExistingIllnessThirtyDaysOrCongenitalDisorder(source.getPreExistingIllnessThirtyDaysOrCongenitalDisorder()); + target.setPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails(source.getPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails()); + target.setHistoryOfHospitalizationInLastThirtyDaysWithCause(source.getHistoryOfHospitalizationInLastThirtyDaysWithCause()); + target.setHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails(source.getHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails()); + target.setCurrentlyOnConcomitantMedication(source.getCurrentlyOnConcomitantMedication()); + target.setCurrentlyOnConcomitantMedicationDetails(source.getCurrentlyOnConcomitantMedicationDetails()); + target.setFamilyHistoryOfDiseaseOrAllergy(source.getFamilyHistoryOfDiseaseOrAllergy()); + target.setFamilyHistoryOfDiseaseOrAllergyDetails(source.getFamilyHistoryOfDiseaseOrAllergyDetails()); + target.setBirthTerm(source.getBirthTerm()); + target.setBirthWeight(source.getBirthWeight()); + target.setDeliveryProcedure(source.getDeliveryProcedure()); + target.setDeliveryProcedureDetails(source.getDeliveryProcedureDetails()); + target.setSeriousAefiInfoSource(source.getSeriousAefiInfoSource()); + target.setSeriousAefiInfoSourceDetails(source.getSeriousAefiInfoSourceDetails()); + target.setSeriousAefiVerbalAutopsyInfoSourceDetails(source.getSeriousAefiVerbalAutopsyInfoSourceDetails()); + target.setFirstCaregiversName(source.getFirstCaregiversName()); + target.setOtherCaregiversNames(source.getOtherCaregiversNames()); + target.setOtherSourcesWhoProvidedInfo(source.getOtherSourcesWhoProvidedInfo()); + target.setSignsAndSymptomsFromTimeOfVaccination(source.getSignsAndSymptomsFromTimeOfVaccination()); + target.setClinicalDetailsOfficerName(source.getClinicalDetailsOfficerName()); + target.setClinicalDetailsOfficerPhoneNumber(source.getClinicalDetailsOfficerPhoneNumber()); + target.setClinicalDetailsOfficerEmail(source.getClinicalDetailsOfficerEmail()); + target.setClinicalDetailsOfficerDesignation(source.getClinicalDetailsOfficerDesignation()); + target.setClinicalDetailsDateTime(source.getClinicalDetailsDateTime()); + target.setPatientReceivedMedicalCare(source.getPatientReceivedMedicalCare()); + target.setPatientReceivedMedicalCareDetails(source.getPatientReceivedMedicalCareDetails()); + target.setProvisionalOrFinalDiagnosis(source.getProvisionalOrFinalDiagnosis()); + target.setPatientImmunizedPeriod(source.getPatientImmunizedPeriod()); + target.setPatientImmunizedPeriodDetails(source.getPatientImmunizedPeriodDetails()); + target.setVaccineGivenPeriod(source.getVaccineGivenPeriod()); + target.setVaccineGivenPeriodDetails(source.getVaccineGivenPeriodDetails()); + target.setErrorPrescribingVaccine(source.getErrorPrescribingVaccine()); + target.setErrorPrescribingVaccineDetails(source.getErrorPrescribingVaccineDetails()); + target.setVaccineCouldHaveBeenUnSterile(source.getVaccineCouldHaveBeenUnSterile()); + target.setVaccineCouldHaveBeenUnSterileDetails(source.getVaccineCouldHaveBeenUnSterileDetails()); + target.setVaccinePhysicalConditionAbnormal(source.getVaccinePhysicalConditionAbnormal()); + target.setVaccinePhysicalConditionAbnormalDetails(source.getVaccinePhysicalConditionAbnormalDetails()); + target.setErrorInVaccineReconstitution(source.getErrorInVaccineReconstitution()); + target.setErrorInVaccineReconstitutionDetails(source.getErrorInVaccineReconstitutionDetails()); + target.setErrorInVaccineHandling(source.getErrorInVaccineHandling()); + target.setErrorInVaccineHandlingDetails(source.getErrorInVaccineHandlingDetails()); + target.setVaccineAdministeredIncorrectly(source.getVaccineAdministeredIncorrectly()); + target.setVaccineAdministeredIncorrectlyDetails(source.getVaccineAdministeredIncorrectlyDetails()); + target.setNumberImmunizedFromConcernedVaccineVial(source.getNumberImmunizedFromConcernedVaccineVial()); + target.setNumberImmunizedWithConcernedVaccineInSameSession(source.getNumberImmunizedWithConcernedVaccineInSameSession()); + target.setNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations( + source.getNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations()); + target.setNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails( + source.getNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails()); + target.setVaccineHasQualityDefect(source.getVaccineHasQualityDefect()); + target.setVaccineHasQualityDefectDetails(source.getVaccineHasQualityDefectDetails()); + target.setEventIsAStressResponseRelatedToImmunization(source.getEventIsAStressResponseRelatedToImmunization()); + target.setEventIsAStressResponseRelatedToImmunizationDetails(source.getEventIsAStressResponseRelatedToImmunizationDetails()); + target.setCaseIsPartOfACluster(source.getCaseIsPartOfACluster()); + target.setCaseIsPartOfAClusterDetails(source.getCaseIsPartOfAClusterDetails()); + target.setNumberOfCasesDetectedInCluster(source.getNumberOfCasesDetectedInCluster()); + target.setAllCasesInClusterReceivedVaccineFromSameVial(source.getAllCasesInClusterReceivedVaccineFromSameVial()); + target.setAllCasesInClusterReceivedVaccineFromSameVialDetails(source.getAllCasesInClusterReceivedVaccineFromSameVialDetails()); + target.setNumberOfVialsUsedInCluster(source.getNumberOfVialsUsedInCluster()); + target.setNumberOfVialsUsedInClusterDetails(source.getNumberOfVialsUsedInClusterDetails()); + target.setAdSyringesUsedForImmunization(source.getAdSyringesUsedForImmunization()); + target.setTypeOfSyringesUsed(source.getTypeOfSyringesUsed()); + target.setTypeOfSyringesUsedDetails(source.getTypeOfSyringesUsedDetails()); + target.setSyringesUsedAdditionalDetails(source.getSyringesUsedAdditionalDetails()); + target.setSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine(source.getSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine()); + target.setSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines( + source.getSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines()); + target.setSameReconstitutionSyringeForEachVaccineVial(source.getSameReconstitutionSyringeForEachVaccineVial()); + target.setSameReconstitutionSyringeForEachVaccination(source.getSameReconstitutionSyringeForEachVaccination()); + target.setVaccinesAndDiluentsUsedRecommendedByManufacturer(source.getVaccinesAndDiluentsUsedRecommendedByManufacturer()); + target.setReconstitutionAdditionalDetails(source.getReconstitutionAdditionalDetails()); + target.setCorrectDoseOrRoute(source.getCorrectDoseOrRoute()); + target.setTimeOfReconstitutionMentionedOnTheVial(source.getTimeOfReconstitutionMentionedOnTheVial()); + target.setNonTouchTechniqueFollowed(source.getNonTouchTechniqueFollowed()); + target.setContraIndicationScreenedPriorToVaccination(source.getContraIndicationScreenedPriorToVaccination()); + target.setNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays( + source.getNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays()); + target.setTrainingReceivedByVaccinator(source.getTrainingReceivedByVaccinator()); + target.setLastTrainingReceivedByVaccinatorDate(source.getLastTrainingReceivedByVaccinatorDate()); + target.setInjectionTechniqueAdditionalDetails(source.getInjectionTechniqueAdditionalDetails()); + target.setVaccineStorageRefrigeratorTemperatureMonitored(source.getVaccineStorageRefrigeratorTemperatureMonitored()); + target.setAnyStorageTemperatureDeviationOutsideTwoToEightDegrees(source.getAnyStorageTemperatureDeviationOutsideTwoToEightDegrees()); + target.setStorageTemperatureMonitoringAdditionalDetails(source.getStorageTemperatureMonitoringAdditionalDetails()); + target.setCorrectProcedureForStorageFollowed(source.getCorrectProcedureForStorageFollowed()); + target.setAnyOtherItemInRefrigerator(source.getAnyOtherItemInRefrigerator()); + target.setPartiallyUsedReconstitutedVaccinesInRefrigerator(source.getPartiallyUsedReconstitutedVaccinesInRefrigerator()); + target.setUnusableVaccinesInRefrigerator(source.getUnusableVaccinesInRefrigerator()); + target.setUnusableDiluentsInStore(source.getUnusableDiluentsInStore()); + target.setVaccineStoragePointAdditionalDetails(source.getVaccineStoragePointAdditionalDetails()); + target.setVaccineCarrierType(source.getVaccineCarrierType()); + target.setVaccineCarrierTypeDetails(source.getVaccineCarrierTypeDetails()); + target.setVaccineCarrierSentToSiteOnSameDateAsVaccination(source.getVaccineCarrierSentToSiteOnSameDateAsVaccination()); + target.setVaccineCarrierReturnedFromSiteOnSameDateAsVaccination(source.getVaccineCarrierReturnedFromSiteOnSameDateAsVaccination()); + target.setConditionedIcepackUsed(source.getConditionedIcepackUsed()); + target.setVaccineTransportationAdditionalDetails(source.getVaccineTransportationAdditionalDetails()); + target.setSimilarEventsReportedSamePeriodAndLocality(source.getSimilarEventsReportedSamePeriodAndLocality()); + target.setSimilarEventsReportedSamePeriodAndLocalityDetails(source.getSimilarEventsReportedSamePeriodAndLocalityDetails()); + target.setNumberOfSimilarEventsReportedSamePeriodAndLocality(source.getNumberOfSimilarEventsReportedSamePeriodAndLocality()); + target.setNumberOfThoseAffectedVaccinated(source.getNumberOfThoseAffectedVaccinated()); + target.setNumberOfThoseAffectedNotVaccinated(source.getNumberOfThoseAffectedNotVaccinated()); + target.setNumberOfThoseAffectedVaccinatedUnknown(source.getNumberOfThoseAffectedVaccinatedUnknown()); + target.setCommunityInvestigationAdditionalDetails(source.getCommunityInvestigationAdditionalDetails()); + target.setOtherInvestigationFindings(source.getOtherInvestigationFindings()); + target.setInvestigationStatus(source.getInvestigationStatus()); + target.setAefiClassification(source.getAefiClassification()); + target.setArchived(source.isArchived()); + target.setDeleted(source.isDeleted()); + target.setDeletionReason(source.getDeletionReason()); + target.setOtherDeletionReason(source.getOtherDeletionReason()); + + return target; + } + + @Override + protected AefiInvestigationDto toDto(AefiInvestigation entity) { + return toAefiInvestigationDto(entity); + } + + public static AefiInvestigationDto toAefiInvestigationDto(AefiInvestigation entity) { + + if (entity == null) { + return null; + } + AefiInvestigationDto dto = new AefiInvestigationDto(); + DtoHelper.fillDto(dto, entity); + + dto.setAefiReport(AefiFacadeEjb.toReferenceDto(entity.getAefiReport())); + dto.setAddress(LocationFacadeEjb.toDto(entity.getAddress())); + + List vaccinationDtos = new ArrayList<>(); + for (Vaccination vaccination : entity.getAefiReport().getImmunization().getVaccinations()) { + VaccinationDto vaccinationDto = VaccinationFacadeEjb.toVaccinationDto(vaccination); + vaccinationDtos.add(vaccinationDto); + } + dto.setVaccinations(vaccinationDtos); + + if (entity.getPrimarySuspectVaccine() != null) { + dto.setPrimarySuspectVaccine(VaccinationFacadeEjb.toVaccinationDto(entity.getPrimarySuspectVaccine())); + } + + dto.setReportDate(entity.getReportDate()); + dto.setReportingUser(UserFacadeEjb.toReferenceDto(entity.getReportingUser())); + dto.setExternalId(entity.getExternalId()); + dto.setResponsibleRegion(RegionFacadeEjb.toReferenceDto(entity.getResponsibleRegion())); + dto.setResponsibleDistrict(DistrictFacadeEjb.toReferenceDto(entity.getResponsibleDistrict())); + dto.setResponsibleCommunity(CommunityFacadeEjb.toReferenceDto(entity.getResponsibleCommunity())); + dto.setCountry(CountryFacadeEjb.toReferenceDto(entity.getCountry())); + dto.setInvestigationCaseId(entity.getInvestigationCaseId()); + dto.setPlaceOfVaccination(entity.getPlaceOfVaccination()); + dto.setPlaceOfVaccinationDetails(entity.getPlaceOfVaccinationDetails()); + dto.setVaccinationActivity(entity.getVaccinationActivity()); + dto.setVaccinationActivityDetails(entity.getVaccinationActivityDetails()); + dto.setVaccinationFacility(FacilityFacadeEjb.toReferenceDto(entity.getVaccinationFacility())); + dto.setVaccinationFacilityDetails(entity.getVaccinationFacilityDetails()); + dto.setReportingOfficerName(entity.getReportingOfficerName()); + dto.setReportingOfficerFacility(FacilityFacadeEjb.toReferenceDto(entity.getReportingOfficerFacility())); + dto.setReportingOfficerFacilityDetails(entity.getReportingOfficerFacilityDetails()); + dto.setReportingOfficerDesignation(entity.getReportingOfficerDesignation()); + dto.setReportingOfficerDepartment(entity.getReportingOfficerDepartment()); + dto.setReportingOfficerAddress(LocationFacadeEjb.toDto(entity.getReportingOfficerAddress())); + dto.setReportingOfficerLandlinePhoneNumber(entity.getReportingOfficerLandlinePhoneNumber()); + dto.setReportingOfficerEmail(entity.getReportingOfficerEmail()); + dto.setReportingOfficerEmail(entity.getReportingOfficerEmail()); + dto.setInvestigationDate(entity.getInvestigationDate()); + dto.setFormCompletionDate(entity.getFormCompletionDate()); + dto.setInvestigationStage(entity.getInvestigationStage()); + dto.setTypeOfSite(entity.getTypeOfSite()); + dto.setTypeOfSiteDetails(entity.getTypeOfSiteDetails()); + dto.setKeySymptomDateTime(entity.getKeySymptomDateTime()); + dto.setHospitalizationDate(entity.getHospitalizationDate()); + dto.setReportedToHealthAuthorityDate(entity.getReportedToHealthAuthorityDate()); + dto.setStatusOnDateOfInvestigation(entity.getStatusOnDateOfInvestigation()); + dto.setDeathDateTime(entity.getDeathDateTime()); + dto.setAutopsyDone(entity.getAutopsyDone()); + dto.setAutopsyPlannedDateTime(entity.getAutopsyPlannedDateTime()); + dto.setPastHistoryOfSimilarEvent(entity.getPastHistoryOfSimilarEvent()); + dto.setPastHistoryOfSimilarEventDetails(entity.getPastHistoryOfSimilarEventDetails()); + dto.setAdverseEventAfterPreviousVaccinations(entity.getAdverseEventAfterPreviousVaccinations()); + dto.setAdverseEventAfterPreviousVaccinationsDetails(entity.getAdverseEventAfterPreviousVaccinationsDetails()); + dto.setHistoryOfAllergyToVaccineDrugOrFood(entity.getHistoryOfAllergyToVaccineDrugOrFood()); + dto.setHistoryOfAllergyToVaccineDrugOrFoodDetails(entity.getHistoryOfAllergyToVaccineDrugOrFoodDetails()); + dto.setPreExistingIllnessThirtyDaysOrCongenitalDisorder(entity.getPreExistingIllnessThirtyDaysOrCongenitalDisorder()); + dto.setPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails(entity.getPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails()); + dto.setHistoryOfHospitalizationInLastThirtyDaysWithCause(entity.getHistoryOfHospitalizationInLastThirtyDaysWithCause()); + dto.setHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails(entity.getHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails()); + dto.setCurrentlyOnConcomitantMedication(entity.getCurrentlyOnConcomitantMedication()); + dto.setCurrentlyOnConcomitantMedicationDetails(entity.getCurrentlyOnConcomitantMedicationDetails()); + dto.setFamilyHistoryOfDiseaseOrAllergy(entity.getFamilyHistoryOfDiseaseOrAllergy()); + dto.setFamilyHistoryOfDiseaseOrAllergyDetails(entity.getFamilyHistoryOfDiseaseOrAllergyDetails()); + dto.setBirthTerm(entity.getBirthTerm()); + dto.setBirthWeight(entity.getBirthWeight()); + dto.setDeliveryProcedure(entity.getDeliveryProcedure()); + dto.setDeliveryProcedureDetails(entity.getDeliveryProcedureDetails()); + dto.setSeriousAefiInfoSource(entity.getSeriousAefiInfoSource()); + dto.setSeriousAefiInfoSourceDetails(entity.getSeriousAefiInfoSourceDetails()); + dto.setSeriousAefiVerbalAutopsyInfoSourceDetails(entity.getSeriousAefiVerbalAutopsyInfoSourceDetails()); + dto.setFirstCaregiversName(entity.getFirstCaregiversName()); + dto.setOtherCaregiversNames(entity.getOtherCaregiversNames()); + dto.setOtherSourcesWhoProvidedInfo(entity.getOtherSourcesWhoProvidedInfo()); + dto.setSignsAndSymptomsFromTimeOfVaccination(entity.getSignsAndSymptomsFromTimeOfVaccination()); + dto.setClinicalDetailsOfficerName(entity.getClinicalDetailsOfficerName()); + dto.setClinicalDetailsOfficerPhoneNumber(entity.getClinicalDetailsOfficerPhoneNumber()); + dto.setClinicalDetailsOfficerEmail(entity.getClinicalDetailsOfficerEmail()); + dto.setClinicalDetailsOfficerDesignation(entity.getClinicalDetailsOfficerDesignation()); + dto.setClinicalDetailsDateTime(entity.getClinicalDetailsDateTime()); + dto.setPatientReceivedMedicalCare(entity.getPatientReceivedMedicalCare()); + dto.setPatientReceivedMedicalCareDetails(entity.getPatientReceivedMedicalCareDetails()); + dto.setProvisionalOrFinalDiagnosis(entity.getProvisionalOrFinalDiagnosis()); + dto.setPatientImmunizedPeriod(entity.getPatientImmunizedPeriod()); + dto.setPatientImmunizedPeriodDetails(entity.getPatientImmunizedPeriodDetails()); + dto.setVaccineGivenPeriod(entity.getVaccineGivenPeriod()); + dto.setVaccineGivenPeriodDetails(entity.getVaccineGivenPeriodDetails()); + dto.setErrorPrescribingVaccine(entity.getErrorPrescribingVaccine()); + dto.setErrorPrescribingVaccineDetails(entity.getErrorPrescribingVaccineDetails()); + dto.setVaccineCouldHaveBeenUnSterile(entity.getVaccineCouldHaveBeenUnSterile()); + dto.setVaccineCouldHaveBeenUnSterileDetails(entity.getVaccineCouldHaveBeenUnSterileDetails()); + dto.setVaccinePhysicalConditionAbnormal(entity.getVaccinePhysicalConditionAbnormal()); + dto.setVaccinePhysicalConditionAbnormalDetails(entity.getVaccinePhysicalConditionAbnormalDetails()); + dto.setErrorInVaccineReconstitution(entity.getErrorInVaccineReconstitution()); + dto.setErrorInVaccineReconstitutionDetails(entity.getErrorInVaccineReconstitutionDetails()); + dto.setErrorInVaccineHandling(entity.getErrorInVaccineHandling()); + dto.setErrorInVaccineHandlingDetails(entity.getErrorInVaccineHandlingDetails()); + dto.setVaccineAdministeredIncorrectly(entity.getVaccineAdministeredIncorrectly()); + dto.setVaccineAdministeredIncorrectlyDetails(entity.getVaccineAdministeredIncorrectlyDetails()); + dto.setNumberImmunizedFromConcernedVaccineVial(entity.getNumberImmunizedFromConcernedVaccineVial()); + dto.setNumberImmunizedWithConcernedVaccineInSameSession(entity.getNumberImmunizedWithConcernedVaccineInSameSession()); + dto.setNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations(entity.getNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations()); + dto.setNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails( + entity.getNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails()); + dto.setVaccineHasQualityDefect(entity.getVaccineHasQualityDefect()); + dto.setVaccineHasQualityDefectDetails(entity.getVaccineHasQualityDefectDetails()); + dto.setEventIsAStressResponseRelatedToImmunization(entity.getEventIsAStressResponseRelatedToImmunization()); + dto.setEventIsAStressResponseRelatedToImmunizationDetails(entity.getEventIsAStressResponseRelatedToImmunizationDetails()); + dto.setCaseIsPartOfACluster(entity.getCaseIsPartOfACluster()); + dto.setCaseIsPartOfAClusterDetails(entity.getCaseIsPartOfAClusterDetails()); + dto.setNumberOfCasesDetectedInCluster(entity.getNumberOfCasesDetectedInCluster()); + dto.setAllCasesInClusterReceivedVaccineFromSameVial(entity.getAllCasesInClusterReceivedVaccineFromSameVial()); + dto.setAllCasesInClusterReceivedVaccineFromSameVialDetails(entity.getAllCasesInClusterReceivedVaccineFromSameVialDetails()); + dto.setNumberOfVialsUsedInCluster(entity.getNumberOfVialsUsedInCluster()); + dto.setNumberOfVialsUsedInClusterDetails(entity.getNumberOfVialsUsedInClusterDetails()); + dto.setAdSyringesUsedForImmunization(entity.getAdSyringesUsedForImmunization()); + dto.setTypeOfSyringesUsed(entity.getTypeOfSyringesUsed()); + dto.setTypeOfSyringesUsedDetails(entity.getTypeOfSyringesUsedDetails()); + dto.setSyringesUsedAdditionalDetails(entity.getSyringesUsedAdditionalDetails()); + dto.setSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine(entity.getSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine()); + dto.setSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines( + entity.getSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines()); + dto.setSameReconstitutionSyringeForEachVaccineVial(entity.getSameReconstitutionSyringeForEachVaccineVial()); + dto.setSameReconstitutionSyringeForEachVaccination(entity.getSameReconstitutionSyringeForEachVaccination()); + dto.setVaccinesAndDiluentsUsedRecommendedByManufacturer(entity.getVaccinesAndDiluentsUsedRecommendedByManufacturer()); + dto.setReconstitutionAdditionalDetails(entity.getReconstitutionAdditionalDetails()); + dto.setCorrectDoseOrRoute(entity.getCorrectDoseOrRoute()); + dto.setTimeOfReconstitutionMentionedOnTheVial(entity.getTimeOfReconstitutionMentionedOnTheVial()); + dto.setNonTouchTechniqueFollowed(entity.getNonTouchTechniqueFollowed()); + dto.setContraIndicationScreenedPriorToVaccination(entity.getContraIndicationScreenedPriorToVaccination()); + dto.setNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays( + entity.getNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays()); + dto.setTrainingReceivedByVaccinator(entity.getTrainingReceivedByVaccinator()); + dto.setLastTrainingReceivedByVaccinatorDate(entity.getLastTrainingReceivedByVaccinatorDate()); + dto.setInjectionTechniqueAdditionalDetails(entity.getInjectionTechniqueAdditionalDetails()); + dto.setVaccineStorageRefrigeratorTemperatureMonitored(entity.getVaccineStorageRefrigeratorTemperatureMonitored()); + dto.setAnyStorageTemperatureDeviationOutsideTwoToEightDegrees(entity.getAnyStorageTemperatureDeviationOutsideTwoToEightDegrees()); + dto.setStorageTemperatureMonitoringAdditionalDetails(entity.getStorageTemperatureMonitoringAdditionalDetails()); + dto.setCorrectProcedureForStorageFollowed(entity.getCorrectProcedureForStorageFollowed()); + dto.setAnyOtherItemInRefrigerator(entity.getAnyOtherItemInRefrigerator()); + dto.setPartiallyUsedReconstitutedVaccinesInRefrigerator(entity.getPartiallyUsedReconstitutedVaccinesInRefrigerator()); + dto.setUnusableVaccinesInRefrigerator(entity.getUnusableVaccinesInRefrigerator()); + dto.setUnusableDiluentsInStore(entity.getUnusableDiluentsInStore()); + dto.setVaccineStoragePointAdditionalDetails(entity.getVaccineStoragePointAdditionalDetails()); + dto.setVaccineCarrierType(entity.getVaccineCarrierType()); + dto.setVaccineCarrierTypeDetails(entity.getVaccineCarrierTypeDetails()); + dto.setVaccineCarrierSentToSiteOnSameDateAsVaccination(entity.getVaccineCarrierSentToSiteOnSameDateAsVaccination()); + dto.setVaccineCarrierReturnedFromSiteOnSameDateAsVaccination(entity.getVaccineCarrierReturnedFromSiteOnSameDateAsVaccination()); + dto.setConditionedIcepackUsed(entity.getConditionedIcepackUsed()); + dto.setVaccineTransportationAdditionalDetails(entity.getVaccineTransportationAdditionalDetails()); + dto.setSimilarEventsReportedSamePeriodAndLocality(entity.getSimilarEventsReportedSamePeriodAndLocality()); + dto.setSimilarEventsReportedSamePeriodAndLocalityDetails(entity.getSimilarEventsReportedSamePeriodAndLocalityDetails()); + dto.setNumberOfSimilarEventsReportedSamePeriodAndLocality(entity.getNumberOfSimilarEventsReportedSamePeriodAndLocality()); + dto.setNumberOfThoseAffectedVaccinated(entity.getNumberOfThoseAffectedVaccinated()); + dto.setNumberOfThoseAffectedNotVaccinated(entity.getNumberOfThoseAffectedNotVaccinated()); + dto.setNumberOfThoseAffectedVaccinatedUnknown(entity.getNumberOfThoseAffectedVaccinatedUnknown()); + dto.setCommunityInvestigationAdditionalDetails(entity.getCommunityInvestigationAdditionalDetails()); + dto.setOtherInvestigationFindings(entity.getOtherInvestigationFindings()); + dto.setInvestigationStatus(entity.getInvestigationStatus()); + dto.setAefiClassification(entity.getAefiClassification()); + dto.setArchived(entity.isArchived()); + dto.setDeleted(entity.isDeleted()); + dto.setDeletionReason(entity.getDeletionReason()); + dto.setOtherDeletionReason(entity.getOtherDeletionReason()); + + return dto; + } + + @Override + protected AefiInvestigationReferenceDto toRefDto(AefiInvestigation aefiInvestigation) { + return toReferenceDto(aefiInvestigation); + } + + public static AefiInvestigationReferenceDto toReferenceDto(AefiInvestigation entity) { + + if (entity == null) { + return null; + } + + return new AefiInvestigationReferenceDto(entity.getUuid(), ""); + } + + @Override + protected void pseudonymizeDto( + AefiInvestigation source, + AefiInvestigationDto dto, + Pseudonymizer pseudonymizer, + boolean inJurisdiction) { + + if (dto != null) { + pseudonymizer.pseudonymizeDto(AefiInvestigationDto.class, dto, inJurisdiction, c -> { + pseudonymizer.pseudonymizeUser(source.getReportingUser(), userService.getCurrentUser(), dto::setReportingUser, dto); + }); + } + } + + @Override + protected void restorePseudonymizedDto( + AefiInvestigationDto dto, + AefiInvestigationDto existingDto, + AefiInvestigation entity, + Pseudonymizer pseudonymizer) { + + if (existingDto != null) { + final boolean inJurisdiction = service.inJurisdictionOrOwned(entity); + final User currentUser = userService.getCurrentUser(); + pseudonymizer.restoreUser(entity.getReportingUser(), currentUser, dto, dto::setReportingUser); + pseudonymizer.restorePseudonymizedValues(AefiInvestigationDto.class, dto, existingDto, inJurisdiction); + } + } + + @Override + protected DeletableEntityType getDeletableEntityType() { + return null; + } + + @LocalBean + @Stateless + public static class AefiInvestigationFacadeEjbLocal extends AefiInvestigationFacadeEjb { + + public AefiInvestigationFacadeEjbLocal() { + super(); + } + + @Inject + public AefiInvestigationFacadeEjbLocal(AefiInvestigationService service) { + super(service); + } + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationJurisdictionPredicateValidator.java new file mode 100644 index 00000000000..bf377ed8fb7 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationJurisdictionPredicateValidator.java @@ -0,0 +1,116 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import java.util.List; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; + +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigationJoins; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.util.PredicateJurisdictionValidator; + +public class AefiInvestigationJurisdictionPredicateValidator extends PredicateJurisdictionValidator { + + private final AefiInvestigationJoins joins; + + public AefiInvestigationJurisdictionPredicateValidator( + CriteriaBuilder cb, + AefiInvestigationJoins joins, + User user, + List jurisdictionValidators) { + super(cb, user, null, jurisdictionValidators); + this.joins = joins; + } + + public static AefiInvestigationJurisdictionPredicateValidator of(AefiInvestigationQueryContext qc, User user) { + return new AefiInvestigationJurisdictionPredicateValidator(qc.getCriteriaBuilder(), qc.getJoins(), user, null); + } + + @Override + public Predicate isRootInJurisdiction() { + return isInJurisdictionByJurisdictionLevel(user.getJurisdictionLevel()); + } + + @Override + public Predicate isRootInJurisdictionOrOwned() { + final Path reportingUserPath = joins.getRoot().get(AefiInvestigation.REPORTING_USER); + final Predicate reportedByCurrentUser = cb.and(cb.isNotNull(reportingUserPath), cb.equal(reportingUserPath.get(User.ID), user.getId())); + return cb.or(reportedByCurrentUser, this.isRootInJurisdiction()); + } + + @Override + public Predicate isRootInJurisdictionForRestrictedAccess() { + return null; + } + + @Override + protected Predicate whenNotAllowed() { + return cb.disjunction(); + } + + @Override + protected Predicate whenNationalLevel() { + return cb.conjunction(); + } + + @Override + protected Predicate whenRegionalLevel() { + return cb.equal( + joins.getRoot().get(AefiInvestigation.AEFI_REPORT).get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_REGION).get(Region.ID), + user.getRegion().getId()); + } + + @Override + protected Predicate whenDistrictLevel() { + return cb.equal( + joins.getRoot().get(AefiInvestigation.AEFI_REPORT).get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_DISTRICT).get(District.ID), + user.getDistrict().getId()); + } + + @Override + protected Predicate whenCommunityLevel() { + return cb.equal( + joins.getRoot().get(AefiInvestigation.AEFI_REPORT).get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_COMMUNITY).get(Community.ID), + user.getCommunity().getId()); + } + + @Override + protected Predicate whenFacilityLevel() { + return cb.equal( + joins.getRoot().get(AefiInvestigation.AEFI_REPORT).get(Aefi.IMMUNIZATION).get(Immunization.HEALTH_FACILITY).get(Facility.ID), + user.getHealthFacility().getId()); + } + + @Override + protected Predicate whenPointOfEntryLevel() { + return cb.disjunction(); + } + + @Override + protected Predicate whenLaboratoryLevel() { + return cb.disjunction(); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationQueryContext.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationQueryContext.java new file mode 100644 index 00000000000..81defa6406f --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationQueryContext.java @@ -0,0 +1,45 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; + +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigationJoins; +import de.symeda.sormas.backend.common.QueryContext; + +public class AefiInvestigationQueryContext extends QueryContext { + + public AefiInvestigationQueryContext(CriteriaBuilder cb, CriteriaQuery query, From root) { + super(cb, query, root, new AefiInvestigationJoins(root)); + } + + public AefiInvestigationQueryContext(CriteriaBuilder cb, CriteriaQuery query, AefiInvestigationJoins joins) { + super(cb, query, joins.getRoot(), joins); + } + + public AefiInvestigationQueryContext(CriteriaBuilder cb, CriteriaQuery query, From root, AefiInvestigationJoins joins) { + super(cb, query, root, joins); + } + + @Override + protected Expression createExpression(String name) { + return null; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationService.java new file mode 100644 index 00000000000..dfa5f010a5f --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiInvestigationService.java @@ -0,0 +1,548 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import static de.symeda.sormas.backend.common.CriteriaBuilderHelper.andEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.persistence.Tuple; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Selection; + +import org.apache.commons.collections4.CollectionUtils; + +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDateType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.feature.FeatureTypeProperty; +import de.symeda.sormas.api.person.PersonIndexDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.SortProperty; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigationJoins; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers.AefiInvestigationIndexDtoResultTransformer; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers.AefiInvestigationListEntryDtoResultTransformer; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.person.Person; +import de.symeda.sormas.backend.person.PersonJoins; +import de.symeda.sormas.backend.person.PersonJurisdictionPredicateValidator; +import de.symeda.sormas.backend.person.PersonQueryContext; +import de.symeda.sormas.backend.person.PersonService; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.IterableHelper; +import de.symeda.sormas.backend.util.JurisdictionHelper; +import de.symeda.sormas.backend.util.ModelConstants; +import de.symeda.sormas.backend.util.QueryHelper; +import de.symeda.sormas.backend.vaccination.Vaccination; + +@Stateless +@LocalBean +public class AefiInvestigationService extends AbstractCoreAdoService { + + @EJB + private PersonService personService; + @EJB + private UserService userService; + @EJB + private FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; + + public AefiInvestigationService() { + super(AefiInvestigation.class, DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION); + } + + public List getEntriesList(Long aefiReportId, Integer first, Integer max) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Tuple.class); + final Root aefiInvestigation = cq.from(AefiInvestigation.class); + + AefiInvestigationQueryContext queryContext = new AefiInvestigationQueryContext(cb, cq, aefiInvestigation); + AefiInvestigationJoins joins = queryContext.getJoins(); + + Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + + cq.multiselect( + aefiInvestigation.get(AefiInvestigation.UUID), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_CASE_ID), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_DATE), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_STAGE), + aefiInvestigation.get(AefiInvestigation.STATUS_ON_DATE_OF_INVESTIGATION), + primarySuspectVaccine.get(Vaccination.VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.OTHER_VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.VACCINE_DOSE), + primarySuspectVaccine.get(Vaccination.VACCINATION_DATE), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_STATUS), + aefiInvestigation.get(AefiInvestigation.AEFI_CLASSIFICATION), + aefiInvestigation.get(Aefi.CHANGE_DATE), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(queryContext))); + + final Predicate criteriaFilter = buildCriteriaFilter(aefiReportId, queryContext); + if (criteriaFilter != null) { + cq.where(criteriaFilter); + } + + cq.orderBy(cb.desc(aefiInvestigation.get(AefiInvestigation.CHANGE_DATE))); + + cq.distinct(true); + + return QueryHelper.getResultList(em, cq, new AefiInvestigationListEntryDtoResultTransformer(), first, max); + } + + private Predicate buildCriteriaFilter(Long aefiReportId, AefiInvestigationQueryContext queryContext) { + + final CriteriaBuilder cb = queryContext.getCriteriaBuilder(); + final From from = queryContext.getRoot(); + + Predicate filter = cb.equal(from.get(AefiInvestigation.AEFI_REPORT_ID), aefiReportId); + + filter = CriteriaBuilderHelper.and(cb, filter, cb.isFalse(from.get(AefiInvestigation.DELETED))); + + return filter; + } + + public long count(AefiInvestigationCriteria criteria) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Long.class); + final Root aefiInvestigation = cq.from(AefiInvestigation.class); + + AefiInvestigationQueryContext queryContext = new AefiInvestigationQueryContext(cb, cq, aefiInvestigation); + + buildWhereCondition(criteria, cb, cq, queryContext, null); + + cq.select(cb.countDistinct(aefiInvestigation)); + return em.createQuery(cq).getSingleResult(); + } + + public List getIndexList( + AefiInvestigationCriteria criteria, + Integer first, + Integer max, + List sortProperties) { + + List indexListIds = getIndexListIds(criteria, first, max, sortProperties); + List aefiInvestigationIndexDtos = new ArrayList<>(); + + IterableHelper.executeBatched(indexListIds, ModelConstants.PARAMETER_LIMIT, batchedIds -> { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Tuple.class); + final Root aefiInvestigation = cq.from(AefiInvestigation.class); + + AefiInvestigationQueryContext queryContext = new AefiInvestigationQueryContext(cb, cq, aefiInvestigation); + AefiInvestigationJoins joins = queryContext.getJoins(); + + final Join aefi = joins.getAefi(); + final Join immunization = joins.getAefiJoins().getImmunization(); + final Join person = joins.getAefiJoins().getImmunizationJoins().getPerson(); + + final Join responsibleRegion = joins.getAefiJoins().getImmunizationJoins().getResponsibleRegion(); + final Join responsibleDistrict = joins.getAefiJoins().getImmunizationJoins().getResponsibleDistrict(); + + final Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + + cq.multiselect( + Stream + .concat( + Stream.of( + aefiInvestigation.get(AefiInvestigation.UUID), + aefi.get(Aefi.UUID), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_CASE_ID), + immunization.get(Immunization.DISEASE), + person.get(Person.FIRST_NAME), + person.get(Person.LAST_NAME), + person.get(Person.APPROXIMATE_AGE), + person.get(Person.APPROXIMATE_AGE_TYPE), + person.get(Person.BIRTHDATE_DD), + person.get(Person.BIRTHDATE_MM), + person.get(Person.BIRTHDATE_YYYY), + person.get(Person.SEX), + responsibleRegion.get(Region.NAME), + responsibleDistrict.get(District.NAME), + aefiInvestigation.get(AefiInvestigation.PLACE_OF_VACCINATION), + aefiInvestigation.get(AefiInvestigation.VACCINATION_ACTIVITY), + aefi.get(Aefi.REPORT_DATE), + aefiInvestigation.get(Aefi.REPORT_DATE), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_DATE), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_STAGE), + aefiInvestigation.get(AefiInvestigation.TYPE_OF_SITE), + aefiInvestigation.get(AefiInvestigation.KEY_SYMPTOM_DATE_TIME), + aefiInvestigation.get(AefiInvestigation.HOSPITALIZATION_DATE), + aefiInvestigation.get(AefiInvestigation.REPORTED_TO_HEALTH_AUTHORITY_DATE), + aefiInvestigation.get(AefiInvestigation.STATUS_ON_DATE_OF_INVESTIGATION), + primarySuspectVaccine.get(Vaccination.VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.OTHER_VACCINE_NAME), + aefiInvestigation.get(AefiInvestigation.INVESTIGATION_STATUS), + aefiInvestigation.get(AefiInvestigation.AEFI_CLASSIFICATION), + aefiInvestigation.get(AefiInvestigation.DELETION_REASON), + aefiInvestigation.get(AefiInvestigation.OTHER_DELETION_REASON), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(queryContext)), + aefiInvestigation.get(AefiInvestigation.CHANGE_DATE)), + // add sort properties to select + sortBy(sortProperties, queryContext).stream()) + .collect(Collectors.toList())); + + buildWhereCondition(criteria, cb, cq, queryContext, aefiInvestigation.get(AefiInvestigation.ID).in(batchedIds)); + cq.distinct(true); + + aefiInvestigationIndexDtos.addAll(QueryHelper.getResultList(em, cq, new AefiInvestigationIndexDtoResultTransformer(), null, null)); + }); + + return aefiInvestigationIndexDtos; + } + + private List getIndexListIds(AefiInvestigationCriteria criteria, Integer first, Integer max, List sortProperties) { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createTupleQuery(); + final Root aefiInvestigation = cq.from(AefiInvestigation.class); + + AefiInvestigationQueryContext queryContext = new AefiInvestigationQueryContext(cb, cq, aefiInvestigation); + + List> selections = new ArrayList<>(); + selections.add(aefiInvestigation.get(AefiInvestigation.ID)); + selections.addAll(sortBy(sortProperties, queryContext)); + + cq.multiselect(selections); + + buildWhereCondition(criteria, cb, cq, queryContext, null); + cq.distinct(true); + + List aefiInvestigationsResultList = QueryHelper.getResultList(em, cq, first, max); + return aefiInvestigationsResultList.stream().map(t -> t.get(0, Long.class)).collect(Collectors.toList()); + } + + private List> sortBy(List sortProperties, AefiInvestigationQueryContext queryContext) { + + List> selections = new ArrayList<>(); + CriteriaBuilder cb = queryContext.getCriteriaBuilder(); + CriteriaQuery cq = queryContext.getQuery(); + + if (CollectionUtils.isNotEmpty(sortProperties)) { + List order = new ArrayList<>(sortProperties.size()); + for (SortProperty sortProperty : sortProperties) { + Expression expression; + switch (sortProperty.propertyName) { + case AefiInvestigationIndexDto.UUID: + case AefiInvestigationIndexDto.DISEASE: + case AefiInvestigationIndexDto.INVESTIGATION_DATE: + case AefiInvestigationIndexDto.STATUS_ON_DATE_OF_INVESTIGATION: + case AefiInvestigationIndexDto.AEFI_CLASSIFICATION: + expression = queryContext.getRoot().get(sortProperty.propertyName); + break; + case AefiInvestigationIndexDto.AEFI_REPORT_UUID: + expression = queryContext.getJoins().getAefi().get(Aefi.UUID); + break; + case AefiInvestigationIndexDto.PERSON_FIRST_NAME: + expression = cb.lower(queryContext.getJoins().getAefiJoins().getImmunizationJoins().getPerson().get(Person.FIRST_NAME)); + break; + case AefiInvestigationIndexDto.PERSON_LAST_NAME: + expression = cb.lower(queryContext.getJoins().getAefiJoins().getImmunizationJoins().getPerson().get(Person.LAST_NAME)); + break; + case AefiInvestigationIndexDto.AGE_AND_BIRTH_DATE: + expression = queryContext.getJoins().getAefiJoins().getImmunizationJoins().getPerson().get(Person.APPROXIMATE_AGE); + break; + case AefiInvestigationIndexDto.SEX: + expression = queryContext.getJoins().getAefiJoins().getImmunizationJoins().getPerson().get(Person.SEX); + break; + case AefiInvestigationIndexDto.REGION: + expression = cb.lower( + queryContext.getJoins() + .getAefiJoins() + .getImmunizationJoins() + .getPersonJoins() + .getAddressJoins() + .getRegion() + .get(Region.NAME)); + break; + case AefiInvestigationIndexDto.DISTRICT: + expression = cb.lower( + queryContext.getJoins() + .getAefiJoins() + .getImmunizationJoins() + .getPersonJoins() + .getAddressJoins() + .getDistrict() + .get(District.NAME)); + break; + case AefiInvestigationIndexDto.PRIMARY_VACCINE_NAME: + expression = queryContext.getJoins().getPrimarySuspectVaccination().get(Vaccination.VACCINE_NAME); + break; + default: + throw new IllegalArgumentException(sortProperty.propertyName); + } + order.add(sortProperty.ascending ? cb.asc(expression) : cb.desc(expression)); + selections.add(expression); + } + cq.orderBy(order); + } else { + Path changeDate = queryContext.getRoot().get(AefiInvestigation.CHANGE_DATE); + cq.orderBy(cb.desc(changeDate)); + selections.add(changeDate); + } + + return selections; + } + + private void buildWhereCondition( + AefiInvestigationCriteria criteria, + CriteriaBuilder cb, + CriteriaQuery cq, + AefiInvestigationQueryContext queryContext, + Predicate additionalFilter) { + + Predicate filter = createUserFilter(queryContext); + if (additionalFilter != null) { + filter = CriteriaBuilderHelper.and(cb, additionalFilter, filter); + } + + if (criteria != null) { + final Predicate criteriaFilter = buildCriteriaFilter(criteria, queryContext); + filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); + } + + if (filter != null) { + cq.where(filter); + } + } + + public Predicate buildCriteriaFilter(AefiInvestigationCriteria criteria, AefiInvestigationQueryContext queryContext) { + + final AefiInvestigationJoins joins = queryContext.getJoins(); + final CriteriaBuilder cb = queryContext.getCriteriaBuilder(); + final From from = queryContext.getRoot(); + final Join aefi = joins.getAefi(); + final Join immunization = joins.getAefiJoins().getImmunization(); + final Join person = joins.getAefiJoins().getImmunizationJoins().getPerson(); + final Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + + final Join location = joins.getAefiJoins().getImmunizationJoins().getPersonJoins().getAddress(); + + Predicate filter = null; + if (criteria.getDisease() != null) { + filter = CriteriaBuilderHelper.and(cb, null, cb.equal(immunization.get(Immunization.DISEASE), criteria.getDisease())); + } + + if (!DataHelper.isNullOrEmpty(criteria.getAefiReportLike())) { + + String[] textFilters = criteria.getAefiReportLike().split("\\s+"); + + for (String textFilter : textFilters) { + if (DataHelper.isNullOrEmpty(textFilter)) { + continue; + } + + Predicate likeFilters = cb.or(CriteriaBuilderHelper.ilike(cb, aefi.get(Aefi.UUID), textFilter)); + filter = CriteriaBuilderHelper.and(cb, filter, likeFilters); + } + } + + if (!DataHelper.isNullOrEmpty(criteria.getPersonLike())) { + final CriteriaQuery cq = cb.createQuery(PersonIndexDto.class); + final PersonQueryContext personQueryContext = + new PersonQueryContext(cb, cq, joins.getAefiJoins().getImmunizationJoins().getPersonJoins()); + + String[] textFilters = criteria.getPersonLike().split("\\s+"); + + for (String textFilter : textFilters) { + if (DataHelper.isNullOrEmpty(textFilter)) { + continue; + } + + Predicate likeFilters = cb.or( + CriteriaBuilderHelper.ilike(cb, from.get(AefiInvestigation.UUID), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, person.get(Person.FIRST_NAME), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, person.get(Person.LAST_NAME), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.UUID), textFilter), + CriteriaBuilderHelper.ilike(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_EMAIL_SUBQUERY), textFilter), + phoneNumberPredicate(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_PHONE_SUBQUERY), textFilter), + CriteriaBuilderHelper + .ilike(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_PRIMARY_OTHER_SUBQUERY), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, location.get(Location.STREET), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, location.get(Location.CITY), textFilter), + CriteriaBuilderHelper.ilike(cb, location.get(Location.POSTAL_CODE), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.INTERNAL_TOKEN), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.EXTERNAL_ID), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.EXTERNAL_TOKEN), textFilter)); + filter = CriteriaBuilderHelper.and(cb, filter, likeFilters); + } + } + if (criteria.getAefiType() != null) { + if (criteria.getAefiType() == AefiType.SERIOUS) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(aefi.get(Aefi.SERIOUS), YesNoUnknown.YES)); + } else { + filter = CriteriaBuilderHelper.and(cb, filter, cb.notEqual(aefi.get(Aefi.SERIOUS), YesNoUnknown.YES)); + } + } + if (criteria.getStatusAtAefiInvestigation() != null) { + filter = CriteriaBuilderHelper + .and(cb, filter, cb.equal(from.get(AefiInvestigation.STATUS_ON_DATE_OF_INVESTIGATION), criteria.getStatusAtAefiInvestigation())); + } + if (criteria.getAefiClassification() != null) { + filter = + CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(AefiInvestigation.AEFI_CLASSIFICATION), criteria.getAefiClassification())); + } + if (criteria.getVaccineName() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(primarySuspectVaccine.get(Vaccination.VACCINE_NAME), criteria.getVaccineName())); + } + if (criteria.getVaccineManufacturer() != null) { + filter = CriteriaBuilderHelper + .and(cb, filter, cb.equal(primarySuspectVaccine.get(Vaccination.VACCINE_MANUFACTURER), criteria.getVaccineManufacturer())); + } + filter = andEquals(cb, () -> joins.getAefiJoins().getImmunizationJoins().getResponsibleRegion(), filter, criteria.getRegion()); + filter = andEquals(cb, () -> joins.getAefiJoins().getImmunizationJoins().getResponsibleDistrict(), filter, criteria.getDistrict()); + filter = andEquals(cb, () -> joins.getAefiJoins().getImmunizationJoins().getResponsibleCommunity(), filter, criteria.getCommunity()); + if (criteria.getFacilityType() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(immunization.get(Immunization.FACILITY_TYPE), criteria.getFacilityType())); + } + filter = andEquals(cb, () -> joins.getAefiJoins().getImmunizationJoins().getHealthFacility(), filter, criteria.getHealthFacility()); + if (criteria.getAefiInvestigationDateType() != null) { + Path path = buildPathForDateFilter(criteria.getAefiInvestigationDateType(), queryContext); + if (path != null) { + filter = CriteriaBuilderHelper.applyDateFilter(cb, filter, path, criteria.getFromDate(), criteria.getToDate()); + } + } + + if (criteria.getRelevanceStatus() != null) { + if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { + filter = CriteriaBuilderHelper + .and(cb, filter, cb.or(cb.equal(from.get(AefiInvestigation.ARCHIVED), false), cb.isNull(from.get(AefiInvestigation.ARCHIVED)))); + } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(AefiInvestigation.ARCHIVED), true)); + } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.DELETED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(AefiInvestigation.DELETED), true)); + } + } + if (criteria.getRelevanceStatus() != EntityRelevanceStatus.DELETED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.isFalse(from.get(AefiInvestigation.DELETED))); + } + + return filter; + } + + private Path buildPathForDateFilter(AefiInvestigationDateType aefiInvestigationDateType, AefiInvestigationQueryContext queryContext) { + Path path = null; + String dateField = getDateFieldFromDateType(aefiInvestigationDateType); + if (dateField != null) { + if (Vaccination.VACCINATION_DATE.equals(dateField)) { + final Join primarySuspectVaccination = queryContext.getJoins().getPrimarySuspectVaccination(); + path = primarySuspectVaccination.get(Vaccination.VACCINATION_DATE); + } else { + path = queryContext.getRoot().get(dateField); + } + } + return path; + } + + private String getDateFieldFromDateType(AefiInvestigationDateType aefiInvestigationDateType) { + switch (aefiInvestigationDateType) { + case REPORT_DATE: + return AefiInvestigation.REPORT_DATE; + case INVESTIGATION_DATE: + return AefiInvestigation.INVESTIGATION_DATE; + case VACCINATION_DATE: + return Vaccination.VACCINATION_DATE; + } + return null; + } + + public Predicate createUserFilter(AefiInvestigationQueryContext qc) { + + User currentUser = getCurrentUser(); + if (currentUser == null) { + return null; + } + final CriteriaBuilder cb = qc.getCriteriaBuilder(); + + Predicate filter = isInJurisdictionOrOwned(qc); + + filter = CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper.limitedDiseasePredicate( + cb, + currentUser, + qc.getRoot().get(AefiInvestigation.AEFI_REPORT).get(Aefi.IMMUNIZATION).get(Immunization.DISEASE))); + + return filter; + } + + private Predicate isInJurisdictionOrOwned(AefiInvestigationQueryContext qc) { + + final User currentUser = userService.getCurrentUser(); + CriteriaBuilder cb = qc.getCriteriaBuilder(); + Predicate filter; + if (!featureConfigurationFacade + .isPropertyValueTrue(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) { + filter = AefiInvestigationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); + } else { + filter = CriteriaBuilderHelper.or( + cb, + cb.equal(qc.getRoot().get(AefiInvestigation.REPORTING_USER), currentUser), + PersonJurisdictionPredicateValidator + .of( + qc.getQuery(), + cb, + new PersonJoins(qc.getJoins().getAefiJoins().getImmunizationJoins().getPerson()), + currentUser, + personService.getPermittedAssociations()) + .inJurisdictionOrOwned()); + } + return filter; + } + + @Override + protected Predicate createUserFilterInternal(CriteriaBuilder cb, CriteriaQuery cq, From from) { + return createUserFilter(new AefiInvestigationQueryContext(cb, cq, from)); + } + + @Override + protected AefiInvestigationJoins toJoins(From adoPath) { + return new AefiInvestigationJoins(adoPath); + } + + @Override + public Predicate inJurisdictionOrOwned(CriteriaBuilder cb, CriteriaQuery query, From from) { + return isInJurisdictionOrOwned(new AefiInvestigationQueryContext(cb, query, from)); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiJurisdictionPredicateValidator.java new file mode 100644 index 00000000000..776d84268c9 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiJurisdictionPredicateValidator.java @@ -0,0 +1,108 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import java.util.List; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; + +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiJoins; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.util.PredicateJurisdictionValidator; + +public class AefiJurisdictionPredicateValidator extends PredicateJurisdictionValidator { + + private final AefiJoins joins; + + public AefiJurisdictionPredicateValidator( + CriteriaBuilder cb, + AefiJoins joins, + User user, + List jurisdictionValidators) { + super(cb, user, null, jurisdictionValidators); + this.joins = joins; + } + + public static AefiJurisdictionPredicateValidator of(AefiQueryContext qc, User user) { + return new AefiJurisdictionPredicateValidator(qc.getCriteriaBuilder(), qc.getJoins(), user, null); + } + + @Override + public Predicate isRootInJurisdiction() { + return isInJurisdictionByJurisdictionLevel(user.getJurisdictionLevel()); + } + + @Override + public Predicate isRootInJurisdictionOrOwned() { + final Path reportingUserPath = joins.getRoot().get(Aefi.REPORTING_USER); + final Predicate reportedByCurrentUser = cb.and(cb.isNotNull(reportingUserPath), cb.equal(reportingUserPath.get(User.ID), user.getId())); + return cb.or(reportedByCurrentUser, this.isRootInJurisdiction()); + } + + @Override + public Predicate isRootInJurisdictionForRestrictedAccess() { + return null; + } + + @Override + protected Predicate whenNotAllowed() { + return cb.disjunction(); + } + + @Override + protected Predicate whenNationalLevel() { + return cb.conjunction(); + } + + @Override + protected Predicate whenRegionalLevel() { + return cb.equal(joins.getRoot().get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_REGION).get(Region.ID), user.getRegion().getId()); + } + + @Override + protected Predicate whenDistrictLevel() { + return cb.equal(joins.getRoot().get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_DISTRICT).get(District.ID), user.getDistrict().getId()); + } + + @Override + protected Predicate whenCommunityLevel() { + return cb + .equal(joins.getRoot().get(Aefi.IMMUNIZATION).get(Immunization.RESPONSIBLE_COMMUNITY).get(Community.ID), user.getCommunity().getId()); + } + + @Override + protected Predicate whenFacilityLevel() { + return cb.equal(joins.getRoot().get(Aefi.IMMUNIZATION).get(Immunization.HEALTH_FACILITY).get(Facility.ID), user.getHealthFacility().getId()); + } + + @Override + protected Predicate whenPointOfEntryLevel() { + return cb.disjunction(); + } + + @Override + protected Predicate whenLaboratoryLevel() { + return cb.disjunction(); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiQueryContext.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiQueryContext.java new file mode 100644 index 00000000000..fa7ec727d58 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiQueryContext.java @@ -0,0 +1,45 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; + +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiJoins; +import de.symeda.sormas.backend.common.QueryContext; + +public class AefiQueryContext extends QueryContext { + + public AefiQueryContext(CriteriaBuilder cb, CriteriaQuery query, From root) { + super(cb, query, root, new AefiJoins(root)); + } + + public AefiQueryContext(CriteriaBuilder cb, CriteriaQuery query, AefiJoins joins) { + super(cb, query, joins.getRoot(), joins); + } + + public AefiQueryContext(CriteriaBuilder cb, CriteriaQuery query, From root, AefiJoins joins) { + super(cb, query, root, joins); + } + + @Override + protected Expression createExpression(String name) { + return null; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiService.java new file mode 100644 index 00000000000..62736e5f1b5 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/AefiService.java @@ -0,0 +1,681 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization; + +import static de.symeda.sormas.backend.common.CriteriaBuilderHelper.andEquals; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.persistence.Tuple; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.ParameterExpression; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Selection; +import javax.validation.constraints.NotNull; + +import org.apache.commons.collections4.CollectionUtils; + +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDateType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiExportDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.feature.FeatureTypeProperty; +import de.symeda.sormas.api.person.PersonIndexDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.SortProperty; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AdverseEvents; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiJoins; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers.AefiIndexDtoResultTransformer; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers.AefiListEntryDtoResultTransformer; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.country.Country; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.person.Person; +import de.symeda.sormas.backend.person.PersonJoins; +import de.symeda.sormas.backend.person.PersonJurisdictionPredicateValidator; +import de.symeda.sormas.backend.person.PersonQueryContext; +import de.symeda.sormas.backend.person.PersonService; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.IterableHelper; +import de.symeda.sormas.backend.util.JurisdictionHelper; +import de.symeda.sormas.backend.util.ModelConstants; +import de.symeda.sormas.backend.util.QueryHelper; +import de.symeda.sormas.backend.vaccination.Vaccination; + +@Stateless +@LocalBean +public class AefiService extends AbstractCoreAdoService { + + @EJB + private PersonService personService; + @EJB + private UserService userService; + @EJB + private FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; + + public AefiService() { + super(Aefi.class, DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION); + } + + public Long getIdByUuid(@NotNull String uuid) { + + if (uuid == null) { + return null; + } + + CriteriaBuilder cb = em.getCriteriaBuilder(); + ParameterExpression uuidParam = cb.parameter(String.class, AbstractDomainObject.UUID); + CriteriaQuery cq = cb.createQuery(Long.class); + Root from = cq.from(Aefi.class); + cq.select(from.get(AbstractDomainObject.ID)); + cq.where(cb.equal(from.get(AbstractDomainObject.UUID), uuidParam)); + + TypedQuery q = em.createQuery(cq).setParameter(uuidParam, uuid); + + return q.getResultList().stream().findFirst().orElse(null); + } + + public List getEntriesList(Long immunizationId, Integer first, Integer max) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Tuple.class); + final Root aefi = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefi); + AefiJoins joins = aefiQueryContext.getJoins(); + + Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + Join adverseEvents = joins.getAdverseEvents(); + + cq.multiselect( + aefi.get(Aefi.UUID), + aefi.get(Aefi.SERIOUS), + primarySuspectVaccine.get(Vaccination.VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.VACCINE_DOSE), + primarySuspectVaccine.get(Vaccination.VACCINATION_DATE), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT), + adverseEvents.get(AdverseEvents.SEIZURES), + adverseEvents.get(AdverseEvents.SEIZURE_TYPE), + adverseEvents.get(AdverseEvents.ABSCESS), + adverseEvents.get(AdverseEvents.SEPSIS), + adverseEvents.get(AdverseEvents.ENCEPHALOPATHY), + adverseEvents.get(AdverseEvents.TOXIC_SHOCK_SYNDROME), + adverseEvents.get(AdverseEvents.THROMBOCYTOPENIA), + adverseEvents.get(AdverseEvents.ANAPHYLAXIS), + adverseEvents.get(AdverseEvents.FEVERISH_FEELING), + adverseEvents.get(AdverseEvents.OTHER_ADVERSE_EVENT_DETAILS), + aefi.get(Aefi.CHANGE_DATE), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(aefiQueryContext))); + + final Predicate criteriaFilter = buildCriteriaFilter(immunizationId, aefiQueryContext); + if (criteriaFilter != null) { + cq.where(criteriaFilter); + } + + cq.orderBy(cb.desc(aefi.get(Aefi.CHANGE_DATE))); + + cq.distinct(true); + + return QueryHelper.getResultList(em, cq, new AefiListEntryDtoResultTransformer(), first, max); + } + + private Predicate buildCriteriaFilter(Long immunizationId, AefiQueryContext aefiQueryContext) { + + final CriteriaBuilder cb = aefiQueryContext.getCriteriaBuilder(); + final From from = aefiQueryContext.getRoot(); + + Predicate filter = cb.equal(from.get(Aefi.IMMUNIZATION_ID), immunizationId); + + filter = CriteriaBuilderHelper.and(cb, filter, cb.isFalse(from.get(Aefi.DELETED))); + + return filter; + } + + public long count(AefiCriteria criteria) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Long.class); + final Root aefi = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefi); + + buildWhereCondition(criteria, cb, cq, aefiQueryContext, null); + + cq.select(cb.countDistinct(aefi)); + return em.createQuery(cq).getSingleResult(); + } + + public List getIndexList(AefiCriteria criteria, Integer first, Integer max, List sortProperties) { + + List indexListIds = getIndexListIds(criteria, first, max, sortProperties); + List aefiIndexDtos = new ArrayList<>(); + + IterableHelper.executeBatched(indexListIds, ModelConstants.PARAMETER_LIMIT, batchedIds -> { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Tuple.class); + final Root aefi = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefi); + AefiJoins joins = aefiQueryContext.getJoins(); + + final Join immunization = joins.getImmunization(); + final Join person = joins.getImmunizationJoins().getPerson(); + + final Join responsibleRegion = joins.getImmunizationJoins().getResponsibleRegion(); + final Join responsibleDistrict = joins.getImmunizationJoins().getResponsibleDistrict(); + + final Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + final Join adverseEvents = joins.getAdverseEvents(); + + cq.multiselect( + Stream + .concat( + Stream.of( + aefi.get(Aefi.UUID), + immunization.get(Immunization.UUID), + immunization.get(Immunization.DISEASE), + person.get(Person.UUID), + person.get(Person.FIRST_NAME), + person.get(Person.LAST_NAME), + person.get(Person.APPROXIMATE_AGE), + person.get(Person.APPROXIMATE_AGE_TYPE), + person.get(Person.BIRTHDATE_DD), + person.get(Person.BIRTHDATE_MM), + person.get(Person.BIRTHDATE_YYYY), + person.get(Person.SEX), + responsibleRegion.get(Region.NAME), + responsibleDistrict.get(District.NAME), + aefi.get(Aefi.SERIOUS), + primarySuspectVaccine.get(Vaccination.VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.OTHER_VACCINE_NAME), + aefi.get(Aefi.OUTCOME), + primarySuspectVaccine.get(Vaccination.VACCINATION_DATE), + aefi.get(Aefi.REPORT_DATE), + aefi.get(Aefi.START_DATE_TIME), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT), + adverseEvents.get(AdverseEvents.SEIZURES), + adverseEvents.get(AdverseEvents.SEIZURE_TYPE), + adverseEvents.get(AdverseEvents.ABSCESS), + adverseEvents.get(AdverseEvents.SEPSIS), + adverseEvents.get(AdverseEvents.ENCEPHALOPATHY), + adverseEvents.get(AdverseEvents.TOXIC_SHOCK_SYNDROME), + adverseEvents.get(AdverseEvents.THROMBOCYTOPENIA), + adverseEvents.get(AdverseEvents.ANAPHYLAXIS), + adverseEvents.get(AdverseEvents.FEVERISH_FEELING), + adverseEvents.get(AdverseEvents.OTHER_ADVERSE_EVENT_DETAILS), + aefi.get(Aefi.DELETION_REASON), + aefi.get(Aefi.OTHER_DELETION_REASON), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(aefiQueryContext)), + aefi.get(Aefi.CHANGE_DATE)), + // add sort properties to select + sortBy(sortProperties, aefiQueryContext).stream()) + .collect(Collectors.toList())); + + buildWhereCondition(criteria, cb, cq, aefiQueryContext, aefi.get(Aefi.ID).in(batchedIds)); + cq.distinct(true); + + aefiIndexDtos.addAll(QueryHelper.getResultList(em, cq, new AefiIndexDtoResultTransformer(), null, null)); + }); + + return aefiIndexDtos; + } + + private List getIndexListIds(AefiCriteria criteria, Integer first, Integer max, List sortProperties) { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createTupleQuery(); + final Root aefi = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefi); + + List> selections = new ArrayList<>(); + selections.add(aefi.get(Aefi.ID)); + selections.addAll(sortBy(sortProperties, aefiQueryContext)); + + cq.multiselect(selections); + + buildWhereCondition(criteria, cb, cq, aefiQueryContext, null); + cq.distinct(true); + + List aefiResultList = QueryHelper.getResultList(em, cq, first, max); + return aefiResultList.stream().map(t -> t.get(0, Long.class)).collect(Collectors.toList()); + } + + public List getExportList(AefiCriteria criteria, Collection selectedRows, int first, int max) { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(AefiExportDto.class); + final Root aefi = cq.from(Aefi.class); + + final AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefi); + AefiJoins joins = aefiQueryContext.getJoins(); + + final Join immunization = joins.getImmunization(); + final Join person = joins.getImmunizationJoins().getPerson(); + final Join immunizationFacility = joins.getImmunizationJoins().getHealthFacility(); + final Join immunizationFacilityRegion = immunizationFacility.join(Facility.REGION, JoinType.LEFT); + final Join immunizationFacilityDistrict = immunizationFacility.join(Facility.DISTRICT, JoinType.LEFT); + final Join immunizationFacilityCommunity = immunizationFacility.join(Facility.COMMUNITY, JoinType.LEFT); + + final Join personLocation = person.join(Person.ADDRESS, JoinType.LEFT); + final Join personLocationRegion = personLocation.join(Location.REGION, JoinType.LEFT); + final Join personLocationDistrict = personLocation.join(Location.DISTRICT, JoinType.LEFT); + final Join personLocationCommunity = personLocation.join(Location.COMMUNITY, JoinType.LEFT); + + final Join responsibleRegion = joins.getImmunizationJoins().getResponsibleRegion(); + final Join responsibleDistrict = joins.getImmunizationJoins().getResponsibleDistrict(); + + final Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + final Join adverseEvents = joins.getAdverseEvents(); + + final Join reportingUser = joins.getReportingUser(); + final Join reportingUserLocation = reportingUser.join(User.ADDRESS, JoinType.LEFT); + final Join reportingUserLocationCountry = reportingUserLocation.join(Location.COUNTRY, JoinType.LEFT); + final Join reportingUserFacility = reportingUser.join(User.HEALTH_FACILITY, JoinType.LEFT); + final Join reportingUserFacilityRegion = reportingUserFacility.join(Facility.REGION, JoinType.LEFT); + final Join reportingUserFacilityDistrict = reportingUserFacility.join(Facility.DISTRICT, JoinType.LEFT); + final Join reportingUserFacilityCommunity = reportingUserFacility.join(Facility.COMMUNITY, JoinType.LEFT); + + cq.multiselect( + aefi.get(Aefi.UUID), + aefi.get(Aefi.RECEIVED_AT_NATIONAL_LEVEL_DATE), + immunizationFacility.get(Facility.NAME), + immunizationFacilityRegion.get(Region.NAME), + immunizationFacilityDistrict.get(District.NAME), + immunizationFacilityCommunity.get(Community.NAME), + reportingUserLocationCountry.get(Country.DEFAULT_NAME), + personLocationRegion.get(Region.NAME), + personLocationDistrict.get(District.NAME), + personLocationCommunity.get(Community.NAME), + personLocation.get(Location.STREET), + personLocation.get(Location.HOUSE_NUMBER), + personLocation.get(Location.POSTAL_CODE), + personLocation.get(Location.CITY), + aefi.get(Aefi.REPORTINGID_NUMBER), + aefi.get(Aefi.WORLD_WIDE_ID), + person.get(Person.FIRST_NAME), + person.get(Person.LAST_NAME), + person.get(Person.BIRTHDATE_DD), + person.get(Person.BIRTHDATE_MM), + person.get(Person.BIRTHDATE_YYYY), + aefi.get(Aefi.ONSET_AGE_YEARS), + aefi.get(Aefi.ONSET_AGE_MONTHS), + aefi.get(Aefi.ONSET_AGE_DAYS), + aefi.get(Aefi.AGE_GROUP), + person.get(Person.SEX), + aefi.get(Aefi.AEFI_DESCRIPTION), + primarySuspectVaccine.get(Vaccination.VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.OTHER_VACCINE_NAME), + primarySuspectVaccine.get(Vaccination.VACCINE_MANUFACTURER), + primarySuspectVaccine.get(Vaccination.VACCINE_BATCH_NUMBER), + primarySuspectVaccine.get(Vaccination.VACCINE_DOSE), + primarySuspectVaccine.get(Vaccination.VACCINATION_DATE), + aefi.get(Aefi.START_DATE_TIME), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS), + adverseEvents.get(AdverseEvents.SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT), + adverseEvents.get(AdverseEvents.SEIZURES), + adverseEvents.get(AdverseEvents.SEIZURE_TYPE), + adverseEvents.get(AdverseEvents.ABSCESS), + adverseEvents.get(AdverseEvents.SEPSIS), + adverseEvents.get(AdverseEvents.ENCEPHALOPATHY), + adverseEvents.get(AdverseEvents.TOXIC_SHOCK_SYNDROME), + adverseEvents.get(AdverseEvents.THROMBOCYTOPENIA), + adverseEvents.get(AdverseEvents.ANAPHYLAXIS), + adverseEvents.get(AdverseEvents.FEVERISH_FEELING), + adverseEvents.get(AdverseEvents.OTHER_ADVERSE_EVENT_DETAILS), + aefi.get(Aefi.OUTCOME), + aefi.get(Aefi.SERIOUS), + reportingUser.get(User.FIRST_NAME), + reportingUser.get(User.LAST_NAME), + reportingUserFacility.get(Facility.NAME), + reportingUserFacilityRegion.get(Region.NAME), + reportingUserFacilityDistrict.get(District.NAME), + reportingUserFacilityCommunity.get(Community.NAME), + reportingUser.get(User.USER_EMAIL), + reportingUser.get(User.PHONE), + aefi.get((Aefi.REPORT_DATE)), + aefi.get((Aefi.NATIONAL_LEVEL_COMMENT)), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(aefiQueryContext))); + + /* + * buildWhereCondition(criteria, cb, cq, aefiQueryContext, null); + * cq.distinct(true); + */ + + Predicate filter = buildExportListWhereCondition(criteria, cb, cq, aefiQueryContext); + if (selectedRows != null && !selectedRows.isEmpty()) { + filter = CriteriaBuilderHelper.andInValues(selectedRows, filter, cb, aefi.get(Aefi.UUID)); + } + + if (filter != null) { + cq.where(filter); + } + cq.distinct(true); + + return QueryHelper.getResultList(em, cq, first, max); + } + + private List> sortBy(List sortProperties, AefiQueryContext aefiQueryContext) { + + List> selections = new ArrayList<>(); + CriteriaBuilder cb = aefiQueryContext.getCriteriaBuilder(); + CriteriaQuery cq = aefiQueryContext.getQuery(); + + if (CollectionUtils.isNotEmpty(sortProperties)) { + List order = new ArrayList<>(sortProperties.size()); + for (SortProperty sortProperty : sortProperties) { + Expression expression; + switch (sortProperty.propertyName) { + case AefiIndexDto.UUID: + case AefiIndexDto.DISEASE: + case AefiIndexDto.START_DATE_TIME: + expression = aefiQueryContext.getRoot().get(sortProperty.propertyName); + break; + case AefiIndexDto.PERSON_UUID: + expression = aefiQueryContext.getJoins().getImmunizationJoins().getPerson().get(Person.UUID); + break; + case AefiIndexDto.PERSON_FIRST_NAME: + expression = cb.lower(aefiQueryContext.getJoins().getImmunizationJoins().getPerson().get(Person.FIRST_NAME)); + break; + case AefiIndexDto.PERSON_LAST_NAME: + expression = cb.lower(aefiQueryContext.getJoins().getImmunizationJoins().getPerson().get(Person.LAST_NAME)); + break; + case AefiIndexDto.AGE_AND_BIRTH_DATE: + expression = aefiQueryContext.getJoins().getImmunizationJoins().getPerson().get(Person.APPROXIMATE_AGE); + break; + case AefiIndexDto.SEX: + expression = aefiQueryContext.getJoins().getImmunizationJoins().getPerson().get(Person.SEX); + break; + case AefiIndexDto.REGION: + expression = + cb.lower(aefiQueryContext.getJoins().getImmunizationJoins().getPersonJoins().getAddressJoins().getRegion().get(Region.NAME)); + break; + case AefiIndexDto.DISTRICT: + expression = cb.lower( + aefiQueryContext.getJoins().getImmunizationJoins().getPersonJoins().getAddressJoins().getDistrict().get(District.NAME)); + break; + case AefiIndexDto.PRIMARY_VACCINE_NAME: + expression = aefiQueryContext.getJoins().getPrimarySuspectVaccination().get(Vaccination.VACCINE_NAME); + break; + case AefiIndexDto.VACCINATION_DATE: + expression = aefiQueryContext.getJoins().getPrimarySuspectVaccination().get(Vaccination.VACCINATION_DATE); + break; + case AefiIndexDto.SERIOUS: + expression = aefiQueryContext.getRoot().get(Aefi.SERIOUS); + break; + case AefiIndexDto.OUTCOME: + expression = aefiQueryContext.getRoot().get(Aefi.OUTCOME); + break; + default: + throw new IllegalArgumentException(sortProperty.propertyName); + } + order.add(sortProperty.ascending ? cb.asc(expression) : cb.desc(expression)); + selections.add(expression); + } + cq.orderBy(order); + } else { + Path changeDate = aefiQueryContext.getRoot().get(Aefi.CHANGE_DATE); + cq.orderBy(cb.desc(changeDate)); + selections.add(changeDate); + } + + return selections; + } + + private void buildWhereCondition( + AefiCriteria criteria, + CriteriaBuilder cb, + CriteriaQuery cq, + AefiQueryContext aefiQueryContext, + Predicate additionalFilter) { + + Predicate filter = createUserFilter(aefiQueryContext); + if (additionalFilter != null) { + filter = CriteriaBuilderHelper.and(cb, additionalFilter, filter); + } + + if (criteria != null) { + final Predicate criteriaFilter = buildCriteriaFilter(criteria, aefiQueryContext); + filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); + } + + if (filter != null) { + cq.where(filter); + } + } + + private Predicate buildExportListWhereCondition( + AefiCriteria criteria, + CriteriaBuilder cb, + CriteriaQuery cq, + AefiQueryContext aefiQueryContext) { + + Predicate filter = createUserFilter(aefiQueryContext); + + if (criteria != null) { + final Predicate criteriaFilter = buildCriteriaFilter(criteria, aefiQueryContext); + filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); + } + + return filter; + } + + public Predicate buildCriteriaFilter(AefiCriteria criteria, AefiQueryContext aefiQueryContext) { + + final AefiJoins joins = aefiQueryContext.getJoins(); + final CriteriaBuilder cb = aefiQueryContext.getCriteriaBuilder(); + final From from = aefiQueryContext.getRoot(); + final Join immunization = joins.getImmunization(); + final Join person = joins.getImmunizationJoins().getPerson(); + final Join primarySuspectVaccine = joins.getPrimarySuspectVaccination(); + + final Join location = joins.getImmunizationJoins().getPersonJoins().getAddress(); + + Predicate filter = null; + if (criteria.getDisease() != null) { + filter = CriteriaBuilderHelper.and(cb, null, cb.equal(immunization.get(Immunization.DISEASE), criteria.getDisease())); + } + + if (!DataHelper.isNullOrEmpty(criteria.getPersonLike())) { + final CriteriaQuery cq = cb.createQuery(PersonIndexDto.class); + final PersonQueryContext personQueryContext = new PersonQueryContext(cb, cq, joins.getImmunizationJoins().getPersonJoins()); + + String[] textFilters = criteria.getPersonLike().split("\\s+"); + + for (String textFilter : textFilters) { + if (DataHelper.isNullOrEmpty(textFilter)) { + continue; + } + + Predicate likeFilters = cb.or( + CriteriaBuilderHelper.ilike(cb, from.get(Aefi.UUID), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, person.get(Person.FIRST_NAME), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, person.get(Person.LAST_NAME), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.UUID), textFilter), + CriteriaBuilderHelper.ilike(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_EMAIL_SUBQUERY), textFilter), + phoneNumberPredicate(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_PHONE_SUBQUERY), textFilter), + CriteriaBuilderHelper + .ilike(cb, personQueryContext.getSubqueryExpression(PersonQueryContext.PERSON_PRIMARY_OTHER_SUBQUERY), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, location.get(Location.STREET), textFilter), + CriteriaBuilderHelper.unaccentedIlike(cb, location.get(Location.CITY), textFilter), + CriteriaBuilderHelper.ilike(cb, location.get(Location.POSTAL_CODE), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.INTERNAL_TOKEN), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.EXTERNAL_ID), textFilter), + CriteriaBuilderHelper.ilike(cb, person.get(Person.EXTERNAL_TOKEN), textFilter)); + filter = CriteriaBuilderHelper.and(cb, filter, likeFilters); + } + } + if (criteria.getAefiType() != null) { + if (criteria.getAefiType() == AefiType.SERIOUS) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Aefi.SERIOUS), YesNoUnknown.YES)); + } else { + filter = CriteriaBuilderHelper.and(cb, filter, cb.notEqual(from.get(Aefi.SERIOUS), YesNoUnknown.YES)); + } + } + if (criteria.getOutcome() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Aefi.OUTCOME), criteria.getOutcome())); + } + if (criteria.getVaccineName() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(primarySuspectVaccine.get(Vaccination.VACCINE_NAME), criteria.getVaccineName())); + } + if (criteria.getVaccineManufacturer() != null) { + filter = CriteriaBuilderHelper + .and(cb, filter, cb.equal(primarySuspectVaccine.get(Vaccination.VACCINE_MANUFACTURER), criteria.getVaccineManufacturer())); + } + filter = andEquals(cb, () -> joins.getImmunizationJoins().getResponsibleRegion(), filter, criteria.getRegion()); + filter = andEquals(cb, () -> joins.getImmunizationJoins().getResponsibleDistrict(), filter, criteria.getDistrict()); + filter = andEquals(cb, () -> joins.getImmunizationJoins().getResponsibleCommunity(), filter, criteria.getCommunity()); + if (criteria.getFacilityType() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(immunization.get(Immunization.FACILITY_TYPE), criteria.getFacilityType())); + } + filter = andEquals(cb, () -> joins.getImmunizationJoins().getHealthFacility(), filter, criteria.getHealthFacility()); + if (criteria.getAefiDateType() != null) { + Path path = buildPathForDateFilter(criteria.getAefiDateType(), aefiQueryContext); + if (path != null) { + filter = CriteriaBuilderHelper.applyDateFilter(cb, filter, path, criteria.getFromDate(), criteria.getToDate()); + } + } + + if (criteria.getRelevanceStatus() != null) { + if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(from.get(Aefi.ARCHIVED), false), cb.isNull(from.get(Aefi.ARCHIVED)))); + } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Aefi.ARCHIVED), true)); + } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.DELETED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Aefi.DELETED), true)); + } + } + if (criteria.getRelevanceStatus() != EntityRelevanceStatus.DELETED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.isFalse(from.get(Aefi.DELETED))); + } + + return filter; + } + + private Path buildPathForDateFilter(AefiDateType aefiDateType, AefiQueryContext aefiQueryContext) { + Path path = null; + String dateField = getDateFieldFromDateType(aefiDateType); + if (dateField != null) { + if (Vaccination.VACCINATION_DATE.equals(dateField)) { + final Join primarySuspectVaccination = aefiQueryContext.getJoins().getPrimarySuspectVaccination(); + path = primarySuspectVaccination.get(Vaccination.VACCINATION_DATE); + } else { + path = aefiQueryContext.getRoot().get(dateField); + } + } + return path; + } + + private String getDateFieldFromDateType(AefiDateType aefiDateType) { + switch (aefiDateType) { + case REPORT_DATE: + return Aefi.REPORT_DATE; + case START_DATE: + return Aefi.START_DATE_TIME; + case VACCINATION_DATE: + return Vaccination.VACCINATION_DATE; + } + return null; + } + + public Predicate createUserFilter(AefiQueryContext qc) { + + User currentUser = getCurrentUser(); + if (currentUser == null) { + return null; + } + final CriteriaBuilder cb = qc.getCriteriaBuilder(); + + Predicate filter = isInJurisdictionOrOwned(qc); + + filter = CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, qc.getRoot().get(Aefi.IMMUNIZATION).get(Immunization.DISEASE))); + + return filter; + } + + private Predicate isInJurisdictionOrOwned(AefiQueryContext qc) { + + final User currentUser = userService.getCurrentUser(); + CriteriaBuilder cb = qc.getCriteriaBuilder(); + Predicate filter; + if (!featureConfigurationFacade + .isPropertyValueTrue(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) { + filter = AefiJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); + } else { + filter = CriteriaBuilderHelper.or( + cb, + cb.equal(qc.getRoot().get(Aefi.REPORTING_USER), currentUser), + PersonJurisdictionPredicateValidator + .of(qc.getQuery(), cb, new PersonJoins(qc.getJoins().getPerson()), currentUser, personService.getPermittedAssociations()) + .inJurisdictionOrOwned()); + } + return filter; + } + + @Override + protected Predicate createUserFilterInternal(CriteriaBuilder cb, CriteriaQuery cq, From from) { + return createUserFilter(new AefiQueryContext(cb, cq, from)); + } + + @Override + protected AefiJoins toJoins(From adoPath) { + return new AefiJoins(adoPath); + } + + @Override + public Predicate inJurisdictionOrOwned(CriteriaBuilder cb, CriteriaQuery query, From from) { + return isInJurisdictionOrOwned(new AefiQueryContext(cb, query, from)); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AdverseEvents.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AdverseEvents.java new file mode 100644 index 00000000000..2513cb06548 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AdverseEvents.java @@ -0,0 +1,179 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity; + +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeizureType; +import de.symeda.sormas.backend.common.AbstractDomainObject; + +@Entity +@Table(name = "adverseevents") +public class AdverseEvents extends AbstractDomainObject { + + private static final long serialVersionUID = 5407524640930885029L; + + public static final String TABLE_NAME = "adverseevents"; + + public static final String SEVERE_LOCAL_REACTION = "severeLocalReaction"; + public static final String SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS = "severeLocalReactionMoreThanThreeDays"; + public static final String SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT = "severeLocalReactionBeyondNearestJoint"; + public static final String SEIZURES = "seizures"; + public static final String SEIZURE_TYPE = "seizureType"; + public static final String ABSCESS = "abscess"; + public static final String SEPSIS = "sepsis"; + public static final String ENCEPHALOPATHY = "encephalopathy"; + public static final String TOXIC_SHOCK_SYNDROME = "toxicShockSyndrome"; + public static final String THROMBOCYTOPENIA = "thrombocytopenia"; + public static final String ANAPHYLAXIS = "anaphylaxis"; + public static final String FEVERISH_FEELING = "feverishFeeling"; + public static final String OTHER_ADVERSE_EVENT_DETAILS = "otherAdverseEventDetails"; + + private AdverseEventState severeLocalReaction; + private boolean severeLocalReactionMoreThanThreeDays; + private boolean severeLocalReactionBeyondNearestJoint; + private AdverseEventState seizures; + private SeizureType seizureType; + private AdverseEventState abscess; + private AdverseEventState sepsis; + private AdverseEventState encephalopathy; + private AdverseEventState toxicShockSyndrome; + private AdverseEventState thrombocytopenia; + private AdverseEventState anaphylaxis; + private AdverseEventState feverishFeeling; + private String otherAdverseEventDetails; + + @Enumerated(EnumType.STRING) + public AdverseEventState getSevereLocalReaction() { + return severeLocalReaction; + } + + public void setSevereLocalReaction(AdverseEventState severeLocalReaction) { + this.severeLocalReaction = severeLocalReaction; + } + + public boolean isSevereLocalReactionMoreThanThreeDays() { + return severeLocalReactionMoreThanThreeDays; + } + + public void setSevereLocalReactionMoreThanThreeDays(boolean severeLocalReactionMoreThanThreeDays) { + this.severeLocalReactionMoreThanThreeDays = severeLocalReactionMoreThanThreeDays; + } + + public boolean isSevereLocalReactionBeyondNearestJoint() { + return severeLocalReactionBeyondNearestJoint; + } + + public void setSevereLocalReactionBeyondNearestJoint(boolean severeLocalReactionBeyondNearestJoint) { + this.severeLocalReactionBeyondNearestJoint = severeLocalReactionBeyondNearestJoint; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getSeizures() { + return seizures; + } + + public void setSeizures(AdverseEventState seizures) { + this.seizures = seizures; + } + + @Enumerated(EnumType.STRING) + public SeizureType getSeizureType() { + return seizureType; + } + + public void setSeizureType(SeizureType seizureType) { + this.seizureType = seizureType; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getAbscess() { + return abscess; + } + + public void setAbscess(AdverseEventState abscess) { + this.abscess = abscess; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getSepsis() { + return sepsis; + } + + public void setSepsis(AdverseEventState sepsis) { + this.sepsis = sepsis; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getEncephalopathy() { + return encephalopathy; + } + + public void setEncephalopathy(AdverseEventState encephalopathy) { + this.encephalopathy = encephalopathy; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getToxicShockSyndrome() { + return toxicShockSyndrome; + } + + public void setToxicShockSyndrome(AdverseEventState toxicShockSyndrome) { + this.toxicShockSyndrome = toxicShockSyndrome; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getThrombocytopenia() { + return thrombocytopenia; + } + + public void setThrombocytopenia(AdverseEventState thrombocytopenia) { + this.thrombocytopenia = thrombocytopenia; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getAnaphylaxis() { + return anaphylaxis; + } + + public void setAnaphylaxis(AdverseEventState anaphylaxis) { + this.anaphylaxis = anaphylaxis; + } + + @Enumerated(EnumType.STRING) + public AdverseEventState getFeverishFeeling() { + return feverishFeeling; + } + + public void setFeverishFeeling(AdverseEventState feverishFeeling) { + this.feverishFeeling = feverishFeeling; + } + + public String getOtherAdverseEventDetails() { + return otherAdverseEventDetails; + } + + public void setOtherAdverseEventDetails(String otherAdverseEventDetails) { + this.otherAdverseEventDetails = otherAdverseEventDetails; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/Aefi.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/Aefi.java new file mode 100644 index 00000000000..63df6410c97 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/Aefi.java @@ -0,0 +1,611 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity; + +import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_DEFAULT; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiAgeGroup; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiOutcome; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeriousAefiReason; +import de.symeda.sormas.api.caze.Trimester; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.country.Country; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.person.Person; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.vaccination.Vaccination; + +@Entity(name = "adverseeventsfollowingimmunization") +public class Aefi extends CoreAdo { + + private static final long serialVersionUID = -7845660472641846292L; + + public static final String TABLE_NAME = "adverseeventsfollowingimmunization"; + public static final String AEFI_VACCINATIONS_TABLE_NAME = "adverseeventsfollowingimmunization_vaccinations"; + + public static final String IMMUNIZATION = "immunization"; + public static final String IMMUNIZATION_ID = "immunizationId"; + public static final String ADDRESS = "address"; + public static final String VACCINATIONS = "vaccinations"; + public static final String PRIMARY_SUSPECT_VACCINE = "primarySuspectVaccine"; + public static final String ADVERSE_EVENTS = "adverseEvents"; + public static final String PERSON = "person"; + public static final String PERSON_ID = "personId"; + public static final String REPORT_DATE = "reportDate"; + public static final String REPORTING_USER = "reportingUser"; + public static final String EXTERNAL_ID = "externalId"; + public static final String RESPONSIBLE_REGION = "responsibleRegion"; + public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict"; + public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity"; + public static final String COUNTRY = "country"; + public static final String REPORTINGID_NUMBER = "reportingIdNumber"; + public static final String PREGNANT = "pregnant"; + public static final String PHONE_NUMBER = "phoneNumber"; + public static final String TRIMESTER = "trimester"; + public static final String LACTATING = "lactating"; + public static final String ONSET_AGE_YEARS = "onsetAgeYears"; + public static final String ONSET_AGE_MONTHS = "onsetAgeMonths"; + public static final String ONSET_AGE_DAYS = "onsetAgeDays"; + public static final String AGE_GROUP = "ageGroup"; + public static final String HEALTH_FACILITY = "healthFacility"; + public static final String HEALTH_FACILITY_DETAILS = "healthFacilityDetails"; + public static final String REPORTING_OFFICER_NAME = "reportingOfficerName"; + public static final String REPORTING_OFFICER_FACILITY = "reportingOfficerFacility"; + public static final String REPORTING_OFFICER_DESIGNATION = "reportingOfficerDesignation"; + public static final String REPORTING_OFFICER_DEPARTMENT = "reportingOfficerDepartment"; + public static final String REPORTING_OFFICER_ADDRESS = "reportingOfficerAddress"; + public static final String REPORTING_OFFICER_PHONE_NUMBER = "reportingOfficerPhoneNumber"; + public static final String REPORTING_OFFICER_EMAIL = "reportingOfficerEmail"; + public static final String TODAYS_DATE = "todaysDate"; + public static final String START_DATE_TIME = "startDateTime"; + public static final String AEFI_DESCRIPTION = "aefiDescription"; + public static final String SERIOUS = "serious"; + public static final String SERIOUS_REASON = "seriousReason"; + public static final String SERIOUS_REASON_DETAILS = "seriousReasonDetails"; + public static final String OUTCOME = "outcome"; + public static final String DEATH_DATE = "deathDate"; + public static final String AUTOPSY_DONE = "autopsyDone"; + public static final String PAST_MEDICAL_HISTORY = "pastMedicalHistory"; + public static final String INVESTIGATION_NEEDED = "investigationNeeded"; + public static final String INVESTIGATION_PLANNED_DATE = "investigationPlannedDate"; + public static final String RECEIVED_AT_NATIONAL_LEVEL_DATE = "receivedAtNationalLevelDate"; + public static final String WORLD_WIDE_ID = "worldwideId"; + public static final String NATIONAL_LEVEL_COMMENT = "nationalLevelComment"; + + private Immunization immunization; + private Long immunizationId; + private Person person; + private Long personId; + private Location address; + private Set vaccinations = new HashSet<>(); + private Vaccination primarySuspectVaccine; + private AdverseEvents adverseEvents; + private Date reportDate; + private User reportingUser; + private String externalId; + private Region responsibleRegion; + private District responsibleDistrict; + private Community responsibleCommunity; + private Country country; + private String reportingIdNumber; + private String phoneNumber; + private YesNoUnknown pregnant; + private Trimester trimester; + private YesNoUnknown lactating; + private Integer onsetAgeYears; + private Integer onsetAgeMonths; + private Integer onsetAgeDays; + private AefiAgeGroup ageGroup; + private Facility healthFacility; + private String healthFacilityDetails; + private String reportingOfficerName; + private Facility reportingOfficerFacility; + private String reportingOfficerDesignation; + private String reportingOfficerDepartment; + private Location reportingOfficerAddress; + private String reportingOfficerPhoneNumber; + private String reportingOfficerEmail; + private Date todaysDate; + private Date startDateTime; + private String aefiDescription; + private YesNoUnknown serious; + private SeriousAefiReason seriousReason; + private String seriousReasonDetails; + private AefiOutcome outcome; + private Date deathDate; + private YesNoUnknown autopsyDone; + private String pastMedicalHistory; + private YesNoUnknown investigationNeeded; + private Date investigationPlannedDate; + private Date receivedAtNationalLevelDate; + private String worldwideId; + private String nationalLevelComment; + + public static Aefi build() { + Aefi aefi = new Aefi(); + return aefi; + } + + @ManyToOne + @JoinColumn(nullable = false) + public Immunization getImmunization() { + return immunization; + } + + public void setImmunization(Immunization immunization) { + this.immunization = immunization; + } + + @Column(name = "immunization_id", updatable = false, insertable = false) + public Long getImmunizationId() { + return immunizationId; + } + + public void setImmunizationId(Long immunizationId) { + this.immunizationId = immunizationId; + } + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = AEFI_VACCINATIONS_TABLE_NAME, + joinColumns = @JoinColumn(name = "adverseeventsfollowingimmunization_id"), + inverseJoinColumns = @JoinColumn(name = "vaccination_id")) + public Set getVaccinations() { + return vaccinations; + } + + public void setVaccinations(Set vaccinations) { + this.vaccinations = vaccinations; + } + + @OneToOne + public Vaccination getPrimarySuspectVaccine() { + return primarySuspectVaccine; + } + + public void setPrimarySuspectVaccine(Vaccination primarySuspectVaccine) { + this.primarySuspectVaccine = primarySuspectVaccine; + } + + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinColumn(nullable = false) + //@ManyToOne + public AdverseEvents getAdverseEvents() { + return adverseEvents; + } + + public void setAdverseEvents(AdverseEvents adverseEvents) { + this.adverseEvents = adverseEvents; + } + + @ManyToOne + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + @Column(name = "person_id", updatable = false, insertable = false) + public Long getPersonId() { + return personId; + } + + public void setPersonId(Long personId) { + this.personId = personId; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + public Location getAddress() { + if (address == null) { + address = new Location(); + } + return address; + } + + public void setAddress(Location address) { + this.address = address; + } + + @Temporal(TemporalType.TIMESTAMP) + @Column(nullable = false) + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(nullable = false) + public User getReportingUser() { + return reportingUser; + } + + public void setReportingUser(User reportingUser) { + this.reportingUser = reportingUser; + } + + @Column(length = CHARACTER_LIMIT_DEFAULT) + public String getExternalId() { + return externalId; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Region getResponsibleRegion() { + return responsibleRegion; + } + + public void setResponsibleRegion(Region responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + @ManyToOne(fetch = FetchType.LAZY) + public District getResponsibleDistrict() { + return responsibleDistrict; + } + + public void setResponsibleDistrict(District responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Community getResponsibleCommunity() { + return responsibleCommunity; + } + + public void setResponsibleCommunity(Community responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Country getCountry() { + return country; + } + + public void setCountry(Country country) { + this.country = country; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + @Column(length = CHARACTER_LIMIT_DEFAULT) + public String getReportingIdNumber() { + return reportingIdNumber; + } + + public void setReportingIdNumber(String reportingIdNumber) { + this.reportingIdNumber = reportingIdNumber; + } + + @Column + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getPregnant() { + return pregnant; + } + + public void setPregnant(YesNoUnknown pregnant) { + this.pregnant = pregnant; + } + + @Enumerated(EnumType.STRING) + public Trimester getTrimester() { + return trimester; + } + + public void setTrimester(Trimester trimester) { + this.trimester = trimester; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getLactating() { + return lactating; + } + + public void setLactating(YesNoUnknown lactating) { + this.lactating = lactating; + } + + @Column + public Integer getOnsetAgeYears() { + return onsetAgeYears; + } + + public void setOnsetAgeYears(Integer onsetAgeYears) { + this.onsetAgeYears = onsetAgeYears; + } + + @Column + public Integer getOnsetAgeMonths() { + return onsetAgeMonths; + } + + public void setOnsetAgeMonths(Integer onsetAgeMonths) { + this.onsetAgeMonths = onsetAgeMonths; + } + + @Column + public Integer getOnsetAgeDays() { + return onsetAgeDays; + } + + public void setOnsetAgeDays(Integer onsetAgeDays) { + this.onsetAgeDays = onsetAgeDays; + } + + @Enumerated(EnumType.STRING) + public AefiAgeGroup getAgeGroup() { + return ageGroup; + } + + public void setAgeGroup(AefiAgeGroup ageGroup) { + this.ageGroup = ageGroup; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Facility getHealthFacility() { + return healthFacility; + } + + public void setHealthFacility(Facility healthFacility) { + this.healthFacility = healthFacility; + } + + @Column(length = CHARACTER_LIMIT_DEFAULT) + public String getHealthFacilityDetails() { + return healthFacilityDetails; + } + + public void setHealthFacilityDetails(String healthFacilityDetails) { + this.healthFacilityDetails = healthFacilityDetails; + } + + @Column + public String getReportingOfficerName() { + return reportingOfficerName; + } + + public void setReportingOfficerName(String reporterName) { + this.reportingOfficerName = reporterName; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Facility getReportingOfficerFacility() { + return reportingOfficerFacility; + } + + public void setReportingOfficerFacility(Facility reporterInstitution) { + this.reportingOfficerFacility = reporterInstitution; + } + + @Column + public String getReportingOfficerDesignation() { + return reportingOfficerDesignation; + } + + public void setReportingOfficerDesignation(String reporterDesignation) { + this.reportingOfficerDesignation = reporterDesignation; + } + + @Column + public String getReportingOfficerDepartment() { + return reportingOfficerDepartment; + } + + public void setReportingOfficerDepartment(String reporterDepartment) { + this.reportingOfficerDepartment = reporterDepartment; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "reportingofficeraddress_id") + public Location getReportingOfficerAddress() { + return reportingOfficerAddress; + } + + public void setReportingOfficerAddress(Location reporterAddress) { + this.reportingOfficerAddress = reporterAddress; + } + + @Column + public String getReportingOfficerPhoneNumber() { + return reportingOfficerPhoneNumber; + } + + public void setReportingOfficerPhoneNumber(String reporterPhone) { + this.reportingOfficerPhoneNumber = reporterPhone; + } + + @Column + public String getReportingOfficerEmail() { + return reportingOfficerEmail; + } + + public void setReportingOfficerEmail(String reporterEmail) { + this.reportingOfficerEmail = reporterEmail; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getTodaysDate() { + return todaysDate; + } + + public void setTodaysDate(Date todaysDate) { + this.todaysDate = todaysDate; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getStartDateTime() { + return startDateTime; + } + + public void setStartDateTime(Date startDateTime) { + this.startDateTime = startDateTime; + } + + @Column(columnDefinition = "text") + public String getAefiDescription() { + return aefiDescription; + } + + public void setAefiDescription(String aefiDescription) { + this.aefiDescription = aefiDescription; + } + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + public YesNoUnknown getSerious() { + return serious; + } + + public void setSerious(YesNoUnknown serious) { + this.serious = serious; + } + + @Enumerated(EnumType.STRING) + public SeriousAefiReason getSeriousReason() { + return seriousReason; + } + + public void setSeriousReason(SeriousAefiReason seriousReason) { + this.seriousReason = seriousReason; + } + + @Column(columnDefinition = "text") + public String getSeriousReasonDetails() { + return seriousReasonDetails; + } + + public void setSeriousReasonDetails(String seriousReasonDetails) { + this.seriousReasonDetails = seriousReasonDetails; + } + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + public AefiOutcome getOutcome() { + return outcome; + } + + public void setOutcome(AefiOutcome outcome) { + this.outcome = outcome; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getDeathDate() { + return deathDate; + } + + public void setDeathDate(Date deathDate) { + this.deathDate = deathDate; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAutopsyDone() { + return autopsyDone; + } + + public void setAutopsyDone(YesNoUnknown autopsyDone) { + this.autopsyDone = autopsyDone; + } + + @Column(columnDefinition = "text") + public String getPastMedicalHistory() { + return pastMedicalHistory; + } + + public void setPastMedicalHistory(String pastMedicalHistory) { + this.pastMedicalHistory = pastMedicalHistory; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getInvestigationNeeded() { + return investigationNeeded; + } + + public void setInvestigationNeeded(YesNoUnknown investigationNeeded) { + this.investigationNeeded = investigationNeeded; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getInvestigationPlannedDate() { + return investigationPlannedDate; + } + + public void setInvestigationPlannedDate(Date investigationPlannedDate) { + this.investigationPlannedDate = investigationPlannedDate; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getReceivedAtNationalLevelDate() { + return receivedAtNationalLevelDate; + } + + public void setReceivedAtNationalLevelDate(Date receivedAtNationalLevelDate) { + this.receivedAtNationalLevelDate = receivedAtNationalLevelDate; + } + + @Column + public String getWorldwideId() { + return worldwideId; + } + + public void setWorldwideId(String worldwideId) { + this.worldwideId = worldwideId; + } + + @Column(columnDefinition = "text") + public String getNationalLevelComment() { + return nationalLevelComment; + } + + public void setNationalLevelComment(String nationalLevelComment) { + this.nationalLevelComment = nationalLevelComment; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigation.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigation.java new file mode 100644 index 00000000000..be0e4de6af1 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigation.java @@ -0,0 +1,1830 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity; + +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.apache.commons.lang3.StringUtils; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCausality; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassificationSubType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiImmunizationPeriod; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStage; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiVaccinationPeriod; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.BirthTerm; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.DeliveryProcedure; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PatientStatusAtAefiInvestigation; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PlaceOfVaccination; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeriousAefiInfoSource; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SyringeType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationActivity; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationSite; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccineCarrier; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.country.Country; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.vaccination.Vaccination; + +@Entity(name = "adverseeventsfollowingimmunizationinvestigation") +public class AefiInvestigation extends CoreAdo { + + private static final long serialVersionUID = 6128204752074963848L; + + public static final String TABLE_NAME = "adverseeventsfollowingimmunizationinvestigation"; + public static final String AEFI_INVESTIGATION_VACCINATIONS_TABLE_NAME = "adverseeventsfollowingimmunizationinvestigation_vaccinations"; + + public static final String AEFI_REPORT = "aefiReport"; + public static final String AEFI_REPORT_ID = "aefiReportId"; + public static final String ADDRESS = "address"; + public static final String VACCINATIONS = "vaccinations"; + public static final String PRIMARY_SUSPECT_VACCINE = "primarySuspectVaccine"; + public static final String REPORT_DATE = "reportDate"; + public static final String REPORTING_USER = "reportingUser"; + public static final String EXTERNAL_ID = "externalId"; + public static final String RESPONSIBLE_REGION = "responsibleRegion"; + public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict"; + public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity"; + public static final String COUNTRY = "country"; + public static final String INVESTIGATION_CASE_ID = "investigationCaseId"; + public static final String PLACE_OF_VACCINATION = "placeOfVaccination"; + public static final String PLACE_OF_VACCINATION_DETAILS = "placeOfVaccinationDetails"; + public static final String VACCINATION_ACTIVITY = "vaccinationActivity"; + public static final String VACCINATION_ACTIVITY_DETAILS = "vaccinationActivityDetails"; + public static final String VACCINATION_FACILITY = "vaccinationFacility"; + public static final String VACCINATION_FACILITY_DETAILS = "vaccinationFacilityDetails"; + public static final String REPORTING_OFFICER_NAME = "reportingOfficerName"; + public static final String REPORTING_OFFICER_FACILITY = "reportingOfficerFacility"; + public static final String REPORTING_OFFICER_FACILITY_DETAILS = "reportingOfficerFacilityDetails"; + public static final String REPORTING_OFFICER_DESIGNATION = "reportingOfficerDesignation"; + public static final String REPORTING_OFFICER_DEPARTMENT = "reportingOfficerDepartment"; + public static final String REPORTING_OFFICER_ADDRESS = "reportingOfficerAddress"; + public static final String REPORTING_OFFICER_LANDLINE_PHONE_NUMBER = "reportingOfficerLandlinePhoneNumber"; + public static final String REPORTING_OFFICER_MOBILE_PHONE_NUMBER = "reportingOfficerMobilePhoneNumber"; + public static final String REPORTING_OFFICER_EMAIL = "reportingOfficerEmail"; + public static final String INVESTIGATION_DATE = "investigationDate"; + public static final String FORM_COMPLETION_DATE = "formCompletionDate"; + public static final String INVESTIGATION_STAGE = "investigationStage"; + public static final String TYPE_OF_SITE = "typeOfSite"; + public static final String TYPE_OF_SITE_DETAILS = "typeOfSiteDetails"; + public static final String KEY_SYMPTOM_DATE_TIME = "keySymptomDateTime"; + public static final String HOSPITALIZATION_DATE = "hospitalizationDate"; + public static final String REPORTED_TO_HEALTH_AUTHORITY_DATE = "reportedToHealthAuthorityDate"; + public static final String STATUS_ON_DATE_OF_INVESTIGATION = "statusOnDateOfInvestigation"; + public static final String DEATH_DATE_TIME = "deathDateTime"; + public static final String AUTOPSY_DONE = "autopsyDone"; + public static final String AUTOPSY_DATE = "autopsyDate"; + public static final String AUTOPSY_PLANNED_DATE_TIME = "autopsyPlannedDateTime"; + public static final String PAST_HISTORY_OF_SIMILAR_EVENT = "pastHistoryOfSimilarEvent"; + public static final String PAST_HISTORY_OF_SIMILAR_EVENT_DETAILS = "pastHistoryOfSimilarEventDetails"; + public static final String ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS = "adverseEventAfterPreviousVaccinations"; + public static final String ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS_DETAILS = "adverseEventAfterPreviousVaccinationsDetails"; + public static final String HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD = "historyOfAllergyToVaccineDrugOrFood"; + public static final String HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD_DETAILS = "historyOfAllergyToVaccineDrugOrFoodDetails"; + public static final String PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER = "preExistingIllnessThirtyDaysOrCongenitalDisorder"; + public static final String PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER_DETAILS = + "preExistingIllnessThirtyDaysOrCongenitalDisorderDetails"; + public static final String HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE = "historyOfHospitalizationInLastThirtyDaysWithCause"; + public static final String HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE_DETAILS = + "historyOfHospitalizationInLastThirtyDaysWithCauseDetails"; + public static final String CURRENTLY_ON_CONCOMITANT_MEDICATION = "currentlyOnConcomitantMedication"; + public static final String CURRENTLY_ON_CONCOMITANT_MEDICATION_DETAILS = "currentlyOnConcomitantMedicationDetails"; + public static final String FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY = "familyHistoryOfDiseaseOrAllergy"; + public static final String FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY_DETAILS = "familyHistoryOfDiseaseOrAllergyDetails"; + public static final String NUMBER_OF_WEEKS_PREGNANT = "numberOfWeeksPregnant"; + public static final String BIRTH_TERM = "birthTerm"; + public static final String BIRTH_WEIGHT = "birthWeight"; + public static final String DELIVERY_PROCEDURE = "deliveryProcedure"; + public static final String DELIVERY_PROCEDURE_DETAILS = "deliveryProcedureDetails"; + public static final String SERIOUS_AEFI_INFO_SOURCE_STRING = "seriousAefiInfoSourceString"; + public static final String SERIOUS_AEFI_INFO_SOURCE_DETAILS = "seriousAefiInfoSourceDetails"; + public static final String SERIOUS_AEFI_VERBAL_AUTOPSY_INFO_SOURCE_DETAILS = "seriousAefiVerbalAutopsyInfoSourceDetails"; + public static final String FIRST_CAREGIVERS_NAME = "firstCaregiversName"; + public static final String OTHER_CAREGIVERS_NAMES = "otherCaregiversNames"; + public static final String OTHER_SOURCES_WHO_PROVIDED_INFO = "otherSourcesWhoProvidedInfo"; + public static final String SIGNS_AND_SYMPTOMS_FROM_TIME_OF_VACCINATION = "signsAndSymptomsFromTimeOfVaccination"; + public static final String CLINICAL_DETAILS_OFFICER_NAME = "clinicalDetailsOfficerName"; + public static final String CLINICAL_DETAILS_OFFICER_PHONE_NUMBER = "clinicalDetailsOfficerPhoneNumber"; + public static final String CLINICAL_DETAILS_OFFICER_EMAIL = "clinicalDetailsOfficerEmail"; + public static final String CLINICAL_DETAILS_OFFICER_DESIGNATION = "clinicalDetailsOfficerDesignation"; + public static final String CLINICAL_DETAILS_DATE_TIME = "clinicalDetailsDateTime"; + public static final String PATIENT_RECEIVED_MEDICAL_CARE = "patientReceivedMedicalCare"; + public static final String PATIENT_RECEIVED_MEDICAL_CARE_DETAILS = "patientReceivedMedicalCareDetails"; + public static final String PROVISIONAL_OR_FINAL_DIAGNOSIS = "provisionalOrFinalDiagnosis"; + public static final String PATIENT_IMMUNIZED_PERIOD = "patientImmunizedPeriod"; + public static final String PATIENT_IMMUNIZED_PERIOD_DETAILS = "patientImmunizedPeriodDetails"; + public static final String VACCINE_GIVEN_PERIOD = "vaccineGivenPeriod"; + public static final String VACCINE_GIVEN_PERIOD_DETAILS = "vaccineGivenPeriodDetails"; + public static final String ERROR_PRESCRIBING_VACCINE = "errorPrescribingVaccine"; + public static final String ERROR_PRESCRIBING_VACCINE_DETAILS = "errorPrescribingVaccineDetails"; + public static final String VACCINE_COULD_HAVE_BEEN_UNSTERILE = "vaccineCouldHaveBeenUnSterile"; + public static final String VACCINE_COULD_HAVE_BEEN_UNSTERILE_DETAILS = "vaccineCouldHaveBeenUnSterileDetails"; + public static final String VACCINE_PHYSICAL_CONDITION_ABNORMAL = "vaccinePhysicalConditionAbnormal"; + public static final String VACCINE_PHYSICAL_CONDITION_ABNORMAL_DETAILS = "vaccinePhysicalConditionAbnormalDetails"; + public static final String ERROR_IN_VACCINE_RECONSTITUTION = "errorInVaccineReconstitution"; + public static final String ERROR_IN_VACCINE_RECONSTITUTION_DETAILS = "errorInVaccineReconstitutionDetails"; + public static final String ERROR_IN_VACCINE_HANDLING = "errorInVaccineHandling"; + public static final String ERROR_IN_VACCINE_HANDLING_DETAILS = "errorInVaccineHandlingDetails"; + public static final String VACCINE_ADMINISTERED_INCORRECTLY = "vaccineAdministeredIncorrectly"; + public static final String VACCINE_ADMINISTERED_INCORRECTLY_DETAILS = "vaccineAdministeredIncorrectlyDetails"; + public static final String NUMBER_IMMUNIZED_FROM_CONCERNED_VACCINE_VIAL = "numberImmunizedFromConcernedVaccineVial"; + public static final String NUMBER_IMMUNIZED_WITH_CONCERNED_VACCINE_IN_SAME_SESSION = "numberImmunizedWithConcernedVaccineInSameSession"; + public static final String NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_OTHER_LOCATIONS = + "numberImmunizedConcernedVaccineSameBatchNumberOtherLocations"; + public static final String NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_LOCATION_DETAILS = + "numberImmunizedConcernedVaccineSameBatchNumberLocationDetails"; + public static final String VACCINE_HAS_QUALITY_DEFECT = "vaccineHasQualityDefect"; + public static final String VACCINE_HAS_QUALITY_DEFECT_DETAILS = "vaccineHasQualityDefectDetails"; + public static final String EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION = "eventIsAStressResponseRelatedToImmunization"; + public static final String EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION_DETAILS = "eventIsAStressResponseRelatedToImmunizationDetails"; + public static final String CASE_IS_PART_OF_A_CLUSTER = "caseIsPartOfACluster"; + public static final String CASE_IS_PART_OF_A_CLUSTER_DETAILS = "caseIsPartOfAClusterDetails"; + public static final String NUMBER_OF_CASES_DETECTED_IN_CLUSTER = "numberOfCasesDetectedInCluster"; + public static final String ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL = "allCasesInClusterReceivedVaccineFromSameVial"; + public static final String ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL_DETAILS = "allCasesInClusterReceivedVaccineFromSameVialDetails"; + public static final String NUMBER_OF_VIALS_USED_IN_CLUSTER = "numberOfVialsUsedInCluster"; + public static final String NUMBER_OF_VIALS_USED_IN_CLUSTER_DETAILS = "numberOfVialsUsedInClusterDetails"; + public static final String AD_SYRINGES_USED_FOR_IMMUNIZATION = "adSyringesUsedForImmunization"; + public static final String TYPE_OF_SYRINGES_USED = "typeOfSyringesUsed"; + public static final String TYPE_OF_SYRINGES_USED_DETAILS = "typeOfSyringesUsedDetails"; + public static final String SYRINGES_USED_ADDITIONAL_DETAILS = "syringesUsedAdditionalDetails"; + public static final String SAME_RECONSTITUTION_SYRINGE_USED_FOR_MULTIPLE_VIALS_OF_SAME_VACCINE = + "sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine"; + public static final String SAME_RECONSTITUTION_SYRINGE_USED_FOR_RECONSTITUTING_DIFFERENT_VACCINES = + "sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines"; + public static final String SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINE_VIAL = "sameReconstitutionSyringeForEachVaccineVial"; + public static final String SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINATION = "sameReconstitutionSyringeForEachVaccination"; + public static final String VACCINES_AND_DILUENTS_USED_RECOMMENDED_BY_MANUFACTURER = "vaccinesAndDiluentsUsedRecommendedByManufacturer"; + public static final String RECONSTITUTION_ADDITIONAL_DETAILS = "reconstitutionAdditionalDetails"; + public static final String CORRECT_DOSE_OR_ROUTE = "correctDoseOrRoute"; + public static final String TIME_OF_RECONSTITUTION_MENTIONED_ON_THE_VIAL = "timeOfReconstitutionMentionedOnTheVial"; + public static final String NON_TOUCH_TECHNIQUE_FOLLOWED = "nonTouchTechniqueFollowed"; + public static final String CONTRAINDICATION_SCREENED_PRIOR_TO_VACCINATION = "contraIndicationScreenedPriorToVaccination"; + public static final String NUMBER_OF_AEFI_REPORTED_FROM_VACCINE_DISTRIBUTION_CENTER_LAST_THIRTY_DAYS = + "numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays"; + public static final String TRAINING_RECEIVED_BY_VACCINATOR = "trainingReceivedByVaccinator"; + public static final String LAST_TRAINING_RECEIVED_BY_VACCINATOR_DATE = "lastTrainingReceivedByVaccinatorDate"; + public static final String INJECTION_TECHNIQUE_ADDITIONAL_DETAILS = "injectionTechniqueAdditionalDetails"; + public static final String VACCINE_STORAGE_REFRIGERATOR_TEMPERATURE_MONITORED = "vaccineStorageRefrigeratorTemperatureMonitored"; + public static final String ANY_STORAGE_TEMPERATURE_DEVIATION_OUTSIDE_TWO_TO_EIGHT_DEGREES = + "anyStorageTemperatureDeviationOutsideTwoToEightDegrees"; + public static final String STORAGE_TEMPERATURE_MONITORING_ADDITIONAL_DETAILS = "storageTemperatureMonitoringAdditionalDetails"; + public static final String CORRECT_PROCEDURE_FOR_STORAGE_FOLLOWED = "correctProcedureForStorageFollowed"; + public static final String ANY_OTHER_ITEM_IN_REFRIGERATOR = "anyOtherItemInRefrigerator"; + public static final String PARTIALLY_USED_RECONSTITUTED_VACCINES_IN_REFRIGERATOR = "partiallyUsedReconstitutedVaccinesInRefrigerator"; + public static final String UNUSABLE_VACCINES_IN_REFRIGERATOR = "unusableVaccinesInRefrigerator"; + public static final String UNUSABLE_DILUENTS_IN_STORE = "unusableDiluentsInStore"; + public static final String VACCINE_STORAGE_POINT_ADDITIONAL_DETAILS = "vaccineStoragePointAdditionalDetails"; + public static final String VACCINE_CARRIER_TYPE = "vaccineCarrierType"; + public static final String VACCINE_CARRIER_TYPE_DETAILS = "vaccineCarrierTypeDetails"; + public static final String VACCINE_CARRIER_SENT_TO_SITE_ON_SAME_DATE_AS_VACCINATION = "vaccineCarrierSentToSiteOnSameDateAsVaccination"; + public static final String VACCINE_CARRIER_RETURNED_FROM_SITE_ON_SAME_DATE_AS_VACCINATION = + "vaccineCarrierReturnedFromSiteOnSameDateAsVaccination"; + public static final String CONDITIONED_ICE_PACK_USED = "conditionedIcepackUsed"; + public static final String VACCINE_TRANSPORTATION_ADDITIONAL_DETAILS = "vaccineTransportationAdditionalDetails"; + public static final String SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY = "similarEventsReportedSamePeriodAndLocality"; + public static final String SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS = "similarEventsReportedSamePeriodAndLocalityDetails"; + public static final String NUMBER_OF_SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY = "numberOfSimilarEventsReportedSamePeriodAndLocality"; + public static final String NUMBER_OF_THOSE_AFFECTED_VACCINATED = "numberOfThoseAffectedVaccinated"; + public static final String NUMBER_OF_THOSE_AFFECTED_NOT_VACCINATED = "numberOfThoseAffectedNotVaccinated"; + public static final String NUMBER_OF_THOSE_AFFECTED_VACCINATED_UNKNOWN = "numberOfThoseAffectedVaccinatedUnknown"; + public static final String COMMUNITY_INVESTIGATION_ADDITIONAL_DETAILS = "communityInvestigationAdditionalDetails"; + public static final String OTHER_INVESTIGATION_FINDINGS = "otherInvestigationFindings"; + public static final String INVESTIGATION_STATUS = "investigationStatus"; + public static final String INVESTIGATION_STATUS_DETAILS = "investigationStatusDetails"; + public static final String AEFI_CLASSIFICATION = "aefiClassification"; + public static final String AEFI_CLASSIFICATION_SUB_TYPE = "aefiClassificationSubType"; + public static final String AEFI_CLASSIFICATION_DETAILS = "aefiClassificationDetails"; + public static final String CAUSALITY = "causality"; + public static final String CAUSALITY_DETAILS = "causalityDetails"; + public static final String INVESTIGATION_COMPLETION_DATE = "investigationCompletionDate"; + + private Aefi aefiReport; + private Long aefiReportId; + private Location address; + private Set vaccinations; + private Vaccination primarySuspectVaccine; + private Date reportDate; + private User reportingUser; + private String externalId; + private Region responsibleRegion; + private District responsibleDistrict; + private Community responsibleCommunity; + private Country country; + private String investigationCaseId; + private PlaceOfVaccination placeOfVaccination; + private String placeOfVaccinationDetails; + private VaccinationActivity vaccinationActivity; + private String vaccinationActivityDetails; + private Facility vaccinationFacility; + private String vaccinationFacilityDetails; + private String reportingOfficerName; + private Facility reportingOfficerFacility; + private String reportingOfficerFacilityDetails; + private String reportingOfficerDesignation; + private String reportingOfficerDepartment; + private Location reportingOfficerAddress; + private String reportingOfficerLandlinePhoneNumber; + private String reportingOfficerMobilePhoneNumber; + private String reportingOfficerEmail; + private Date investigationDate; + private Date formCompletionDate; + private AefiInvestigationStage investigationStage; + private VaccinationSite typeOfSite; + private String typeOfSiteDetails; + private Date keySymptomDateTime; + private Date hospitalizationDate; + private Date reportedToHealthAuthorityDate; + private PatientStatusAtAefiInvestigation statusOnDateOfInvestigation; + private Date deathDateTime; + private YesNoUnknown autopsyDone; + private Date autopsyDate; + private Date autopsyPlannedDateTime; + private YesNoUnknown pastHistoryOfSimilarEvent; + private String pastHistoryOfSimilarEventDetails; + private YesNoUnknown adverseEventAfterPreviousVaccinations; + private String adverseEventAfterPreviousVaccinationsDetails; + private YesNoUnknown historyOfAllergyToVaccineDrugOrFood; + private String historyOfAllergyToVaccineDrugOrFoodDetails; + private YesNoUnknown preExistingIllnessThirtyDaysOrCongenitalDisorder; + private String preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + private YesNoUnknown historyOfHospitalizationInLastThirtyDaysWithCause; + private String historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + private YesNoUnknown currentlyOnConcomitantMedication; + private String currentlyOnConcomitantMedicationDetails; + private YesNoUnknown familyHistoryOfDiseaseOrAllergy; + private String familyHistoryOfDiseaseOrAllergyDetails; + private Integer numberOfWeeksPregnant; + private BirthTerm birthTerm; + private Float birthWeight; + private DeliveryProcedure deliveryProcedure; + private String deliveryProcedureDetails; + private Set seriousAefiInfoSource; + private String seriousAefiInfoSourceString; + private String seriousAefiInfoSourceDetails; + private String seriousAefiVerbalAutopsyInfoSourceDetails; + private String firstCaregiversName; + private String otherCaregiversNames; + private String otherSourcesWhoProvidedInfo; + private String signsAndSymptomsFromTimeOfVaccination; + private String clinicalDetailsOfficerName; + private String clinicalDetailsOfficerPhoneNumber; + private String clinicalDetailsOfficerEmail; + private String clinicalDetailsOfficerDesignation; + private Date clinicalDetailsDateTime; + private YesNoUnknown patientReceivedMedicalCare; + private String patientReceivedMedicalCareDetails; + private String provisionalOrFinalDiagnosis; + private AefiImmunizationPeriod patientImmunizedPeriod; + private String patientImmunizedPeriodDetails; + private AefiVaccinationPeriod vaccineGivenPeriod; + private String vaccineGivenPeriodDetails; + private YesNoUnknown errorPrescribingVaccine; + private String errorPrescribingVaccineDetails; + private YesNoUnknown vaccineCouldHaveBeenUnSterile; + private String vaccineCouldHaveBeenUnSterileDetails; + private YesNoUnknown vaccinePhysicalConditionAbnormal; + private String vaccinePhysicalConditionAbnormalDetails; + private YesNoUnknown errorInVaccineReconstitution; + private String errorInVaccineReconstitutionDetails; + private YesNoUnknown errorInVaccineHandling; + private String errorInVaccineHandlingDetails; + private YesNoUnknown vaccineAdministeredIncorrectly; + private String vaccineAdministeredIncorrectlyDetails; + private Integer numberImmunizedFromConcernedVaccineVial; + private Integer numberImmunizedWithConcernedVaccineInSameSession; + private Integer numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + private String numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + private YesNoUnknown vaccineHasQualityDefect; + private String vaccineHasQualityDefectDetails; + private YesNoUnknown eventIsAStressResponseRelatedToImmunization; + private String eventIsAStressResponseRelatedToImmunizationDetails; + private YesNoUnknown caseIsPartOfACluster; + private String caseIsPartOfAClusterDetails; + private Integer numberOfCasesDetectedInCluster; + private YesNoUnknown allCasesInClusterReceivedVaccineFromSameVial; + private String allCasesInClusterReceivedVaccineFromSameVialDetails; + private Integer numberOfVialsUsedInCluster; + private String numberOfVialsUsedInClusterDetails; + private YesNoUnknown adSyringesUsedForImmunization; + private SyringeType typeOfSyringesUsed; + private String typeOfSyringesUsedDetails; + private String syringesUsedAdditionalDetails; + private YesNoUnknown sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + private YesNoUnknown sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + private YesNoUnknown sameReconstitutionSyringeForEachVaccineVial; + private YesNoUnknown sameReconstitutionSyringeForEachVaccination; + private YesNoUnknown vaccinesAndDiluentsUsedRecommendedByManufacturer; + private String reconstitutionAdditionalDetails; + private YesNoUnknown correctDoseOrRoute; + private YesNoUnknown timeOfReconstitutionMentionedOnTheVial; + private YesNoUnknown nonTouchTechniqueFollowed; + private YesNoUnknown contraIndicationScreenedPriorToVaccination; + private Integer numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + private YesNoUnknown trainingReceivedByVaccinator; + private Date lastTrainingReceivedByVaccinatorDate; + private String injectionTechniqueAdditionalDetails; + private YesNoUnknown vaccineStorageRefrigeratorTemperatureMonitored; + private YesNoUnknown anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + private String storageTemperatureMonitoringAdditionalDetails; + private YesNoUnknown correctProcedureForStorageFollowed; + private YesNoUnknown anyOtherItemInRefrigerator; + private YesNoUnknown partiallyUsedReconstitutedVaccinesInRefrigerator; + private YesNoUnknown unusableVaccinesInRefrigerator; + private YesNoUnknown unusableDiluentsInStore; + private String vaccineStoragePointAdditionalDetails; + private VaccineCarrier vaccineCarrierType; + private String vaccineCarrierTypeDetails; + private YesNoUnknown vaccineCarrierSentToSiteOnSameDateAsVaccination; + private YesNoUnknown vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + private YesNoUnknown conditionedIcepackUsed; + private String vaccineTransportationAdditionalDetails; + private YesNoUnknown similarEventsReportedSamePeriodAndLocality; + private String similarEventsReportedSamePeriodAndLocalityDetails; + private Integer numberOfSimilarEventsReportedSamePeriodAndLocality; + private Integer numberOfThoseAffectedVaccinated; + private Integer numberOfThoseAffectedNotVaccinated; + private Integer numberOfThoseAffectedVaccinatedUnknown; + private String communityInvestigationAdditionalDetails; + private String otherInvestigationFindings; + private AefiInvestigationStatus investigationStatus; + private String investigationStatusDetails; + private AefiClassification aefiClassification; + private AefiClassificationSubType aefiClassificationSubType; + private String aefiClassificationDetails; + private AefiCausality causality; + private String causalityDetails; + private Date investigationCompletionDate; + + public static AefiInvestigation build() { + AefiInvestigation aefiInvestigation = new AefiInvestigation(); + return aefiInvestigation; + } + + @ManyToOne + @JoinColumn(name = "adverseeventsfollowingimmunization_id", nullable = false) + public Aefi getAefiReport() { + return aefiReport; + } + + public void setAefiReport(Aefi aefiReport) { + this.aefiReport = aefiReport; + } + + @Column(name = "adverseeventsfollowingimmunization_id", updatable = false, insertable = false) + public Long getAefiReportId() { + return aefiReportId; + } + + public void setAefiReportId(Long aefiReportId) { + this.aefiReportId = aefiReportId; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + public Location getAddress() { + return address; + } + + public void setAddress(Location address) { + this.address = address; + } + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = AEFI_INVESTIGATION_VACCINATIONS_TABLE_NAME, + joinColumns = @JoinColumn(name = "adverseeventsfollowingimmunizationinvestigation_id"), + inverseJoinColumns = @JoinColumn(name = "vaccination_id")) + public Set getVaccinations() { + return vaccinations; + } + + public void setVaccinations(Set vaccinations) { + this.vaccinations = vaccinations; + } + + @OneToOne + public Vaccination getPrimarySuspectVaccine() { + return primarySuspectVaccine; + } + + public void setPrimarySuspectVaccine(Vaccination primarySuspectVaccine) { + this.primarySuspectVaccine = primarySuspectVaccine; + } + + @Temporal(TemporalType.TIMESTAMP) + @Column(nullable = false) + public Date getReportDate() { + return reportDate; + } + + public void setReportDate(Date reportDate) { + this.reportDate = reportDate; + } + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(nullable = false) + public User getReportingUser() { + return reportingUser; + } + + public void setReportingUser(User reportingUser) { + this.reportingUser = reportingUser; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Region getResponsibleRegion() { + return responsibleRegion; + } + + public void setResponsibleRegion(Region responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + @ManyToOne(fetch = FetchType.LAZY) + public District getResponsibleDistrict() { + return responsibleDistrict; + } + + public void setResponsibleDistrict(District responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Community getResponsibleCommunity() { + return responsibleCommunity; + } + + public void setResponsibleCommunity(Community responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Country getCountry() { + return country; + } + + public void setCountry(Country country) { + this.country = country; + } + + public String getInvestigationCaseId() { + return investigationCaseId; + } + + public void setInvestigationCaseId(String investigationCaseId) { + this.investigationCaseId = investigationCaseId; + } + + @Enumerated(EnumType.STRING) + public PlaceOfVaccination getPlaceOfVaccination() { + return placeOfVaccination; + } + + public void setPlaceOfVaccination(PlaceOfVaccination placeOfVaccination) { + this.placeOfVaccination = placeOfVaccination; + } + + public String getPlaceOfVaccinationDetails() { + return placeOfVaccinationDetails; + } + + public void setPlaceOfVaccinationDetails(String placeOfVaccinationDetails) { + this.placeOfVaccinationDetails = placeOfVaccinationDetails; + } + + @Enumerated(EnumType.STRING) + public VaccinationActivity getVaccinationActivity() { + return vaccinationActivity; + } + + public void setVaccinationActivity(VaccinationActivity vaccinationActivity) { + this.vaccinationActivity = vaccinationActivity; + } + + public String getVaccinationActivityDetails() { + return vaccinationActivityDetails; + } + + public void setVaccinationActivityDetails(String vaccinationActivityDetails) { + this.vaccinationActivityDetails = vaccinationActivityDetails; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Facility getVaccinationFacility() { + return vaccinationFacility; + } + + public void setVaccinationFacility(Facility vaccinationFacility) { + this.vaccinationFacility = vaccinationFacility; + } + + public String getVaccinationFacilityDetails() { + return vaccinationFacilityDetails; + } + + public void setVaccinationFacilityDetails(String vaccinationFacilityDetails) { + this.vaccinationFacilityDetails = vaccinationFacilityDetails; + } + + public String getReportingOfficerName() { + return reportingOfficerName; + } + + public void setReportingOfficerName(String reportingOfficerName) { + this.reportingOfficerName = reportingOfficerName; + } + + @ManyToOne(fetch = FetchType.LAZY) + public Facility getReportingOfficerFacility() { + return reportingOfficerFacility; + } + + public void setReportingOfficerFacility(Facility reportingOfficerFacility) { + this.reportingOfficerFacility = reportingOfficerFacility; + } + + public String getReportingOfficerFacilityDetails() { + return reportingOfficerFacilityDetails; + } + + public void setReportingOfficerFacilityDetails(String reportingOfficerFacilityDetails) { + this.reportingOfficerFacilityDetails = reportingOfficerFacilityDetails; + } + + public String getReportingOfficerDesignation() { + return reportingOfficerDesignation; + } + + public void setReportingOfficerDesignation(String reportingOfficerDesignation) { + this.reportingOfficerDesignation = reportingOfficerDesignation; + } + + public String getReportingOfficerDepartment() { + return reportingOfficerDepartment; + } + + public void setReportingOfficerDepartment(String reportingOfficerDepartment) { + this.reportingOfficerDepartment = reportingOfficerDepartment; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "reportingofficeraddress_id") + public Location getReportingOfficerAddress() { + return reportingOfficerAddress; + } + + public void setReportingOfficerAddress(Location reportingOfficerAddress) { + this.reportingOfficerAddress = reportingOfficerAddress; + } + + public String getReportingOfficerLandlinePhoneNumber() { + return reportingOfficerLandlinePhoneNumber; + } + + public void setReportingOfficerLandlinePhoneNumber(String reportingOfficerLandlinePhoneNumber) { + this.reportingOfficerLandlinePhoneNumber = reportingOfficerLandlinePhoneNumber; + } + + public String getReportingOfficerMobilePhoneNumber() { + return reportingOfficerMobilePhoneNumber; + } + + public void setReportingOfficerMobilePhoneNumber(String reportingOfficerMobilePhoneNumber) { + this.reportingOfficerMobilePhoneNumber = reportingOfficerMobilePhoneNumber; + } + + public String getReportingOfficerEmail() { + return reportingOfficerEmail; + } + + public void setReportingOfficerEmail(String reportingOfficerEmail) { + this.reportingOfficerEmail = reportingOfficerEmail; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getInvestigationDate() { + return investigationDate; + } + + public void setInvestigationDate(Date investigationDate) { + this.investigationDate = investigationDate; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getFormCompletionDate() { + return formCompletionDate; + } + + public void setFormCompletionDate(Date formCompletionDate) { + this.formCompletionDate = formCompletionDate; + } + + @Enumerated(EnumType.STRING) + public AefiInvestigationStage getInvestigationStage() { + return investigationStage; + } + + public void setInvestigationStage(AefiInvestigationStage investigationStage) { + this.investigationStage = investigationStage; + } + + @Enumerated(EnumType.STRING) + public VaccinationSite getTypeOfSite() { + return typeOfSite; + } + + public void setTypeOfSite(VaccinationSite typeOfSite) { + this.typeOfSite = typeOfSite; + } + + @Column + public String getTypeOfSiteDetails() { + return typeOfSiteDetails; + } + + public void setTypeOfSiteDetails(String typeOfSiteDetails) { + this.typeOfSiteDetails = typeOfSiteDetails; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getKeySymptomDateTime() { + return keySymptomDateTime; + } + + public void setKeySymptomDateTime(Date keySymptomDateTime) { + this.keySymptomDateTime = keySymptomDateTime; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getHospitalizationDate() { + return hospitalizationDate; + } + + public void setHospitalizationDate(Date hospitalizationDate) { + this.hospitalizationDate = hospitalizationDate; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getReportedToHealthAuthorityDate() { + return reportedToHealthAuthorityDate; + } + + public void setReportedToHealthAuthorityDate(Date reportedToHealthAuthorityDate) { + this.reportedToHealthAuthorityDate = reportedToHealthAuthorityDate; + } + + @Enumerated(EnumType.STRING) + public PatientStatusAtAefiInvestigation getStatusOnDateOfInvestigation() { + return statusOnDateOfInvestigation; + } + + public void setStatusOnDateOfInvestigation(PatientStatusAtAefiInvestigation statusOnDateOfInvestigation) { + this.statusOnDateOfInvestigation = statusOnDateOfInvestigation; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getDeathDateTime() { + return deathDateTime; + } + + public void setDeathDateTime(Date deathDateTime) { + this.deathDateTime = deathDateTime; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAutopsyDone() { + return autopsyDone; + } + + public void setAutopsyDone(YesNoUnknown autopsyDone) { + this.autopsyDone = autopsyDone; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getAutopsyDate() { + return autopsyDate; + } + + public void setAutopsyDate(Date autopsyDate) { + this.autopsyDate = autopsyDate; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getAutopsyPlannedDateTime() { + return autopsyPlannedDateTime; + } + + public void setAutopsyPlannedDateTime(Date autopsyPlannedDateTime) { + this.autopsyPlannedDateTime = autopsyPlannedDateTime; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getPastHistoryOfSimilarEvent() { + return pastHistoryOfSimilarEvent; + } + + public void setPastHistoryOfSimilarEvent(YesNoUnknown pastHistoryOfSimilarEvent) { + this.pastHistoryOfSimilarEvent = pastHistoryOfSimilarEvent; + } + + @Column + public String getPastHistoryOfSimilarEventDetails() { + return pastHistoryOfSimilarEventDetails; + } + + public void setPastHistoryOfSimilarEventDetails(String pastHistoryOfSimilarEventDetails) { + this.pastHistoryOfSimilarEventDetails = pastHistoryOfSimilarEventDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAdverseEventAfterPreviousVaccinations() { + return adverseEventAfterPreviousVaccinations; + } + + public void setAdverseEventAfterPreviousVaccinations(YesNoUnknown adverseEventAfterPreviousVaccinations) { + this.adverseEventAfterPreviousVaccinations = adverseEventAfterPreviousVaccinations; + } + + @Column + public String getAdverseEventAfterPreviousVaccinationsDetails() { + return adverseEventAfterPreviousVaccinationsDetails; + } + + public void setAdverseEventAfterPreviousVaccinationsDetails(String adverseEventAfterPreviousVaccinationsDetails) { + this.adverseEventAfterPreviousVaccinationsDetails = adverseEventAfterPreviousVaccinationsDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getHistoryOfAllergyToVaccineDrugOrFood() { + return historyOfAllergyToVaccineDrugOrFood; + } + + public void setHistoryOfAllergyToVaccineDrugOrFood(YesNoUnknown historyOfAllergyToVaccineDrugOrFood) { + this.historyOfAllergyToVaccineDrugOrFood = historyOfAllergyToVaccineDrugOrFood; + } + + @Column + public String getHistoryOfAllergyToVaccineDrugOrFoodDetails() { + return historyOfAllergyToVaccineDrugOrFoodDetails; + } + + public void setHistoryOfAllergyToVaccineDrugOrFoodDetails(String historyOfAllergyToVaccineDrugOrFoodDetails) { + this.historyOfAllergyToVaccineDrugOrFoodDetails = historyOfAllergyToVaccineDrugOrFoodDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getPreExistingIllnessThirtyDaysOrCongenitalDisorder() { + return preExistingIllnessThirtyDaysOrCongenitalDisorder; + } + + public void setPreExistingIllnessThirtyDaysOrCongenitalDisorder(YesNoUnknown preExistingIllnessThirtyDaysOrCongenitalDisorder) { + this.preExistingIllnessThirtyDaysOrCongenitalDisorder = preExistingIllnessThirtyDaysOrCongenitalDisorder; + } + + @Column + public String getPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails() { + return preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + } + + public void setPreExistingIllnessThirtyDaysOrCongenitalDisorderDetails(String preExistingIllnessThirtyDaysOrCongenitalDisorderDetails) { + this.preExistingIllnessThirtyDaysOrCongenitalDisorderDetails = preExistingIllnessThirtyDaysOrCongenitalDisorderDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getHistoryOfHospitalizationInLastThirtyDaysWithCause() { + return historyOfHospitalizationInLastThirtyDaysWithCause; + } + + public void setHistoryOfHospitalizationInLastThirtyDaysWithCause(YesNoUnknown historyOfHospitalizationInLastThirtyDaysWithCause) { + this.historyOfHospitalizationInLastThirtyDaysWithCause = historyOfHospitalizationInLastThirtyDaysWithCause; + } + + @Column + public String getHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails() { + return historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + } + + public void setHistoryOfHospitalizationInLastThirtyDaysWithCauseDetails(String historyOfHospitalizationInLastThirtyDaysWithCauseDetails) { + this.historyOfHospitalizationInLastThirtyDaysWithCauseDetails = historyOfHospitalizationInLastThirtyDaysWithCauseDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getCurrentlyOnConcomitantMedication() { + return currentlyOnConcomitantMedication; + } + + public void setCurrentlyOnConcomitantMedication(YesNoUnknown currentlyOnConcomitantMedication) { + this.currentlyOnConcomitantMedication = currentlyOnConcomitantMedication; + } + + @Column + public String getCurrentlyOnConcomitantMedicationDetails() { + return currentlyOnConcomitantMedicationDetails; + } + + public void setCurrentlyOnConcomitantMedicationDetails(String currentlyOnConcomitantMedicationDetails) { + this.currentlyOnConcomitantMedicationDetails = currentlyOnConcomitantMedicationDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getFamilyHistoryOfDiseaseOrAllergy() { + return familyHistoryOfDiseaseOrAllergy; + } + + public void setFamilyHistoryOfDiseaseOrAllergy(YesNoUnknown familyHistoryOfDiseaseOrAllergy) { + this.familyHistoryOfDiseaseOrAllergy = familyHistoryOfDiseaseOrAllergy; + } + + @Column + public String getFamilyHistoryOfDiseaseOrAllergyDetails() { + return familyHistoryOfDiseaseOrAllergyDetails; + } + + public void setFamilyHistoryOfDiseaseOrAllergyDetails(String familyHistoryOfDiseaseOrAllergyDetails) { + this.familyHistoryOfDiseaseOrAllergyDetails = familyHistoryOfDiseaseOrAllergyDetails; + } + + @Column + public Integer getNumberOfWeeksPregnant() { + return numberOfWeeksPregnant; + } + + public void setNumberOfWeeksPregnant(Integer numberOfWeeksPregnant) { + this.numberOfWeeksPregnant = numberOfWeeksPregnant; + } + + @Enumerated(EnumType.STRING) + public BirthTerm getBirthTerm() { + return birthTerm; + } + + public void setBirthTerm(BirthTerm birthTerm) { + this.birthTerm = birthTerm; + } + + @Column + public Float getBirthWeight() { + return birthWeight; + } + + public void setBirthWeight(Float birthWeight) { + this.birthWeight = birthWeight; + } + + @Enumerated(EnumType.STRING) + public DeliveryProcedure getDeliveryProcedure() { + return deliveryProcedure; + } + + public void setDeliveryProcedure(DeliveryProcedure deliveryProcedure) { + this.deliveryProcedure = deliveryProcedure; + } + + @Column + public String getDeliveryProcedureDetails() { + return deliveryProcedureDetails; + } + + public void setDeliveryProcedureDetails(String deliveryProcedureDetails) { + this.deliveryProcedureDetails = deliveryProcedureDetails; + } + + @Transient + public Set getSeriousAefiInfoSource() { + if (seriousAefiInfoSource == null) { + if (StringUtils.isEmpty(seriousAefiInfoSourceString)) { + seriousAefiInfoSource = new HashSet<>(); + } else { + seriousAefiInfoSource = + Arrays.stream(seriousAefiInfoSourceString.split(",")).map(SeriousAefiInfoSource::valueOf).collect(Collectors.toSet()); + } + } + return seriousAefiInfoSource; + } + + public void setSeriousAefiInfoSource(Set seriousAefiInfoSource) { + this.seriousAefiInfoSource = seriousAefiInfoSource; + + if (this.seriousAefiInfoSource == null) { + return; + } + + StringBuilder sb = new StringBuilder(); + seriousAefiInfoSource.stream().forEach(t -> { + sb.append(t.name()); + sb.append(","); + }); + if (sb.length() > 0) { + sb.substring(0, sb.lastIndexOf(",")); + } + seriousAefiInfoSourceString = sb.toString(); + } + + @Column + public String getSeriousAefiInfoSourceString() { + return seriousAefiInfoSourceString; + } + + public void setSeriousAefiInfoSourceString(String seriousAefiInfoSourceString) { + this.seriousAefiInfoSourceString = seriousAefiInfoSourceString; + } + + @Column + public String getSeriousAefiInfoSourceDetails() { + return seriousAefiInfoSourceDetails; + } + + public void setSeriousAefiInfoSourceDetails(String seriousAefiInfoSourceDetails) { + this.seriousAefiInfoSourceDetails = seriousAefiInfoSourceDetails; + } + + @Column + public String getSeriousAefiVerbalAutopsyInfoSourceDetails() { + return seriousAefiVerbalAutopsyInfoSourceDetails; + } + + public void setSeriousAefiVerbalAutopsyInfoSourceDetails(String seriousAefiVerbalAutopsyInfoSourceDetails) { + this.seriousAefiVerbalAutopsyInfoSourceDetails = seriousAefiVerbalAutopsyInfoSourceDetails; + } + + @Column + public String getFirstCaregiversName() { + return firstCaregiversName; + } + + public void setFirstCaregiversName(String firstCaregiversName) { + this.firstCaregiversName = firstCaregiversName; + } + + @Column + public String getOtherCaregiversNames() { + return otherCaregiversNames; + } + + public void setOtherCaregiversNames(String otherCaregiversNames) { + this.otherCaregiversNames = otherCaregiversNames; + } + + @Column + public String getOtherSourcesWhoProvidedInfo() { + return otherSourcesWhoProvidedInfo; + } + + public void setOtherSourcesWhoProvidedInfo(String otherSourcesWhoProvidedInfo) { + this.otherSourcesWhoProvidedInfo = otherSourcesWhoProvidedInfo; + } + + @Column + public String getSignsAndSymptomsFromTimeOfVaccination() { + return signsAndSymptomsFromTimeOfVaccination; + } + + public void setSignsAndSymptomsFromTimeOfVaccination(String signsAndSymptomsFromTimeOfVaccination) { + this.signsAndSymptomsFromTimeOfVaccination = signsAndSymptomsFromTimeOfVaccination; + } + + @Column + public String getClinicalDetailsOfficerName() { + return clinicalDetailsOfficerName; + } + + public void setClinicalDetailsOfficerName(String clinicalDetailsOfficerName) { + this.clinicalDetailsOfficerName = clinicalDetailsOfficerName; + } + + @Column + public String getClinicalDetailsOfficerPhoneNumber() { + return clinicalDetailsOfficerPhoneNumber; + } + + public void setClinicalDetailsOfficerPhoneNumber(String clinicalDetailsOfficerPhoneNumber) { + this.clinicalDetailsOfficerPhoneNumber = clinicalDetailsOfficerPhoneNumber; + } + + @Column + public String getClinicalDetailsOfficerEmail() { + return clinicalDetailsOfficerEmail; + } + + public void setClinicalDetailsOfficerEmail(String clinicalDetailsOfficerEmail) { + this.clinicalDetailsOfficerEmail = clinicalDetailsOfficerEmail; + } + + @Column + public String getClinicalDetailsOfficerDesignation() { + return clinicalDetailsOfficerDesignation; + } + + public void setClinicalDetailsOfficerDesignation(String clinicalDetailsOfficerDesignation) { + this.clinicalDetailsOfficerDesignation = clinicalDetailsOfficerDesignation; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getClinicalDetailsDateTime() { + return clinicalDetailsDateTime; + } + + public void setClinicalDetailsDateTime(Date clinicalDetailsDateTime) { + this.clinicalDetailsDateTime = clinicalDetailsDateTime; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getPatientReceivedMedicalCare() { + return patientReceivedMedicalCare; + } + + public void setPatientReceivedMedicalCare(YesNoUnknown patientReceivedMedicalCare) { + this.patientReceivedMedicalCare = patientReceivedMedicalCare; + } + + @Column + public String getPatientReceivedMedicalCareDetails() { + return patientReceivedMedicalCareDetails; + } + + public void setPatientReceivedMedicalCareDetails(String patientReceivedMedicalCareDetails) { + this.patientReceivedMedicalCareDetails = patientReceivedMedicalCareDetails; + } + + @Column + public String getProvisionalOrFinalDiagnosis() { + return provisionalOrFinalDiagnosis; + } + + public void setProvisionalOrFinalDiagnosis(String provisionalOrFinalDiagnosis) { + this.provisionalOrFinalDiagnosis = provisionalOrFinalDiagnosis; + } + + @Enumerated(EnumType.STRING) + public AefiImmunizationPeriod getPatientImmunizedPeriod() { + return patientImmunizedPeriod; + } + + public void setPatientImmunizedPeriod(AefiImmunizationPeriod patientImmunizedPeriod) { + this.patientImmunizedPeriod = patientImmunizedPeriod; + } + + @Column + public String getPatientImmunizedPeriodDetails() { + return patientImmunizedPeriodDetails; + } + + public void setPatientImmunizedPeriodDetails(String patientImmunizedPeriodDetails) { + this.patientImmunizedPeriodDetails = patientImmunizedPeriodDetails; + } + + @Enumerated(EnumType.STRING) + public AefiVaccinationPeriod getVaccineGivenPeriod() { + return vaccineGivenPeriod; + } + + public void setVaccineGivenPeriod(AefiVaccinationPeriod vaccineGivenPeriod) { + this.vaccineGivenPeriod = vaccineGivenPeriod; + } + + @Column + public String getVaccineGivenPeriodDetails() { + return vaccineGivenPeriodDetails; + } + + public void setVaccineGivenPeriodDetails(String vaccineGivenPeriodDetails) { + this.vaccineGivenPeriodDetails = vaccineGivenPeriodDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getErrorPrescribingVaccine() { + return errorPrescribingVaccine; + } + + public void setErrorPrescribingVaccine(YesNoUnknown errorPrescribingVaccine) { + this.errorPrescribingVaccine = errorPrescribingVaccine; + } + + @Column + public String getErrorPrescribingVaccineDetails() { + return errorPrescribingVaccineDetails; + } + + public void setErrorPrescribingVaccineDetails(String errorPrescribingVaccineDetails) { + this.errorPrescribingVaccineDetails = errorPrescribingVaccineDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineCouldHaveBeenUnSterile() { + return vaccineCouldHaveBeenUnSterile; + } + + public void setVaccineCouldHaveBeenUnSterile(YesNoUnknown vaccineCouldHaveBeenUnSterile) { + this.vaccineCouldHaveBeenUnSterile = vaccineCouldHaveBeenUnSterile; + } + + @Column + public String getVaccineCouldHaveBeenUnSterileDetails() { + return vaccineCouldHaveBeenUnSterileDetails; + } + + public void setVaccineCouldHaveBeenUnSterileDetails(String vaccineCouldHaveBeenUnSterileDetails) { + this.vaccineCouldHaveBeenUnSterileDetails = vaccineCouldHaveBeenUnSterileDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccinePhysicalConditionAbnormal() { + return vaccinePhysicalConditionAbnormal; + } + + public void setVaccinePhysicalConditionAbnormal(YesNoUnknown vaccinePhysicalConditionAbnormal) { + this.vaccinePhysicalConditionAbnormal = vaccinePhysicalConditionAbnormal; + } + + @Column + public String getVaccinePhysicalConditionAbnormalDetails() { + return vaccinePhysicalConditionAbnormalDetails; + } + + public void setVaccinePhysicalConditionAbnormalDetails(String vaccinePhysicalConditionAbnormalDetails) { + this.vaccinePhysicalConditionAbnormalDetails = vaccinePhysicalConditionAbnormalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getErrorInVaccineReconstitution() { + return errorInVaccineReconstitution; + } + + public void setErrorInVaccineReconstitution(YesNoUnknown errorInVaccineReconstitution) { + this.errorInVaccineReconstitution = errorInVaccineReconstitution; + } + + @Column + public String getErrorInVaccineReconstitutionDetails() { + return errorInVaccineReconstitutionDetails; + } + + public void setErrorInVaccineReconstitutionDetails(String errorInVaccineReconstitutionDetails) { + this.errorInVaccineReconstitutionDetails = errorInVaccineReconstitutionDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getErrorInVaccineHandling() { + return errorInVaccineHandling; + } + + public void setErrorInVaccineHandling(YesNoUnknown errorInVaccineHandling) { + this.errorInVaccineHandling = errorInVaccineHandling; + } + + @Column + public String getErrorInVaccineHandlingDetails() { + return errorInVaccineHandlingDetails; + } + + public void setErrorInVaccineHandlingDetails(String errorInVaccineHandlingDetails) { + this.errorInVaccineHandlingDetails = errorInVaccineHandlingDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineAdministeredIncorrectly() { + return vaccineAdministeredIncorrectly; + } + + public void setVaccineAdministeredIncorrectly(YesNoUnknown vaccineAdministeredIncorrectly) { + this.vaccineAdministeredIncorrectly = vaccineAdministeredIncorrectly; + } + + @Column + public String getVaccineAdministeredIncorrectlyDetails() { + return vaccineAdministeredIncorrectlyDetails; + } + + public void setVaccineAdministeredIncorrectlyDetails(String vaccineAdministeredIncorrectlyDetails) { + this.vaccineAdministeredIncorrectlyDetails = vaccineAdministeredIncorrectlyDetails; + } + + @Column + public Integer getNumberImmunizedFromConcernedVaccineVial() { + return numberImmunizedFromConcernedVaccineVial; + } + + public void setNumberImmunizedFromConcernedVaccineVial(Integer numberImmunizedFromConcernedVaccineVial) { + this.numberImmunizedFromConcernedVaccineVial = numberImmunizedFromConcernedVaccineVial; + } + + @Column + public Integer getNumberImmunizedWithConcernedVaccineInSameSession() { + return numberImmunizedWithConcernedVaccineInSameSession; + } + + public void setNumberImmunizedWithConcernedVaccineInSameSession(Integer numberImmunizedWithConcernedVaccineInSameSession) { + this.numberImmunizedWithConcernedVaccineInSameSession = numberImmunizedWithConcernedVaccineInSameSession; + } + + @Column + public Integer getNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations() { + return numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + } + + public void setNumberImmunizedConcernedVaccineSameBatchNumberOtherLocations( + Integer numberImmunizedConcernedVaccineSameBatchNumberOtherLocations) { + this.numberImmunizedConcernedVaccineSameBatchNumberOtherLocations = numberImmunizedConcernedVaccineSameBatchNumberOtherLocations; + } + + @Column + public String getNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails() { + return numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + } + + public void setNumberImmunizedConcernedVaccineSameBatchNumberLocationDetails( + String numberImmunizedConcernedVaccineSameBatchNumberLocationDetails) { + this.numberImmunizedConcernedVaccineSameBatchNumberLocationDetails = numberImmunizedConcernedVaccineSameBatchNumberLocationDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineHasQualityDefect() { + return vaccineHasQualityDefect; + } + + public void setVaccineHasQualityDefect(YesNoUnknown vaccineHasQualityDefect) { + this.vaccineHasQualityDefect = vaccineHasQualityDefect; + } + + @Column + public String getVaccineHasQualityDefectDetails() { + return vaccineHasQualityDefectDetails; + } + + public void setVaccineHasQualityDefectDetails(String vaccineHasQualityDefectDetails) { + this.vaccineHasQualityDefectDetails = vaccineHasQualityDefectDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getEventIsAStressResponseRelatedToImmunization() { + return eventIsAStressResponseRelatedToImmunization; + } + + public void setEventIsAStressResponseRelatedToImmunization(YesNoUnknown eventIsAStressResponseRelatedToImmunization) { + this.eventIsAStressResponseRelatedToImmunization = eventIsAStressResponseRelatedToImmunization; + } + + @Column + public String getEventIsAStressResponseRelatedToImmunizationDetails() { + return eventIsAStressResponseRelatedToImmunizationDetails; + } + + public void setEventIsAStressResponseRelatedToImmunizationDetails(String eventIsAStressResponseRelatedToImmunizationDetails) { + this.eventIsAStressResponseRelatedToImmunizationDetails = eventIsAStressResponseRelatedToImmunizationDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getCaseIsPartOfACluster() { + return caseIsPartOfACluster; + } + + public void setCaseIsPartOfACluster(YesNoUnknown caseIsPartOfACluster) { + this.caseIsPartOfACluster = caseIsPartOfACluster; + } + + @Column + public String getCaseIsPartOfAClusterDetails() { + return caseIsPartOfAClusterDetails; + } + + public void setCaseIsPartOfAClusterDetails(String caseIsPartOfAClusterDetails) { + this.caseIsPartOfAClusterDetails = caseIsPartOfAClusterDetails; + } + + @Column + public Integer getNumberOfCasesDetectedInCluster() { + return numberOfCasesDetectedInCluster; + } + + public void setNumberOfCasesDetectedInCluster(Integer numberOfCasesDetectedInCluster) { + this.numberOfCasesDetectedInCluster = numberOfCasesDetectedInCluster; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAllCasesInClusterReceivedVaccineFromSameVial() { + return allCasesInClusterReceivedVaccineFromSameVial; + } + + public void setAllCasesInClusterReceivedVaccineFromSameVial(YesNoUnknown allCasesInClusterReceivedVaccineFromSameVial) { + this.allCasesInClusterReceivedVaccineFromSameVial = allCasesInClusterReceivedVaccineFromSameVial; + } + + @Column + public String getAllCasesInClusterReceivedVaccineFromSameVialDetails() { + return allCasesInClusterReceivedVaccineFromSameVialDetails; + } + + public void setAllCasesInClusterReceivedVaccineFromSameVialDetails(String allCasesInClusterReceivedVaccineFromSameVialDetails) { + this.allCasesInClusterReceivedVaccineFromSameVialDetails = allCasesInClusterReceivedVaccineFromSameVialDetails; + } + + @Column + public Integer getNumberOfVialsUsedInCluster() { + return numberOfVialsUsedInCluster; + } + + public void setNumberOfVialsUsedInCluster(Integer numberOfVialsUsedInCluster) { + this.numberOfVialsUsedInCluster = numberOfVialsUsedInCluster; + } + + @Column + public String getNumberOfVialsUsedInClusterDetails() { + return numberOfVialsUsedInClusterDetails; + } + + public void setNumberOfVialsUsedInClusterDetails(String numberOfVialsUsedInClusterDetails) { + this.numberOfVialsUsedInClusterDetails = numberOfVialsUsedInClusterDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAdSyringesUsedForImmunization() { + return adSyringesUsedForImmunization; + } + + public void setAdSyringesUsedForImmunization(YesNoUnknown adSyringesUsedForImmunization) { + this.adSyringesUsedForImmunization = adSyringesUsedForImmunization; + } + + @Enumerated(EnumType.STRING) + public SyringeType getTypeOfSyringesUsed() { + return typeOfSyringesUsed; + } + + public void setTypeOfSyringesUsed(SyringeType typeOfSyringesUsed) { + this.typeOfSyringesUsed = typeOfSyringesUsed; + } + + @Column + public String getTypeOfSyringesUsedDetails() { + return typeOfSyringesUsedDetails; + } + + public void setTypeOfSyringesUsedDetails(String typeOfSyringesUsedDetails) { + this.typeOfSyringesUsedDetails = typeOfSyringesUsedDetails; + } + + @Column + public String getSyringesUsedAdditionalDetails() { + return syringesUsedAdditionalDetails; + } + + public void setSyringesUsedAdditionalDetails(String syringesUsedAdditionalDetails) { + this.syringesUsedAdditionalDetails = syringesUsedAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine() { + return sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + } + + public void setSameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine( + YesNoUnknown sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine) { + this.sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine = sameReconstitutionSyringeUsedForMultipleVialsOfSameVaccine; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines() { + return sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + } + + public void setSameReconstitutionSyringeUsedForReconstitutingDifferentVaccines( + YesNoUnknown sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines) { + this.sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines = sameReconstitutionSyringeUsedForReconstitutingDifferentVaccines; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getSameReconstitutionSyringeForEachVaccineVial() { + return sameReconstitutionSyringeForEachVaccineVial; + } + + public void setSameReconstitutionSyringeForEachVaccineVial(YesNoUnknown sameReconstitutionSyringeForEachVaccineVial) { + this.sameReconstitutionSyringeForEachVaccineVial = sameReconstitutionSyringeForEachVaccineVial; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getSameReconstitutionSyringeForEachVaccination() { + return sameReconstitutionSyringeForEachVaccination; + } + + public void setSameReconstitutionSyringeForEachVaccination(YesNoUnknown sameReconstitutionSyringeForEachVaccination) { + this.sameReconstitutionSyringeForEachVaccination = sameReconstitutionSyringeForEachVaccination; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccinesAndDiluentsUsedRecommendedByManufacturer() { + return vaccinesAndDiluentsUsedRecommendedByManufacturer; + } + + public void setVaccinesAndDiluentsUsedRecommendedByManufacturer(YesNoUnknown vaccinesAndDiluentsUsedRecommendedByManufacturer) { + this.vaccinesAndDiluentsUsedRecommendedByManufacturer = vaccinesAndDiluentsUsedRecommendedByManufacturer; + } + + @Column + public String getReconstitutionAdditionalDetails() { + return reconstitutionAdditionalDetails; + } + + public void setReconstitutionAdditionalDetails(String reconstitutionAdditionalDetails) { + this.reconstitutionAdditionalDetails = reconstitutionAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getCorrectDoseOrRoute() { + return correctDoseOrRoute; + } + + public void setCorrectDoseOrRoute(YesNoUnknown correctDoseOrRoute) { + this.correctDoseOrRoute = correctDoseOrRoute; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getTimeOfReconstitutionMentionedOnTheVial() { + return timeOfReconstitutionMentionedOnTheVial; + } + + public void setTimeOfReconstitutionMentionedOnTheVial(YesNoUnknown timeOfReconstitutionMentionedOnTheVial) { + this.timeOfReconstitutionMentionedOnTheVial = timeOfReconstitutionMentionedOnTheVial; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getNonTouchTechniqueFollowed() { + return nonTouchTechniqueFollowed; + } + + public void setNonTouchTechniqueFollowed(YesNoUnknown nonTouchTechniqueFollowed) { + this.nonTouchTechniqueFollowed = nonTouchTechniqueFollowed; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getContraIndicationScreenedPriorToVaccination() { + return contraIndicationScreenedPriorToVaccination; + } + + public void setContraIndicationScreenedPriorToVaccination(YesNoUnknown contraIndicationScreenedPriorToVaccination) { + this.contraIndicationScreenedPriorToVaccination = contraIndicationScreenedPriorToVaccination; + } + + @Column + public Integer getNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays() { + return numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + } + + public void setNumberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays( + Integer numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays) { + this.numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays = numberOfAefiReportedFromVaccineDistributionCenterLastThirtyDays; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getTrainingReceivedByVaccinator() { + return trainingReceivedByVaccinator; + } + + public void setTrainingReceivedByVaccinator(YesNoUnknown trainingReceivedByVaccinator) { + this.trainingReceivedByVaccinator = trainingReceivedByVaccinator; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getLastTrainingReceivedByVaccinatorDate() { + return lastTrainingReceivedByVaccinatorDate; + } + + public void setLastTrainingReceivedByVaccinatorDate(Date lastTrainingReceivedByVaccinatorDate) { + this.lastTrainingReceivedByVaccinatorDate = lastTrainingReceivedByVaccinatorDate; + } + + @Column + public String getInjectionTechniqueAdditionalDetails() { + return injectionTechniqueAdditionalDetails; + } + + public void setInjectionTechniqueAdditionalDetails(String injectionTechniqueAdditionalDetails) { + this.injectionTechniqueAdditionalDetails = injectionTechniqueAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineStorageRefrigeratorTemperatureMonitored() { + return vaccineStorageRefrigeratorTemperatureMonitored; + } + + public void setVaccineStorageRefrigeratorTemperatureMonitored(YesNoUnknown vaccineStorageRefrigeratorTemperatureMonitored) { + this.vaccineStorageRefrigeratorTemperatureMonitored = vaccineStorageRefrigeratorTemperatureMonitored; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAnyStorageTemperatureDeviationOutsideTwoToEightDegrees() { + return anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + } + + public void setAnyStorageTemperatureDeviationOutsideTwoToEightDegrees(YesNoUnknown anyStorageTemperatureDeviationOutsideTwoToEightDegrees) { + this.anyStorageTemperatureDeviationOutsideTwoToEightDegrees = anyStorageTemperatureDeviationOutsideTwoToEightDegrees; + } + + @Column + public String getStorageTemperatureMonitoringAdditionalDetails() { + return storageTemperatureMonitoringAdditionalDetails; + } + + public void setStorageTemperatureMonitoringAdditionalDetails(String storageTemperatureMonitoringAdditionalDetails) { + this.storageTemperatureMonitoringAdditionalDetails = storageTemperatureMonitoringAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getCorrectProcedureForStorageFollowed() { + return correctProcedureForStorageFollowed; + } + + public void setCorrectProcedureForStorageFollowed(YesNoUnknown correctProcedureForStorageFollowed) { + this.correctProcedureForStorageFollowed = correctProcedureForStorageFollowed; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAnyOtherItemInRefrigerator() { + return anyOtherItemInRefrigerator; + } + + public void setAnyOtherItemInRefrigerator(YesNoUnknown anyOtherItemInRefrigerator) { + this.anyOtherItemInRefrigerator = anyOtherItemInRefrigerator; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getPartiallyUsedReconstitutedVaccinesInRefrigerator() { + return partiallyUsedReconstitutedVaccinesInRefrigerator; + } + + public void setPartiallyUsedReconstitutedVaccinesInRefrigerator(YesNoUnknown partiallyUsedReconstitutedVaccinesInRefrigerator) { + this.partiallyUsedReconstitutedVaccinesInRefrigerator = partiallyUsedReconstitutedVaccinesInRefrigerator; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getUnusableVaccinesInRefrigerator() { + return unusableVaccinesInRefrigerator; + } + + public void setUnusableVaccinesInRefrigerator(YesNoUnknown unusableVaccinesInRefrigerator) { + this.unusableVaccinesInRefrigerator = unusableVaccinesInRefrigerator; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getUnusableDiluentsInStore() { + return unusableDiluentsInStore; + } + + public void setUnusableDiluentsInStore(YesNoUnknown unusableDiluentsInStore) { + this.unusableDiluentsInStore = unusableDiluentsInStore; + } + + @Column + public String getVaccineStoragePointAdditionalDetails() { + return vaccineStoragePointAdditionalDetails; + } + + public void setVaccineStoragePointAdditionalDetails(String vaccineStoragePointAdditionalDetails) { + this.vaccineStoragePointAdditionalDetails = vaccineStoragePointAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public VaccineCarrier getVaccineCarrierType() { + return vaccineCarrierType; + } + + public void setVaccineCarrierType(VaccineCarrier vaccineCarrierType) { + this.vaccineCarrierType = vaccineCarrierType; + } + + @Column + public String getVaccineCarrierTypeDetails() { + return vaccineCarrierTypeDetails; + } + + public void setVaccineCarrierTypeDetails(String vaccineCarrierTypeDetails) { + this.vaccineCarrierTypeDetails = vaccineCarrierTypeDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineCarrierSentToSiteOnSameDateAsVaccination() { + return vaccineCarrierSentToSiteOnSameDateAsVaccination; + } + + public void setVaccineCarrierSentToSiteOnSameDateAsVaccination(YesNoUnknown vaccineCarrierSentToSiteOnSameDateAsVaccination) { + this.vaccineCarrierSentToSiteOnSameDateAsVaccination = vaccineCarrierSentToSiteOnSameDateAsVaccination; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getVaccineCarrierReturnedFromSiteOnSameDateAsVaccination() { + return vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + } + + public void setVaccineCarrierReturnedFromSiteOnSameDateAsVaccination(YesNoUnknown vaccineCarrierReturnedFromSiteOnSameDateAsVaccination) { + this.vaccineCarrierReturnedFromSiteOnSameDateAsVaccination = vaccineCarrierReturnedFromSiteOnSameDateAsVaccination; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getConditionedIcepackUsed() { + return conditionedIcepackUsed; + } + + public void setConditionedIcepackUsed(YesNoUnknown conditionedIcepackUsed) { + this.conditionedIcepackUsed = conditionedIcepackUsed; + } + + @Column + public String getVaccineTransportationAdditionalDetails() { + return vaccineTransportationAdditionalDetails; + } + + public void setVaccineTransportationAdditionalDetails(String vaccineTransportationAdditionalDetails) { + this.vaccineTransportationAdditionalDetails = vaccineTransportationAdditionalDetails; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getSimilarEventsReportedSamePeriodAndLocality() { + return similarEventsReportedSamePeriodAndLocality; + } + + public void setSimilarEventsReportedSamePeriodAndLocality(YesNoUnknown similarEventsReportedSamePeriodAndLocality) { + this.similarEventsReportedSamePeriodAndLocality = similarEventsReportedSamePeriodAndLocality; + } + + @Column + public String getSimilarEventsReportedSamePeriodAndLocalityDetails() { + return similarEventsReportedSamePeriodAndLocalityDetails; + } + + public void setSimilarEventsReportedSamePeriodAndLocalityDetails(String similarEventsReportedSamePeriodAndLocalityDetails) { + this.similarEventsReportedSamePeriodAndLocalityDetails = similarEventsReportedSamePeriodAndLocalityDetails; + } + + @Column + public Integer getNumberOfSimilarEventsReportedSamePeriodAndLocality() { + return numberOfSimilarEventsReportedSamePeriodAndLocality; + } + + public void setNumberOfSimilarEventsReportedSamePeriodAndLocality(Integer numberOfSimilarEventsReportedSamePeriodAndLocality) { + this.numberOfSimilarEventsReportedSamePeriodAndLocality = numberOfSimilarEventsReportedSamePeriodAndLocality; + } + + @Column + public Integer getNumberOfThoseAffectedVaccinated() { + return numberOfThoseAffectedVaccinated; + } + + public void setNumberOfThoseAffectedVaccinated(Integer numberOfThoseAffectedVaccinated) { + this.numberOfThoseAffectedVaccinated = numberOfThoseAffectedVaccinated; + } + + @Column + public Integer getNumberOfThoseAffectedNotVaccinated() { + return numberOfThoseAffectedNotVaccinated; + } + + public void setNumberOfThoseAffectedNotVaccinated(Integer numberOfThoseAffectedNotVaccinated) { + this.numberOfThoseAffectedNotVaccinated = numberOfThoseAffectedNotVaccinated; + } + + @Column + public Integer getNumberOfThoseAffectedVaccinatedUnknown() { + return numberOfThoseAffectedVaccinatedUnknown; + } + + public void setNumberOfThoseAffectedVaccinatedUnknown(Integer numberOfThoseAffectedVaccinatedUnknown) { + this.numberOfThoseAffectedVaccinatedUnknown = numberOfThoseAffectedVaccinatedUnknown; + } + + @Column + public String getCommunityInvestigationAdditionalDetails() { + return communityInvestigationAdditionalDetails; + } + + public void setCommunityInvestigationAdditionalDetails(String communityInvestigationAdditionalDetails) { + this.communityInvestigationAdditionalDetails = communityInvestigationAdditionalDetails; + } + + @Column + public String getOtherInvestigationFindings() { + return otherInvestigationFindings; + } + + public void setOtherInvestigationFindings(String otherInvestigationFindings) { + this.otherInvestigationFindings = otherInvestigationFindings; + } + + @Enumerated(EnumType.STRING) + public AefiInvestigationStatus getInvestigationStatus() { + return investigationStatus; + } + + public void setInvestigationStatus(AefiInvestigationStatus investigationStatus) { + this.investigationStatus = investigationStatus; + } + + @Column + public String getInvestigationStatusDetails() { + return investigationStatusDetails; + } + + public void setInvestigationStatusDetails(String investigationStatusDetails) { + this.investigationStatusDetails = investigationStatusDetails; + } + + @Enumerated(EnumType.STRING) + @Column(name = "adverseeventfollowingimmunizationclassification") + public AefiClassification getAefiClassification() { + return aefiClassification; + } + + public void setAefiClassification(AefiClassification aefiClassification) { + this.aefiClassification = aefiClassification; + } + + @Enumerated(EnumType.STRING) + @Column(name = "adverseeventfollowingimmunizationclassificationsubtype") + public AefiClassificationSubType getAefiClassificationSubType() { + return aefiClassificationSubType; + } + + public void setAefiClassificationSubType(AefiClassificationSubType aefiClassificationSubType) { + this.aefiClassificationSubType = aefiClassificationSubType; + } + + @Column(name = "adverseeventfollowingimmunizationclassificationdetails") + public String getAefiClassificationDetails() { + return aefiClassificationDetails; + } + + public void setAefiClassificationDetails(String aefiClassificationDetails) { + this.aefiClassificationDetails = aefiClassificationDetails; + } + + @Column + public AefiCausality getCausality() { + return causality; + } + + public void setCausality(AefiCausality causality) { + this.causality = causality; + } + + @Column + public String getCausalityDetails() { + return causalityDetails; + } + + public void setCausalityDetails(String causalityDetails) { + this.causalityDetails = causalityDetails; + } + + @Temporal(TemporalType.TIMESTAMP) + public Date getInvestigationCompletionDate() { + return investigationCompletionDate; + } + + public void setInvestigationCompletionDate(Date investigationCompletionDate) { + this.investigationCompletionDate = investigationCompletionDate; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigationJoins.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigationJoins.java new file mode 100644 index 00000000000..03495959759 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiInvestigationJoins.java @@ -0,0 +1,138 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity; + +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; + +import de.symeda.sormas.backend.common.QueryJoins; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.country.Country; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.vaccination.Vaccination; + +public class AefiInvestigationJoins extends QueryJoins { + + private Join aefi; + + private AefiJoins aefiJoins; + private Join address; + private Join primarySuspectVaccination; + private Join reportingUser; + private Join responsibleRegion; + private Join responsibleDistrict; + private Join responsibleCommunity; + private Join country; + private Join vaccinationFacility; + private Join reportingOfficerFacility; + + public AefiInvestigationJoins(From root) { + super(root); + } + + public Join getAefi() { + return getOrCreate(aefi, AefiInvestigation.AEFI_REPORT, JoinType.LEFT, this::setAefi); + } + + public void setAefi(Join aefi) { + this.aefi = aefi; + } + + public AefiJoins getAefiJoins() { + return getOrCreate(aefiJoins, () -> new AefiJoins(getAefi()), this::setAefiJoins); + } + + public void setAefiJoins(AefiJoins aefiJoins) { + this.aefiJoins = aefiJoins; + } + + public Join getAddress() { + return getOrCreate(address, AefiInvestigation.ADDRESS, JoinType.LEFT, this::setAddress); + } + + public void setAddress(Join address) { + this.address = address; + } + + public Join getPrimarySuspectVaccination() { + return getOrCreate(primarySuspectVaccination, AefiInvestigation.PRIMARY_SUSPECT_VACCINE, JoinType.LEFT, this::setPrimarySuspectVaccination); + } + + public void setPrimarySuspectVaccination(Join primarySuspectVaccination) { + this.primarySuspectVaccination = primarySuspectVaccination; + } + + public Join getReportingUser() { + return getOrCreate(reportingUser, AefiInvestigation.REPORTING_USER, JoinType.LEFT, this::setReportingUser); + } + + public void setReportingUser(Join reportingUser) { + this.reportingUser = reportingUser; + } + + public Join getResponsibleRegion() { + return getOrCreate(responsibleRegion, AefiInvestigation.RESPONSIBLE_REGION, JoinType.LEFT, this::setResponsibleRegion); + } + + public void setResponsibleRegion(Join responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + public Join getResponsibleDistrict() { + return getOrCreate(responsibleDistrict, AefiInvestigation.RESPONSIBLE_DISTRICT, JoinType.LEFT, this::setResponsibleDistrict); + } + + public void setResponsibleDistrict(Join responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + public Join getResponsibleCommunity() { + return getOrCreate(responsibleCommunity, AefiInvestigation.RESPONSIBLE_COMMUNITY, JoinType.LEFT, this::setResponsibleCommunity); + } + + public void setResponsibleCommunity(Join responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + public Join getCountry() { + return getOrCreate(country, AefiInvestigation.COUNTRY, JoinType.LEFT, this::setCountry); + } + + public void setCountry(Join country) { + this.country = country; + } + + public Join getVaccinationFacility() { + return getOrCreate(vaccinationFacility, AefiInvestigation.VACCINATION_FACILITY, JoinType.LEFT, this::setVaccinationFacility); + } + + public void setVaccinationFacility(Join vaccinationFacility) { + this.vaccinationFacility = vaccinationFacility; + } + + public Join getReportingOfficerFacility() { + return getOrCreate(reportingOfficerFacility, AefiInvestigation.REPORTING_OFFICER_FACILITY, JoinType.LEFT, this::setReportingOfficerFacility); + } + + public void setReportingOfficerFacility(Join reportingOfficerFacility) { + this.reportingOfficerFacility = reportingOfficerFacility; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiJoins.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiJoins.java new file mode 100644 index 00000000000..e1f29ef65fd --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/entity/AefiJoins.java @@ -0,0 +1,159 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity; + +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; + +import de.symeda.sormas.backend.common.QueryJoins; +import de.symeda.sormas.backend.immunization.ImmunizationJoins; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.community.Community; +import de.symeda.sormas.backend.infrastructure.country.Country; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.person.Person; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.vaccination.Vaccination; + +public class AefiJoins extends QueryJoins { + + private Join immunization; + private Join address; + private Join primarySuspectVaccination; + private Join adverseEvents; + private Join person; + private Join reportingUser; + private Join responsibleRegion; + private Join responsibleDistrict; + private Join responsibleCommunity; + private Join country; + private Join healthFacility; + private Join reporterInstitution; + + private ImmunizationJoins immunizationJoins; + + public AefiJoins(From root) { + super(root); + } + + public Join getImmunization() { + return getOrCreate(immunization, Aefi.IMMUNIZATION, JoinType.LEFT, this::setImmunization); + } + + public void setImmunization(Join immunization) { + this.immunization = immunization; + } + + public ImmunizationJoins getImmunizationJoins() { + return getOrCreate(immunizationJoins, () -> new ImmunizationJoins(getImmunization()), this::setImmunizationJoins); + } + + public void setImmunizationJoins(ImmunizationJoins immunizationJoins) { + this.immunizationJoins = immunizationJoins; + } + + public Join getAddress() { + return getOrCreate(address, Aefi.ADDRESS, JoinType.LEFT, this::setAddress); + } + + public void setAddress(Join address) { + this.address = address; + } + + public Join getPrimarySuspectVaccination() { + return getOrCreate(primarySuspectVaccination, Aefi.PRIMARY_SUSPECT_VACCINE, JoinType.LEFT, this::setPrimarySuspectVaccination); + } + + public void setPrimarySuspectVaccination(Join primarySuspectVaccination) { + this.primarySuspectVaccination = primarySuspectVaccination; + } + + public Join getAdverseEvents() { + return getOrCreate(adverseEvents, Aefi.ADVERSE_EVENTS, JoinType.LEFT, this::setAdverseEvents); + } + + public void setAdverseEvents(Join adverseEvents) { + this.adverseEvents = adverseEvents; + } + + public Join getPerson() { + return getOrCreate(person, Aefi.PERSON, JoinType.LEFT, this::setPerson); + } + + public void setPerson(Join person) { + this.person = person; + } + + public Join getReportingUser() { + return getOrCreate(reportingUser, Aefi.REPORTING_USER, JoinType.LEFT, this::setReportingUser); + } + + public void setReportingUser(Join reportingUser) { + this.reportingUser = reportingUser; + } + + public Join getResponsibleRegion() { + return getOrCreate(responsibleRegion, Aefi.RESPONSIBLE_REGION, JoinType.LEFT, this::setResponsibleRegion); + } + + public void setResponsibleRegion(Join responsibleRegion) { + this.responsibleRegion = responsibleRegion; + } + + public Join getResponsibleDistrict() { + return getOrCreate(responsibleDistrict, Aefi.RESPONSIBLE_DISTRICT, JoinType.LEFT, this::setResponsibleDistrict); + } + + public void setResponsibleDistrict(Join responsibleDistrict) { + this.responsibleDistrict = responsibleDistrict; + } + + public Join getResponsibleCommunity() { + return getOrCreate(responsibleCommunity, Aefi.RESPONSIBLE_COMMUNITY, JoinType.LEFT, this::setResponsibleCommunity); + } + + public void setResponsibleCommunity(Join responsibleCommunity) { + this.responsibleCommunity = responsibleCommunity; + } + + public Join getCountry() { + return getOrCreate(country, Aefi.COUNTRY, JoinType.LEFT, this::setCountry); + } + + public void setCountry(Join country) { + this.country = country; + } + + public Join getHealthFacility() { + return getOrCreate(healthFacility, Aefi.HEALTH_FACILITY, JoinType.LEFT, this::setHealthFacility); + } + + public void setHealthFacility(Join healthFacility) { + this.healthFacility = healthFacility; + } + + public Join getReporterInstitution() { + return getOrCreate(reporterInstitution, Aefi.REPORTING_OFFICER_FACILITY, JoinType.LEFT, this::setReporterInstitution); + } + + public void setReporterInstitution(Join reporterInstitution) { + this.reporterInstitution = reporterInstitution; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiIndexDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiIndexDtoResultTransformer.java new file mode 100644 index 00000000000..c2173e84654 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiIndexDtoResultTransformer.java @@ -0,0 +1,84 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers; + +import java.util.Date; +import java.util.List; + +import org.hibernate.transform.ResultTransformer; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiHelper; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiOutcome; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeizureType; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.person.ApproximateAgeType; +import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.YesNoUnknown; + +public class AefiIndexDtoResultTransformer implements ResultTransformer { + + @Override + public Object transformTuple(Object[] objects, String[] strings) { + + Integer age = objects[6] != null ? (int) objects[6] : null; + ApproximateAgeType approximateAgeType = (ApproximateAgeType) objects[7]; + Integer birthdateDD = objects[8] != null ? (int) objects[8] : null; + Integer birthdateMM = objects[9] != null ? (int) objects[9] : null; + Integer birthdateYYYY = objects[10] != null ? (int) objects[10] : null; + + //@formatter:off + String adverseEvents = AefiHelper + .buildAdverseEventsString((AdverseEventState) objects[21], (boolean) objects[22], (boolean) objects[23], + (AdverseEventState) objects[24], (SeizureType) objects[25], (AdverseEventState) objects[26], + (AdverseEventState) objects[27], (AdverseEventState) objects[28], (AdverseEventState) objects[29], + (AdverseEventState) objects[30], (AdverseEventState) objects[31], (AdverseEventState) objects[32], + (String) objects[33]); + //@formatter:on + + return new AefiIndexDto( + (String) objects[0], + (String) objects[1], + (String) objects[3], + (String) objects[4], + (String) objects[5], + (Disease) objects[2], + new AgeAndBirthDateDto(age, approximateAgeType, birthdateDD, birthdateMM, birthdateYYYY), + (Sex) objects[11], + (String) objects[12], + (String) objects[13], + (YesNoUnknown) objects[14], + (Vaccine) objects[15], + (String) objects[16], + (AefiOutcome) objects[17], + (Date) objects[18], + (Date) objects[19], + (Date) objects[20], + adverseEvents, + (DeletionReason) objects[34], + (String) objects[35], + (boolean) objects[36]); + } + + @Override + public List transformList(List list) { + return list; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationIndexDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationIndexDtoResultTransformer.java new file mode 100644 index 00000000000..51e2e29fa19 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationIndexDtoResultTransformer.java @@ -0,0 +1,84 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers; + +import java.util.Date; +import java.util.List; + +import org.hibernate.transform.ResultTransformer; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationIndexDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStage; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PatientStatusAtAefiInvestigation; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PlaceOfVaccination; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationActivity; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationSite; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.person.ApproximateAgeType; +import de.symeda.sormas.api.person.Sex; + +public class AefiInvestigationIndexDtoResultTransformer implements ResultTransformer { + + @Override + public Object transformTuple(Object[] objects, String[] strings) { + + Integer age = objects[6] != null ? (int) objects[6] : null; + ApproximateAgeType approximateAgeType = (ApproximateAgeType) objects[7]; + Integer birthdateDD = objects[8] != null ? (int) objects[8] : null; + Integer birthdateMM = objects[9] != null ? (int) objects[9] : null; + Integer birthdateYYYY = objects[10] != null ? (int) objects[10] : null; + + return new AefiInvestigationIndexDto( + (String) objects[0], + (String) objects[1], + (String) objects[2], + (Disease) objects[3], + (String) objects[4], + (String) objects[5], + new AgeAndBirthDateDto(age, approximateAgeType, birthdateDD, birthdateMM, birthdateYYYY), + (Sex) objects[11], + (String) objects[12], + (String) objects[13], + (PlaceOfVaccination) objects[14], + (VaccinationActivity) objects[15], + (Date) objects[16], + (Date) objects[17], + (Date) objects[18], + (AefiInvestigationStage) objects[19], + (VaccinationSite) objects[20], + (Date) objects[21], + (Date) objects[22], + (Date) objects[23], + (PatientStatusAtAefiInvestigation) objects[24], + (Vaccine) objects[25], + (String) objects[26], + (AefiInvestigationStatus) objects[27], + (AefiClassification) objects[28], + (DeletionReason) objects[29], + (String) objects[30], + (boolean) objects[31]); + } + + @Override + public List transformList(List list) { + return list; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationListEntryDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationListEntryDtoResultTransformer.java new file mode 100644 index 00000000000..e22f380b2d7 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiInvestigationListEntryDtoResultTransformer.java @@ -0,0 +1,53 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers; + +import java.util.Date; +import java.util.List; + +import org.hibernate.transform.ResultTransformer; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStage; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PatientStatusAtAefiInvestigation; +import de.symeda.sormas.api.caze.Vaccine; + +public class AefiInvestigationListEntryDtoResultTransformer implements ResultTransformer { + + @Override + public Object transformTuple(Object[] objects, String[] strings) { + + return new AefiInvestigationListEntryDto( + (String) objects[0], + (String) objects[1], + (Date) objects[2], + (AefiInvestigationStage) objects[3], + (PatientStatusAtAefiInvestigation) objects[4], + (Vaccine) objects[5], + (String) objects[6], + (String) objects[7], + (Date) objects[8], + (AefiInvestigationStatus) objects[9], + (AefiClassification) objects[10]); + } + + @Override + public List transformList(List list) { + return list; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiListEntryDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiListEntryDtoResultTransformer.java new file mode 100644 index 00000000000..02e9082cace --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/adverseeventsfollowingimmunization/transformers/AefiListEntryDtoResultTransformer.java @@ -0,0 +1,60 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.adverseeventsfollowingimmunization.transformers; + +import java.util.Date; +import java.util.List; + +import org.hibernate.transform.ResultTransformer; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiHelper; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeizureType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.utils.YesNoUnknown; + +public class AefiListEntryDtoResultTransformer implements ResultTransformer { + + @Override + public Object transformTuple(Object[] objects, String[] strings) { + + //@formatter:off + String adverseEvents = AefiHelper + .buildAdverseEventsString((AdverseEventState) objects[5], (boolean) objects[6], (boolean) objects[7], + (AdverseEventState) objects[8], (SeizureType) objects[9], (AdverseEventState) objects[10], + (AdverseEventState) objects[11], (AdverseEventState) objects[12], (AdverseEventState) objects[13], + (AdverseEventState) objects[14], (AdverseEventState) objects[15], (AdverseEventState) objects[16], + (String) objects[17]); + //@formatter:on + + return new AefiListEntryDto( + (String) objects[0], + (YesNoUnknown) objects[1], + (Vaccine) objects[2], + (String) objects[3], + (Date) objects[4], + adverseEvents); + } + + @Override + public List transformList(List list) { + return list; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/bagexport/BAGExportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/bagexport/BAGExportFacadeEjb.java index c477fa6d7df..ec36a2e45e1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/bagexport/BAGExportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/bagexport/BAGExportFacadeEjb.java @@ -106,7 +106,7 @@ public List getCaseExportList(Collection selectedRows, person.get(Person.BIRTHDATE_DD), person.get(Person.BIRTHDATE_MM), person.get(Person.BIRTHDATE_YYYY), - person.get(Person.OCCUPATION_TYPE), + person.get(Person.OCCUPATION_TYPE_VALUE), caseJoins.getSymptoms().get(Symptoms.SYMPTOMATIC), caseJoins.getSymptoms().get(Symptoms.ONSET_DATE), @@ -264,7 +264,7 @@ public List getContactExportList(Collection selecte person.get(Person.BIRTHDATE_DD), person.get(Person.BIRTHDATE_MM), person.get(Person.BIRTHDATE_YYYY), - person.get(Person.OCCUPATION_TYPE), + person.get(Person.OCCUPATION_TYPE_VALUE), contactRoot.get(Contact.QUARANTINE), contactRoot.get(Contact.QUARANTINE_TYPE_DETAILS), caze.get(Case.CASE_ID_ISM), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java index 09e8f58644e..c1cb44119f9 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java @@ -29,7 +29,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -42,7 +41,6 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; -import de.symeda.sormas.backend.selfreport.SelfReport; import org.hibernate.annotations.Type; import de.symeda.sormas.api.Disease; @@ -70,6 +68,7 @@ import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.contact.QuarantineType; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.externaldata.HasExternalData; import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.utils.PersonalData; @@ -81,7 +80,6 @@ import de.symeda.sormas.backend.clinicalcourse.HealthConditions; import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.epidata.EpiData; import de.symeda.sormas.backend.event.EventParticipant; import de.symeda.sormas.backend.hospitalization.Hospitalization; @@ -92,6 +90,7 @@ import de.symeda.sormas.backend.infrastructure.region.Region; import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.sample.Sample; +import de.symeda.sormas.backend.selfreport.SelfReport; import de.symeda.sormas.backend.share.ExternalShareInfo; import de.symeda.sormas.backend.sormastosormas.entities.SormasToSormasShareable; import de.symeda.sormas.backend.sormastosormas.origin.SormasToSormasOriginInfo; @@ -123,7 +122,7 @@ public class Case extends CoreAdo implements IsCase, SormasToSormasShareable, Ha public static final String PERSON = "person"; public static final String PERSON_ID = "personId"; public static final String DISEASE = "disease"; - public static final String DISEASE_VARIANT = "diseaseVariant"; + public static final String DISEASE_VARIANT_VALUE = "diseaseVariantValue"; public static final String DISEASE_DETAILS = "diseaseDetails"; public static final String DISEASE_VARIANT_DETAILS = "diseaseVariantDetails"; public static final String PLAGUE_TYPE = "plagueType"; @@ -250,6 +249,7 @@ public class Case extends CoreAdo implements IsCase, SormasToSormasShareable, Ha private Person person; private String description; private Disease disease; + private String diseaseVariantValue; private DiseaseVariant diseaseVariant; private String diseaseDetails; private String diseaseVariantDetails; @@ -478,14 +478,24 @@ public void setDisease(Disease disease) { this.disease = disease; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "diseasevariant") + public String getDiseaseVariantValue() { + return diseaseVariantValue; + } + + public void setDiseaseVariantValue(String diseaseVariantValue) { + this.diseaseVariantValue = diseaseVariantValue; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariantValue); + } + + @Transient public DiseaseVariant getDiseaseVariant() { return diseaseVariant; } public void setDiseaseVariant(DiseaseVariant diseaseVariant) { this.diseaseVariant = diseaseVariant; + this.diseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); } @Column(length = CHARACTER_LIMIT_DEFAULT) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index a698d2c3ba4..3e59a8302cb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -801,7 +801,7 @@ public List getExportList( joins.getHospitalization().get(Hospitalization.ID), joins.getRoot().get(Case.HEALTH_CONDITIONS).get(HealthConditions.ID), caseRoot.get(Case.UUID), - caseRoot.get(Case.EPID_NUMBER), caseRoot.get(Case.DISEASE), caseRoot.get(Case.DISEASE_VARIANT), caseRoot.get(Case.DISEASE_DETAILS), + caseRoot.get(Case.EPID_NUMBER), caseRoot.get(Case.DISEASE), caseRoot.get(Case.DISEASE_VARIANT_VALUE), caseRoot.get(Case.DISEASE_DETAILS), caseRoot.get(Case.DISEASE_VARIANT_DETAILS), joins.getPerson().get(Person.UUID), joins.getPerson().get(Person.FIRST_NAME), joins.getPerson().get(Person.LAST_NAME), joins.getPerson().get(Person.SALUTATION), joins.getPerson().get(Person.OTHER_SALUTATION), joins.getPerson().get(Person.SEX), caseRoot.get(Case.PREGNANT), joins.getPerson().get(Person.APPROXIMATE_AGE), @@ -852,7 +852,7 @@ public List getExportList( caseQueryContext.getSubqueryExpression(CaseQueryContext.PERSON_EMAIL_SUBQUERY), caseQueryContext.getSubqueryExpression(CaseQueryContext.PERSON_OTHER_CONTACT_DETAILS_SUBQUERY), joins.getPerson().get(Person.EDUCATION_TYPE), - joins.getPerson().get(Person.EDUCATION_DETAILS), joins.getPerson().get(Person.OCCUPATION_TYPE), + joins.getPerson().get(Person.EDUCATION_DETAILS), joins.getPerson().get(Person.OCCUPATION_TYPE_VALUE), joins.getPerson().get(Person.OCCUPATION_DETAILS), joins.getPerson().get(Person.ARMED_FORCES_RELATION_TYPE), joins.getEpiData().get(EpiData.CONTACT_WITH_SOURCE_CASE_KNOWN), caseRoot.get(Case.VACCINATION_STATUS), caseRoot.get(Case.POSTPARTUM), caseRoot.get(Case.TRIMESTER), eventCountSq, @@ -2066,7 +2066,8 @@ private void updateTasksOnCaseChanged(Case newCase, CaseDataDto existingCase) { @PermitAll public void onCaseSampleChanged(Case associatedCase) { // Update case classification if the feature is enabled - if (configFacade.getCaseClassificationCalculationMode(associatedCase.getDisease()).isAutomaticEnabled()) { + if (configFacade.getCaseClassificationCalculationMode(associatedCase.getDisease()).isAutomaticEnabled() + & associatedCase.getDisease() != Disease.RESPIRATORY_SYNCYTIAL_VIRUS) { if (associatedCase.getCaseClassification() != CaseClassification.NO_CASE) { Long pathogenTestsCount = pathogenTestService.countByCase(associatedCase); if (pathogenTestsCount == 0) { @@ -2200,8 +2201,14 @@ public void onCaseChanged(CaseDataDto existingCase, Case newCase, boolean syncSh service.updateFollowUpDetails(newCase, existingCase != null && newCase.getFollowUpStatus() != existingCase.getFollowUpStatus()); updateTasksOnCaseChanged(newCase, existingCase); - - handleClassificationOnCaseChange(existingCase, newCase); + if ((existingCase == null || existingCase.getDisease() != newCase.getDisease()) + && newCase.getDisease() == Disease.RESPIRATORY_SYNCYTIAL_VIRUS) { + newCase.setCaseClassification(CaseClassification.CONFIRMED); + newCase.setClassificationDate(newCase.getReportDate()); + newCase.setClassificationUser(newCase.getReportingUser()); + } else { + handleClassificationOnCaseChange(existingCase, newCase); + } // Set Yes/No/Unknown fields associated with embedded lists to Yes if the lists // are not empty @@ -2263,7 +2270,8 @@ private void handleClassificationOnCaseChange(CaseDataDto existingDto, Case save // Update case classification if the feature is enabled CaseClassification classification = null; boolean setClassificationInfo = true; - if (configFacade.getCaseClassificationCalculationMode(savedCase.getDisease()).isAutomaticEnabled()) { + if (configFacade.getCaseClassificationCalculationMode(savedCase.getDisease()).isAutomaticEnabled() + & savedCase.getDisease() != Disease.RESPIRATORY_SYNCYTIAL_VIRUS) { if (savedCase.getCaseClassification() != CaseClassification.NO_CASE || configFacade.isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)) { // calculate classification @@ -4168,7 +4176,8 @@ public List getCaseFollowUpList( private Pseudonymizer createPseudonymizerForDtoWithClinician( @Nullable String pseudonymizedValue, Collection cases) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, createSpecialAccessChecker(cases), pseudonymizedValue); + Pseudonymizer pseudonymizer = + Pseudonymizer.getDefault(userService, createSpecialAccessChecker(cases), pseudonymizedValue, configFacade.getCountryCode()); UserRightFieldAccessChecker clinicianViewRightChecker = new UserRightFieldAccessChecker<>(UserRight.CASE_CLINICIAN_VIEW, userService.hasRight(UserRight.CASE_CLINICIAN_VIEW)); @@ -4179,12 +4188,12 @@ private Pseudonymizer createPseudonymizerForDtoWithClinici @PermitAll public Pseudonymizer createSimplePseudonymizer(Collection cases) { - return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(cases)); + return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(cases), configFacade.getCountryCode()); } @PermitAll public Pseudonymizer createSimplePlaceholderPseudonymizer(Collection cases) { - return Pseudonymizer.getDefaultWithPlaceHolder(userService, createSpecialAccessChecker(cases)); + return Pseudonymizer.getDefaultWithPlaceHolder(userService, createSpecialAccessChecker(cases), configFacade.getCountryCode()); } private AnnotationBasedFieldAccessChecker.SpecialAccessCheck createSpecialAccessChecker( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDetailedDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDetailedDtoResultTransformer.java index 09c6e5f68f6..30160c17219 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDetailedDtoResultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDetailedDtoResultTransformer.java @@ -45,7 +45,7 @@ public CaseIndexDetailedDto transformTuple(Object[] tuple, String[] aliases) { //@formatter:off return new CaseIndexDetailedDto((Long)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (Disease)tuple[++index], - (DiseaseVariant) tuple[++index], (String)tuple[++index], (CaseClassification)tuple[++index], (InvestigationStatus)tuple[++index], + (String) tuple[++index], (String)tuple[++index], (CaseClassification)tuple[++index], (InvestigationStatus)tuple[++index], (PresentCondition)tuple[++index], (Date)tuple[++index], (Date)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (CaseOutcome) tuple[++index], diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDtoResultTransformer.java index 2340b0bec49..3463a6e0904 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDtoResultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseIndexDtoResultTransformer.java @@ -44,7 +44,7 @@ public CaseIndexDto transformTuple(Object[] tuple, String[] aliases) { //@formatter:off return new CaseIndexDto((Long)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (Disease)tuple[++index], - (DiseaseVariant) tuple[++index], (String)tuple[++index], (CaseClassification)tuple[++index], (InvestigationStatus)tuple[++index], + (String) tuple[++index], (String)tuple[++index], (CaseClassification)tuple[++index], (InvestigationStatus)tuple[++index], (PresentCondition)tuple[++index], (Date)tuple[++index], (Date)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (String)tuple[++index], (CaseOutcome) tuple[++index], diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseListCriteriaBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseListCriteriaBuilder.java index 0b23bd5dd0c..887e5494375 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseListCriteriaBuilder.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseListCriteriaBuilder.java @@ -219,7 +219,7 @@ public List> getCaseIndexSelections(From root, CaseQueryCo joins.getPerson().get(Person.FIRST_NAME), joins.getPerson().get(Person.LAST_NAME), root.get(Case.DISEASE), - root.get(Case.DISEASE_VARIANT), + root.get(Case.DISEASE_VARIANT_VALUE), root.get(Case.DISEASE_DETAILS), root.get(Case.CASE_CLASSIFICATION), root.get(Case.INVESTIGATION_STATUS), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 4d4d35ab8aa..ae3fe83e966 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -31,6 +31,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import javax.annotation.Nullable; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; @@ -177,6 +178,7 @@ import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserRole; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.BirthdateRangeFilterPredicate; import de.symeda.sormas.backend.util.ExternalDataUtil; import de.symeda.sormas.backend.util.IterableHelper; import de.symeda.sormas.backend.util.JurisdictionHelper; @@ -684,7 +686,7 @@ public Predicate createCriteriaFilter(CaseCrite filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Case.DISEASE), caseCriteria.getDisease())); } if (caseCriteria.getDiseaseVariant() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Case.DISEASE_VARIANT), caseCriteria.getDiseaseVariant())); + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Case.DISEASE_VARIANT_VALUE), caseCriteria.getDiseaseVariant().getValue())); } if (caseCriteria.getOutcome() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Case.OUTCOME), caseCriteria.getOutcome())); @@ -912,6 +914,15 @@ public Predicate createCriteriaFilter(CaseCrite filter = CriteriaBuilderHelper.and(cb, filter, likeFilters); } } + + filter = BirthdateRangeFilterPredicate.createBirthdateRangeFilter( + caseCriteria.getBirthdateFrom(), + caseCriteria.getBirthdateTo(), + caseCriteria.isIncludePartialMatch(), + cb, + joins.getPerson(), + filter); + if (caseCriteria.getBirthdateYYYY() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(joins.getPerson().get(Person.BIRTHDATE_YYYY), caseCriteria.getBirthdateYYYY())); } @@ -1033,7 +1044,7 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, From root) { } @Override - public void deletePermanent(Case caze) { + public boolean deletePermanent(Case caze) { // Delete all tasks associated with this case Optional.ofNullable(caze.getTasks()).ifPresent(tl -> tl.forEach(t -> taskService.deletePermanent(t))); @@ -1111,6 +1122,7 @@ public void deletePermanent(Case caze) { deleteCaseLinks(caze); super.deletePermanent(caze); + return false; } private void initVisitSubqueryForDeletion(CriteriaBuilder cb, Root visitRoot, Subquery contactVisitsSubquery) { @@ -2204,7 +2216,8 @@ public PreviousCaseDto getMostRecentPreviousCase(String personUuid, Disease dise root.get(AbstractDomainObject.UUID), root.get(Case.REPORT_DATE), root.get(Case.EXTERNAL_TOKEN), - root.get(Case.DISEASE_VARIANT), + root.get(Case.DISEASE), + root.get(Case.DISEASE_VARIANT_VALUE), symptomsJoin.get(Symptoms.ONSET_DATE)); cq.where( @@ -2334,7 +2347,9 @@ protected String getDeleteReferenceField(DeletionReference deletionReference) { return super.getDeleteReferenceField(deletionReference); } - public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease disease, int threshold) { + public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease disease, @Nullable Date sampleDateTime, int threshold) { + Date dateToCompareTo = sampleDateTime != null ? sampleDateTime : new Date(); + CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(String.class); Root caseRoot = cq.from(Case.class); @@ -2355,7 +2370,7 @@ public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease ExtendedPostgreSQL94Dialect.DATE, Date.class, CriteriaBuilderHelper.coalesce(cb, Date.class, earliestSampleSq, caseRoot.get(Case.REPORT_DATE))), - cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(new Date()))), + cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(dateToCompareTo))), Long.valueOf(TimeUnit.DAYS.toSeconds(threshold)).doubleValue())); cq.orderBy(cb.desc(caseRoot.get(Case.REPORT_DATE))); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/porthealthinfo/PortHealthInfoFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/porthealthinfo/PortHealthInfoFacadeEjb.java index 941f1d44268..e42bb80b028 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/porthealthinfo/PortHealthInfoFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/porthealthinfo/PortHealthInfoFacadeEjb.java @@ -7,6 +7,7 @@ import de.symeda.sormas.api.caze.porthealthinfo.PortHealthInfoDto; import de.symeda.sormas.api.caze.porthealthinfo.PortHealthInfoFacade; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; import de.symeda.sormas.backend.util.Pseudonymizer; @@ -18,6 +19,8 @@ public class PortHealthInfoFacadeEjb implements PortHealthInfoFacade { private PortHealthInfoService portHealthInfoService; @EJB private UserService userService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; public static PortHealthInfoDto toDto(PortHealthInfo source) { if (source == null) { @@ -89,7 +92,7 @@ public PortHealthInfoDto getByCaseUuid(String caseUuid) { } private PortHealthInfoDto toPseudonymizedDto(PortHealthInfo portHealthInfo) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); PortHealthInfoDto portHealthInfoDto = toDto(portHealthInfo); pseudonymizer.pseudonymizeDto(PortHealthInfoDto.class, portHealthInfoDto, portHealthInfoService.inJurisdictionOrOwned(portHealthInfo), null); return portHealthInfoDto; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/surveillancereport/SurveillanceReportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/surveillancereport/SurveillanceReportFacadeEjb.java index 53d7addf02e..4d9bc572eb7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/surveillancereport/SurveillanceReportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/surveillancereport/SurveillanceReportFacadeEjb.java @@ -51,6 +51,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractBaseEjb; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.externalmessage.ExternalMessageFacadeEjb.ExternalMessageFacadeEjbLocal; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; import de.symeda.sormas.backend.infrastructure.district.DistrictService; @@ -102,6 +103,8 @@ public class SurveillanceReportFacadeEjb private SormasToSormasCaseFacadeEjbLocal sormasToSormasCaseFacade; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; public SurveillanceReportFacadeEjb() { super(); @@ -198,7 +201,7 @@ protected SurveillanceReportReferenceDto toRefDto(SurveillanceReport surveillanc @Override protected Pseudonymizer createPseudonymizer(List surveillanceReports) { List withSpecialAccess = specialCaseAccessService.getSurveillanceReportUuidsWithSpecialAccess(surveillanceReports); - return Pseudonymizer.getDefault(userService, r -> withSpecialAccess.contains(r.getUuid())); + return Pseudonymizer.getDefault(userService, r -> withSpecialAccess.contains(r.getUuid()), configFacade.getCountryCode()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java index 4133237fad0..d830f08488d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java @@ -42,6 +42,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.symptoms.Symptoms; @@ -78,6 +79,8 @@ public class ClinicalVisitFacadeEjb implements ClinicalVisitFacade { private CaseService caseService; @EJB private SymptomsService symptomsService; + @EJB + private ConfigFacadeEjbLocal configFacade; // private String countPositiveSymptomsQuery; @@ -159,7 +162,7 @@ public List getIndexList(ClinicalVisitCriteria criteria, List results = QueryHelper.getResultList(em, cq, first, max); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(ClinicalVisitIndexDto.class, results, ClinicalVisitIndexDto::getInJurisdiction, null); // Build the query to count positive symptoms @@ -209,7 +212,7 @@ public List getIndexList(ClinicalVisitCriteria criteria, @Override public ClinicalVisitDto getClinicalVisitByUuid(String uuid) { - return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService)); + return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override @@ -244,7 +247,7 @@ private ClinicalVisitDto saveClinicalVisit(ClinicalVisitDto clinicalVisit, Strin caseFacade.save(caze); } - return convertToDto(entity, Pseudonymizer.getDefault(userService)); + return convertToDto(entity, Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } /** @@ -286,7 +289,7 @@ public List getAllActiveClinicalVisitsAfter(Date date, Integer private List toPseudonymizedDtos(List entities) { List inJurisdictionIds = service.getInJurisdictionIds(entities); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); List dtos = entities.stream().map(p -> convertToDto(p, pseudonymizer, inJurisdictionIds.contains(p.getId()))).collect(Collectors.toList()); return dtos; @@ -294,7 +297,7 @@ private List toPseudonymizedDtos(List entities) @Override public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); return service.getByUuids(uuids).stream().map(t -> convertToDto(t, pseudonymizer)).collect(Collectors.toList()); } @@ -340,7 +343,7 @@ public List getExportList(CaseCriteria criteria, Collect List resultList = QueryHelper.getResultList(em, cq, first, max); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); for (ClinicalVisitExportDto exportDto : resultList) { exportDto.setSymptoms(SymptomsFacadeEjb.toSymptomsDto(symptomsService.getById(exportDto.getSymptomsId()))); @@ -382,7 +385,7 @@ private void pseudonymizeDto(ClinicalVisit source, ClinicalVisitDto dto, Pseudon private void restorePseudonymizedDto(ClinicalVisitDto clinicalVisit, ClinicalVisit existingClinicalVisit) { if (existingClinicalVisit != null) { boolean inJurisdiction = caseService.inJurisdictionOrOwned(existingClinicalVisit.getClinicalCourse().getCaze()); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); ClinicalVisitDto existingDto = toDto(existingClinicalVisit); pseudonymizer.restorePseudonymizedValues(ClinicalVisitDto.class, clinicalVisit, existingDto, inJurisdiction); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java index 07b968e4974..c6bdfd09d65 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java @@ -35,6 +35,8 @@ public abstract class AbstractBaseEjb adoClass; protected Class dtoClass; + @Inject + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; protected AbstractBaseEjb() { } @@ -141,23 +143,25 @@ protected Pseudonymizer createPseudonymizer(ADO ado) { } protected Pseudonymizer createPseudonymizer(List adoList) { - return Pseudonymizer.getDefault(userService); + return Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); } protected Pseudonymizer createGenericPseudonymizer() { - return Pseudonymizer.getDefault(userService); + return Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); } protected Pseudonymizer createGenericPseudonymizer(SpecialAccessCheck specialAccessCheck) { - return Pseudonymizer.getDefault(userService, specialAccessCheck); + return Pseudonymizer.getDefault(userService, specialAccessCheck, configFacade.getCountryCode()); } protected Pseudonymizer createGenericPlaceholderPseudonymizer() { - return Pseudonymizer.getDefault(userService, I18nProperties.getCaption(Captions.inaccessibleValue)); + return Pseudonymizer.getDefault(userService, I18nProperties.getCaption(Captions.inaccessibleValue), configFacade.getCountryCode()); } protected Pseudonymizer createGenericPlaceholderPseudonymizer(SpecialAccessCheck specialAccessCheck) { - return Pseudonymizer.getDefault(userService, specialAccessCheck, I18nProperties.getCaption(Captions.inaccessibleValue)); + Pseudonymizer aDefault = Pseudonymizer + .getDefault(userService, specialAccessCheck, I18nProperties.getCaption(Captions.inaccessibleValue), configFacade.getCountryCode()); + return aDefault; } protected abstract ADO fillOrBuildEntity(@NotNull DTO source, ADO target, boolean checkChangeDate); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoService.java index 111cd6abb80..a625f731622 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoService.java @@ -34,10 +34,11 @@ public interface AdoService { /** * DELETES an entity from the database! - * + * * @param ado + * @return */ - void deletePermanent(ADO ado); + boolean deletePermanent(ADO ado); /** * Speichert ein neues Objekt in der Datenbank. diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java index f1fb15356d4..1b022714d67 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java @@ -517,9 +517,10 @@ public void persist(ADO persistme) { } @Override - public void deletePermanent(ADO ado) { + public boolean deletePermanent(ADO ado) { em.remove(em.contains(ado) ? ado : em.merge(ado)); // todo: investigate why the entity might be detached (example: AdditionalTest) em.flush(); + return false; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java index affeadc8726..96ccbf3388a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java @@ -187,6 +187,7 @@ public class ConfigFacadeEjb implements ConfigFacade { public static final int DEFAULT_DOCUMENT_UPLOAD_SIZE_LIMIT_MB = 20; public static final String IMPORT_FILE_SIZE_LIMIT_MB = "importFileSizeLimitMb"; public static final int DEFAULT_IMPOR_FILE_SIZE_LIMIT_MB = 20; + public static final String NEGATIVE_COVID_TESTS_MAX_AGE_DAYS = "negativeCovidTestsMaxAgeDays"; private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -838,6 +839,11 @@ public void resetRequestContext() { RequestContextHolder.reset(); } + @Override + public Integer getNegaiveCovidTestsMaxAgeDays() { + return parseProperty(NEGATIVE_COVID_TESTS_MAX_AGE_DAYS, null, Integer::parseInt); + } + @LocalBean @Stateless public static class ConfigFacadeEjbLocal extends ConfigFacadeEjb { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java index ec8e92357c2..dd443441e71 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java @@ -48,6 +48,7 @@ import de.symeda.sormas.backend.immunization.ImmunizationFacadeEjb; import de.symeda.sormas.backend.infrastructure.central.CentralInfraSyncFacade; import de.symeda.sormas.backend.report.WeeklyReportFacadeEjb.WeeklyReportFacadeEjbLocal; +import de.symeda.sormas.backend.sample.SampleService; import de.symeda.sormas.backend.specialcaseaccess.SpecialCaseAccessFacadeEjb.SpecialCaseAccessFacadeEjbLocal; import de.symeda.sormas.backend.systemevent.SystemEventFacadeEjb.SystemEventFacadeEjbLocal; import de.symeda.sormas.backend.task.TaskFacadeEjb.TaskFacadeEjbLocal; @@ -96,6 +97,8 @@ public class CronService { private SpecialCaseAccessFacadeEjbLocal specialCaseAccessFacade; @EJB private UserFacadeEjbLocal userFacade; + @EJB + private SampleService sampleService; @Schedule(hour = "*", minute = "*/" + TASK_UPDATE_INTERVAL, second = "0", persistent = false) public void sendNewAndDueTaskMessages() { @@ -297,4 +300,9 @@ public void syncUsersFromAuthenticationProvider() { userFacade.syncUsersFromAuthenticationProvider(); } } + + @Schedule(hour = "2", minute = "40", persistent = false) + public void sofDeleteOldNegativeSamples() { + sampleService.cleanupOldCovidSamples(); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java index d81b66d14cb..b051759007e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java @@ -14,6 +14,7 @@ */ package de.symeda.sormas.backend.common; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -26,6 +27,7 @@ import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; @@ -64,6 +66,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.customizableenum.CustomizableEnumType; +import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.externaljournal.PatientDiaryConfig; import de.symeda.sormas.api.externaljournal.SymptomJournalConfig; import de.symeda.sormas.api.externaljournal.UserConfig; @@ -88,6 +91,8 @@ import de.symeda.sormas.backend.deletionconfiguration.DeletionConfigurationService; import de.symeda.sormas.backend.disease.DiseaseConfiguration; import de.symeda.sormas.backend.disease.DiseaseConfigurationService; +import de.symeda.sormas.backend.docgeneration.DocumentTemplate; +import de.symeda.sormas.backend.docgeneration.DocumentTemplateService; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.feature.FeatureConfigurationService; import de.symeda.sormas.backend.importexport.ImportFacadeEjb.ImportFacadeEjbLocal; @@ -186,6 +191,8 @@ public class StartupShutdownService { private CustomizableEnumFacadeEjb.CustomizableEnumFacadeEjbLocal customizableEnumFacade; @EJB private CustomizableEnumValueService customizableEnumValueService; + @EJB + private DocumentTemplateService documentTemplateService; @Inject private Event passwordResetEvent; @@ -868,6 +875,9 @@ private void upgrade() { case 516: fillDefaultUserRole(DefaultUserRole.ENVIRONMENTAL_SURVEILLANCE_USER); break; + case 553: + createEntitiesForDocumentTemplates(); + break; default: throw new NoSuchElementException(DataHelper.toStringNullable(versionNeedingUpgrade)); } @@ -1019,6 +1029,21 @@ private void createMissingDiseaseConfigurations() { }); } + private void createEntitiesForDocumentTemplates() { + Map> templateFiles = documentTemplateService.getAllTemplateFiles(); + + templateFiles.forEach((workflow, files) -> { + for (File file : files) { + DocumentTemplate documentTemplate = new DocumentTemplate(); + documentTemplate.setUuid(DataHelper.createUuid()); + documentTemplate.setWorkflow(workflow); + documentTemplate.setFileName(file.getName()); + + documentTemplateService.ensurePersisted(documentTemplate); + } + }); + } + @PreDestroy public void shutdown() { auditLogger.logApplicationStop(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index e09a585e276..f6e2fa0efa6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -161,6 +161,7 @@ import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.TaskCreationException; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; @@ -291,6 +292,8 @@ public class ContactFacadeEjb private UserRoleFacadeEjb.UserRoleFacadeEjbLocal userRoleFacadeEjb; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; @Resource private ManagedScheduledExecutorService executorService; @@ -768,7 +771,7 @@ public List getExportList( contactQueryContext.getSubqueryExpression(ContactQueryContext.PERSON_PHONE_OWNER_SUBQUERY), contactQueryContext.getSubqueryExpression(ContactQueryContext.PERSON_EMAIL_SUBQUERY), contactQueryContext.getSubqueryExpression(ContactQueryContext.PERSON_OTHER_CONTACT_DETAILS_SUBQUERY), - joins.getPerson().get(Person.OCCUPATION_TYPE), + joins.getPerson().get(Person.OCCUPATION_TYPE_VALUE), joins.getPerson().get(Person.OCCUPATION_DETAILS), joins.getPerson().get(Person.ARMED_FORCES_RELATION_TYPE), joins.getRegion().get(Region.NAME), @@ -1725,7 +1728,7 @@ protected List toPseudonymizedDtos(List adoList) { @Override protected Pseudonymizer createPseudonymizer(List contacts) { - return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(contacts)); + return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(contacts), configFacade.getCountryCode()); } private SpecialAccessCheck createSpecialAccessChecker(Collection contacts) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 3c8f1cd2b22..b1ee6b30c7c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -137,6 +137,7 @@ import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserRole; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.BirthdateRangeFilterPredicate; import de.symeda.sormas.backend.util.ExternalDataUtil; import de.symeda.sormas.backend.util.IterableHelper; import de.symeda.sormas.backend.util.JurisdictionHelper; @@ -1419,6 +1420,15 @@ public Predicate buildCriteriaFilter(ContactCriteria contactCriteria, ContactQue if (contactCriteria.getPerson() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(joins.getPerson().get(Person.UUID), contactCriteria.getPerson().getUuid())); } + + filter = BirthdateRangeFilterPredicate.createBirthdateRangeFilter( + contactCriteria.getBirthdateFrom(), + contactCriteria.getBirthdateTo(), + contactCriteria.isIncludePartialMatch(), + cb, + joins.getPerson(), + filter); + if (contactCriteria.getBirthdateYYYY() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(joins.getPerson().get(Person.BIRTHDATE_YYYY), contactCriteria.getBirthdateYYYY())); @@ -1482,7 +1492,8 @@ public Predicate buildCriteriaFilter(ContactCriteria contactCriteria, ContactQue CriteriaBuilderHelper.and(cb, filter, cb.or(cb.exists(sharesSubQuery), cb.isNotNull(from.get(Contact.SORMAS_TO_SORMAS_ORIGIN_INFO)))); } if (contactCriteria.getDiseaseVariant() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(joins.getCaze().get(Case.DISEASE_VARIANT), contactCriteria.getDiseaseVariant())); + filter = CriteriaBuilderHelper + .and(cb, filter, cb.equal(joins.getCaze().get(Case.DISEASE_VARIANT_VALUE), contactCriteria.getDiseaseVariant().getValue())); } if (contactCriteria.getWithOwnership() != null) { filter = CriteriaBuilderHelper @@ -1722,7 +1733,7 @@ public void restore(Contact contact) { } @Override - public void deletePermanent(Contact contact) { + public boolean deletePermanent(Contact contact) { // Delete all tasks associated with this case Optional.ofNullable(contact.getTasks()).ifPresent(tl -> tl.forEach(t -> taskService.deletePermanent(t))); @@ -1763,6 +1774,7 @@ public void deletePermanent(Contact contact) { deleteContactLinks(contact); super.deletePermanent(contact); + return false; } private void deleteContactLinks(Contact contact) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java index d6b5892daa1..9de113916a6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java @@ -19,6 +19,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.EnumMap; @@ -26,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -85,12 +87,13 @@ public class CustomizableEnumFacadeEjb /** * Maps a customizable enum type to all enum value strings of that type in the database. */ - private static final EnumMap> enumValues = new EnumMap<>(CustomizableEnumType.class); + private static final EnumMap>> enumValues = new EnumMap<>(CustomizableEnumType.class); /** * Maps a customizable enum type to a map with all enum values of this type as its keys and info, e.g. properties and active status, * defined for these enum values as its values. */ - private static final EnumMap> enumInfo = new EnumMap<>(CustomizableEnumType.class); + private static final EnumMap>> enumInfo = + new EnumMap<>(CustomizableEnumType.class); /** * Maps a customizable enum type (defined by its class) to a map which in turn maps all languages for which translations exist to * the possible enum values of this type, which then finally map to their translated captions. @@ -162,10 +165,12 @@ public CustomizableEnumValueDto save(CustomizableEnumValueDto dto) { CustomizableEnumValue existingEntity = service.getByUuid(dto.getUuid()); - List dataTypeValues = enumValues.get(dto.getDataType()); - if (existingEntity == null && dataTypeValues != null && dataTypeValues.contains(dto.getValue())) { - throw new ValidationRuntimeException( - I18nProperties.getValidationError(Validations.customizableEnumValueDuplicateValue, dto.getDataType().toString(), dto.getValue())); + for (Disease disease : dto.getDiseases()) { + List dataTypeValues = enumValues.get(dto.getDataType()).getOrDefault(disease, Collections.emptyList()); + if (existingEntity == null && dataTypeValues != null && dataTypeValues.contains(dto.getValue())) { + throw new ValidationRuntimeException( + I18nProperties.getValidationError(Validations.customizableEnumValueDuplicateValue, dto.getDataType().toString(), dto.getValue())); + } } CustomizableEnumValue enumValue = fillOrBuildEntity(dto, existingEntity, true); @@ -267,8 +272,8 @@ private CustomizableEnumValueIndexDto toIndexDto(CustomizableEnumValue entity) { @Lock(LockType.READ) @Override @SuppressWarnings("unchecked") - public T getEnumValue(CustomizableEnumType type, String value) { - if (!enumValues.get(type).contains(value)) { + public T getEnumValue(CustomizableEnumType type, Disease disease, String value) { + if (!enumValues.get(type).getOrDefault(disease, Collections.emptyList()).contains(value)) { throw new IllegalArgumentException(String.format("Invalid enum value %s for customizable enum type %s", value, type.toString())); } @@ -279,7 +284,7 @@ public T getEnumValue(CustomizableEnumType type, St fillLanguageCache(type, enumClass, language); } - return buildCustomizableEnum(type, value, language, enumClass); + return buildCustomizableEnum(type, disease, value, language, enumClass); } @Lock(LockType.READ) @@ -329,8 +334,8 @@ public List getEnumValues(CustomizableEnumType t diseaseValuesStream = enumValuesByDisease.get(enumClass).get(Optional.empty()).stream(); } - return diseaseValuesStream.filter(value -> getEnumInfo(type, value).isActive()) - .map(value -> buildCustomizableEnum(type, value, language, enumClass)) + return diseaseValuesStream.filter(value -> getEnumInfo(type, disease, value).isActive()) + .map(value -> buildCustomizableEnum(type, disease, value, language, enumClass)) .sorted(Comparator.comparing(CustomizableEnum::getCaption)) .collect(Collectors.toList()); } @@ -341,12 +346,17 @@ public boolean hasEnumValues(CustomizableEnumType type, Disease disease) { return !getEnumValues(type, disease).isEmpty(); } - private T buildCustomizableEnum(CustomizableEnumType type, String value, Language language, Class enumClass) { + private T buildCustomizableEnum( + CustomizableEnumType type, + Disease disease, + String value, + Language language, + Class enumClass) { try { T enumValue = enumClass.getDeclaredConstructor().newInstance(); enumValue.setValue(value); enumValue.setCaption(enumValuesByLanguage.get(enumClass).get(language).get(value)); - enumValue.setProperties(getEnumInfo(type, value).getProperties()); + enumValue.setProperties(getEnumInfo(type, disease, value).getProperties()); return enumValue; } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e); @@ -426,7 +436,7 @@ public void loadData() { for (CustomizableEnumType enumType : CustomizableEnumType.values()) { enumValueEntities.putIfAbsent(enumType, new ArrayList<>()); - enumValues.putIfAbsent(enumType, new ArrayList<>()); + enumValues.putIfAbsent(enumType, new HashMap<>()); } // Build list of customizable enums mapped by their enum type; other caches are built on-demand @@ -434,14 +444,26 @@ public void loadData() { CustomizableEnumType enumType = customizableEnumValue.getDataType(); enumValueEntities.get(enumType).add(customizableEnumValue); String value = customizableEnumValue.getValue(); - if (enumValues.get(enumType).contains(value)) { - throw new InvalidCustomizationException( - "Enum value " + value + " for customizable enum type " + enumType.toString() + " is not unique"); + Set diseases = customizableEnumValue.getDiseases(); + + if (diseases == null) { + diseases = Collections.singleton(null); + } + for (Disease disease : diseases) { + if (enumValues.get(enumType).getOrDefault(disease, Collections.emptyList()).contains(value)) { + throw new InvalidCustomizationException( + "Enum value " + value + " for customizable enum type " + enumType.toString() + " is not unique"); + } + + enumValues.get(enumType).putIfAbsent(disease, new ArrayList<>()); + enumValues.get(enumType).get(disease).add(value); + + enumInfo.putIfAbsent(enumType, new HashMap<>()); + enumInfo.get(enumType).putIfAbsent(disease, new HashMap<>()); + enumInfo.get(enumType) + .get(disease) + .putIfAbsent(value, new CustomizableEnumCacheInfo(customizableEnumValue.getProperties(), customizableEnumValue.isActive())); } - enumValues.get(enumType).add(value); - enumInfo.putIfAbsent(enumType, new HashMap<>()); - enumInfo.get(enumType) - .putIfAbsent(value, new CustomizableEnumCacheInfo(customizableEnumValue.getProperties(), customizableEnumValue.isActive())); } for (CustomizableEnumType enumType : CustomizableEnumType.values()) { @@ -455,8 +477,10 @@ public void loadData() { } } - private CustomizableEnumCacheInfo getEnumInfo(CustomizableEnumType type, String value) { - return enumInfo.get(type).get(value); + private CustomizableEnumCacheInfo getEnumInfo(CustomizableEnumType type, Disease disease, String value) { + return enumInfo.get(type) + .getOrDefault(disease, Collections.emptyMap()) + .getOrDefault(value, disease != null ? getEnumInfo(type, null, value) : null); } public CustomizableEnumValueDto toDto(CustomizableEnumValue source) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumValue.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumValue.java index 2097ab0e235..5149aa366bf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumValue.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumValue.java @@ -25,6 +25,7 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; +import de.symeda.sormas.api.customizableenum.CustomizableEnumConverter; import org.hibernate.annotations.Type; import de.symeda.sormas.api.Disease; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacadeEjb.java new file mode 100644 index 00000000000..9a3fc77ec3f --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardFacadeEjb.java @@ -0,0 +1,89 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.dashboard.adverseeventsfollowingimmunization; + +import java.util.List; +import java.util.Map; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartData; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiDashboardFacade; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.MapAefiDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.backend.util.RightsAllowed; + +@Stateless(name = "AefiDashboardFacade") +@RightsAllowed(UserRight._DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW) +public class AefiDashboardFacadeEjb implements AefiDashboardFacade { + + @EJB + private AefiDashboardService aefiDashboardService; + + @Override + public Map getAefiCountsByType(AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiCountsByType(dashboardCriteria); + } + + @Override + public Map> getAefiInvestigationCountsByInvestigationStatus( + AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiInvestigationCountsByInvestigationStatus(dashboardCriteria); + } + + @Override + public Map> getAefiInvestigationCountsByAefiClassification(AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiInvestigationCountsByAefiClassification(dashboardCriteria); + } + + @Override + public Map> getAefiCountsByVaccine(AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiCountsByVaccine(dashboardCriteria); + } + + @Override + public AefiChartData getAefiByVaccineDoseChartData(AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiByVaccineDoseChartData(dashboardCriteria); + } + + @Override + public AefiChartData getAefiEventsByGenderChartData(AefiDashboardCriteria dashboardCriteria) { + return aefiDashboardService.getAefiEventsByGenderChartData(dashboardCriteria); + } + + @Override + public Long countAefiForMap(AefiDashboardCriteria criteria) { + return aefiDashboardService.countAefiForMap(criteria); + } + + @Override + public List getAefiForMap(AefiDashboardCriteria criteria) { + return aefiDashboardService.getAefiForMap(criteria); + } + + @LocalBean + @Stateless + public static class AefiDashboardFacadeEjbLocal extends AefiDashboardFacadeEjb { + + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardService.java new file mode 100644 index 00000000000..213655e0049 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/dashboard/adverseeventsfollowingimmunization/AefiDashboardService.java @@ -0,0 +1,680 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.dashboard.adverseeventsfollowingimmunization; + +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.Tuple; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDashboardFilterDateType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartData; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartSeries; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.MapAefiDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.AefiInvestigationService; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.AefiQueryContext; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.AefiService; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AdverseEvents; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiJoins; +import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.immunization.entity.Immunization; +import de.symeda.sormas.backend.infrastructure.district.District; +import de.symeda.sormas.backend.infrastructure.district.DistrictService; +import de.symeda.sormas.backend.infrastructure.facility.Facility; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.infrastructure.region.RegionService; +import de.symeda.sormas.backend.location.Location; +import de.symeda.sormas.backend.person.Person; +import de.symeda.sormas.backend.util.ModelConstants; +import de.symeda.sormas.backend.util.QueryHelper; + +@Stateless +@LocalBean +public class AefiDashboardService { + + private final Logger logger = LoggerFactory.getLogger(AefiDashboardService.class); + + @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) + private EntityManager em; + + public static final String SERIOUS_SERIES_COLOR = "#E04A5B"; + public static final String NON_SERIOUS_SERIES_COLOR = "#7565B8"; + public static final String MALE_SERIES_COLOR = "#544FC5"; + public static final String FEMALE_SERIES_COLOR = "#2CAFFE"; + + @EJB + private AefiService aefiService; + @EJB + private AefiInvestigationService aefiInvestigationService; + @EJB + private RegionService regionService; + @EJB + private DistrictService districtService; + + public Map getAefiCountsByType(AefiDashboardCriteria dashboardCriteria) { + + Map result = new HashMap<>(); + + Map dataMap = getAefiCountsByEnumProperty(Aefi.SERIOUS, YesNoUnknown.class, dashboardCriteria, null); + + result.put(AefiType.SERIOUS, dataMap.getOrDefault(YesNoUnknown.YES, 0L)); + result.put(AefiType.NON_SERIOUS, dataMap.getOrDefault(YesNoUnknown.NO, 0L) + dataMap.getOrDefault(YesNoUnknown.UNKNOWN, 0L)); + + return result; + } + + public Map> getAefiInvestigationCountsByInvestigationStatus( + AefiDashboardCriteria dashboardCriteria) { + + Map> countsByInvestigationStatus = new HashMap<>(); + + Map defaultValuesMap = new HashMap<>(); + defaultValuesMap.put("total", "0"); + defaultValuesMap.put("percent", "0"); + + for (AefiInvestigationStatus investigationStatus : AefiInvestigationStatus.values()) { + countsByInvestigationStatus.put(investigationStatus, new HashMap<>(defaultValuesMap)); + } + + Disease disease = dashboardCriteria.getDisease(); + RegionReferenceDto regionReference = dashboardCriteria.getRegion(); + DistrictReferenceDto districtReference = dashboardCriteria.getDistrict(); + + String whereConditions = createAefiNativeQueryFilter(dashboardCriteria); + if (StringUtils.isBlank(whereConditions)) { + whereConditions = " aefininvestigation.investigationstatus is not null"; + } else { + whereConditions = whereConditions + " AND aefininvestigation.investigationstatus is not null"; + } + + //@formatter:off + String queryString = "select aefininvestigation.investigationstatus, count(*) as total_status " + + " from adverseeventsfollowingimmunizationinvestigation aefininvestigation" + + " join adverseeventsfollowingimmunization aefi on aefininvestigation.adverseeventsfollowingimmunization_id = aefi.id" + + " join immunization on aefi.immunization_id = immunization.id" + + " where " + whereConditions + + " group by aefininvestigation.investigationstatus"; + //@formatter:on + + Query dataQuery = em.createNativeQuery(queryString); + + if (disease != null) { + dataQuery.setParameter("disease", disease.name()); + } + + if (regionReference != null) { + Region region = regionService.getByReferenceDto(regionReference); + dataQuery.setParameter("responsibleregion_id", region.getId()); + } + + if (districtReference != null) { + District district = districtService.getByReferenceDto(districtReference); + dataQuery.setParameter("responsibledistrict_id", district.getId()); + } + + if (dashboardCriteria.getDateFrom() != null && dashboardCriteria.getDateTo() != null) { + Date dateFrom = DateHelper.getStartOfDay(dashboardCriteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(dashboardCriteria.getDateTo()); + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String dateFromStr = DateHelper.formatLocalDate(dateFrom, simpleDateFormat); + String dateToStr = DateHelper.formatLocalDate(dateTo, simpleDateFormat); + + dataQuery.setParameter("dateFrom", dateFromStr); + dataQuery.setParameter("dateTo", dateToStr); + } + + @SuppressWarnings("unchecked") + List resultList = dataQuery.getResultList(); + + int totalInvestigations = 0; + for (Object[] result : resultList) { + totalInvestigations += ((BigInteger) result[1]).intValue(); + } + + int statusTotal; + int statusPercent; + for (Object[] result : resultList) { + statusTotal = ((BigInteger) result[1]).intValue(); + statusPercent = (totalInvestigations == 0) ? 0 : ((int) ((statusTotal * 100.0f) / totalInvestigations)); + countsByInvestigationStatus.get(AefiInvestigationStatus.valueOf((String) result[0])).put("total", String.valueOf(statusTotal)); + countsByInvestigationStatus.get(AefiInvestigationStatus.valueOf((String) result[0])).put("percent", String.valueOf(statusPercent)); + } + + return countsByInvestigationStatus; + } + + public Map> getAefiInvestigationCountsByAefiClassification(AefiDashboardCriteria dashboardCriteria) { + + Map> countsByAefiClassitication = new HashMap<>(); + + Map defaultValuesMap = new HashMap<>(); + defaultValuesMap.put("total", "0"); + defaultValuesMap.put("percent", "0"); + + for (AefiClassification aefiClassification : AefiClassification.values()) { + countsByAefiClassitication.put(aefiClassification, new HashMap<>(defaultValuesMap)); + } + + Disease disease = dashboardCriteria.getDisease(); + RegionReferenceDto regionReference = dashboardCriteria.getRegion(); + DistrictReferenceDto districtReference = dashboardCriteria.getDistrict(); + + String whereConditions = createAefiNativeQueryFilter(dashboardCriteria); + if (StringUtils.isBlank(whereConditions)) { + whereConditions = " aefininvestigation.adverseeventfollowingimmunizationclassification is not null"; + } else { + whereConditions = whereConditions + " AND aefininvestigation.adverseeventfollowingimmunizationclassification is not null"; + } + + //@formatter:off + String queryString = "select aefininvestigation.adverseeventfollowingimmunizationclassification, count(*) as total_classification " + + " from adverseeventsfollowingimmunizationinvestigation aefininvestigation" + + " join adverseeventsfollowingimmunization aefi on aefininvestigation.adverseeventsfollowingimmunization_id = aefi.id" + + " join immunization on aefi.immunization_id = immunization.id" + + " where " + whereConditions + + " group by aefininvestigation.adverseeventfollowingimmunizationclassification"; + //@formatter:on + + Query dataQuery = em.createNativeQuery(queryString); + + if (disease != null) { + dataQuery.setParameter("disease", disease.name()); + } + + if (regionReference != null) { + Region region = regionService.getByReferenceDto(regionReference); + dataQuery.setParameter("responsibleregion_id", region.getId()); + } + + if (districtReference != null) { + District district = districtService.getByReferenceDto(districtReference); + dataQuery.setParameter("responsibledistrict_id", district.getId()); + } + + if (dashboardCriteria.getDateFrom() != null && dashboardCriteria.getDateTo() != null) { + Date dateFrom = DateHelper.getStartOfDay(dashboardCriteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(dashboardCriteria.getDateTo()); + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String dateFromStr = DateHelper.formatLocalDate(dateFrom, simpleDateFormat); + String dateToStr = DateHelper.formatLocalDate(dateTo, simpleDateFormat); + + dataQuery.setParameter("dateFrom", dateFromStr); + dataQuery.setParameter("dateTo", dateToStr); + } + + @SuppressWarnings("unchecked") + List resultList = dataQuery.getResultList(); + + int totalInvestigations = 0; + for (Object[] result : resultList) { + totalInvestigations += ((BigInteger) result[1]).intValue(); + } + + int classificationTotal; + int classificationPercent; + for (Object[] result : resultList) { + classificationTotal = ((BigInteger) result[1]).intValue(); + classificationPercent = (totalInvestigations == 0) ? 0 : ((int) ((classificationTotal * 100.0f) / totalInvestigations)); + countsByAefiClassitication.get(AefiClassification.valueOf((String) result[0])).put("total", String.valueOf(classificationTotal)); + countsByAefiClassitication.get(AefiClassification.valueOf((String) result[0])).put("percent", String.valueOf(classificationPercent)); + } + + return countsByAefiClassitication; + } + + public Map> getAefiCountsByVaccine(AefiDashboardCriteria dashboardCriteria) { + + Map> countsByVaccine = new HashMap<>(); + + Disease disease = dashboardCriteria.getDisease(); + RegionReferenceDto regionReference = dashboardCriteria.getRegion(); + DistrictReferenceDto districtReference = dashboardCriteria.getDistrict(); + + String whereConditions = createAefiNativeQueryFilter(dashboardCriteria); + if (StringUtils.isBlank(whereConditions)) { + whereConditions = " primaryvaccine.vaccinename is not null"; + } else { + whereConditions = whereConditions + " AND primaryvaccine.vaccinename is not null"; + } + + //@formatter:off + String queryString = "select primaryvaccine.vaccinename as vaccine_name " + + " , count(CASE WHEN aefi.serious = 'YES' THEN 1 END) as serious" + + " , count(CASE WHEN aefi.serious <> 'YES' THEN 1 END) as non_serious" + + " from adverseeventsfollowingimmunization aefi" + + " join immunization on aefi.immunization_id = immunization.id" + + " join vaccination primaryvaccine on aefi.primarysuspectvaccine_id = primaryvaccine.id" + + " where " + whereConditions + + " group by primaryvaccine.vaccinename" + + " order by primaryvaccine.vaccinename"; + //@formatter:on + + Query dataQuery = em.createNativeQuery(queryString); + + if (disease != null) { + dataQuery.setParameter("disease", disease.name()); + } + + if (regionReference != null) { + Region region = regionService.getByReferenceDto(regionReference); + dataQuery.setParameter("responsibleregion_id", region.getId()); + } + + if (districtReference != null) { + District district = districtService.getByReferenceDto(districtReference); + dataQuery.setParameter("responsibledistrict_id", district.getId()); + } + + if (dashboardCriteria.getDateFrom() != null && dashboardCriteria.getDateTo() != null) { + Date dateFrom = DateHelper.getStartOfDay(dashboardCriteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(dashboardCriteria.getDateTo()); + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String dateFromStr = DateHelper.formatLocalDate(dateFrom, simpleDateFormat); + String dateToStr = DateHelper.formatLocalDate(dateTo, simpleDateFormat); + + dataQuery.setParameter("dateFrom", dateFromStr); + dataQuery.setParameter("dateTo", dateToStr); + } + + @SuppressWarnings("unchecked") + List resultList = dataQuery.getResultList(); + + Map aefiTypeDataMap; + for (Object[] result : resultList) { + aefiTypeDataMap = new HashMap<>(); + aefiTypeDataMap.put(AefiType.SERIOUS, ((BigInteger) result[1]).longValue()); + aefiTypeDataMap.put(AefiType.NON_SERIOUS, ((BigInteger) result[2]).longValue()); + + countsByVaccine.put(Vaccine.valueOf((String) result[0]), aefiTypeDataMap); + } + + return countsByVaccine; + } + + public AefiChartData getAefiByVaccineDoseChartData(AefiDashboardCriteria dashboardCriteria) { + + AefiChartData chartData = new AefiChartData(); + + AefiChartSeries seriousSeries = new AefiChartSeries(AefiType.SERIOUS); + seriousSeries.setColor(SERIOUS_SERIES_COLOR); + AefiChartSeries nonSeriousSeries = new AefiChartSeries(AefiType.NON_SERIOUS); + nonSeriousSeries.setColor(NON_SERIOUS_SERIES_COLOR); + + chartData.addSeries(seriousSeries); + chartData.addSeries(nonSeriousSeries); + + Disease disease = dashboardCriteria.getDisease(); + RegionReferenceDto regionReference = dashboardCriteria.getRegion(); + DistrictReferenceDto districtReference = dashboardCriteria.getDistrict(); + + String whereConditions = createAefiNativeQueryFilter(dashboardCriteria); + if (StringUtils.isBlank(whereConditions)) { + whereConditions = " primaryvaccine.vaccinedose is not null"; + } else { + whereConditions = whereConditions + " AND primaryvaccine.vaccinedose is not null"; + } + + //@formatter:off + String queryString = "select primaryvaccine.vaccinedose as vaccine_dose " + + " , count(CASE WHEN aefi.serious = 'YES' THEN 1 END) as serious" + + " , count(CASE WHEN aefi.serious <> 'YES' THEN 1 END) as non_serious" + + " from adverseeventsfollowingimmunization aefi" + + " join immunization on aefi.immunization_id = immunization.id" + + " join vaccination primaryvaccine on aefi.primarysuspectvaccine_id = primaryvaccine.id" + + " where " + whereConditions + + " group by primaryvaccine.vaccinedose" + + " order by primaryvaccine.vaccinedose"; + //@formatter:on + + Query dataQuery = em.createNativeQuery(queryString); + + if (disease != null) { + dataQuery.setParameter("disease", disease.name()); + } + + if (regionReference != null) { + Region region = regionService.getByReferenceDto(regionReference); + dataQuery.setParameter("responsibleregion_id", region.getId()); + } + + if (districtReference != null) { + District district = districtService.getByReferenceDto(districtReference); + dataQuery.setParameter("responsibledistrict_id", district.getId()); + } + + if (dashboardCriteria.getDateFrom() != null && dashboardCriteria.getDateTo() != null) { + Date dateFrom = DateHelper.getStartOfDay(dashboardCriteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(dashboardCriteria.getDateTo()); + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String dateFromStr = DateHelper.formatLocalDate(dateFrom, simpleDateFormat); + String dateToStr = DateHelper.formatLocalDate(dateTo, simpleDateFormat); + + dataQuery.setParameter("dateFrom", dateFromStr); + dataQuery.setParameter("dateTo", dateToStr); + } + + @SuppressWarnings("unchecked") + List resultList = dataQuery.getResultList(); + + for (Object[] result : resultList) { + chartData.addXAxisCategory(result[0]); + seriousSeries.addData(result[1].toString()); + nonSeriousSeries.addData(result[2].toString()); + } + + return chartData; + } + + public AefiChartData getAefiEventsByGenderChartData(AefiDashboardCriteria dashboardCriteria) { + + AefiChartData chartData = new AefiChartData(); + + AefiChartSeries maleSeries = new AefiChartSeries(Sex.MALE); + maleSeries.setColor(MALE_SERIES_COLOR); + AefiChartSeries femaleSeries = new AefiChartSeries(Sex.FEMALE); + femaleSeries.setColor(FEMALE_SERIES_COLOR); + + chartData.addSeries(maleSeries); + chartData.addSeries(femaleSeries); + + Disease disease = dashboardCriteria.getDisease(); + RegionReferenceDto regionReference = dashboardCriteria.getRegion(); + DistrictReferenceDto districtReference = dashboardCriteria.getDistrict(); + + List adverseEventsList = new ArrayList<>(); + adverseEventsList.add(AdverseEvents.SEVERE_LOCAL_REACTION); + adverseEventsList.add(AdverseEvents.SEIZURES); + adverseEventsList.add(AdverseEvents.ABSCESS); + adverseEventsList.add(AdverseEvents.SEPSIS); + adverseEventsList.add(AdverseEvents.ENCEPHALOPATHY); + adverseEventsList.add(AdverseEvents.TOXIC_SHOCK_SYNDROME); + adverseEventsList.add(AdverseEvents.THROMBOCYTOPENIA); + adverseEventsList.add(AdverseEvents.ANAPHYLAXIS); + adverseEventsList.add(AdverseEvents.FEVERISH_FEELING); + + String queryString; + String queryFilter = createAefiNativeQueryFilter(dashboardCriteria); + String whereConditions; + String adverseEventCondition; + String lowerCaseAdverseEvent; + + for (String adverseEvent : adverseEventsList) { + + whereConditions = queryFilter; + lowerCaseAdverseEvent = adverseEvent.toLowerCase(); + adverseEventCondition = " adverseevents." + lowerCaseAdverseEvent + " = 'YES'"; + if (StringUtils.isBlank(whereConditions)) { + whereConditions = adverseEventCondition; + } else { + whereConditions = whereConditions + " AND " + adverseEventCondition; + } + + //@formatter:off + queryString = "select adverseevents." + lowerCaseAdverseEvent + " as " + lowerCaseAdverseEvent + + " , count(CASE WHEN person.sex = 'MALE' THEN 1 END) as total_male" + + " , count(CASE WHEN person.sex = 'FEMALE' THEN 1 END) as total_female" + + " from adverseeventsfollowingimmunization aefi" + + " join immunization on aefi.immunization_id = immunization.id" + + " join person on immunization.person_id = person.id" + + " join adverseevents on aefi.adverseevents_id = adverseevents.id" + + " where " + whereConditions + + " group by adverseevents." + lowerCaseAdverseEvent; + //@formatter:on + + Query dataQuery = em.createNativeQuery(queryString); + + if (disease != null) { + dataQuery.setParameter("disease", disease.name()); + } + + if (regionReference != null) { + Region region = regionService.getByReferenceDto(regionReference); + dataQuery.setParameter("responsibleregion_id", region.getId()); + } + + if (districtReference != null) { + District district = districtService.getByReferenceDto(districtReference); + dataQuery.setParameter("responsibledistrict_id", district.getId()); + } + + if (dashboardCriteria.getDateFrom() != null && dashboardCriteria.getDateTo() != null) { + Date dateFrom = DateHelper.getStartOfDay(dashboardCriteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(dashboardCriteria.getDateTo()); + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String dateFromStr = DateHelper.formatLocalDate(dateFrom, simpleDateFormat); + String dateToStr = DateHelper.formatLocalDate(dateTo, simpleDateFormat); + + dataQuery.setParameter("dateFrom", dateFromStr); + dataQuery.setParameter("dateTo", dateToStr); + } + + chartData.addXAxisCategory(adverseEvent); + + @SuppressWarnings("unchecked") + List resultList = dataQuery.getResultList(); + + if (!resultList.isEmpty()) { + Object[] firstResult = resultList.get(0); + maleSeries.addData("-" + firstResult[1].toString()); + femaleSeries.addData(firstResult[2].toString()); + } else { + maleSeries.addData("0"); + femaleSeries.addData("0"); + } + } + + return chartData; + } + + private > Map getAefiCountsByEnumProperty( + String property, + Class propertyType, + AefiDashboardCriteria dashboardCriteria, + BiFunction, Predicate> additionalFilters) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createTupleQuery(); + final Root aefiRoot = cq.from(Aefi.class); + final Path groupingProperty = aefiRoot.get(property); + + cq.multiselect(groupingProperty, cb.count(aefiRoot)); + + final Predicate criteriaFilter = createAefiFilter(new AefiQueryContext(cb, cq, aefiRoot), dashboardCriteria); + cq.where(CriteriaBuilderHelper.and(cb, criteriaFilter, additionalFilters != null ? additionalFilters.apply(cb, aefiRoot) : null)); + + cq.groupBy(groupingProperty); + + return QueryHelper.getResultList(em, cq, null, null, Function.identity()) + .stream() + .collect(Collectors.toMap(t -> propertyType.cast(t.get(0)), t -> (Long) t.get(1))); + } + + public Long countAefiForMap(AefiDashboardCriteria criteria) { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(Long.class); + final Root aefiRoot = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefiRoot); + AefiJoins joins = aefiQueryContext.getJoins(); + + cq.select(cb.count(aefiRoot)); + + final Predicate criteriaFilter = createAefiFilter(aefiQueryContext, criteria); + + cq.where(CriteriaBuilderHelper.and(cb, criteriaFilter)); + + return QueryHelper.getSingleResult(em, cq); + } + + public List getAefiForMap(AefiDashboardCriteria criteria) { + + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery(MapAefiDto.class); + final Root aefiRoot = cq.from(Aefi.class); + + AefiQueryContext aefiQueryContext = new AefiQueryContext(cb, cq, aefiRoot); + AefiJoins joins = aefiQueryContext.getJoins(); + + Join aefiFacility = joins.getHealthFacility(); + Join immunizationFacility = joins.getImmunizationJoins().getHealthFacility(); + Join immunizationPersonAddress = joins.getImmunizationJoins().getPersonJoins().getAddress(); + + cq.multiselect( + aefiFacility.get(Facility.LATITUDE), + aefiFacility.get(Facility.LONGITUDE), + immunizationFacility.get(Facility.LATITUDE), + immunizationFacility.get(Facility.LONGITUDE), + immunizationPersonAddress.get(Facility.LATITUDE), + immunizationPersonAddress.get(Facility.LONGITUDE), + aefiRoot.get(Aefi.SERIOUS)); + + final Predicate criteriaFilter = createAefiFilter(aefiQueryContext, criteria); + + cq.where(CriteriaBuilderHelper.and(cb, criteriaFilter)); + + return QueryHelper.getResultList(em, cq, null, null); + } + + private Predicate createAefiFilter(AefiQueryContext queryContext, AefiDashboardCriteria criteria) { + CriteriaBuilder cb = queryContext.getCriteriaBuilder(); + CriteriaQuery cq = queryContext.getQuery(); + From aefiRoot = queryContext.getRoot(); + AefiJoins joins = queryContext.getJoins(); + + Predicate filter = aefiService.createUserFilter(queryContext); + + filter = CriteriaBuilderHelper.and( + cb, + filter, + aefiService.buildCriteriaFilter( + new AefiCriteria().disease(criteria.getDisease()) + .region(criteria.getRegion()) + .district(criteria.getDistrict()) + .aefiType(criteria.getAefiType()), + queryContext)); + + if (criteria.getDateFrom() != null && criteria.getDateTo() != null) { + final Predicate dateFilter; + Date dateFrom = DateHelper.getStartOfDay(criteria.getDateFrom()); + Date dateTo = DateHelper.getEndOfDay(criteria.getDateTo()); + + AefiDashboardFilterDateType aefiDashboardFilterDateType = criteria.getAefiDashboardFilterDateType() != null + ? criteria.getAefiDashboardFilterDateType() + : AefiDashboardFilterDateType.REPORT_DATE; + + switch (aefiDashboardFilterDateType) { + case REPORT_DATE: + dateFilter = cb.between(aefiRoot.get(Aefi.REPORT_DATE), dateFrom, dateTo); + break; + case START_DATE: + dateFilter = cb.between(aefiRoot.get(Aefi.START_DATE_TIME), dateFrom, dateTo); + break; + default: + throw new RuntimeException("Unhandled date type [" + aefiDashboardFilterDateType + "]"); + } + + filter = CriteriaBuilderHelper.and(cb, filter, dateFilter); + } + + return CriteriaBuilderHelper.and( + cb, + filter, + // Exclude deleted adverse events. Archived adverse events should stay included + cb.isFalse(aefiRoot.get(Aefi.DELETED))); + } + + private String createAefiNativeQueryFilter(AefiDashboardCriteria criteria) { + + List whereConditions = new ArrayList<>(); + + if (criteria.getDisease() != null) { + whereConditions.add("immunization.disease = :disease"); + } + + if (criteria.getRegion() != null) { + whereConditions.add("immunization.responsibleregion_id = :responsibleregion_id"); + } + + if (criteria.getDistrict() != null) { + whereConditions.add("immunization.responsibledistrict_id = :responsibledistrict_id"); + } + + if (criteria.getDateFrom() != null && criteria.getDateTo() != null) { + AefiDashboardFilterDateType aefiDashboardFilterDateType = criteria.getAefiDashboardFilterDateType() != null + ? criteria.getAefiDashboardFilterDateType() + : AefiDashboardFilterDateType.REPORT_DATE; + + switch (aefiDashboardFilterDateType) { + case REPORT_DATE: + whereConditions + .add("(cast(aefi.reportdate as date) >= cast(:dateFrom as date) and cast(aefi.reportdate as date) <= cast(:dateTo as date))"); + break; + case START_DATE: + whereConditions.add( + "(cast(aefi.startdatetime as date) >= cast(:dateFrom as date) and cast(aefi.startdatetime as date) <= cast(:dateTo as date))"); + break; + default: + throw new RuntimeException("Unhandled date type [" + aefiDashboardFilterDateType + "]"); + } + } + + return String.join(" AND ", whereConditions); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocGenerationHelper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocGenerationHelper.java index bd1ba299331..94b7b993860 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocGenerationHelper.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocGenerationHelper.java @@ -13,6 +13,7 @@ import de.symeda.sormas.api.action.ActionReferenceDto; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.document.DocumentDto; import de.symeda.sormas.api.document.DocumentRelatedEntityDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; @@ -45,13 +46,13 @@ public DocumentRelatedEntityType getDocumentRelatedEntityType(ReferenceDto rootE } } - public String getDocumentFileName(ReferenceDto rootEntityReference, String templateFileName) { + public String getDocumentFileName(ReferenceDto rootEntityReference, DocumentTemplateReferenceDto templateReference) { List docs = documentFacade.getDocumentsRelatedToEntity(getDocumentRelatedEntityType(rootEntityReference), rootEntityReference.getUuid()); return generateNewFileName( docs.stream().map(DocumentDto::getName).collect(Collectors.toList()), DataHelper.getShortUuid(rootEntityReference), - '-' + templateFileName); + '-' + templateReference.getCaption()); } private String generateNewFileName(List docs, String shortUuid, String templateFileName) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplate.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplate.java new file mode 100644 index 00000000000..1babf8c57ac --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplate.java @@ -0,0 +1,68 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.docgeneration; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; +import de.symeda.sormas.api.utils.FieldConstraints; +import de.symeda.sormas.backend.common.AbstractDomainObject; + +@Entity(name = "documenttemplates") +public class DocumentTemplate extends AbstractDomainObject { + + private static final long serialVersionUID = -8191658284208086022L; + + public static final String WORKFLOW = "workflow"; + public static final String DISEASE = "disease"; + public static final String DOCUMENT_PATH = "documentPath"; + + private DocumentWorkflow workflow; + private Disease disease; + private String fileName; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + public DocumentWorkflow getWorkflow() { + return workflow; + } + + public void setWorkflow(DocumentWorkflow workflow) { + this.workflow = workflow; + } + + @Enumerated(EnumType.STRING) + public Disease getDisease() { + return disease; + } + + public void setDisease(Disease disease) { + this.disease = disease; + } + + @Column(length = FieldConstraints.CHARACTER_LIMIT_BIG) + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index ae62fc5870c..79f2dd24828 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -17,14 +17,8 @@ import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Set; @@ -32,22 +26,27 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import javax.annotation.Nullable; import javax.annotation.security.PermitAll; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; +import javax.persistence.criteria.Predicate; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.EntityDtoAccessHelper; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateEntities; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentTemplateFacade; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.DocumentWorkflowType; @@ -72,6 +71,7 @@ import de.symeda.sormas.api.uuid.HasUuid; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.event.EventFacadeEjb.EventFacadeEjbLocal; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb.EventParticipantFacadeEjbLocal; @@ -85,6 +85,7 @@ import de.symeda.sormas.backend.travelentry.TravelEntryFacadeEjb.TravelEntryFacadeEjbLocal; import de.symeda.sormas.backend.user.UserFacadeEjb.UserFacadeEjbLocal; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.DtoHelper; import de.symeda.sormas.backend.util.RightsAllowed; @Stateless(name = "DocumentTemplateFacade") @@ -94,6 +95,9 @@ public class DocumentTemplateFacadeEjb implements DocumentTemplateFacade { public static final int EMAIL_SUBJECT_MAX_LENGTH = 50; public static final String EMAIL_TEMPLATE_SUBJECT_PREFIX = "#"; + @EJB + private DocumentTemplateService documentTemplateService; + @EJB private ConfigFacadeEjbLocal configFacade; @@ -144,18 +148,20 @@ public class DocumentTemplateFacadeEjb implements DocumentTemplateFacade { @Override @PermitAll public byte[] generateDocumentDocxFromEntities( - DocumentWorkflow documentWorkflow, - String templateName, + DocumentTemplateReferenceDto templateReference, DocumentTemplateEntities entities, Properties extraProperties) throws DocumentTemplateException { + DocumentTemplate template = documentTemplateService.getByReferenceDto(templateReference); + DocumentWorkflow documentWorkflow = template.getWorkflow(); + if (!documentWorkflow.isDocx()) { throw new DocumentTemplateException( String.format(I18nProperties.getString(Strings.messageWrongTemplateFileType), documentWorkflow, documentWorkflow.getFileExtension())); } // 1. Read template from custom directory - File templateFile = getTemplateFile(documentWorkflow, templateName); + File templateFile = documentTemplateService.getTemplateFile(template); // 2. Extract document variables DocumentVariables documentVariables = getTemplateVariablesDocx(templateFile); @@ -170,24 +176,27 @@ public byte[] generateDocumentDocxFromEntities( @Override @PermitAll public String generateDocumentTxtFromEntities( - DocumentWorkflow documentWorkflow, - String templateName, + DocumentTemplateReferenceDto templateReference, DocumentTemplateEntities entities, Properties extraProperties) throws DocumentTemplateException { - if (documentWorkflow.isDocx()) { + DocumentTemplate template = documentTemplateService.getByReferenceDto(templateReference); + if (template.getWorkflow().isDocx()) { throw new DocumentTemplateException( - String.format(I18nProperties.getString(Strings.messageWrongTemplateFileType), documentWorkflow, documentWorkflow.getFileExtension())); + String.format( + I18nProperties.getString(Strings.messageWrongTemplateFileType), + template.getWorkflow(), + template.getWorkflow().getFileExtension())); } // 1. Read template from custom directory - File templateFile = getTemplateFile(documentWorkflow, templateName); + File templateFile = documentTemplateService.getTemplateFile(template); // 2. Extract document variables DocumentVariables documentVariables = getTemplateVariablesTxt(templateFile); // 3. prepare properties - Properties properties = prepareProperties(documentWorkflow, entities, extraProperties, documentVariables); + Properties properties = prepareProperties(template.getWorkflow(), entities, extraProperties, documentVariables); // 4. generate document return generateDocumentTxt(templateFile, properties); @@ -283,34 +292,38 @@ private String generateDocumentTxt(File templateFile, Properties properties) { @Override @PermitAll - public List getAvailableTemplates(DocumentWorkflow documentWorkflow) { - File workflowTemplateDir = new File(getWorkflowTemplateDirPath(documentWorkflow).toUri()); - if (!workflowTemplateDir.exists() || !workflowTemplateDir.isDirectory()) { - return Collections.emptyList(); - } - File[] availableTemplates = - workflowTemplateDir.listFiles((d, name) -> name.toLowerCase().endsWith("." + documentWorkflow.getFileExtension())); - if (availableTemplates == null) { - return Collections.emptyList(); - } - return Arrays.stream(availableTemplates).map(File::getName).sorted(String::compareTo).collect(Collectors.toList()); + public List getAvailableTemplates(DocumentWorkflow documentWorkflow, @Nullable Disease disease) { + List templates = documentTemplateService.getByPredicate((cb, root, cq) -> { + Predicate diseasePredicate = null; + + if (disease != null) { + diseasePredicate = cb.or(cb.isNull(root.get(DocumentTemplate.DISEASE)), cb.equal(root.get(DocumentTemplate.DISEASE), disease)); + } + + return CriteriaBuilderHelper.and(cb, cb.equal(root.get(DocumentTemplate.WORKFLOW), documentWorkflow), diseasePredicate); + }); + + return templates.stream().map(DocumentTemplateFacadeEjb::toDto).collect(Collectors.toList()); } @Override @RightsAllowed({ UserRight._DOCUMENT_TEMPLATE_MANAGEMENT, UserRight._EMAIL_TEMPLATE_MANAGEMENT }) - public boolean isExistingTemplate(DocumentWorkflow documentWorkflow, String templateName) { + public boolean isExistingTemplateFile(DocumentWorkflow documentWorkflow, Disease disease, String templateName) { assertRequredUserRight(documentWorkflow); - File templateFile = new File(getWorkflowTemplateDirPath(documentWorkflow).resolve(templateName).toUri()); - return templateFile.exists(); + return documentTemplateService.existsFile(documentWorkflow, disease, templateName); + } @Override @PermitAll - public DocumentVariables getDocumentVariables(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException { - File templateFile = getTemplateFile(documentWorkflow, templateName); + public DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + DocumentTemplate template = documentTemplateService.getByReferenceDto(templateReference); + DocumentWorkflow documentWorkflow = template.getWorkflow(); + + File templateFile = documentTemplateService.getTemplateFile(template); DocumentVariables documentVariables = documentWorkflow.isDocx() ? getTemplateVariablesDocx(templateFile) : getTemplateVariablesTxt(templateFile); Set propertyKeys = documentVariables.getVariables(); @@ -326,16 +339,18 @@ public DocumentVariables getDocumentVariables(DocumentWorkflow documentWorkflow, @RightsAllowed({ UserRight._DOCUMENT_TEMPLATE_MANAGEMENT, UserRight._EMAIL_TEMPLATE_MANAGEMENT }) - public void writeDocumentTemplate(DocumentWorkflow documentWorkflow, String templateName, byte[] document) throws DocumentTemplateException { + public DocumentTemplateDto saveDocumentTemplate(DocumentTemplateDto template, byte[] document) throws DocumentTemplateException { + DocumentWorkflow documentWorkflow = template.getWorkflow(); assertRequredUserRight(documentWorkflow); - if (!documentWorkflow.getFileExtension().equalsIgnoreCase(FilenameUtils.getExtension(templateName))) { - throw new DocumentTemplateException(I18nProperties.getString(Strings.headingWrongFileType)); + String fileName = template.getFileName(); + if (!documentWorkflow.getFileExtension().equalsIgnoreCase(FilenameUtils.getExtension(fileName))) { + throw new ValidationRuntimeException(I18nProperties.getString(Strings.headingWrongFileType)); } - String path = FilenameUtils.getPath(templateName); + String path = FilenameUtils.getPath(fileName); if (StringUtils.isNotBlank(path)) { - throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorIllegalFilename), templateName)); + throw new ValidationRuntimeException(String.format(I18nProperties.getString(Strings.errorIllegalFilename), fileName)); } ByteArrayInputStream templateInputStream = new ByteArrayInputStream(document); @@ -349,56 +364,47 @@ public void writeDocumentTemplate(DocumentWorkflow documentWorkflow, String temp validateEmailTemplate(document); } - Path workflowTemplateDirPath = getWorkflowTemplateDirPath(documentWorkflow); - try { - Files.createDirectories(workflowTemplateDirPath); - } catch (IOException e) { - throw new DocumentTemplateException(I18nProperties.getString(Strings.errorCreatingTemplateDirectory)); - } - try (FileOutputStream fileOutputStream = - new FileOutputStream(new File(workflowTemplateDirPath.resolve(FilenameUtils.getName(templateName)).toUri()))) { - fileOutputStream.write(document); - } catch (IOException e) { - throw new DocumentTemplateException(I18nProperties.getString(Strings.errorWritingTemplate)); + DocumentTemplate existingTemplate = documentTemplateService.getByReferenceDto(template.toReference()); + if (existingTemplate != null) { + if (existingTemplate.getWorkflow() != template.getWorkflow()) { + throw new ValidationRuntimeException(I18nProperties.getString(Strings.errorDocumentTemplateWorkflowChangeNotAllowed)); + } + if (existingTemplate.getDisease() != template.getDisease() || existingTemplate.getFileName() != template.getFileName()) { + documentTemplateService.deleteTemplateFile(existingTemplate); + } } + + DocumentTemplate documentTemplate = fillOrBuildEntity(template, existingTemplate); + documentTemplateService.ensurePersisted(documentTemplate, document); + + return toDto(documentTemplate); } @Override @RightsAllowed({ UserRight._DOCUMENT_TEMPLATE_MANAGEMENT, UserRight._EMAIL_TEMPLATE_MANAGEMENT }) - public boolean deleteDocumentTemplate(DocumentWorkflow documentWorkflow, String fileName) throws DocumentTemplateException { - assertRequredUserRight(documentWorkflow); + public boolean deleteDocumentTemplate(DocumentTemplateReferenceDto templateReference) { + DocumentTemplate template = documentTemplateService.getByReferenceDto(templateReference); - File templateFile = new File(getWorkflowTemplateDirPath(documentWorkflow).resolve(fileName).toUri()); - if (templateFile.exists() && templateFile.isFile()) { - return templateFile.delete(); - } else { - throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorFileNotFound), fileName)); - } + assertRequredUserRight(template.getWorkflow()); + + return documentTemplateService.deletePermanent(template); } @Override @RightsAllowed({ UserRight._DOCUMENT_TEMPLATE_MANAGEMENT, UserRight._EMAIL_TEMPLATE_MANAGEMENT }) - public byte[] getDocumentTemplate(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException { - assertRequredUserRight(documentWorkflow); + public byte[] getDocumentTemplateContent(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + DocumentTemplate template = documentTemplateService.getByReferenceDto(templateReference); + assertRequredUserRight(template.getWorkflow()); try { - return FileUtils.readFileToByteArray(getTemplateFile(documentWorkflow, templateName)); + return FileUtils.readFileToByteArray(documentTemplateService.getTemplateFile(template)); } catch (IOException e) { - throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorReadingTemplate), templateName)); - } - } - - private File getTemplateFile(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException { - File templateFile = new File(getWorkflowTemplateDirPath(documentWorkflow).resolve(templateName).toString()); - - if (!templateFile.exists()) { - throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorFileNotFound), templateName)); + throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorReadingTemplate), template.getFileName())); } - return templateFile; } private DocumentVariables getTemplateVariablesDocx(File templateFile) throws DocumentTemplateException { @@ -423,10 +429,6 @@ private String getVariableBaseName(String propertyKey) { return matcher.matches() ? matcher.group(1) : ""; } - private Path getWorkflowTemplateDirPath(DocumentWorkflow documentWorkflow) { - return Paths.get(configFacade.getCustomFilesPath()).resolve("docgeneration").resolve(documentWorkflow.getTemplateDirectory()); - } - private EntityDtoAccessHelper.IReferenceDtoResolver getReferenceDtoResolver() { EntityDtoAccessHelper.IReferenceDtoResolver referenceDtoResolver = referenceDto -> { if (referenceDto != null) { @@ -482,6 +484,31 @@ private static void validateEmailTemplate(byte[] document) { } } + public static DocumentTemplateDto toDto(DocumentTemplate source) { + if (source == null) { + return null; + } + + DocumentTemplateDto target = new DocumentTemplateDto(); + DtoHelper.fillDto(target, source); + + target.setWorkflow(source.getWorkflow()); + target.setDisease(source.getDisease()); + target.setFileName(source.getFileName()); + + return target; + } + + private DocumentTemplate fillOrBuildEntity(DocumentTemplateDto source, DocumentTemplate target) { + target = DtoHelper.fillOrBuildEntity(source, target, DocumentTemplate::new, true); + + target.setWorkflow(source.getWorkflow()); + target.setDisease(source.getDisease()); + target.setFileName(source.getFileName()); + + return target; + } + public static EmailTemplateTexts splitTemplateContent(String content) { return splitTemplateContent(content, true); } @@ -499,6 +526,11 @@ private static EmailTemplateTexts splitTemplateContent(String templateString, bo return new EmailTemplateTexts(cleanupSubject ? subjectLine.substring(1).trim() : subjectLine, content); } + @PermitAll + public DocumentTemplateDto getByUuid(String uuid) { + return toDto(documentTemplateService.getByUuid(uuid)); + } + public static final class EmailTemplateTexts { private final String subject; @@ -518,7 +550,7 @@ public String getContent() { } } - public class ObjectFormatter { + public static class ObjectFormatter { public Object format(Object value) { return EntityDtoAccessHelper.formatObject(value); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateService.java new file mode 100644 index 00000000000..7aa7cba0c79 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateService.java @@ -0,0 +1,141 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.docgeneration; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; + +import org.apache.commons.io.FilenameUtils; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.backend.common.BaseAdoService; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; + +@Stateless +@LocalBean +public class DocumentTemplateService extends BaseAdoService { + + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; + + public DocumentTemplateService() { + super(DocumentTemplate.class); + } + + @Override + public boolean deletePermanent(DocumentTemplate documentTemplate) { + boolean fileDeleted = deleteTemplateFile(documentTemplate); + if (fileDeleted) { + super.deletePermanent(documentTemplate); + } + + return fileDeleted; + } + + public boolean deleteTemplateFile(DocumentTemplate documentTemplate) { + String fileName = documentTemplate.getFileName(); + File templateFile = new File(getTemplateDirPath(documentTemplate).resolve(fileName).toUri()); + + boolean deleted = false; + boolean exists = templateFile.exists(); + if (!exists) { + return true; + } + + if (templateFile.isFile()) { + deleted = templateFile.delete(); + } + + return deleted; + } + + private Path getTemplateDirPath(DocumentTemplate documentTemplate) { + return getTemplateDirPath(documentTemplate.getWorkflow(), documentTemplate.getDisease()); + } + + private Path getTemplateDirPath(DocumentWorkflow documentWorkflow, Disease disease) { + Path path = Paths.get(configFacade.getCustomFilesPath()).resolve("docgeneration").resolve(documentWorkflow.getTemplateDirectory()); + + if (disease != null) { + path = path.resolve(disease.name()); + } + + return path; + } + + public boolean existsFile(DocumentWorkflow documentWorkflow, Disease disease, String templateName) { + File templateFile = new File(this.getTemplateDirPath(documentWorkflow, disease).resolve(templateName).toUri()); + return templateFile.exists(); + } + + public void ensurePersisted(DocumentTemplate documentTemplate, byte[] document) throws DocumentTemplateException { + Path workflowTemplateDirPath = getTemplateDirPath(documentTemplate.getWorkflow(), documentTemplate.getDisease()); + try { + Files.createDirectories(workflowTemplateDirPath); + } catch (IOException e) { + throw new DocumentTemplateException(I18nProperties.getString(Strings.errorCreatingTemplateDirectory)); + } + + try (FileOutputStream fileOutputStream = + new FileOutputStream(new File(workflowTemplateDirPath.resolve(FilenameUtils.getName(documentTemplate.getFileName())).toUri()))) { + fileOutputStream.write(document); + ensurePersisted(documentTemplate); + } catch (IOException e) { + throw new DocumentTemplateException(I18nProperties.getString(Strings.errorWritingTemplate)); + } + } + + public File getTemplateFile(DocumentTemplate template) throws DocumentTemplateException { + File templateFile = new File(getTemplateDirPath(template).resolve(template.getFileName()).toString()); + + if (!templateFile.exists()) { + throw new DocumentTemplateException(String.format(I18nProperties.getString(Strings.errorFileNotFound), template.getFileName())); + } + return templateFile; + } + + public Map> getAllTemplateFiles() { + Map> templateFiles = new HashMap<>(); + + for (DocumentWorkflow workflow : DocumentWorkflow.values()) { + Path templateDirPath = getTemplateDirPath(workflow, null); + File templateDir = templateDirPath.toFile(); + + if (templateDir.exists() && templateDir.isDirectory()) { + templateFiles.put(workflow, Stream.of(templateDir.listFiles()).filter(File::isFile).collect(Collectors.toList())); + } + } + + return templateFiles; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjb.java index 02f6ab5a25f..d30496f7bef 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjb.java @@ -13,10 +13,13 @@ import org.apache.commons.io.IOUtils; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.action.ActionCriteria; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateEntities; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EventDocumentFacade; @@ -50,7 +53,7 @@ public class EventDocumentFacadeEjb implements EventDocumentFacade { @Override public String getGeneratedDocument( - String templateName, + DocumentTemplateReferenceDto templateReference, EventReferenceDto eventReference, Properties extraProperties, Boolean shouldUploadGeneratedDoc) @@ -64,13 +67,13 @@ public String getGeneratedDocument( entities .addEntity(RootEntityType.ROOT_EVENT_PARTICIPANTS, eventParticipantFacade.getAllActiveEventParticipantsByEvent(eventReference.getUuid())); - String body = documentTemplateFacade.generateDocumentTxtFromEntities(DOCUMENT_WORKFLOW, templateName, entities, extraProperties); - String styledHtml = createStyledHtml(templateName, body); + String body = documentTemplateFacade.generateDocumentTxtFromEntities(templateReference, entities, extraProperties); + String styledHtml = createStyledHtml(templateReference.getCaption(), body); if (shouldUploadGeneratedDoc) { byte[] documentToSave = styledHtml.getBytes(StandardCharsets.UTF_8);//mandatory UTF_8 try { helper.saveDocument( - helper.getDocumentFileName(eventReference, templateName), + helper.getDocumentFileName(eventReference, templateReference), DocumentDto.MIME_TYPE_DEFAULT, documentToSave.length, helper.getDocumentRelatedEntityType(eventReference), @@ -85,7 +88,7 @@ public String getGeneratedDocument( @Override public Map getGeneratedDocuments( - String templateName, + DocumentTemplateReferenceDto templateReference, List eventReferences, Properties extraProperties, Boolean shouldUploadGeneratedDoc) @@ -93,7 +96,7 @@ public Map getGeneratedDocuments( Map documents = new HashMap<>(eventReferences.size()); for (EventReferenceDto referenceDto : eventReferences) { - String documentContent = getGeneratedDocument(templateName, referenceDto, extraProperties, shouldUploadGeneratedDoc); + String documentContent = getGeneratedDocument(templateReference, referenceDto, extraProperties, shouldUploadGeneratedDoc); documents.put(referenceDto, documentContent.getBytes(StandardCharsets.UTF_8)); } @@ -101,13 +104,13 @@ public Map getGeneratedDocuments( } @Override - public List getAvailableTemplates() { - return documentTemplateFacade.getAvailableTemplates(DOCUMENT_WORKFLOW); + public List getAvailableTemplates(Disease disease) { + return documentTemplateFacade.getAvailableTemplates(DOCUMENT_WORKFLOW, disease); } @Override - public DocumentVariables getDocumentVariables(String templateName) throws DocumentTemplateException { - return documentTemplateFacade.getDocumentVariables(DOCUMENT_WORKFLOW, templateName); + public DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + return documentTemplateFacade.getDocumentVariables(templateReference); } private String createStyledHtml(String title, String body) throws DocumentTemplateException { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjb.java index 8933054aeb8..c92a09cb6e7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjb.java @@ -26,8 +26,10 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateEntities; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.QuarantineOrderFacade; @@ -59,8 +61,7 @@ public class QuarantineOrderFacadeEjb implements QuarantineOrderFacade { @Override public byte[] getGeneratedDocument( - String templateName, - DocumentWorkflow workflow, + DocumentTemplateReferenceDto templateReference, RootEntityType rootEntityType, ReferenceDto rootEntityReference, SampleReferenceDto sampleReference, @@ -72,9 +73,9 @@ public byte[] getGeneratedDocument( DocumentTemplateEntities entities = entitiesBuilder .getQuarantineOrderEntities(rootEntityType, rootEntityReference, sampleReference, pathogenTestReference, vaccinationReference); - byte[] documentToSave = documentTemplateFacade.generateDocumentDocxFromEntities(workflow, templateName, entities, extraProperties); + byte[] documentToSave = documentTemplateFacade.generateDocumentDocxFromEntities(templateReference, entities, extraProperties); if (shouldUploadGeneratedDoc) { - uploadDocument(helper.getDocumentFileName(rootEntityReference, templateName), rootEntityReference, documentToSave); + uploadDocument(helper.getDocumentFileName(rootEntityReference, templateReference), rootEntityReference, documentToSave); } return documentToSave; } @@ -105,22 +106,23 @@ private boolean isFileSizeLimitExceeded(int length) { @Override public Map getGeneratedDocuments( - String templateName, - DocumentWorkflow workflow, + DocumentTemplateReferenceDto templateReference, List rootEntityReferences, Properties extraProperties, Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException { + DocumentTemplateDto template = documentTemplateFacade.getByUuid(templateReference.getUuid()); + Map quarantineOrderEntities = - entitiesBuilder.getQuarantineOrderEntities(workflow, rootEntityReferences); + entitiesBuilder.getQuarantineOrderEntities(template.getWorkflow(), rootEntityReferences); - return getGeneratedDocuments(templateName, workflow, quarantineOrderEntities, extraProperties, shouldUploadGeneratedDoc); + return getGeneratedDocuments(templateReference, quarantineOrderEntities, extraProperties, shouldUploadGeneratedDoc); } @Override public Map getGeneratedDocumentsForEventParticipants( - String templateName, + DocumentTemplateReferenceDto templateReference, List rootEntityReferences, Disease eventDisease, Properties extraProperties, @@ -130,17 +132,11 @@ public Map getGeneratedDocumentsForEventParticipants( Map quarantineOrderEntities = entitiesBuilder.getEventParticipantQuarantineOrderEntities(rootEntityReferences, eventDisease); - return getGeneratedDocuments( - templateName, - DocumentWorkflow.QUARANTINE_ORDER_EVENT_PARTICIPANT, - quarantineOrderEntities, - extraProperties, - shouldUploadGeneratedDoc); + return getGeneratedDocuments(templateReference, quarantineOrderEntities, extraProperties, shouldUploadGeneratedDoc); } private Map getGeneratedDocuments( - String templateName, - DocumentWorkflow workflow, + DocumentTemplateReferenceDto templateReference, Map quarantineOrderEntities, Properties extraProperties, Boolean shouldUploadGeneratedDoc) @@ -149,10 +145,9 @@ private Map getGeneratedDocuments( Map documents = new HashMap<>(quarantineOrderEntities.size()); for (Map.Entry entities : quarantineOrderEntities.entrySet()) { - byte[] documentContent = - documentTemplateFacade.generateDocumentDocxFromEntities(workflow, templateName, entities.getValue(), extraProperties); + byte[] documentContent = documentTemplateFacade.generateDocumentDocxFromEntities(templateReference, entities.getValue(), extraProperties); if (shouldUploadGeneratedDoc) { - uploadDocument(helper.getDocumentFileName(entities.getKey(), templateName), entities.getKey(), documentContent); + uploadDocument(helper.getDocumentFileName(entities.getKey(), templateReference), entities.getKey(), documentContent); } documents.put(entities.getKey(), documentContent); } @@ -161,13 +156,13 @@ private Map getGeneratedDocuments( } @Override - public List getAvailableTemplates(DocumentWorkflow workflow) { - return documentTemplateFacade.getAvailableTemplates(workflow); + public List getAvailableTemplates(DocumentWorkflow workflow, Disease disease) { + return documentTemplateFacade.getAvailableTemplates(workflow, disease); } @Override - public DocumentVariables getDocumentVariables(DocumentWorkflow documentWorkflow, String templateName) throws DocumentTemplateException { - return documentTemplateFacade.getDocumentVariables(documentWorkflow, templateName); + public DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + return documentTemplateFacade.getDocumentVariables(templateReference); } @LocalBean diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java index 3f7da3c0d99..f0b40263530 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java @@ -55,6 +55,7 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.utils.HtmlHelper; +import de.symeda.sormas.api.utils.ValidationRuntimeException; import fr.opensagres.xdocreport.core.XDocReportException; import fr.opensagres.xdocreport.document.IXDocReport; import fr.opensagres.xdocreport.document.registry.XDocReportRegistry; @@ -181,13 +182,15 @@ public String generateDocumentTxt(Properties properties, File templateFile) { return Jsoup.clean(stringWriter.toString(), "", HTML_TEMPLATE_WHITELIST, outputSettings); } - public void validateTemplateDocx(InputStream templateInputStream) throws DocumentTemplateException { + public void validateTemplateDocx(InputStream templateInputStream) { try { IXDocReport report = readXDocReport(templateInputStream); FieldsExtractor extractor = FieldsExtractor.create(); report.extractFields(extractor); } catch (XDocReportException | IOException e) { - throw new DocumentTemplateException(I18nProperties.getString(Strings.errorProcessingTemplate)); + throw new ValidationRuntimeException(I18nProperties.getString(Strings.errorProcessingTemplate)); + } catch (DocumentTemplateException e) { + throw new ValidationRuntimeException(e.getMessage()); } } @@ -214,11 +217,11 @@ protected IXDocReport readXDocReport(InputStream templateInputStream) throws Doc } } - public void validateTemplateTxt(InputStream templateInputStream) throws DocumentTemplateException { + public void validateTemplateTxt(InputStream templateInputStream) { getFieldExtractorTxt(new InputStreamReader(templateInputStream), "validate"); } - private FieldsExtractor getFieldExtractorTxt(Reader templateFileReader, String templateName) throws DocumentTemplateException { + private FieldsExtractor getFieldExtractorTxt(Reader templateFileReader, String templateName) { FieldsExtractor extractor = FieldsExtractor.create(); ExtractVariablesVelocityVisitor visitor = new ExtractVariablesVelocityVisitor(extractor); try { @@ -228,7 +231,7 @@ private FieldsExtractor getFieldExtractorTxt(Reader templateFile document.jjtAccept(visitor, null); return extractor; } catch (ParseException e) { - throw new DocumentTemplateException(I18nProperties.getString(Strings.errorProcessingTemplate)); + throw new ValidationRuntimeException(I18nProperties.getString(Strings.errorProcessingTemplate)); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/document/DocumentFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/document/DocumentFacadeEjb.java index ae27dda00f1..7f5fbb42f81 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/document/DocumentFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/document/DocumentFacadeEjb.java @@ -112,7 +112,7 @@ public class DocumentFacadeEjb implements DocumentFacade { @Override public DocumentDto getDocumentByUuid(String uuid) { - return convertToDto(documentService.getByUuid(uuid), Pseudonymizer.getDefault(userService)); + return convertToDto(documentService.getByUuid(uuid), Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override @@ -157,7 +157,7 @@ public DocumentDto saveDocument(@Valid DocumentDto dto, byte[] content, @Nonnull document.setRelatedEntities(documentRelatedEntitySet); documentService.ensurePersisted(document); - return convertToDto(document, Pseudonymizer.getDefault(userService)); + return convertToDto(document, Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } catch (Throwable t) { try { documentStorageService.delete(storageReference); @@ -209,9 +209,10 @@ public void deleteDocument(String documentUuid, String relatedEntityUuid, Docume documentService.markAsDeleted(document); } } + @Override public List getDocumentsRelatedToEntity(DocumentRelatedEntityType type, String uuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); return documentService.getRelatedToEntity(type, uuid).stream().map(d -> convertToDto(d, pseudonymizer)).collect(Collectors.toList()); } @@ -222,7 +223,7 @@ public List getReferencesRelatedToEntity(DocumentRelatedEn @Override public Map> getDocumentsRelatedToEntities(DocumentCriteria criteria, List sortProperties) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); List allDocuments = documentService.getRelatedToEntities(criteria.getDocumentRelatedEntityType(), criteria.getEntityUuids(), sortProperties); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSample.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSample.java index 26f291e0157..8248c388098 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSample.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSample.java @@ -24,7 +24,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -33,6 +32,7 @@ import javax.persistence.OneToMany; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import org.hibernate.annotations.Type; @@ -85,6 +85,7 @@ public class EnvironmentSample extends DeletableAdo { private Float chlorineResiduals; private Facility laboratory; private String laboratoryDetails; + private String requestedPathogenTestsValue; private Set requestedPathogenTests; private String otherRequestedPathogenTests; private Map weatherConditions; @@ -230,14 +231,24 @@ public void setLaboratoryDetails(String laboratoryDetails) { this.laboratoryDetails = laboratoryDetails; } - @Column(columnDefinition = ModelConstants.COLUMN_DEFINITION_JSON) - @Convert(converter = RequestedPathogensConverter.class) + @Column(name = "requestedpathogentests", columnDefinition = ModelConstants.COLUMN_DEFINITION_JSON) + public String getRequestedPathogenTestsValue() { + return requestedPathogenTestsValue; + } + + public void setRequestedPathogenTestsValue(String requestedPathogenTestsValue) { + this.requestedPathogenTestsValue = requestedPathogenTestsValue; + this.requestedPathogenTests = new RequestedPathogensConverter().convertToEntityAttribute(null, requestedPathogenTestsValue); + } + + @Transient public Set getRequestedPathogenTests() { return requestedPathogenTests; } public void setRequestedPathogenTests(Set requestedPathogenTests) { this.requestedPathogenTests = requestedPathogenTests; + this.requestedPathogenTestsValue = new RequestedPathogensConverter().convertToDatabaseColumn(requestedPathogenTests); } @Column(length = CHARACTER_LIMIT_TEXT) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjb.java index 7c7fa3216fd..cea8575bc38 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjb.java @@ -42,6 +42,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.disease.PathogenConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -239,11 +240,14 @@ private void loadAndSetPositivePathogens(CriteriaBuilder cb, List positivePathogens = QueryHelper.getResultList(em, positivePathogensCq, null, null); positivePathogens.stream() - .collect(Collectors.groupingBy(t -> (Long) t.get(0), Collectors.mapping(t -> (Pathogen) t.get(1), Collectors.toList()))) + .collect( + Collectors.groupingBy( + t -> (Long) t.get(0), + Collectors.mapping(t -> new PathogenConverter().convertToEntityAttribute(null, (String) t.get(1)), Collectors.toList()))) .forEach( (sampleId, pathogens) -> samples.stream() .filter(s -> s.getId().equals(sampleId)) @@ -260,7 +264,7 @@ private void loadAndSetLatestTest(CriteriaBuilder cb, List sampleIdExpr = testRoot.get(PathogenTest.ENVIRONMENT_SAMPLE).get(Sample.ID); testCq.multiselect( - testRoot.get(PathogenTest.TESTED_PATHOGEN), + testRoot.get(PathogenTest.TESTED_PATHOGEN_VALUE), testRoot.get(PathogenTest.TESTED_PATHOGEN_DETAILS), testRoot.get(PathogenTest.TEST_RESULT), sampleIdExpr); @@ -274,7 +278,7 @@ private void loadAndSetLatestTest(CriteriaBuilder cb, List (Long) pathogenTest[3], Function.identity(), (t1, t2) -> t1)) .forEach((sampleId, t) -> samples.stream().filter(s -> s.getId().equals(sampleId)).findFirst().ifPresent(s -> { - s.setLatestTestedPathogen((Pathogen) t[0]); + s.setLatestTestedPathogen(new PathogenConverter().convertToEntityAttribute(null, (String) t[0])); s.setLatestTestedPathogenDetails((String) t[1]); s.setLatestPathogenTestResult((PathogenTestResultType) t[2]); })); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleService.java index 35ac3d17963..15caca625d7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleService.java @@ -164,8 +164,10 @@ public Predicate buildCriteriaFilter(EnvironmentSampleCriteria criteria, Environ filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(joins.getLaboratory().get(Facility.UUID), criteria.getLaboratory().getUuid())); } if (criteria.getTestedPathogen() != null) { - filter = CriteriaBuilderHelper - .and(cb, filter, cb.equal(joins.getPathogenTests().get(PathogenTestDto.TESTED_PATHOGEN), criteria.getTestedPathogen())); + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.equal(joins.getPathogenTests().get(PathogenTest.TESTED_PATHOGEN_VALUE), criteria.getTestedPathogen().getValue())); } if (criteria.getReportDateFrom() != null && criteria.getReportDateTo() != null) { filter = CriteriaBuilderHelper diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/RequestedPathogensConverter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/RequestedPathogensConverter.java index ea8fde070e8..99c2ca24c69 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/RequestedPathogensConverter.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/environmentsample/RequestedPathogensConverter.java @@ -19,28 +19,27 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.persistence.AttributeConverter; - +import de.symeda.sormas.api.Disease; import org.apache.commons.lang3.StringUtils; import de.symeda.sormas.api.environment.environmentsample.Pathogen; -import de.symeda.sormas.backend.disease.PathogenConverter; +import de.symeda.sormas.api.disease.PathogenConverter; -public class RequestedPathogensConverter implements AttributeConverter, String> { +public class RequestedPathogensConverter { private final PathogenConverter pathogenConverter = new PathogenConverter(); - @Override public String convertToDatabaseColumn(Set pathogens) { return pathogens != null ? String.join(",", pathogens.stream().map(pathogenConverter::convertToDatabaseColumn).collect(Collectors.toSet())) : null; } - @Override - public Set convertToEntityAttribute(String pathogensText) { + public Set convertToEntityAttribute(Disease disease, String pathogensText) { return pathogensText != null - ? Stream.of(StringUtils.split(pathogensText, ",")).map(pathogenConverter::convertToEntityAttribute).collect(Collectors.toSet()) + ? Stream.of(StringUtils.split(pathogensText, ",")) + .map((String value) -> pathogenConverter.convertToEntityAttribute(disease, value)) + .collect(Collectors.toSet()) : null; } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java index 26202be9bf5..c089347ddc3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java @@ -24,7 +24,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -37,7 +36,9 @@ import javax.persistence.OneToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; +import de.symeda.sormas.api.event.SpecificRiskConverter; import org.hibernate.annotations.Type; import de.symeda.sormas.api.Disease; @@ -64,7 +65,7 @@ import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.action.Action; import de.symeda.sormas.backend.common.CoreAdo; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.location.Location; import de.symeda.sormas.backend.share.ExternalShareInfo; import de.symeda.sormas.backend.sormastosormas.entities.SormasToSormasShareable; @@ -88,7 +89,7 @@ public class Event extends CoreAdo implements SormasToSormasShareable, HasExtern public static final String INTERNAL_TOKEN = "internalToken"; public static final String EVENT_STATUS = "eventStatus"; public static final String RISK_LEVEL = "riskLevel"; - public static final String SPECIFIC_RISK = "specificRisk"; + public static final String SPECIFIC_RISK_VALUE = "specificRiskValue"; public static final String EVENT_INVESTIGATION_STATUS = "eventInvestigationStatus"; public static final String EVENT_INVESTIGATION_START_DATE = "eventInvestigationStartDate"; public static final String EVENT_INVESTIGATION_END_DATE = "eventInvestigationEndDate"; @@ -123,7 +124,7 @@ public class Event extends CoreAdo implements SormasToSormasShareable, HasExtern public static final String SRC_MEDIA_NAME = "srcMediaName"; public static final String SRC_MEDIA_DETAILS = "srcMediaDetails"; public static final String DISEASE = "disease"; - public static final String DISEASE_VARIANT = "diseaseVariant"; + public static final String DISEASE_VARIANT_VALUE = "diseaseVariantValue"; public static final String DISEASE_DETAILS = "diseaseDetails"; public static final String DISEASE_VARIANT_DETAILS = "diseaseVariantDetails"; public static final String RESPONSIBLE_USER = "responsibleUser"; @@ -151,6 +152,7 @@ public class Event extends CoreAdo implements SormasToSormasShareable, HasExtern private EventStatus eventStatus; private RiskLevel riskLevel; + private String specificRiskValue; private SpecificRisk specificRisk; private EventInvestigationStatus eventInvestigationStatus; private Date eventInvestigationStartDate; @@ -185,6 +187,7 @@ public class Event extends CoreAdo implements SormasToSormasShareable, HasExtern private String srcMediaName; private String srcMediaDetails; private Disease disease; + private String diseaseVariantValue; private DiseaseVariant diseaseVariant; private String diseaseDetails; private String diseaseVariantDetails; @@ -238,14 +241,24 @@ public void setRiskLevel(RiskLevel riskLevel) { this.riskLevel = riskLevel; } - @Column - @Convert(converter = SpecificRiskConverter.class) + @Column(name = "specificrisk") + public String getSpecificRiskValue() { + return specificRiskValue; + } + + public void setSpecificRiskValue(String specificRiskValue) { + this.specificRiskValue = specificRiskValue; + this.specificRisk = new SpecificRiskConverter().convertToEntityAttribute(disease, specificRiskValue); + } + + @Transient public SpecificRisk getSpecificRisk() { return specificRisk; } public void setSpecificRisk(SpecificRisk specificRisk) { this.specificRisk = specificRisk; + this.specificRiskValue = new SpecificRiskConverter().convertToDatabaseColumn(specificRisk); } @Enumerated(EnumType.STRING) @@ -548,14 +561,24 @@ public void setDisease(Disease disease) { this.disease = disease; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "diseasevariant") + public String getDiseaseVariantValue() { + return diseaseVariantValue; + } + + public void setDiseaseVariantValue(String diseaseVariantValue) { + this.diseaseVariantValue = diseaseVariantValue; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariantValue); + } + + @Transient public DiseaseVariant getDiseaseVariant() { return diseaseVariant; } public void setDiseaseVariant(DiseaseVariant diseaseVariant) { this.diseaseVariant = diseaseVariant; + this.diseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); } @Column(length = CHARACTER_LIMIT_DEFAULT) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 3d776fe4351..da748cf65c0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -497,11 +497,11 @@ public List getIndexList(EventCriteria eventCriteria, Integer fir event.get(Event.INTERNAL_TOKEN), event.get(Event.EVENT_STATUS), event.get(Event.RISK_LEVEL), - event.get(Event.SPECIFIC_RISK), + event.get(Event.SPECIFIC_RISK_VALUE), event.get(Event.EVENT_INVESTIGATION_STATUS), event.get(Event.EVENT_MANAGEMENT_STATUS), event.get(Event.DISEASE), - event.get(Event.DISEASE_VARIANT), + event.get(Event.DISEASE_VARIANT_VALUE), event.get(Event.DISEASE_DETAILS), event.get(Event.START_DATE), event.get(Event.END_DATE), @@ -838,12 +838,12 @@ public List getExportList(EventCriteria eventCriteria, Collectio event.get(Event.INTERNAL_TOKEN), event.get(Event.EVENT_STATUS), event.get(Event.RISK_LEVEL), - event.get(Event.SPECIFIC_RISK), + event.get(Event.SPECIFIC_RISK_VALUE), event.get(Event.EVENT_INVESTIGATION_STATUS), event.get(Event.EVENT_INVESTIGATION_START_DATE), event.get(Event.EVENT_INVESTIGATION_END_DATE), event.get(Event.DISEASE), - event.get(Event.DISEASE_VARIANT), + event.get(Event.DISEASE_VARIANT_VALUE), event.get(Event.DISEASE_DETAILS), event.get(Event.DISEASE_VARIANT_DETAILS), event.get(Event.START_DATE), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventIndexDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventIndexDtoResultTransformer.java index eace54ae644..087c1598753 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventIndexDtoResultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventIndexDtoResultTransformer.java @@ -43,8 +43,8 @@ public EventIndexDto transformTuple(Object[] tuple, String[] aliases) { //@formatter:off return new EventIndexDto( (Long) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], - (EventStatus) tuple[++index], (RiskLevel) tuple[++index], (SpecificRisk) tuple[++index], (EventInvestigationStatus) tuple[++index], - (EventManagementStatus) tuple[++index], (Disease) tuple[++index], (DiseaseVariant) tuple[++index], (String) tuple[++index], + (EventStatus) tuple[++index], (RiskLevel) tuple[++index], (String) tuple[++index], (EventInvestigationStatus) tuple[++index], + (EventManagementStatus) tuple[++index], (Disease) tuple[++index], (String) tuple[++index], (String) tuple[++index], (Date) tuple[++index], (Date) tuple[++index], (Date) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 39f4e5766a2..f5526b3588e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -104,6 +104,7 @@ import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; @@ -180,6 +181,8 @@ public class EventParticipantFacadeEjb private VaccinationService vaccinationService; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; public EventParticipantFacadeEjb() { } @@ -1157,7 +1160,7 @@ public EventParticipant fillOrBuildEntity(@NotNull EventParticipantDto source, E @Override protected Pseudonymizer createPseudonymizer(List eventParticipants) { - return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(eventParticipants)); + return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(eventParticipants), configFacade.getCountryCode()); } private SpecialAccessCheck createSpecialAccessChecker( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index a9941a14f7e..781b2fb686a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -333,7 +333,7 @@ public void restore(EventParticipant eventParticipant) { } @Override - public void deletePermanent(EventParticipant eventParticipant) { + public boolean deletePermanent(EventParticipant eventParticipant) { if (eventParticipant.getSamples() != null) { for (Sample sample : eventParticipant.getSamples()) { if (sample.getAssociatedCase() == null && sample.getAssociatedContact() == null) { @@ -354,6 +354,7 @@ public void deletePermanent(EventParticipant eventParticipant) { }); super.deletePermanent(eventParticipant); + return false; } public List getAllUuidsByEventUuids(List eventUuids) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index 7814c312f48..f394c5f72c6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -638,7 +638,7 @@ public void restore(Event event) { } @Override - public void deletePermanent(Event event) { + public boolean deletePermanent(Event event) { // Delete all tasks associated with this event List tasks = taskService.findBy(new TaskCriteria().event(new EventReferenceDto(event.getUuid())), true); @@ -677,6 +677,7 @@ public void deletePermanent(Event event) { removeFromSubordinateEvents(event); super.deletePermanent(event); + return false; } private void removeFromSubordinateEvents(Event event) { @@ -721,7 +722,7 @@ public Predicate buildCriteriaFilter(EventCriteria eventCriteria, EventQueryCont filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.DISEASE), eventCriteria.getDisease())); } if (eventCriteria.getDiseaseVariant() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.DISEASE_VARIANT), eventCriteria.getDiseaseVariant())); + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.DISEASE_VARIANT_VALUE), eventCriteria.getDiseaseVariant().getValue())); } if (eventCriteria.getEventStatus() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.EVENT_STATUS), eventCriteria.getEventStatus())); @@ -730,7 +731,7 @@ public Predicate buildCriteriaFilter(EventCriteria eventCriteria, EventQueryCont filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.RISK_LEVEL), eventCriteria.getRiskLevel())); } if (eventCriteria.getSpecificRisk() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.SPECIFIC_RISK), eventCriteria.getSpecificRisk())); + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.SPECIFIC_RISK_VALUE), eventCriteria.getSpecificRisk().getValue())); } if (eventCriteria.getEventInvestigationStatus() != null) { filter = CriteriaBuilderHelper diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjb.java index c61d503ac4f..aac294570ad 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjb.java @@ -51,6 +51,7 @@ import de.symeda.sormas.api.common.progress.ProcessedEntity; import de.symeda.sormas.api.common.progress.ProcessedEntityStatus; import de.symeda.sormas.api.contact.ContactReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateEntities; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; @@ -157,8 +158,8 @@ public class ExternalEmailFacadeEjb implements ExternalEmailFacade { private DocGenerationHelper docGenerationHelper; @Override - public List getTemplateNames(DocumentWorkflow documentWorkflow) { - return documentTemplateFacade.getAvailableTemplates(documentWorkflow); + public List getTemplates(DocumentWorkflow documentWorkflow) { + return documentTemplateFacade.getAvailableTemplates(documentWorkflow, null); } @Override @@ -200,7 +201,7 @@ private void sendEmail(@Valid ExternalEmailOptionsDto options, boolean onlyLinke String personalizedFileName = null; Map filesToBeEncryped = new HashMap<>(); - if (options.getQuarantineOrderDocumentOptions() != null && options.getQuarantineOrderDocumentOptions().getTemplateFile() != null) { + if (options.getQuarantineOrderDocumentOptions() != null && options.getQuarantineOrderDocumentOptions().getTemplate() != null) { Map.Entry fileFromTemplate = createFileFromTemplate(options); personalizedFile = fileFromTemplate.getKey(); personalizedFileName = fileFromTemplate.getValue(); @@ -232,8 +233,7 @@ private void sendEmail(@Valid ExternalEmailOptionsDto options, boolean onlyLinke emailAttachments = attachmentService.createEncryptedPdfs(filesToBeEncryped, password); } - String generatedText = - documentTemplateFacade.generateDocumentTxtFromEntities(options.getDocumentWorkflow(), options.getTemplateName(), documentEntities, null); + String generatedText = documentTemplateFacade.generateDocumentTxtFromEntities(options.getTemplate(), documentEntities, null); EmailTemplateTexts emailTexts = splitTemplateContent(generatedText); try { @@ -281,8 +281,7 @@ private void sendEmail(@Valid ExternalEmailOptionsDto options, boolean onlyLinke private Map.Entry createFileFromTemplate(ExternalEmailOptionsDto emailOptions) throws DocumentTemplateException, IOException { QuarantineOrderDocumentOptionsDto documentOptions = emailOptions.getQuarantineOrderDocumentOptions(); byte[] generatedDocument = quarantineOrderFacade.getGeneratedDocument( - documentOptions.getTemplateFile(), - documentOptions.getDocumentWorkflow(), + documentOptions.getTemplate(), emailOptions.getRootEntityType(), emailOptions.getRootEntityReference(), null, @@ -291,7 +290,7 @@ private Map.Entry createFileFromTemplate(ExternalEmailOptionsDto e documentOptions.getExtraProperties(), // document uploading will be handled in another place false); - String fileName = docGenerationHelper.getDocumentFileName(emailOptions.getRootEntityReference(), documentOptions.getTemplateFile()); + String fileName = docGenerationHelper.getDocumentFileName(emailOptions.getRootEntityReference(), documentOptions.getTemplate()); File tempTemplateFile = Paths.get(configFacade.getTempFilesPath()).resolve(fileName).toFile(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(Files.newOutputStream(tempTemplateFile.toPath())); bufferedOutputStream.write(generatedDocument); @@ -341,7 +340,7 @@ public List sendBulkEmail(@Valid ExternalEmailOptionsWithAttach try { ExternalEmailOptionsDto emailOptions = new ExternalEmailOptionsDto(options.getDocumentWorkflow(), options.getRootEntityType(), entityRef); - emailOptions.setTemplateName(options.getTemplateName()); + emailOptions.setTemplate(options.getTemplate()); emailOptions.setAttachedDocuments(attachedDocuments); emailOptions.setRootEntityReference(entityRef); @@ -481,7 +480,7 @@ private ManualMessageLog createMessageLog( log.setRecipientPerson(personService.getByReferenceDto(personRef)); log.setSentDate(new Date()); log.setEmailAddress(options.getRecipientEmail()); - log.setUsedTemplate(options.getTemplateName()); + log.setUsedTemplate(options.getTemplate().getCaption()); log.setAttachedDocuments(attachedDocumentsName); // `*Service::getByReferenceDto` does a null check, so we don't need to do it here diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessage.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessage.java index 4785bc2b3e5..72a7698665f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessage.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessage.java @@ -8,7 +8,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -19,6 +18,7 @@ import javax.persistence.OneToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; @@ -26,15 +26,17 @@ import com.vladmihalcea.hibernate.type.array.ListArrayType; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.disease.DiseaseVariant; import de.symeda.sormas.api.externalmessage.ExternalMessageStatus; import de.symeda.sormas.api.externalmessage.ExternalMessageType; import de.symeda.sormas.api.person.PhoneNumberType; import de.symeda.sormas.api.person.PresentCondition; import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.surveillancereport.SurveillanceReport; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.externalmessage.labmessage.SampleReport; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.facility.Facility; @@ -50,7 +52,7 @@ public class ExternalMessage extends AbstractDomainObject { public static final String TYPE = "type"; public static final String DISEASE = "disease"; - public static final String DISEASE_VARIANT = "diseaseVariant"; + public static final String DISEASE_VARIANT_VALUE = "diseaseVariantValue"; public static final String DISEASE_VARIANT_DETAILS = "diseaseVariantDetails"; public static final String MESSAGE_DATE_TIME = "messageDateTime"; public static final String CASE_REPORT_DATE = "caseReportDate"; @@ -85,6 +87,7 @@ public class ExternalMessage extends AbstractDomainObject { private ExternalMessageType type; private Disease disease; + private String diseaseVariantValue; private DiseaseVariant diseaseVariant; private String diseaseVariantDetails; private Date messageDateTime; @@ -126,6 +129,9 @@ public class ExternalMessage extends AbstractDomainObject { private String tsv; private String personAdditionalDetails; + private VaccinationStatus vaccinationStatus; + private YesNoUnknown admittedToHealthFacility; + @Enumerated(EnumType.STRING) public ExternalMessageType getType() { return type; @@ -144,14 +150,24 @@ public void setDisease(Disease disease) { this.disease = disease; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "diseasevariant") + public String getDiseaseVariantValue() { + return diseaseVariantValue; + } + + public void setDiseaseVariantValue(String diseaseVariantValue) { + this.diseaseVariantValue = diseaseVariantValue; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariantValue); + } + + @Transient public DiseaseVariant getDiseaseVariant() { return diseaseVariant; } public void setDiseaseVariant(DiseaseVariant diseaseVariant) { this.diseaseVariant = diseaseVariant; + this.diseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); } @Column(length = CHARACTER_LIMIT_DEFAULT) @@ -460,4 +476,22 @@ public String getPersonAdditionalDetails() { public void setPersonAdditionalDetails(String personAdditionalDetails) { this.personAdditionalDetails = personAdditionalDetails; } + + @Enumerated(EnumType.STRING) + public VaccinationStatus getVaccinationStatus() { + return vaccinationStatus; + } + + public void setVaccinationStatus(VaccinationStatus vaccinationStatus) { + this.vaccinationStatus = vaccinationStatus; + } + + @Enumerated(EnumType.STRING) + public YesNoUnknown getAdmittedToHealthFacility() { + return admittedToHealthFacility; + } + + public void setAdmittedToHealthFacility(YesNoUnknown admittedToHealthFacility) { + this.admittedToHealthFacility = admittedToHealthFacility; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjb.java index b21a7c3e732..81fe078bf4d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjb.java @@ -192,6 +192,9 @@ ExternalMessage fillOrBuildEntity(@NotNull ExternalMessageDto source, ExternalMe target.setSampleReports(sampleReports); } target.setSurveillanceReport(surveillanceReportService.getByReferenceDto(source.getSurveillanceReport())); + target.setVaccinationStatus(source.getVaccinationStatus()); + target.setAdmittedToHealthFacility(source.getAdmittedToHealthFacility()); + return target; } @@ -368,6 +371,9 @@ public ExternalMessageDto toDto(ExternalMessage source) { target.setAssignee(source.getAssignee().toReference()); } + target.setVaccinationStatus(source.getVaccinationStatus()); + target.setAdmittedToHealthFacility(source.getAdmittedToHealthFacility()); + return target; } @@ -486,7 +492,7 @@ public List getIndexList( externalMessage.get(ExternalMessage.REPORTER_NAME), externalMessage.get(ExternalMessage.REPORTER_POSTAL_CODE), externalMessage.get(ExternalMessage.DISEASE), - externalMessage.get(ExternalMessage.DISEASE_VARIANT), + externalMessage.get(ExternalMessage.DISEASE_VARIANT_VALUE), externalMessage.get(ExternalMessage.PERSON_FIRST_NAME), externalMessage.get(ExternalMessage.PERSON_LAST_NAME), externalMessage.get(ExternalMessage.PERSON_BIRTH_DATE_YYYY), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageIndexDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageIndexDtoResultTransformer.java index 0c00756ee2a..58c1574b6b7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageIndexDtoResultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageIndexDtoResultTransformer.java @@ -37,7 +37,7 @@ public ExternalMessageIndexDto transformTuple(Object[] tuple, String[] aliases) //@formatter:off return new ExternalMessageIndexDto( (String) tuple[++index], (ExternalMessageType) tuple[++index], (Date) tuple[++index], (String) tuple[++index], - (String) tuple[++index], (Disease) tuple[++index], (DiseaseVariant) tuple[++index], + (String) tuple[++index], (Disease) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (Integer) tuple[++index], (Integer) tuple[++index], (Integer) tuple[++index], (String) tuple[++index], (ExternalMessageStatus) tuple[++index], diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageService.java index f4bd04ba457..d40f751e5ae 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/ExternalMessageService.java @@ -50,9 +50,10 @@ public ExternalMessageService() { } @Override - public void deletePermanent(ExternalMessage externalMessage) { + public boolean deletePermanent(ExternalMessage externalMessage) { super.deletePermanent(externalMessage); + return false; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) @@ -91,7 +92,8 @@ public Predicate buildCriteriaFilter(CriteriaBuilder cb, Root l filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(labMessage.get(ExternalMessage.DISEASE), criteria.getDisease())); } if (criteria.getDiseaseVariant() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(labMessage.get(ExternalMessage.DISEASE_VARIANT), criteria.getDiseaseVariant())); + filter = CriteriaBuilderHelper + .and(cb, filter, cb.equal(labMessage.get(ExternalMessage.DISEASE_VARIANT_VALUE), criteria.getDiseaseVariant().getValue())); } if (criteria.getExternalMessageStatus() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(labMessage.get(ExternalMessage.STATUS), criteria.getExternalMessageStatus())); @@ -122,6 +124,7 @@ public Predicate buildCriteriaFilter(CriteriaBuilder cb, Root 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)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java index beaa4e0eb02..763177459f2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java @@ -15,7 +15,11 @@ package de.symeda.sormas.backend.externalmessage.labmessage; +import java.text.Collator; +import java.util.Comparator; +import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -42,6 +46,7 @@ import de.symeda.sormas.api.event.EventParticipantDto; import de.symeda.sormas.api.event.SimilarEventParticipantDto; import de.symeda.sormas.api.externalmessage.ExternalMessageDto; +import de.symeda.sormas.api.externalmessage.labmessage.SampleReportDto; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageMapper; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageProcessingFacade; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageProcessingResult; @@ -148,7 +153,7 @@ protected void handlePickOrCreatePerson(PersonDto person, HandlerCallback similarCaseUuids = similarCases.stream().map(CaseSelectionDto::getUuid).collect(Collectors.toSet()); - String caseUuid = caseService.getCaseUuidForAutomaticSampleAssignment(similarCaseUuids, disease, automaticSampleAssignmentThreshold); + Date sampleDate = externalMessageDto.getSampleReports() + .stream() + .map(SampleReportDto::getSampleDateTime) + .filter(Objects::nonNull) + .min(Comparator.comparing(Date::getTime)) + .orElse(null); + String caseUuid = + caseService.getCaseUuidForAutomaticSampleAssignment(similarCaseUuids, disease, sampleDate, automaticSampleAssignmentThreshold); if (caseUuid == null) { logger.debug( @@ -316,5 +328,20 @@ private boolean unsetOrMatches(T personValue, T messageValue) { return personValue.equals(messageValue); } + + private boolean unsetOrMatches(String personValue, String messageValue) { + if (personValue == null || messageValue == null) { + return true; + } + + Collator collator = Collator.getInstance(); + collator.setStrength(Collator.PRIMARY); + + return collator.compare(normalizatString(personValue), normalizatString(messageValue)) == 0; + } + + private String normalizatString(String string) { + return string.replaceAll("[\\s-,;:]", ""); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/SampleReportService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/SampleReportService.java index 8153c30db63..542a4ca6fd0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/SampleReportService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/SampleReportService.java @@ -15,8 +15,7 @@ package de.symeda.sormas.backend.externalmessage.labmessage; -import de.symeda.sormas.backend.common.BaseAdoService; -import de.symeda.sormas.backend.common.DeletableAdo; +import java.util.Optional; import javax.ejb.EJB; import javax.ejb.LocalBean; @@ -25,7 +24,9 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import java.util.Optional; + +import de.symeda.sormas.backend.common.BaseAdoService; +import de.symeda.sormas.backend.common.DeletableAdo; @Stateless @LocalBean @@ -47,10 +48,11 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) } @Override - public void deletePermanent(SampleReport sampleReport) { + public boolean deletePermanent(SampleReport sampleReport) { Optional.ofNullable(sampleReport.getTestReports()).ifPresent(testReports -> testReports.forEach(t -> testReportService.deletePermanent(t))); super.deletePermanent(sampleReport); + return false; } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index f3132958c5b..10265699d6b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -41,6 +41,9 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.ConfigFacade; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -170,6 +173,8 @@ public class ImmunizationFacadeEjb private VaccinationService vaccinationService; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; public ImmunizationFacadeEjb() { } @@ -440,7 +445,7 @@ public ImmunizationDto save(@Valid @NotNull ImmunizationDto dto, boolean checkCh @Override protected Pseudonymizer createPseudonymizer(List immunizations) { - return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(immunizations)); + return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(immunizations), configFacade.getCountryCode()); } private SpecialAccessCheck getSpecialAccessChecker(Collection immunizations) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index 237cdad9507..5b3e12e0d7e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -22,7 +22,6 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.stream.Collectors; import javax.ejb.EJB; import javax.ejb.LocalBean; @@ -30,16 +29,19 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.Tuple; +import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaUpdate; import javax.persistence.criteria.From; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.criteria.Subquery; +import javax.validation.constraints.NotNull; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.EditPermissionType; @@ -53,7 +55,6 @@ import de.symeda.sormas.api.immunization.ImmunizationStatus; import de.symeda.sormas.api.immunization.MeansOfImmunization; import de.symeda.sormas.api.person.PersonAssociation; -import de.symeda.sormas.api.person.PersonCriteria; import de.symeda.sormas.api.sormastosormas.share.incoming.ShareRequestStatus; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractCoreAdoService; @@ -70,7 +71,6 @@ import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.person.PersonJoins; import de.symeda.sormas.backend.person.PersonJurisdictionPredicateValidator; -import de.symeda.sormas.backend.person.PersonQueryContext; import de.symeda.sormas.backend.person.PersonService; import de.symeda.sormas.backend.sormastosormas.origin.SormasToSormasOriginInfo; import de.symeda.sormas.backend.sormastosormas.share.outgoing.ShareRequestInfo; @@ -87,7 +87,6 @@ import de.symeda.sormas.backend.util.QueryHelper; import de.symeda.sormas.backend.vaccination.LastVaccinationDate; import de.symeda.sormas.backend.vaccination.Vaccination; -import org.hibernate.query.Query; @Stateless @LocalBean @@ -108,8 +107,26 @@ public ImmunizationService() { super(Immunization.class, DeletableEntityType.IMMUNIZATION); } + public Long getIdByUuid(@NotNull String uuid) { + + if (uuid == null) { + return null; + } + + CriteriaBuilder cb = em.getCriteriaBuilder(); + ParameterExpression uuidParam = cb.parameter(String.class, AbstractDomainObject.UUID); + CriteriaQuery cq = cb.createQuery(Long.class); + Root from = cq.from(Immunization.class); + cq.select(from.get(AbstractDomainObject.ID)); + cq.where(cb.equal(from.get(AbstractDomainObject.UUID), uuidParam)); + + TypedQuery q = em.createQuery(cq).setParameter(uuidParam, uuid); + + return q.getResultList().stream().findFirst().orElse(null); + } + @Override - public void deletePermanent(Immunization immunization) { + public boolean deletePermanent(Immunization immunization) { // Remove the immunization from any S2S share info referencing it sormasToSormasShareInfoService.getByAssociatedEntity(SormasToSormasShareInfo.IMMUNIZATION, immunization.getUuid()).forEach(s -> { @@ -131,6 +148,7 @@ public void deletePermanent(Immunization immunization) { } super.deletePermanent(immunization); + return false; } public List getEntriesList(Long personId, Disease disease, Integer first, Integer max) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java deleted file mode 100644 index 72d898f1a5f..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package de.symeda.sormas.backend.info; - -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.Date; -import java.util.Map; -import java.util.function.Function; - -import javax.validation.constraints.NotNull; - -import org.apache.commons.lang3.reflect.TypeUtils; - -import de.symeda.sormas.api.Disease; -import de.symeda.sormas.api.EntityDto; -import de.symeda.sormas.api.ReferenceDto; -import de.symeda.sormas.api.i18n.Captions; -import de.symeda.sormas.api.i18n.I18nProperties; -import de.symeda.sormas.api.i18n.Strings; -import de.symeda.sormas.api.utils.DataHelper; -import de.symeda.sormas.api.utils.Diseases; -import de.symeda.sormas.api.utils.HideForCountries; -import de.symeda.sormas.api.utils.HideForCountriesExcept; -import de.symeda.sormas.api.utils.Outbreaks; -import de.symeda.sormas.api.utils.PersonalData; -import de.symeda.sormas.api.utils.SensitiveData; - -public enum EntityColumn { - - ENTITY(256 * 30, EntityColumn::getEntity, false, true, true), - FIELD_ID(256 * 30, EntityColumn::getFieldId, false, true, false), - FIELD(256 * 30, EntityColumn::getFieldName, false, true, false), - TYPE(256 * 30, EntityColumn::getFieldType, true, true, false), - DATA_PROTECTION(256 * 30, EntityColumn::getDataProtection, false, true, false), - CAPTION(256 * 30, EntityColumn::getCaption, false, true, false), - DESCRIPTION(256 * 60, EntityColumn::getDescription, true, true, false), - REQUIRED(256 * 10, EntityColumn::getNotNull, false, true, false), - NEW_DISEASE(256 * 8, EntityColumn::getNewDisease, false, true, false), - DISEASES(256 * 45, EntityColumn::getDiseases, true, true, false), - OUTBREAKS(256 * 10, EntityColumn::getOutbreaks, false, true, false), - IGNORED_COUNTRIES(256 * 20, EntityColumn::getIgnoredCountries, false, false, false), - EXCLUSIVE_COUNTRIES(256 * 20, EntityColumn::getExclusiveCountries, false, false, false); - - private final int width; - private final Function getValueFromField; - private final boolean hasDefaultStyle; - private final boolean isDataProtectionColumn; - private final boolean isColumnForAllFieldsSheet; - - EntityColumn( - int width, - Function getValueFromField, - boolean hasDefaultStyle, - boolean isDataProtectionColumn, - boolean isColumnForAllFieldsSheet) { - - this.width = width; - this.getValueFromField = getValueFromField; - this.hasDefaultStyle = hasDefaultStyle; - this.isDataProtectionColumn = isDataProtectionColumn; - this.isColumnForAllFieldsSheet = isColumnForAllFieldsSheet; - } - - public int getWidth() { - return width; - } - - public String getGetValueFromField(FieldData fieldData) { - return getValueFromField.apply(fieldData); - } - - public boolean hasDefaultStyle() { - return hasDefaultStyle; - } - - public boolean isDataProtectionColumn() { - return isDataProtectionColumn; - } - - public boolean isColumnForAllFieldsSheet() { - return isColumnForAllFieldsSheet; - } - - @Override - public String toString() { - return I18nProperties.getEnumCaption(this); - } - - private static String getEntity(FieldData fieldData) { - return DataHelper.getHumanClassName(fieldData.getEntityClass()); - } - - private static String getFieldId(FieldData fieldData) { - return DataHelper.getHumanClassName(fieldData.getEntityClass()) + "." + fieldData.getField().getName(); - } - - private static String getFieldName(FieldData fieldData) { - return fieldData.getField().getName(); - } - - private static String getFieldType(FieldData fieldData) { - Class fieldType = fieldData.getField().getType(); - if (fieldType.isEnum()) { - // use enum type name - values are added below - return fieldType.getSimpleName(); - } else if (EntityDto.class.isAssignableFrom(fieldType)) { - return DataHelper.getHumanClassName(fieldType); - } else if (ReferenceDto.class.isAssignableFrom(fieldType)) { - return DataHelper.getHumanClassName(fieldType); - } else if (String.class.isAssignableFrom(fieldType)) { - return I18nProperties.getString(Strings.text); - } else if (Date.class.isAssignableFrom(fieldType)) { - return I18nProperties.getString(Captions.date); - } else if (Number.class.isAssignableFrom(fieldType)) { - return I18nProperties.getString(Strings.number); - } else if (Boolean.class.isAssignableFrom(fieldType) || boolean.class.isAssignableFrom(fieldType)) { - return Boolean.TRUE + ", " + Boolean.FALSE; - } else if (Collection.class.isAssignableFrom(fieldType)) { - return TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()) - .values() - .stream() - .findFirst() - .map(type -> String.format(I18nProperties.getString(Strings.listOf), DataHelper.getHumanClassName((Class) type))) - .orElseGet(fieldType::getSimpleName); - } else if (Map.class.isAssignableFrom(fieldType)) { - Type[] generics = TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()).values().toArray(new Type[0]); - if (generics.length != 2) { - throw new IllegalStateException("Could not clearly determine key and value generics."); - } - return String.format( - I18nProperties.getString(Strings.mapOf), - DataHelper.getHumanClassName((Class) generics[0]), - DataHelper.getHumanClassName((Class) generics[1])); - } - - return fieldType.getSimpleName(); - } - - private static String getDataProtection(FieldData fieldData) { - Field field = fieldData.getField(); - - if (field.getAnnotation(PersonalData.class) != null) { - return "personal"; - } else { - if (field.getAnnotation(SensitiveData.class) != null) { - return "sensitive"; - } - } - - return null; - } - - private static String getCaption(FieldData fieldData) { - return I18nProperties.getPrefixCaption(fieldData.getI18NPrefix(), fieldData.getField().getName(), ""); - } - - private static String getDescription(FieldData fieldData) { - return I18nProperties.getPrefixDescription(fieldData.getI18NPrefix(), fieldData.getField().getName(), ""); - } - - private static String getNotNull(FieldData fieldData) { - if (fieldData.getField().getAnnotation(NotNull.class) == null) { - return null; - } - - return Boolean.TRUE.toString(); - } - - private static String getNewDisease(FieldData fieldData) { - return null; - } - - private static String getDiseases(FieldData fieldData) { - Diseases diseases = fieldData.getField().getAnnotation(Diseases.class); - if (diseases == null) { - return "All"; - } else { - StringBuilder diseasesString = new StringBuilder(); - for (Disease disease : diseases.value()) { - if (diseasesString.length() > 0) - diseasesString.append(", "); - diseasesString.append(disease.toShortString()); - } - return diseasesString.toString(); - } - } - - private static String getOutbreaks(FieldData fieldData) { - if (fieldData.getField().getAnnotation(Outbreaks.class) == null) { - return null; - } - - return Boolean.TRUE.toString(); - } - - private static String getIgnoredCountries(FieldData fieldData) { - HideForCountries hideForCountries = fieldData.getField().getAnnotation(HideForCountries.class); - if (hideForCountries == null) { - return null; - } - - StringBuilder hideForCountriesString = new StringBuilder(); - for (String country : hideForCountries.countries()) { - if (hideForCountriesString.length() > 0) - hideForCountriesString.append(", "); - hideForCountriesString.append(country); - } - - return hideForCountriesString.toString(); - } - - private static String getExclusiveCountries(FieldData fieldData) { - HideForCountriesExcept hideForCountriesExcept = fieldData.getField().getAnnotation(HideForCountriesExcept.class); - if (hideForCountriesExcept == null) { - return null; - } - - StringBuilder hideForCountriesExceptString = new StringBuilder(); - for (String exceptCountry : hideForCountriesExcept.countries()) { - if (hideForCountriesExceptString.length() > 0) - hideForCountriesExceptString.append(", "); - hideForCountriesExceptString.append(exceptCountry); - } - - return hideForCountriesExceptString.toString(); - } -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumns.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumns.java new file mode 100644 index 00000000000..4dce653489a --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumns.java @@ -0,0 +1,326 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.info; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.validation.constraints.NotNull; + +import org.apache.commons.lang3.reflect.TypeUtils; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityDto; +import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.Diseases; +import de.symeda.sormas.api.utils.HideForCountries; +import de.symeda.sormas.api.utils.HideForCountriesExcept; +import de.symeda.sormas.api.utils.Outbreaks; +import de.symeda.sormas.api.utils.PersonalData; +import de.symeda.sormas.api.utils.SensitiveData; + +public class EntityColumns { + + private final EntityColumn ENTITY = new EntityColumn("ENTITY", 256 * 30, this::getEntity, false, false, false, true); + private final EntityColumn FIELD_ID = new EntityColumn("FIELD_ID", 256 * 30, EntityColumns::getFieldId, false, true, true, true); + private final EntityColumn FIELD = new EntityColumn("FIELD", 256 * 30, this::getFieldName, false, true, true, true); + private final EntityColumn TYPE = new EntityColumn("TYPE", 256 * 30, this::getFieldType, true, true, true, true); + private final EntityColumn DATA_PROTECTION = new EntityColumn("DATA_PROTECTION", 256 * 30, this::getDataProtection, false, true, true, true); + private final EntityColumn CAPTION = new EntityColumn("CAPTION", 256 * 30, this::getCaption, false, true, true, true); + private final EntityColumn DESCRIPTION = new EntityColumn("DESCRIPTION", 256 * 60, this::getDescription, true, true, true, true); + private final EntityColumn REQUIRED = new EntityColumn("REQUIRED", 256 * 10, this::getNotNull, false, true, true, true); + private final EntityColumn NEW_DISEASE = new EntityColumn("NEW_DISEASE", 256 * 8, this::getNewDisease, false, true, true, true); + private final EntityColumn DISEASES = new EntityColumn("DISEASES", 256 * 45, this::getDiseases, true, true, true, true); + private final EntityColumn OUTBREAKS = new EntityColumn("OUTBREAKS", 256 * 10, this::getOutbreaks, false, true, true, true); + private final EntityColumn IGNORED_COUNTRIES = + new EntityColumn("IGNORED_COUNTRIES", 256 * 20, this::getIgnoredCountries, false, true, false, false); + private final EntityColumn EXCLUSIVE_COUNTRIES = + new EntityColumn("EXCLUSIVE_COUNTRIES", 256 * 20, this::getExclusiveCountries, false, true, false, false); + + private final List entityColumns = List.of( + ENTITY, + FIELD_ID, + FIELD, + TYPE, + DATA_PROTECTION, + CAPTION, + DESCRIPTION, + REQUIRED, + NEW_DISEASE, + DISEASES, + OUTBREAKS, + IGNORED_COUNTRIES, + EXCLUSIVE_COUNTRIES); + + private final String serverCountry; + private final boolean isDataProtectionFlow; + + public EntityColumns(final String serverCountry, final boolean isDataProtectionFlow) { + this.serverCountry = serverCountry; + this.isDataProtectionFlow = isDataProtectionFlow; + } + + public List getEntityColumns() { + + if (isDataProtectionFlow) { + return entityColumns.stream().filter(EntityColumn::isDataProtectionColumn).collect(Collectors.toList()); + } + + return entityColumns.stream().filter(EntityColumn::isDataDictionaryColumn).collect(Collectors.toList()); + } + + public List getColumnsForAllFieldsSheet() { + return entityColumns.stream().filter(EntityColumn::isColumnForAllFieldsSheet).collect(Collectors.toList()); + } + + private String getEntity(FieldData fieldData) { + return DataHelper.getHumanClassName(fieldData.getEntityClass()); + } + + public static String getFieldId(FieldData fieldData) { + return DataHelper.getHumanClassName(fieldData.getEntityClass()) + "." + fieldData.getField().getName(); + } + + private String getFieldName(FieldData fieldData) { + return fieldData.getField().getName(); + } + + private String getFieldType(FieldData fieldData) { + Class fieldType = fieldData.getField().getType(); + if (fieldType.isEnum()) { + // use enum type name - values are added below + return fieldType.getSimpleName(); + } else if (EntityDto.class.isAssignableFrom(fieldType)) { + return DataHelper.getHumanClassName(fieldType); + } else if (ReferenceDto.class.isAssignableFrom(fieldType)) { + return DataHelper.getHumanClassName(fieldType); + } else if (String.class.isAssignableFrom(fieldType)) { + return I18nProperties.getString(Strings.text); + } else if (Date.class.isAssignableFrom(fieldType)) { + return I18nProperties.getString(Captions.date); + } else if (Number.class.isAssignableFrom(fieldType)) { + return I18nProperties.getString(Strings.number); + } else if (Boolean.class.isAssignableFrom(fieldType) || boolean.class.isAssignableFrom(fieldType)) { + return Boolean.TRUE + ", " + Boolean.FALSE; + } else if (Collection.class.isAssignableFrom(fieldType)) { + return TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()) + .values() + .stream() + .findFirst() + .map(type -> String.format(I18nProperties.getString(Strings.listOf), DataHelper.getHumanClassName((Class) type))) + .orElseGet(fieldType::getSimpleName); + } else if (Map.class.isAssignableFrom(fieldType)) { + Type[] generics = TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()).values().toArray(new Type[0]); + if (generics.length != 2) { + throw new IllegalStateException("Could not clearly determine key and value generics."); + } + return String.format( + I18nProperties.getString(Strings.mapOf), + DataHelper.getHumanClassName((Class) generics[0]), + DataHelper.getHumanClassName((Class) generics[1])); + } + + return fieldType.getSimpleName(); + } + + private String getDataProtection(FieldData fieldData) { + Field field = fieldData.getField(); + + if (field.getAnnotation(PersonalData.class) != null + && (!isDataProtectionFlow || !Arrays.asList(field.getAnnotation(PersonalData.class).excludeForCountries()).contains(serverCountry))) { + return "personal"; + } else { + if (field.getAnnotation(SensitiveData.class) != null + && (!isDataProtectionFlow + || !Arrays.asList(field.getAnnotation(SensitiveData.class).excludeForCountries()).contains(serverCountry))) { + return "sensitive"; + } + } + + return null; + } + + private String getCaption(FieldData fieldData) { + return I18nProperties.getPrefixCaption(fieldData.getI18NPrefix(), fieldData.getField().getName(), ""); + } + + private String getDescription(FieldData fieldData) { + String fieldDescription = I18nProperties.getPrefixDescription(fieldData.getI18NPrefix(), fieldData.getField().getName(), ""); + + if (isDataProtectionFlow) { + return fieldDescription; + } + + String[] excludedForCountries = null; + + Field field = fieldData.getField(); + if (field.getAnnotation(PersonalData.class) != null) { + excludedForCountries = field.getAnnotation(PersonalData.class).excludeForCountries(); + + } else if (field.getAnnotation(SensitiveData.class) != null) { + excludedForCountries = field.getAnnotation(SensitiveData.class).excludeForCountries(); + + } + + String description; + if (excludedForCountries != null && excludedForCountries.length > 0) { + description = fieldDescription + I18nProperties.getString(Strings.messageCountriesExcludedFromDataProtection) + " " + + Arrays.toString(excludedForCountries); + } else { + description = fieldDescription; + } + + return description; + } + + private String getNotNull(FieldData fieldData) { + if (fieldData.getField().getAnnotation(NotNull.class) == null) { + return null; + } + + return Boolean.TRUE.toString(); + } + + private String getNewDisease(FieldData fieldData) { + return null; + } + + private String getDiseases(FieldData fieldData) { + Diseases diseases = fieldData.getField().getAnnotation(Diseases.class); + if (diseases == null) { + return "All"; + } else { + StringBuilder diseasesString = new StringBuilder(); + for (Disease disease : diseases.value()) { + if (diseasesString.length() > 0) + diseasesString.append(", "); + diseasesString.append(disease.toShortString()); + } + return diseasesString.toString(); + } + } + + private String getOutbreaks(FieldData fieldData) { + if (fieldData.getField().getAnnotation(Outbreaks.class) == null) { + return null; + } + + return Boolean.TRUE.toString(); + } + + private String getIgnoredCountries(FieldData fieldData) { + HideForCountries hideForCountries = fieldData.getField().getAnnotation(HideForCountries.class); + if (hideForCountries == null) { + return null; + } + + StringBuilder hideForCountriesString = new StringBuilder(); + for (String country : hideForCountries.countries()) { + if (hideForCountriesString.length() > 0) + hideForCountriesString.append(", "); + hideForCountriesString.append(country); + } + + return hideForCountriesString.toString(); + } + + private String getExclusiveCountries(FieldData fieldData) { + HideForCountriesExcept hideForCountriesExcept = fieldData.getField().getAnnotation(HideForCountriesExcept.class); + if (hideForCountriesExcept == null) { + return null; + } + + StringBuilder hideForCountriesExceptString = new StringBuilder(); + for (String exceptCountry : hideForCountriesExcept.countries()) { + if (hideForCountriesExceptString.length() > 0) + hideForCountriesExceptString.append(", "); + hideForCountriesExceptString.append(exceptCountry); + } + + return hideForCountriesExceptString.toString(); + } + + public class EntityColumn { + + private final String name; + private final int width; + private final Function getValueFromField; + private final boolean hasDefaultStyle; + private final boolean isDataDictionaryColumn; + private final boolean isDataProtectionColumn; + private final boolean isColumnForAllFieldsSheet; + + EntityColumn( + String name, + int width, + Function getValueFromField, + boolean hasDefaultStyle, + boolean isDataDictionaryColumn, + boolean isDataProtectionColumn, + boolean isColumnForAllFieldsSheet) { + + this.name = name; + this.width = width; + this.getValueFromField = getValueFromField; + this.hasDefaultStyle = hasDefaultStyle; + this.isDataDictionaryColumn = isDataDictionaryColumn; + this.isDataProtectionColumn = isDataProtectionColumn; + this.isColumnForAllFieldsSheet = isColumnForAllFieldsSheet; + } + + public int getWidth() { + return width; + } + + public String getGetValueFromField(FieldData fieldData) { + return getValueFromField.apply(fieldData); + } + + public boolean hasDefaultStyle() { + return hasDefaultStyle; + } + + public boolean isDataDictionaryColumn() { + return isDataDictionaryColumn; + } + + public boolean isDataProtectionColumn() { + return isDataProtectionColumn; + } + + public boolean isColumnForAllFieldsSheet() { + return isColumnForAllFieldsSheet; + } + + @Override + public String toString() { + return I18nProperties.getPrefixCaption("EntityColumn", name); + } + + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java index 44caabb4c59..3e0c1fa8ff5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; -import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,7 +40,6 @@ import javax.ejb.Stateless; import org.apache.commons.lang3.reflect.TypeUtils; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.CellCopyPolicy; import org.apache.poi.ss.usermodel.CellStyle; @@ -110,6 +108,7 @@ import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; +import de.symeda.sormas.backend.info.EntityColumns.EntityColumn; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.XssfHelper; @@ -170,35 +169,17 @@ public class InfoFacadeEjb implements InfoFacade { @EJB private FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; - private static EnumSet getColumnsForDataDictionary() { - EnumSet enumSet = EnumSet.allOf(EntityColumn.class); - enumSet.remove(EntityColumn.ENTITY); - return enumSet; - } - @Override public boolean isGenerateDataProtectionDictionaryAllowed() { return userService.hasRight(UserRight.EXPORT_DATA_PROTECTION_DATA) && getDataProtectionFile().exists(); } - private static EnumSet getColumnsForDataProtectionDictionary() { - EnumSet enumSet = EnumSet.allOf(EntityColumn.class); - return enumSet.stream() - .filter(EntityColumn::isDataProtectionColumn) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityColumn.class))); - } - - private static EnumSet getColumnsForAllFieldsSheet(EnumSet enumSet) { - return enumSet.stream() - .filter(column -> !column.isColumnForAllFieldsSheet()) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityColumn.class))); - } - @Override public String generateDataDictionary() throws IOException { + EntityColumns entityColumns = new EntityColumns(configFacade.getCountryLocale(), false); return generateDataDictionary( DATA_DICTIONARY_ENTITIES, - getColumnsForDataDictionary(), + entityColumns, new VisibilityChecks((c, f) -> true, FieldVisibilityCheckers.getNoop()), Collections.emptyList(), Collections.emptyMap(), @@ -218,6 +199,8 @@ public String generateDataProtectionDictionary() throws IOException { .filter(e -> isVisibleByFeatureConfiguration(e.getEntityClass(), featureConfigurations)) .collect(Collectors.toList()); + EntityColumns entityColumns = new EntityColumns(configFacade.getCountryLocale(), true); + try (XSSFWorkbook dataProtectionInputWorkbook = new XSSFWorkbook(getDataProtectionFile())) { XSSFSheet dataProtectionSheet = dataProtectionInputWorkbook.getSheetAt(0); @@ -226,7 +209,7 @@ public String generateDataProtectionDictionary() throws IOException { Map> dataProtectionData = getDataProtectionCellData(dataProtectionSheet); return generateDataDictionary( entities, - getColumnsForDataProtectionDictionary(), + entityColumns, new VisibilityChecks( (dtoClass, field) -> fieldVisibilityCheckers.isVisible(dtoClass, field) && isVisibleByFeatureConfiguration(field.getType(), featureConfigurations), @@ -235,14 +218,15 @@ && isVisibleByFeatureConfiguration(field.getType(), featureConfigurations), dataProtectionData, true); - } catch (InvalidFormatException e) { + } catch (Exception e) { + e.printStackTrace(); throw new IOException(e); } } private String generateDataDictionary( List entities, - EnumSet entityColumns, + EntityColumns entityColumns, VisibilityChecks visibilityChecks, List extraColumns, Map> extraCells, @@ -256,7 +240,7 @@ private String generateDataDictionary( workbook, defaultCellStyle, entities, - entityColumns, + entityColumns.getColumnsForAllFieldsSheet(), visibilityChecks.fieldVisibilityPredicate, extraColumns, extraCells); @@ -266,7 +250,7 @@ private String generateDataDictionary( workbook, defaultCellStyle, entities, - getColumnsForAllFieldsSheet(entityColumns), + entityColumns.getEntityColumns(), visibilityChecks, extraColumns, extraCells, @@ -468,7 +452,7 @@ private void createEntitySheets( XSSFWorkbook workbook, CellStyle defaultCellStyle, List entityInfoList, - EnumSet entityColumns, + List entityColumns, VisibilityChecks visibilityChecks, List extraColumns, Map> extraCells, @@ -491,7 +475,7 @@ private void createAllFieldsSheet( XSSFWorkbook workbook, CellStyle defaultCellStyle, List entityInfoList, - EnumSet entityColumns, + List entityColumns, BiPredicate, Field> fieldVisibilityPredicate, List extraColumns, Map> extraCells) { @@ -529,7 +513,7 @@ private void createEntitySheet( XSSFWorkbook workbook, CellStyle defaultCellStyle, EntityInfo entityInfo, - EnumSet entityColumns, + List entityColumns, VisibilityChecks visibilityChecks, List extraColumns, Map> extraCells, @@ -620,7 +604,7 @@ private XSSFCell createCellsForRow(EntityColumn c, XSSFRow row, FieldData fieldD } private void copyCellsFromExtraCells(XSSFRow row, FieldData fieldData, Map> extraCells) { - String fieldId = EntityColumn.FIELD_ID.getGetValueFromField(fieldData); + String fieldId = EntityColumns.getFieldId(fieldData); if (extraCells.containsKey(fieldId)) { extraCells.get(fieldId).forEach(extraCell -> { XSSFCell newCell = row.createCell(row.getLastCellNum()); @@ -631,7 +615,7 @@ private void copyCellsFromExtraCells(XSSFRow row, FieldData fieldData, Map entityColumns, List extraColumns) { + private void buildHeader(XSSFSheet sheet, List entityColumns, List extraColumns) { XSSFRow headerRow = sheet.createRow(0); entityColumns.forEach(column -> { int colIndex = Math.max(headerRow.getLastCellNum(), 0); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/manualmessagelog/ManualMessageLogFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/manualmessagelog/ManualMessageLogFacadeEjb.java index 68546300739..983a2b33d54 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/manualmessagelog/ManualMessageLogFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/manualmessagelog/ManualMessageLogFacadeEjb.java @@ -35,6 +35,7 @@ import de.symeda.sormas.api.manualmessagelog.ManualMessageLogIndexDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.fieldaccess.checkers.AnnotationBasedFieldAccessChecker.SpecialAccessCheck; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.specialcaseaccess.SpecialCaseAccessService; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; @@ -55,6 +56,8 @@ public class ManualMessageLogFacadeEjb implements ManualMessageLogFacade { private UserService userService; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; @RightsAllowed({ UserRight._SEND_MANUAL_EXTERNAL_MESSAGES, @@ -104,7 +107,7 @@ public List getIndexList(ManualMessageLogCriteria crit @NotNull private Pseudonymizer createPseudonymizerWithPlaceholder(Collection manualMessageLogs) { - return Pseudonymizer.getDefaultWithPlaceHolder(userService, getSpecialAccessChecker(manualMessageLogs)); + return Pseudonymizer.getDefaultWithPlaceHolder(userService, getSpecialAccessChecker(manualMessageLogs), configFacade.getCountryCode()); } private SpecialAccessCheck getSpecialAccessChecker(Collection manualMessageLogs) { @@ -113,7 +116,6 @@ private SpecialAccessCheck getSpecialAccessChecker(Col return i -> specialAccessUuids.contains(i.getUuid()); } - @LocalBean @Stateless public static class ManualMessageLogFacadeEjbLocal extends ManualMessageLogFacadeEjb { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/OccupationTypeConverter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/OccupationTypeConverter.java deleted file mode 100644 index 26e59dfd31a..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/OccupationTypeConverter.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.symeda.sormas.backend.person; - -import de.symeda.sormas.api.person.OccupationType; -import de.symeda.sormas.backend.customizableenum.CustomizableEnumConverter; - -public class OccupationTypeConverter extends CustomizableEnumConverter { - - public OccupationTypeConverter() { - super(OccupationType.class); - } -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java index eee616d80fc..c3d8fc916a2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java @@ -28,7 +28,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -53,6 +52,7 @@ import de.symeda.sormas.api.person.EducationType; import de.symeda.sormas.api.person.IsPerson; import de.symeda.sormas.api.person.OccupationType; +import de.symeda.sormas.api.person.OccupationTypeConverter; import de.symeda.sormas.api.person.PersonContactDetailType; import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.person.PresentCondition; @@ -108,7 +108,7 @@ public class Person extends AbstractDomainObject implements IsPerson, HasExterna public static final String PRESENT_CONDITION = "presentCondition"; public static final String EDUCATION_TYPE = "educationType"; public static final String EDUCATION_DETAILS = "educationDetails"; - public static final String OCCUPATION_TYPE = "occupationType"; + public static final String OCCUPATION_TYPE_VALUE = "occupationTypeValue"; public static final String OCCUPATION_DETAILS = "occupationDetails"; public static final String ARMED_FORCES_RELATION_TYPE = "armedForcesRelationType"; public static final String FATHERS_NAME = "fathersName"; @@ -188,6 +188,7 @@ public class Person extends AbstractDomainObject implements IsPerson, HasExterna private EducationType educationType; private String educationDetails; + private String occupationTypeValue; private OccupationType occupationType; private String occupationDetails; private ArmedForcesRelationType armedForcesRelationType; @@ -455,14 +456,24 @@ public void setEducationDetails(String educationDetails) { this.educationDetails = educationDetails; } - @Column - @Convert(converter = OccupationTypeConverter.class) + @Column(name = "occupationtype") + public String getOccupationTypeValue() { + return occupationTypeValue; + } + + public void setOccupationTypeValue(String occupationType) { + this.occupationTypeValue = occupationType; + this.occupationType = new OccupationTypeConverter().convertToEntityAttribute(null, occupationTypeValue); + } + + @Transient public OccupationType getOccupationType() { return occupationType; } public void setOccupationType(OccupationType occupationType) { this.occupationType = occupationType; + this.occupationTypeValue = new OccupationTypeConverter().convertToDatabaseColumn(occupationType); } public String getOccupationDetails() { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 0c9d9f9f17f..a6d939302f2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -134,6 +134,7 @@ import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractBaseEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactFacadeEjb; @@ -258,6 +259,8 @@ public class PersonFacadeEjb extends AbstractBaseEjb getExportList(PersonCriteria criteria, int first, i person.get(Person.EDUCATION_TYPE), person.get(Person.EDUCATION_DETAILS), - person.get(Person.OCCUPATION_TYPE), + person.get(Person.OCCUPATION_TYPE_VALUE), person.get(Person.OCCUPATION_DETAILS), person.get(Person.ARMED_FORCES_RELATION_TYPE), @@ -1613,7 +1616,7 @@ public Page getIndexPage(PersonCriteria personCriteria, Integer @Override protected Pseudonymizer createPseudonymizer(List persons) { - return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(persons)); + return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(persons), configFacade.getCountryCode()); } private SpecialAccessCheck createSpecialAccessChecker(Collection persons) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java index b681af27ae7..57d37c49f9f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java @@ -114,6 +114,7 @@ import de.symeda.sormas.backend.travelentry.services.TravelEntryService; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.BirthdateRangeFilterPredicate; import de.symeda.sormas.backend.util.ExternalDataUtil; import de.symeda.sormas.backend.util.IterableHelper; import de.symeda.sormas.backend.util.JurisdictionHelper; @@ -353,16 +354,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: @@ -386,6 +387,15 @@ public Predicate buildCriteriaFilter(PersonCriteria personCriteria, PersonQueryC filter = andEquals(cb, personFrom, filter, personCriteria.getBirthdateYYYY(), Person.BIRTHDATE_YYYY); filter = andEquals(cb, personFrom, filter, personCriteria.getBirthdateMM(), Person.BIRTHDATE_MM); filter = andEquals(cb, personFrom, filter, personCriteria.getBirthdateDD(), Person.BIRTHDATE_DD); + + filter = BirthdateRangeFilterPredicate.createBirthdateRangeFilter( + personCriteria.getBirthdateFrom(), + personCriteria.getBirthdateTo(), + personCriteria.isIncludePartialMatch(), + cb, + personFrom, + filter); + if (personCriteria.getNameAddressPhoneEmailLike() != null) { String[] textFilters = personCriteria.getNameAddressPhoneEmailLike().split("\\s+"); @@ -408,7 +418,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); } } @@ -924,7 +935,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())); } @@ -1054,13 +1066,14 @@ private Subquery createSubquery( } @Override - public void deletePermanent(Person person) { + public boolean deletePermanent(Person person) { manualMessageLogService.getByPersonUuid(person.getUuid()) .forEach(manualMessageLog -> manualMessageLogService.deletePermanent(manualMessageLog)); visitService.deletePersonVisits(Collections.singletonList(person.getUuid())); super.deletePermanent(person); + return false; } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestFacadeEjb.java index 6e553c5bd93..394de84a91b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestFacadeEjb.java @@ -20,6 +20,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.FacadeHelper; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; @@ -38,6 +39,8 @@ public class AdditionalTestFacadeEjb implements AdditionalTestFacade { private SampleService sampleService; @EJB private UserService userService; + @EJB + private ConfigFacadeEjbLocal configFacade; @Override public AdditionalTestDto getByUuid(String uuid) { @@ -118,7 +121,7 @@ public List getAllActiveAdditionalTestsAfter(Date date, Integ private List toPseudonymizedDtos(List entities) { List inJurisdictionIds = service.getInJurisdictionIds(entities); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); return entities.stream().map(p -> convertToDto(p, pseudonymizer, inJurisdictionIds.contains(p.getId()))).collect(Collectors.toList()); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java index 52beec65f52..a521ca962af 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java @@ -23,7 +23,6 @@ import java.util.Date; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -32,6 +31,7 @@ import javax.persistence.ManyToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.disease.DiseaseVariant; @@ -41,8 +41,8 @@ import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.backend.common.DeletableAdo; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; -import de.symeda.sormas.backend.disease.PathogenConverter; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; +import de.symeda.sormas.api.disease.PathogenConverter; import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSample; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.facility.Facility; @@ -58,9 +58,9 @@ public class PathogenTest extends DeletableAdo { public static final String SAMPLE = "sample"; public static final String ENVIRONMENT_SAMPLE = "environmentSample"; public static final String TESTED_DISEASE = "testedDisease"; - public static final String TESTED_DISEASE_VARIANT = "testedDiseaseVariant"; + public static final String TESTED_DISEASE_VARIANT_VALUE = "testedDiseaseVariantValue"; public static final String TESTED_DISEASE_VARIANT_DETAILS = "testedDiseaseVariantDetails"; - public static final String TESTED_PATHOGEN = "testedPathogen"; + public static final String TESTED_PATHOGEN_VALUE = "testedPathogenValue"; public static final String TESTED_PATHOGEN_DETAILS = "testedPathogenDetails"; public static final String TYPING_ID = "typingId"; public static final String TEST_TYPE = "testType"; @@ -95,11 +95,11 @@ public class PathogenTest extends DeletableAdo { private Sample sample; private EnvironmentSample environmentSample; private Disease testedDisease; - @Convert(converter = DiseaseVariantConverter.class) + private String testedDiseaseVariantValue; private DiseaseVariant testedDiseaseVariant; private String testedDiseaseDetails; private String testedDiseaseVariantDetails; - @Convert(converter = PathogenConverter.class) + private String testedPathogenValue; private Pathogen testedPathogen; private String testedPathogenDetails; private String typingId; @@ -181,24 +181,44 @@ public void setTestedDiseaseVariantDetails(String testedDiseaseVariantDetails) { this.testedDiseaseVariantDetails = testedDiseaseVariantDetails; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "testeddiseasevariant") + public String getTestedDiseaseVariantValue() { + return testedDiseaseVariantValue; + } + + public void setTestedDiseaseVariantValue(String diseaseVariantValue) { + this.testedDiseaseVariantValue = diseaseVariantValue; + this.testedDiseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(testedDisease, testedDiseaseVariantValue); + } + + @Transient public DiseaseVariant getTestedDiseaseVariant() { return testedDiseaseVariant; } public void setTestedDiseaseVariant(DiseaseVariant diseaseVariant) { this.testedDiseaseVariant = diseaseVariant; + this.testedDiseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); } - @Column - @Convert(converter = PathogenConverter.class) + @Column(name = "testedpathogen") + public String getTestedPathogenValue() { + return testedPathogenValue; + } + + public void setTestedPathogenValue(String testedPathogenValue) { + this.testedPathogenValue = testedPathogenValue; + this.testedPathogen = new PathogenConverter().convertToEntityAttribute(null, testedPathogenValue); + } + + @Transient public Pathogen getTestedPathogen() { return testedPathogen; } public void setTestedPathogen(Pathogen testedPathogen) { this.testedPathogen = testedPathogen; + this.testedPathogenValue = new PathogenConverter().convertToDatabaseColumn(testedPathogen); } @Column(length = CHARACTER_LIMIT_DEFAULT) @@ -248,7 +268,6 @@ public void setTestTypeText(String testTypeText) { } @Temporal(TemporalType.TIMESTAMP) - @Column(nullable = false) public Date getTestDateTime() { return testDateTime; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index 4dc4a8cbe50..46a80c89851 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -60,6 +60,7 @@ import de.symeda.sormas.backend.FacadeHelper; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; @@ -120,6 +121,8 @@ public class PathogenTestFacadeEjb implements PathogenTestFacade { private CountryService countryService; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; @Override public List getAllActiveUuids() { @@ -485,7 +488,7 @@ private static void pseudonymizeDto( } private Pseudonymizer createPseudonymizer(Collection tests) { - return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(tests)); + return Pseudonymizer.getDefault(userService, createSpecialAccessChecker(tests), configFacade.getCountryCode()); } private SpecialAccessCheck createSpecialAccessChecker(Collection tests) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java index 1295c31c7e8..458059e7624 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java @@ -56,18 +56,24 @@ import org.apache.commons.collections4.CollectionUtils; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.EntityRelevanceStatus; import de.symeda.sormas.api.RequestContextHolder; import de.symeda.sormas.api.caze.IsCase; import de.symeda.sormas.api.common.DeletableEntityType; import de.symeda.sormas.api.common.DeletionDetails; +import de.symeda.sormas.api.common.DeletionReason; import de.symeda.sormas.api.common.progress.ProcessedEntity; import de.symeda.sormas.api.common.progress.ProcessedEntityStatus; import de.symeda.sormas.api.contact.ContactReferenceDto; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.event.EventParticipantReferenceDto; import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.sample.IsSample; +import de.symeda.sormas.api.sample.PathogenTestCriteria; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.api.sample.SampleAssociationType; @@ -87,6 +93,7 @@ import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.JurisdictionFlagsService; @@ -145,6 +152,8 @@ public class SampleService extends AbstractDeletableAdoService protected FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjbLocal configFacade; public SampleService() { super(Sample.class, DeletableEntityType.SAMPLE); @@ -324,12 +333,15 @@ public SamplePseudonymizer createPseudonymizer(boolean w AnnotationBasedFieldAccessChecker.SpecialAccessCheck specialAccessChecker = createSpecialAccessChecker(samples); Pseudonymizer rootPseudonymizer = withPlaceHolder - ? Pseudonymizer.getDefaultWithPlaceHolder(userService, specialAccessChecker) - : Pseudonymizer.getDefault(userService, specialAccessChecker); + ? Pseudonymizer.getDefaultWithPlaceHolder(userService, specialAccessChecker, configFacade.getCountryCode()) + : Pseudonymizer.getDefault(userService, specialAccessChecker, configFacade.getCountryCode()); Collection cases = samples.stream().map(IsSample::getAssociatedCase).filter(Objects::nonNull).collect(Collectors.toList()); - return new SamplePseudonymizer<>(rootPseudonymizer, caseFacade.createSimplePseudonymizer(cases), Pseudonymizer.getDefault(userService)); + return new SamplePseudonymizer<>( + rootPseudonymizer, + caseFacade.createSimplePseudonymizer(cases), + Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } private AnnotationBasedFieldAccessChecker.SpecialAccessCheck createSpecialAccessChecker( @@ -913,6 +925,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), @@ -1027,7 +1040,7 @@ private Predicate allAssignedEntitiesAreArchived(CriteriaBuilder cb, SampleJoins } @Override - public void deletePermanent(Sample sample) { + public boolean deletePermanent(Sample sample) { // Delete all pathogen tests of this sample for (PathogenTest pathogenTest : sample.getPathogenTests()) { @@ -1052,6 +1065,7 @@ public void deletePermanent(Sample sample) { deleteSampleLinks(sample); super.deletePermanent(sample); + return false; } @Override @@ -1264,7 +1278,7 @@ public List getAssociatedDiseaseVariants(String sampleUuid) { } final CriteriaBuilder cb = em.getCriteriaBuilder(); - final CriteriaQuery cq = cb.createQuery(DiseaseVariant.class); + final CriteriaQuery cq = cb.createTupleQuery(); final Root from = cq.from(getElementClass()); final Join pathogenTestJoin = from.join(Sample.PATHOGENTESTS, JoinType.LEFT); @@ -1273,7 +1287,44 @@ public List getAssociatedDiseaseVariants(String sampleUuid) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(AbstractDomainObject.UUID), sampleUuid)); filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(pathogenTestJoin.get(DeletableAdo.DELETED), false)); cq.where(filter); - cq.select(pathogenTestJoin.get(PathogenTest.TESTED_DISEASE_VARIANT)); - return em.createQuery(cq).getResultList(); + cq.multiselect(pathogenTestJoin.get(PathogenTest.TESTED_DISEASE), pathogenTestJoin.get(PathogenTest.TESTED_DISEASE_VARIANT_VALUE)); + return em.createQuery(cq) + .getResultList() + .stream() + .map(tuple -> new DiseaseVariantConverter().convertToEntityAttribute((Disease) tuple.get(0), (String) tuple.get(1))) + .collect(Collectors.toList()); + } + + public void cleanupOldCovidSamples() { + final Integer maxAgeDays = configFacade.getNegaiveCovidTestsMaxAgeDays(); + if (maxAgeDays == null) { + return; + } + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(PathogenTest.class); + Root from = cq.from(PathogenTest.class); + + cq.where( + cb.equal(from.get(PathogenTest.TESTED_DISEASE), Disease.CORONAVIRUS), + cb.equal(from.get(PathogenTest.TEST_RESULT), PathogenTestResultType.NEGATIVE), + cb.notEqual(from.get(PathogenTest.DELETED), true), + cb.lessThan( + CriteriaBuilderHelper.coalesce( + cb, + Date.class, + from.get(PathogenTest.TEST_DATE_TIME), + from.get(PathogenTest.REPORT_DATE), + from.get(PathogenTest.CREATION_DATE)), + DateHelper.subtractDays(new Date(), maxAgeDays))); + em.createQuery(cq).getResultList().stream().collect(Collectors.groupingBy(PathogenTest::getSample)).forEach((sample, tests) -> { + if (pathogenTestService.count(new PathogenTestCriteria().sample(sample.toReference())) == tests.size()) { + delete(sample, new DeletionDetails(DeletionReason.OTHER_REASON, I18nProperties.getString(Strings.entityAutomaticSoftDeletion))); + } else { + tests.forEach( + p -> pathogenTestService + .delete(p, new DeletionDetails(DeletionReason.OTHER_REASON, I18nProperties.getString(Strings.entityAutomaticSoftDeletion)))); + } + }); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReport.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReport.java index 6e678199391..f09d7bbceaf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReport.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReport.java @@ -22,7 +22,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -31,6 +30,7 @@ import javax.persistence.OneToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.disease.DiseaseVariant; @@ -41,7 +41,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.location.Location; import de.symeda.sormas.backend.user.User; @@ -55,7 +55,7 @@ public class SelfReport extends CoreAdo { public static final String CASE_REFERENCE = "caseReference"; public static final String DISEASE = "disease"; public static final String DISEASE_DETAILS = "diseaseDetails"; - public static final String DISEASE_VARIANT = "diseaseVariant"; + public static final String DISEASE_VARIANT_VALUE = "diseaseVariantValue"; public static final String DISEASE_VARIANT_DETAILS = "diseaseVariantDetails"; public static final String FIRST_NAME = "firstName"; public static final String LAST_NAME = "lastName"; @@ -85,6 +85,7 @@ public class SelfReport extends CoreAdo { private String caseReference; private Disease disease; private String diseaseDetails; + private String diseaseVariantValue; private DiseaseVariant diseaseVariant; private String diseaseVariantDetails; // person data @@ -161,12 +162,26 @@ public void setDiseaseDetails(String diseaseDetails) { this.diseaseDetails = diseaseDetails; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "diseasevariant") + public String getDiseaseVariantValue() { + return diseaseVariantValue; + } + + public void setDiseaseVariantValue(String diseaseVariantValue) { + this.diseaseVariantValue = diseaseVariantValue; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariantValue); + } + + @Transient public DiseaseVariant getDiseaseVariant() { return diseaseVariant; } + public void setDiseaseVariant(DiseaseVariant diseaseVariant) { + this.diseaseVariant = diseaseVariant; + this.diseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); + } + @Column(length = CHARACTER_LIMIT_DEFAULT) public String getDiseaseVariantDetails() { return diseaseVariantDetails; @@ -176,10 +191,6 @@ public void setDiseaseVariantDetails(String diseaseVariantDetails) { this.diseaseVariantDetails = diseaseVariantDetails; } - public void setDiseaseVariant(DiseaseVariant diseaseVariant) { - this.diseaseVariant = diseaseVariant; - } - @Column(nullable = false, length = CHARACTER_LIMIT_DEFAULT) public String getFirstName() { return firstName; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportExportDtoResultTransformer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportExportDtoResultTransformer.java index c1fe9af4a0c..192029a2eaf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportExportDtoResultTransformer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportExportDtoResultTransformer.java @@ -27,7 +27,7 @@ public SelfReportExportDto transformTuple(Object[] tuple, String[] aliases) { //@formatter:off return new SelfReportExportDto( (String) tuple[++index], (SelfReportType) tuple[++index], (Date) tuple[++index], - (String) tuple[++index], (Disease) tuple[++index], (String) tuple[++index], (DiseaseVariant) tuple[++index], + (String) tuple[++index], (Disease) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (Sex) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], (String) tuple[++index], new BirthDateDto((Integer)tuple[++index], (Integer) tuple[++index], (Integer) tuple[++index]), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportFacadeEjb.java index dd86712e11f..95bb2a6605c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportFacadeEjb.java @@ -253,7 +253,7 @@ public List getExportList(SelfReportCriteria selfReportCrit selfReport.get(SelfReport.CASE_REFERENCE), selfReport.get(SelfReport.DISEASE), selfReport.get(SelfReport.DISEASE_DETAILS), - selfReport.get(SelfReport.DISEASE_VARIANT), + selfReport.get(SelfReport.DISEASE_VARIANT_VALUE), selfReport.get(SelfReport.DISEASE_VARIANT_DETAILS), selfReport.get(SelfReport.FIRST_NAME), selfReport.get(SelfReport.LAST_NAME), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportService.java index 19b1fe0192c..825b6674e09 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/selfreport/SelfReportService.java @@ -15,6 +15,11 @@ package de.symeda.sormas.backend.selfreport; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.persistence.Tuple; @@ -26,25 +31,19 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.Selection; -import de.symeda.sormas.api.selfreport.SelfReportListEntryDto; -import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.sample.Sample; -import de.symeda.sormas.backend.util.QueryHelper; import org.apache.commons.lang3.StringUtils; import de.symeda.sormas.api.EntityRelevanceStatus; import de.symeda.sormas.api.common.DeletableEntityType; import de.symeda.sormas.api.selfreport.SelfReportCriteria; +import de.symeda.sormas.api.selfreport.SelfReportListEntryDto; import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.location.Location; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import de.symeda.sormas.backend.util.QueryHelper; @Stateless @LocalBean @@ -115,7 +114,8 @@ public Predicate buildCriteriaFilter(SelfReportCriteria criteria, SelfReportQuer } if (criteria.getDiseaseVariant() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(SelfReport.DISEASE_VARIANT), criteria.getDiseaseVariant())); + filter = + CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(SelfReport.DISEASE_VARIANT_VALUE), criteria.getDiseaseVariant().getValue())); } if (criteria.getReportDateFrom() != null && criteria.getReportDateTo() != null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/share/ExternalShareInfoFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/share/ExternalShareInfoFacadeEjb.java index 099709e5e4f..056b9582832 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/share/ExternalShareInfoFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/share/ExternalShareInfoFacadeEjb.java @@ -36,6 +36,7 @@ import de.symeda.sormas.api.share.ExternalShareInfoFacade; import de.symeda.sormas.api.share.ExternalShareStatus; import de.symeda.sormas.backend.caze.Case; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.event.Event; import de.symeda.sormas.backend.user.UserFacadeEjb; @@ -57,6 +58,9 @@ public class ExternalShareInfoFacadeEjb implements ExternalShareInfoFacade { @EJB private UserService userService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; + @Override public List getIndexList(ExternalShareInfoCriteria criteria, Integer first, Integer max) { final CriteriaBuilder cb = em.getCriteriaBuilder(); @@ -78,7 +82,7 @@ public List getIndexList(ExternalShareInfoCriteria criteri List shareInfoList = QueryHelper.getResultList(em, cq, first, max); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); return shareInfoList.stream().map(i -> convertToDto(i, pseudonymizer)).collect(Collectors.toList()); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java index 8aa6c858e34..6067f8e63f3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java @@ -358,10 +358,10 @@ private TaskPseudonymizer createPseudonymizer(boolean with return new TaskPseudonymizer<>( withPlaceHolder - ? Pseudonymizer.getDefaultWithPlaceHolder(userService, specialAccessCheck) - : Pseudonymizer.getDefault(userService, specialAccessCheck), + ? Pseudonymizer.getDefaultWithPlaceHolder(userService, specialAccessCheck, configFacade.getCountryCode()) + : Pseudonymizer.getDefault(userService, specialAccessCheck, configFacade.getCountryCode()), caseFacade.createSimplePseudonymizer(associatedCases), - Pseudonymizer.getDefault(userService)); + Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjb.java index f10a766ad9f..188e78bec4f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjb.java @@ -30,6 +30,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.user.User; @@ -56,6 +57,8 @@ public class PrescriptionFacadeEjb implements PrescriptionFacade { private TherapyService therapyService; @EJB private CaseService caseService; + @EJB + private ConfigFacadeEjbLocal configFacade; @Override public List getIndexList(PrescriptionCriteria criteria) { @@ -87,7 +90,7 @@ public List getIndexList(PrescriptionCriteria criteria) { List indexList = em.createQuery(cq).getResultList(); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(PrescriptionIndexDto.class, indexList, PrescriptionIndexDto::getInJurisdiction, null); return indexList; @@ -95,7 +98,7 @@ public List getIndexList(PrescriptionCriteria criteria) { @Override public PrescriptionDto getPrescriptionByUuid(String uuid) { - return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService)); + return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override @@ -114,7 +117,7 @@ public PrescriptionDto savePrescription(@Valid PrescriptionDto prescription) { service.ensurePersisted(entity); - return convertToDto(entity, Pseudonymizer.getDefault(userService)); + return convertToDto(entity, Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override @@ -143,7 +146,7 @@ public List getAllActivePrescriptionsAfter(Date date, Integer b private List toPseudonymizedDtos(List entities) { List inJurisdictionIds = service.getInJurisdictionIds(entities); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); return entities.stream().map(p -> convertToDto(p, pseudonymizer, inJurisdictionIds.contains(p.getId()))).collect(Collectors.toList()); } @@ -202,7 +205,7 @@ public List getExportList(CaseCriteria criteria, Collecti List exportList = QueryHelper.getResultList(em, cq, first, max); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(PrescriptionExportDto.class, exportList, PrescriptionExportDto::getInJurisdiction, null); return exportList; @@ -233,7 +236,7 @@ private void pseudonymizeDto(Prescription source, PrescriptionDto dto, Pseudonym private void restorePseudonymizedDto(PrescriptionDto prescription, Prescription existingPrescription, PrescriptionDto existingPrescriptionDto) { if (existingPrescription != null) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); pseudonymizer.restorePseudonymizedValues( PrescriptionDto.class, prescription, diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjb.java index e71060be315..85cf01f177a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjb.java @@ -29,6 +29,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.user.User; @@ -57,6 +58,8 @@ public class TreatmentFacadeEjb implements TreatmentFacade { private PrescriptionService prescriptionService; @EJB private CaseService caseService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; @Override public List getIndexList(TreatmentCriteria criteria) { @@ -86,7 +89,7 @@ public List getIndexList(TreatmentCriteria criteria) { List indexList = em.createQuery(cq).getResultList(); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(TreatmentIndexDto.class, indexList, TreatmentIndexDto::getInJurisdiction, null); return indexList; @@ -122,7 +125,7 @@ public List getTreatmentForPrescription(List prescrip List treatmentIndexDtos = em.createQuery(cq).getResultList(); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(TreatmentIndexDto.class, treatmentIndexDtos, TreatmentIndexDto::getInJurisdiction, null); return treatmentIndexDtos; @@ -130,7 +133,7 @@ public List getTreatmentForPrescription(List prescrip @Override public TreatmentDto getTreatmentByUuid(String uuid) { - return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService)); + return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService, configFacade.getCountryCode())); } @Override @@ -195,7 +198,7 @@ public List getByUuids(List uuids) { private List toPseudonymizedDtos(List entities) { List inJurisdictionIds = service.getInJurisdictionIds(entities); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); return entities.stream().map(p -> convertToDto(p, pseudonymizer, inJurisdictionIds.contains(p.getId()))).collect(Collectors.toList()); } @@ -245,7 +248,7 @@ public List getExportList(CaseCriteria criteria, Collection< List exportList = QueryHelper.getResultList(em, cq, first, max); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithPlaceHolder(userService, configFacade.getCountryCode()); pseudonymizer.pseudonymizeDtoCollection(TreatmentExportDto.class, exportList, TreatmentExportDto::getInJurisdiction, null); return exportList; @@ -276,7 +279,7 @@ private void pseudonymizeDto(Treatment source, TreatmentDto dto, Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, configFacade.getCountryCode()); pseudonymizer.restorePseudonymizedValues(TreatmentDto.class, source, existingDto, service.inJurisdictionOrOwned(existingTreatment)); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java index 193dcdba31e..7d356fd1bea 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java @@ -4,7 +4,6 @@ import java.util.List; import javax.persistence.Column; -import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -13,18 +12,19 @@ import javax.persistence.ManyToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import org.hibernate.annotations.Type; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.contact.QuarantineType; import de.symeda.sormas.api.disease.DiseaseVariant; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; import de.symeda.sormas.api.travelentry.DeaContentEntry; import de.symeda.sormas.api.travelentry.IsTravelEntry; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.CoreAdo; -import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; import de.symeda.sormas.backend.infrastructure.pointofentry.PointOfEntry; @@ -46,7 +46,7 @@ public class TravelEntry extends CoreAdo implements IsTravelEntry { public static final String REPORTING_USER = "reportingUser"; public static final String DELETED = "deleted"; public static final String DISEASE = "disease"; - public static final String DISEASE_VARIANT = "diseaseVariant"; + public static final String DISEASE_VARIANT_VALUE = "diseaseVariantValue"; public static final String RESPONSIBLE_REGION = "responsibleRegion"; public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict"; public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity"; @@ -69,6 +69,7 @@ public class TravelEntry extends CoreAdo implements IsTravelEntry { private boolean deleted; private Disease disease; private String diseaseDetails; + private String diseaseVariantValue; private DiseaseVariant diseaseVariant; private String diseaseVariantDetails; private Region responsibleRegion; @@ -174,14 +175,24 @@ public void setDiseaseDetails(String diseaseDetails) { this.diseaseDetails = diseaseDetails; } - @Column - @Convert(converter = DiseaseVariantConverter.class) + @Column(name = "diseasevariant") + public String getDiseaseVariantValue() { + return diseaseVariantValue; + } + + public void setDiseaseVariantValue(String diseaseVariantValue) { + this.diseaseVariantValue = diseaseVariantValue; + this.diseaseVariant = new DiseaseVariantConverter().convertToEntityAttribute(disease, diseaseVariantValue); + } + + @Transient public DiseaseVariant getDiseaseVariant() { return diseaseVariant; } public void setDiseaseVariant(DiseaseVariant diseaseVariant) { this.diseaseVariant = diseaseVariant; + this.diseaseVariantValue = new DiseaseVariantConverter().convertToDatabaseColumn(diseaseVariant); } @Column(columnDefinition = "text") diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index e311abde4f4..accd4e2dc1f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -50,6 +50,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; @@ -96,6 +97,8 @@ public class TravelEntryFacadeEjb private TravelEntryService travelEntryService; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; public TravelEntryFacadeEjb() { } @@ -223,7 +226,7 @@ public long count(TravelEntryCriteria criteria, boolean ignoreUserFilter) { @Override protected Pseudonymizer createPseudonymizer(List travelEntries) { - return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(travelEntries)); + return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(travelEntries), configFacade.getCountryCode()); } private SpecialAccessCheck getSpecialAccessChecker(Collection entries) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java index 7b006c17a25..775b1d97b91 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java @@ -277,7 +277,7 @@ public EditPermissionType getEditPermissionType(TravelEntry travelEntry) { } @Override - public void deletePermanent(TravelEntry travelEntry) { + public boolean deletePermanent(TravelEntry travelEntry) { // Delete all tasks associated with this travel entry List tasks = taskService.findBy( new TaskCriteria().travelEntry( @@ -295,6 +295,7 @@ public void deletePermanent(TravelEntry travelEntry) { .forEach(document -> documentService.markAsDeleted(document)); super.deletePermanent(travelEntry); + return false; } public TravelEntry getLastTravelEntry() { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleService.java index 2ba7576570b..a435131a022 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleService.java @@ -175,7 +175,7 @@ public boolean isCaptionUnique(String excludedUuid, String caption) { } @Override - public void deletePermanent(UserRole userRole) { + public boolean deletePermanent(UserRole userRole) { List usersWithRole = userService.getAllWithRole(userRole); for (User u : usersWithRole) { @@ -191,5 +191,6 @@ public void deletePermanent(UserRole userRole) { } super.deletePermanent(userRole); + return false; } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/BirthdateRangeFilterPredicate.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/BirthdateRangeFilterPredicate.java new file mode 100644 index 00000000000..b2dcfcbd287 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/BirthdateRangeFilterPredicate.java @@ -0,0 +1,87 @@ +package de.symeda.sormas.backend.util; + +import java.util.Calendar; +import java.util.Date; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.From; +import javax.persistence.criteria.Predicate; + +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.person.Person; + +public class BirthdateRangeFilterPredicate { + + public static Predicate createBirthdateRangeFilter( + Date birthdateFrom, + Date birthdateTo, + boolean includePartialMatch, + CriteriaBuilder cb, + From personFrom, + Predicate filter) { + if (birthdateFrom != null) { + Calendar calendarBirthdateFrom = Calendar.getInstance(); + calendarBirthdateFrom.setTime(birthdateFrom); + int birthdateFromCriteriaYear = calendarBirthdateFrom.get(Calendar.YEAR); + int birthdateFromCriteriaMonth = calendarBirthdateFrom.get(Calendar.MONTH) + 1; + int birthdateFromCriteriaDay = calendarBirthdateFrom.get(Calendar.DAY_OF_MONTH); + + Predicate yearPredicate = cb.greaterThan(personFrom.get(Person.BIRTHDATE_YYYY), birthdateFromCriteriaYear); + + Predicate monthPredicate = cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateFromCriteriaYear); + monthPredicate = cb.and(monthPredicate, cb.greaterThan(personFrom.get(Person.BIRTHDATE_MM), birthdateFromCriteriaMonth)); + + Predicate dayPredicate = cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateFromCriteriaYear); + dayPredicate = cb.and(dayPredicate, cb.equal(personFrom.get(Person.BIRTHDATE_MM), birthdateFromCriteriaMonth)); + dayPredicate = cb.and(dayPredicate, cb.greaterThanOrEqualTo(personFrom.get(Person.BIRTHDATE_DD), birthdateFromCriteriaDay)); + + if (includePartialMatch) { + Predicate sameYearPartialMatchPredicate = cb + .and(cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateFromCriteriaYear), cb.isNull(personFrom.get(Person.BIRTHDATE_MM))); + Predicate sameYearMonthPartialMatchPredicate = cb.and( + cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateFromCriteriaYear), + cb.equal(personFrom.get(Person.BIRTHDATE_MM), birthdateFromCriteriaMonth), + cb.isNull(personFrom.get(Person.BIRTHDATE_DD))); + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.or(yearPredicate, monthPredicate, dayPredicate, sameYearPartialMatchPredicate, sameYearMonthPartialMatchPredicate)); + } else { + filter = CriteriaBuilderHelper.and(cb, filter, cb.or(yearPredicate, monthPredicate, dayPredicate)); + } + } + + if (birthdateTo != null) { + Calendar calendarBirthdateTo = Calendar.getInstance(); + calendarBirthdateTo.setTime(birthdateTo); + int birthdateToCriteriaYear = calendarBirthdateTo.get(Calendar.YEAR); + int birthdateToCriteriaMonth = calendarBirthdateTo.get(Calendar.MONTH) + 1; + int birthdateToCriteriaDay = calendarBirthdateTo.get(Calendar.DAY_OF_MONTH); + + Predicate yearPredicate = cb.lessThan(personFrom.get(Person.BIRTHDATE_YYYY), birthdateToCriteriaYear); + + Predicate monthPredicate = cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateToCriteriaYear); + monthPredicate = cb.and(monthPredicate, cb.lessThan(personFrom.get(Person.BIRTHDATE_MM), birthdateToCriteriaMonth)); + + Predicate dayPredicate = cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateToCriteriaYear); + dayPredicate = cb.and(dayPredicate, cb.equal(personFrom.get(Person.BIRTHDATE_MM), birthdateToCriteriaMonth)); + dayPredicate = cb.and(dayPredicate, cb.lessThanOrEqualTo(personFrom.get(Person.BIRTHDATE_DD), birthdateToCriteriaDay)); + + if (includePartialMatch) { + Predicate sameYearPartialMatchPredicate = + cb.and(cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateToCriteriaYear), cb.isNull(personFrom.get(Person.BIRTHDATE_MM))); + Predicate sameYearMonthPartialMatchPredicate = cb.and( + cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), birthdateToCriteriaYear), + cb.equal(personFrom.get(Person.BIRTHDATE_MM), birthdateToCriteriaMonth), + cb.isNull(personFrom.get(Person.BIRTHDATE_DD))); + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.or(yearPredicate, monthPredicate, dayPredicate, sameYearPartialMatchPredicate, sameYearMonthPartialMatchPredicate)); + } else { + filter = CriteriaBuilderHelper.and(cb, filter, cb.or(yearPredicate, monthPredicate, dayPredicate)); + } + } + return filter; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/Pseudonymizer.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/Pseudonymizer.java index 48cc1772c09..211cf1729da 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/Pseudonymizer.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/Pseudonymizer.java @@ -33,48 +33,62 @@ public final class Pseudonymizer extends DtoPseudonymizer { - public static Pseudonymizer getDefault(UserService userService) { - return getDefault(userService::hasRight, noopSpecialAccessCheck()); + public static Pseudonymizer getDefault(UserService userService, String serverCountry) { + return getDefault(userService::hasRight, noopSpecialAccessCheck(), serverCountry); } - public static Pseudonymizer getDefault(UserService userService, SpecialAccessCheck specialAccessCheck) { - return getDefault(userService::hasRight, specialAccessCheck); + public static Pseudonymizer getDefault(UserService userService, SpecialAccessCheck specialAccessCheck, String serverCountry) { + return getDefault(userService::hasRight, specialAccessCheck, serverCountry); } - public static Pseudonymizer getDefault(UserService userService, SpecialAccessCheck specialAccessCheck, String stringValuePlaceholder) { - return getDefault(userService::hasRight, specialAccessCheck, stringValuePlaceholder); + public static Pseudonymizer getDefault( + UserService userService, + SpecialAccessCheck specialAccessCheck, + String stringValuePlaceholder, + String serverCountry) { + return getDefault(userService::hasRight, specialAccessCheck, stringValuePlaceholder, serverCountry); } - public static Pseudonymizer getDefault(UserService userService, String stringValuePlaceholder) { - return getDefault(userService::hasRight, noopSpecialAccessCheck(), stringValuePlaceholder); + public static Pseudonymizer getDefault(UserService userService, String stringValuePlaceholder, String serverCountry) { + return getDefault(userService::hasRight, noopSpecialAccessCheck(), stringValuePlaceholder, serverCountry); } - private static Pseudonymizer getDefault(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { + private static Pseudonymizer getDefault(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck, String serverCountry) { return new Pseudonymizer<>( - createDefaultFieldAccessCheckers(true, rightCheck, specialAccessCheck), - createDefaultFieldAccessCheckers(false, rightCheck, specialAccessCheck), + createDefaultFieldAccessCheckers(true, rightCheck, specialAccessCheck, serverCountry), + createDefaultFieldAccessCheckers(false, rightCheck, specialAccessCheck, serverCountry), "", true); } - private static Pseudonymizer getDefault(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck, String stringValuePlaceholder) { + private static Pseudonymizer getDefault( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String stringValuePlaceholder, + String serverCountry) { return new Pseudonymizer<>( - createDefaultFieldAccessCheckers(true, rightCheck, specialAccessCheck), - createDefaultFieldAccessCheckers(false, rightCheck, specialAccessCheck), + createDefaultFieldAccessCheckers(true, rightCheck, specialAccessCheck, serverCountry), + createDefaultFieldAccessCheckers(false, rightCheck, specialAccessCheck, serverCountry), stringValuePlaceholder, true); } - public static Pseudonymizer getDefaultWithPlaceHolder(UserService userService) { - return getDefaultWithPlaceHolder(userService, noopSpecialAccessCheck()); + public static Pseudonymizer getDefaultWithPlaceHolder(UserService userService, String serverCountry) { + return getDefaultWithPlaceHolder(userService, noopSpecialAccessCheck(), serverCountry); } - public static Pseudonymizer getDefaultWithPlaceHolder(UserService userService, SpecialAccessCheck specialAccessCheck) { - return getDefaultWithPlaceHolder(userService::hasRight, specialAccessCheck); + public static Pseudonymizer getDefaultWithPlaceHolder( + UserService userService, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return getDefaultWithPlaceHolder(userService::hasRight, specialAccessCheck, serverCountry); } - private static Pseudonymizer getDefaultWithPlaceHolder(RightCheck rightCheck, SpecialAccessCheck specialAccessCheck) { - return getDefault(rightCheck, specialAccessCheck, I18nProperties.getCaption(Captions.inaccessibleValue)); + private static Pseudonymizer getDefaultWithPlaceHolder( + RightCheck rightCheck, + SpecialAccessCheck specialAccessCheck, + String serverCountry) { + return getDefault(rightCheck, specialAccessCheck, I18nProperties.getCaption(Captions.inaccessibleValue), serverCountry); } public static Pseudonymizer getDefaultNoCheckers(boolean pseudonymizeMandatoryFields) { @@ -161,13 +175,14 @@ private static boolean isUserInJurisdiction(User user, User currentUser) { private static FieldAccessCheckers createDefaultFieldAccessCheckers( boolean inJurisdiction, final RightCheck rightCheck, - SpecialAccessCheck specialAccessCheck) { + SpecialAccessCheck specialAccessCheck, + String serverCountry) { PersonalDataFieldAccessChecker personalFieldAccessChecker = inJurisdiction - ? PersonalDataFieldAccessChecker.inJurisdiction(rightCheck::hasRight, specialAccessCheck) - : PersonalDataFieldAccessChecker.outsideJurisdiction(rightCheck::hasRight, specialAccessCheck); + ? PersonalDataFieldAccessChecker.inJurisdiction(rightCheck::hasRight, specialAccessCheck, serverCountry) + : PersonalDataFieldAccessChecker.outsideJurisdiction(rightCheck::hasRight, specialAccessCheck, serverCountry); SensitiveDataFieldAccessChecker sensitiveFieldAccessChecker = inJurisdiction - ? SensitiveDataFieldAccessChecker.inJurisdiction(rightCheck::hasRight, specialAccessCheck) - : SensitiveDataFieldAccessChecker.outsideJurisdiction(rightCheck::hasRight, specialAccessCheck); + ? SensitiveDataFieldAccessChecker.inJurisdiction(rightCheck::hasRight, specialAccessCheck, serverCountry) + : SensitiveDataFieldAccessChecker.outsideJurisdiction(rightCheck::hasRight, specialAccessCheck, serverCountry); return FieldAccessCheckers.withCheckers(Arrays.asList(personalFieldAccessChecker, sensitiveFieldAccessChecker)); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java index d1dee05a51f..4bbc8281817 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java @@ -71,6 +71,7 @@ import de.symeda.sormas.backend.clinicalcourse.HealthConditions; import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import de.symeda.sormas.backend.common.AbstractBaseEjb; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.event.Event; @@ -113,6 +114,8 @@ public class VaccinationFacadeEjb private HealthConditionsMapper healthConditionsMapper; @EJB private SpecialCaseAccessService specialCaseAccessService; + @EJB + private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; public VaccinationFacadeEjb() { } @@ -397,7 +400,7 @@ protected Pseudonymizer createPseudonymizer(List va SpecialAccessCheck specialAccessCheck = t -> specialAccessUuids.contains(t.getUuid()); - return Pseudonymizer.getDefault(userService, specialAccessCheck); + return Pseudonymizer.getDefault(userService, specialAccessCheck, configFacade.getCountryCode()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java index ea579696a92..8c1eba2a289 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java @@ -87,6 +87,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractBaseEjb; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; @@ -137,6 +138,8 @@ public class VisitFacadeEjb extends AbstractBaseEjb getVisitsExportList( if (!resultList.isEmpty()) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService, getSpecialAccessChecker(resultList)); + Pseudonymizer pseudonymizer = + Pseudonymizer.getDefault(userService, getSpecialAccessChecker(resultList), configFacade.getCountryCode()); Set userIds = resultList.stream().map(VisitExportDto::getVisitUserId).filter(Objects::nonNull).collect(Collectors.toSet()); Map visitUsers = userIds.isEmpty() ? null @@ -587,7 +591,7 @@ public Visit fillOrBuildEntity(@NotNull VisitDto source, Visit target, boolean c @Override protected Pseudonymizer createPseudonymizer(List visits) { - return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(visits)); + return Pseudonymizer.getDefault(userService, getSpecialAccessChecker(visits), configFacade.getCountryCode()); } private SpecialAccessCheck getSpecialAccessChecker(Collection visits) { diff --git a/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml b/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml index 584b2fa6fd6..c907e3669f4 100644 --- a/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml +++ b/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml @@ -122,6 +122,36 @@ IMMUNIZATION_ARCHIVE + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + + PERSON_VIEW PERSON_VIEW @@ -607,6 +637,11 @@ DASHBOARD_SAMPLES_VIEW + + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + CASE_CLINICIAN_VIEW CASE_CLINICIAN_VIEW diff --git a/sormas-backend/src/main/resources/META-INF/persistence.xml b/sormas-backend/src/main/resources/META-INF/persistence.xml index b792ff39147..9d440b08f53 100644 --- a/sormas-backend/src/main/resources/META-INF/persistence.xml +++ b/sormas-backend/src/main/resources/META-INF/persistence.xml @@ -86,11 +86,15 @@ de.symeda.sormas.backend.externalmessage.labmessage.TestReport de.symeda.sormas.backend.deletionconfiguration.DeletionConfiguration de.symeda.sormas.backend.externalmessage.labmessage.SampleReport + de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi + de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AdverseEvents + de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation de.symeda.sormas.backend.specialcaseaccess.SpecialCaseAccess de.symeda.sormas.backend.selfreport.SelfReport + de.symeda.sormas.backend.docgeneration.DocumentTemplate - true + true ENABLE_SELECTIVE CALLBACK diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index f08ecaec095..57f222938b2 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -13257,4 +13257,481 @@ ALTER TABLE externalmessage_history ADD COLUMN personadditionaldetails text; INSERT INTO schema_version (version_number, comment) VALUES (551, '#13147 Phone Number Validation for E-Santé Reports – Remove and Store Non-Numeric Text'); + +-- 2024-10-16 Adverse Events Following Immunization (AEFI) - Entities #12634 +-- adverse events +create table adverseevents +( + id bigint not null, + uuid varchar(36) not null, + changedate timestamp(3) not null, + creationdate timestamp(3) not null, + severelocalreaction varchar(255), + severelocalreactionmorethanthreedays boolean, + severelocalreactionbeyondnearestjoint boolean, + seizures varchar(255), + seizuretype varchar(255), + abscess varchar(255), + sepsis varchar(255), + encephalopathy varchar(255), + toxicshocksyndrome varchar(255), + thrombocytopenia varchar(255), + anaphylaxis varchar(255), + feverishfeeling varchar(255), + otheradverseeventdetails varchar(255), + sys_period tstzrange not null, + change_user_id bigint +); + +alter table adverseevents owner to sormas_user; + +alter table adverseevents add primary key (id); +alter table adverseevents add unique (uuid); +alter table adverseevents add constraint fk_adverseevents_change_user_id foreign key (change_user_id) references users; + +-- adverse events history +CREATE TABLE adverseevents_history (LIKE adverseevents); +DROP TRIGGER IF EXISTS versioning_trigger ON adverseevents; +CREATE TRIGGER versioning_trigger + BEFORE INSERT OR UPDATE ON adverseevents + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'adverseevents_history', true); +DROP TRIGGER IF EXISTS delete_history_trigger ON adverseevents; +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON adverseevents + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('adverseevents_history', 'id'); +ALTER TABLE adverseevents_history OWNER TO sormas_user; + +-- adverse events following immunization (AEFI) +create table adverseeventsfollowingimmunization +( + id bigint not null, + uuid varchar(36) not null, + changedate timestamp(3) not null, + creationdate timestamp(3) not null, + immunization_id bigint not null, + address_id bigint, + primarysuspectvaccine_id bigint not null, + adverseevents_id bigint not null, + person_id bigint, + reportdate timestamp not null, + reportinguser_id bigint not null, + externalid varchar(512), + responsibleregion_id bigint, + responsibledistrict_id bigint, + responsiblecommunity_id bigint, + country_id bigint, + reportingidnumber varchar(512) not null, + firstname varchar(255), + lastname varchar(255), + phonenumber varchar(255), + pregnant varchar(255), + trimester varchar(255), + lactating varchar(255), + onsetageyears integer, + onsetagemonths integer, + onsetagedays integer, + agegroup varchar(255), + healthfacility_id bigint, + healthfacilitydetails varchar(512), + reportingofficername varchar(255), + reportingofficerfacility_id bigint, + reportingofficerfacilitydetails varchar(512), + reportingofficerdesignation varchar(255), + reportingofficerdepartment varchar(255), + reportingofficeraddress_id bigint, + reportingofficerphonenumber varchar(255), + reportingofficeremail varchar(255), + healthsystemnotifieddate timestamp, + todaysdate timestamp, + startdatetime timestamp, + aefidescription text, + serious varchar(255) not null, + seriousreason varchar(255), + seriousreasondetails text, + outcome varchar(255) not null, + deathdate timestamp, + autopsydone varchar(255), + pastmedicalhistory text, + investigationneeded varchar(255), + investigationplanneddate timestamp, + receivedatnationalleveldate timestamp, + worldwideid varchar(255), + nationallevelcomment text, + archived boolean default false, + endofprocessingdate timestamp, + archiveundonereason varchar(255), + deleted boolean default false, + deletionreason varchar(255), + otherdeletionreason text, + sys_period tstzrange not null, + change_user_id bigint +); + +alter table adverseeventsfollowingimmunization owner to sormas_user; + +alter table adverseeventsfollowingimmunization add primary key (id); +alter table adverseeventsfollowingimmunization add unique (uuid); +alter table adverseeventsfollowingimmunization add constraint fk_aefi_address_id foreign key (address_id) references location; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_adverseevents_id foreign key (adverseevents_id) references adverseevents; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_change_user_id foreign key (change_user_id) references users; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_country_id foreign key (country_id) references country; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_healthfacility_id foreign key (healthfacility_id) references facility; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_immunization_id foreign key (immunization_id) references immunization; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_person_id foreign key (person_id) references person; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_primarysuspectvaccine_id foreign key (primarysuspectvaccine_id) references vaccination; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_reporting_user_id foreign key (reportinguser_id) references users; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_reportingofficeraddress_id foreign key (reportingofficeraddress_id) references location; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_reportingofficerfacility_id foreign key (reportingofficerfacility_id) references facility; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_responsiblecommunity_id foreign key (responsiblecommunity_id) references community; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_responsibledistrict_id foreign key (responsibledistrict_id) references district; +alter table adverseeventsfollowingimmunization add constraint fk_aefi_responsibleregion_id foreign key (responsibleregion_id) references region; + +-- AEFI history +CREATE TABLE adverseeventsfollowingimmunization_history (LIKE adverseeventsfollowingimmunization); +DROP TRIGGER IF EXISTS versioning_trigger ON adverseeventsfollowingimmunization; +CREATE TRIGGER versioning_trigger + BEFORE INSERT OR UPDATE ON adverseeventsfollowingimmunization + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'adverseeventsfollowingimmunization_history', true); +DROP TRIGGER IF EXISTS delete_history_trigger ON adverseeventsfollowingimmunization; +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON adverseeventsfollowingimmunization + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('adverseeventsfollowingimmunization_history', 'id'); +ALTER TABLE adverseeventsfollowingimmunization_history OWNER TO sormas_user; + +-- AEFI vaccination +create table adverseeventsfollowingimmunization_vaccinations +( + adverseeventsfollowingimmunization_id bigint not null, + vaccination_id bigint not null, + sys_period tstzrange not null +); + +alter table adverseeventsfollowingimmunization_vaccinations owner to sormas_user; + +alter table adverseeventsfollowingimmunization_vaccinations add constraint aefi_vaccinations_pkey primary key (adverseeventsfollowingimmunization_id, vaccination_id); +alter table adverseeventsfollowingimmunization_vaccinations add constraint fk_aefi_vaccinations_aefi_id foreign key (adverseeventsfollowingimmunization_id) references adverseeventsfollowingimmunization; +alter table adverseeventsfollowingimmunization_vaccinations add constraint fk_aefi_vaccinations_vaccination_id foreign key (vaccination_id) references vaccination; + +-- AEFI vaccination history +CREATE TABLE adverseeventsfollowingimmunization_vaccinations_history (LIKE adverseeventsfollowingimmunization_vaccinations); +DROP TRIGGER IF EXISTS versioning_trigger ON adverseeventsfollowingimmunization_vaccinations; +CREATE TRIGGER versioning_trigger + BEFORE INSERT OR UPDATE ON adverseeventsfollowingimmunization_vaccinations + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'adverseeventsfollowingimmunization_vaccinations_history', true); +DROP TRIGGER IF EXISTS delete_history_trigger ON adverseeventsfollowingimmunization_vaccinations; +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON adverseeventsfollowingimmunization_vaccinations + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('adverseeventsfollowingimmunization_vaccinations_history', 'id'); +ALTER TABLE adverseeventsfollowingimmunization_vaccinations_history OWNER TO sormas_user; + +-- AEFI investigation +create table adverseeventsfollowingimmunizationinvestigation +( + id bigint not null, + uuid varchar(36) not null, + changedate timestamp(3) not null, + creationdate timestamp(3) not null, + adverseeventsfollowingimmunization_id bigint not null, + address_id bigint, + primarysuspectvaccine_id bigint, + reportdate timestamp not null, + reportinguser_id bigint not null, + externalid varchar(512), + responsibleregion_id bigint, + responsibledistrict_id bigint, + responsiblecommunity_id bigint, + country_id bigint, + investigationcaseid varchar(255), + placeofvaccination varchar(255) not null, + placeofvaccinationdetails varchar(512), + vaccinationactivity varchar(255) not null, + vaccinationactivitydetails varchar(512), + vaccinationfacility_id bigint, + vaccinationfacilitydetails varchar(512), + reportingofficername varchar(255), + reportingofficerfacility_id bigint, + reportingofficerfacilitydetails varchar(512), + reportingofficerdesignation varchar(255), + reportingofficerdepartment varchar(255), + reportingofficeraddress_id bigint, + reportingofficerlandlinephonenumber varchar(255), + reportingofficermobilephonenumber varchar(255), + reportingofficeremail varchar(255), + investigationdate timestamp not null, + formcompletiondate timestamp not null, + investigationstage varchar(255), + onsetageyears integer, + onsetagemonths integer, + onsetagedays integer, + agegroup varchar(255), + typeofsite varchar(255) not null, + typeofsitedetails varchar(255), + keysymptomdatetime timestamp, + hospitalizationdate timestamp, + reportedtohealthauthoritydate timestamp, + statusondateofinvestigation varchar(255), + deathdatetime timestamp, + autopsydone varchar(255), + autopsydate timestamp, + autopsyplanneddatetime timestamp, + autopsyreportname varchar(255), + pasthistoryofsimilarevent varchar(255), + pasthistoryofsimilareventdetails varchar(512), + adverseeventafterpreviousvaccinations varchar(255), + adverseeventafterpreviousvaccinationsdetails varchar(512), + historyofallergytovaccinedrugorfood varchar(255), + historyofallergytovaccinedrugorfooddetails varchar(512), + preexistingillnessthirtydaysorcongenitaldisorder varchar(255), + preexistingillnessthirtydaysorcongenitaldisorderdetails varchar(512), + historyofhospitalizationinlastthirtydayswithcause varchar(255), + historyofhospitalizationinlastthirtydayswithcausedetails varchar(512), + currentlyonconcomitantmedication varchar(255), + currentlyonconcomitantmedicationdetails varchar(255), + familyhistoryofdiseaseorallergy varchar(255), + familyhistoryofdiseaseorallergydetails varchar(512), + pregnant varchar(255), + numberofweekspregnant integer, + breastfeeding varchar(255), + birthterm varchar(255), + birthweight real, + deliveryprocedure varchar(255), + deliveryproceduredetails varchar(512), + seriousaefiinfosourcestring varchar(512), + seriousaefiinfosourcedetails varchar(512), + seriousaefiverbalautopsyinfosourcedetails varchar(512), + firstcaregiversname varchar(255), + othercaregiversnames varchar(512), + othersourceswhoprovidedinfo varchar(512), + signsandsymptomsfromtimeofvaccination text, + clinicaldetailsofficername varchar(255), + clinicaldetailsofficerphonenumber varchar(255), + clinicaldetailsofficeremail varchar(255), + clinicaldetailsofficerdesignation varchar(255), + clinicaldetailsdatetime timestamp, + patientreceivedmedicalcare varchar(255), + patientreceivedmedicalcaredetails text, + provisionalorfinaldiagnosis text, + patientimmunizedperiod varchar(255), + patientimmunizedperioddetails varchar(512), + vaccinegivenperiod varchar(255), + vaccinegivenperioddetails varchar(512), + errorprescribingvaccine varchar(255), + errorprescribingvaccinedetails varchar(512), + vaccinecouldhavebeenunsterile varchar(255), + vaccinecouldhavebeenunsteriledetails varchar(512), + vaccinephysicalconditionabnormal varchar(255), + vaccinephysicalconditionabnormaldetails varchar(255), + errorinvaccinereconstitution varchar(255), + errorinvaccinereconstitutiondetails varchar(512), + errorinvaccinehandling varchar(255), + errorinvaccinehandlingdetails varchar(512), + vaccineadministeredincorrectly varchar(255), + vaccineadministeredincorrectlydetails varchar(255), + numberimmunizedfromconcernedvaccinevial integer, + numberimmunizedwithconcernedvaccineinsamesession integer, + numberimmunizedconcernedvaccinesamebatchnumberotherlocations integer, + numberimmunizedconcernedvaccinesamebatchnumberlocationdetails varchar(512), + vaccinehasqualitydefect varchar(255), + vaccinehasqualitydefectdetails varchar(512), + eventisastressresponserelatedtoimmunization varchar(255), + eventisastressresponserelatedtoimmunizationdetails varchar(255), + caseispartofacluster varchar(255), + caseispartofaclusterdetails varchar(255), + numberofcasesdetectedincluster integer, + allcasesinclusterreceivedvaccinefromsamevial varchar(255), + allcasesinclusterreceivedvaccinefromsamevialdetails varchar(512), + numberofvialsusedincluster integer, + numberofvialsusedinclusterdetails varchar(255), + adsyringesusedforimmunization varchar(255), + typeofsyringesused varchar(255), + typeofsyringesuseddetails varchar(512), + syringesusedadditionaldetails text, + samereconstitutionsyringeusedformultiplevialsofsamevaccine varchar(255), + samereconstitutionsyringeusedforreconstitutingdifferentvaccines varchar(255), + samereconstitutionsyringeforeachvaccinevial varchar(255), + samereconstitutionsyringeforeachvaccination varchar(255), + vaccinesanddiluentsusedrecommendedbymanufacturer varchar(255), + reconstitutionadditionaldetails text, + correctdoseorroute varchar(255), + timeofreconstitutionmentionedonthevial varchar(255), + nontouchtechniquefollowed varchar(255), + contraindicationscreenedpriortovaccination varchar(255), + numberofaefireportedfromvaccinedistributioncenterlastthirtydays integer, + trainingreceivedbyvaccinator varchar(255), + lasttrainingreceivedbyvaccinatordate timestamp, + injectiontechniqueadditionaldetails text, + vaccinestoragerefrigeratortemperaturemonitored varchar(255), + anystoragetemperaturedeviationoutsidetwotoeightdegrees varchar(255), + storagetemperaturemonitoringadditionaldetails text, + correctprocedureforstoragefollowed varchar(255), + anyotheriteminrefrigerator varchar(255), + partiallyusedreconstitutedvaccinesinrefrigerator varchar(255), + unusablevaccinesinrefrigerator varchar(255), + unusablediluentsinstore varchar(255), + vaccinestoragepointadditionaldetails text, + vaccinecarriertype varchar(255), + vaccinecarriertypedetails varchar(512), + vaccinecarriersenttositeonsamedateasvaccination varchar(255), + vaccinecarrierreturnedfromsiteonsamedateasvaccination varchar(255), + conditionedicepackused varchar(255), + vaccinetransportationadditionaldetails text, + similareventsreportedsameperiodandlocality varchar(255), + similareventsreportedsameperiodandlocalitydetails varchar(512), + numberofsimilareventsreportedsameperiodandlocality integer, + numberofthoseaffectedvaccinated integer, + numberofthoseaffectednotvaccinated integer, + numberofthoseaffectedvaccinatedunknown integer, + communityinvestigationadditionaldetails text, + otherinvestigationfindings text, + investigationstatus varchar(255), + investigationstatusdetails text, + adverseeventfollowingimmunizationclassification varchar(255), + adverseeventfollowingimmunizationclassificationsubtype varchar(255), + adverseeventfollowingimmunizationclassificationdetails varchar(512), + causality varchar(255), + causalitydetails text, + investigationcompletiondate timestamp, + archived boolean, + endofprocessingdate timestamp, + archiveundonereason varchar(255), + deleted boolean, + deletionreason varchar(255), + otherdeletionreason text, + sys_period tstzrange not null, + change_user_id bigint +); + +alter table adverseeventsfollowingimmunizationinvestigation owner to sormas_user; + +alter table adverseeventsfollowingimmunizationinvestigation add primary key (id); +alter table adverseeventsfollowingimmunizationinvestigation add unique (uuid); +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_address_id foreign key (address_id) references location; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_aefi_id foreign key (adverseeventsfollowingimmunization_id) references adverseeventsfollowingimmunization; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_change_user_id foreign key (change_user_id) references users; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_country_id foreign key (country_id) references country; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_primarysuspectvaccine_id foreign key (primarysuspectvaccine_id) references vaccination; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_reportingofficeraddress_id foreign key (reportingofficeraddress_id) references location; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_reportingofficerfacility_id foreign key (reportingofficerfacility_id) references facility; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_reportinguser_id foreign key (reportinguser_id) references users; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_responsiblecommunity_id foreign key (responsiblecommunity_id) references community; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_responsibledistrict_id foreign key (responsibledistrict_id) references district; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_responsibleregion_id foreign key (responsibleregion_id) references region; +alter table adverseeventsfollowingimmunizationinvestigation add constraint fk_aefiinvestigation_vaccinationfacility_id foreign key (vaccinationfacility_id) references facility; + +-- AEFI investigation history +CREATE TABLE adverseeventsfollowingimmunizationinvestigation_history (LIKE adverseeventsfollowingimmunizationinvestigation); + +DROP TRIGGER IF EXISTS versioning_trigger ON adverseeventsfollowingimmunizationinvestigation; +CREATE TRIGGER versioning_trigger + BEFORE INSERT OR UPDATE ON adverseeventsfollowingimmunizationinvestigation + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'adverseeventsfollowingimmunizationinvestigation_history', true); +DROP TRIGGER IF EXISTS delete_history_trigger ON adverseeventsfollowingimmunizationinvestigation; +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON adverseeventsfollowingimmunizationinvestigation + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('adverseeventsfollowingimmunizationinvestigation_history', 'id'); + +ALTER TABLE adverseeventsfollowingimmunizationinvestigation_history OWNER TO sormas_user; + +-- AEFI investigation vaccination +create table adverseeventsfollowingimmunizationinvestigation_vaccinations +( + adverseeventsfollowingimmunizationinvestigation_id bigint not null, + vaccination_id bigint not null, + sys_period tstzrange not null +); + +alter table adverseeventsfollowingimmunizationinvestigation_vaccinations owner to sormas_user; + +alter table adverseeventsfollowingimmunizationinvestigation_vaccinations add constraint aefi_investigation_vaccinations_pkey primary key (adverseeventsfollowingimmunizationinvestigation_id, vaccination_id); +alter table adverseeventsfollowingimmunizationinvestigation_vaccinations add constraint fk_aefiinvestigation_vaccinations_aefiinvestigation_id foreign key (adverseeventsfollowingimmunizationinvestigation_id) references adverseeventsfollowingimmunizationinvestigation; +alter table adverseeventsfollowingimmunizationinvestigation_vaccinations add constraint fk_aefiinvestigation_vaccinations_vaccination_id foreign key (vaccination_id) references vaccination; + +-- AEFI investigation vaccination history +CREATE TABLE aefiinvestigation_vaccinations_history (LIKE adverseeventsfollowingimmunizationinvestigation_vaccinations); +DROP TRIGGER IF EXISTS versioning_trigger ON adverseeventsfollowingimmunizationinvestigation_vaccinations; +CREATE TRIGGER versioning_trigger + BEFORE INSERT OR UPDATE ON adverseeventsfollowingimmunizationinvestigation_vaccinations + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'aefiinvestigation_vaccinations_history', true); +DROP TRIGGER IF EXISTS delete_history_trigger ON adverseeventsfollowingimmunizationinvestigation_vaccinations; +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON adverseeventsfollowingimmunizationinvestigation_vaccinations + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('aefiinvestigation_vaccinations_history', 'id'); +ALTER TABLE aefiinvestigation_vaccinations_history OWNER TO sormas_user; + +-- Assign AEFI user rights to default admin and national_user user roles +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT' FROM public.userroles WHERE userroles.linkeddefaultuserrole in ('ADMIN','NATIONAL_USER'); + +INSERT INTO schema_version (version_number, comment) VALUES (552, 'Adverse Events Following Immunization (AEFI) - Entities #12634'); + + +-- 2024-10-23 Add "Disease" Attribute to Document Templates for Filtering #13160 +CREATE TABLE documenttemplates ( + id bigint not null, + uuid varchar(36) not null unique, + changedate timestamp not null, + creationdate timestamp not null, + change_user_id bigint, + + workflow varchar(255) not null, + disease varchar(255), + fileName text, + + sys_period tstzrange not null, + primary key(id) +); + +ALTER TABLE documenttemplates OWNER TO sormas_user; +ALTER TABLE documenttemplates ADD CONSTRAINT fk_change_user_id FOREIGN KEY (change_user_id) REFERENCES users (id); + +CREATE TABLE documenttemplates_history (LIKE documenttemplates); +CREATE TRIGGER versioning_trigger BEFORE INSERT OR UPDATE ON documenttemplates + FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'documenttemplates_history', true); +CREATE TRIGGER delete_history_trigger + AFTER DELETE ON documenttemplates + FOR EACH ROW EXECUTE PROCEDURE delete_history_trigger('documenttemplates_history', 'id'); +ALTER TABLE documenttemplates_history OWNER TO sormas_user; + +INSERT INTO schema_version (version_number, comment, upgradeneeded) VALUES (553, 'Add "Disease" Attribute to Document Templates for Filtering #13160', true); + +-- 2024-11-18 Add New Influenza Disease Types and Modify Display for SORMAS-LuxembourgAdd #13183 +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases, properties) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'A', 'Type A', + 'INFLUENZA', jsonb_build_object('hasDetails', true)); +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'B', 'Type B', + 'INFLUENZA'); +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases, properties) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'AB', 'Type A+B', + 'INFLUENZA', jsonb_build_object('hasDetails', true)); + +INSERT INTO schema_version (version_number, comment) VALUES (554, 'Add New Influenza Disease Types and Modify Display for SORMAS-LuxembourgAdd #13183'); + +-- 2024-12-12 RSV disease variants #13204 +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'A', 'Type A', + 'RESPIRATORY_SYNCYTIAL_VIRUS'); +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'B', 'Type B', + 'RESPIRATORY_SYNCYTIAL_VIRUS'); +INSERT INTO customizableenumvalue(id, uuid, changedate, creationdate, datatype, value, caption, diseases) +VALUES (nextval('entity_seq'), generate_base32_uuid(), now(), now(), 'DISEASE_VARIANT', 'AB', 'Type A+B', + 'RESPIRATORY_SYNCYTIAL_VIRUS'); + +INSERT INTO schema_version (version_number, comment) VALUES (555, 'RSV disease variants #13204'); + +-- 2024-12-12 Additional lab message fields #13203 +ALTER TABLE externalmessage + ADD COLUMN vaccinationstatus varchar(255), + ADD COLUMN admittedtohealthfacility varchar(255); +ALTER TABLE externalmessage_history + ADD COLUMN vaccinationstatus varchar(255), + ADD COLUMN admittedtohealthfacility varchar(255); + +INSERT INTO schema_version (version_number, comment) VALUES (556, 'Additional lab message fields #13203'); -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index a8dcfb20fbf..4a940ef86a5 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -155,6 +155,7 @@ import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.disease.DiseaseConfigurationService; import de.symeda.sormas.backend.docgeneration.DocumentTemplateFacadeEjb.DocumentTemplateFacadeEjbLocal; +import de.symeda.sormas.backend.docgeneration.DocumentTemplateService; import de.symeda.sormas.backend.docgeneration.EventDocumentFacadeEjb; import de.symeda.sormas.backend.docgeneration.QuarantineOrderFacadeEjb; import de.symeda.sormas.backend.document.DocumentFacadeEjb; @@ -899,6 +900,10 @@ public DocumentTemplateFacade getDocumentTemplateFacade() { return getBean(DocumentTemplateFacadeEjbLocal.class); } + public DocumentTemplateService getDocumentTemplateService() { + return getBean(DocumentTemplateService.class); + } + public QuarantineOrderFacade getQuarantineOrderFacade() { return getBean(QuarantineOrderFacadeEjb.QuarantineOrderFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index a45518e4ce8..b679bac8f35 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -2236,7 +2236,7 @@ public DiseaseVariant createDiseaseVariant(String name, Disease disease) { beanTest.getCustomizableEnumValueService().ensurePersisted(diseaseVariant); - return beanTest.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, name); + return beanTest.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, disease, name); } public Pathogen createPathogen(String value, String caption) { @@ -2251,7 +2251,7 @@ public Pathogen createPathogen(String value, String caption) { beanTest.getCustomizableEnumFacade().loadData(); - return beanTest.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.PATHOGEN, value); + return beanTest.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.PATHOGEN, null, value); } public ExternalShareInfo createExternalShareInfo( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index 46bc12c5d7b..03015193c41 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -3343,7 +3343,9 @@ public void testBulkUpdateBulkEditDiseaseVariant() { DiseaseVariant diseaseVariant = creator.createDiseaseVariant("BF.1.2", Disease.CORONAVIRUS); Mockito - .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, diseaseVariant.getValue())) + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, diseaseVariant.getValue())) .thenReturn(diseaseVariant); CaseBulkEditData bulkEditData = new CaseBulkEditData(); @@ -3376,7 +3378,9 @@ public void testBulkUpdateBulkEditDiseaseVariant() { public void testBulkUpdateBulkEditDiseaseClearVariantOfChangedDisease() { DiseaseVariant diseaseVariant = creator.createDiseaseVariant("BF.1.2", Disease.CORONAVIRUS); Mockito - .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, diseaseVariant.getValue())) + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, diseaseVariant.getValue())) .thenReturn(diseaseVariant); CaseDataDto caze = creator.createCase(surveillanceSupervisor.toReference(), creator.createPerson().toReference(), rdcf, c -> { c.setDisease(Disease.CORONAVIRUS); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/HistoryTablesTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/HistoryTablesTest.java index ecaba04ef41..725e266a9ed 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/HistoryTablesTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/HistoryTablesTest.java @@ -27,13 +27,19 @@ import org.testcontainers.containers.JdbcDatabaseContainer; import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.images.builder.ImageFromDockerfile; +import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; import de.hilling.junit.cdi.CdiTestJunitExtension; import de.hilling.junit.cdi.annotations.BypassTestInterceptor; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; @ExtendWith(CdiTestJunitExtension.class) public class HistoryTablesTest { + private static final List NO_HISTORY_REQUIRED_TABLES = + Arrays.asList(Aefi.AEFI_VACCINATIONS_TABLE_NAME, AefiInvestigation.AEFI_INVESTIGATION_VACCINATIONS_TABLE_NAME); + /** * Test that the *_history tables have the same columns as the corresponding production tables * @@ -71,6 +77,7 @@ public void testHistoryTablesMatch() throws IOException, URISyntaxException { Files.readAllBytes(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("checkHistoryTables.sql")).toURI()))); @SuppressWarnings("unchecked") List results = (List) em.createNativeQuery(checkHistoryTablesSql).getResultList(); + results.removeIf(o -> StringUtils.containsAny(o[1].toString(), NO_HISTORY_REQUIRED_TABLES.toArray(String[]::new))); StringBuilder result = new StringBuilder(); results.forEach(objects -> { result.append("\n"); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverterTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverterTest.java new file mode 100644 index 00000000000..745c09082ef --- /dev/null +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverterTest.java @@ -0,0 +1,114 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.customizableenum; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.CaseDataDto; +import de.symeda.sormas.api.customizableenum.CustomizableEnum; +import de.symeda.sormas.api.customizableenum.CustomizableEnumType; +import de.symeda.sormas.api.disease.DiseaseVariantConverter; +import de.symeda.sormas.api.user.DefaultUserRole; +import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.backend.AbstractBeanTest; +import de.symeda.sormas.backend.MockProducer; +import de.symeda.sormas.backend.TestDataCreator; + +public class CustomizableEnumConverterTest extends AbstractBeanTest { + + private TestDataCreator.RDCF rdcf; + private UserReferenceDto reportingUser; + private CustomizableEnum bf_1_2; + private CustomizableEnum generic; + + @Override + public void init() { + super.init(); + + rdcf = creator.createRDCF(); + reportingUser = creator.createUser(rdcf, DefaultUserRole.SURVEILLANCE_OFFICER).toReference(); + + List enumValues = getCustomizableEnumValueService().getAll(); + if (enumValues.isEmpty()) { + CustomizableEnumValue bf_1_2_value = new CustomizableEnumValue(); + bf_1_2_value.setDataType(CustomizableEnumType.DISEASE_VARIANT); + bf_1_2_value.setValue("BF.1.2"); + Set diseases = new HashSet<>(); + diseases.add(Disease.CORONAVIRUS); + bf_1_2_value.setDiseases(diseases); + bf_1_2_value.setCaption("BF.1.2 variant"); + bf_1_2_value.setActive(true); + getCustomizableEnumValueService().ensurePersisted(bf_1_2_value); + + CustomizableEnumValue generic_value = new CustomizableEnumValue(); + generic_value.setDataType(CustomizableEnumType.DISEASE_VARIANT); + generic_value.setValue("GENERIC"); + generic_value.setCaption("Variant 2"); + generic_value.setActive(true); + getCustomizableEnumValueService().ensurePersisted(generic_value); + + getCustomizableEnumFacade().loadData(); + + bf_1_2 = getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, bf_1_2_value.getValue()); + generic = getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, null, generic_value.getValue()); + + Mockito + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, bf_1_2_value.getValue())) + .thenReturn(bf_1_2); + Mockito + .when( + MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, null, generic_value.getValue())) + .thenReturn(generic); + } + } + + @Test + public void testConvertCovidDiseaseVariant() { + CaseDataDto caze = creator.createCase(reportingUser, creator.createPerson().toReference(), rdcf, c -> { + c.setDisease(Disease.CORONAVIRUS); + c.setDiseaseVariant(new DiseaseVariantConverter().convertToEntityAttribute(Disease.CORONAVIRUS, bf_1_2.getValue())); + }); + + assertThat(caze.getDiseaseVariant().getValue(), is(bf_1_2.getValue())); + + CaseDataDto reloadedCase = getCaseFacade().getByUuid(caze.getUuid()); + assertThat(reloadedCase.getDiseaseVariant().getValue(), is(bf_1_2.getValue())); + } + + @Test + public void testConvertGenericDiseaseVariant() { + CaseDataDto caze = creator.createCase(reportingUser, creator.createPerson().toReference(), rdcf, c -> { + c.setDisease(Disease.CORONAVIRUS); + c.setDiseaseVariant(new DiseaseVariantConverter().convertToEntityAttribute(Disease.CORONAVIRUS, generic.getValue())); + }); + + assertThat(caze.getDiseaseVariant().getValue(), is(generic.getValue())); + + CaseDataDto reloadedCase = getCaseFacade().getByUuid(caze.getUuid()); + assertThat(reloadedCase.getDiseaseVariant().getValue(), is(generic.getValue())); + } +} diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/AbstractDocGenerationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/AbstractDocGenerationTest.java index 913be35319d..187a888afb2 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/AbstractDocGenerationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/AbstractDocGenerationTest.java @@ -6,6 +6,9 @@ import org.junit.jupiter.api.AfterEach; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; +import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.AbstractBeanTest; import de.symeda.sormas.backend.MockProducer; import de.symeda.sormas.backend.common.ConfigFacadeEjb; @@ -36,4 +39,19 @@ protected void resetDefaultNullReplacement() { public void teardown() throws URISyntaxException { reset(); } + + protected DocumentTemplate createDocumentTemplate(DocumentWorkflow workflow, String templateFileName) { + DocumentTemplate template = new DocumentTemplate(); + template.setUuid(DataHelper.createUuid()); + template.setFileName(templateFileName); + template.setWorkflow(workflow); + + getDocumentTemplateService().persist(template); + + return template; + } + + protected static DocumentTemplateReferenceDto toReference(DocumentTemplate documentTemplate) { + return new DocumentTemplateReferenceDto(documentTemplate.getUuid(), documentTemplate.getFileName()); + } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjbTest.java index 8f410e4df3a..69cec0fe7ce 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjbTest.java @@ -27,14 +27,18 @@ import java.io.IOException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentTemplateFacade; +import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.MockProducer; import de.symeda.sormas.backend.common.ConfigFacadeEjb; @@ -54,46 +58,74 @@ public void writeAndDeleteTemplateTest() throws IOException, URISyntaxException, String testDirectory = "target" + File.separator + "doctest"; byte[] document = IOUtils.toByteArray(getClass().getResourceAsStream("/docgeneration/quarantine/Quarantine.docx")); MockProducer.getProperties().setProperty(ConfigFacadeEjb.CUSTOM_FILES_PATH, testDirectory); - documentTemplateFacade.writeDocumentTemplate(QUARANTINE_ORDER_CASE, "TemplateFileToBeDeleted.docx", document); - assertTrue(documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE).contains("TemplateFileToBeDeleted.docx")); - assertTrue(documentTemplateFacade.deleteDocumentTemplate(QUARANTINE_ORDER_CASE, "TemplateFileToBeDeleted.docx")); - assertFalse(documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE).contains("TemplateFileToBeDeleted.docx")); + + DocumentTemplateDto templateDto = DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "TemplateFileToBeDeleted.docx"); + documentTemplateFacade.saveDocumentTemplate(templateDto, document); + + assertTrue(documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE, null).contains(templateDto)); + + DocumentTemplateDto templateForCovid = DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "TemplateFileToBeDeletedCovid.docx"); + templateForCovid.setDisease(Disease.CORONAVIRUS); + documentTemplateFacade.saveDocumentTemplate(templateForCovid, document); + + List templatesForCovid = documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE, Disease.CORONAVIRUS); + assertTrue(templatesForCovid.contains(templateDto)); + assertTrue(templatesForCovid.contains(templateForCovid)); + + List templatesForLassa = documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE, Disease.LASSA); + assertTrue(templatesForLassa.contains(templateDto)); + assertFalse(templatesForLassa.contains(templateForCovid)); + + assertTrue(documentTemplateFacade.deleteDocumentTemplate(templateDto.toReference())); + assertFalse(documentTemplateFacade.getAvailableTemplates(QUARANTINE_ORDER_CASE, null).contains(templateDto)); + FileUtils.deleteDirectory(new File(testDirectory)); resetCustomPath(); } @Test - public void isExistingTemplateTest() { - assertTrue(documentTemplateFacade.isExistingTemplate(QUARANTINE_ORDER_CASE, "Quarantine.docx")); - assertFalse(documentTemplateFacade.isExistingTemplate(QUARANTINE_ORDER_CASE, "ThisTemplateDoesNotExist.docx")); + public void isExistingTemplateFileTest() { + assertTrue(documentTemplateFacade.isExistingTemplateFile(QUARANTINE_ORDER_CASE, null, "Quarantine.docx")); + assertFalse(documentTemplateFacade.isExistingTemplateFile(QUARANTINE_ORDER_CASE, null, "ThisTemplateDoesNotExist.docx")); } @Test public void validateTemplateTest() throws IOException { try { - documentTemplateFacade.writeDocumentTemplate(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.txt", new byte[0]); + documentTemplateFacade + .saveDocumentTemplate(DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.txt"), new byte[0]); fail("Invalid file extension not recognized."); - } catch (DocumentTemplateException e) { + } catch (ValidationRuntimeException e) { assertEquals("Wrong file type", e.getMessage()); + } catch (DocumentTemplateException e) { + fail("Invalid file extension not recognized.", e); } try { - documentTemplateFacade.writeDocumentTemplate(QUARANTINE_ORDER_CASE, "../TemplateFileToBeValidated.docx", new byte[0]); + documentTemplateFacade + .saveDocumentTemplate(DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "../TemplateFileToBeValidated.docx"), new byte[0]); fail("Invalid file extension not recognized."); - } catch (DocumentTemplateException e) { + } catch (ValidationRuntimeException e) { assertEquals("Illegal file name: ../TemplateFileToBeValidated.docx", e.getMessage()); + } catch (DocumentTemplateException e) { + fail("Invalid file extension not recognized.", e); } try { - documentTemplateFacade.writeDocumentTemplate(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.docx", new byte[0]); + documentTemplateFacade + .saveDocumentTemplate(DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.docx"), new byte[0]); fail("Invalid docx file not recognized."); - } catch (DocumentTemplateException e) { + } catch (ValidationRuntimeException e) { assertEquals("The template file is corrupt.", e.getMessage()); + } catch (DocumentTemplateException e) { + fail("Invalid docx file not recognized", e); } try { byte[] document = IOUtils.toByteArray(getClass().getResourceAsStream("/docgeneration/quarantine/FaultyTemplate.docx")); - documentTemplateFacade.writeDocumentTemplate(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.docx", document); + documentTemplateFacade.saveDocumentTemplate(DocumentTemplateDto.build(QUARANTINE_ORDER_CASE, "TemplateFileToBeValidated.docx"), document); fail("Syntax error not recognized."); - } catch (DocumentTemplateException e) { + } catch (ValidationRuntimeException e) { assertEquals("Error processing template.", e.getMessage()); + } catch (DocumentTemplateException e) { + fail("Syntax error not recognized.", e); } } @@ -101,38 +133,41 @@ public void validateTemplateTest() throws IOException { public void testEmailTemplateValidation() throws DocumentTemplateException { assertThrows( ValidationRuntimeException.class, - () -> documentTemplateFacade - .writeDocumentTemplate(CASE_EMAIL, "CaseEmailTemplate.txt", "Email template without subject".getBytes(StandardCharsets.UTF_8))); + () -> documentTemplateFacade.saveDocumentTemplate( + DocumentTemplateDto.build(CASE_EMAIL, "CaseEmailTemplate.txt"), + "Email template without subject".getBytes(StandardCharsets.UTF_8))); assertThrows( ValidationRuntimeException.class, - () -> documentTemplateFacade.writeDocumentTemplate( - CASE_EMAIL, - "CaseEmailTemplate.txt", + () -> documentTemplateFacade.saveDocumentTemplate( + DocumentTemplateDto.build(CASE_EMAIL, "CaseEmailTemplate.txt"), "Email template without subject\nSecond line".getBytes(StandardCharsets.UTF_8))); assertThrows( ValidationRuntimeException.class, - () -> documentTemplateFacade.writeDocumentTemplate( - CASE_EMAIL, - "CaseEmailTemplate.txt", + () -> documentTemplateFacade.saveDocumentTemplate( + DocumentTemplateDto.build(CASE_EMAIL, "CaseEmailTemplate.txt"), "#\nEmail template without subject\nSecond line".getBytes(StandardCharsets.UTF_8))); assertThrows( ValidationRuntimeException.class, - () -> documentTemplateFacade.writeDocumentTemplate( - CASE_EMAIL, - "CaseEmailTemplate.txt", + () -> documentTemplateFacade.saveDocumentTemplate( + DocumentTemplateDto.build(CASE_EMAIL, "CaseEmailTemplate.txt"), "# \nEmail template without subject\nSecond line".getBytes(StandardCharsets.UTF_8))); assertThrows( ValidationRuntimeException.class, - () -> documentTemplateFacade.writeDocumentTemplate( - CASE_EMAIL, - "CaseEmailTemplate.txt", + () -> documentTemplateFacade.saveDocumentTemplate( + DocumentTemplateDto.build(CASE_EMAIL, "CaseEmailTemplate.txt"), "*Subject\nEmail template without subject\nSecond line".getBytes(StandardCharsets.UTF_8))); } @Test public void readTemplateTest() throws DocumentTemplateException { - byte[] template = documentTemplateFacade.getDocumentTemplate(QUARANTINE_ORDER_CASE, "Quarantine.docx"); + DocumentTemplate templateEntity = new DocumentTemplate(); + templateEntity.setUuid(DataHelper.createUuid()); + templateEntity.setWorkflow(QUARANTINE_ORDER_CASE); + templateEntity.setFileName("Quarantine.docx"); + + getDocumentTemplateService().ensurePersisted(templateEntity); + byte[] template = documentTemplateFacade.getDocumentTemplateContent(toReference(templateEntity)); assertEquals(12731, template.length); } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjbTest.java index 441e8356e8d..222f107e9a6 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/EventDocumentFacadeEjbTest.java @@ -9,6 +9,8 @@ import java.io.StringWriter; import java.net.URISyntaxException; import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; import org.apache.commons.io.FilenameUtils; @@ -20,6 +22,7 @@ import de.symeda.sormas.api.action.ActionContext; import de.symeda.sormas.api.action.ActionDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EventDocumentFacade; import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventInvestigationStatus; @@ -129,11 +132,19 @@ public void generateEventHandoutTest() throws IOException, URISyntaxException, D File[] testCasesHtml = testCasesDir.listFiles((d, name) -> name.endsWith(".html")); assertNotNull(testCasesHtml); + Map documentTemplates = new HashMap<>(testCasesHtml.length); for (File testCaseHtml : testCasesHtml) { String testcaseBasename = FilenameUtils.getBaseName(testCaseHtml.getName()); + DocumentTemplate documentTemplate = createDocumentTemplate(DocumentWorkflow.EVENT_HANDOUT, testcaseBasename + ".html"); + documentTemplates.put(testcaseBasename, documentTemplate); + } + + for (File testCaseHtml : testCasesHtml) { + String testcaseBasename = FilenameUtils.getBaseName(testCaseHtml.getName()); + DocumentTemplate documentTemplate = documentTemplates.get(testcaseBasename); String htmlText = - eventDocumentFacade.getGeneratedDocument(testcaseBasename + ".html", eventDto.toReference(), new Properties(), Boolean.FALSE); + eventDocumentFacade.getGeneratedDocument(toReference(documentTemplate), eventDto.toReference(), new Properties(), Boolean.FALSE); String actual = cleanLineSeparators( htmlText.replaceAll("

Event-ID: [A-Z0-9-]*

", "

Event-ID: STN3WX-5JTGYV-IU2LRM-4UHCSOEE

")); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java index 5dac8076044..a885d1ecf9c 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java @@ -44,6 +44,7 @@ import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; @@ -69,9 +70,7 @@ import de.symeda.sormas.api.travelentry.TravelEntryReferenceDto; import de.symeda.sormas.api.user.DefaultUserRole; import de.symeda.sormas.api.user.UserDto; -import de.symeda.sormas.backend.MockProducer; import de.symeda.sormas.backend.TestDataCreator; -import de.symeda.sormas.backend.common.ConfigFacadeEjb; public class QuarantineOrderFacadeEjbTest extends AbstractDocGenerationTest { @@ -85,6 +84,11 @@ public class QuarantineOrderFacadeEjbTest extends AbstractDocGenerationTest { private SampleDto sampleDto; private PathogenTestDto pathogenTestDto; + private DocumentTemplate caseDocumentTemplate; + private DocumentTemplate contactDocumentTemplate; + private DocumentTemplate eventParticipantDocumentTemplate; + private DocumentTemplate travelEntryDocumentTemplate; + @BeforeEach public void setup() throws URISyntaxException { TestDataCreator.RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility", "PointOfEntry"); @@ -167,6 +171,12 @@ public void setup() throws URISyntaxException { travelEntryDto.setResponsibleRegion(rdcf.region); travelEntryDto.setResponsibleDistrict(rdcf.district); travelEntryDto = getTravelEntryFacade().save(travelEntryDto); + + caseDocumentTemplate = createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_CASE, "Quarantine.docx"); + createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_CASE, "FaultyTemplate.docx"); + contactDocumentTemplate = createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_CONTACT, "Quarantine.docx"); + eventParticipantDocumentTemplate = createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_EVENT_PARTICIPANT, "Quarantine.docx"); + travelEntryDocumentTemplate = createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_TRAVEL_ENTRY, "Quarantine.docx"); } private Date parseDate(String dateString) { @@ -182,7 +192,7 @@ public void generateQuarantineOrderCaseTest() throws IOException, DocumentTempla generateQuarantineOrderTest( RootEntityType.ROOT_CASE, caseDataDto.toReference(), - DocumentWorkflow.QUARANTINE_ORDER_CASE, + caseDocumentTemplate, sampleDto.toReference(), pathogenTestDto.toReference(), "QuarantineCase.cmp"); @@ -193,7 +203,7 @@ public void generateQuarantineOrderContactTest() throws IOException, DocumentTem generateQuarantineOrderTest( RootEntityType.ROOT_CONTACT, contactDto.toReference(), - DocumentWorkflow.QUARANTINE_ORDER_CONTACT, + contactDocumentTemplate, null, null, "QuarantineContact.cmp"); @@ -204,7 +214,7 @@ public void generateQuarantineOrderEventParticipantTest() throws IOException, Do generateQuarantineOrderTest( RootEntityType.ROOT_EVENT_PARTICIPANT, eventParticipantDto.toReference(), - DocumentWorkflow.QUARANTINE_ORDER_EVENT_PARTICIPANT, + eventParticipantDocumentTemplate, null, null, "QuarantineEvent.cmp"); @@ -215,7 +225,7 @@ public void generateQuarantineOrderTravelEntryTest() throws IOException, Documen generateQuarantineOrderTest( RootEntityType.ROOT_TRAVEL_ENTRY, travelEntryDto.toReference(), - DocumentWorkflow.QUARANTINE_ORDER_TRAVEL_ENTRY, + travelEntryDocumentTemplate, null, null, "QuarantineTravelEntry.cmp"); @@ -229,7 +239,7 @@ public void generateQuarantineOrderCustomNullReplacementTest() throws IOExceptio generateQuarantineOrderTest( RootEntityType.ROOT_CASE, rootEntityReference, - DocumentWorkflow.QUARANTINE_ORDER_CASE, + caseDocumentTemplate, null, null, "QuarantineCaseEmptyNullReplacement.cmp"); @@ -238,7 +248,7 @@ public void generateQuarantineOrderCustomNullReplacementTest() throws IOExceptio generateQuarantineOrderTest( RootEntityType.ROOT_CASE, rootEntityReference, - DocumentWorkflow.QUARANTINE_ORDER_CASE, + caseDocumentTemplate, null, null, "QuarantineCaseCustomNullReplacement.cmp"); @@ -252,11 +262,10 @@ public void testBulkCaseDocumentCreation() throws DocumentTemplateException, IOE properties.setProperty("extraremark1", "the first remark"); properties.setProperty("extra.remark.no3", "the third remark"); - DocumentWorkflow workflow = DocumentWorkflow.QUARANTINE_ORDER_CASE; Map documentContents = quarantineOrderFacadeEjb - .getGeneratedDocuments("Quarantine.docx", workflow, Collections.singletonList(rootEntityReference), properties, false); + .getGeneratedDocuments(toReference(caseDocumentTemplate), Collections.singletonList(rootEntityReference), properties, false); - verifyGeneratedDocument(rootEntityReference, workflow, "QuarantineCase.cmp", documentContents.get(rootEntityReference)); + verifyGeneratedDocument(rootEntityReference, caseDocumentTemplate, "QuarantineCase.cmp", documentContents.get(rootEntityReference)); } @Test @@ -266,11 +275,10 @@ public void testBulkContactDocumentCreation() throws DocumentTemplateException, properties.setProperty("extraremark1", "the first remark"); properties.setProperty("extra.remark.no3", "the third remark"); - DocumentWorkflow workflow = DocumentWorkflow.QUARANTINE_ORDER_CONTACT; Map documentContents = quarantineOrderFacadeEjb - .getGeneratedDocuments("Quarantine.docx", workflow, Collections.singletonList(rootEntityReference), properties, false); + .getGeneratedDocuments(toReference(contactDocumentTemplate), Collections.singletonList(rootEntityReference), properties, false); - verifyGeneratedDocument(rootEntityReference, workflow, "QuarantineContact.cmp", documentContents.get(rootEntityReference)); + verifyGeneratedDocument(rootEntityReference, contactDocumentTemplate, "QuarantineContact.cmp", documentContents.get(rootEntityReference)); } @Test @@ -281,21 +289,24 @@ public void testBulkEventParticipantDocumentCreation() throws DocumentTemplateEx properties.setProperty("extraremark1", "the first remark"); properties.setProperty("extra.remark.no3", "the third remark"); - DocumentWorkflow workflow = DocumentWorkflow.QUARANTINE_ORDER_EVENT_PARTICIPANT; Map documentContents = quarantineOrderFacadeEjb.getGeneratedDocumentsForEventParticipants( - "Quarantine.docx", + toReference(eventParticipantDocumentTemplate), Collections.singletonList(rootEntityReference), eventDto.getDisease(), properties, false); - verifyGeneratedDocument(rootEntityReference, workflow, "QuarantineEvent.cmp", documentContents.get(rootEntityReference)); + verifyGeneratedDocument( + rootEntityReference, + eventParticipantDocumentTemplate, + "QuarantineEvent.cmp", + documentContents.get(rootEntityReference)); } private void generateQuarantineOrderTest( RootEntityType rootEntityType, ReferenceDto rootEntityReference, - DocumentWorkflow documentWorkflow, + DocumentTemplate template, SampleReferenceDto sampleReference, PathogenTestReferenceDto pathogenTest, String comparisonFile) @@ -308,11 +319,10 @@ private void generateQuarantineOrderTest( verifyGeneratedDocument( rootEntityReference, - documentWorkflow, + template, comparisonFile, quarantineOrderFacadeEjb.getGeneratedDocument( - "Quarantine.docx", - documentWorkflow, + toReference(template), rootEntityType, rootEntityReference, sampleReference, @@ -324,19 +334,19 @@ private void generateQuarantineOrderTest( private void verifyGeneratedDocument( ReferenceDto rootEntityReference, - DocumentWorkflow documentWorkflow, + DocumentTemplate docuembtTemplate, String comparisonFile, byte[] documentContent) throws IOException, DocumentTemplateException { - DocumentVariables documentVariables = quarantineOrderFacadeEjb.getDocumentVariables(documentWorkflow, "Quarantine.docx"); + DocumentVariables documentVariables = quarantineOrderFacadeEjb.getDocumentVariables(toReference(docuembtTemplate)); List additionalVariables = documentVariables.getAdditionalVariables(); String rootEntityName; List expectedVariables = Arrays.asList("extraremark1", "extra.remark2", "extra.remark.no3"); List expectedUsedEntities = new ArrayList<>(Arrays.asList("person", "user", "sample", "pathogenTest")); - switch (documentWorkflow) { + switch (docuembtTemplate.getWorkflow()) { case QUARANTINE_ORDER_CASE: rootEntityName = "case"; break; @@ -391,17 +401,11 @@ private void verifyGeneratedDocument( } @Test - public void getAvailableTemplatesTest() throws URISyntaxException { - List availableTemplates = quarantineOrderFacadeEjb.getAvailableTemplates(DocumentWorkflow.QUARANTINE_ORDER_CASE); + public void getAvailableTemplatesTest() { + List availableTemplates = quarantineOrderFacadeEjb.getAvailableTemplates(DocumentWorkflow.QUARANTINE_ORDER_CASE, null); assertEquals(2, availableTemplates.size()); - assertTrue(availableTemplates.contains("Quarantine.docx")); - assertTrue(availableTemplates.contains("FaultyTemplate.docx")); - - MockProducer.getProperties().setProperty(ConfigFacadeEjb.CUSTOM_FILES_PATH, "thisDirectoryDoesNotExist"); - - assertTrue(quarantineOrderFacadeEjb.getAvailableTemplates(DocumentWorkflow.QUARANTINE_ORDER_CASE).isEmpty()); - - resetCustomPath(); + assertTrue(availableTemplates.stream().anyMatch(dt -> dt.getFileName().equals("Quarantine.docx"))); + assertTrue(availableTemplates.stream().anyMatch(dt -> dt.getFileName().equals("FaultyTemplate.docx"))); } private DocumentWorkflow getDocumentWorkflow(ReferenceDto reference) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjbTest.java index c993b2d4fe2..e378f6c844a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/environment/environmentsample/EnvironmentSampleFacadeEjbTest.java @@ -449,7 +449,8 @@ public void testGetIndexList() { reportingUser.toReference(), PathogenTestResultType.POSITIVE, null); - Mockito.when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.PATHOGEN, positivePathogen.getValue())) + Mockito + .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.PATHOGEN, null, positivePathogen.getValue())) .thenReturn(positivePathogen); Pathogen pendingPathogen = creator.createPathogen("TEST_PATHOGEN_2", "Test pathogen 2"); @@ -461,7 +462,8 @@ public void testGetIndexList() { reportingUser.toReference(), PathogenTestResultType.PENDING, null); - Mockito.when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.PATHOGEN, pendingPathogen.getValue())) + Mockito + .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.PATHOGEN, null, pendingPathogen.getValue())) .thenReturn(pendingPathogen); creator.createEnvironmentSample(environment.toReference(), reportingUser.toReference(), rdcf, lab.toReference(), null); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjbTest.java index a5a811d255c..efe9c0f1122 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalemail/ExternalEmailFacadeEjbTest.java @@ -62,6 +62,7 @@ import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactStatus; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EmailAttachementDto; @@ -96,6 +97,7 @@ import de.symeda.sormas.backend.common.messaging.InvalidPhoneNumberException; import de.symeda.sormas.backend.common.messaging.SmsService; import de.symeda.sormas.backend.docgeneration.AbstractDocGenerationTest; +import de.symeda.sormas.backend.docgeneration.DocumentTemplate; import de.symeda.sormas.backend.document.Document; import de.symeda.sormas.backend.document.DocumentRelatedEntity; @@ -107,6 +109,10 @@ public class ExternalEmailFacadeEjbTest extends AbstractDocGenerationTest { private PersonDto personDto; private LocationDto locationDto2; + private DocumentTemplate caseEmailTemplate; + private DocumentTemplate quarantineOrderTemplate; + private DocumentTemplate contactEmailTemplate; + @Mock private EmailService emailService; @Mock @@ -154,6 +160,10 @@ public void init() { personDto.setEmailAddress("testEmail@email.com"); getPersonFacade().save(personDto); + + caseEmailTemplate = createDocumentTemplate(DocumentWorkflow.CASE_EMAIL, "CaseEmail.txt"); + quarantineOrderTemplate = createDocumentTemplate(DocumentWorkflow.QUARANTINE_ORDER_CASE, "Quarantine.docx"); + contactEmailTemplate = createDocumentTemplate(DocumentWorkflow.CONTACT_EMAIL, "ContactEmail.txt"); } @BeforeEach @@ -165,21 +175,28 @@ public void setup() throws URISyntaxException { public void testGetAvailableTemplates() throws DocumentTemplateException { loginWith(admin); - getDocumentTemplateFacade() - .writeDocumentTemplate(DocumentWorkflow.CASE_EMAIL, "CaseEmailMock.txt", "#Subject\nContent".getBytes(StandardCharsets.UTF_8)); - getDocumentTemplateFacade() - .writeDocumentTemplate(DocumentWorkflow.CONTACT_EMAIL, "ContactEmailMock.txt", "#Subject\nContent".getBytes(StandardCharsets.UTF_8)); + getDocumentTemplateFacade().saveDocumentTemplate( + DocumentTemplateDto.build(DocumentWorkflow.CASE_EMAIL, "CaseEmailMock.txt"), + "#Subject\nContent".getBytes(StandardCharsets.UTF_8)); + getDocumentTemplateFacade().saveDocumentTemplate( + DocumentTemplateDto.build(DocumentWorkflow.CONTACT_EMAIL, "ContactEmailMock.txt"), + "#Subject\nContent".getBytes(StandardCharsets.UTF_8)); loginWith(userDto); - List templateNames = getExternalEmailFacade().getTemplateNames(DocumentWorkflow.CASE_EMAIL); + List templates = getExternalEmailFacade().getTemplates(DocumentWorkflow.CASE_EMAIL); - assertThat(templateNames.size(), is(2)); + assertThat(templates.size(), is(2)); // should return predefined test template "CaseEmail.txt" and the one just created by the test - assertThat(templateNames, containsInAnyOrder("CaseEmail.txt", "CaseEmailMock.txt")); + assertThat( + templates.stream().map(DocumentTemplateDto::getFileName).collect(Collectors.toList()), + containsInAnyOrder("CaseEmail.txt", "CaseEmailMock.txt")); assertThat( - getExternalEmailFacade().getTemplateNames(DocumentWorkflow.CONTACT_EMAIL), + getExternalEmailFacade().getTemplates(DocumentWorkflow.CONTACT_EMAIL) + .stream() + .map(DocumentTemplateDto::getFileName) + .collect(Collectors.toList()), containsInAnyOrder("ContactEmail.txt", "ContactEmailMock.txt")); } @@ -297,7 +314,7 @@ public void testSendEmailToCasePerson() }).when(emailService).sendEmail(any(), any(), any(), any()); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); getExternalEmailFacade().sendEmail(options); @@ -336,7 +353,7 @@ public void testSendEmailToContactPerson() ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CONTACT_EMAIL, RootEntityType.ROOT_CONTACT, contact.toReference()); - options.setTemplateName("ContactEmail.txt"); + options.setTemplate(toReference(contactEmailTemplate)); options.setRecipientEmail("test@mail.com"); getExternalEmailFacade().sendEmail(options); @@ -397,7 +414,7 @@ public void testSendEmailWithAttachments() }).when(emailService).sendEmail(any(), any(), any(), any()); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); options.setAttachedDocuments(documents.stream().map(DocumentDto::toReference).collect(Collectors.toSet())); @@ -476,7 +493,7 @@ public void testEncryptAttachmentsWithRandomPassword() }).when(smsService).sendSms(any(), any()); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); options.setAttachedDocuments(documents.stream().map(DocumentDto::toReference).collect(Collectors.toSet())); @@ -497,7 +514,7 @@ public void testSendEmailWithUnsupportedAttachment() throws MessagingException, createDocument("SomeDocument.txt", DocumentRelatedEntityType.CASE, caze.getUuid(), "Some content".getBytes(StandardCharsets.UTF_8)); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); options.setAttachedDocuments(Collections.singleton(document.toReference())); @@ -518,7 +535,7 @@ public void testSendAttachmentWithUnavailablePassword() throws MessagingExceptio createDocument("SomeDocument.txt", DocumentRelatedEntityType.CASE, caze.getUuid(), "Some content".getBytes(StandardCharsets.UTF_8)); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); options.setAttachedDocuments(Collections.singleton(document.toReference())); @@ -541,7 +558,7 @@ public void testSendAttachmentNotRelatedToEntity() throws MessagingException, IO createDocument("SomeDocument.txt", DocumentRelatedEntityType.CONTACT, "mock-uuid", "Some content".getBytes(StandardCharsets.UTF_8)); ExternalEmailOptionsDto options = new ExternalEmailOptionsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE, caze.toReference()); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); options.setRecipientEmail("test@mail.com"); options.setAttachedDocuments(Collections.singleton(document.toReference())); @@ -613,7 +630,7 @@ public void testSendBulkEmailToCasePerson() throws MessagingException, IOExcepti ExternalEmailOptionsWithAttachmentsDto options = new ExternalEmailOptionsWithAttachmentsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); DocumentDto documentDto = DocumentDto.build(); documentDto.setUploadingUser(admin.toReference()); @@ -702,10 +719,10 @@ public void testSendBulkEmailToCasePersonAttachmentsAndTemplateDocument() throws ExternalEmailOptionsWithAttachmentsDto options = new ExternalEmailOptionsWithAttachmentsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); QuarantineOrderDocumentOptionsDto quarantineOrderDocumentOptions = new QuarantineOrderDocumentOptionsDto(); - quarantineOrderDocumentOptions.setTemplateFile("Quarantine.docx"); + quarantineOrderDocumentOptions.setTemplate(toReference(quarantineOrderTemplate)); quarantineOrderDocumentOptions.setExtraProperties(new Properties()); quarantineOrderDocumentOptions.setShouldUploadGeneratedDoc(false); quarantineOrderDocumentOptions.setDocumentWorkflow(DocumentWorkflow.QUARANTINE_ORDER_CASE); @@ -799,9 +816,9 @@ public void testSendBulkEmailToCasePersonTemplateDocument() throws MessagingExce ExternalEmailOptionsWithAttachmentsDto options = new ExternalEmailOptionsWithAttachmentsDto(DocumentWorkflow.CASE_EMAIL, RootEntityType.ROOT_CASE); - options.setTemplateName("CaseEmail.txt"); + options.setTemplate(toReference(caseEmailTemplate)); QuarantineOrderDocumentOptionsDto quarantineOrderDocumentOptions = new QuarantineOrderDocumentOptionsDto(); - quarantineOrderDocumentOptions.setTemplateFile("Quarantine.docx"); + quarantineOrderDocumentOptions.setTemplate(toReference(quarantineOrderTemplate)); quarantineOrderDocumentOptions.setExtraProperties(new Properties()); quarantineOrderDocumentOptions.setShouldUploadGeneratedDoc(true); quarantineOrderDocumentOptions.setDocumentWorkflow(DocumentWorkflow.QUARANTINE_ORDER_CASE); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjbTest.java index 3529521a1da..b4847774593 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/ExternalMessageFacadeEjbTest.java @@ -306,10 +306,14 @@ public void testDiseaseVariantDeterminationOnSave() { diseaseVariant2.setValue(diseaseVariantEnumValue2.getValue()); Mockito - .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, diseaseVariant.getValue())) + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, diseaseVariant.getValue())) .thenReturn(diseaseVariant); Mockito - .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, diseaseVariant2.getValue())) + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, diseaseVariant2.getValue())) .thenReturn(diseaseVariant2); ExternalMessageDto labMessage = diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java index 0a0ba4d7f90..85da716cf6f 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.CaseCriteria; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.externalmessage.ExternalMessageDto; import de.symeda.sormas.api.externalmessage.ExternalMessageStatus; @@ -40,11 +41,13 @@ import de.symeda.sormas.api.externalmessage.processing.ExternalMessageProcessingResult; import de.symeda.sormas.api.infrastructure.facility.FacilityDto; import de.symeda.sormas.api.infrastructure.facility.FacilityType; +import de.symeda.sormas.api.person.PersonCriteria; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.sample.PathogenTestDto; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; +import de.symeda.sormas.api.sample.SampleCriteria; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SamplePurpose; @@ -212,6 +215,42 @@ public void testProcessWithExistingPersonAndCase() throws ExecutionException, In assertThat(samples, hasSize(2)); } + /** + * External message with sample date in the threshold period should generate a new sample to the existing case + * @throws ExecutionException + * @throws InterruptedException + */ + @Test + public void testThresholdAgainstSampleDate() throws ExecutionException, InterruptedException { + ExternalMessageDto externalMessage = createExternalMessage(e -> { + e.getSampleReports().get(0).setSampleDateTime(DateHelper.subtractDays(new Date(), 10)); + }); + + PersonDto person = + creator.createPerson(externalMessage.getPersonFirstName(), externalMessage.getPersonLastName(), externalMessage.getPersonSex(), p -> { + p.setNationalHealthId(externalMessage.getPersonNationalHealthId()); + }); + + CaseDataDto caze = creator.createCase(reportingUser.toReference(), person.toReference(), rdcf, c -> { + c.setDisease(externalMessage.getDisease()); + c.setReportDate(DateHelper.subtractDays(new Date(), 15)); + }); + creator.createSample(caze.toReference(), reportingUser.toReference(), rdcf.facility, s -> { + s.setSampleDateTime(DateHelper.subtractDays(new Date(), 15)); + }); + + // set the threshold + creator.updateDiseaseConfiguration(externalMessage.getDisease(), true, true, true, true, null, 10); + getBean(DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal.class).loadData(); + + ProcessingResult result = runFlow(externalMessage); + assertThat(result.getStatus(), is(DONE)); + assertThat(externalMessage.getStatus(), is(ExternalMessageStatus.PROCESSED)); + + assertThat(getCaseFacade().count(new CaseCriteria().person(caze.getPerson())), is(1L)); + assertThat(getSampleFacade().count(new SampleCriteria().caze(caze.toReference())), is(2L)); + } + @Test public void testProcessWithExistingPersonAndCaseWithBySampleDate() throws ExecutionException, InterruptedException { ExternalMessageDto externalMessage = createExternalMessage(null); @@ -310,6 +349,29 @@ public void testProcessWithExistingPersonWithSameNationalHealthIdButDifferentDet assertThat(getPathogenTestFacade().getAllActiveUuids(), hasSize(0)); } + @Test + public void testProcessWithExistingPersonWithSameNationalHealthIdAndPersonDetailsNormalizedCheck() + throws ExecutionException, InterruptedException { + ExternalMessageDto externalMessage = createExternalMessage(m -> { + m.setPersonFirstName("john vander"); + m.setPersonLastName("DOÉ"); + m.setPersonCity(" PERSON city \n"); + m.setPersonStreet(" person STREET 12A"); + }); + + creator.createPerson("John Van Der", "Doe", Sex.MALE, p -> { + p.setNationalHealthId(externalMessage.getPersonNationalHealthId()); + p.getAddress().setCity("person city"); + p.getAddress().setStreet("PERSON STREET, 12a"); + }); + + ProcessingResult result = runFlow(externalMessage); + assertThat(result.getStatus(), is(DONE)); + assertThat(externalMessage.getStatus(), is(ExternalMessageStatus.PROCESSED)); + assertThat(getExternalMessageFacade().getByUuid(externalMessage.getUuid()).getStatus(), is(ExternalMessageStatus.PROCESSED)); + assertThat(getPersonFacade().count(new PersonCriteria()), is(1L)); + } + @Test public void testProcessWithExistingSimilarPerson() throws ExecutionException, InterruptedException { ExternalMessageDto externalMessage = createExternalMessage(m -> m.setPersonNationalHealthId(null)); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/importexport/DatabaseExportServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/importexport/DatabaseExportServiceTest.java index afcc4faf9bf..0746186095b 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/importexport/DatabaseExportServiceTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/importexport/DatabaseExportServiceTest.java @@ -23,6 +23,10 @@ import com.tngtech.archunit.core.importer.ClassFileImporter; import de.symeda.sormas.api.importexport.DatabaseTable; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AdverseEvents; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.Aefi; +import de.symeda.sormas.backend.adverseeventsfollowingimmunization.entity.AefiInvestigation; +import de.symeda.sormas.backend.docgeneration.DocumentTemplate; import de.symeda.sormas.backend.environment.Environment; import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSample; import de.symeda.sormas.backend.immunization.entity.DirectoryImmunization; @@ -64,7 +68,11 @@ public void testGetConfigFullyDefined() { FirstVaccinationDate.class, Environment.class, EnvironmentSample.class, - SelfReport.class); + SelfReport.class, + Aefi.class, + AdverseEvents.class, + AefiInvestigation.class, + DocumentTemplate.class); @Test public void test_all_entities_have_export_configuration() { @@ -107,6 +115,10 @@ public void test_all_entities_have_export_configuration() { // remove not exported entities from the list of missing ones NOT_EXPORTED_ENTITIES.forEach(e -> missingEntities.remove(e.getSimpleName())); + //remove aefi join tables + missingJoinTables.remove(Aefi.AEFI_VACCINATIONS_TABLE_NAME); + missingJoinTables.remove(AefiInvestigation.AEFI_INVESTIGATION_VACCINATIONS_TABLE_NAME); + assertThat("Missing export configuration for entities [" + String.join(", ", missingEntities) + "]", missingEntities, hasSize(0)); assertThat( "Export configuration not wanted for entities [" + String.join(", ", exportedButNotWantedEntity) + "]", diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index e825a6d7fd3..39cf2a43e70 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -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()); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/DeleteOldPathogenTestsAndSamplesTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/DeleteOldPathogenTestsAndSamplesTest.java new file mode 100644 index 00000000000..7ef341689c4 --- /dev/null +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/DeleteOldPathogenTestsAndSamplesTest.java @@ -0,0 +1,264 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.sample; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.util.Date; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.CaseDataDto; +import de.symeda.sormas.api.common.DeletionDetails; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.sample.PathogenTestDto; +import de.symeda.sormas.api.sample.PathogenTestResultType; +import de.symeda.sormas.api.sample.PathogenTestType; +import de.symeda.sormas.api.sample.SampleDto; +import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.backend.AbstractBeanTest; +import de.symeda.sormas.backend.MockProducer; +import de.symeda.sormas.backend.TestDataCreator; +import de.symeda.sormas.backend.common.ConfigFacadeEjb; + +public class DeleteOldPathogenTestsAndSamplesTest extends AbstractBeanTest { + + private TestDataCreator.RDCF rdcf; + private UserReferenceDto user; + private CaseDataDto caze; + + final int negativeCovidTestMaxAge = 15; + + @Override + public void init() { + super.init(); + + rdcf = creator.createRDCF(); + user = creator.createUser(rdcf).toReference(); + caze = creator.createCase(user, creator.createPerson().toReference(), rdcf); + + MockProducer.getProperties().setProperty(ConfigFacadeEjb.NEGATIVE_COVID_TESTS_MAX_AGE_DAYS, String.valueOf(negativeCovidTestMaxAge)); + } + + @Test + public void testDeleteOldTestsOnly() { + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + PathogenTestDto oldTest = creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + PathogenTestDto newTest = creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.RAPID_TEST); + s.setTestDateTime(new Date()); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + List sampleTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(sampleTests.size(), is(1)); + assertThat(sampleTests.get(0).getUuid(), is(newTest.getUuid())); + assertThat(getPathogenTestFacade().getByUuid(oldTest.getUuid()).isDeleted(), is(true)); + } + + @Test + public void testDeleteOnlyNegativeTests() { + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setPathogenTestResult(PathogenTestResultType.POSITIVE); + }); + PathogenTestDto positiveTest = creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.POSITIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + List sampleTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(sampleTests.size(), is(1)); + assertThat(sampleTests.get(0).getUuid(), is(positiveTest.getUuid())); + } + + @Test + public void testDeleteSampleIfEmptied() { + + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setSampleDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 5)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + List sampleTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(sampleTests.size(), is(0)); + assertThat(getSampleFacade().getSampleByUuid(sample.getUuid()).isDeleted(), is(true)); + } + + @Test + public void testDeleteSampleWithOldAndDeletedTests() { + + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setSampleDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 5)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + PathogenTestDto deletedTest = creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + getPathogenTestFacade().deletePathogenTest(deletedTest.getUuid(), new DeletionDetails(DeletionReason.DELETION_REQUEST, null)); + + getSampleService().cleanupOldCovidSamples(); + + List sampleTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(sampleTests.size(), is(0)); + assertThat(getSampleFacade().getSampleByUuid(sample.getUuid()).isDeleted(), is(true)); + } + + @Test + public void testCovidTestsOnly() { + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + PathogenTestDto otherDiseaseTest = creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.DENGUE); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + List sampleTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(sampleTests.size(), is(1)); + assertThat(sampleTests.get(0).getUuid(), is(otherDiseaseTest.getUuid())); + } + + @Test + public void testDeletionReferenceDate() { + + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + // old by creation date + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(null); + s.setCreationDate(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + // old by result date + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setCreationDate(new Date()); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + // old by reporting date + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setCreationDate(new Date()); + s.setTestDateTime(null); + s.setReportDate(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + List pathogenTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(getSampleFacade().getSampleByUuid(sample.getUuid()).isDeleted(), is(true)); + } + + @Test + public void testNotConfigured() { + MockProducer.getProperties().remove(ConfigFacadeEjb.NEGATIVE_COVID_TESTS_MAX_AGE_DAYS); + + SampleDto sample = creator.createSample(caze.toReference(), user, rdcf.facility, s -> { + s.setPathogenTestResult(PathogenTestResultType.NEGATIVE); + }); + creator.createPathogenTest(sample.toReference(), user, s -> { + s.setLab(rdcf.facility); + s.setTestedDisease(Disease.CORONAVIRUS); + s.setTestType(PathogenTestType.PCR_RT_PCR); + s.setTestDateTime(DateHelper.subtractDays(new Date(), negativeCovidTestMaxAge + 1)); + s.setTestResult(PathogenTestResultType.NEGATIVE); + }); + + getSampleService().cleanupOldCovidSamples(); + + assertThat(getSampleFacade().getSampleByUuid(sample.getUuid()).isDeleted(), is(false)); + List pathogenTests = getPathogenTestFacade().getAllBySample(sample.toReference()); + assertThat(pathogenTests.size(), is(1)); + } +} diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/selfreport/AbstractSelfReportProcessingFlowTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/selfreport/AbstractSelfReportProcessingFlowTest.java index 208a652ef8d..a73999e8f10 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/selfreport/AbstractSelfReportProcessingFlowTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/selfreport/AbstractSelfReportProcessingFlowTest.java @@ -582,7 +582,9 @@ private SelfReportDto createSelfReport(SelfReportType type) { DiseaseVariant diseaseVariant = creator.createDiseaseVariant("BF.1.2", Disease.CORONAVIRUS); Mockito - .when(MockProducer.getCustomizableEnumFacadeForConverter().getEnumValue(CustomizableEnumType.DISEASE_VARIANT, diseaseVariant.getValue())) + .when( + MockProducer.getCustomizableEnumFacadeForConverter() + .getEnumValue(CustomizableEnumType.DISEASE_VARIANT, Disease.CORONAVIRUS, diseaseVariant.getValue())) .thenReturn(diseaseVariant); selfReport.setDiseaseVariant(diseaseVariant); selfReport.setDiseaseVariantDetails("Variant Details"); diff --git a/sormas-backend/src/test/resources/META-INF/persistence.xml b/sormas-backend/src/test/resources/META-INF/persistence.xml index 3d878a502f2..5182f469a14 100644 --- a/sormas-backend/src/test/resources/META-INF/persistence.xml +++ b/sormas-backend/src/test/resources/META-INF/persistence.xml @@ -89,6 +89,7 @@ de.symeda.sormas.backend.externalmessage.labmessage.SampleReport de.symeda.sormas.backend.specialcaseaccess.SpecialCaseAccess de.symeda.sormas.backend.selfreport.SelfReport + de.symeda.sormas.backend.docgeneration.DocumentTemplate true diff --git a/sormas-backend/src/test/resources/checkHistoryTables.sql b/sormas-backend/src/test/resources/checkHistoryTables.sql index 7d0a5860b3a..9f8056274ef 100644 --- a/sormas-backend/src/test/resources/checkHistoryTables.sql +++ b/sormas-backend/src/test/resources/checkHistoryTables.sql @@ -23,11 +23,11 @@ AND c_hist.column_name IS NULL AND c.table_name NOT IN (SELECT t.table_name FROM information_schema."tables" t WHERE t.table_schema = 'public' AND t.table_name NOT LIKE '%_history' - AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist .table_name) = 0) + AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist.table_name) = 0) UNION SELECT 'no history table' as remark, t.table_name, null as column_name, null as data_type FROM information_schema."tables" t WHERE t.table_schema = 'public' AND t.table_name NOT LIKE '%_history' AND t.table_name NOT IN ('schema_version', 'systemevent') AND t.table_name NOT like 'pg_%' -AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist .table_name) = 0 +AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist.table_name) = 0 UNION SELECT 'missing delete history trigger' as remark, t.table_name, null as column_name, null as data_type FROM information_schema."tables" t WHERE t.table_schema = 'public' diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 90ec7bded5c..54b0dfea876 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT 3.6.3 diff --git a/sormas-base/setup/sormas.properties b/sormas-base/setup/sormas.properties index d5f57df3d3e..cbf7653b9e9 100644 --- a/sormas-base/setup/sormas.properties +++ b/sormas-base/setup/sormas.properties @@ -140,6 +140,10 @@ app.url= # Number of days after which system events are deleted from the database. An example for a system event is the last date at which data from an external service was pulled. # default: 90 #daysAfterSystemEventGetsDeleted=90 +# Number of days after which negative CORONAVIRUS pathogen tests and their samples are soft deleted +# default: not set, meaning no delete +# possible values: any integer representing the number of days +# negativeCovidTestsMaxAgeDays # The similarity threshold after which two names are identified as similar enough to consider them for duplicate detection. # The default value should work for most servers. If you need to change it, please change it carefully as slightly higher or lower values already lead to significant differences. diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 96d5fc57b5d..ddd91e81e6f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 7bc40057f54..b4b5ab67ecb 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 522f79343bb..dc275ddc073 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 7f4271781ae..a1026dd3168 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base diff --git a/sormas-rest/src/main/webapp/WEB-INF/glassfish-web.xml b/sormas-rest/src/main/webapp/WEB-INF/glassfish-web.xml index c78da1af03b..d9f6a362c55 100644 --- a/sormas-rest/src/main/webapp/WEB-INF/glassfish-web.xml +++ b/sormas-rest/src/main/webapp/WEB-INF/glassfish-web.xml @@ -115,6 +115,36 @@ IMMUNIZATION_ARCHIVE
+ + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + + PERSON_VIEW PERSON_VIEW @@ -590,6 +620,11 @@ DASHBOARD_SAMPLES_VIEW + + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + CASE_CLINICIAN_VIEW CASE_CLINICIAN_VIEW diff --git a/sormas-rest/src/main/webapp/WEB-INF/web.xml b/sormas-rest/src/main/webapp/WEB-INF/web.xml index 3decccae6a9..dc2a67e6b83 100644 --- a/sormas-rest/src/main/webapp/WEB-INF/web.xml +++ b/sormas-rest/src/main/webapp/WEB-INF/web.xml @@ -100,6 +100,30 @@ IMMUNIZATION_ARCHIVE + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + + PERSON_VIEW @@ -480,6 +504,10 @@ DASHBOARD_SAMPLES_VIEW + + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + CASE_CLINICIAN_VIEW diff --git a/sormas-serverlibs/pom.xml b/sormas-serverlibs/pom.xml index d620d49979a..e958c99ad63 100644 --- a/sormas-serverlibs/pom.xml +++ b/sormas-serverlibs/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index e44c2105da5..8f035e19788 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/ActivityAsCase/ActivityAsCaseField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/ActivityAsCase/ActivityAsCaseField.java index 95f37cd7415..fbfc08b132e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/ActivityAsCase/ActivityAsCaseField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/ActivityAsCase/ActivityAsCaseField.java @@ -31,6 +31,7 @@ import com.vaadin.v7.ui.Label; import com.vaadin.v7.ui.Table; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.activityascase.ActivityAsCaseDto; import de.symeda.sormas.api.activityascase.ActivityAsCaseType; import de.symeda.sormas.api.event.TypeOfPlace; @@ -80,7 +81,9 @@ protected void updateColumns() { .setVisibleColumns(ACTION_COLUMN_ID, COLUMN_ACTIVITY_AS_CASE_TYPE, COLUMN_TYPE_OF_PLACE, COLUMN_DATE, COLUMN_ADDRESS, COLUMN_DESCRIPTION); table.setCellStyleGenerator( - FieldAccessCellStyleGenerator.withFieldAccessCheckers(ActivityAsCaseDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + ActivityAsCaseDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); for (Object columnId : table.getVisibleColumns()) { if (!columnId.equals(ACTION_COLUMN_ID)) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java index 12b32cf2f3c..1e8db100332 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java @@ -18,6 +18,8 @@ package de.symeda.sormas.ui; import de.symeda.sormas.ui.action.ActionController; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.AefiController; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.AefiInvestigationController; import de.symeda.sormas.ui.campaign.CampaignController; import de.symeda.sormas.ui.caze.CaseController; import de.symeda.sormas.ui.caze.surveillancereport.SurveillanceReportController; @@ -89,6 +91,8 @@ public class ControllerProvider extends BaseControllerProvider { private final DocGenerationController docGenerationController; private final TravelEntryController travelEntryController; private final ImmunizationController immunizationController; + private final AefiController aefiController; + private final AefiInvestigationController aefiInvestigationController; private final VaccinationController vaccinationController; private final ArchivingController archivingController; private final DeleteRestoreController deleteRestoreController; @@ -132,6 +136,8 @@ public ControllerProvider() { docGenerationController = new DocGenerationController(); travelEntryController = new TravelEntryController(); immunizationController = new ImmunizationController(); + aefiController = new AefiController(); + aefiInvestigationController = new AefiInvestigationController(); vaccinationController = new VaccinationController(); archivingController = new ArchivingController(); deleteRestoreController = new DeleteRestoreController(); @@ -264,6 +270,14 @@ public static ImmunizationController getImmunizationController() { return get().immunizationController; } + public static AefiController getAefiController() { + return get().aefiController; + } + + public static AefiInvestigationController getAefiInvestigationController() { + return get().aefiInvestigationController; + } + public static VaccinationController getVaccinationController() { return get().vaccinationController; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java index 890097e8b3b..00ecea96b08 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java @@ -52,6 +52,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.criteria.BaseCriteria; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.AefiView; import de.symeda.sormas.ui.campaign.AbstractCampaignView; import de.symeda.sormas.ui.campaign.campaigndata.CampaignDataView; import de.symeda.sormas.ui.campaign.campaigns.CampaignsView; @@ -69,6 +70,7 @@ import de.symeda.sormas.ui.configuration.outbreak.OutbreaksView; import de.symeda.sormas.ui.contact.ContactsView; import de.symeda.sormas.ui.dashboard.AbstractDashboardView; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.AefiDashboardView; import de.symeda.sormas.ui.dashboard.campaigns.CampaignDashboardView; import de.symeda.sormas.ui.dashboard.contacts.ContactsDashboardView; import de.symeda.sormas.ui.dashboard.sample.SampleDashboardView; @@ -231,6 +233,12 @@ public View getView(String viewName) { AbstractDashboardView.ROOT_VIEW_NAME, I18nProperties.getCaption(Captions.mainMenuDashboard), VaadinIcons.DASHBOARD); + } else if (aefiDashboardPermitted()) { + menu.addView( + AefiDashboardView.class, + AbstractDashboardView.ROOT_VIEW_NAME, + I18nProperties.getCaption(Captions.mainMenuDashboard), + VaadinIcons.DASHBOARD); } if (permitted(FeatureType.TASK_MANAGEMENT, UserRight.TASK_VIEW)) { @@ -299,6 +307,13 @@ public View getView(String viewName) { VaadinIcons.HEALTH_CARD); } + if (permitted(FeatureType.IMMUNIZATION_MANAGEMENT, UserRight.IMMUNIZATION_VIEW) + && !FacadeProvider.getFeatureConfigurationFacade().isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED) + && permitted(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + ControllerProvider.getAefiController().registerViews(navigator); + menu.addView(AefiView.class, AefiView.VIEW_NAME, I18nProperties.getCaption(Captions.mainMenuAdverseEvents), VaadinIcons.BELL_SLASH); + } + if (permitted(FeatureType.TRAVEL_ENTRIES, UserRight.TRAVEL_ENTRY_MANAGEMENT_ACCESS) && FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_GERMANY)) { ControllerProvider.getTravelEntryController().registerViews(navigator); @@ -439,6 +454,12 @@ private static boolean sampleDashboardPermitted() { return permitted(EnumSet.of(FeatureType.DASHBOARD_SAMPLES, FeatureType.SAMPLES_LAB), UserRight.DASHBOARD_SAMPLES_VIEW); } + private static boolean aefiDashboardPermitted() { + return permitted( + EnumSet.of(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT), + UserRight.DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW); + } + private static Set initKnownViews() { final Set views = new HashSet<>( Arrays.asList( @@ -468,7 +489,8 @@ private static Set initKnownViews() { CountriesView.VIEW_NAME, ExternalMessagesView.VIEW_NAME, TravelEntriesView.VIEW_NAME, - ImmunizationsView.VIEW_NAME)); + ImmunizationsView.VIEW_NAME, + AefiView.VIEW_NAME)); if (surveillanceDashboardPermitted()) { views.add(SurveillanceDashboardView.VIEW_NAME); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/action/ActionEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/action/ActionEditForm.java index e1b6811807d..69a354b2339 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/action/ActionEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/action/ActionEditForm.java @@ -41,6 +41,7 @@ import de.symeda.sormas.ui.utils.DateTimeField; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; +import de.symeda.sormas.ui.utils.VaadinUiUtil; public class ActionEditForm extends AbstractEditForm { @@ -100,8 +101,11 @@ protected void addFields() { TextField title = addField(ActionDto.TITLE, TextField.class); title.addStyleName(SOFT_REQUIRED); RichTextArea description = addField(ActionDto.DESCRIPTION, RichTextArea.class); + description.setNullRepresentation(""); description.setImmediate(true); + VaadinUiUtil.addGdprMessageOnClick(description); + RichTextArea reply = addField(ActionDto.REPLY, RichTextArea.class); reply.setNullRepresentation(""); reply.setImmediate(true); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiDataView.java new file mode 100644 index 00000000000..d021b2ac3b0 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiDataView.java @@ -0,0 +1,113 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; + +import de.symeda.sormas.api.EditPermissionFacade; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiReferenceDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SubMenu; +import de.symeda.sormas.ui.immunization.ImmunizationDataView; +import de.symeda.sormas.ui.immunization.ImmunizationPersonView; +import de.symeda.sormas.ui.utils.AbstractEditAllowedDetailView; + +public abstract class AbstractAefiDataView extends AbstractEditAllowedDetailView { + + public static final String ROOT_VIEW_NAME = AefiView.VIEW_NAME; + + protected AbstractAefiDataView(String viewName) { + super(viewName); + } + + @Override + protected AefiReferenceDto getReferenceByUuid(String uuid) { + + final AefiReferenceDto reference; + + boolean isCreateAction = ControllerProvider.getAefiController().isCreateAction(uuid); + + if (isCreateAction) { + reference = new AefiReferenceDto(); + reference.setUuid(DataHelper.createUuid()); + } else { + if (FacadeProvider.getAefiFacade().exists(uuid)) { + reference = FacadeProvider.getAefiFacade().getReferenceByUuid(uuid); + } else { + reference = null; + } + } + return reference; + } + + @Override + protected String getRootViewName() { + return ROOT_VIEW_NAME; + } + + @Override + protected void initView(String params) { + + } + + @Override + protected EditPermissionFacade getEditPermissionFacade() { + return FacadeProvider.getAefiFacade(); + } + + @Override + public void enter(ViewChangeEvent event) { + + super.enter(event); + initOrRedirect(event); + } + + @Override + public void refreshMenu(SubMenu menu, String params) { + + if (!findReferenceByParams(params)) { + return; + } + + boolean isCreateAction = ControllerProvider.getAefiController().isCreateAction(params); + + String immunizationUuid = ""; + if (isCreateAction) { + immunizationUuid = ControllerProvider.getAefiController().getCreateActionImmunizationUuid(params); + } else { + AefiDto aefiDto = FacadeProvider.getAefiFacade().getByUuid(params); + immunizationUuid = aefiDto.getImmunization().getUuid(); + } + + menu.removeAllViews(); + menu.addView(AefiView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiList)); + menu.addView(ImmunizationDataView.VIEW_NAME, I18nProperties.getCaption(ImmunizationDto.I18N_PREFIX), immunizationUuid); + menu.addView( + ImmunizationPersonView.VIEW_NAME, + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, ImmunizationDto.PERSON), + immunizationUuid); + menu.addView(AefiDataView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiDataView), params); + + setMainHeaderComponent( + ControllerProvider.getAefiController().getAefiViewTitleLayout(getReference().getUuid(), immunizationUuid, isCreateAction)); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiInvestigationDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiInvestigationDataView.java new file mode 100644 index 00000000000..3b2ffe2cb7b --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiInvestigationDataView.java @@ -0,0 +1,122 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import com.vaadin.navigator.ViewChangeListener; + +import de.symeda.sormas.api.EditPermissionFacade; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationReferenceDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SubMenu; +import de.symeda.sormas.ui.immunization.ImmunizationDataView; +import de.symeda.sormas.ui.immunization.ImmunizationPersonView; +import de.symeda.sormas.ui.utils.AbstractEditAllowedDetailView; + +public class AbstractAefiInvestigationDataView extends AbstractEditAllowedDetailView { + + public static final String ROOT_VIEW_NAME = AefiInvestigationView.VIEW_NAME; + + protected AbstractAefiInvestigationDataView(String viewName) { + super(viewName); + } + + @Override + protected AefiInvestigationReferenceDto getReferenceByUuid(String uuid) { + + final AefiInvestigationReferenceDto reference; + + boolean isCreateAction = ControllerProvider.getAefiInvestigationController().isCreateAction(uuid); + + if (isCreateAction) { + reference = new AefiInvestigationReferenceDto(); + reference.setUuid(DataHelper.createUuid()); + } else { + if (FacadeProvider.getAefiInvestigationFacade().exists(uuid)) { + reference = FacadeProvider.getAefiInvestigationFacade().getReferenceByUuid(uuid); + } else { + reference = null; + } + } + return reference; + } + + @Override + protected String getRootViewName() { + return ROOT_VIEW_NAME; + } + + @Override + protected void initView(String params) { + + } + + @Override + protected EditPermissionFacade getEditPermissionFacade() { + return FacadeProvider.getAefiInvestigationFacade(); + } + + @Override + public void enter(ViewChangeListener.ViewChangeEvent event) { + + super.enter(event); + initOrRedirect(event); + } + + @Override + public void refreshMenu(SubMenu menu, String params) { + + if (!findReferenceByParams(params)) { + return; + } + + boolean isCreateAction = ControllerProvider.getAefiInvestigationController().isCreateAction(params); + + String aefiReportUuid = ""; + String immunizationUuid = ""; + if (isCreateAction) { + aefiReportUuid = ControllerProvider.getAefiInvestigationController().getCreateActionAefiReportUuid(params); + AefiDto aefiDto = FacadeProvider.getAefiFacade().getByUuid(aefiReportUuid); + immunizationUuid = aefiDto.getImmunization().getUuid(); + } else { + AefiInvestigationDto aefiInvestigationDto = FacadeProvider.getAefiInvestigationFacade().getByUuid(params); + aefiReportUuid = aefiInvestigationDto.getAefiReport().getUuid(); + + AefiDto aefiDto = FacadeProvider.getAefiFacade().getByUuid(aefiReportUuid); + immunizationUuid = aefiDto.getImmunization().getUuid(); + } + + menu.removeAllViews(); + menu.addView(AefiView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiList)); + menu.addView(ImmunizationDataView.VIEW_NAME, I18nProperties.getCaption(ImmunizationDto.I18N_PREFIX), immunizationUuid); + menu.addView( + ImmunizationPersonView.VIEW_NAME, + I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, ImmunizationDto.PERSON), + immunizationUuid); + menu.addView(AefiDataView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiDataView), aefiReportUuid); + menu.addView(AefiInvestigationDataView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiInvestigationDataView), params); + + setMainHeaderComponent( + ControllerProvider.getAefiInvestigationController() + .getAefiInvestigationViewTitleLayout(getReference().getUuid(), aefiReportUuid, immunizationUuid, isCreateAction)); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiView.java new file mode 100644 index 00000000000..66cff5e28c8 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AbstractAefiView.java @@ -0,0 +1,40 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import com.vaadin.ui.Component; + +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.SubMenu; +import de.symeda.sormas.ui.utils.AbstractSubNavigationView; + +public class AbstractAefiView extends AbstractSubNavigationView { + + public static final String ROOT_VIEW_NAME = "adverseevents"; + + protected AbstractAefiView(String viewName) { + super(viewName); + } + + @Override + public void refreshMenu(SubMenu menu, String params) { + menu.removeAllViews(); + + menu.addView(AefiView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiList), params); + menu.addView(AefiInvestigationView.VIEW_NAME, I18nProperties.getCaption(Captions.aefiAefiInvestigationList), params); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiController.java new file mode 100644 index 00000000000..7a6f3ef13fe --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiController.java @@ -0,0 +1,209 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.function.Consumer; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.navigator.Navigator; +import com.vaadin.server.Sizeable; +import com.vaadin.ui.Notification; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.deletionconfiguration.DeletionInfoDto; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines.AefiPrimarySuspectVaccinationSelectionField; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form.AefiDataForm; +import de.symeda.sormas.ui.utils.ArchiveHandlers; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.VaadinUiUtil; +import de.symeda.sormas.ui.utils.components.automaticdeletion.DeletionLabel; +import de.symeda.sormas.ui.utils.components.page.title.RowLayout; +import de.symeda.sormas.ui.utils.components.page.title.TitleLayout; +import de.symeda.sormas.ui.utils.components.page.title.TitleLayoutHelper; + +public class AefiController { + + public void registerViews(Navigator navigator) { + navigator.addView(AefiView.VIEW_NAME, AefiView.class); + navigator.addView(AefiDataView.VIEW_NAME, AefiDataView.class); + navigator.addView(AefiInvestigationView.VIEW_NAME, AefiInvestigationView.class); + navigator.addView(AefiInvestigationDataView.VIEW_NAME, AefiInvestigationDataView.class); + } + + public void selectPrimarySuspectVaccination(AefiDto aefiDto, Consumer commitCallback) { + + AefiPrimarySuspectVaccinationSelectionField selectionField = + new AefiPrimarySuspectVaccinationSelectionField(aefiDto.getVaccinations(), aefiDto.getPrimarySuspectVaccine()); + selectionField.setWidth(1024, Sizeable.Unit.PIXELS); + + final CommitDiscardWrapperComponent component = + new CommitDiscardWrapperComponent<>(selectionField); + component.addCommitListener(() -> { + + VaccinationDto selectedVaccination = selectionField.getValue(); + if (selectedVaccination != null) { + aefiDto.setPrimarySuspectVaccine(selectedVaccination); + + if (commitCallback != null) { + commitCallback.accept(selectedVaccination); + } + } + }); + + selectionField.setSelectionChangeCallback((commitAllowed) -> component.getCommitButton().setEnabled(commitAllowed)); + VaadinUiUtil.showModalPopupWindow(component, I18nProperties.getString(Strings.headingAefiSelectPrimarySuspectVaccine)); + } + + public void navigateToAefi(String uuid) { + navigateToView(AefiDataView.VIEW_NAME, uuid); + } + + public void navigateToView(String viewName, String uuid) { + final String navigationState = viewName + "/" + uuid; + SormasUI.get().getNavigator().navigateTo(navigationState); + } + + public CommitDiscardWrapperComponent getAefiDataEditComponent( + boolean isCreateAction, + AefiDto aefiDto, + Consumer actionCallback) { + + AefiDataForm aefiDataForm = new AefiDataForm(isCreateAction, aefiDto.isPseudonymized(), aefiDto.isInJurisdiction(), actionCallback); + aefiDataForm.setValue(aefiDto); + + CommitDiscardWrapperComponent editComponent = + new CommitDiscardWrapperComponent<>(aefiDataForm, true, aefiDataForm.getFieldGroup()); + + if (!isCreateAction) { + DeletionInfoDto automaticDeletionInfoDto = FacadeProvider.getAefiFacade().getAutomaticDeletionInfo(aefiDto.getUuid()); + DeletionInfoDto manuallyDeletionInfoDto = FacadeProvider.getAefiFacade().getManuallyDeletionInfo(aefiDto.getUuid()); + + editComponent.getButtonsPanel() + .addComponentAsFirst(new DeletionLabel(automaticDeletionInfoDto, manuallyDeletionInfoDto, aefiDto.isDeleted(), AefiDto.I18N_PREFIX)); + + if (aefiDto.isDeleted()) { + editComponent.getWrappedComponent().getField(AefiDto.DELETION_REASON).setVisible(true); + if (editComponent.getWrappedComponent().getField(AefiDto.DELETION_REASON).getValue() == DeletionReason.OTHER_REASON) { + editComponent.getWrappedComponent().getField(AefiDto.OTHER_DELETION_REASON).setVisible(true); + } + } + } + + editComponent.addCommitListener(() -> { + if (!aefiDataForm.getFieldGroup().isModified()) { + AefiDto aefiDataFormValue = aefiDataForm.getValue(); + + AefiDto savedAefiDto = FacadeProvider.getAefiFacade().save(aefiDataFormValue); + Notification.show(I18nProperties.getString(Strings.messageAdverseEventSaved), Notification.Type.WARNING_MESSAGE); + + if (isCreateAction) { + navigateToAefi(savedAefiDto.getUuid()); + } else { + SormasUI.refreshView(); + } + } + }); + + if (!isCreateAction) { + // Initialize 'Delete' button + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE)) { + editComponent.addDeleteWithReasonOrRestoreListener( + AefiView.VIEW_NAME, + null, + I18nProperties.getString(Strings.entityAdverseEvent), + aefiDto.getUuid(), + FacadeProvider.getAefiFacade()); + } + + // Initialize 'Archive' button + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE)) { + ControllerProvider.getArchiveController() + .addArchivingButton(aefiDto, ArchiveHandlers.forAefi(), editComponent, () -> navigateToAefi(aefiDto.getUuid())); + } + + editComponent.restrictEditableComponentsOnEditView( + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT, + null, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE, + FacadeProvider.getAefiFacade().getEditPermissionType(aefiDto.getUuid()), + aefiDto.isInJurisdiction()); + } + + return editComponent; + } + + public TitleLayout getAefiViewTitleLayout(String aefiUuid, String immunizationUuid, boolean isCreateAction) { + + TitleLayout titleLayout = new TitleLayout(); + + if (!isCreateAction) { + AefiDto aefiDto = findAefi(aefiUuid); + immunizationUuid = aefiDto.getImmunization().getUuid(); + + if (aefiDto.getSerious() == YesNoUnknown.YES) { + RowLayout aefiTypeLayout = new RowLayout(); + aefiTypeLayout.addToLayout(AefiType.SERIOUS.toString(), CssStyles.LABEL_CRITICAL); + titleLayout.addRow(aefiTypeLayout); + } else { + titleLayout.addRow(AefiType.NON_SERIOUS.toString()); + } + } + + String shortUuid = DataHelper.getShortUuid(aefiUuid); + ImmunizationDto immunizationDto = FacadeProvider.getImmunizationFacade().getByUuid(immunizationUuid); + PersonDto person = FacadeProvider.getPersonFacade().getByUuid(immunizationDto.getPerson().getUuid()); + StringBuilder mainRowText = TitleLayoutHelper.buildPersonString(person); + + if (!StringUtils.isBlank(shortUuid)) { + mainRowText.append(mainRowText.length() > 0 ? " (" + shortUuid + ")" : shortUuid); + } + + titleLayout.addMainRow(mainRowText.toString()); + + return titleLayout; + } + + private AefiDto findAefi(String uuid) { + return FacadeProvider.getAefiFacade().getByUuid(uuid); + } + + public boolean isCreateAction(String params) { + return StringUtils.startsWith(params, "immunization") && StringUtils.endsWith(params, "create"); + } + + public String getCreateActionImmunizationUuid(String params) { + return StringUtils.contains(params, "/") + ? StringUtils.substringBetween(params, "immunization/", "/adverseevent/create") + : StringUtils.substringBetween(params, "immunization", "adverseeventcreate"); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiDataView.java new file mode 100644 index 00000000000..44444a3b191 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiDataView.java @@ -0,0 +1,139 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.ArrayList; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EditPermissionType; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListCriteria; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.feature.FeatureTypeProperty; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefiinvestigationlink.AefiInvestigationListComponent; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form.AefiDataForm; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information.AefiImmunizationInfo; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information.AefiPersonInfo; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; +import de.symeda.sormas.ui.utils.LayoutWithSidePanel; + +public class AefiDataView extends AbstractAefiDataView { + + public static final String VIEW_NAME = ROOT_VIEW_NAME + "/data"; + + public static final String PERSON_LOC = "personLoc"; + public static final String IMMUNIZATION_LOC = "immunizationLoc"; + public static final String INVESTIGATIONS_LOC = "investigationsLoc"; + + private CommitDiscardWrapperComponent editComponent; + + public AefiDataView() { + super(VIEW_NAME); + } + + @Override + protected String getRootViewName() { + return super.getRootViewName(); + } + + @Override + protected void initView(String params) { + setHeightUndefined(); + + AefiDto aefi; + ImmunizationDto immunization; + + boolean isCreateAction = ControllerProvider.getAefiController().isCreateAction(params); + if (isCreateAction) { + aefi = AefiDto.build(getReference()); + + String immunizationUuid = ControllerProvider.getAefiController().getCreateActionImmunizationUuid(params); + immunization = FacadeProvider.getImmunizationFacade().getByUuid(immunizationUuid); + + aefi.setImmunization(immunization.toReference()); + aefi.setVaccinations(new ArrayList<>(immunization.getVaccinations())); + aefi.setReportingUser(UserProvider.getCurrent().getUserReference()); + } else { + aefi = FacadeProvider.getAefiFacade().getByUuid(getReference().getUuid()); + immunization = FacadeProvider.getImmunizationFacade().getByUuid(aefi.getImmunization().getUuid()); + } + + editComponent = ControllerProvider.getAefiController().getAefiDataEditComponent(isCreateAction, aefi, this::showUnsavedChangesPopup); + + DetailSubComponentWrapper container = new DetailSubComponentWrapper(() -> editComponent); + container.setWidth(100, Unit.PERCENTAGE); + container.setMargin(true); + setSubComponent(container); + container.setEnabled(true); + + LayoutWithSidePanel layout = new LayoutWithSidePanel(editComponent, PERSON_LOC, IMMUNIZATION_LOC, INVESTIGATIONS_LOC); + + container.addComponent(layout); + + UserProvider currentUser = UserProvider.getCurrent(); + if (currentUser.hasAllUserRights(UserRight.PERSON_VIEW)) { + PersonDto personDto = FacadeProvider.getPersonFacade().getByUuid(immunization.getPerson().getUuid()); + Disease disease = immunization.getDisease(); + + AefiPersonInfo aefiPersonInfo = new AefiPersonInfo(personDto, disease); + CssStyles.style(aefiPersonInfo, CssStyles.VIEW_SECTION); + + layout.addSidePanelComponent(aefiPersonInfo, PERSON_LOC); + } + + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.IMMUNIZATION_MANAGEMENT) + && currentUser != null + && currentUser.hasUserRight(UserRight.IMMUNIZATION_VIEW)) { + if (!FacadeProvider.getFeatureConfigurationFacade() + .isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) { + + AefiImmunizationInfo aefiImmunizationInfo = new AefiImmunizationInfo(immunization, (r) -> { + }); + CssStyles.style(aefiImmunizationInfo, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + layout.addSidePanelComponent(aefiImmunizationInfo, IMMUNIZATION_LOC); + } + } + + if (!isCreateAction + && (aefi.getSerious() == YesNoUnknown.YES) + && currentUser.hasAllUserRights(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + + AefiInvestigationListCriteria listCriteria = new AefiInvestigationListCriteria.Builder(getReference()).build(); + AefiInvestigationListComponent aefiInvestigationListComponent = + new AefiInvestigationListComponent(listCriteria, this::showUnsavedChangesPopup, isEditAllowed(), isCreateAction); + CssStyles.style(aefiInvestigationListComponent, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + layout.addSidePanelComponent(aefiInvestigationListComponent, INVESTIGATIONS_LOC); + } + + if (!isCreateAction) { + final String uuid = aefi.getUuid(); + final EditPermissionType aefiEditAllowed = FacadeProvider.getAefiFacade().getEditPermissionType(uuid); + final boolean deleted = FacadeProvider.getAefiFacade().isDeleted(uuid); + layout.disableIfNecessary(deleted, aefiEditAllowed); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationController.java new file mode 100644 index 00000000000..0c44bb7a702 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationController.java @@ -0,0 +1,229 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.function.Consumer; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.navigator.Navigator; +import com.vaadin.server.Sizeable; +import com.vaadin.ui.Notification; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.common.DeletionReason; +import de.symeda.sormas.api.deletionconfiguration.DeletionInfoDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines.AefiPrimarySuspectVaccinationSelectionField; +import de.symeda.sormas.ui.utils.ArchiveHandlers; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.VaadinUiUtil; +import de.symeda.sormas.ui.utils.components.automaticdeletion.DeletionLabel; +import de.symeda.sormas.ui.utils.components.page.title.RowLayout; +import de.symeda.sormas.ui.utils.components.page.title.TitleLayout; +import de.symeda.sormas.ui.utils.components.page.title.TitleLayoutHelper; + +public class AefiInvestigationController { + + public void registerViews(Navigator navigator) { + } + + public void selectPrimarySuspectVaccination(AefiInvestigationDto aefiInvestigationDto, Consumer commitCallback) { + + AefiPrimarySuspectVaccinationSelectionField selectionField = + new AefiPrimarySuspectVaccinationSelectionField(aefiInvestigationDto.getVaccinations(), aefiInvestigationDto.getPrimarySuspectVaccine()); + selectionField.setWidth(1024, Sizeable.Unit.PIXELS); + + final CommitDiscardWrapperComponent component = + new CommitDiscardWrapperComponent<>(selectionField); + component.addCommitListener(() -> { + VaccinationDto selectedVaccination = selectionField.getValue(); + if (selectedVaccination != null) { + aefiInvestigationDto.setPrimarySuspectVaccine(selectedVaccination); + + if (commitCallback != null) { + commitCallback.accept(selectedVaccination); + } + } + }); + + selectionField.setSelectionChangeCallback((commitAllowed) -> component.getCommitButton().setEnabled(commitAllowed)); + VaadinUiUtil.showModalPopupWindow(component, I18nProperties.getString(Strings.headingAefiInvestigationSelectConcernedVaccine)); + } + + public void navigateToAefiInvestigation(String uuid) { + navigateToView(AefiInvestigationDataView.VIEW_NAME, uuid); + } + + public void navigateToView(String viewName, String uuid) { + final String navigationState = viewName + "/" + uuid; + SormasUI.get().getNavigator().navigateTo(navigationState); + } + + public CommitDiscardWrapperComponent getAefiInvestigationDataEditComponent( + boolean isCreateAction, + AefiInvestigationDto aefiInvestigationDto, + Consumer actionCallback) { + + AefiInvestigationDataForm aefiInvestigationDataForm = new AefiInvestigationDataForm( + isCreateAction, + aefiInvestigationDto.isPseudonymized(), + aefiInvestigationDto.isInJurisdiction(), + actionCallback); + aefiInvestigationDataForm.setValue(aefiInvestigationDto); + + CommitDiscardWrapperComponent editComponent = + new CommitDiscardWrapperComponent<>(aefiInvestigationDataForm, true, aefiInvestigationDataForm.getFieldGroup()); + + if (!isCreateAction) { + DeletionInfoDto automaticDeletionInfoDto = + FacadeProvider.getAefiInvestigationFacade().getAutomaticDeletionInfo(aefiInvestigationDto.getUuid()); + DeletionInfoDto manuallyDeletionInfoDto = + FacadeProvider.getAefiInvestigationFacade().getManuallyDeletionInfo(aefiInvestigationDto.getUuid()); + + editComponent.getButtonsPanel() + .addComponentAsFirst( + new DeletionLabel( + automaticDeletionInfoDto, + manuallyDeletionInfoDto, + aefiInvestigationDto.isDeleted(), + AefiInvestigationDto.I18N_PREFIX)); + + if (aefiInvestigationDto.isDeleted()) { + editComponent.getWrappedComponent().getField(AefiInvestigationDto.DELETION_REASON).setVisible(true); + if (editComponent.getWrappedComponent().getField(AefiInvestigationDto.DELETION_REASON).getValue() == DeletionReason.OTHER_REASON) { + editComponent.getWrappedComponent().getField(AefiInvestigationDto.OTHER_DELETION_REASON).setVisible(true); + } + } + } + + editComponent.addCommitListener(() -> { + if (!aefiInvestigationDataForm.getFieldGroup().isModified()) { + AefiInvestigationDto aefiInvestigationDataFormValue = aefiInvestigationDataForm.getValue(); + + AefiInvestigationDto savedAefiInvestigationDto = FacadeProvider.getAefiInvestigationFacade().save(aefiInvestigationDataFormValue); + Notification.show(I18nProperties.getString(Strings.messageAdverseEventInvestigationSaved), Notification.Type.WARNING_MESSAGE); + + if (isCreateAction) { + navigateToAefiInvestigation(savedAefiInvestigationDto.getUuid()); + } else { + SormasUI.refreshView(); + } + } + }); + + if (!isCreateAction) { + // Initialize 'Delete' button + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE)) { + editComponent.addDeleteWithReasonOrRestoreListener( + AefiInvestigationView.VIEW_NAME, + null, + I18nProperties.getString(Strings.entityAdverseEventInvestigation), + aefiInvestigationDto.getUuid(), + FacadeProvider.getAefiInvestigationFacade()); + } + + // Initialize 'Archive' button + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE)) { + ControllerProvider.getArchiveController() + .addArchivingButton( + aefiInvestigationDto, + ArchiveHandlers.forAefiInvestigation(), + editComponent, + () -> navigateToAefiInvestigation(aefiInvestigationDto.getUuid())); + } + + editComponent.restrictEditableComponentsOnEditView( + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT, + null, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE, + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE, + FacadeProvider.getAefiInvestigationFacade().getEditPermissionType(aefiInvestigationDto.getUuid()), + aefiInvestigationDto.isInJurisdiction()); + } + + return editComponent; + } + + public TitleLayout getAefiInvestigationViewTitleLayout( + String aefiInvestigationUuid, + String aefiUuid, + String immunizationUuid, + boolean isCreateAction) { + + TitleLayout titleLayout = new TitleLayout(); + + String investigationStage = ""; + + if (isCreateAction) { + investigationStage = I18nProperties.getCaption(Captions.aefiNewAefiInvestigationStageTitle); + } else { + AefiInvestigationDto aefiInvestigationDto = findAefiInvestigation(aefiInvestigationUuid); + investigationStage = aefiInvestigationDto.getInvestigationStage().toString(); + } + + AefiDto aefiDto = FacadeProvider.getAefiFacade().getByUuid(aefiUuid); + if (aefiDto.getSerious() == YesNoUnknown.YES) { + RowLayout aefiTypeLayout = new RowLayout(); + aefiTypeLayout.addToLayout(investigationStage + ", "); + aefiTypeLayout.addToLayout(AefiType.SERIOUS.toString(), CssStyles.LABEL_CRITICAL); + titleLayout.addRow(aefiTypeLayout); + } else { + titleLayout.addRow(investigationStage + ", " + AefiType.NON_SERIOUS); + } + + String shortUuid = DataHelper.getShortUuid(aefiInvestigationUuid); + ImmunizationDto immunizationDto = FacadeProvider.getImmunizationFacade().getByUuid(immunizationUuid); + PersonDto person = FacadeProvider.getPersonFacade().getByUuid(immunizationDto.getPerson().getUuid()); + StringBuilder mainRowText = TitleLayoutHelper.buildPersonString(person); + + if (!StringUtils.isBlank(shortUuid)) { + mainRowText.append(mainRowText.length() > 0 ? " (" + shortUuid + ")" : shortUuid); + } + titleLayout.addMainRow(mainRowText.toString()); + + return titleLayout; + } + + private AefiInvestigationDto findAefiInvestigation(String uuid) { + return FacadeProvider.getAefiInvestigationFacade().getByUuid(uuid); + } + + public boolean isCreateAction(String params) { + return StringUtils.startsWith(params, "adverseevent") && StringUtils.endsWith(params, "create"); + } + + public String getCreateActionAefiReportUuid(String params) { + return StringUtils.contains(params, "/") + ? StringUtils.substringBetween(params, "adverseevent/", "/investigation/create") + : StringUtils.substringBetween(params, "adverseevent", "investigationcreate"); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataForm.java new file mode 100644 index 00000000000..416e6fba5a4 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataForm.java @@ -0,0 +1,951 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import static de.symeda.sormas.ui.utils.CssStyles.H3; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidColumnLocCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRow; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; +import static de.symeda.sormas.ui.utils.LayoutUtil.locCss; + +import java.util.Arrays; +import java.util.function.Consumer; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Label; +import com.vaadin.v7.data.util.converter.Converter; +import com.vaadin.v7.ui.DateField; +import com.vaadin.v7.ui.OptionGroup; +import com.vaadin.v7.ui.PasswordField; +import com.vaadin.v7.ui.TextArea; +import com.vaadin.v7.ui.TextField; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.DeliveryProcedure; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PatientStatusAtAefiInvestigation; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.PlaceOfVaccination; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeriousAefiInfoSource; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SyringeType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationActivity; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.VaccinationSite; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines.AefiVaccinationsField; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form.FormSectionAccordion; +import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; +import de.symeda.sormas.ui.utils.FieldHelper; +import de.symeda.sormas.ui.utils.NullableOptionGroup; +import de.symeda.sormas.ui.utils.UserField; + +@SuppressWarnings("deprecation") +public class AefiInvestigationDataForm extends AbstractEditForm { + + public static final String FORM_HEADING_LOC = "formHeadingLoc"; + public static final String MAIN_ACCORDION_LOC = "mainAccordionLoc"; + public static final String FOR_INFANTS_HEADING_LOC = "forInfantsHeadingLoc"; + public static final String SOURCE_OF_INFORMATION_HEADING_LOC = "sourceOfInformationHeadingLoc"; + public static final String CLINICAL_DETAILS_OFFICER_HEADING_LOC = "clinicalDetailsOfficerHeadingLoc"; + public static final String SYRINGES_AND_NEEDLES_HEADING_LOC = "syringesAndNeedlesHeadingLoc"; + public static final String RECONSTITUTION_HEADING_LOC = "reconstitutionHeadingLoc"; + public static final String INJECTION_TECHNIQUE_HEADING_LOC = "injectionTechniqueHeadingLoc"; + public static final String VACCINE_STORAGE_POINT_HEADING_LOC = "vaccineStoragePointHeadingLoc"; + public static final String VACCINE_TRANSPORTATION_HEADING_LOC = "vaccineTransportationHeadingLoc"; + public static final String THOSE_AFFECTED_HEADING_LOC = "thoseAffectedHeadingLoc"; + + //@formatter:off + public static final String HTML_LAYOUT = + locCss(CssStyles.VSPACE_3, FORM_HEADING_LOC) + + fluidRowLocs(MAIN_ACCORDION_LOC); + //@formatter:on + + //@formatter:off + public static final String BASIC_DETAILS_HTML_LAYOUT = + fluidRowLocs(4, AefiInvestigationDto.UUID, 4, AefiInvestigationDto.REPORT_DATE, 3, AefiInvestigationDto.REPORTING_USER) + + fluidRowLocs(4, AefiInvestigationDto.RESPONSIBLE_REGION, 4, AefiInvestigationDto.RESPONSIBLE_DISTRICT, 3, AefiInvestigationDto.RESPONSIBLE_COMMUNITY) + + fluidRowLocs(4, AefiInvestigationDto.INVESTIGATION_CASE_ID) + + fluidRowLocs(8, AefiInvestigationDto.PLACE_OF_VACCINATION, 4, AefiInvestigationDto.PLACE_OF_VACCINATION_DETAILS) + + fluidRowLocs(4, AefiInvestigationDto.VACCINATION_ACTIVITY, 4, AefiInvestigationDto.VACCINATION_ACTIVITY_DETAILS) + + fluidRowLocs(AefiInvestigationDto.INVESTIGATION_DATE, AefiInvestigationDto.FORM_COMPLETION_DATE, AefiInvestigationDto.INVESTIGATION_STAGE) + + fluidRowLocs(AefiInvestigationDto.VACCINATIONS) + + fluidRowLocs(8, AefiInvestigationDto.TYPE_OF_SITE, 4, AefiInvestigationDto.TYPE_OF_SITE_DETAILS) + + fluidRowLocs(4, AefiInvestigationDto.KEY_SYMPTOM_DATE_TIME, 3, AefiInvestigationDto.HOSPITALIZATION_DATE, 5, AefiInvestigationDto.REPORTED_TO_HEALTH_AUTHORITY_DATE) + + fluidRowLocs(AefiInvestigationDto.STATUS_ON_DATE_OF_INVESTIGATION) + + fluidRowLocs(4, AefiInvestigationDto.DEATH_DATE_TIME, 3, AefiInvestigationDto.AUTOPSY_DONE, 5, AefiInvestigationDto.AUTOPSY_DATE) + + fluidRowLocs(4, "", 5, AefiInvestigationDto.AUTOPSY_PLANNED_DATE_TIME); + //@formatter:on + + //@formatter:off + public static final String RELEVANT_PATIENT_INFO_HTML_LAYOUT = + fluidRowLocs(8, AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT, 4, AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS, 4, AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD, 4, AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER, 4, AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE, 4, AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION, 4, AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY, 4, AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY_DETAILS) + + loc(FOR_INFANTS_HEADING_LOC) + + fluidRowLocs(8, AefiInvestigationDto.BIRTH_TERM, 4, AefiInvestigationDto.BIRTH_WEIGHT) + + fluidRowLocs(8, AefiInvestigationDto.DELIVERY_PROCEDURE, 4, AefiInvestigationDto.DELIVERY_PROCEDURE_DETAILS); + //@formatter:on + + //@formatter:off + public static final String FIRST_EXAMINATION_HTML_LAYOUT = + loc(SOURCE_OF_INFORMATION_HEADING_LOC) + + fluidRowLocs(AefiInvestigationDto.SERIOUS_AEFI_INFO_SOURCE) + + fluidRowLocs(AefiInvestigationDto.SERIOUS_AEFI_INFO_SOURCE_DETAILS, AefiInvestigationDto.SERIOUS_AEFI_VERBAL_AUTOPSY_INFO_SOURCE_DETAILS) + + fluidRowLocs(AefiInvestigationDto.FIRST_CAREGIVERS_NAME, AefiInvestigationDto.OTHER_CAREGIVERS_NAMES) + + fluidRowLocs(6, AefiInvestigationDto.OTHER_SOURCES_WHO_PROVIDED_INFO) + + fluidRowLocs(AefiInvestigationDto.SIGNS_AND_SYMPTOMS_FROM_TIME_OF_VACCINATION) + + loc(CLINICAL_DETAILS_OFFICER_HEADING_LOC) + + fluidRowLocs(5, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_NAME, 4, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_PHONE_NUMBER, 3, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_EMAIL) + + fluidRowLocs(5, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_DESIGNATION, 4, AefiInvestigationDto.CLINICAL_DETAILS_DATE_TIME) + + fluidRowLocs(4, AefiInvestigationDto.PATIENT_RECEIVED_MEDICAL_CARE) + + fluidRowLocs(AefiInvestigationDto.PATIENT_RECEIVED_MEDICAL_CARE_DETAILS) + + fluidRowLocs(AefiInvestigationDto.PROVISIONAL_OR_FINAL_DIAGNOSIS); + //@formatter:on + + //@formatter:off + public static final String VACCINES_DETAILS_HTML_LAYOUT = + fluidRowLocs(AefiInvestigationDto.PATIENT_IMMUNIZED_PERIOD) + + fluidRowLocs(AefiInvestigationDto.VACCINE_GIVEN_PERIOD) + + fluidRowCss(CssStyles.VSPACE_TOP_4, + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.ERROR_PRESCRIBING_VACCINE), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.ERROR_PRESCRIBING_VACCINE_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_COULD_HAVE_BEEN_UNSTERILE), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.VACCINE_COULD_HAVE_BEEN_UNSTERILE_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_PHYSICAL_CONDITION_ABNORMAL), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.VACCINE_PHYSICAL_CONDITION_ABNORMAL_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.ERROR_IN_VACCINE_RECONSTITUTION), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.ERROR_IN_VACCINE_RECONSTITUTION_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.ERROR_IN_VACCINE_HANDLING), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.ERROR_IN_VACCINE_HANDLING_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_ADMINISTERED_INCORRECTLY), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.VACCINE_ADMINISTERED_INCORRECTLY_DETAILS) + ) + + fluidRowLocs(8, AefiInvestigationDto.NUMBER_IMMUNIZED_FROM_CONCERNED_VACCINE_VIAL) + + fluidRowLocs(8, AefiInvestigationDto.NUMBER_IMMUNIZED_WITH_CONCERNED_VACCINE_IN_SAME_SESSION) + + fluidRowLocs(12, AefiInvestigationDto.NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_OTHER_LOCATIONS) + + fluidRowLocs(12, AefiInvestigationDto.NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_LOCATION_DETAILS) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_HAS_QUALITY_DEFECT), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.VACCINE_HAS_QUALITY_DEFECT_DETAILS) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION), + fluidColumnLocCss("", 4, 0, AefiInvestigationDto.EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION_DETAILS) + ) + + fluidRowLocs(4, AefiInvestigationDto.CASE_IS_PART_OF_A_CLUSTER, 8, AefiInvestigationDto.CASE_IS_PART_OF_A_CLUSTER_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.NUMBER_OF_CASES_DETECTED_IN_CLUSTER) + + fluidRowLocs(8, AefiInvestigationDto.ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL, 4, AefiInvestigationDto.ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL_DETAILS) + + fluidRowLocs(8, AefiInvestigationDto.NUMBER_OF_VIALS_USED_IN_CLUSTER); + //@formatter:on + + //@formatter:off + public static final String IMMUNIZATION_PRACTICES_HTML_LAYOUT = + loc(SYRINGES_AND_NEEDLES_HEADING_LOC) + + fluidRowLocs(6, AefiInvestigationDto.AD_SYRINGES_USED_FOR_IMMUNIZATION) + + fluidRowLocs(8, AefiInvestigationDto.TYPE_OF_SYRINGES_USED, 4, AefiInvestigationDto.TYPE_OF_SYRINGES_USED_DETAILS) + + fluidRowLocs(AefiInvestigationDto.SYRINGES_USED_ADDITIONAL_DETAILS) + + loc(RECONSTITUTION_HEADING_LOC) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_USED_FOR_MULTIPLE_VIALS_OF_SAME_VACCINE) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_USED_FOR_RECONSTITUTING_DIFFERENT_VACCINES) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINE_VIAL) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINATION) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINES_AND_DILUENTS_USED_RECOMMENDED_BY_MANUFACTURER) + ) + + fluidRowLocs(AefiInvestigationDto.RECONSTITUTION_ADDITIONAL_DETAILS) + + loc(INJECTION_TECHNIQUE_HEADING_LOC) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.CORRECT_DOSE_OR_ROUTE) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.TIME_OF_RECONSTITUTION_MENTIONED_ON_THE_VIAL) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.NON_TOUCH_TECHNIQUE_FOLLOWED) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.CONTRAINDICATION_SCREENED_PRIOR_TO_VACCINATION) + ) + + fluidRowLocs(AefiInvestigationDto.NUMBER_OF_AEFI_REPORTED_FROM_VACCINE_DISTRIBUTION_CENTER_LAST_THIRTY_DAYS) + + fluidRowLocs(4, AefiInvestigationDto.TRAINING_RECEIVED_BY_VACCINATOR, 4, AefiInvestigationDto.LAST_TRAINING_RECEIVED_BY_VACCINATOR_DATE) + + fluidRowLocs(AefiInvestigationDto.INJECTION_TECHNIQUE_ADDITIONAL_DETAILS); + //@formatter:on + + //@formatter:off + public static final String COLD_CHAIN_AND_TRANSPORT_HTML_LAYOUT = + loc(VACCINE_STORAGE_POINT_HEADING_LOC) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_STORAGE_REFRIGERATOR_TEMPERATURE_MONITORED) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.ANY_STORAGE_TEMPERATURE_DEVIATION_OUTSIDE_TWO_TO_EIGHT_DEGREES) + ) + + fluidRowLocs(AefiInvestigationDto.STORAGE_TEMPERATURE_MONITORING_ADDITIONAL_DETAILS) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.CORRECT_PROCEDURE_FOR_STORAGE_FOLLOWED) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.ANY_OTHER_ITEM_IN_REFRIGERATOR) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.PARTIALLY_USED_RECONSTITUTED_VACCINES_IN_REFRIGERATOR) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.UNUSABLE_VACCINES_IN_REFRIGERATOR) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.UNUSABLE_DILUENTS_IN_STORE) + ) + + fluidRowLocs(AefiInvestigationDto.VACCINE_STORAGE_POINT_ADDITIONAL_DETAILS) + + loc(VACCINE_TRANSPORTATION_HEADING_LOC) + + fluidRowLocs(4, AefiInvestigationDto.VACCINE_CARRIER_TYPE) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_CARRIER_SENT_TO_SITE_ON_SAME_DATE_AS_VACCINATION) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.VACCINE_CARRIER_RETURNED_FROM_SITE_ON_SAME_DATE_AS_VACCINATION) + ) + + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.CONDITIONED_ICE_PACK_USED) + ) + + fluidRowLocs(AefiInvestigationDto.VACCINE_TRANSPORTATION_ADDITIONAL_DETAILS); + //@formatter:on + + //@formatter:off + public static final String COMMUNITY_INVESTIGATION_HTML_LAYOUT = + fluidRow( + fluidColumnLocCss(CssStyles.OPTIONGROUP_CAPTION_FLEX, 8, 0, AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY) + ) + + fluidRowLocs(AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS, AefiInvestigationDto.NUMBER_OF_SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY) + + loc(THOSE_AFFECTED_HEADING_LOC) + + fluidRowLocs(AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_VACCINATED, AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_NOT_VACCINATED, AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_VACCINATED_UNKNOWN) + + fluidRowLocs(AefiInvestigationDto.COMMUNITY_INVESTIGATION_ADDITIONAL_DETAILS); + //@formatter:on + + //@formatter:off + public static final String OTHER_FINDINGS_HTML_LAYOUT = + fluidRowLocs(AefiInvestigationDto.OTHER_INVESTIGATION_FINDINGS); + //@formatter:on + + //@formatter:off + public static final String INVESTIGATION_STATUS_HTML_LAYOUT = + fluidRowLocs(4, AefiInvestigationDto.INVESTIGATION_STATUS, 8, AefiInvestigationDto.INVESTIGATION_STATUS_DETAILS) + + fluidRowLocs(AefiInvestigationDto.AEFI_CLASSIFICATION) + + fluidRowLocs(AefiInvestigationDto.AEFI_CLASSIFICATION_DETAILS); + //@formatter:on + + private boolean isCreateAction; + private final Consumer actionCallback; + private TextField responsibleRegion; + private TextField responsibleDistrict; + private TextField responsibleCommunity; + private AefiVaccinationsField vaccinationsField; + + public AefiInvestigationDataForm(boolean isCreateAction, boolean isPseudonymized, boolean inJurisdiction, Consumer actionCallback) { + super( + AefiInvestigationDto.class, + AefiInvestigationDto.I18N_PREFIX, + false, + FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); + + this.isCreateAction = isCreateAction; + this.actionCallback = actionCallback; + + if (isCreateAction) { + hideValidationUntilNextCommit(); + } + + addFields(); + } + + @Override + protected String createHtmlLayout() { + return HTML_LAYOUT; + } + + @Override + protected void addFields() { + + Label formHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiInvestigationFormSubHeading)); + formHeadingLabel.addStyleNames(H3, CssStyles.LABEL_CRITICAL, CssStyles.VSPACE_NONE, CssStyles.VSPACE_TOP_NONE); + getContent().addComponent(formHeadingLabel, FORM_HEADING_LOC); + + FormSectionAccordion accordion = new FormSectionAccordion(); + + //Basic details + CustomLayout basicDetailsLayout = new CustomLayout(); + basicDetailsLayout.setTemplateContents(BASIC_DETAILS_HTML_LAYOUT); + + if (isCreateAction) { + addField(basicDetailsLayout, AefiInvestigationDto.UUID, PasswordField.class); + } else { + addField(basicDetailsLayout, AefiInvestigationDto.UUID); + } + addField(basicDetailsLayout, AefiInvestigationDto.REPORT_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.REPORTING_USER, UserField.class); + + responsibleRegion = new TextField(I18nProperties.getPrefixCaption(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.RESPONSIBLE_REGION)); + basicDetailsLayout.addComponent(responsibleRegion, AefiInvestigationDto.RESPONSIBLE_REGION); + responsibleDistrict = + new TextField(I18nProperties.getPrefixCaption(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.RESPONSIBLE_DISTRICT)); + basicDetailsLayout.addComponent(responsibleDistrict, AefiInvestigationDto.RESPONSIBLE_DISTRICT); + responsibleCommunity = + new TextField(I18nProperties.getPrefixCaption(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.RESPONSIBLE_COMMUNITY)); + basicDetailsLayout.addComponent(responsibleCommunity, AefiInvestigationDto.RESPONSIBLE_COMMUNITY); + + addField(basicDetailsLayout, AefiInvestigationDto.INVESTIGATION_CASE_ID); + addField(basicDetailsLayout, AefiInvestigationDto.PLACE_OF_VACCINATION, NullableOptionGroup.class); + addField(basicDetailsLayout, AefiInvestigationDto.PLACE_OF_VACCINATION_DETAILS); + addField(basicDetailsLayout, AefiInvestigationDto.VACCINATION_ACTIVITY, NullableOptionGroup.class); + addField(basicDetailsLayout, AefiInvestigationDto.VACCINATION_ACTIVITY_DETAILS); + addField(basicDetailsLayout, AefiInvestigationDto.INVESTIGATION_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.FORM_COMPLETION_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.INVESTIGATION_STAGE, NullableOptionGroup.class); + vaccinationsField = addField(basicDetailsLayout, AefiInvestigationDto.VACCINATIONS, AefiVaccinationsField.class); + addField(basicDetailsLayout, AefiInvestigationDto.TYPE_OF_SITE, NullableOptionGroup.class); + addField(basicDetailsLayout, AefiInvestigationDto.TYPE_OF_SITE_DETAILS); + addField(basicDetailsLayout, AefiInvestigationDto.KEY_SYMPTOM_DATE_TIME, DateTimeField.class); + addField(basicDetailsLayout, AefiInvestigationDto.HOSPITALIZATION_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.REPORTED_TO_HEALTH_AUTHORITY_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.STATUS_ON_DATE_OF_INVESTIGATION, NullableOptionGroup.class); + addField(basicDetailsLayout, AefiInvestigationDto.DEATH_DATE_TIME, DateTimeField.class); + addField(basicDetailsLayout, AefiInvestigationDto.AUTOPSY_DONE, NullableOptionGroup.class); + addField(basicDetailsLayout, AefiInvestigationDto.AUTOPSY_DATE, DateField.class); + addField(basicDetailsLayout, AefiInvestigationDto.AUTOPSY_PLANNED_DATE_TIME, DateTimeField.class); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationBasicDetails, true, basicDetailsLayout); + + CustomLayout relevantPatientInformationLayout = new CustomLayout(); + relevantPatientInformationLayout.setTemplateContents(RELEVANT_PATIENT_INFO_HTML_LAYOUT); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT); + TextField pastHistoryOfSimilarEventDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT_DETAILS); + pastHistoryOfSimilarEventDetails.setCaption(null); + pastHistoryOfSimilarEventDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS); + TextField adverseEventAfterPreviousVaccinationsDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS_DETAILS); + adverseEventAfterPreviousVaccinationsDetails.setCaption(null); + adverseEventAfterPreviousVaccinationsDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD); + TextField historyOfAllergyDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD_DETAILS); + historyOfAllergyDetails.setCaption(null); + historyOfAllergyDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER); + TextField preExistingIllnessDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER_DETAILS); + preExistingIllnessDetails.setCaption(null); + preExistingIllnessDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE); + TextField historyOfHospitalizationDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE_DETAILS); + historyOfHospitalizationDetails.setCaption(null); + historyOfHospitalizationDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION); + TextField currentlyOnConcomitantMedicationDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION_DETAILS); + currentlyOnConcomitantMedicationDetails.setCaption(null); + currentlyOnConcomitantMedicationDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY); + TextField familyHistoryOfDiseaseDetails = + addField(relevantPatientInformationLayout, AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY_DETAILS); + familyHistoryOfDiseaseDetails.setCaption(null); + familyHistoryOfDiseaseDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + Label forInfantsLabel = new Label(I18nProperties.getCaption(Captions.aefiInvestigationForInfants)); + forInfantsLabel.addStyleName(CssStyles.H4); + relevantPatientInformationLayout.addComponent(forInfantsLabel, FOR_INFANTS_HEADING_LOC); + + addField(relevantPatientInformationLayout, AefiInvestigationDto.BIRTH_TERM, NullableOptionGroup.class); + addField(relevantPatientInformationLayout, AefiInvestigationDto.BIRTH_WEIGHT); + addField(relevantPatientInformationLayout, AefiInvestigationDto.DELIVERY_PROCEDURE, NullableOptionGroup.class); + addField(relevantPatientInformationLayout, AefiInvestigationDto.DELIVERY_PROCEDURE_DETAILS); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationRelevantPatientInformation, false, relevantPatientInformationLayout); + + //First examination + CustomLayout firstExaminationDetailsLayout = new CustomLayout(); + firstExaminationDetailsLayout.setTemplateContents(FIRST_EXAMINATION_HTML_LAYOUT); + + Label sourceOfInformationLabel = new Label(I18nProperties.getCaption(Captions.aefiInvestigationSourceOfInformation)); + sourceOfInformationLabel.addStyleName(CssStyles.H4); + firstExaminationDetailsLayout.addComponent(sourceOfInformationLabel, SOURCE_OF_INFORMATION_HEADING_LOC); + + OptionGroup seriousAefiSourcesOfInformation = + addField(firstExaminationDetailsLayout, AefiInvestigationDto.SERIOUS_AEFI_INFO_SOURCE, OptionGroup.class); + CssStyles.style(seriousAefiSourcesOfInformation, CssStyles.OPTIONGROUP_CHECKBOXES_HORIZONTAL); + seriousAefiSourcesOfInformation.setMultiSelect(true); + seriousAefiSourcesOfInformation.addItems((Object[]) SeriousAefiInfoSource.values()); + seriousAefiSourcesOfInformation.setCaption(null); + + addField(firstExaminationDetailsLayout, AefiInvestigationDto.SERIOUS_AEFI_INFO_SOURCE_DETAILS); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.SERIOUS_AEFI_VERBAL_AUTOPSY_INFO_SOURCE_DETAILS); + + addField(firstExaminationDetailsLayout, AefiInvestigationDto.FIRST_CAREGIVERS_NAME); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.OTHER_CAREGIVERS_NAMES); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.OTHER_SOURCES_WHO_PROVIDED_INFO); + + TextArea signsAndSymptomsFromTimeOfVaccination = + addField(firstExaminationDetailsLayout, AefiInvestigationDto.SIGNS_AND_SYMPTOMS_FROM_TIME_OF_VACCINATION, TextArea.class); + signsAndSymptomsFromTimeOfVaccination.setRows(6); + signsAndSymptomsFromTimeOfVaccination.setDescription( + I18nProperties + .getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.SIGNS_AND_SYMPTOMS_FROM_TIME_OF_VACCINATION, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + Label clinicalDetailsOfficerLabel = new Label(I18nProperties.getCaption(Captions.aefiInvestigationClinicalDetailsOfficer)); + clinicalDetailsOfficerLabel.addStyleName(CssStyles.H4); + firstExaminationDetailsLayout.addComponent(clinicalDetailsOfficerLabel, CLINICAL_DETAILS_OFFICER_HEADING_LOC); + + addField(firstExaminationDetailsLayout, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_NAME); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_PHONE_NUMBER); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_EMAIL); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.CLINICAL_DETAILS_OFFICER_DESIGNATION); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.CLINICAL_DETAILS_DATE_TIME, DateTimeField.class); + addField(firstExaminationDetailsLayout, AefiInvestigationDto.PATIENT_RECEIVED_MEDICAL_CARE, NullableOptionGroup.class); + + TextArea patientReceivedMedicalCareDetails = + addField(firstExaminationDetailsLayout, AefiInvestigationDto.PATIENT_RECEIVED_MEDICAL_CARE_DETAILS, TextArea.class); + patientReceivedMedicalCareDetails.setRows(6); + patientReceivedMedicalCareDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.PATIENT_RECEIVED_MEDICAL_CARE_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + TextArea provisionalOrFinalDiagnosis = + addField(firstExaminationDetailsLayout, AefiInvestigationDto.PROVISIONAL_OR_FINAL_DIAGNOSIS, TextArea.class); + provisionalOrFinalDiagnosis.setRows(6); + provisionalOrFinalDiagnosis.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.PROVISIONAL_OR_FINAL_DIAGNOSIS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationFirstExaminationDetails, false, firstExaminationDetailsLayout); + + //Vaccines details + CustomLayout vaccinesDetailsLayout = new CustomLayout(); + vaccinesDetailsLayout.setTemplateContents(VACCINES_DETAILS_HTML_LAYOUT); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.PATIENT_IMMUNIZED_PERIOD, NullableOptionGroup.class); + /* + * TextField patientImmunizedPeriodDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.PATIENT_IMMUNIZED_PERIOD_DETAILS); + * patientImmunizedPeriodDetails.setCaption(null); + * patientImmunizedPeriodDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + */ + + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_GIVEN_PERIOD, NullableOptionGroup.class); + /* + * TextField vaccineGivenPeriodDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_GIVEN_PERIOD_DETAILS); + * vaccineGivenPeriodDetails.setCaption(null); + * vaccineGivenPeriodDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + */ + + addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_PRESCRIBING_VACCINE); + TextField errorPrescribingVaccineDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_PRESCRIBING_VACCINE_DETAILS); + errorPrescribingVaccineDetails.setCaption(null); + errorPrescribingVaccineDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_COULD_HAVE_BEEN_UNSTERILE); + TextField vaccineCouldBeUnsterileDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_COULD_HAVE_BEEN_UNSTERILE_DETAILS); + vaccineCouldBeUnsterileDetails.setCaption(null); + vaccineCouldBeUnsterileDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_PHYSICAL_CONDITION_ABNORMAL); + TextField vaccinePhysicalConditionAbnormalDetails = + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_PHYSICAL_CONDITION_ABNORMAL_DETAILS); + vaccinePhysicalConditionAbnormalDetails.setCaption(null); + vaccinePhysicalConditionAbnormalDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_IN_VACCINE_RECONSTITUTION); + TextField errorInVaccineReconstitutionAbnormalDetails = + addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_IN_VACCINE_RECONSTITUTION_DETAILS); + errorInVaccineReconstitutionAbnormalDetails.setCaption(null); + errorInVaccineReconstitutionAbnormalDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_IN_VACCINE_HANDLING); + TextField errorInVaccineHandlingDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.ERROR_IN_VACCINE_HANDLING_DETAILS); + errorInVaccineHandlingDetails.setCaption(null); + errorInVaccineHandlingDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_ADMINISTERED_INCORRECTLY); + TextField vaccineAdministeredIncorrectlyDetails = + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_ADMINISTERED_INCORRECTLY_DETAILS); + vaccineAdministeredIncorrectlyDetails.setCaption(null); + vaccineAdministeredIncorrectlyDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + TextField numberImmunizedFromConcernedVaccineVial = + addField(vaccinesDetailsLayout, AefiInvestigationDto.NUMBER_IMMUNIZED_FROM_CONCERNED_VACCINE_VIAL, TextField.class); + numberImmunizedFromConcernedVaccineVial.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberImmunizedFromConcernedVaccineVial.getCaption())); + + TextField numberImmunizedFromConcernedVaccineInSameSession = + addField(vaccinesDetailsLayout, AefiInvestigationDto.NUMBER_IMMUNIZED_WITH_CONCERNED_VACCINE_IN_SAME_SESSION, TextField.class); + numberImmunizedFromConcernedVaccineInSameSession.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberImmunizedFromConcernedVaccineInSameSession.getCaption())); + + TextField numberImmunizedFromConcernedVaccineSameBatchNumberOtherLocationsSession = addField( + vaccinesDetailsLayout, + AefiInvestigationDto.NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_OTHER_LOCATIONS, + TextField.class); + numberImmunizedFromConcernedVaccineSameBatchNumberOtherLocationsSession.setConversionError( + I18nProperties.getValidationError( + Validations.onlyIntegerNumbersAllowed, + numberImmunizedFromConcernedVaccineSameBatchNumberOtherLocationsSession.getCaption())); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.NUMBER_IMMUNIZED_CONCERNED_VACCINE_SAME_BATCH_NUMBER_LOCATION_DETAILS); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_HAS_QUALITY_DEFECT); + TextField vaccineHasQualityDefectDetails = addField(vaccinesDetailsLayout, AefiInvestigationDto.VACCINE_HAS_QUALITY_DEFECT_DETAILS); + vaccineHasQualityDefectDetails.setCaption(null); + vaccineHasQualityDefectDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION); + TextField eventIsStressResponseRelatedToImmunizationDetails = + addField(vaccinesDetailsLayout, AefiInvestigationDto.EVENT_IS_A_STRESS_RESPONSE_RELATED_TO_IMMUNIZATION_DETAILS); + eventIsStressResponseRelatedToImmunizationDetails.setCaption(null); + eventIsStressResponseRelatedToImmunizationDetails.setInputPrompt(I18nProperties.getString(Strings.promptRemarks)); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.CASE_IS_PART_OF_A_CLUSTER, NullableOptionGroup.class); + addField(vaccinesDetailsLayout, AefiInvestigationDto.CASE_IS_PART_OF_A_CLUSTER_DETAILS); + + TextField numberOfCasesDetectedInCluster = + addField(vaccinesDetailsLayout, AefiInvestigationDto.NUMBER_OF_CASES_DETECTED_IN_CLUSTER, TextField.class); + numberOfCasesDetectedInCluster.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfCasesDetectedInCluster.getCaption())); + + addField(vaccinesDetailsLayout, AefiInvestigationDto.ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL, NullableOptionGroup.class); + addField(vaccinesDetailsLayout, AefiInvestigationDto.ALL_CASES_IN_CLUSTER_RECEIVED_VACCINE_FROM_SAME_VIAL_DETAILS); + + TextField numberOfVialsUsedInCluster = addField(vaccinesDetailsLayout, AefiInvestigationDto.NUMBER_OF_VIALS_USED_IN_CLUSTER, TextField.class); + numberOfVialsUsedInCluster + .setConversionError(I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfVialsUsedInCluster.getCaption())); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationVaccinesDetails, false, vaccinesDetailsLayout); + + //Immunization practices + CustomLayout immunizationPracticesLayout = new CustomLayout(); + immunizationPracticesLayout.setTemplateContents(IMMUNIZATION_PRACTICES_HTML_LAYOUT); + + Label syringesAndNeedlesUsedLabel = + new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationImmunizationPracticesSyringesAndNeedlesUsed)); + syringesAndNeedlesUsedLabel.addStyleName(CssStyles.H4); + immunizationPracticesLayout.addComponent(syringesAndNeedlesUsedLabel, SYRINGES_AND_NEEDLES_HEADING_LOC); + + addField(immunizationPracticesLayout, AefiInvestigationDto.AD_SYRINGES_USED_FOR_IMMUNIZATION, NullableOptionGroup.class); + addField(immunizationPracticesLayout, AefiInvestigationDto.TYPE_OF_SYRINGES_USED, NullableOptionGroup.class); + addField(immunizationPracticesLayout, AefiInvestigationDto.TYPE_OF_SYRINGES_USED_DETAILS); + + TextArea syringesUsedAdditionalDetails = + addField(immunizationPracticesLayout, AefiInvestigationDto.SYRINGES_USED_ADDITIONAL_DETAILS, TextArea.class); + syringesUsedAdditionalDetails.setRows(6); + syringesUsedAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.SYRINGES_USED_ADDITIONAL_DETAILS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + Label reconstitutionLabel = new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationImmunizationPracticesReconstitution)); + reconstitutionLabel.addStyleName(CssStyles.H4); + immunizationPracticesLayout.addComponent(reconstitutionLabel, RECONSTITUTION_HEADING_LOC); + + addField(immunizationPracticesLayout, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_USED_FOR_MULTIPLE_VIALS_OF_SAME_VACCINE); + addField(immunizationPracticesLayout, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_USED_FOR_RECONSTITUTING_DIFFERENT_VACCINES); + addField(immunizationPracticesLayout, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINE_VIAL); + addField(immunizationPracticesLayout, AefiInvestigationDto.SAME_RECONSTITUTION_SYRINGE_FOR_EACH_VACCINATION); + addField(immunizationPracticesLayout, AefiInvestigationDto.VACCINES_AND_DILUENTS_USED_RECOMMENDED_BY_MANUFACTURER); + + TextArea reconstitutionAdditionalDetails = + addField(immunizationPracticesLayout, AefiInvestigationDto.RECONSTITUTION_ADDITIONAL_DETAILS, TextArea.class); + reconstitutionAdditionalDetails.setRows(6); + reconstitutionAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.RECONSTITUTION_ADDITIONAL_DETAILS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + Label injectionTechniqueLabel = new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationImmunizationPracticesInjectionTechnique)); + injectionTechniqueLabel.addStyleName(CssStyles.H4); + immunizationPracticesLayout.addComponent(injectionTechniqueLabel, INJECTION_TECHNIQUE_HEADING_LOC); + + addField(immunizationPracticesLayout, AefiInvestigationDto.CORRECT_DOSE_OR_ROUTE); + addField(immunizationPracticesLayout, AefiInvestigationDto.TIME_OF_RECONSTITUTION_MENTIONED_ON_THE_VIAL); + addField(immunizationPracticesLayout, AefiInvestigationDto.NON_TOUCH_TECHNIQUE_FOLLOWED); + addField(immunizationPracticesLayout, AefiInvestigationDto.CONTRAINDICATION_SCREENED_PRIOR_TO_VACCINATION); + + TextField numberOfAefiFromDistributionCenter = addField( + immunizationPracticesLayout, + AefiInvestigationDto.NUMBER_OF_AEFI_REPORTED_FROM_VACCINE_DISTRIBUTION_CENTER_LAST_THIRTY_DAYS, + TextField.class); + numberOfAefiFromDistributionCenter.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfAefiFromDistributionCenter.getCaption())); + + addField(immunizationPracticesLayout, AefiInvestigationDto.TRAINING_RECEIVED_BY_VACCINATOR, NullableOptionGroup.class); + addField(immunizationPracticesLayout, AefiInvestigationDto.LAST_TRAINING_RECEIVED_BY_VACCINATOR_DATE, DateField.class); + + TextArea injectionTechniqueAdditionalDetails = + addField(immunizationPracticesLayout, AefiInvestigationDto.INJECTION_TECHNIQUE_ADDITIONAL_DETAILS, TextArea.class); + injectionTechniqueAdditionalDetails.setRows(6); + injectionTechniqueAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.INJECTION_TECHNIQUE_ADDITIONAL_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationImmunizationPractices, false, immunizationPracticesLayout); + + //Cold chain and transport + CustomLayout coldChainAndTransportLayout = new CustomLayout(); + coldChainAndTransportLayout.setTemplateContents(COLD_CHAIN_AND_TRANSPORT_HTML_LAYOUT); + + Label lastVaccineStoragePointLabel = + new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationColdChainAndTransportLastVaccineStoragePoint)); + lastVaccineStoragePointLabel.addStyleName(CssStyles.H4); + coldChainAndTransportLayout.addComponent(lastVaccineStoragePointLabel, VACCINE_STORAGE_POINT_HEADING_LOC); + + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_STORAGE_REFRIGERATOR_TEMPERATURE_MONITORED); + addField(coldChainAndTransportLayout, AefiInvestigationDto.ANY_STORAGE_TEMPERATURE_DEVIATION_OUTSIDE_TWO_TO_EIGHT_DEGREES); + + TextArea storageTemperatureMonitoringDetails = + addField(coldChainAndTransportLayout, AefiInvestigationDto.STORAGE_TEMPERATURE_MONITORING_ADDITIONAL_DETAILS, TextArea.class); + storageTemperatureMonitoringDetails.setRows(6); + storageTemperatureMonitoringDetails.setDescription( + I18nProperties + .getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.STORAGE_TEMPERATURE_MONITORING_ADDITIONAL_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + addField(coldChainAndTransportLayout, AefiInvestigationDto.CORRECT_PROCEDURE_FOR_STORAGE_FOLLOWED); + addField(coldChainAndTransportLayout, AefiInvestigationDto.ANY_OTHER_ITEM_IN_REFRIGERATOR); + addField(coldChainAndTransportLayout, AefiInvestigationDto.PARTIALLY_USED_RECONSTITUTED_VACCINES_IN_REFRIGERATOR); + addField(coldChainAndTransportLayout, AefiInvestigationDto.UNUSABLE_VACCINES_IN_REFRIGERATOR); + addField(coldChainAndTransportLayout, AefiInvestigationDto.UNUSABLE_DILUENTS_IN_STORE); + + TextArea vaccineStoragePointAdditionalDetails = + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_STORAGE_POINT_ADDITIONAL_DETAILS, TextArea.class); + vaccineStoragePointAdditionalDetails.setRows(6); + vaccineStoragePointAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.VACCINE_STORAGE_POINT_ADDITIONAL_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + Label vaccineTransportationLabel = + new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationColdChainAndTransportVaccineTransportation)); + vaccineTransportationLabel.addStyleName(CssStyles.H4); + coldChainAndTransportLayout.addComponent(vaccineTransportationLabel, VACCINE_TRANSPORTATION_HEADING_LOC); + + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_CARRIER_TYPE, NullableOptionGroup.class); + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_CARRIER_SENT_TO_SITE_ON_SAME_DATE_AS_VACCINATION); + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_CARRIER_RETURNED_FROM_SITE_ON_SAME_DATE_AS_VACCINATION); + addField(coldChainAndTransportLayout, AefiInvestigationDto.CONDITIONED_ICE_PACK_USED); + + TextArea vaccineTransportationAdditionalDetails = + addField(coldChainAndTransportLayout, AefiInvestigationDto.VACCINE_TRANSPORTATION_ADDITIONAL_DETAILS, TextArea.class); + vaccineTransportationAdditionalDetails.setRows(6); + vaccineTransportationAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.VACCINE_TRANSPORTATION_ADDITIONAL_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationColdChainAndTransport, false, coldChainAndTransportLayout); + + //Community investigation + CustomLayout communityInvestigationLayout = new CustomLayout(); + communityInvestigationLayout.setTemplateContents(COMMUNITY_INVESTIGATION_HTML_LAYOUT); + + addField(communityInvestigationLayout, AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY); + + TextArea similarEventsReportedSamePeriodDetails = + addField(communityInvestigationLayout, AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS, TextArea.class); + similarEventsReportedSamePeriodDetails.setRows(6); + similarEventsReportedSamePeriodDetails.setDescription( + I18nProperties.getPrefixDescription( + AefiInvestigationDto.I18N_PREFIX, + AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS, + "") + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + TextField numberOfSimilarEventsReportedInSamePeriod = + addField(communityInvestigationLayout, AefiInvestigationDto.NUMBER_OF_SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY, TextField.class); + numberOfSimilarEventsReportedInSamePeriod.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfSimilarEventsReportedInSamePeriod.getCaption())); + + Label thoseAffectedLabelLabel = new Label(I18nProperties.getCaption(Captions.titleAefiInvestigationCommunityInvestigationThoseAffected)); + thoseAffectedLabelLabel.addStyleName(CssStyles.H4); + communityInvestigationLayout.addComponent(thoseAffectedLabelLabel, THOSE_AFFECTED_HEADING_LOC); + + TextField numberOfThoseAffectedVaccinated = + addField(communityInvestigationLayout, AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_VACCINATED, TextField.class); + numberOfThoseAffectedVaccinated.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfThoseAffectedVaccinated.getCaption())); + + TextField numberOfThoseAffectedNotVaccinated = + addField(communityInvestigationLayout, AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_NOT_VACCINATED, TextField.class); + numberOfThoseAffectedNotVaccinated.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfThoseAffectedNotVaccinated.getCaption())); + + TextField numberOfThoseAffectedVaccinatedUnknown = + addField(communityInvestigationLayout, AefiInvestigationDto.NUMBER_OF_THOSE_AFFECTED_VACCINATED_UNKNOWN, TextField.class); + numberOfThoseAffectedVaccinatedUnknown.setConversionError( + I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, numberOfThoseAffectedVaccinatedUnknown.getCaption())); + + TextArea communityInvestigationAdditionalDetails = + addField(communityInvestigationLayout, AefiInvestigationDto.COMMUNITY_INVESTIGATION_ADDITIONAL_DETAILS, TextArea.class); + communityInvestigationAdditionalDetails.setRows(6); + communityInvestigationAdditionalDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.COMMUNITY_INVESTIGATION_ADDITIONAL_DETAILS, "") + + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationCommunityInvestigation, false, communityInvestigationLayout); + + //Other findings + CustomLayout otherFindingsLayout = new CustomLayout(); + otherFindingsLayout.setTemplateContents(OTHER_FINDINGS_HTML_LAYOUT); + + TextArea otherInvestigationFindingsDetails = addField(otherFindingsLayout, AefiInvestigationDto.OTHER_INVESTIGATION_FINDINGS, TextArea.class); + otherInvestigationFindingsDetails.setRows(6); + otherInvestigationFindingsDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.OTHER_INVESTIGATION_FINDINGS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationOtherFindings, true, otherFindingsLayout); + + //Investigation status + CustomLayout investigationStatusLayout = new CustomLayout(); + investigationStatusLayout.setTemplateContents(INVESTIGATION_STATUS_HTML_LAYOUT); + + addField(investigationStatusLayout, AefiInvestigationDto.INVESTIGATION_STATUS, NullableOptionGroup.class); + addField(investigationStatusLayout, AefiInvestigationDto.INVESTIGATION_STATUS_DETAILS); + addField(investigationStatusLayout, AefiInvestigationDto.AEFI_CLASSIFICATION, NullableOptionGroup.class); + TextArea aefiClassificationDetails = addField(investigationStatusLayout, AefiInvestigationDto.AEFI_CLASSIFICATION_DETAILS, TextArea.class); + aefiClassificationDetails.setRows(6); + aefiClassificationDetails.setDescription( + I18nProperties.getPrefixDescription(AefiInvestigationDto.I18N_PREFIX, AefiInvestigationDto.AEFI_CLASSIFICATION_DETAILS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + accordion.addFormSectionPanel(Captions.titleAefiInvestigationInvestigationStatus, true, investigationStatusLayout); + + getContent().addComponent(accordion, MAIN_ACCORDION_LOC); + + //set visibility, read only and required status + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.PLACE_OF_VACCINATION_DETAILS, + AefiInvestigationDto.PLACE_OF_VACCINATION, + Arrays.asList(PlaceOfVaccination.OTHER), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.VACCINATION_ACTIVITY_DETAILS, + AefiInvestigationDto.VACCINATION_ACTIVITY, + Arrays.asList(VaccinationActivity.OTHER), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.TYPE_OF_SITE_DETAILS, + AefiInvestigationDto.TYPE_OF_SITE, + Arrays.asList(VaccinationSite.OTHER), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + Arrays.asList(AefiInvestigationDto.DEATH_DATE_TIME, AefiInvestigationDto.AUTOPSY_DONE), + AefiInvestigationDto.STATUS_ON_DATE_OF_INVESTIGATION, + Arrays.asList(PatientStatusAtAefiInvestigation.DIED), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.AUTOPSY_DATE, + AefiInvestigationDto.AUTOPSY_DONE, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.AUTOPSY_PLANNED_DATE_TIME, + AefiInvestigationDto.AUTOPSY_DONE, + Arrays.asList(YesNoUnknown.NO), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT_DETAILS, + AefiInvestigationDto.PAST_HISTORY_OF_SIMILAR_EVENT, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS_DETAILS, + AefiInvestigationDto.ADVERSE_EVENT_AFTER_PREVIOUS_VACCINATIONS, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD_DETAILS, + AefiInvestigationDto.HISTORY_OF_ALLERGY_TO_VACCINE_DRUG_OR_FOOD, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER_DETAILS, + AefiInvestigationDto.PRE_EXISTING_ILLNESS_THIRTY_DAYS_OR_CONGENITAL_DISORDER, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE_DETAILS, + AefiInvestigationDto.HISTORY_OF_HOSPITALIZATION_IN_LAST_THIRTY_DAYS_WITH_CAUSE, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION_DETAILS, + AefiInvestigationDto.CURRENTLY_ON_CONCOMITANT_MEDICATION, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY_DETAILS, + AefiInvestigationDto.FAMILY_HISTORY_OF_DISEASE_OR_ALLERGY, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.DELIVERY_PROCEDURE_DETAILS, + AefiInvestigationDto.DELIVERY_PROCEDURE, + Arrays.asList(DeliveryProcedure.WITH_COMPLICATION), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.TYPE_OF_SYRINGES_USED_DETAILS, + AefiInvestigationDto.TYPE_OF_SYRINGES_USED, + Arrays.asList(SyringeType.OTHER), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + AefiInvestigationDto.LAST_TRAINING_RECEIVED_BY_VACCINATOR_DATE, + AefiInvestigationDto.TRAINING_RECEIVED_BY_VACCINATOR, + Arrays.asList(YesNoUnknown.YES), + true); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + Arrays.asList( + AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY_DETAILS, + AefiInvestigationDto.NUMBER_OF_SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY), + AefiInvestigationDto.SIMILAR_EVENTS_REPORTED_SAME_PERIOD_AND_LOCALITY, + Arrays.asList(YesNoUnknown.YES), + true); + + setReadOnly(true, AefiDto.UUID, AefiDto.REPORTING_USER); + + setRequired(true, AefiInvestigationDto.REPORT_DATE, AefiInvestigationDto.INVESTIGATION_CASE_ID); + setRequired(true, AefiInvestigationDto.PLACE_OF_VACCINATION, AefiInvestigationDto.VACCINATION_ACTIVITY); + setRequired( + true, + AefiInvestigationDto.INVESTIGATION_DATE, + AefiInvestigationDto.FORM_COMPLETION_DATE, + AefiInvestigationDto.INVESTIGATION_STAGE); + setRequired(true, AefiInvestigationDto.TYPE_OF_SITE); + setRequired(true, AefiInvestigationDto.KEY_SYMPTOM_DATE_TIME); + setRequired(true, AefiInvestigationDto.STATUS_ON_DATE_OF_INVESTIGATION); + setRequired(true, AefiInvestigationDto.INVESTIGATION_STATUS, AefiInvestigationDto.AEFI_CLASSIFICATION); + } + + @Override + public void attach() { + super.attach(); + + AefiInvestigationDto dataFormValue = getValue(); + + AefiDto aefiDto = FacadeProvider.getAefiFacade().getByUuid(dataFormValue.getAefiReport().getUuid()); + ImmunizationDto immunizationDto = FacadeProvider.getImmunizationFacade().getByUuid(aefiDto.getImmunization().getUuid()); + + responsibleRegion.setValue(immunizationDto.getResponsibleRegion().getCaption()); + responsibleDistrict.setValue(immunizationDto.getResponsibleDistrict().getCaption()); + if (immunizationDto.getResponsibleCommunity() != null) { + responsibleCommunity.setValue(immunizationDto.getResponsibleCommunity().getCaption()); + } + + responsibleRegion.setReadOnly(true); + responsibleDistrict.setReadOnly(true); + responsibleCommunity.setReadOnly(true); + + vaccinationsField.applyAefiInvestigationContext(dataFormValue); + if (dataFormValue.getPrimarySuspectVaccine() != null) { + vaccinationsField.selectPrimarySuspectVaccination(dataFormValue.getPrimarySuspectVaccine()); + } + } + + @Override + public void setValue(AefiInvestigationDto newFieldValue) throws ReadOnlyException, Converter.ConversionException { + super.setValue(newFieldValue); + + getValue(); + + // HACK: Binding to the fields will call field listeners that may clear/modify the values of other fields. + // this hopefully resets everything to its correct value + discard(); + } + + @Override + public void discard() throws SourceException { + super.discard(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataView.java new file mode 100644 index 00000000000..30979b59ca1 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationDataView.java @@ -0,0 +1,132 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.ArrayList; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EditPermissionType; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information.AefiImmunizationInfo; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information.AefiInfo; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information.AefiPersonInfo; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; +import de.symeda.sormas.ui.utils.LayoutWithSidePanel; + +public class AefiInvestigationDataView extends AbstractAefiInvestigationDataView { + + public static final String VIEW_NAME = ROOT_VIEW_NAME + "/data"; + + public static final String ADVERSE_EVENT_LOC = "adverseEventLoc"; + public static final String PERSON_LOC = "personLoc"; + public static final String IMMUNIZATION_LOC = "immunizationLoc"; + + private CommitDiscardWrapperComponent editComponent; + + public AefiInvestigationDataView() { + super(VIEW_NAME); + } + + @Override + protected String getRootViewName() { + return super.getRootViewName(); + } + + @Override + protected void initView(String params) { + setHeightUndefined(); + + AefiInvestigationDto aefiInvestigationDto; + AefiDto aefiReport; + ImmunizationDto immunization; + + boolean isCreateAction = ControllerProvider.getAefiInvestigationController().isCreateAction(params); + if (isCreateAction) { + aefiInvestigationDto = AefiInvestigationDto.build(getReference()); + + String aefiReportUuid = ControllerProvider.getAefiInvestigationController().getCreateActionAefiReportUuid(params); + aefiReport = FacadeProvider.getAefiFacade().getByUuid(aefiReportUuid); + immunization = FacadeProvider.getImmunizationFacade().getByUuid(aefiReport.getImmunization().getUuid()); + + aefiInvestigationDto.setAefiReport(aefiReport.toReference()); + aefiInvestigationDto.setVaccinations(new ArrayList<>(immunization.getVaccinations())); + aefiInvestigationDto.setReportingUser(UserProvider.getCurrent().getUserReference()); + } else { + aefiInvestigationDto = FacadeProvider.getAefiInvestigationFacade().getByUuid(getReference().getUuid()); + aefiReport = FacadeProvider.getAefiFacade().getByUuid(aefiInvestigationDto.getAefiReport().getUuid()); + immunization = FacadeProvider.getImmunizationFacade().getByUuid(aefiReport.getImmunization().getUuid()); + } + + editComponent = ControllerProvider.getAefiInvestigationController() + .getAefiInvestigationDataEditComponent(isCreateAction, aefiInvestigationDto, this::showUnsavedChangesPopup); + + DetailSubComponentWrapper container = new DetailSubComponentWrapper(() -> editComponent); + container.setWidth(100, Unit.PERCENTAGE); + container.setMargin(true); + setSubComponent(container); + container.setEnabled(true); + + LayoutWithSidePanel layout = new LayoutWithSidePanel(editComponent, PERSON_LOC, ADVERSE_EVENT_LOC, IMMUNIZATION_LOC); + + container.addComponent(layout); + + UserProvider currentUser = UserProvider.getCurrent(); + if (currentUser.hasAllUserRights(UserRight.PERSON_VIEW)) { + + PersonDto personDto = FacadeProvider.getPersonFacade().getByUuid(immunization.getPerson().getUuid()); + Disease disease = immunization.getDisease(); + + AefiPersonInfo aefiPersonInfo = new AefiPersonInfo(personDto, disease); + CssStyles.style(aefiPersonInfo, CssStyles.VIEW_SECTION); + + layout.addSidePanelComponent(aefiPersonInfo, PERSON_LOC); + } + + if (currentUser.hasUserRight(UserRight.IMMUNIZATION_VIEW)) { + + AefiImmunizationInfo aefiImmunizationInfo = new AefiImmunizationInfo(immunization, (r) -> { + }); + CssStyles.style(aefiImmunizationInfo, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + layout.addSidePanelComponent(aefiImmunizationInfo, IMMUNIZATION_LOC); + } + + if (currentUser.hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + + AefiInfo aefiInfo = new AefiInfo(aefiReport, (r) -> { + }); + CssStyles.style(aefiInfo, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + layout.addSidePanelComponent(aefiInfo, ADVERSE_EVENT_LOC); + } + + if (!isCreateAction) { + final String uuid = aefiInvestigationDto.getUuid(); + final EditPermissionType aefiInvestigationEditAllowed = FacadeProvider.getAefiInvestigationFacade().getEditPermissionType(uuid); + final boolean deleted = FacadeProvider.getAefiInvestigationFacade().isDeleted(uuid); + layout.disableIfNecessary(deleted, aefiInvestigationEditAllowed); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationView.java new file mode 100644 index 00000000000..5dccd5e14cb --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiInvestigationView.java @@ -0,0 +1,244 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.Collections; +import java.util.Objects; + +import org.vaadin.hene.popupbutton.PopupButton; + +import com.vaadin.icons.VaadinIcons; +import com.vaadin.navigator.ViewChangeListener; +import com.vaadin.server.FileDownloader; +import com.vaadin.server.StreamResource; +import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.MarginInfo; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.ui.ComboBox; + +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.feature.FeatureTypeProperty; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.ViewModelProviders; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory.AefiInvestigationDataLayout; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory.AefiInvestigationFilterFormLayout; +import de.symeda.sormas.ui.utils.ButtonHelper; +import de.symeda.sormas.ui.utils.ComboBoxHelper; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.ExportEntityName; +import de.symeda.sormas.ui.utils.GridExportStreamResource; +import de.symeda.sormas.ui.utils.ViewConfiguration; + +public class AefiInvestigationView extends AbstractAefiView { + + public static final String VIEW_NAME = ROOT_VIEW_NAME + "/investigations"; + + private final AefiInvestigationCriteria criteria; + + private AefiInvestigationFilterFormLayout filterFormLayout; + private final AefiInvestigationDataLayout dataLayout; + + // Filters + private Label relevanceStatusInfoLabel; + private ComboBox relevanceStatusFilter; + private ViewConfiguration viewConfiguration; + + public AefiInvestigationView() { + super(VIEW_NAME); + + CssStyles.style(getViewTitleLabel(), CssStyles.PAGE_TITLE); + + viewConfiguration = ViewModelProviders.of(getClass()).get(ViewConfiguration.class); + + criteria = ViewModelProviders.of(AefiInvestigationView.class).get(AefiInvestigationCriteria.class); + if (criteria.getRelevanceStatus() == null) { + criteria.setRelevanceStatus(EntityRelevanceStatus.ACTIVE); + } + dataLayout = new AefiInvestigationDataLayout(criteria); + + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT)) { + VerticalLayout exportLayout = new VerticalLayout(); + exportLayout.setSpacing(true); + exportLayout.setMargin(true); + exportLayout.addStyleName(CssStyles.LAYOUT_MINIMAL); + exportLayout.setWidth(200, Unit.PIXELS); + + PopupButton exportButton = ButtonHelper.createIconPopupButton(Captions.export, VaadinIcons.DOWNLOAD, exportLayout); + addHeaderComponent(exportButton); + + Button basicExportButton = ButtonHelper.createIconButton(Captions.exportBasic, VaadinIcons.TABLE, null, ValoTheme.BUTTON_PRIMARY); + basicExportButton.setDescription(I18nProperties.getString(Strings.infoBasicExport)); + basicExportButton.setWidth(100, Unit.PERCENTAGE); + exportLayout.addComponent(basicExportButton); + StreamResource streamResource = GridExportStreamResource.createStreamResourceWithSelectedItems( + dataLayout.getGrid(), + () -> viewConfiguration.isInEagerMode() ? dataLayout.getGrid().asMultiSelect().getSelectedItems() : Collections.emptySet(), + ExportEntityName.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_INVESTIGATION); + FileDownloader fileDownloader = new FileDownloader(streamResource); + fileDownloader.extend(basicExportButton); + } + + final VerticalLayout mainLayout = new VerticalLayout(); + mainLayout.addComponent(createFilterBar()); + + final VerticalLayout gridLayout = new VerticalLayout(); + gridLayout.setMargin(false); + gridLayout.setSpacing(false); + gridLayout.setSizeFull(); + //CssStyles.style(gridLayout, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + gridLayout.addComponent(createStatusFilterBar()); + gridLayout.addComponent(dataLayout); + gridLayout.setExpandRatio(dataLayout, 1); + + mainLayout.addComponent(gridLayout); + + mainLayout.setMargin(new MarginInfo(false, true, true, true)); + mainLayout.setSpacing(false); + mainLayout.setSizeFull(); + mainLayout.setExpandRatio(gridLayout, 1); + mainLayout.addStyleNames("crud-main-layout", CssStyles.VSPACE_TOP_4); + + addComponent(mainLayout); + } + + private void updateFilterComponents() { + // TODO replace with Vaadin 8 databinding + applyingCriteria = true; + + if (relevanceStatusFilter != null) { + relevanceStatusFilter.setValue(criteria.getRelevanceStatus()); + } + + filterFormLayout.setValue(criteria); + + applyingCriteria = false; + } + + private AefiInvestigationFilterFormLayout createFilterBar() { + filterFormLayout = new AefiInvestigationFilterFormLayout(); + + filterFormLayout.addResetHandler(clickEvent -> { + ViewModelProviders.of(AefiInvestigationView.class).remove(AefiInvestigationCriteria.class); + navigateTo(null, true); + }); + + filterFormLayout.addApplyHandler(clickEvent -> { + dataLayout.refreshGrid(); + }); + + return filterFormLayout; + } + + public HorizontalLayout createStatusFilterBar() { + HorizontalLayout statusFilterLayout = new HorizontalLayout(); + statusFilterLayout.setSpacing(true); + statusFilterLayout.setMargin(false); + statusFilterLayout.setWidth(100, Unit.PERCENTAGE); + statusFilterLayout.addStyleName(CssStyles.VSPACE_3); + + HorizontalLayout actionButtonsLayout = new HorizontalLayout(); + actionButtonsLayout.setSpacing(true); + + // Show active/archived/all dropdown + if (Objects.nonNull(UserProvider.getCurrent()) + && UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + + if (FacadeProvider.getFeatureConfigurationFacade() + .isFeatureEnabled(FeatureType.AUTOMATIC_ARCHIVING, DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION)) { + + int daysAfterAefiEntryGetsArchived = FacadeProvider.getFeatureConfigurationFacade() + .getProperty( + FeatureType.AUTOMATIC_ARCHIVING, + DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION, + FeatureTypeProperty.THRESHOLD_IN_DAYS, + Integer.class); + if (daysAfterAefiEntryGetsArchived > 0) { + relevanceStatusInfoLabel = new Label( + VaadinIcons.INFO_CIRCLE.getHtml() + " " + + String.format(I18nProperties.getString(Strings.infoArchivedAefiEntries), daysAfterAefiEntryGetsArchived), + ContentMode.HTML); + relevanceStatusInfoLabel.setVisible(false); + relevanceStatusInfoLabel.addStyleName(CssStyles.LABEL_VERTICAL_ALIGN_SUPER); + actionButtonsLayout.addComponent(relevanceStatusInfoLabel); + actionButtonsLayout.setComponentAlignment(relevanceStatusInfoLabel, Alignment.MIDDLE_RIGHT); + } + } + relevanceStatusFilter = ComboBoxHelper.createComboBoxV7(); + relevanceStatusFilter.setId("relevanceStatus"); + relevanceStatusFilter.setWidth(260, Unit.PIXELS); + relevanceStatusFilter.setNullSelectionAllowed(false); + relevanceStatusFilter.setTextInputAllowed(false); + relevanceStatusFilter.addItems((Object[]) EntityRelevanceStatus.values()); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ACTIVE, I18nProperties.getCaption(Captions.aefiActiveInvestigations)); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ARCHIVED, I18nProperties.getCaption(Captions.aefiArchivedInvestigations)); + relevanceStatusFilter.setItemCaption( + EntityRelevanceStatus.ACTIVE_AND_ARCHIVED, + I18nProperties.getCaption(Captions.aefiAllActiveAndArchivedInvestigations)); + relevanceStatusFilter.setCaption(null); + relevanceStatusFilter.addStyleName(CssStyles.VSPACE_NONE); + + if (UserProvider.getCurrent().hasUserRight(UserRight.IMMUNIZATION_DELETE)) { + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.DELETED, I18nProperties.getCaption(Captions.aefiDeletedInvestigations)); + } else { + relevanceStatusFilter.removeItem(EntityRelevanceStatus.DELETED); + } + + relevanceStatusFilter.addValueChangeListener(e -> { + if (relevanceStatusInfoLabel != null) { + relevanceStatusInfoLabel.setVisible(EntityRelevanceStatus.ARCHIVED.equals(e.getProperty().getValue())); + } + criteria.setRelevanceStatus((EntityRelevanceStatus) e.getProperty().getValue()); + navigateTo(criteria); + }); + actionButtonsLayout.addComponent(relevanceStatusFilter); + } + + if (actionButtonsLayout.getComponentCount() > 0) { + statusFilterLayout.addComponent(actionButtonsLayout); + statusFilterLayout.setComponentAlignment(actionButtonsLayout, Alignment.TOP_RIGHT); + statusFilterLayout.setExpandRatio(actionButtonsLayout, 1); + } + + return statusFilterLayout; + } + + @Override + public void enter(ViewChangeListener.ViewChangeEvent event) { + + String params = event.getParameters().trim(); + if (params.startsWith("?")) { + params = params.substring(1); + criteria.fromUrlParams(params); + } + updateFilterComponents(); + + super.enter(event); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiView.java new file mode 100644 index 00000000000..c68ab2828be --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/AefiView.java @@ -0,0 +1,263 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization; + +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.vaadin.hene.popupbutton.PopupButton; + +import com.vaadin.icons.VaadinIcons; +import com.vaadin.navigator.ViewChangeListener; +import com.vaadin.server.FileDownloader; +import com.vaadin.server.StreamResource; +import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.MarginInfo; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.ui.ComboBox; + +import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.common.DeletableEntityType; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.feature.FeatureTypeProperty; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.ViewModelProviders; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory.AefiDataLayout; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory.AefiFilterFormLayout; +import de.symeda.sormas.ui.utils.AefiDownloadUtil; +import de.symeda.sormas.ui.utils.ButtonHelper; +import de.symeda.sormas.ui.utils.ComboBoxHelper; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.ExportEntityName; +import de.symeda.sormas.ui.utils.GridExportStreamResource; +import de.symeda.sormas.ui.utils.ViewConfiguration; + +public class AefiView extends AbstractAefiView { + + public static final String VIEW_NAME = ROOT_VIEW_NAME; + + private final AefiCriteria criteria; + + private AefiFilterFormLayout filterFormLayout; + private final AefiDataLayout dataLayout; + + // Filters + private Label relevanceStatusInfoLabel; + private ComboBox relevanceStatusFilter; + private ViewConfiguration viewConfiguration; + + public AefiView() { + super(VIEW_NAME); + + CssStyles.style(getViewTitleLabel(), CssStyles.PAGE_TITLE); + + viewConfiguration = ViewModelProviders.of(getClass()).get(ViewConfiguration.class); + + criteria = ViewModelProviders.of(AefiView.class).get(AefiCriteria.class); + if (criteria.getRelevanceStatus() == null) { + criteria.setRelevanceStatus(EntityRelevanceStatus.ACTIVE); + } + dataLayout = new AefiDataLayout(criteria); + + if (UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT)) { + VerticalLayout exportLayout = new VerticalLayout(); + exportLayout.setSpacing(true); + exportLayout.setMargin(true); + exportLayout.addStyleName(CssStyles.LAYOUT_MINIMAL); + exportLayout.setWidth(200, Unit.PIXELS); + + PopupButton exportButton = ButtonHelper.createIconPopupButton(Captions.export, VaadinIcons.DOWNLOAD, exportLayout); + addHeaderComponent(exportButton); + + Button basicExportButton = ButtonHelper.createIconButton(Captions.exportBasic, VaadinIcons.TABLE, null, ValoTheme.BUTTON_PRIMARY); + basicExportButton.setDescription(I18nProperties.getString(Strings.infoBasicExport)); + basicExportButton.setWidth(100, Unit.PERCENTAGE); + exportLayout.addComponent(basicExportButton); + StreamResource streamResource = GridExportStreamResource.createStreamResourceWithSelectedItems( + dataLayout.getGrid(), + () -> viewConfiguration.isInEagerMode() ? dataLayout.getGrid().asMultiSelect().getSelectedItems() : Collections.emptySet(), + ExportEntityName.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION); + FileDownloader fileDownloader = new FileDownloader(streamResource); + fileDownloader.extend(basicExportButton); + + StreamResource extendedExportStreamResource = + AefiDownloadUtil.createAefiExportResource(dataLayout.getGrid().getCriteria(), this::getSelectedRowUuids, null); + addExportButton( + extendedExportStreamResource, + exportButton, + exportLayout, + VaadinIcons.FILE_TEXT, + Captions.exportDetailed, + Strings.infoDetailedExport); + } + + final VerticalLayout mainLayout = new VerticalLayout(); + mainLayout.addComponent(createFilterBar()); + + final VerticalLayout gridLayout = new VerticalLayout(); + gridLayout.setMargin(false); + gridLayout.setSpacing(false); + gridLayout.setSizeFull(); + //CssStyles.style(gridLayout, CssStyles.VIEW_SECTION, CssStyles.VSPACE_TOP_3); + + gridLayout.addComponent(createStatusFilterBar()); + gridLayout.addComponent(dataLayout); + gridLayout.setExpandRatio(dataLayout, 1); + + mainLayout.addComponent(gridLayout); + + mainLayout.setMargin(new MarginInfo(false, true, true, true)); + mainLayout.setSpacing(false); + mainLayout.setSizeFull(); + mainLayout.setExpandRatio(gridLayout, 1); + mainLayout.addStyleNames("crud-main-layout", CssStyles.VSPACE_TOP_4); + + addComponent(mainLayout); + } + + private void updateFilterComponents() { + // TODO replace with Vaadin 8 databinding + applyingCriteria = true; + + if (relevanceStatusFilter != null) { + relevanceStatusFilter.setValue(criteria.getRelevanceStatus()); + } + + filterFormLayout.setValue(criteria); + + applyingCriteria = false; + } + + private AefiFilterFormLayout createFilterBar() { + filterFormLayout = new AefiFilterFormLayout(); + + filterFormLayout.addResetHandler(clickEvent -> { + ViewModelProviders.of(AefiView.class).remove(AefiCriteria.class); + navigateTo(null, true); + }); + + filterFormLayout.addApplyHandler(clickEvent -> { + dataLayout.refreshGrid(); + }); + + return filterFormLayout; + } + + public HorizontalLayout createStatusFilterBar() { + HorizontalLayout statusFilterLayout = new HorizontalLayout(); + statusFilterLayout.setSpacing(true); + statusFilterLayout.setMargin(false); + statusFilterLayout.setWidth(100, Unit.PERCENTAGE); + statusFilterLayout.addStyleName(CssStyles.VSPACE_3); + + HorizontalLayout actionButtonsLayout = new HorizontalLayout(); + actionButtonsLayout.setSpacing(true); + + // Show active/archived/all dropdown + if (Objects.nonNull(UserProvider.getCurrent()) + && UserProvider.getCurrent().hasUserRight(UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + + if (FacadeProvider.getFeatureConfigurationFacade() + .isFeatureEnabled(FeatureType.AUTOMATIC_ARCHIVING, DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION)) { + + int daysAfterAefiEntryGetsArchived = FacadeProvider.getFeatureConfigurationFacade() + .getProperty( + FeatureType.AUTOMATIC_ARCHIVING, + DeletableEntityType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION, + FeatureTypeProperty.THRESHOLD_IN_DAYS, + Integer.class); + if (daysAfterAefiEntryGetsArchived > 0) { + relevanceStatusInfoLabel = new Label( + VaadinIcons.INFO_CIRCLE.getHtml() + " " + + String.format(I18nProperties.getString(Strings.infoArchivedAefiEntries), daysAfterAefiEntryGetsArchived), + ContentMode.HTML); + relevanceStatusInfoLabel.setVisible(false); + relevanceStatusInfoLabel.addStyleName(CssStyles.LABEL_VERTICAL_ALIGN_SUPER); + actionButtonsLayout.addComponent(relevanceStatusInfoLabel); + actionButtonsLayout.setComponentAlignment(relevanceStatusInfoLabel, Alignment.MIDDLE_RIGHT); + } + } + relevanceStatusFilter = ComboBoxHelper.createComboBoxV7(); + relevanceStatusFilter.setId("relevanceStatus"); + relevanceStatusFilter.setWidth(260, Unit.PIXELS); + relevanceStatusFilter.setNullSelectionAllowed(false); + relevanceStatusFilter.setTextInputAllowed(false); + relevanceStatusFilter.addItems((Object[]) EntityRelevanceStatus.values()); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ACTIVE, I18nProperties.getCaption(Captions.aefiActiveAdverseEvents)); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ARCHIVED, I18nProperties.getCaption(Captions.aefiArchivedAdverseEvents)); + relevanceStatusFilter + .setItemCaption(EntityRelevanceStatus.ACTIVE_AND_ARCHIVED, I18nProperties.getCaption(Captions.aefiAllActiveAndArchivedAdverseEvents)); + relevanceStatusFilter.setCaption(null); + relevanceStatusFilter.addStyleName(CssStyles.VSPACE_NONE); + + if (UserProvider.getCurrent().hasUserRight(UserRight.IMMUNIZATION_DELETE)) { + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.DELETED, I18nProperties.getCaption(Captions.aefiDeletedAdverseEvents)); + } else { + relevanceStatusFilter.removeItem(EntityRelevanceStatus.DELETED); + } + + relevanceStatusFilter.addValueChangeListener(e -> { + if (relevanceStatusInfoLabel != null) { + relevanceStatusInfoLabel.setVisible(EntityRelevanceStatus.ARCHIVED.equals(e.getProperty().getValue())); + } + criteria.setRelevanceStatus((EntityRelevanceStatus) e.getProperty().getValue()); + navigateTo(criteria); + }); + actionButtonsLayout.addComponent(relevanceStatusFilter); + } + + if (actionButtonsLayout.getComponentCount() > 0) { + statusFilterLayout.addComponent(actionButtonsLayout); + statusFilterLayout.setComponentAlignment(actionButtonsLayout, Alignment.TOP_RIGHT); + statusFilterLayout.setExpandRatio(actionButtonsLayout, 1); + } + + return statusFilterLayout; + } + + private Set getSelectedRowUuids() { + return viewConfiguration.isInEagerMode() + ? dataLayout.getGrid().asMultiSelect().getSelectedItems().stream().map(AefiIndexDto::getUuid).collect(Collectors.toSet()) + : Collections.emptySet(); + } + + @Override + public void enter(ViewChangeListener.ViewChangeEvent event) { + + String params = event.getParameters().trim(); + if (params.startsWith("?")) { + params = params.substring(1); + criteria.fromUrlParams(params); + } + updateFilterComponents(); + + super.enter(event); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationList.java new file mode 100644 index 00000000000..b063ad4f542 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationList.java @@ -0,0 +1,86 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefiinvestigationlink; + +import java.util.List; +import java.util.function.Consumer; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListEntryDto; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.utils.PaginationList; + +@SuppressWarnings("serial") +public class AefiInvestigationList extends PaginationList { + + private static final int MAX_DISPLAYED_ENTRIES = 5; + + private final AefiInvestigationListCriteria listCriteria; + private final Consumer actionCallback; + private final boolean isEditable; + private final Label noInvestigationsLabel; + + public AefiInvestigationList(AefiInvestigationListCriteria listCriteria, Consumer actionCallback, boolean isEditable) { + + super(MAX_DISPLAYED_ENTRIES); + + this.listCriteria = listCriteria; + this.actionCallback = actionCallback; + this.isEditable = isEditable; + + noInvestigationsLabel = new Label(I18nProperties.getString(Strings.infoNoAefiInvestigations)); + } + + @Override + public void reload() { + + List listEntries = + FacadeProvider.getAefiInvestigationFacade().getEntriesList(listCriteria, 0, maxDisplayedEntries * 20); + + setEntries(listEntries); + if (!listEntries.isEmpty()) { + showPage(1); + } else { + listLayout.removeAllComponents(); + updatePaginationLayout(); + listLayout.addComponent(noInvestigationsLabel); + } + } + + @Override + protected void drawDisplayedEntries() { + + List displayedEntries = getDisplayedEntries(); + for (AefiInvestigationListEntryDto listEntryDto : displayedEntries) { + AefiInvestigationListEntry listEntry = new AefiInvestigationListEntry(listEntryDto); + + String aefiInvestigationUuid = listEntryDto.getUuid(); + listEntry.addEditButton( + "edit-aefiinvestigation-" + aefiInvestigationUuid, + (Button.ClickListener) event -> ControllerProvider.getAefiInvestigationController() + .navigateToAefiInvestigation(aefiInvestigationUuid)); + + listEntry.setEnabled(isEditable); + listLayout.addComponent(listEntry); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListComponent.java new file mode 100644 index 00000000000..9faf3780c03 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListComponent.java @@ -0,0 +1,57 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefiinvestigationlink; + +import java.util.function.Consumer; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListCriteria; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; + +@SuppressWarnings("serial") +public class AefiInvestigationListComponent extends SideComponent { + + public AefiInvestigationListComponent( + AefiInvestigationListCriteria listCriteria, + Consumer actionCallback, + boolean isEditAllowed, + boolean isCreateAction) { + super(I18nProperties.getString(Strings.headingAefiReportInvestigations), actionCallback); + + setMargin(false); + setWidth(100, Unit.PERCENTAGE); + + if (isEditAllowed) { + addCreateButton( + I18nProperties.getCaption(Captions.aefiNewAefiInvestigation), + () -> ControllerProvider.getAefiInvestigationController() + .navigateToAefiInvestigation("adverseevent/" + listCriteria.getAefiReport().getUuid() + "/investigation/create"), + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE); + + if (isCreateAction) { + createButton.setEnabled(false); + } + } + + AefiInvestigationList aefiInvestigationList = new AefiInvestigationList(listCriteria, actionCallback, isEditAllowed); + addComponent(aefiInvestigationList); + aefiInvestigationList.reload(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListEntry.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListEntry.java new file mode 100644 index 00000000000..74e571ef1cd --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefiinvestigationlink/AefiInvestigationListEntry.java @@ -0,0 +1,76 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefiinvestigationlink; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.Label; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationListEntryDto; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentField; + +@SuppressWarnings("serial") +public class AefiInvestigationListEntry extends SideComponentField { + + public static final String SEPARATOR = ": "; + + private final AefiInvestigationListEntryDto listEntry; + + public AefiInvestigationListEntry(AefiInvestigationListEntryDto listEntry) { + + this.listEntry = listEntry; + + if (!StringUtils.isBlank(listEntry.getInvestigationCaseId())) { + Label labelCaseId = new Label(listEntry.getInvestigationCaseId()); + CssStyles.style(labelCaseId, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelCaseId); + } + + Label labelInvestigationDate = new Label( + I18nProperties.getPrefixCaption(AefiInvestigationListEntryDto.I18N_PREFIX, AefiInvestigationListEntryDto.INVESTIGATION_DATE) + + SEPARATOR + + DateFormatHelper.formatLocalDate(listEntry.getInvestigationDate())); + addComponentToField(labelInvestigationDate); + + Label labelInvestigationStage = new Label( + I18nProperties.getPrefixCaption(AefiInvestigationListEntryDto.I18N_PREFIX, AefiInvestigationListEntryDto.INVESTIGATION_STAGE) + + SEPARATOR + + listEntry.getInvestigationStage()); + CssStyles.style(labelInvestigationStage, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelInvestigationStage); + + Label labelStatusOnInvestigation = new Label( + I18nProperties.getPrefixCaption(AefiInvestigationListEntryDto.I18N_PREFIX, AefiInvestigationListEntryDto.STATUS_ON_DATE_OF_INVESTIGATION) + + SEPARATOR + + listEntry.getStatusOnDateOfInvestigation()); + CssStyles.style(labelStatusOnInvestigation, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelStatusOnInvestigation); + + Label labelAefiClassification = new Label( + I18nProperties.getPrefixCaption(AefiInvestigationListEntryDto.I18N_PREFIX, AefiInvestigationListEntryDto.AEFI_CLASSIFICATION) + + SEPARATOR + + ((listEntry.getAefiClassification() != null) ? listEntry.getAefiClassification() : "")); + CssStyles.style(labelAefiClassification, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelAefiClassification); + } + + public AefiInvestigationListEntryDto getListEntry() { + return listEntry; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiList.java new file mode 100644 index 00000000000..d4c8a1dd8ef --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiList.java @@ -0,0 +1,84 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefilink; + +import java.util.List; +import java.util.function.Consumer; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.utils.PaginationList; + +@SuppressWarnings("serial") +public class AefiList extends PaginationList { + + private static final int MAX_DISPLAYED_ENTRIES = 5; + + private AefiListCriteria aefiListCriteria; + private Consumer actionCallback; + private final boolean isEditable; + private Label noAdverseEventsLabel; + + public AefiList(AefiListCriteria aefiListCriteria, Consumer actionCallback, boolean isEditable) { + + super(MAX_DISPLAYED_ENTRIES); + + this.aefiListCriteria = aefiListCriteria; + this.actionCallback = actionCallback; + this.isEditable = isEditable; + + noAdverseEventsLabel = new Label(I18nProperties.getString(Strings.infoNoImmunizationAdverseEvents)); + } + + @Override + public void reload() { + + List listEntries = FacadeProvider.getAefiFacade().getEntriesList(aefiListCriteria, 0, maxDisplayedEntries * 20); + + setEntries(listEntries); + if (!listEntries.isEmpty()) { + showPage(1); + } else { + listLayout.removeAllComponents(); + updatePaginationLayout(); + listLayout.addComponent(noAdverseEventsLabel); + } + } + + @Override + protected void drawDisplayedEntries() { + + List displayedEntries = getDisplayedEntries(); + for (AefiListEntryDto aefiListEntry : displayedEntries) { + AefiListEntry listEntry = new AefiListEntry(aefiListEntry); + + String aefiUuid = aefiListEntry.getUuid(); + listEntry.addEditButton( + "edit-aefi-" + aefiUuid, + (Button.ClickListener) event -> ControllerProvider.getAefiController().navigateToAefi(aefiUuid)); + + listEntry.setEnabled(isEditable); + listLayout.addComponent(listEntry); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListComponent.java new file mode 100644 index 00000000000..3503f05bbde --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListComponent.java @@ -0,0 +1,53 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefilink; + +import java.util.function.Consumer; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListCriteria; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; + +@SuppressWarnings("serial") +public class AefiListComponent extends SideComponent { + + public AefiListComponent(AefiListCriteria aefiListCriteria, Consumer actionCallback, boolean isEditAllowed, int totalVaccinations) { + super(I18nProperties.getString(Strings.headingImmunizationAdverseEvents), actionCallback); + + setMargin(false); + setWidth(100, Unit.PERCENTAGE); + + if (isEditAllowed) { + addCreateButton( + I18nProperties.getCaption(Captions.aefiNewAdverseEvent), + () -> ControllerProvider.getAefiController() + .navigateToAefi("immunization/" + aefiListCriteria.getImmunization().getUuid() + "/adverseevent/create"), + UserRight.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE); + + if (totalVaccinations == 0) { + createButton.setEnabled(false); + } + } + + AefiList aefiList = new AefiList(aefiListCriteria, actionCallback, isEditAllowed); + addComponent(aefiList); + aefiList.reload(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListEntry.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListEntry.java new file mode 100644 index 00000000000..a47a70bfe60 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/aefilink/AefiListEntry.java @@ -0,0 +1,79 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefilink; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.Label; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentField; + +@SuppressWarnings("serial") +public class AefiListEntry extends SideComponentField { + + public static final String SEPARATOR = ": "; + + private final AefiListEntryDto aefiListEntryDto; + + public AefiListEntry(AefiListEntryDto aefiListEntryDto) { + + this.aefiListEntryDto = aefiListEntryDto; + + Label labelAefiType = new Label(AefiType.toString(aefiListEntryDto.getSerious())); + CssStyles.style(labelAefiType, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + if (aefiListEntryDto.getSerious() == YesNoUnknown.YES) { + CssStyles.style(labelAefiType, CssStyles.LABEL_CRITICAL); + } + addComponentToField(labelAefiType); + + Label labelVaccineName = new Label(aefiListEntryDto.getPrimaryVaccineName().toString()); + CssStyles.style(labelVaccineName, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelVaccineName); + + if (!StringUtils.isBlank(aefiListEntryDto.getPrimaryVaccineDose())) { + Label labelVaccineDose = new Label( + I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_DOSE) + + SEPARATOR + + aefiListEntryDto.getPrimaryVaccineDose()); + CssStyles.style(labelVaccineDose, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelVaccineDose); + } + + Label labelVaccineDate = new Label( + I18nProperties.getPrefixCaption(AefiListEntryDto.I18N_PREFIX, AefiListEntryDto.PRIMARY_VACCINE_VACCINATION_DATE) + + SEPARATOR + + DateFormatHelper.formatLocalDate(aefiListEntryDto.getPrimaryVaccineVaccinationDate())); + addComponentToField(labelVaccineDate); + + Label labelAdverseEvents = new Label(StringUtils.abbreviate(aefiListEntryDto.getAdverseEvents(), 56)); + CssStyles.style(labelAdverseEvents, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + addComponentToField(labelAdverseEvents); + } + + public AefiListEntryDto getAefiListEntryDto() { + return aefiListEntryDto; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiDataLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiDataLayout.java new file mode 100644 index 00000000000..8b96dd8bc29 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiDataLayout.java @@ -0,0 +1,43 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; + +public class AefiDataLayout extends VerticalLayout { + + private final AefiGrid grid; + + public AefiDataLayout(AefiCriteria criteria) { + grid = new AefiGrid(criteria); + addComponent(grid); + + setMargin(false); + setSpacing(false); + setSizeFull(); + setExpandRatio(grid, 1); + } + + public AefiGrid getGrid() { + return grid; + } + + public void refreshGrid() { + grid.reload(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterForm.java new file mode 100644 index 00000000000..5f1f4a47288 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterForm.java @@ -0,0 +1,414 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import static de.symeda.sormas.ui.utils.LayoutUtil.divCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.filterLocs; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; +import static de.symeda.sormas.ui.utils.LayoutUtil.locCss; + +import java.util.Date; +import java.util.stream.Stream; + +import org.apache.commons.lang3.ArrayUtils; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.ui.ComboBox; +import com.vaadin.v7.ui.Field; +import com.vaadin.v7.ui.TextField; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDateType; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityType; +import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.user.JurisdictionLevel; +import de.symeda.sormas.api.user.UserDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.DateFilterOption; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.EpiWeek; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.utils.AbstractFilterForm; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; +import de.symeda.sormas.ui.utils.FieldConfiguration; +import de.symeda.sormas.ui.utils.FieldHelper; + +public class AefiFilterForm extends AbstractFilterForm { + + private static final String ACTION_BUTTONS_ID = "actionButtons"; + private static final String MORE_FILTERS_ID = "moreFilters"; + private static final String WEEK_AND_DATE_FILTER = "weekAndDateFilter"; + + private static final String MORE_FILTERS_HTML = loc(WEEK_AND_DATE_FILTER); + + public AefiFilterForm() { + super( + AefiCriteria.class, + AefiCriteria.I18N_PREFIX, + JurisdictionFieldConfig.of(AefiCriteria.REGION, AefiCriteria.DISTRICT, AefiCriteria.COMMUNITY)); + } + + @Override + protected String createHtmlLayout() { + return divCss( + "", + filterLocs(ArrayUtils.addAll(getMainFilterLocators(), ACTION_BUTTONS_ID)) + locCss(CssStyles.VSPACE_TOP_NONE, MORE_FILTERS_ID)); + + } + + @Override + protected String[] getMainFilterLocators() { + return new String[] { + AefiCriteria.DISEASE, + AefiCriteria.PERSON_LIKE, + AefiCriteria.AEFI_TYPE, + AefiCriteria.VACCINE_NAME, + AefiCriteria.REGION, + AefiCriteria.DISTRICT, + AefiCriteria.COMMUNITY, + AefiCriteria.OUTCOME }; + } + + @Override + protected String createMoreFiltersHtmlLayout() { + return MORE_FILTERS_HTML; + } + + @Override + protected void addFields() { + addField(FieldConfiguration.pixelSized(AefiCriteria.DISEASE, 140)); + + final TextField searchField = addField( + FieldConfiguration.withCaptionAndPixelSized(AefiCriteria.PERSON_LIKE, I18nProperties.getString(Strings.promptPersonsSearchField), 200)); + searchField.setNullRepresentation(""); + + addFields(FieldConfiguration.pixelSized(AefiCriteria.AEFI_TYPE, 140), FieldConfiguration.pixelSized(AefiCriteria.VACCINE_NAME, 140)); + + if (currentUserDto().getRegion() == null) { + ComboBox regionFilter = addField(getContent(), FieldConfiguration.pixelSized(AefiCriteria.REGION, 140)); + regionFilter.addItems(FacadeProvider.getRegionFacade().getAllActiveByServerCountry()); + } + + ComboBox districtFilter = addField(getContent(), FieldConfiguration.pixelSized(AefiCriteria.DISTRICT, 140)); + districtFilter.setDescription(I18nProperties.getDescription(Descriptions.descDistrictFilter)); + if (currentUserDto().getDistrict() != null) { + districtFilter.setVisible(false); + } + + addField(getContent(), FieldConfiguration.pixelSized(AefiCriteria.COMMUNITY, 140)); + + addField(FieldConfiguration.pixelSized(AefiCriteria.OUTCOME, 140)); + } + + @Override + public void addMoreFilters(CustomLayout moreFiltersContainer) { + moreFiltersContainer.addComponent(buildWeekAndDateFilter(), WEEK_AND_DATE_FILTER); + } + + @Override + protected void applyDependenciesOnFieldChange(String propertyId, Property.ValueChangeEvent event) { + + super.applyDependenciesOnFieldChange(propertyId, event); + + final AefiCriteria criteria = getValue(); + + final ComboBox facilityTypeGroupField = getField(AefiCriteria.FACILITY_TYPE_GROUP); + final ComboBox facilityTypeField = getField(AefiCriteria.FACILITY_TYPE); + final ComboBox facilityField = getField(AefiCriteria.HEALTH_FACILITY); + + final UserDto user = currentUserDto(); + final DistrictReferenceDto currentDistrict = + user.getDistrict() != null ? user.getDistrict() : (DistrictReferenceDto) districtFilter.getValue(); + + switch (propertyId) { + case AefiCriteria.REGION: { + final RegionReferenceDto region = user.getRegion() != null ? user.getRegion() : (RegionReferenceDto) event.getProperty().getValue(); + + if (!DataHelper.equal(region, criteria.getRegion())) { + if (region != null) { + enableFields(districtFilter); + FieldHelper.updateItems(districtFilter, FacadeProvider.getDistrictFacade().getAllActiveByRegion(region.getUuid())); + } else { + clearAndDisableFields(districtFilter); + } + clearAndDisableFields(communityFilter, facilityField, facilityTypeField, facilityTypeGroupField); + } + + break; + } + case AefiCriteria.DISTRICT: { + final DistrictReferenceDto newDistrict = (DistrictReferenceDto) event.getProperty().getValue(); + + if (!DataHelper.equal(newDistrict, criteria.getDistrict())) { + if (newDistrict != null) { + enableFields(communityFilter, facilityTypeGroupField); + + clearAndDisableFields(facilityField); + if (facilityTypeGroupField != null) { + if (facilityTypeGroupField.getValue() != null && facilityTypeField.getValue() != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade() + .getActiveFacilitiesByDistrictAndType(newDistrict, (FacilityType) facilityTypeField.getValue(), true, false)); + enableFields(facilityField); + } else { + FieldHelper.updateEnumData(facilityTypeGroupField, FacilityTypeGroup.getAccomodationGroups()); + } + } + + FieldHelper.updateItems(communityFilter, FacadeProvider.getCommunityFacade().getAllActiveByDistrict(newDistrict.getUuid())); + } else { + clearAndDisableFields(communityFilter, facilityField, facilityTypeField, facilityTypeGroupField); + } + } + + break; + } + case AefiCriteria.COMMUNITY: { + CommunityReferenceDto community = (CommunityReferenceDto) event.getProperty().getValue(); + if (!DataHelper.equal(community, criteria.getCommunity())) { + if (facilityField != null) { + facilityField.setValue(null); + } + + final FacilityType facilityType = facilityTypeField != null ? (FacilityType) facilityTypeField.getValue() : null; + + if (facilityType == null && facilityField != null) { + facilityField.removeAllItems(); + } else if (facilityField != null) { + if (community == null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(currentDistrict, facilityType, true, false)); + } else { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } + } + } + break; + } + case AefiCriteria.FACILITY_TYPE_GROUP: { + FacilityTypeGroup typeGroup = (FacilityTypeGroup) event.getProperty().getValue(); + if (!DataHelper.equal(typeGroup, criteria.getFacilityTypeGroup())) { + if (typeGroup != null) { + enableFields(AefiCriteria.FACILITY_TYPE); + FieldHelper.updateEnumData(facilityTypeField, FacilityType.getAccommodationTypes(typeGroup)); + facilityField.setValue(null); + } else { + clearAndDisableFields(facilityTypeField, facilityField); + } + } + + break; + } + case AefiCriteria.FACILITY_TYPE: { + FacilityType facilityType = (FacilityType) event.getProperty().getValue(); + if (!DataHelper.equal(facilityType, criteria.getFacilityType())) { + if (facilityType == null) { + clearAndDisableFields(facilityField); + } else { + enableFields(facilityField); + facilityField.setValue(null); + + CommunityReferenceDto community = (CommunityReferenceDto) communityFilter.getValue(); + if (community != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } else if (currentDistrict != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(currentDistrict, facilityType, true, false)); + } + } + } + break; + } + } + } + + @Override + protected void applyDependenciesOnNewValue(AefiCriteria criteria) { + + final UserDto user = currentUserDto(); + + UserProvider currentUserProvider = UserProvider.getCurrent(); + final JurisdictionLevel userJurisdictionLevel = currentUserProvider != null ? UserProvider.getCurrent().getJurisdictionLevel() : null; + + final ComboBox facilityTypeGroupField = getField(AefiCriteria.FACILITY_TYPE_GROUP); + final ComboBox facilityTypeField = getField(AefiCriteria.FACILITY_TYPE); + final ComboBox facilityField = getField(AefiCriteria.HEALTH_FACILITY); + + // Disable all fields + clearAndDisableFields(districtFilter, communityFilter, facilityTypeGroupField, facilityTypeField, facilityField); + + // Get initial field values according to user and criteria + final RegionReferenceDto region = user.getRegion() == null ? criteria.getRegion() : user.getRegion(); + final DistrictReferenceDto district = user.getDistrict() == null ? criteria.getDistrict() : user.getDistrict(); + final CommunityReferenceDto community = user.getCommunity() == null ? criteria.getCommunity() : user.getCommunity(); + final FacilityTypeGroup facilityTypeGroup = criteria.getFacilityTypeGroup(); + final FacilityType facilityType = criteria.getFacilityType(); + + // district + if (region != null) { + enableFields(districtFilter); + districtFilter.addItems(FacadeProvider.getDistrictFacade().getAllActiveByRegion(region.getUuid())); + // community + if (district != null) { + districtFilter.setValue(district); + communityFilter.addItems(FacadeProvider.getCommunityFacade().getAllActiveByDistrict(district.getUuid())); + enableFields(communityFilter); + if (community != null) { + communityFilter.setValue(community); + } + } else { + clearAndDisableFields(communityFilter); + } + } else { + clearAndDisableFields(districtFilter, communityFilter); + } + + // facility + if (userJurisdictionLevel == JurisdictionLevel.HEALTH_FACILITY) { + facilityField.setValue(user.getHealthFacility()); + disableFields(facilityTypeGroupField, facilityTypeField, facilityField); + } else if (facilityTypeGroupField != null && district != null) { + enableFields(facilityTypeGroupField); + FieldHelper.updateEnumData(facilityTypeGroupField, FacilityTypeGroup.getAccomodationGroups()); + if (facilityTypeGroup != null) { + facilityTypeGroupField.setValue(facilityTypeGroup); + enableFields(facilityTypeField); + FieldHelper.updateEnumData(facilityTypeField, FacilityType.getAccommodationTypes(facilityTypeGroup)); + if (facilityType != null) { + facilityTypeField.setValue(facilityType); + enableFields(facilityField); + if (community != null) { + facilityField + .addItems(FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } else { + facilityField + .addItems(FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(district, facilityType, true, false)); + } + } else { + disableFields(facilityField); + } + } else { + disableFields(facilityTypeField); + } + } + + // Disable fields according to user & jurisdiction + if (userJurisdictionLevel == JurisdictionLevel.DISTRICT) { + clearAndDisableFields(districtFilter); + } else if (userJurisdictionLevel == JurisdictionLevel.COMMUNITY) { + clearAndDisableFields(districtFilter, communityFilter); + } else if (userJurisdictionLevel == JurisdictionLevel.HEALTH_FACILITY) { + clearAndDisableFields(districtFilter, communityFilter, facilityTypeGroupField, facilityTypeField, facilityField); + } + + // Date/Epi week filter + HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + @SuppressWarnings("unchecked") + EpiWeekAndDateFilterComponent weekAndDateFilter = + (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + AefiDateType aefiDateType = criteria.getAefiDateType(); + weekAndDateFilter.getDateTypeSelector().setValue(aefiDateType); + weekAndDateFilter.getDateFilterOptionFilter().setValue(criteria.getDateFilterOption()); + Date dateFrom = criteria.getFromDate(); + Date dateTo = criteria.getToDate(); + + if (DateFilterOption.EPI_WEEK.equals(criteria.getDateFilterOption())) { + weekAndDateFilter.getWeekFromFilter().setValue(dateFrom == null ? null : DateHelper.getEpiWeek(dateFrom)); + weekAndDateFilter.getWeekToFilter().setValue(dateTo == null ? null : DateHelper.getEpiWeek(dateTo)); + } else { + weekAndDateFilter.getDateFromFilter().setValue(dateFrom); + weekAndDateFilter.getDateToFilter().setValue(dateTo); + } + } + + @Override + protected Stream streamFieldsForEmptyCheck(CustomLayout layout) { + HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + EpiWeekAndDateFilterComponent weekAndDateFilter = + (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + return super.streamFieldsForEmptyCheck(layout).filter(f -> f != weekAndDateFilter.getDateFilterOptionFilter()); + } + + private HorizontalLayout buildWeekAndDateFilter() { + + EpiWeekAndDateFilterComponent weekAndDateFilter = new EpiWeekAndDateFilterComponent<>( + false, + false, + null, + AefiDateType.values(), + I18nProperties.getString(Strings.promptAefiDateType), + null, + this); + weekAndDateFilter.getWeekFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiEpiWeekFrom)); + weekAndDateFilter.getWeekToFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiEpiWeekTo)); + weekAndDateFilter.getDateFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiDateFrom)); + weekAndDateFilter.getDateToFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiDateTo)); + + addApplyHandler(e -> onApplyClick(weekAndDateFilter)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(weekAndDateFilter); + + return dateFilterRowLayout; + } + + private void onApplyClick(EpiWeekAndDateFilterComponent weekAndDateFilter) { + AefiCriteria criteria = getValue(); + + DateFilterOption dateFilterOption = (DateFilterOption) weekAndDateFilter.getDateFilterOptionFilter().getValue(); + Date fromDate, toDate; + if (dateFilterOption == DateFilterOption.DATE) { + Date dateFrom = weekAndDateFilter.getDateFromFilter().getValue(); + fromDate = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = weekAndDateFilter.getDateToFilter().getValue(); + toDate = dateFrom != null ? DateHelper.getEndOfDay(dateTo) : null; + } else { + fromDate = DateHelper.getEpiWeekStart((EpiWeek) weekAndDateFilter.getWeekFromFilter().getValue()); + toDate = DateHelper.getEpiWeekEnd((EpiWeek) weekAndDateFilter.getWeekToFilter().getValue()); + } + if ((fromDate != null && toDate != null) || (fromDate == null && toDate == null)) { + criteria.setDateFilterOption(dateFilterOption); + AefiDateType AefiDateType = (AefiDateType) weekAndDateFilter.getDateTypeSelector().getValue(); + criteria.setAefiDateType(AefiDateType); + criteria.setFromDate(fromDate); + criteria.setToDate(toDate); + } else { + weekAndDateFilter.setNotificationsForMissingFilters(); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterFormLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterFormLayout.java new file mode 100644 index 00000000000..801b80ae08c --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiFilterFormLayout.java @@ -0,0 +1,53 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import com.vaadin.ui.Button; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; + +public class AefiFilterFormLayout extends VerticalLayout { + + private static final float PERCENTAGE_WIDTH = 100; + + private final AefiFilterForm filterForm; + + public AefiFilterFormLayout() { + setSpacing(false); + setMargin(false); + setWidth(PERCENTAGE_WIDTH, Unit.PERCENTAGE); + + filterForm = new AefiFilterForm(); + addComponent(filterForm); + } + + public AefiCriteria getValue() { + return filterForm.getValue(); + } + + public void setValue(AefiCriteria criteria) { + filterForm.setValue(criteria); + } + + public void addResetHandler(Button.ClickListener listener) { + filterForm.addResetHandler(listener); + } + + public void addApplyHandler(Button.ClickListener listener) { + filterForm.addApplyHandler(listener); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiGrid.java new file mode 100644 index 00000000000..f89c5d7f240 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiGrid.java @@ -0,0 +1,150 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.renderers.DateRenderer; +import com.vaadin.ui.renderers.TextRenderer; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.person.PersonHelper; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UiUtil; +import de.symeda.sormas.ui.immunization.ImmunizationPersonView; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.FieldAccessColumnStyleGenerator; +import de.symeda.sormas.ui.utils.FilteredGrid; +import de.symeda.sormas.ui.utils.ShowDetailsListener; +import de.symeda.sormas.ui.utils.UuidRenderer; + +public class AefiGrid extends FilteredGrid { + + public static final String PRIMARY_VACCINE_COLUMN = "primaryVaccineColumn"; + + public AefiGrid(AefiCriteria criteria) { + super(AefiIndexDto.class); + setSizeFull(); + setLazyDataProvider(); + setCriteria(criteria); + + Column primaryVaccineColumn = addColumn(entry -> { + if (entry.getPrimaryVaccine() != null) { + if (entry.getPrimaryVaccine() != Vaccine.OTHER) { + return entry.getPrimaryVaccine().toString(); + } else { + return StringUtils.isBlank(entry.getPrimaryVaccineDetails()) + ? entry.getPrimaryVaccine().toString() + : (entry.getPrimaryVaccine() + " (" + entry.getPrimaryVaccineDetails() + ")"); + } + } else { + return "-"; + } + }); + primaryVaccineColumn.setId(PRIMARY_VACCINE_COLUMN); + primaryVaccineColumn.setCaption(I18nProperties.getPrefixCaption(AefiIndexDto.I18N_PREFIX, AefiIndexDto.PRIMARY_VACCINE_NAME)); + + Column deleteColumn = addColumn(entry -> { + if (entry.getDeletionReason() != null) { + return entry.getDeletionReason() + (entry.getOtherDeletionReason() != null ? ": " + entry.getOtherDeletionReason() : ""); + } else { + return "-"; + } + }); + deleteColumn.setId(DELETE_REASON_COLUMN); + deleteColumn.setSortable(false); + deleteColumn.setCaption(I18nProperties.getCaption(Captions.deletionReason)); + + initColumns(); + + addItemClickListener(new ShowDetailsListener<>(AefiIndexDto.UUID, e -> ControllerProvider.getAefiController().navigateToAefi(e.getUuid()))); + addItemClickListener(new ShowDetailsListener<>(AefiIndexDto.IMMUNIZATION_UUID, e -> { + ControllerProvider.getImmunizationController().navigateToImmunization(e.getImmunizationUuid()); + })); + addItemClickListener(new ShowDetailsListener<>(AefiIndexDto.PERSON_UUID, e -> { + ControllerProvider.getImmunizationController().navigateToView(ImmunizationPersonView.VIEW_NAME, e.getImmunizationUuid()); + })); + } + + public void reload() { + getDataProvider().refreshAll(); + } + + private void initColumns() { + setColumns( + AefiIndexDto.UUID, + AefiIndexDto.IMMUNIZATION_UUID, + AefiIndexDto.PERSON_UUID, + AefiIndexDto.PERSON_FIRST_NAME, + AefiIndexDto.PERSON_LAST_NAME, + AefiIndexDto.DISEASE, + AefiIndexDto.AGE_AND_BIRTH_DATE, + AefiIndexDto.SEX, + AefiIndexDto.REGION, + AefiIndexDto.DISTRICT, + AefiIndexDto.SERIOUS, + PRIMARY_VACCINE_COLUMN, + AefiIndexDto.OUTCOME, + AefiIndexDto.VACCINATION_DATE, + AefiIndexDto.REPORT_DATE, + AefiIndexDto.START_DATE_TIME, + AefiIndexDto.ADVERSE_EVENTS, + DELETE_REASON_COLUMN); + + ((Column) getColumn(AefiIndexDto.UUID)).setRenderer(new UuidRenderer()); + ((Column) getColumn(AefiIndexDto.IMMUNIZATION_UUID)).setRenderer(new UuidRenderer()); + ((Column) getColumn(AefiIndexDto.PERSON_UUID)).setRenderer(new UuidRenderer()); + + ((Column) getColumn(AefiIndexDto.AGE_AND_BIRTH_DATE)).setRenderer( + value -> value == null + ? "" + : PersonHelper.getAgeAndBirthdateString( + value.getAge(), + value.getAgeType(), + value.getDateOfBirthDD(), + value.getDateOfBirthMM(), + value.getDateOfBirthYYYY()), + new TextRenderer()); + + ((Column) getColumn(AefiIndexDto.VACCINATION_DATE)).setRenderer(new DateRenderer(DateFormatHelper.getDateFormat())); + ((Column) getColumn(AefiIndexDto.REPORT_DATE)).setRenderer(new DateRenderer(DateFormatHelper.getDateFormat())); + ((Column) getColumn(AefiIndexDto.START_DATE_TIME)).setRenderer(new DateRenderer(DateFormatHelper.getDateFormat())); + + for (Column column : getColumns()) { + column.setCaption(I18nProperties.findPrefixCaptionWithDefault(column.getId(), column.getCaption(), AefiIndexDto.I18N_PREFIX)); + column.setStyleGenerator(FieldAccessColumnStyleGenerator.getDefault(getBeanType(), column.getId())); + } + + if (UiUtil.enabled(FeatureType.HIDE_JURISDICTION_FIELDS)) { + getColumn(AefiIndexDto.REGION).setHidden(true); + getColumn(AefiIndexDto.DISTRICT).setHidden(true); + } + } + + private void setLazyDataProvider() { + + setLazyDataProvider(FacadeProvider.getAefiFacade()::getIndexList, FacadeProvider.getAefiFacade()::count); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationDataLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationDataLayout.java new file mode 100644 index 00000000000..e649ebc0473 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationDataLayout.java @@ -0,0 +1,43 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; + +public class AefiInvestigationDataLayout extends VerticalLayout { + + private final AefiInvestigationGrid grid; + + public AefiInvestigationDataLayout(AefiInvestigationCriteria criteria) { + grid = new AefiInvestigationGrid(criteria); + addComponent(grid); + + setMargin(false); + setSpacing(false); + setSizeFull(); + setExpandRatio(grid, 1); + } + + public AefiInvestigationGrid getGrid() { + return grid; + } + + public void refreshGrid() { + grid.reload(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterForm.java new file mode 100644 index 00000000000..c10376e2785 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterForm.java @@ -0,0 +1,418 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import static de.symeda.sormas.ui.utils.LayoutUtil.divCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.filterLocs; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; +import static de.symeda.sormas.ui.utils.LayoutUtil.locCss; + +import java.util.Date; +import java.util.stream.Stream; + +import org.apache.commons.lang3.ArrayUtils; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.ui.ComboBox; +import com.vaadin.v7.ui.Field; +import com.vaadin.v7.ui.TextField; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDateType; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; +import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityType; +import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; +import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.user.JurisdictionLevel; +import de.symeda.sormas.api.user.UserDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.DateFilterOption; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.EpiWeek; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.utils.AbstractFilterForm; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; +import de.symeda.sormas.ui.utils.FieldConfiguration; +import de.symeda.sormas.ui.utils.FieldHelper; + +public class AefiInvestigationFilterForm extends AbstractFilterForm { + + private static final String ACTION_BUTTONS_ID = "actionButtons"; + private static final String MORE_FILTERS_ID = "moreFilters"; + private static final String WEEK_AND_DATE_FILTER = "weekAndDateFilter"; + + private static final String MORE_FILTERS_HTML = loc(WEEK_AND_DATE_FILTER); + + public AefiInvestigationFilterForm() { + super( + AefiInvestigationCriteria.class, + AefiInvestigationCriteria.I18N_PREFIX, + JurisdictionFieldConfig.of(AefiInvestigationCriteria.REGION, AefiInvestigationCriteria.DISTRICT, AefiInvestigationCriteria.COMMUNITY)); + } + + @Override + protected String createHtmlLayout() { + return divCss( + "", + filterLocs(ArrayUtils.addAll(getMainFilterLocators(), ACTION_BUTTONS_ID)) + locCss(CssStyles.VSPACE_TOP_NONE, MORE_FILTERS_ID)); + + } + + @Override + protected String[] getMainFilterLocators() { + return new String[] { + AefiInvestigationCriteria.DISEASE, + AefiInvestigationCriteria.PERSON_LIKE, + AefiInvestigationCriteria.VACCINE_NAME, + AefiInvestigationCriteria.REGION, + AefiInvestigationCriteria.DISTRICT, + AefiInvestigationCriteria.COMMUNITY, + AefiInvestigationCriteria.STATUS_ON_DATE_OF_INVESTIGATION, + AefiInvestigationCriteria.AEFI_CLASSIFICATION }; + } + + @Override + protected String createMoreFiltersHtmlLayout() { + return MORE_FILTERS_HTML; + } + + @Override + protected void addFields() { + addField(FieldConfiguration.pixelSized(AefiInvestigationCriteria.DISEASE, 140)); + + final TextField searchField = addField( + FieldConfiguration + .withCaptionAndPixelSized(AefiInvestigationCriteria.PERSON_LIKE, I18nProperties.getString(Strings.promptPersonsSearchField), 200)); + searchField.setNullRepresentation(""); + + addFields( + FieldConfiguration.pixelSized(AefiInvestigationCriteria.AEFI_TYPE, 140), + FieldConfiguration.pixelSized(AefiInvestigationCriteria.VACCINE_NAME, 140)); + + if (currentUserDto().getRegion() == null) { + ComboBox regionFilter = addField(getContent(), FieldConfiguration.pixelSized(AefiInvestigationCriteria.REGION, 140)); + regionFilter.addItems(FacadeProvider.getRegionFacade().getAllActiveByServerCountry()); + } + + ComboBox districtFilter = addField(getContent(), FieldConfiguration.pixelSized(AefiInvestigationCriteria.DISTRICT, 140)); + districtFilter.setDescription(I18nProperties.getDescription(Descriptions.descDistrictFilter)); + if (currentUserDto().getDistrict() != null) { + districtFilter.setVisible(false); + } + + addField(getContent(), FieldConfiguration.pixelSized(AefiInvestigationCriteria.COMMUNITY, 140)); + + addField(FieldConfiguration.pixelSized(AefiInvestigationCriteria.STATUS_ON_DATE_OF_INVESTIGATION, 140)); + addField(FieldConfiguration.pixelSized(AefiInvestigationCriteria.AEFI_CLASSIFICATION, 140)); + } + + @Override + public void addMoreFilters(CustomLayout moreFiltersContainer) { + moreFiltersContainer.addComponent(buildWeekAndDateFilter(), WEEK_AND_DATE_FILTER); + } + + @Override + protected void applyDependenciesOnFieldChange(String propertyId, Property.ValueChangeEvent event) { + + super.applyDependenciesOnFieldChange(propertyId, event); + + final AefiInvestigationCriteria criteria = getValue(); + + final ComboBox facilityTypeGroupField = getField(AefiInvestigationCriteria.FACILITY_TYPE_GROUP); + final ComboBox facilityTypeField = getField(AefiInvestigationCriteria.FACILITY_TYPE); + final ComboBox facilityField = getField(AefiInvestigationCriteria.HEALTH_FACILITY); + + final UserDto user = currentUserDto(); + final DistrictReferenceDto currentDistrict = + user.getDistrict() != null ? user.getDistrict() : (DistrictReferenceDto) districtFilter.getValue(); + + switch (propertyId) { + case AefiInvestigationCriteria.REGION: { + final RegionReferenceDto region = user.getRegion() != null ? user.getRegion() : (RegionReferenceDto) event.getProperty().getValue(); + + if (!DataHelper.equal(region, criteria.getRegion())) { + if (region != null) { + enableFields(districtFilter); + FieldHelper.updateItems(districtFilter, FacadeProvider.getDistrictFacade().getAllActiveByRegion(region.getUuid())); + } else { + clearAndDisableFields(districtFilter); + } + clearAndDisableFields(communityFilter, facilityField, facilityTypeField, facilityTypeGroupField); + } + + break; + } + case AefiInvestigationCriteria.DISTRICT: { + final DistrictReferenceDto newDistrict = (DistrictReferenceDto) event.getProperty().getValue(); + + if (!DataHelper.equal(newDistrict, criteria.getDistrict())) { + if (newDistrict != null) { + enableFields(communityFilter, facilityTypeGroupField); + + clearAndDisableFields(facilityField); + if (facilityTypeGroupField != null) { + if (facilityTypeGroupField.getValue() != null && facilityTypeField.getValue() != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade() + .getActiveFacilitiesByDistrictAndType(newDistrict, (FacilityType) facilityTypeField.getValue(), true, false)); + enableFields(facilityField); + } else { + FieldHelper.updateEnumData(facilityTypeGroupField, FacilityTypeGroup.getAccomodationGroups()); + } + } + + FieldHelper.updateItems(communityFilter, FacadeProvider.getCommunityFacade().getAllActiveByDistrict(newDistrict.getUuid())); + } else { + clearAndDisableFields(communityFilter, facilityField, facilityTypeField, facilityTypeGroupField); + } + } + + break; + } + case AefiInvestigationCriteria.COMMUNITY: { + CommunityReferenceDto community = (CommunityReferenceDto) event.getProperty().getValue(); + if (!DataHelper.equal(community, criteria.getCommunity())) { + if (facilityField != null) { + facilityField.setValue(null); + } + + final FacilityType facilityType = facilityTypeField != null ? (FacilityType) facilityTypeField.getValue() : null; + + if (facilityType == null && facilityField != null) { + facilityField.removeAllItems(); + } else if (facilityField != null) { + if (community == null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(currentDistrict, facilityType, true, false)); + } else { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } + } + } + break; + } + case AefiInvestigationCriteria.FACILITY_TYPE_GROUP: { + FacilityTypeGroup typeGroup = (FacilityTypeGroup) event.getProperty().getValue(); + if (!DataHelper.equal(typeGroup, criteria.getFacilityTypeGroup())) { + if (typeGroup != null) { + enableFields(AefiInvestigationCriteria.FACILITY_TYPE); + FieldHelper.updateEnumData(facilityTypeField, FacilityType.getAccommodationTypes(typeGroup)); + facilityField.setValue(null); + } else { + clearAndDisableFields(facilityTypeField, facilityField); + } + } + + break; + } + case AefiInvestigationCriteria.FACILITY_TYPE: { + FacilityType facilityType = (FacilityType) event.getProperty().getValue(); + if (!DataHelper.equal(facilityType, criteria.getFacilityType())) { + if (facilityType == null) { + clearAndDisableFields(facilityField); + } else { + enableFields(facilityField); + facilityField.setValue(null); + + CommunityReferenceDto community = (CommunityReferenceDto) communityFilter.getValue(); + if (community != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } else if (currentDistrict != null) { + FieldHelper.updateItems( + facilityField, + FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(currentDistrict, facilityType, true, false)); + } + } + } + break; + } + } + } + + @Override + protected void applyDependenciesOnNewValue(AefiInvestigationCriteria criteria) { + + final UserDto user = currentUserDto(); + + UserProvider currentUserProvider = UserProvider.getCurrent(); + final JurisdictionLevel userJurisdictionLevel = currentUserProvider != null ? UserProvider.getCurrent().getJurisdictionLevel() : null; + + final ComboBox facilityTypeGroupField = getField(AefiInvestigationCriteria.FACILITY_TYPE_GROUP); + final ComboBox facilityTypeField = getField(AefiInvestigationCriteria.FACILITY_TYPE); + final ComboBox facilityField = getField(AefiInvestigationCriteria.HEALTH_FACILITY); + + // Disable all fields + clearAndDisableFields(districtFilter, communityFilter, facilityTypeGroupField, facilityTypeField, facilityField); + + // Get initial field values according to user and criteria + final RegionReferenceDto region = user.getRegion() == null ? criteria.getRegion() : user.getRegion(); + final DistrictReferenceDto district = user.getDistrict() == null ? criteria.getDistrict() : user.getDistrict(); + final CommunityReferenceDto community = user.getCommunity() == null ? criteria.getCommunity() : user.getCommunity(); + final FacilityTypeGroup facilityTypeGroup = criteria.getFacilityTypeGroup(); + final FacilityType facilityType = criteria.getFacilityType(); + + // district + if (region != null) { + enableFields(districtFilter); + districtFilter.addItems(FacadeProvider.getDistrictFacade().getAllActiveByRegion(region.getUuid())); + // community + if (district != null) { + districtFilter.setValue(district); + communityFilter.addItems(FacadeProvider.getCommunityFacade().getAllActiveByDistrict(district.getUuid())); + enableFields(communityFilter); + if (community != null) { + communityFilter.setValue(community); + } + } else { + clearAndDisableFields(communityFilter); + } + } else { + clearAndDisableFields(districtFilter, communityFilter); + } + + // facility + if (userJurisdictionLevel == JurisdictionLevel.HEALTH_FACILITY) { + facilityField.setValue(user.getHealthFacility()); + disableFields(facilityTypeGroupField, facilityTypeField, facilityField); + } else if (facilityTypeGroupField != null && district != null) { + enableFields(facilityTypeGroupField); + FieldHelper.updateEnumData(facilityTypeGroupField, FacilityTypeGroup.getAccomodationGroups()); + if (facilityTypeGroup != null) { + facilityTypeGroupField.setValue(facilityTypeGroup); + enableFields(facilityTypeField); + FieldHelper.updateEnumData(facilityTypeField, FacilityType.getAccommodationTypes(facilityTypeGroup)); + if (facilityType != null) { + facilityTypeField.setValue(facilityType); + enableFields(facilityField); + if (community != null) { + facilityField + .addItems(FacadeProvider.getFacilityFacade().getActiveFacilitiesByCommunityAndType(community, facilityType, true, false)); + } else { + facilityField + .addItems(FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(district, facilityType, true, false)); + } + } else { + disableFields(facilityField); + } + } else { + disableFields(facilityTypeField); + } + } + + // Disable fields according to user & jurisdiction + if (userJurisdictionLevel == JurisdictionLevel.DISTRICT) { + clearAndDisableFields(districtFilter); + } else if (userJurisdictionLevel == JurisdictionLevel.COMMUNITY) { + clearAndDisableFields(districtFilter, communityFilter); + } else if (userJurisdictionLevel == JurisdictionLevel.HEALTH_FACILITY) { + clearAndDisableFields(districtFilter, communityFilter, facilityTypeGroupField, facilityTypeField, facilityField); + } + + // Date/Epi week filter + HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + @SuppressWarnings("unchecked") + EpiWeekAndDateFilterComponent weekAndDateFilter = + (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + AefiInvestigationDateType aefiInvestigationDateType = criteria.getAefiInvestigationDateType(); + weekAndDateFilter.getDateTypeSelector().setValue(aefiInvestigationDateType); + weekAndDateFilter.getDateFilterOptionFilter().setValue(criteria.getDateFilterOption()); + Date dateFrom = criteria.getFromDate(); + Date dateTo = criteria.getToDate(); + + if (DateFilterOption.EPI_WEEK.equals(criteria.getDateFilterOption())) { + weekAndDateFilter.getWeekFromFilter().setValue(dateFrom == null ? null : DateHelper.getEpiWeek(dateFrom)); + weekAndDateFilter.getWeekToFilter().setValue(dateTo == null ? null : DateHelper.getEpiWeek(dateTo)); + } else { + weekAndDateFilter.getDateFromFilter().setValue(dateFrom); + weekAndDateFilter.getDateToFilter().setValue(dateTo); + } + } + + @Override + protected Stream streamFieldsForEmptyCheck(CustomLayout layout) { + HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + EpiWeekAndDateFilterComponent weekAndDateFilter = + (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + return super.streamFieldsForEmptyCheck(layout).filter(f -> f != weekAndDateFilter.getDateFilterOptionFilter()); + } + + private HorizontalLayout buildWeekAndDateFilter() { + + EpiWeekAndDateFilterComponent weekAndDateFilter = new EpiWeekAndDateFilterComponent<>( + false, + false, + null, + AefiInvestigationDateType.values(), + I18nProperties.getString(Strings.promptAefiInvestigationDateType), + null, + this); + weekAndDateFilter.getWeekFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiInvestigationEpiWeekFrom)); + weekAndDateFilter.getWeekToFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiInvestigationEpiWeekTo)); + weekAndDateFilter.getDateFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiInvestigationDateFrom)); + weekAndDateFilter.getDateToFilter().setInputPrompt(I18nProperties.getString(Strings.promptAefiInvestigationDateTo)); + + addApplyHandler(e -> onApplyClick(weekAndDateFilter)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(weekAndDateFilter); + + return dateFilterRowLayout; + } + + private void onApplyClick(EpiWeekAndDateFilterComponent weekAndDateFilter) { + AefiInvestigationCriteria criteria = getValue(); + + DateFilterOption dateFilterOption = (DateFilterOption) weekAndDateFilter.getDateFilterOptionFilter().getValue(); + Date fromDate, toDate; + if (dateFilterOption == DateFilterOption.DATE) { + Date dateFrom = weekAndDateFilter.getDateFromFilter().getValue(); + fromDate = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = weekAndDateFilter.getDateToFilter().getValue(); + toDate = dateFrom != null ? DateHelper.getEndOfDay(dateTo) : null; + } else { + fromDate = DateHelper.getEpiWeekStart((EpiWeek) weekAndDateFilter.getWeekFromFilter().getValue()); + toDate = DateHelper.getEpiWeekEnd((EpiWeek) weekAndDateFilter.getWeekToFilter().getValue()); + } + if ((fromDate != null && toDate != null) || (fromDate == null && toDate == null)) { + criteria.setDateFilterOption(dateFilterOption); + AefiInvestigationDateType aefiInvestigationDateType = (AefiInvestigationDateType) weekAndDateFilter.getDateTypeSelector().getValue(); + criteria.setAefiInvestigationDateType(aefiInvestigationDateType); + criteria.setFromDate(fromDate); + criteria.setToDate(toDate); + } else { + weekAndDateFilter.setNotificationsForMissingFilters(); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterFormLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterFormLayout.java new file mode 100644 index 00000000000..eddd5ee5c8b --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationFilterFormLayout.java @@ -0,0 +1,53 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import com.vaadin.ui.Button; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; + +public class AefiInvestigationFilterFormLayout extends VerticalLayout { + + private static final float PERCENTAGE_WIDTH = 100; + + private final AefiInvestigationFilterForm filterForm; + + public AefiInvestigationFilterFormLayout() { + setSpacing(false); + setMargin(false); + setWidth(PERCENTAGE_WIDTH, Unit.PERCENTAGE); + + filterForm = new AefiInvestigationFilterForm(); + addComponent(filterForm); + } + + public AefiInvestigationCriteria getValue() { + return filterForm.getValue(); + } + + public void setValue(AefiInvestigationCriteria criteria) { + filterForm.setValue(criteria); + } + + public void addResetHandler(Button.ClickListener listener) { + filterForm.addResetHandler(listener); + } + + public void addApplyHandler(Button.ClickListener listener) { + filterForm.addApplyHandler(listener); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationGrid.java new file mode 100644 index 00000000000..a0575b79a3f --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/directory/AefiInvestigationGrid.java @@ -0,0 +1,151 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.directory; + +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.renderers.DateRenderer; +import com.vaadin.ui.renderers.TextRenderer; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationIndexDto; +import de.symeda.sormas.api.caze.AgeAndBirthDateDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.person.PersonHelper; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UiUtil; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.FieldAccessColumnStyleGenerator; +import de.symeda.sormas.ui.utils.FilteredGrid; +import de.symeda.sormas.ui.utils.ShowDetailsListener; +import de.symeda.sormas.ui.utils.UuidRenderer; + +public class AefiInvestigationGrid extends FilteredGrid { + + public static final String PRIMARY_VACCINE_COLUMN = "primaryVaccineColumn"; + + public AefiInvestigationGrid(AefiInvestigationCriteria criteria) { + super(AefiInvestigationIndexDto.class); + setSizeFull(); + setLazyDataProvider(); + setCriteria(criteria); + + Column primaryVaccineColumn = addColumn(entry -> { + if (entry.getPrimaryVaccine() != null) { + if (entry.getPrimaryVaccine() != Vaccine.OTHER) { + return entry.getPrimaryVaccine().toString(); + } else { + return StringUtils.isBlank(entry.getPrimaryVaccineDetails()) + ? entry.getPrimaryVaccine().toString() + : (entry.getPrimaryVaccine() + " (" + entry.getPrimaryVaccineDetails() + ")"); + } + } else { + return "-"; + } + }); + primaryVaccineColumn.setId(PRIMARY_VACCINE_COLUMN); + primaryVaccineColumn + .setCaption(I18nProperties.getPrefixCaption(AefiInvestigationIndexDto.I18N_PREFIX, AefiInvestigationIndexDto.PRIMARY_VACCINE_NAME)); + + Column deleteColumn = addColumn(entry -> { + if (entry.getDeletionReason() != null) { + return entry.getDeletionReason() + (entry.getOtherDeletionReason() != null ? ": " + entry.getOtherDeletionReason() : ""); + } else { + return "-"; + } + }); + deleteColumn.setId(DELETE_REASON_COLUMN); + deleteColumn.setSortable(false); + deleteColumn.setCaption(I18nProperties.getCaption(Captions.deletionReason)); + + initColumns(); + + addItemClickListener( + new ShowDetailsListener<>( + AefiInvestigationIndexDto.UUID, + e -> ControllerProvider.getAefiInvestigationController().navigateToAefiInvestigation(e.getUuid()))); + addItemClickListener(new ShowDetailsListener<>(AefiInvestigationIndexDto.AEFI_REPORT_UUID, e -> { + ControllerProvider.getAefiController().navigateToAefi(e.getAefiReportUuid()); + })); + } + + public void reload() { + getDataProvider().refreshAll(); + } + + private void initColumns() { + setColumns( + AefiInvestigationIndexDto.UUID, + AefiInvestigationIndexDto.INVESTIGATION_CASE_ID, + AefiInvestigationIndexDto.AEFI_REPORT_UUID, + AefiInvestigationIndexDto.PERSON_FIRST_NAME, + AefiInvestigationIndexDto.PERSON_LAST_NAME, + AefiInvestigationIndexDto.DISEASE, + AefiInvestigationIndexDto.AGE_AND_BIRTH_DATE, + AefiInvestigationIndexDto.SEX, + AefiInvestigationIndexDto.REGION, + AefiInvestigationIndexDto.DISTRICT, + PRIMARY_VACCINE_COLUMN, + AefiInvestigationIndexDto.STATUS_ON_DATE_OF_INVESTIGATION, + AefiInvestigationIndexDto.INVESTIGATION_STATUS, + AefiInvestigationIndexDto.AEFI_CLASSIFICATION, + AefiInvestigationIndexDto.REPORT_DATE, + AefiInvestigationIndexDto.INVESTIGATION_DATE, + AefiInvestigationIndexDto.INVESTIGATION_STAGE, + DELETE_REASON_COLUMN); + + ((Column) getColumn(AefiInvestigationIndexDto.UUID)).setRenderer(new UuidRenderer()); + ((Column) getColumn(AefiInvestigationIndexDto.AEFI_REPORT_UUID)).setRenderer(new UuidRenderer()); + + ((Column) getColumn(AefiInvestigationIndexDto.AGE_AND_BIRTH_DATE)).setRenderer( + value -> value == null + ? "" + : PersonHelper.getAgeAndBirthdateString( + value.getAge(), + value.getAgeType(), + value.getDateOfBirthDD(), + value.getDateOfBirthMM(), + value.getDateOfBirthYYYY()), + new TextRenderer()); + + ((Column) getColumn(AefiInvestigationIndexDto.REPORT_DATE)) + .setRenderer(new DateRenderer(DateFormatHelper.getDateFormat())); + ((Column) getColumn(AefiInvestigationIndexDto.INVESTIGATION_DATE)) + .setRenderer(new DateRenderer(DateFormatHelper.getDateFormat())); + + for (Column column : getColumns()) { + column + .setCaption(I18nProperties.findPrefixCaptionWithDefault(column.getId(), column.getCaption(), AefiInvestigationIndexDto.I18N_PREFIX)); + column.setStyleGenerator(FieldAccessColumnStyleGenerator.getDefault(getBeanType(), column.getId())); + } + + if (UiUtil.enabled(FeatureType.HIDE_JURISDICTION_FIELDS)) { + getColumn(AefiInvestigationIndexDto.REGION).setHidden(true); + getColumn(AefiInvestigationIndexDto.DISTRICT).setHidden(true); + } + } + + private void setLazyDataProvider() { + + setLazyDataProvider(FacadeProvider.getAefiInvestigationFacade()::getIndexList, FacadeProvider.getAefiInvestigationFacade()::count); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiPrimarySuspectVaccinationSelectionField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiPrimarySuspectVaccinationSelectionField.java new file mode 100644 index 00000000000..6f86f5792bc --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiPrimarySuspectVaccinationSelectionField.java @@ -0,0 +1,146 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines; + +import java.util.List; +import java.util.function.Consumer; + +import com.vaadin.shared.ui.grid.HeightMode; +import com.vaadin.ui.Component; +import com.vaadin.ui.CustomField; +import com.vaadin.ui.Grid; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.caze.VaccineManufacturer; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.VaadinUiUtil; + +public class AefiPrimarySuspectVaccinationSelectionField extends CustomField { + + private VerticalLayout mainLayout; + private Grid vaccinationGrid; + private final String infoAefiSelectPrimarySuspectVaccine; + private Consumer selectionChangeCallback; + private List vaccinationDtoList; + private VaccinationDto primarySuspectVaccine; + + public AefiPrimarySuspectVaccinationSelectionField(List vaccinationDtoList, VaccinationDto primarySuspectVaccine) { + this.vaccinationDtoList = vaccinationDtoList; + this.primarySuspectVaccine = primarySuspectVaccine; + this.infoAefiSelectPrimarySuspectVaccine = I18nProperties.getString(Strings.infoAefiSelectPrimarySuspectVaccine); + + initializeGrid(); + } + + private void addInfoComponent() { + mainLayout.addComponent(VaadinUiUtil.createInfoComponent(infoAefiSelectPrimarySuspectVaccine)); + } + + public void initializeGrid() { + + vaccinationGrid = new Grid<>(); + vaccinationGrid.setSizeFull(); + vaccinationGrid.setSelectionMode(Grid.SelectionMode.SINGLE); + vaccinationGrid.setHeightByRows(5); + vaccinationGrid.setHeightMode(HeightMode.ROW); + + vaccinationGrid.setItems(vaccinationDtoList); + + if (primarySuspectVaccine != null) { + vaccinationGrid.select(primarySuspectVaccine); + } + + vaccinationGrid.addColumn(vaccinationDto -> DateFormatHelper.formatDate(vaccinationDto.getVaccinationDate())) + .setCaption(I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINATION_DATE)); + + vaccinationGrid + .addColumn( + vaccinationDto -> Vaccine.OTHER.equals(vaccinationDto.getVaccineName()) + ? vaccinationDto.getOtherVaccineName() + : vaccinationDto.getVaccineName()) + .setCaption(I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_NAME)); + + vaccinationGrid + .addColumn( + vaccinationDto -> VaccineManufacturer.OTHER.equals(vaccinationDto.getVaccineManufacturer()) + ? vaccinationDto.getOtherVaccineManufacturer() + : vaccinationDto.getVaccineManufacturer()) + .setCaption(I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_MANUFACTURER)); + + vaccinationGrid.addColumn(VaccinationDto::getVaccineType) + .setCaption(I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_TYPE)); + + vaccinationGrid.addColumn(VaccinationDto::getVaccineDose) + .setCaption(I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_DOSE)); + + vaccinationGrid.addSelectionListener(e -> { + + if (selectionChangeCallback != null) { + selectionChangeCallback.accept(!e.getAllSelectedItems().isEmpty()); + } + }); + } + + @Override + protected Component initContent() { + + mainLayout = new VerticalLayout(); + mainLayout.setSpacing(true); + mainLayout.setMargin(false); + mainLayout.setSizeUndefined(); + mainLayout.setWidth(100, Unit.PERCENTAGE); + CssStyles.style(mainLayout, CssStyles.VSPACE_2); + + addInfoComponent(); + + mainLayout.addComponent(vaccinationGrid); + + return mainLayout; + } + + @Override + protected void doSetValue(VaccinationDto vaccinationDto) { + if (vaccinationDto != null) { + vaccinationGrid.select(vaccinationDto); + } + } + + @Override + public VaccinationDto getValue() { + if (vaccinationGrid != null) { + VaccinationDto value = vaccinationGrid.getSelectedItems().stream().findFirst().orElse(null); + return value; + } + + return null; + } + + public void setSelectionChangeCallback(Consumer callback) { + this.selectionChangeCallback = callback; + } + + public Grid getVaccinationGrid() { + return vaccinationGrid; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiVaccinationsField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiVaccinationsField.java new file mode 100644 index 00000000000..8597fdac53a --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/fields/vaccines/AefiVaccinationsField.java @@ -0,0 +1,192 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines; + +import java.util.function.Consumer; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.icons.VaadinIcons; +import com.vaadin.shared.ui.ContentMode; +import com.vaadin.ui.Label; +import com.vaadin.v7.data.util.BeanItemContainer; +import com.vaadin.v7.ui.Table; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.utils.DateFormatHelper; +import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.caze.AbstractTableField; + +public class AefiVaccinationsField extends AbstractTableField { + + private AefiDto aefiDto; + private AefiInvestigationDto aefiInvestigationDto; + private VaccinationDto primarySuspectVaccination; + private boolean aefiReportContext; + private boolean aefiInvestigationContext; + private final UiFieldAccessCheckers fieldAccessCheckers; + + public AefiVaccinationsField(UiFieldAccessCheckers fieldAccessCheckers) { + super(fieldAccessCheckers); + this.fieldAccessCheckers = fieldAccessCheckers; + + updateAddButtonCaption(); + } + + @Override + public Class getEntryType() { + return VaccinationDto.class; + } + + @Override + protected void editEntry(VaccinationDto entry, boolean create, Consumer commitCallback) { + + if (create) { + if (aefiReportContext) { + ControllerProvider.getAefiController().selectPrimarySuspectVaccination(aefiDto, this::selectPrimarySuspectVaccination); + } else if (aefiInvestigationContext) { + ControllerProvider.getAefiInvestigationController() + .selectPrimarySuspectVaccination(aefiInvestigationDto, this::selectPrimarySuspectVaccination); + } + } + } + + public void updateAddButtonCaption() { + getAddButton().setCaption(I18nProperties.getCaption(Captions.actionAefiSelectPrimarySuspectVaccination)); + } + + @Override + protected void updateColumns() { + Table table = getTable(); + + table.addGeneratedColumn(Captions.aefiVaccinationsPrimaryVaccine, (Table.ColumnGenerator) (source, itemId, columnId) -> { + VaccinationDto vaccinationDto = (VaccinationDto) itemId; + return new Label( + primarySuspectVaccination != null && StringUtils.equals(vaccinationDto.getUuid(), primarySuspectVaccination.getUuid()) + ? VaadinIcons.CHECK_CIRCLE.getHtml() + : "", + ContentMode.HTML); + }); + + table.addGeneratedColumn(Captions.aefiVaccinationsVaccineDetails, (Table.ColumnGenerator) (source, item, columnId) -> { + VaccinationDto vaccinationDto = (VaccinationDto) item; + + StringBuilder vaccineDetailsBuilder = new StringBuilder(); + vaccineDetailsBuilder.append(vaccinationDto.getVaccineManufacturer()); + vaccineDetailsBuilder.append(", ") + .append( + Vaccine.OTHER.equals(vaccinationDto.getVaccineName()) ? vaccinationDto.getOtherVaccineName() : vaccinationDto.getVaccineName()); + + if (vaccinationDto.getVaccinationDate() != null) { + vaccineDetailsBuilder.append(", ").append(DateFormatHelper.formatDate(vaccinationDto.getVaccinationDate())); + } + + if (!StringUtils.isBlank(vaccinationDto.getVaccineDose())) { + vaccineDetailsBuilder.append(", Dose ").append(vaccinationDto.getVaccineDose()); + } + + return vaccineDetailsBuilder.toString(); + }); + + table.addGeneratedColumn(Captions.aefiVaccinationsDiluentBatchLotNumber, (Table.ColumnGenerator) (source, item, columnId) -> { + VaccinationDto vaccinationDto = (VaccinationDto) item; + return "-"; + }); + + table.addGeneratedColumn(Captions.aefiVaccinationsDiluentExpiryDate, (Table.ColumnGenerator) (source, item, columnId) -> { + VaccinationDto vaccinationDto = (VaccinationDto) item; + return "-"; + }); + + table.addGeneratedColumn(Captions.aefiVaccinationsDiluentTimeOfReconstitution, (Table.ColumnGenerator) (source, item, columnId) -> { + VaccinationDto vaccinationDto = (VaccinationDto) item; + return "-"; + }); + + table.setVisibleColumns( + Captions.aefiVaccinationsPrimaryVaccine, + Captions.aefiVaccinationsVaccineDetails, + Captions.aefiVaccinationsDiluentBatchLotNumber, + Captions.aefiVaccinationsDiluentExpiryDate, + Captions.aefiVaccinationsDiluentTimeOfReconstitution); + + for (Object columnId : table.getVisibleColumns()) { + if (columnId.equals(ACTION_COLUMN_ID)) { + table.setColumnHeader(columnId, " "); + } else if (columnId.equals(Captions.aefiVaccinationsPrimaryVaccine)) { + table.setColumnHeader(columnId, I18nProperties.getCaption(Captions.aefiVaccinationsPrimaryVaccine)); + } else if (columnId.equals(Captions.aefiVaccinationsVaccineDetails)) { + table.setColumnHeader(columnId, I18nProperties.getCaption(Captions.aefiVaccinationsVaccineDetails)); + } else if (columnId.equals(Captions.aefiVaccinationsDiluentBatchLotNumber)) { + table.setColumnHeader(columnId, I18nProperties.getCaption(Captions.aefiVaccinationsDiluentBatchLotNumber)); + } else if (columnId.equals(Captions.aefiVaccinationsDiluentExpiryDate)) { + table.setColumnHeader(columnId, I18nProperties.getCaption(Captions.aefiVaccinationsDiluentExpiryDate)); + } else if (columnId.equals(Captions.aefiVaccinationsDiluentTimeOfReconstitution)) { + table.setColumnHeader(columnId, I18nProperties.getCaption(Captions.aefiVaccinationsDiluentTimeOfReconstitution)); + } else { + table.setColumnHeader(columnId, I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, (String) columnId)); + } + } + } + + public void refreshTable() { + Table table = getTable(); + + BeanItemContainer container = getContainer(); + if (container == null) { + return; + } + + container.removeAllItems(); + if (aefiReportContext) { + container.addAll(aefiDto.getVaccinations()); + } else { + container.addAll(aefiInvestigationDto.getVaccinations()); + } + table.refreshRowCache(); + } + + public void applyAefiReportContext(AefiDto aefiDto) { + this.aefiDto = aefiDto; + aefiReportContext = true; + } + + public void applyAefiInvestigationContext(AefiInvestigationDto aefiInvestigationDto) { + this.aefiInvestigationDto = aefiInvestigationDto; + aefiInvestigationContext = true; + } + + public void selectPrimarySuspectVaccination(VaccinationDto vaccinationDto) { + primarySuspectVaccination = vaccinationDto; + refreshTable(); + } + + @Override + protected boolean isEmpty(VaccinationDto entry) { + return false; + } + + @Override + protected boolean isModified(VaccinationDto oldEntry, VaccinationDto newEntry) { + return false; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AdverseEventsForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AdverseEventsForm.java new file mode 100644 index 00000000000..48181c91253 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AdverseEventsForm.java @@ -0,0 +1,150 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form; + +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.ABSCESS; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.ANAPHYLAXIS; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.ENCEPHALOPATHY; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.FEVERISH_FEELING; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.I18N_PREFIX; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.OTHER_ADVERSE_EVENT_DETAILS; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEIZURES; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEIZURE_TYPE; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEPSIS; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEVERE_LOCAL_REACTION; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.THROMBOCYTOPENIA; +import static de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto.TOXIC_SHOCK_SYNDROME; +import static de.symeda.sormas.ui.utils.CssStyles.H3; +import static de.symeda.sormas.ui.utils.LayoutUtil.divCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidColumn; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRow; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; +import static de.symeda.sormas.ui.utils.LayoutUtil.locs; + +import java.util.Arrays; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.ui.CheckBox; +import com.vaadin.v7.ui.Field; +import com.vaadin.v7.ui.TextArea; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; +import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.FieldHelper; +import de.symeda.sormas.ui.utils.NullableOptionGroup; + +@SuppressWarnings("deprecation") +public class AdverseEventsForm extends AbstractEditForm { + + private static final long serialVersionUID = 5081846814610543073L; + + private static final String ADVERSE_EVENTS_HEADINGS_LOC = "adverseEventsHeadingLoc"; + private static final String EMPTY_LABEL_LOC = "emptyLabelLoc"; + + //@formatter:off + private static final String HTML_LAYOUT = + loc(ADVERSE_EVENTS_HEADINGS_LOC) + + fluidRow( + fluidColumn(6, 0, locs( + SEVERE_LOCAL_REACTION, SEIZURES, + ABSCESS, SEPSIS, ENCEPHALOPATHY, + TOXIC_SHOCK_SYNDROME, THROMBOCYTOPENIA, + ANAPHYLAXIS, FEVERISH_FEELING)), + fluidColumn(5, 0, + divCss(CssStyles.VSPACE_TOP_4, + fluidRowLocs(4, SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS, + 6, SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT, + 2, EMPTY_LABEL_LOC)) + + divCss(CssStyles.VSPACE_TOP_3, + fluidRowLocs(10, SEIZURE_TYPE))) + ) + + loc(OTHER_ADVERSE_EVENT_DETAILS); + //@formatter:on + + public AdverseEventsForm(FieldVisibilityCheckers fieldVisibilityCheckers, UiFieldAccessCheckers fieldAccessCheckers) { + super(AdverseEventsDto.class, I18N_PREFIX, true, fieldVisibilityCheckers, fieldAccessCheckers); + } + + @Override + protected String createHtmlLayout() { + return HTML_LAYOUT; + } + + @Override + protected void addFields() { + Label adverseEventsHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiAdverseEvents)); + adverseEventsHeadingLabel.addStyleName(H3); + getContent().addComponent(adverseEventsHeadingLabel, ADVERSE_EVENTS_HEADINGS_LOC); + + addFields( + SEVERE_LOCAL_REACTION, + SEIZURES, + ABSCESS, + SEPSIS, + ENCEPHALOPATHY, + TOXIC_SHOCK_SYNDROME, + THROMBOCYTOPENIA, + ANAPHYLAXIS, + FEVERISH_FEELING); + + addField(SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS, CheckBox.class); + addField(SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT, CheckBox.class); + + Label emptyLabel = new Label(""); + emptyLabel.addStyleName(H3); + getContent().addComponent(emptyLabel, EMPTY_LABEL_LOC); + + NullableOptionGroup seizureType = addField(SEIZURE_TYPE, NullableOptionGroup.class); + CssStyles.style(seizureType, ValoTheme.OPTIONGROUP_HORIZONTAL, CssStyles.OPTIONGROUP_CAPTION_INLINE); + + TextArea otherAdverseEvents = addField(OTHER_ADVERSE_EVENT_DETAILS, TextArea.class); + otherAdverseEvents.setRows(6); + otherAdverseEvents.setDescription( + I18nProperties.getPrefixDescription(AdverseEventsDto.I18N_PREFIX, OTHER_ADVERSE_EVENT_DETAILS, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + initializeVisibilitiesAndAllowedVisibilities(); + initializeAccessAndAllowedAccesses(); + + FieldHelper.setVisibleWhen( + getFieldGroup(), + Arrays.asList(SEVERE_LOCAL_REACTION_MORE_THAN_THREE_DAYS, SEVERE_LOCAL_REACTION_BEYOND_NEAREST_JOINT), + SEVERE_LOCAL_REACTION, + Arrays.asList(AdverseEventState.YES), + true); + + FieldHelper.setVisibleWhen(getFieldGroup(), SEIZURE_TYPE, SEIZURES, Arrays.asList(AdverseEventState.YES), true); + } + + @Override + protected F addFieldToLayout(CustomLayout layout, String propertyId, F field) { + field.addValueChangeListener(e -> fireValueChange(false)); + + return super.addFieldToLayout(layout, propertyId, field); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AefiDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AefiDataForm.java new file mode 100644 index 00000000000..4b1411c561a --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/AefiDataForm.java @@ -0,0 +1,317 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form; + +import static de.symeda.sormas.ui.utils.CssStyles.FORCE_CAPTION; +import static de.symeda.sormas.ui.utils.CssStyles.H3; +import static de.symeda.sormas.ui.utils.CssStyles.H4; +import static de.symeda.sormas.ui.utils.LayoutUtil.divCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRow; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; + +import java.util.Arrays; +import java.util.function.Consumer; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.data.util.converter.Converter; +import com.vaadin.v7.ui.ComboBox; +import com.vaadin.v7.ui.DateField; +import com.vaadin.v7.ui.PasswordField; +import com.vaadin.v7.ui.TextArea; +import com.vaadin.v7.ui.TextField; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiOutcome; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.SeriousAefiReason; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines.AefiVaccinationsField; +import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.ButtonHelper; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; +import de.symeda.sormas.ui.utils.FieldHelper; +import de.symeda.sormas.ui.utils.NullableOptionGroup; +import de.symeda.sormas.ui.utils.UserField; + +@SuppressWarnings("deprecation") +public class AefiDataForm extends AbstractEditForm { + + private static final String ASSIGN_NEW_AEFI_ID_LOC = "assignNewAefiIdLoc"; + private static final String REPORTING_INFORMATION_HEADING_LOC = "reportingInformationHeadingLoc"; + private static final String PATIENTS_IDENTIFICATION_HEADING_LOC = "patientsIdentificationHeadingLoc"; + private static final String PATIENTS_IDENTIFICATION_AGE_AT_ONSET = "patientsIdentificationAgeAtOnsetHeadingLoc"; + private static final String VACCINATIONS_HEADING_LOC = "vaccinationsHeadingLoc"; + private static final String ADVERSE_EVENTS_HEADING_LOC = "adverseEventsHeadingLoc"; + private static final String FIRST_DECISION_LEVEL_HEADING_LOC = "firstDecisionLevelHeadingLoc"; + private static final String NATIONAL_DECISION_LEVEL_HEADING_LOC = "nationalDecisionLevelHeadingLoc"; + private static final String REPORTERS_INFORMATION_HEADING_LOC = "reportersInformationHeadingLoc"; + + //@formatter:off + private static final String HTML_LAYOUT = + divCss(CssStyles.VIEW_SECTION_MARGIN_TOP_4_MARGIN_X_4, + loc(REPORTING_INFORMATION_HEADING_LOC) + + fluidRowLocs(4, AefiDto.UUID, 4, AefiDto.REPORT_DATE, 3, AefiDto.REPORTING_USER) + + fluidRowLocs(4, AefiDto.RESPONSIBLE_REGION, 4, AefiDto.RESPONSIBLE_DISTRICT, 3, AefiDto.RESPONSIBLE_COMMUNITY) + + fluidRowLocs(4, AefiDto.REPORTING_ID_NUMBER, 3, ASSIGN_NEW_AEFI_ID_LOC) + ) + + divCss(CssStyles.VIEW_SECTION_MARGIN_X_4 + " " + CssStyles.VSPACE_TOP_3, + loc(PATIENTS_IDENTIFICATION_HEADING_LOC) + + fluidRowLocs(AefiDto.PREGNANT, AefiDto.TRIMESTER, AefiDto.LACTATING) + + loc(PATIENTS_IDENTIFICATION_AGE_AT_ONSET) + + fluidRow( + fluidRowLocs(AefiDto.ONSET_AGE_YEARS, AefiDto.ONSET_AGE_MONTHS, AefiDto.ONSET_AGE_DAYS), + fluidRowLocs(6, AefiDto.AGE_GROUP) + ) + ) + + divCss(CssStyles.VIEW_SECTION_MARGIN_X_4 + " " + CssStyles.VSPACE_TOP_3, + loc(VACCINATIONS_HEADING_LOC) + + fluidRowLocs(AefiDto.VACCINATIONS) + ) + + divCss(CssStyles.VIEW_SECTION_MARGIN_X_4 + " " + CssStyles.VSPACE_TOP_3, + loc(ADVERSE_EVENTS_HEADING_LOC) + + fluidRowLocs(AefiDto.ADVERSE_EVENTS) + + fluidRowLocs(6, AefiDto.START_DATE_TIME) + + fluidRowLocs(AefiDto.AEFI_DESCRIPTION) + + fluidRowLocs(4, AefiDto.SERIOUS, 4, AefiDto.SERIOUS_REASON, 4, AefiDto.SERIOUS_REASON_DETAILS) + + fluidRowLocs(AefiDto.OUTCOME) + + fluidRowLocs(4, AefiDto.DEATH_DATE, 4, AefiDto.AUTOPSY_DONE) + + fluidRowLocs(AefiDto.PAST_MEDICAL_HISTORY) + ) + + divCss(CssStyles.VIEW_SECTION_MARGIN_X_4 + " " + CssStyles.VSPACE_TOP_3, + loc(FIRST_DECISION_LEVEL_HEADING_LOC) + + fluidRowLocs(4, AefiDto.INVESTIGATION_NEEDED, 4, AefiDto.INVESTIGATION_PLANNED_DATE) + ) + + divCss(CssStyles.VIEW_SECTION_MARGIN_X_4 + " " + CssStyles.VSPACE_2 + " " + CssStyles.VSPACE_TOP_3, + loc(NATIONAL_DECISION_LEVEL_HEADING_LOC) + + fluidRowLocs(4, AefiDto.RECEIVED_AT_NATIONAL_LEVEL_DATE, 4, AefiDto.WORLD_WIDE_ID) + + fluidRowLocs(AefiDto.NATIONAL_LEVEL_COMMENT) + ); + //@formatter:on + + private boolean isCreateAction; + private final Consumer actionCallback; + private TextField responsibleRegion; + private TextField responsibleDistrict; + private TextField responsibleCommunity; + private AefiVaccinationsField vaccinationsField; + + public AefiDataForm(boolean isCreateAction, boolean isPseudonymized, boolean inJurisdiction, Consumer actionCallback) { + super( + AefiDto.class, + AefiDto.I18N_PREFIX, + false, + FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); + + this.isCreateAction = isCreateAction; + this.actionCallback = actionCallback; + + if (isCreateAction) { + hideValidationUntilNextCommit(); + } + + addFields(); + } + + @Override + protected String createHtmlLayout() { + return HTML_LAYOUT; + } + + @Override + protected void addFields() { + + Label reportingInformationHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiReportingInformation)); + reportingInformationHeadingLabel.addStyleName(H3); + getContent().addComponent(reportingInformationHeadingLabel, REPORTING_INFORMATION_HEADING_LOC); + + if (isCreateAction) { + addField(AefiDto.UUID, PasswordField.class); + } else { + addField(AefiDto.UUID); + } + addField(AefiDto.REPORT_DATE, DateField.class); + addField(AefiDto.REPORTING_USER, UserField.class); + + responsibleRegion = new TextField(I18nProperties.getPrefixCaption(AefiDto.I18N_PREFIX, AefiDto.RESPONSIBLE_REGION)); + getContent().addComponent(responsibleRegion, AefiDto.RESPONSIBLE_REGION); + responsibleDistrict = new TextField(I18nProperties.getPrefixCaption(AefiDto.I18N_PREFIX, AefiDto.RESPONSIBLE_DISTRICT)); + getContent().addComponent(responsibleDistrict, AefiDto.RESPONSIBLE_DISTRICT); + responsibleCommunity = new TextField(I18nProperties.getPrefixCaption(AefiDto.I18N_PREFIX, AefiDto.RESPONSIBLE_COMMUNITY)); + getContent().addComponent(responsibleCommunity, AefiDto.RESPONSIBLE_COMMUNITY); + + TextField reportIdField = addField(AefiDto.REPORTING_ID_NUMBER, TextField.class); + /* + * reportIdField.setInvalidCommitted(true); + * reportIdField.setMaxLength(24); + * style(reportIdField, ERROR_COLOR_PRIMARY); + */ + + // Button to automatically assign a new reporting ID + Button assignNewReportingIdNumberButton = ButtonHelper.createButton(Captions.actionAefiAssignNewReportingIdNumber, e -> { + }, ValoTheme.BUTTON_DANGER, FORCE_CAPTION); + + getContent().addComponent(assignNewReportingIdNumberButton, ASSIGN_NEW_AEFI_ID_LOC); + assignNewReportingIdNumberButton.setVisible(false); + + Label patientsIdentificationHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiPatientsIdentification)); + patientsIdentificationHeadingLabel.addStyleName(H3); + getContent().addComponent(patientsIdentificationHeadingLabel, PATIENTS_IDENTIFICATION_HEADING_LOC); + + addField(AefiDto.PREGNANT, NullableOptionGroup.class); + addField(AefiDto.TRIMESTER, NullableOptionGroup.class); + addField(AefiDto.LACTATING, NullableOptionGroup.class); + + Label patientsAgeAtOnsetHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiPatientsAgeAtOnset)); + patientsAgeAtOnsetHeadingLabel.addStyleName(H4); + getContent().addComponent(patientsAgeAtOnsetHeadingLabel, PATIENTS_IDENTIFICATION_AGE_AT_ONSET); + + TextField onsetAgeYearsField = addField(AefiDto.ONSET_AGE_YEARS, TextField.class); + onsetAgeYearsField + .setConversionError(I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, onsetAgeYearsField.getCaption())); + + TextField onsetAgeMonthsField = addField(AefiDto.ONSET_AGE_MONTHS, TextField.class); + onsetAgeMonthsField + .setConversionError(I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, onsetAgeMonthsField.getCaption())); + + TextField onsetAgeDaysField = addField(AefiDto.ONSET_AGE_DAYS, TextField.class); + onsetAgeDaysField + .setConversionError(I18nProperties.getValidationError(Validations.onlyIntegerNumbersAllowed, onsetAgeDaysField.getCaption())); + + addField(AefiDto.AGE_GROUP, ComboBox.class); + + Label vaccinationsHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiVaccinations)); + vaccinationsHeadingLabel.addStyleName(H3); + getContent().addComponent(vaccinationsHeadingLabel, VACCINATIONS_HEADING_LOC); + + vaccinationsField = addField(AefiDto.VACCINATIONS, AefiVaccinationsField.class); + + addField(AefiDto.ADVERSE_EVENTS, AdverseEventsForm.class).setCaption(null); + + final DateTimeField startDateField = addField(AefiDto.START_DATE_TIME, DateTimeField.class); + startDateField.setInvalidCommitted(false); + + TextArea aefiDescriptionField = addField(AefiDto.AEFI_DESCRIPTION, TextArea.class); + aefiDescriptionField.setRows(6); + aefiDescriptionField.setDescription( + I18nProperties.getPrefixDescription(AefiDto.I18N_PREFIX, AefiDto.AEFI_DESCRIPTION, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + addField(AefiDto.SERIOUS, NullableOptionGroup.class); + addField(AefiDto.SERIOUS_REASON, ComboBox.class); + addField(AefiDto.SERIOUS_REASON_DETAILS, TextField.class); + addField(AefiDto.OUTCOME, NullableOptionGroup.class); + addField(AefiDto.DEATH_DATE, DateField.class); + addField(AefiDto.AUTOPSY_DONE, NullableOptionGroup.class); + + TextArea pastMedicalHistoryField = addField(AefiDto.PAST_MEDICAL_HISTORY, TextArea.class); + pastMedicalHistoryField.setRows(6); + pastMedicalHistoryField.setDescription( + I18nProperties.getPrefixDescription(AefiDto.I18N_PREFIX, AefiDto.PAST_MEDICAL_HISTORY, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + Label firstDecisionLevelHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiFirstDecisionLevel)); + firstDecisionLevelHeadingLabel.addStyleName(H3); + getContent().addComponent(firstDecisionLevelHeadingLabel, FIRST_DECISION_LEVEL_HEADING_LOC); + + addField(AefiDto.INVESTIGATION_NEEDED, NullableOptionGroup.class); + addField(AefiDto.INVESTIGATION_PLANNED_DATE, DateField.class); + + Label nationalDecisionLevelHeadingLabel = new Label(I18nProperties.getString(Strings.headingAefiNationalDecisionLevel)); + nationalDecisionLevelHeadingLabel.addStyleName(H3); + getContent().addComponent(nationalDecisionLevelHeadingLabel, NATIONAL_DECISION_LEVEL_HEADING_LOC); + + addField(AefiDto.RECEIVED_AT_NATIONAL_LEVEL_DATE, DateField.class); + addField(AefiDto.WORLD_WIDE_ID, TextField.class); + + TextArea nationalLevelCommentField = addField(AefiDto.NATIONAL_LEVEL_COMMENT, TextArea.class); + nationalLevelCommentField.setRows(6); + nationalLevelCommentField.setDescription( + I18nProperties.getPrefixDescription(AefiDto.I18N_PREFIX, AefiDto.NATIONAL_LEVEL_COMMENT, "") + "\n" + + I18nProperties.getDescription(Descriptions.descGdpr)); + + //set visibility, read only and required status + FieldHelper.setVisibleWhen(getFieldGroup(), AefiDto.TRIMESTER, AefiDto.PREGNANT, Arrays.asList(YesNoUnknown.YES), true); + FieldHelper.setVisibleWhen(getFieldGroup(), AefiDto.SERIOUS_REASON, AefiDto.SERIOUS, Arrays.asList(YesNoUnknown.YES), true); + FieldHelper + .setVisibleWhen(getFieldGroup(), AefiDto.SERIOUS_REASON_DETAILS, AefiDto.SERIOUS_REASON, Arrays.asList(SeriousAefiReason.OTHER), true); + FieldHelper.setVisibleWhen( + getFieldGroup(), + Arrays.asList(AefiDto.DEATH_DATE, AefiDto.AUTOPSY_DONE), + AefiDto.OUTCOME, + Arrays.asList(AefiOutcome.DIED), + true); + FieldHelper + .setVisibleWhen(getFieldGroup(), AefiDto.INVESTIGATION_PLANNED_DATE, AefiDto.INVESTIGATION_NEEDED, Arrays.asList(YesNoUnknown.YES), true); + + setReadOnly(true, AefiDto.UUID, AefiDto.REPORTING_USER); + + setRequired(true, AefiDto.REPORT_DATE, AefiDto.REPORTING_ID_NUMBER, AefiDto.SERIOUS, AefiDto.OUTCOME); + FieldHelper.setRequiredWhen(getFieldGroup(), AefiDto.SERIOUS_REASON, Arrays.asList(AefiDto.SERIOUS_REASON), Arrays.asList(YesNoUnknown.YES)); + } + + @Override + public void attach() { + super.attach(); + + AefiDto dataFormValue = getValue(); + + ImmunizationDto immunizationDto = FacadeProvider.getImmunizationFacade().getByUuid(dataFormValue.getImmunization().getUuid()); + + responsibleRegion.setValue(immunizationDto.getResponsibleRegion().getCaption()); + responsibleDistrict.setValue(immunizationDto.getResponsibleDistrict().getCaption()); + if (immunizationDto.getResponsibleCommunity() != null) { + responsibleCommunity.setValue(immunizationDto.getResponsibleCommunity().getCaption()); + } + + responsibleRegion.setReadOnly(true); + responsibleDistrict.setReadOnly(true); + responsibleCommunity.setReadOnly(true); + + vaccinationsField.applyAefiReportContext(dataFormValue); + if (dataFormValue.getPrimarySuspectVaccine() != null) { + vaccinationsField.selectPrimarySuspectVaccination(dataFormValue.getPrimarySuspectVaccine()); + } + } + + @Override + public void setValue(AefiDto newFieldValue) throws ReadOnlyException, Converter.ConversionException { + super.setValue(newFieldValue); + + getValue(); + + // HACK: Binding to the fields will call field listeners that may clear/modify the values of other fields. + // this hopefully resets everything to its correct value + discard(); + } + + @Override + public void discard() throws SourceException { + super.discard(); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordion.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordion.java new file mode 100644 index 00000000000..ce435e84443 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordion.java @@ -0,0 +1,55 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.ui.Component; +import com.vaadin.ui.VerticalLayout; + +public class FormSectionAccordion extends VerticalLayout { + + private final List formSectionAccordionPanelList = new ArrayList<>(); + + public FormSectionAccordion() { + setMargin(false); + setSpacing(false); + setWidth(100, Unit.PERCENTAGE); + } + + public void addFormSectionPanel(String sectionTitleCaption, boolean expanded, Component component) { + + FormSectionAccordionPanel formSectionAccordionPanel = new FormSectionAccordionPanel(sectionTitleCaption, expanded, FormSectionAccordion.this); + formSectionAccordionPanel.addComponentToMainLayout(component); + + formSectionAccordionPanelList.add(formSectionAccordionPanel); + + addComponent(formSectionAccordionPanel); + } + + public void toggleFormSection(FormSectionAccordionPanel formSectionAccordionPanel) { + formSectionAccordionPanel.getMainLayout().setVisible(!formSectionAccordionPanel.isExpanded()); + formSectionAccordionPanel.setExpanded(!formSectionAccordionPanel.isExpanded()); + } + + public void toggleAllFormSections(boolean expanded) { + for (FormSectionAccordionPanel formSectionAccordionPanel : formSectionAccordionPanelList) { + formSectionAccordionPanel.getMainLayout().setVisible(!expanded); + formSectionAccordionPanel.setExpanded(!expanded); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordionPanel.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordionPanel.java new file mode 100644 index 00000000000..6e8cc33ef79 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/form/FormSectionAccordionPanel.java @@ -0,0 +1,77 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Component; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; + +import de.symeda.sormas.ui.utils.ButtonHelper; +import de.symeda.sormas.ui.utils.CssStyles; + +public class FormSectionAccordionPanel extends VerticalLayout { + + private final Button titleButton; + private final VerticalLayout mainLayout; + private final FormSectionAccordion formSectionAccordion; + private boolean expanded; + + public FormSectionAccordionPanel(String titleButtonCaption, boolean expanded, FormSectionAccordion formSectionAccordion) { + + this.expanded = expanded; + this.formSectionAccordion = formSectionAccordion; + + setMargin(false); + setSpacing(false); + setWidth(99, Unit.PERCENTAGE); + addStyleNames(CssStyles.VIEW_SECTION_MARGIN_X_4, CssStyles.VSPACE_3); + + titleButton = ButtonHelper.createButton(titleButtonCaption, (event) -> { + formSectionAccordion.toggleFormSection(FormSectionAccordionPanel.this); + }, ValoTheme.BUTTON_LINK, CssStyles.FORM_SECTION_ACCORDION_PANEL_TITLE_BUTTON); + addComponent(titleButton); + + mainLayout = new VerticalLayout(); + mainLayout.setMargin(false); + mainLayout.setSpacing(false); + //mainLayout.setWidth(100, Unit.PERCENTAGE); + mainLayout.setVisible(expanded); + mainLayout.addStyleNames(CssStyles.VSPACE_TOP_3); + + addComponent(mainLayout); + } + + public void addComponentToMainLayout(Component component) { + mainLayout.addComponent(component); + } + + public Button getTitleButton() { + return titleButton; + } + + public VerticalLayout getMainLayout() { + return mainLayout; + } + + public boolean isExpanded() { + return expanded; + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiImmunizationInfo.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiImmunizationInfo.java new file mode 100644 index 00000000000..94341c9e0bd --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiImmunizationInfo.java @@ -0,0 +1,109 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information; + +import java.util.function.Consumer; + +import com.vaadin.ui.Alignment; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.immunization.ImmunizationListEntryDto; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; + +public class AefiImmunizationInfo extends SideComponent { + + public static final String SEPARATOR = ": "; + + private ImmunizationDto immunization; + private final VerticalLayout mainLayout; + + public AefiImmunizationInfo(ImmunizationDto immunization, Consumer actionCallback) { + super(I18nProperties.getString(Strings.entityImmunization), actionCallback); + + this.immunization = immunization; + mainLayout = new VerticalLayout(); + mainLayout.setWidth(100, Unit.PERCENTAGE); + mainLayout.setMargin(false); + mainLayout.setSpacing(false); + + buildMainLayout(); + addComponent(mainLayout); + } + + public void buildMainLayout() { + + HorizontalLayout uuidReportLayout = new HorizontalLayout(); + uuidReportLayout.setMargin(false); + uuidReportLayout.setSpacing(true); + + Label immunizationUuidLabel = new Label(DataHelper.getShortUuid(immunization.getUuid())); + immunizationUuidLabel.setDescription(immunization.getUuid()); + CssStyles.style(immunizationUuidLabel, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + uuidReportLayout.addComponent(immunizationUuidLabel); + + Label diseaseLabel = new Label(DataHelper.toStringNullable(immunization.getDisease())); + CssStyles.style(diseaseLabel, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + uuidReportLayout.addComponent(diseaseLabel); + + uuidReportLayout.setWidthFull(); + uuidReportLayout.setComponentAlignment(immunizationUuidLabel, Alignment.MIDDLE_LEFT); + uuidReportLayout.setComponentAlignment(diseaseLabel, Alignment.MIDDLE_RIGHT); + mainLayout.addComponent(uuidReportLayout); + + HorizontalLayout meansOfImmunizationLayout = new HorizontalLayout(); + Label meansOfImmunizationLabel = new Label( + I18nProperties.getPrefixCaption(ImmunizationListEntryDto.I18N_PREFIX, ImmunizationListEntryDto.MEANS_OF_IMMUNIZATION) + + SEPARATOR + + DataHelper.toStringNullable(immunization.getMeansOfImmunization())); + meansOfImmunizationLayout.addComponent(meansOfImmunizationLabel); + mainLayout.addComponent(meansOfImmunizationLayout); + + HorizontalLayout immunizationStatusLayout = new HorizontalLayout(); + Label immunizationStatusLabel = new Label( + I18nProperties.getPrefixCaption(ImmunizationListEntryDto.I18N_PREFIX, ImmunizationListEntryDto.IMMUNIZATION_STATUS) + + SEPARATOR + + DataHelper.toStringNullable(immunization.getImmunizationStatus())); + immunizationStatusLayout.addComponent(immunizationStatusLabel); + mainLayout.addComponent(immunizationStatusLayout); + + HorizontalLayout managementStatusLayout = new HorizontalLayout(); + Label managementStatusLabel = new Label( + I18nProperties.getPrefixCaption(ImmunizationListEntryDto.I18N_PREFIX, ImmunizationListEntryDto.IMMUNIZATION_MANAGEMENT_STATUS) + + SEPARATOR + + DataHelper.toStringNullable(immunization.getImmunizationManagementStatus())); + managementStatusLayout.addComponent(managementStatusLabel); + mainLayout.addComponent(managementStatusLayout); + + HorizontalLayout immunizationPeriodLayout = new HorizontalLayout(); + Label reportDateLabel = new Label( + I18nProperties.getPrefixCaption(ImmunizationListEntryDto.I18N_PREFIX, ImmunizationListEntryDto.IMMUNIZATION_PERIOD) + + SEPARATOR + + DateFormatHelper.buildPeriodString(immunization.getStartDate(), immunization.getEndDate())); + immunizationPeriodLayout.addComponent(reportDateLabel); + mainLayout.addComponent(immunizationPeriodLayout); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiInfo.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiInfo.java new file mode 100644 index 00000000000..43824207209 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiInfo.java @@ -0,0 +1,89 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information; + +import java.util.function.Consumer; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiHelper; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListEntryDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; + +public class AefiInfo extends SideComponent { + + public static final String SEPARATOR = ": "; + + private AefiDto aefi; + private final VerticalLayout mainLayout; + + public AefiInfo(AefiDto aefi, Consumer actionCallback) { + super(I18nProperties.getString(Strings.entityAdverseEvent), actionCallback); + + this.aefi = aefi; + mainLayout = new VerticalLayout(); + mainLayout.setWidth(100, Unit.PERCENTAGE); + mainLayout.setMargin(false); + mainLayout.setSpacing(false); + + buildMainLayout(); + addComponent(mainLayout); + } + + public void buildMainLayout() { + + Label labelAefiType = new Label(AefiType.toString(aefi.getSerious())); + CssStyles.style(labelAefiType, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + if (aefi.getSerious() == YesNoUnknown.YES) { + CssStyles.style(labelAefiType, CssStyles.LABEL_CRITICAL); + } + mainLayout.addComponent(labelAefiType); + + Label labelVaccineName = new Label(aefi.getPrimarySuspectVaccine().getVaccineName().toString()); + CssStyles.style(labelVaccineName, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + mainLayout.addComponent(labelVaccineName); + + if (!StringUtils.isBlank(aefi.getPrimarySuspectVaccine().getVaccineDose())) { + Label labelVaccineDose = new Label( + I18nProperties.getPrefixCaption(VaccinationDto.I18N_PREFIX, VaccinationDto.VACCINE_DOSE) + + SEPARATOR + + aefi.getPrimarySuspectVaccine().getVaccineDose()); + CssStyles.style(labelVaccineDose, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + mainLayout.addComponent(labelVaccineDose); + } + + Label labelVaccineDate = new Label( + I18nProperties.getPrefixCaption(AefiListEntryDto.I18N_PREFIX, AefiListEntryDto.PRIMARY_VACCINE_VACCINATION_DATE) + + SEPARATOR + + DateFormatHelper.formatLocalDate(aefi.getPrimarySuspectVaccine().getVaccinationDate())); + mainLayout.addComponent(labelVaccineDate); + + Label labelAdverseEvents = new Label(StringUtils.abbreviate(AefiHelper.buildAdverseEventsString(aefi.getAdverseEvents()), 56)); + CssStyles.style(labelAdverseEvents, CssStyles.LABEL_BOLD, CssStyles.LABEL_UPPERCASE); + mainLayout.addComponent(labelAdverseEvents); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiPersonInfo.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiPersonInfo.java new file mode 100644 index 00000000000..c8bc7373e0a --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/adverseeventsfollowingimmunization/components/information/AefiPersonInfo.java @@ -0,0 +1,135 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.information; + +import com.vaadin.server.Sizeable; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.person.ApproximateAgeType; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.ui.AbstractInfoLayout; +import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.FieldAccessHelper; + +@SuppressWarnings("serial") +public class AefiPersonInfo extends AbstractInfoLayout { + + public static final String PERSON_FULL_NAME = "personFullName"; + public static final String DISEASE = "disease"; + + private PersonDto personDto; + private Disease disease; + + public AefiPersonInfo(PersonDto personDto, Disease disease) { + super(PersonDto.class, FieldAccessHelper.getFieldAccessCheckers(personDto)); + + this.personDto = personDto; + this.disease = disease; + + setSpacing(true); + setMargin(false); + setWidth(100, Unit.PERCENTAGE); + updatePersonInfo(); + } + + private void updatePersonInfo() { + + this.removeAllComponents(); + + VerticalLayout mainLayout = new VerticalLayout(); + mainLayout.setWidth(100, Sizeable.Unit.PERCENTAGE); + CssStyles.style(mainLayout, CssStyles.PADDING_NONE); + + HorizontalLayout componentHeader = new HorizontalLayout(); + componentHeader.setMargin(false); + componentHeader.setSpacing(false); + componentHeader.setWidth(100, Sizeable.Unit.PERCENTAGE); + + Label headingLabel = new Label(I18nProperties.getString(Strings.headingPersonInformation)); + headingLabel.addStyleName(CssStyles.H3); + componentHeader.addComponent(headingLabel); + componentHeader.setExpandRatio(headingLabel, 1); + + HorizontalLayout infoColumnsLayout = new HorizontalLayout(); + infoColumnsLayout.setMargin(false); + infoColumnsLayout.setSpacing(false); + infoColumnsLayout.setWidth(100, Sizeable.Unit.PERCENTAGE); + + VerticalLayout leftColumnLayout = new VerticalLayout(); + leftColumnLayout.setMargin(false); + leftColumnLayout.setSpacing(true); + boolean hasUserRightPersonView = UserProvider.getCurrent().hasUserRight(UserRight.PERSON_VIEW); + { + final Label personIdLabel = addDescLabel( + leftColumnLayout, + PersonDto.UUID, + DataHelper.getShortUuid(personDto.getUuid()), + I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.UUID)); + personIdLabel.setId("personIdLabel"); + personIdLabel.setDescription(personDto.getUuid()); + + if (hasUserRightPersonView) { + addDescLabel(leftColumnLayout, PersonDto.LAST_NAME, personDto.buildCaption(), I18nProperties.getCaption(PERSON_FULL_NAME)); + + HorizontalLayout ageSexLayout = new HorizontalLayout(); + ageSexLayout.setMargin(false); + ageSexLayout.setSpacing(true); + addCustomDescLabel( + ageSexLayout, + PersonDto.class, + PersonDto.APPROXIMATE_AGE, + ApproximateAgeType.ApproximateAgeHelper.formatApproximateAge(personDto.getApproximateAge(), personDto.getApproximateAgeType()), + I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.APPROXIMATE_AGE)); + addCustomDescLabel( + ageSexLayout, + PersonDto.class, + PersonDto.SEX, + personDto.getSex(), + I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.SEX)); + leftColumnLayout.addComponent(ageSexLayout); + } + } + infoColumnsLayout.addComponent(leftColumnLayout); + + VerticalLayout rightColumnLayout = new VerticalLayout(); + rightColumnLayout.setMargin(false); + rightColumnLayout.setSpacing(true); + { + addDescLabel(rightColumnLayout, DISEASE, disease, I18nProperties.getPrefixCaption(ImmunizationDto.I18N_PREFIX, ImmunizationDto.DISEASE)); + + addDescLabel( + rightColumnLayout, + PersonDto.PHONE, + personDto.getPhone(), + I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.PHONE)); + } + infoColumnsLayout.addComponent(rightColumnLayout); + + mainLayout.addComponent(componentHeader); + mainLayout.addComponent(infoColumnsLayout); + + this.addComponent(mainLayout); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/BulkCaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/BulkCaseDataForm.java index 1df2dc6f717..4cdcf912dd1 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/BulkCaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/BulkCaseDataForm.java @@ -169,7 +169,7 @@ protected void addFields() { diseaseCheckBox = new CheckBox(I18nProperties.getCaption(Captions.bulkDisease)); diseaseCheckBox.setReadOnly(!UiUtil.permitted(UserRight.CASE_CHANGE_DISEASE)); getContent().addComponent(diseaseCheckBox, DISEASE_CHECKBOX); - ComboBox diseaseField = addDiseaseField(CaseBulkEditData.DISEASE, false); + ComboBox diseaseField = addDiseaseField(CaseBulkEditData.DISEASE, false, false); diseaseField.setEnabled(false); addField(CaseBulkEditData.DISEASE_DETAILS, TextField.class); addField(CaseBulkEditData.PLAGUE_TYPE, NullableOptionGroup.class); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index f6f1a2cb389..2c0b8db9493 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -110,7 +110,6 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.uuid.HasUuid; import de.symeda.sormas.api.visit.VisitDto; import de.symeda.sormas.ui.ControllerProvider; @@ -131,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; @@ -141,6 +141,7 @@ import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DeleteRestoreHandlers; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.VaadinUiUtil; import de.symeda.sormas.ui.utils.ViewMode; @@ -151,6 +152,9 @@ public class CaseController { + private CommitDiscardWrapperComponent caseCreateComponent; + private boolean caseSaveTriggered; + public CaseController() { } @@ -187,7 +191,7 @@ public void registerViews(Navigator navigator) { } public void create() { - CommitDiscardWrapperComponent caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false); + caseCreateComponent = getCaseCreateComponent(null, null, null, null, null, false); VaadinUiUtil.showModalPopupWindow(caseCreateComponent, I18nProperties.getString(Strings.headingCreateNewCase)); } @@ -718,6 +722,7 @@ public CommitDiscardWrapperComponent getCaseCreateComponent( editView.addFieldGroups(createForm.getHomeAddressForm().getFieldGroup()); } + caseSaveTriggered = false; editView.addCommitListener(() -> { if (!createForm.getFieldGroup().isModified()) { final CaseDataDto dto = createForm.getValue(); @@ -835,25 +840,55 @@ public CommitDiscardWrapperComponent 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 warningPopUpDuplicatePerson = + (CommitDiscardWrapperComponent) 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) { @@ -1298,8 +1333,7 @@ public CommitDiscardWrapperComponent getSymptomsEditComponent(fina person, SymptomsContext.CASE, viewMode, - UiFieldAccessCheckers - .forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(caseDataDto.isInJurisdiction()), caseDataDto.isPseudonymized())); + FieldAccessHelper.getFieldAccessCheckers(caseDataDto)); symptomsForm.setValue(caseDataDto.getSymptoms()); CommitDiscardWrapperComponent editView = @@ -1381,9 +1415,7 @@ public DetailSubComponentWrapper getExternalDataComponent(final String caseUuid, CaseDataDto caseDataDto = findCase(caseUuid); - CaseExternalDataForm caseExternalDataForm = new CaseExternalDataForm( - UiFieldAccessCheckers - .forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(caseDataDto.isInJurisdiction()), caseDataDto.isPseudonymized())); + CaseExternalDataForm caseExternalDataForm = new CaseExternalDataForm(FieldAccessHelper.getFieldAccessCheckers(caseDataDto)); caseExternalDataForm.setValue(caseDataDto); DetailSubComponentWrapper wrapper = new DetailSubComponentWrapper(() -> null); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java index d118187e0f1..0d9c5b85bff 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java @@ -31,10 +31,12 @@ import java.util.Date; import java.util.List; +import de.symeda.sormas.api.caze.CaseClassification; import org.apache.commons.collections4.CollectionUtils; 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; @@ -72,6 +74,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; @@ -111,6 +114,7 @@ public class CaseCreateForm extends AbstractEditForm { private NullableOptionGroup ogCaseOrigin; private PersonCreateForm personCreateForm; + private Window warningSimilarPersons; private final boolean showHomeAddressForm; private final boolean showPersonSearchButton; @@ -192,7 +196,7 @@ protected void addFields() { addField(CaseDataDto.CASE_REFERENCE_NUMBER, TextField.class); addField(CaseDataDto.REPORT_DATE, DateField.class); - ComboBox diseaseField = addDiseaseField(CaseDataDto.DISEASE, false, true); + ComboBox diseaseField = addDiseaseField(CaseDataDto.DISEASE, false, true, false); diseaseVariantField = addField(CaseDataDto.DISEASE_VARIANT, ComboBox.class); diseaseVariantDetailsField = addField(CaseDataDto.DISEASE_VARIANT_DETAILS, TextField.class); diseaseVariantDetailsField.setVisible(false); @@ -209,6 +213,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); @@ -544,6 +553,15 @@ private void updateDiseaseVariant(Disease disease) { FieldHelper.updateItems(diseaseVariantField, diseaseVariants); diseaseVariantField .setVisible(disease != null && isVisibleAllowed(CaseDataDto.DISEASE_VARIANT) && CollectionUtils.isNotEmpty(diseaseVariants)); + if (disease == Disease.INFLUENZA) { + facilityOrHome.setValue(Sets.newHashSet(TypeOfPlace.HOME)); + facilityOrHome.select(TypeOfPlace.HOME); + getValue().setCaseClassification(CaseClassification.CONFIRMED); + } else { + facilityOrHome.setValue(null); + facilityOrHome.unselect(TypeOfPlace.HOME); + getValue().setCaseClassification(CaseClassification.NOT_CLASSIFIED); + } } private void setNoneFacility() { @@ -730,4 +748,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; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index 5fc2d4a525b..94a3cac8154 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -118,7 +118,6 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.ExtendedReduced; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.api.utils.fieldvisibility.checkers.CountryFieldVisibilityChecker; import de.symeda.sormas.api.utils.fieldvisibility.checkers.FeatureTypeFieldVisibilityChecker; @@ -135,6 +134,7 @@ import de.symeda.sormas.ui.utils.ConfirmationComponent; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.InfrastructureFieldsHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -327,7 +327,7 @@ public CaseDataForm( .add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())) .add(new UserRightFieldVisibilityChecker(UiUtil::permitted)) .add(new FeatureTypeFieldVisibilityChecker(FacadeProvider.getFeatureConfigurationFacade().getActiveServerFeatureConfigurations())), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.caseUuid = caseUuid; this.person = person; @@ -453,7 +453,7 @@ protected void addFields() { Collections.singletonList(CaseIdentificationSource.SCREENING), true); - ComboBox diseaseField = addDiseaseField(CaseDataDto.DISEASE, false); + ComboBox diseaseField = addDiseaseField(CaseDataDto.DISEASE, false, false); ComboBox diseaseVariantField = addCustomizableEnumField(CaseDataDto.DISEASE_VARIANT); TextField diseaseVariantDetailsField = addField(CaseDataDto.DISEASE_VARIANT_DETAILS, TextField.class); diseaseVariantDetailsField.setVisible(false); @@ -523,19 +523,6 @@ protected void addFields() { caseClassificationGroup.removeItem(CaseClassification.CONFIRMED_UNKNOWN_SYMPTOMS); } - if (diseaseClassificationExists() && FacadeProvider.getConfigFacade().getCaseClassificationCalculationMode(disease).isManualEnabled()) { - Button caseClassificationCalculationButton = ButtonHelper.createButton(Captions.caseClassificationCalculationButton, e -> { - CaseClassification classification = FacadeProvider.getCaseClassificationFacade().getClassification(getValue()); - ((Field) getField(CaseDataDto.CASE_CLASSIFICATION)).setValue(classification); - }, ValoTheme.BUTTON_PRIMARY, FORCE_CAPTION); - - getContent().addComponent(caseClassificationCalculationButton, CASE_CLASSIFICATION_CALCULATE_BTN_LOC); - - if (!UiUtil.permitted(UserRight.CASE_CLASSIFY)) { - caseClassificationCalculationButton.setEnabled(false); - } - } - boolean extendedClassification = FacadeProvider.getDiseaseConfigurationFacade().usesExtendedClassification(disease); if (extendedClassification) { @@ -949,10 +936,13 @@ protected void addFields() { CssStyles.style(additionalDetails, CssStyles.CAPTION_HIDDEN); addField(CaseDataDto.PREGNANT, NullableOptionGroup.class); + addField(CaseDataDto.POSTPARTUM, NullableOptionGroup.class); addField(CaseDataDto.TRIMESTER, NullableOptionGroup.class); + FieldHelper.setVisibleWhen(getFieldGroup(), CaseDataDto.TRIMESTER, CaseDataDto.PREGNANT, Arrays.asList(YesNoUnknown.YES), true); - addField(CaseDataDto.VACCINATION_STATUS); + addField(CaseDataDto.VACCINATION_STATUS, TextField.class); +// getContent().addComponent(new Label("Debug vaccination"), CaseDataDto.VACCINATION_STATUS); addFields(CaseDataDto.SMALLPOX_VACCINATION_SCAR, CaseDataDto.SMALLPOX_VACCINATION_RECEIVED); addDateField(CaseDataDto.SMALLPOX_LAST_VACCINATION_DATE, DateField.class, 0); @@ -1020,6 +1010,8 @@ protected void addFields() { } }); + addField(CaseDataDto.HEALTH_CONDITIONS, HealthConditionsForm.class).setCaption(null); + // Set initial visibilities & accesses initializeVisibilitiesAndAllowedVisibilities(); initializeAccessAndAllowedAccesses(); @@ -1033,6 +1025,22 @@ protected void addFields() { CaseDataDto.OUTCOME, CaseDataDto.DISEASE); setSoftRequired(true, CaseDataDto.INVESTIGATED_DATE, CaseDataDto.OUTCOME_DATE, CaseDataDto.PLAGUE_TYPE, CaseDataDto.SURVEILLANCE_OFFICER); + + if (diseaseClassificationExists() + && FacadeProvider.getConfigFacade().getCaseClassificationCalculationMode(disease).isManualEnabled() + && isVisibleAllowed(CaseDataDto.CASE_CLASSIFICATION)) { + Button caseClassificationCalculationButton = ButtonHelper.createButton(Captions.caseClassificationCalculationButton, e -> { + CaseClassification classification = FacadeProvider.getCaseClassificationFacade().getClassification(getValue()); + ((Field) getField(CaseDataDto.CASE_CLASSIFICATION)).setValue(classification); + }, ValoTheme.BUTTON_PRIMARY, FORCE_CAPTION); + + getContent().addComponent(caseClassificationCalculationButton, CASE_CLASSIFICATION_CALCULATE_BTN_LOC); + + if (!UiUtil.permitted(UserRight.CASE_CLASSIFY)) { + caseClassificationCalculationButton.setEnabled(false); + } + } + if (isEditableAllowed(CaseDataDto.INVESTIGATED_DATE)) { FieldHelper.setVisibleWhen( getFieldGroup(), @@ -1082,8 +1090,6 @@ protected void addFields() { differentPlaceOfStayJurisdiction.setVisible(false); } - FieldHelper.setVisibleWhen(getFieldGroup(), CaseDataDto.TRIMESTER, CaseDataDto.PREGNANT, Arrays.asList(YesNoUnknown.YES), true); - diseaseField.addValueChangeListener((ValueChangeListener) valueChangeEvent -> { Disease disease = (Disease) valueChangeEvent.getProperty().getValue(); List diseaseVariants = @@ -1206,8 +1212,6 @@ protected void addFields() { List medicalInformationFields = Arrays.asList(CaseDataDto.PREGNANT, CaseDataDto.VACCINATION_STATUS, CaseDataDto.SMALLPOX_VACCINATION_RECEIVED); - addField(CaseDataDto.HEALTH_CONDITIONS, HealthConditionsForm.class).setCaption(null); - for (String medicalInformationField : medicalInformationFields) { if (getFieldGroup().getField(medicalInformationField).isVisible()) { Label medicalInformationCaptionLabel = new Label(I18nProperties.getString(Strings.headingMedicalInformation)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java index cd651e8c8d2..c495eb0d07d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java @@ -62,6 +62,7 @@ import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractFilterForm; +import de.symeda.sormas.ui.utils.BirthdateRangeFilterComponent; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; import de.symeda.sormas.ui.utils.FieldConfiguration; @@ -72,6 +73,7 @@ public class CaseFilterForm extends AbstractFilterForm { private static final long serialVersionUID = -8326451364091398731L; private static final String WEEK_AND_DATE_FILTER = "moreFilters"; + private static final String BIRTHDATE_RANGE_FILTER = "birthdateRangeFilter"; private static final String MORE_FILTERS_HTML_LAYOUT = filterLocs( CaseCriteria.PRESENT_CONDITION, @@ -114,7 +116,8 @@ public class CaseFilterForm extends AbstractFilterForm { CaseCriteria.ONLY_ENTITIES_SHARED_WITH_EXTERNAL_SURV_TOOL, CaseCriteria.ONLY_ENTITIES_CHANGED_SINCE_LAST_SHARED_WITH_EXTERNAL_SURV_TOOL, CaseCriteria.ONLY_CASES_WITH_DONT_SHARE_WITH_EXTERNAL_SURV_TOOL) - + loc(WEEK_AND_DATE_FILTER); + + loc(WEEK_AND_DATE_FILTER) + + loc(BIRTHDATE_RANGE_FILTER); protected CaseFilterForm() { super( @@ -365,7 +368,8 @@ public void addMoreFilters(CustomLayout moreFiltersContainer) { CaseCriteria.ONLY_CASES_WITH_EVENTS, I18nProperties.getCaption(Captions.caseFilterRelatedToEvent), I18nProperties.getDescription(Descriptions.descCaseFilterRelatedToEvent), - CssStyles.CHECKBOX_FILTER_INLINE)).setVisible(UiUtil.permitted(UserRight.EVENT_VIEW)); + CssStyles.CHECKBOX_FILTER_INLINE)) + .setVisible(UiUtil.permitted(UserRight.EVENT_VIEW)); addField( moreFiltersContainer, @@ -448,6 +452,8 @@ public void addMoreFilters(CustomLayout moreFiltersContainer) { } moreFiltersContainer.addComponent(buildWeekAndDateFilter(isExternalShareEnabled), WEEK_AND_DATE_FILTER); + + moreFiltersContainer.addComponent(buildBirthdayRangeFilter(), BIRTHDATE_RANGE_FILTER); } @Override @@ -829,6 +835,19 @@ private HorizontalLayout buildWeekAndDateFilter(boolean isExternalShareEnabled) return dateFilterRowLayout; } + private HorizontalLayout buildBirthdayRangeFilter() { + BirthdateRangeFilterComponent birthdateRangeFilterComponent = new BirthdateRangeFilterComponent(false, this); + addApplyHandler(e -> onApplyClick(birthdateRangeFilterComponent)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(birthdateRangeFilterComponent); + + return dateFilterRowLayout; + } + private void onApplyClick(EpiWeekAndDateFilterComponent weekAndDateFilter) { DateFilterOption dateFilterOption = (DateFilterOption) weekAndDateFilter.getDateFilterOptionFilter().getValue(); Date fromDate, toDate; @@ -852,6 +871,18 @@ private void onApplyClick(EpiWeekAndDateFilterComponent weekAn } } + private void onApplyClick(BirthdateRangeFilterComponent birthdateRangeFilter) { + Date birthdateFrom, birthdateTo; + Date dateFrom = birthdateRangeFilter.getDateFromFilter().getValue(); + birthdateFrom = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = birthdateRangeFilter.getDateToFilter().getValue(); + birthdateTo = dateTo != null ? DateHelper.getEndOfDay(dateTo) : null; + CaseCriteria criteria = getValue(); + criteria.setBirthdateFrom(birthdateFrom); + criteria.setBirthdateTo(birthdateTo); + criteria.setIncludePartialMatch(birthdateRangeFilter.getIncludePartialMatch().getValue()); + } + @Override public void setValue(CaseCriteria newCriteria) throws ReadOnlyException, Converter.ConversionException { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java index fd7a689f335..529827e3de6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java @@ -32,11 +32,11 @@ import de.symeda.sormas.api.symptoms.SymptomsDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.ui.AbstractInfoLayout; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.FieldAccessHelper; @SuppressWarnings("serial") public class CaseInfoLayout extends AbstractInfoLayout { @@ -49,10 +49,7 @@ public CaseInfoLayout(CaseDataDto caseDto) { } public CaseInfoLayout(CaseDataDto caseDto, boolean isTravelEntry) { - super( - CaseDataDto.class, - UiFieldAccessCheckers - .forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(caseDto.isInJurisdiction()), caseDto.isPseudonymized())); + super(CaseDataDto.class, FieldAccessHelper.getFieldAccessCheckers(caseDto)); this.caseDto = caseDto; this.isTravelEntry = isTravelEntry; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/maternalhistory/MaternalHistoryForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/maternalhistory/MaternalHistoryForm.java index 9bfc0a029ed..75a24f1bb71 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/maternalhistory/MaternalHistoryForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/maternalhistory/MaternalHistoryForm.java @@ -18,10 +18,9 @@ import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.ViewMode; @@ -55,7 +54,7 @@ public MaternalHistoryForm(ViewMode viewMode, boolean isPseudonymized, boolean i MaternalHistoryDto.I18N_PREFIX, true, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.viewMode = viewMode; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/porthealthinfo/PortHealthInfoForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/porthealthinfo/PortHealthInfoForm.java index 52abe79dec9..2fecf46b4c4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/porthealthinfo/PortHealthInfoForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/porthealthinfo/PortHealthInfoForm.java @@ -24,13 +24,12 @@ import de.symeda.sormas.api.infrastructure.pointofentry.PointOfEntryReferenceDto; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -83,7 +82,7 @@ public PortHealthInfoForm(PointOfEntryDto pointOfEntry, String pointOfEntryDetai PortHealthInfoDto.I18N_PREFIX, false, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), pseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, pseudonymized)); this.pointOfEntry = pointOfEntry; this.pointOfEntryDetails = pointOfEntryDetails; this.pseudonymized = pseudonymized; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/surveillancereport/SurveillanceReportForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/surveillancereport/SurveillanceReportForm.java index dfd24c9a6b2..880ee52d8d6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/surveillancereport/SurveillanceReportForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/surveillancereport/SurveillanceReportForm.java @@ -24,10 +24,9 @@ import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.ComboBoxHelper; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.InfrastructureFieldsHelper; public class SurveillanceReportForm extends AbstractEditForm { @@ -46,12 +45,7 @@ public class SurveillanceReportForm extends AbstractEditForm { @@ -19,7 +18,7 @@ public ClinicalCourseForm(boolean isPseudonymized, boolean inJurisdiction) { ClinicalCourseDto.I18N_PREFIX, true, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); } @Override diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitForm.java index 36b9e4926a0..ce80ece4dbe 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitForm.java @@ -6,6 +6,7 @@ import com.vaadin.v7.ui.TextField; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.clinicalcourse.ClinicalVisitDto; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -36,7 +37,10 @@ public ClinicalVisitForm(boolean create, Disease disease, PersonDto person, bool ClinicalVisitDto.I18N_PREFIX, false, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + UiFieldAccessCheckers.forDataAccessLevel( + UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), + isPseudonymized, + FacadeProvider.getConfigFacade().getCountryLocale())); if (create) { hideValidationUntilNextCommit(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitGrid.java index 1318e7b3e78..fbebeec4aa3 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalVisitGrid.java @@ -66,8 +66,9 @@ public ClinicalVisitGrid(CaseReferenceDto caseRef, boolean isPseudonymized, bool } setCellStyleGenerator( - FieldAccessCellStyleGenerator - .withFieldAccessCheckers(ClinicalVisitIndexDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + ClinicalVisitIndexDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); addItemClickListener(e -> { if (ACTION_BTN_ID.equals(e.getPropertyId()) || e.isDoubleClick()) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java index c377cb9281f..c99568bef0b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java @@ -31,6 +31,7 @@ import static de.symeda.sormas.ui.utils.LayoutUtil.locs; import java.util.Arrays; +import java.util.List; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; @@ -38,6 +39,7 @@ import com.vaadin.v7.ui.TextArea; import de.symeda.sormas.api.clinicalcourse.HealthConditionsDto; +import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -45,6 +47,7 @@ import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.FieldHelper; public class HealthConditionsForm extends AbstractEditForm { @@ -52,6 +55,7 @@ public class HealthConditionsForm extends AbstractEditForm private static final long serialVersionUID = 1L; private static final String HEALTH_CONDITIONS_HEADINGS_LOC = "healthConditionsHeadingLoc"; + private static final String CONFIDENTIAL_LABEL_LOC = "confidentialLabel"; //@formatter:off private static final String HTML_LAYOUT = @@ -65,10 +69,33 @@ public class HealthConditionsForm extends AbstractEditForm CHRONIC_HEART_FAILURE, CHRONIC_PULMONARY_DISEASE, CHRONIC_KIDNEY_DISEASE, CHRONIC_NEUROLOGIC_CONDITION, CARDIOVASCULAR_DISEASE_INCLUDING_HYPERTENSION, OBESITY, CURRENT_SMOKER, FORMER_SMOKER, ASTHMA, SICKLE_CELL_DISEASE)) - ) + - loc(OTHER_CONDITIONS); + ) + loc(OTHER_CONDITIONS) + loc(CONFIDENTIAL_LABEL_LOC); //@formatter:on + private static final List fieldsList = List.of( + TUBERCULOSIS, + ASPLENIA, + HEPATITIS, + DIABETES, + HIV, + HIV_ART, + CHRONIC_LIVER_DISEASE, + MALIGNANCY_CHEMOTHERAPY, + CHRONIC_HEART_FAILURE, + CHRONIC_PULMONARY_DISEASE, + CHRONIC_KIDNEY_DISEASE, + CHRONIC_NEUROLOGIC_CONDITION, + DOWN_SYNDROME, + CONGENITAL_SYPHILIS, + IMMUNODEFICIENCY_OTHER_THAN_HIV, + CARDIOVASCULAR_DISEASE_INCLUDING_HYPERTENSION, + OBESITY, + CURRENT_SMOKER, + FORMER_SMOKER, + ASTHMA, + SICKLE_CELL_DISEASE, + IMMUNODEFICIENCY_INCLUDING_HIV); + public HealthConditionsForm(FieldVisibilityCheckers fieldVisibilityCheckers, UiFieldAccessCheckers fieldAccessCheckers) { super(HealthConditionsDto.class, I18N_PREFIX, true, fieldVisibilityCheckers, fieldAccessCheckers); } @@ -80,39 +107,18 @@ protected void addFields() { healthConditionsHeadingLabel.addStyleName(H3); getContent().addComponent(healthConditionsHeadingLabel, HEALTH_CONDITIONS_HEADINGS_LOC); - addFields( - TUBERCULOSIS, - ASPLENIA, - HEPATITIS, - DIABETES, - HIV, - HIV_ART, - CHRONIC_LIVER_DISEASE, - MALIGNANCY_CHEMOTHERAPY, - CHRONIC_HEART_FAILURE, - CHRONIC_PULMONARY_DISEASE, - CHRONIC_KIDNEY_DISEASE, - CHRONIC_NEUROLOGIC_CONDITION, - DOWN_SYNDROME, - CONGENITAL_SYPHILIS, - IMMUNODEFICIENCY_OTHER_THAN_HIV, - CARDIOVASCULAR_DISEASE_INCLUDING_HYPERTENSION, - OBESITY, - CURRENT_SMOKER, - FORMER_SMOKER, - ASTHMA, - SICKLE_CELL_DISEASE, - IMMUNODEFICIENCY_INCLUDING_HIV); + addFields(fieldsList); + TextArea otherConditions = addField(OTHER_CONDITIONS, TextArea.class); otherConditions.setRows(6); otherConditions.setDescription( I18nProperties.getPrefixDescription(HealthConditionsDto.I18N_PREFIX, OTHER_CONDITIONS, "") + "\n" + I18nProperties.getDescription(Descriptions.descGdpr)); + FieldHelper.setVisibleWhen(getFieldGroup(), HIV_ART, HIV, Arrays.asList(YesNoUnknown.YES), true); + initializeVisibilitiesAndAllowedVisibilities(); initializeAccessAndAllowedAccesses(); - - FieldHelper.setVisibleWhen(getFieldGroup(), HIV_ART, HIV, Arrays.asList(YesNoUnknown.YES), true); } @Override @@ -126,4 +132,14 @@ protected F addFieldToLayout(CustomLayout layout, String prope return super.addFieldToLayout(layout, propertyId, field); } + + public void setInaccessible() { + fieldsList.stream().forEach(field -> { + getContent().getComponent(field).setVisible(false); + }); + getContent().getComponent(OTHER_CONDITIONS).setVisible(false); + Label confidentialLabel = new Label(I18nProperties.getCaption(Captions.inaccessibleValue)); + confidentialLabel.addStyleName(CssStyles.INACCESSIBLE_LABEL); + getContent().addComponent(confidentialLabel, CONFIDENTIAL_LABEL_LOC); + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateSection.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateSection.java index 4b6509ca069..f141b16e31c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateSection.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateSection.java @@ -39,15 +39,15 @@ public class DocumentTemplateSection extends VerticalLayout { private static final long serialVersionUID = 379271838736314055L; - public DocumentTemplateSection(DocumentWorkflow documentWorkflow) { + public DocumentTemplateSection(DocumentWorkflow documentWorkflow, boolean hasDisease) { HorizontalLayout sectionHeader = new HorizontalLayout(); - DocumentTemplatesGrid documentTemplatesGrid = new DocumentTemplatesGrid(documentWorkflow); + DocumentTemplatesGrid documentTemplatesGrid = new DocumentTemplatesGrid(documentWorkflow, hasDisease); documentTemplatesGrid.setWidth(700, Unit.PIXELS); Label quarantineTemplatesLabel = new Label(documentWorkflow.toString()); quarantineTemplatesLabel.addStyleName(H3); - Button uploadButton = buildUploadButton(documentWorkflow, documentTemplatesGrid); + Button uploadButton = buildUploadButton(documentWorkflow, documentTemplatesGrid, hasDisease); sectionHeader.addComponents(quarantineTemplatesLabel, uploadButton); sectionHeader.setComponentAlignment(uploadButton, Alignment.MIDDLE_RIGHT); sectionHeader.setWidth(700, Unit.PIXELS); @@ -57,9 +57,9 @@ public DocumentTemplateSection(DocumentWorkflow documentWorkflow) { setExpandRatio(documentTemplatesGrid, 1F); } - private Button buildUploadButton(DocumentWorkflow documentWorkflow, DocumentTemplatesGrid documentTemplatesGrid) { + private Button buildUploadButton(DocumentWorkflow documentWorkflow, DocumentTemplatesGrid documentTemplatesGrid, boolean hasDisease) { return ButtonHelper.createIconButton(I18nProperties.getCaption(Captions.DocumentTemplate_uploadTemplate), VaadinIcons.UPLOAD, e -> { - Window window = VaadinUiUtil.showPopupWindow(new DocumentTemplateUploadLayout(documentWorkflow)); + Window window = VaadinUiUtil.showPopupWindow(new DocumentTemplateUploadLayout(documentWorkflow, hasDisease)); window.setCaption(String.format(I18nProperties.getCaption(Captions.DocumentTemplate_uploadWorkflowTemplate), documentWorkflow)); window.addCloseListener(c -> documentTemplatesGrid.reload()); }, ValoTheme.BUTTON_PRIMARY); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateUploadLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateUploadLayout.java index bf8a1c4fb78..05391e5c8ff 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateUploadLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplateUploadLayout.java @@ -16,15 +16,19 @@ package de.symeda.sormas.ui.configuration.docgeneration; import java.util.Map; +import java.util.function.Supplier; import com.vaadin.icons.VaadinIcons; import com.vaadin.server.ClassResource; import com.vaadin.server.FileDownloader; import com.vaadin.ui.Button; +import com.vaadin.ui.ComboBox; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; import com.vaadin.v7.ui.Upload; +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -42,6 +46,7 @@ public class DocumentTemplateUploadLayout extends VerticalLayout { protected Upload upload; private ImportLayoutComponent importGuideComponent; private final DocumentWorkflow documentWorkflow; + private final boolean hasDisease; private static final Map templateInfoData = Map.ofEntries( Map.entry( @@ -79,9 +84,10 @@ public class DocumentTemplateUploadLayout extends VerticalLayout { DocumentTemplateInfoData .forEmailTemplate(Captions.DocumentTemplate_exampleTemplateTravelEntryEmail, "ExampleDocumentTemplateTravelEntryEmail.txt"))); - public DocumentTemplateUploadLayout(DocumentWorkflow documentWorkflow) { + public DocumentTemplateUploadLayout(DocumentWorkflow documentWorkflow, boolean hasDisease) { super(); this.documentWorkflow = documentWorkflow; + this.hasDisease = hasDisease; addDownloadResourcesComponent(); addUploadResourceComponent(); } @@ -116,13 +122,30 @@ private void addUploadResourceComponent() { ImportLayoutComponent uploadTemplateComponent = new ImportLayoutComponent(2, headline, infoText, null, null); addComponent(uploadTemplateComponent); - DocumentTemplateReceiver receiver = new DocumentTemplateReceiver(documentWorkflow); + VerticalLayout uploadLatout = new VerticalLayout(); + uploadLatout.setMargin(false); + uploadLatout.setSpacing(false); + uploadLatout.setSizeFull(); + addComponent(uploadLatout); + + Supplier diseaseSupplier = () -> null; + if (hasDisease) { + ComboBox diseaseComboBox = new ComboBox<>(); + diseaseComboBox.setCaption(I18nProperties.getCaption(Captions.disease)); + diseaseComboBox.setItems(FacadeProvider.getDiseaseConfigurationFacade().getAllDiseases(true, true, true)); + diseaseComboBox.setPlaceholder(I18nProperties.getString(Strings.all)); + diseaseComboBox.setEmptySelectionAllowed(true); + uploadLatout.addComponent(diseaseComboBox); + diseaseSupplier = diseaseComboBox::getValue; + } + + DocumentTemplateReceiver receiver = new DocumentTemplateReceiver(documentWorkflow, diseaseSupplier); upload = new Upload("", receiver); upload.setButtonCaption(I18nProperties.getCaption(Captions.DocumentTemplate_buttonUploadTemplate)); CssStyles.style(upload, CssStyles.VSPACE_2); upload.addStartedListener(receiver); upload.addSucceededListener(receiver); - addComponent(upload); + uploadLatout.addComponent(upload); } private void addDownloadResource(String caption, VaadinIcons icon, ClassResource resource) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesGrid.java index 24978bdfb57..706301cd92e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesGrid.java @@ -31,6 +31,7 @@ import com.vaadin.ui.Notification; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.i18n.Captions; @@ -39,23 +40,30 @@ import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.VaadinUiUtil; -public class DocumentTemplatesGrid extends Grid { +public class DocumentTemplatesGrid extends Grid { private static final long serialVersionUID = 2589713987152595369L; private final DocumentWorkflow documentWorkflow; - public DocumentTemplatesGrid(DocumentWorkflow documentWorkflow) { - super(String.class); + public DocumentTemplatesGrid(DocumentWorkflow documentWorkflow, boolean hasDisease) { + super(DocumentTemplateDto.class); this.documentWorkflow = documentWorkflow; setSizeFull(); - List availableTemplates = FacadeProvider.getDocumentTemplateFacade().getAvailableTemplates(documentWorkflow); - ListDataProvider dataProvider = DataProvider.fromStream(availableTemplates.stream()); + List availableTemplates = FacadeProvider.getDocumentTemplateFacade().getAvailableTemplates(documentWorkflow, null); + ListDataProvider dataProvider = DataProvider.fromStream(availableTemplates.stream()); setDataProvider(dataProvider); - removeAllColumns(); - addColumn(String::toString).setCaption(I18nProperties.getString(Strings.fileName)).setExpandRatio(1); + setColumns(DocumentTemplateDto.FILE_NAME); + if (hasDisease) { + addColumn(DocumentTemplateDto.DISEASE); + } + + for (Column column : getColumns()) { + column.setCaption(I18nProperties.getPrefixCaption(DocumentTemplateDto.I18N_PREFIX, column.getId(), column.getCaption())); + } + addComponentColumn(this::buildActionButtons).setCaption(I18nProperties.getCaption(Captions.eventActionsView)) .setWidth(100) .setStyleGenerator(item -> "v-align-center"); @@ -67,20 +75,20 @@ public DocumentTemplatesGrid(DocumentWorkflow documentWorkflow) { public void reload() { // This is bad practice but it works (unlike refreshAll), and in this case its sufficient - List availableTemplates = FacadeProvider.getDocumentTemplateFacade().getAvailableTemplates(documentWorkflow); + List availableTemplates = FacadeProvider.getDocumentTemplateFacade().getAvailableTemplates(documentWorkflow, null); setItems(availableTemplates); getDataProvider().refreshAll(); setHeightByRows(Math.max(1, availableTemplates.size())); } - private Button buildDeleteButton(String templateFileName) { + private Button buildDeleteButton(DocumentTemplateDto template) { return ButtonHelper.createIconButton( "", VaadinIcons.TRASH, e -> VaadinUiUtil - .showDeleteConfirmationWindow(String.format(I18nProperties.getString(Strings.confirmationDeleteFile), templateFileName), () -> { + .showDeleteConfirmationWindow(String.format(I18nProperties.getString(Strings.confirmationDeleteFile), template.getFileName()), () -> { try { - FacadeProvider.getDocumentTemplateFacade().deleteDocumentTemplate(documentWorkflow, templateFileName); + FacadeProvider.getDocumentTemplateFacade().deleteDocumentTemplate(template.toReference()); } catch (DocumentTemplateException ex) { new Notification( I18nProperties.getString(Strings.errorDeletingDocumentTemplate), @@ -92,21 +100,21 @@ private Button buildDeleteButton(String templateFileName) { })); } - private Button buildViewDocumentButton(String templateFileName) { + private Button buildViewDocumentButton(DocumentTemplateDto template) { Button viewButton = ButtonHelper.createIconButton(VaadinIcons.DOWNLOAD); StreamResource streamResource = new StreamResource((StreamResource.StreamSource) () -> { try { - return new ByteArrayInputStream(FacadeProvider.getDocumentTemplateFacade().getDocumentTemplate(documentWorkflow, templateFileName)); + return new ByteArrayInputStream(FacadeProvider.getDocumentTemplateFacade().getDocumentTemplateContent(template.toReference())); } catch (DocumentTemplateException e) { new Notification( - String.format(I18nProperties.getString(Strings.errorReadingTemplate), templateFileName), + String.format(I18nProperties.getString(Strings.errorReadingTemplate), template.getFileName()), e.getMessage(), Notification.Type.ERROR_MESSAGE, false).show(Page.getCurrent()); return null; } - }, templateFileName); + }, template.getFileName()); FileDownloader fileDownloader = new FileDownloader(streamResource); fileDownloader.extend(viewButton); fileDownloader.setFileDownloadResource(streamResource); @@ -114,11 +122,11 @@ private Button buildViewDocumentButton(String templateFileName) { return viewButton; } - private HorizontalLayout buildActionButtons(String s) { + private HorizontalLayout buildActionButtons(DocumentTemplateDto template) { HorizontalLayout horizontalLayout = new HorizontalLayout(); - horizontalLayout.addComponent(buildViewDocumentButton(s)); - horizontalLayout.addComponent(buildDeleteButton(s)); + horizontalLayout.addComponent(buildViewDocumentButton(template)); + horizontalLayout.addComponent(buildDeleteButton(template)); horizontalLayout.setSpacing(false); horizontalLayout.setMargin(false); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesView.java index 3f5fcaf0220..fea59946f8b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/DocumentTemplatesView.java @@ -37,11 +37,11 @@ public DocumentTemplatesView() { super(VIEW_NAME); gridLayout = new VerticalLayout( - new DocumentTemplateSection(QUARANTINE_ORDER_CASE), - new DocumentTemplateSection(QUARANTINE_ORDER_CONTACT), - new DocumentTemplateSection(QUARANTINE_ORDER_EVENT_PARTICIPANT), - new DocumentTemplateSection(QUARANTINE_ORDER_TRAVEL_ENTRY), - new DocumentTemplateSection(EVENT_HANDOUT)); + new DocumentTemplateSection(QUARANTINE_ORDER_CASE, true), + new DocumentTemplateSection(QUARANTINE_ORDER_CONTACT, true), + new DocumentTemplateSection(QUARANTINE_ORDER_EVENT_PARTICIPANT, true), + new DocumentTemplateSection(QUARANTINE_ORDER_TRAVEL_ENTRY, true), + new DocumentTemplateSection(EVENT_HANDOUT, true)); gridLayout.setWidth(100, Unit.PERCENTAGE); gridLayout.setMargin(true); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/emailtemplate/EmailTemplatesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/emailtemplate/EmailTemplatesView.java index 3ae757f1033..4e989fef819 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/emailtemplate/EmailTemplatesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/docgeneration/emailtemplate/EmailTemplatesView.java @@ -37,10 +37,10 @@ public EmailTemplatesView() { super(VIEW_NAME); VerticalLayout gridLayout = new VerticalLayout( - new DocumentTemplateSection(CASE_EMAIL), - new DocumentTemplateSection(CONTACT_EMAIL), - new DocumentTemplateSection(EVENT_PARTICIPANT_EMAIL), - new DocumentTemplateSection(TRAVEL_ENTRY_EMAIL)); + new DocumentTemplateSection(CASE_EMAIL, false), + new DocumentTemplateSection(CONTACT_EMAIL, false), + new DocumentTemplateSection(EVENT_PARTICIPANT_EMAIL, false), + new DocumentTemplateSection(TRAVEL_ENTRY_EMAIL, false)); gridLayout.setWidth(100, Unit.PERCENTAGE); gridLayout.setMargin(true); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java index 926e6d61662..24a49fb16e7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java @@ -93,6 +93,7 @@ import de.symeda.sormas.ui.contact.components.linelisting.layout.LineListingLayout; import de.symeda.sormas.ui.epidata.ContactEpiDataView; import de.symeda.sormas.ui.epidata.EpiDataForm; +import de.symeda.sormas.ui.person.PersonSelectionGrid; import de.symeda.sormas.ui.utils.AbstractView; import de.symeda.sormas.ui.utils.ArchiveHandlers; import de.symeda.sormas.ui.utils.BulkOperationHandler; @@ -110,6 +111,8 @@ public class ContactController { protected final Logger logger = LoggerFactory.getLogger(getClass()); + private boolean contactSaveTriggered; + private CommitDiscardWrapperComponent createComponent; public ContactController() { @@ -270,8 +273,7 @@ public void create(CaseReferenceDto caseRef, boolean asResultingCase, Runnable a if (caseRef != null) { caze = FacadeProvider.getCaseFacade().getCaseDataByUuid(caseRef.getUuid()); } - CommitDiscardWrapperComponent createComponent = - getContactCreateComponent(caze, asResultingCase, alternativeCallback, false); + createComponent = getContactCreateComponent(caze, asResultingCase, alternativeCallback, false); VaadinUiUtil.showModalPopupWindow(createComponent, I18nProperties.getString(Strings.headingCreateNewContact)); } @@ -452,6 +454,7 @@ public CommitDiscardWrapperComponent getContactCreateComponen final CommitDiscardWrapperComponent createComponent = new CommitDiscardWrapperComponent(createForm, UiUtil.permitted(UserRight.CONTACT_CREATE), createForm.getFieldGroup()); + contactSaveTriggered = false; createComponent.addCommitListener(() -> { if (!createForm.getFieldGroup().isModified()) { final ContactDto dto = createForm.getValue(); @@ -504,26 +507,73 @@ public CommitDiscardWrapperComponent getContactCreateComponen } else { final PersonDto person = PersonDto.build(); - transferDataToPerson(createForm, person); - ControllerProvider.getPersonController() - .selectOrCreatePerson(person, I18nProperties.getString(Strings.infoSelectOrCreatePersonForContact), selectedPerson -> { - if (selectedPerson != null) { - dto.setPerson(selectedPerson); - - selectOrCreateContact(dto, selectedPerson, selectedContactUuid -> { - if (selectedContactUuid != null) { - editData(selectedContactUuid); - } - }); - } - if (createForm.adoptAddressLayout.isAdoptAddress()) { - FacadeProvider.getPersonFacade() - .copyHomeAddress( - FacadeProvider.getCaseFacade().getByUuid(dto.getCaze().getUuid()).getPerson(), - dto.getPerson()); + if (createForm.getWarningSimilarPersons() != null) { + CommitDiscardWrapperComponent warningPopUpDuplicatePerson = + (CommitDiscardWrapperComponent) createComponent.getWrappedComponent() + .getWarningSimilarPersons() + .getContent(); + warningPopUpDuplicatePerson.getDiscardButton().setVisible(true); + warningPopUpDuplicatePerson.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionContinue)); + warningPopUpDuplicatePerson.addDoneListener(() -> { + if (!contactSaveTriggered) { + VaadinUiUtil.showModalPopupWindow(createComponent, I18nProperties.getString(Strings.headingCreateNewContact)); } - }, true); + }); + + warningPopUpDuplicatePerson.addCommitListener(() -> { + contactSaveTriggered = true; + transferDataToPerson(createForm, person); + + ControllerProvider.getPersonController() + .selectOrCreatePerson( + person, + I18nProperties.getString(Strings.infoSelectOrCreatePersonForContact), + selectedPerson -> { + if (selectedPerson != null) { + dto.setPerson(selectedPerson); + + selectOrCreateContact(dto, selectedPerson, selectedContactUuid -> { + if (selectedContactUuid != null) { + editData(selectedContactUuid); + } + }); + } + if (createForm.adoptAddressLayout.isAdoptAddress()) { + FacadeProvider.getPersonFacade() + .copyHomeAddress( + FacadeProvider.getCaseFacade().getByUuid(dto.getCaze().getUuid()).getPerson(), + dto.getPerson()); + } + }, + true); + }); + } else { + transferDataToPerson(createForm, person); + + ControllerProvider.getPersonController() + .selectOrCreatePerson( + person, + I18nProperties.getString(Strings.infoSelectOrCreatePersonForContact), + selectedPerson -> { + if (selectedPerson != null) { + dto.setPerson(selectedPerson); + + selectOrCreateContact(dto, selectedPerson, selectedContactUuid -> { + if (selectedContactUuid != null) { + editData(selectedContactUuid); + } + }); + } + if (createForm.adoptAddressLayout.isAdoptAddress()) { + FacadeProvider.getPersonFacade() + .copyHomeAddress( + FacadeProvider.getCaseFacade().getByUuid(dto.getCaze().getUuid()).getPerson(), + dto.getPerson()); + } + }, + true); + } } } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactCreateForm.java index bb00efe417d..e7c57c7d226 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactCreateForm.java @@ -27,6 +27,7 @@ import com.vaadin.shared.ui.ContentMode; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; import com.vaadin.v7.ui.AbstractField; import com.vaadin.v7.ui.CheckBox; @@ -55,6 +56,7 @@ import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UiUtil; 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.ButtonHelper; import de.symeda.sormas.ui.utils.CssStyles; @@ -119,6 +121,7 @@ public class ContactCreateForm extends AbstractEditForm { ComboBox community; private final boolean showPersonSearchButton; + private Window warningSimilarPersons; /** * TODO use disease and case relation information given in ContactDto @@ -151,7 +154,7 @@ protected void addFields() { reportDate = addField(ContactDto.REPORT_DATE_TIME, DateField.class); addField(CaseDataDto.CASE_REFERENCE_NUMBER, TextField.class); - ComboBox cbDisease = addDiseaseField(ContactDto.DISEASE, false, true); + ComboBox cbDisease = addDiseaseField(ContactDto.DISEASE, false, true, true); addField(ContactDto.DISEASE_DETAILS, TextField.class); personCreateForm = new PersonCreateForm(false, false, false, showPersonSearchButton); @@ -159,6 +162,11 @@ protected void addFields() { personCreateForm.setValue(new PersonDto()); getContent().addComponent(personCreateForm, ContactDto.PERSON); + personCreateForm.getNationalHealthIdField().addTextFieldValueChangeListener(e -> { + warningSimilarPersons = PersonFormHelper + .warningSimilarPersons(personCreateForm.getNationalHealthIdField().getValue(), null, () -> warningSimilarPersons = null); + }); + addField(ContactDto.RETURNING_TRAVELER, NullableOptionGroup.class); region = addInfrastructureField(ContactDto.REGION); district = addInfrastructureField(ContactDto.DISTRICT); @@ -430,4 +438,7 @@ private void updateDateComparison() { } } + public Window getWarningSimilarPersons() { + return warningSimilarPersons; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java index 5b0fe16c52c..e981850aca6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java @@ -81,7 +81,6 @@ import de.symeda.sormas.api.utils.Diseases.DiseasesConfiguration; import de.symeda.sormas.api.utils.ExtendedReduced; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UiUtil; @@ -90,6 +89,7 @@ import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.LayoutUtil; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -204,7 +204,7 @@ public ContactDataForm(Disease disease, ViewMode viewMode, boolean isPseudonymiz FieldVisibilityCheckers.withDisease(disease) .andWithCountry(FacadeProvider.getConfigFacade().getCountryLocale()) .andWithFeatureType(FacadeProvider.getFeatureConfigurationFacade().getActiveServerFeatureConfigurations()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.viewMode = viewMode; this.disease = disease; @@ -299,7 +299,7 @@ protected void addFields() { } ComboBox relationToCase = addField(ContactDto.RELATION_TO_CASE, ComboBox.class); addField(ContactDto.RELATION_DESCRIPTION, TextField.class); - cbDisease = addDiseaseField(ContactDto.DISEASE, false); + cbDisease = addDiseaseField(ContactDto.DISEASE, false, true); cbDisease.setNullSelectionAllowed(false); addField(ContactDto.DISEASE_DETAILS, TextField.class); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java index f0745c2c774..a374a345851 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java @@ -28,7 +28,6 @@ import de.symeda.sormas.api.EditPermissionType; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; -import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactClassification; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactLogic; @@ -293,7 +292,12 @@ protected void initView(String params) { layout.addSidePanelComponent(new SideComponentLayout(documentList), DOCUMENTS_LOC); } - QuarantineOrderDocumentsComponent.addComponentToLayout(layout, contactDto, documentList); + Disease disease = contactDto.getDisease(); + if (disease == null && caseDto != null) { + disease = caseDto.getDisease(); + } + + QuarantineOrderDocumentsComponent.addComponentToLayout(layout, contactDto, disease, documentList); if (UiUtil.permitted(FeatureType.EXTERNAL_EMAILS, UserRight.EXTERNAL_EMAIL_SEND)) { ExternalEmailSideComponent externalEmailSideComponent = diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactsFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactsFilterForm.java index c7744674782..82167788cf3 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactsFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactsFilterForm.java @@ -49,6 +49,7 @@ import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractFilterForm; +import de.symeda.sormas.ui.utils.BirthdateRangeFilterComponent; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; import de.symeda.sormas.ui.utils.FieldConfiguration; @@ -60,6 +61,7 @@ public class ContactsFilterForm extends AbstractFilterForm { private static final String DISTRICT_INFO_LABEL_ID = "infoContactsViewRegionDistrictFilter"; private static final String WEEK_AND_DATE_FILTER = "moreFilters"; + private static final String BIRTHDATE_RANGE_FILTER = "birthdateRangeFilter"; private static final String CHECKBOX_STYLE = CssStyles.CHECKBOX_FILTER_INLINE + " " + CssStyles.VSPACE_3; @@ -92,7 +94,8 @@ public class ContactsFilterForm extends AbstractFilterForm { ContactCriteria.ONLY_CONTACTS_FROM_OTHER_INSTANCES, ContactCriteria.INCLUDE_CONTACTS_FROM_OTHER_JURISDICTIONS) - + loc(WEEK_AND_DATE_FILTER); + + loc(WEEK_AND_DATE_FILTER) + + loc(BIRTHDATE_RANGE_FILTER); protected ContactsFilterForm() { super( @@ -320,7 +323,8 @@ public void addMoreFilters(CustomLayout moreFiltersContainer) { ContactCriteria.ONLY_CONTACTS_SHARING_EVENT_WITH_SOURCE_CASE, I18nProperties.getCaption(Captions.contactOnlyWithSharedEventWithSourceCase), null, - CHECKBOX_STYLE)).setVisible(UiUtil.permitted(UserRight.EVENT_VIEW)); + CHECKBOX_STYLE)) + .setVisible(UiUtil.permitted(UserRight.EVENT_VIEW)); addField( moreFiltersContainer, @@ -344,6 +348,8 @@ public void addMoreFilters(CustomLayout moreFiltersContainer) { } moreFiltersContainer.addComponent(buildWeekAndDateFilter(), WEEK_AND_DATE_FILTER); + + moreFiltersContainer.addComponent(buildBirthdayRangeFilter(), BIRTHDATE_RANGE_FILTER); } @Override @@ -526,6 +532,19 @@ private HorizontalLayout buildWeekAndDateFilter() { return dateFilterRowLayout; } + private HorizontalLayout buildBirthdayRangeFilter() { + BirthdateRangeFilterComponent birthdateRangeFilterComponent = new BirthdateRangeFilterComponent(false, this); + addApplyHandler(e -> onApplyClick(birthdateRangeFilterComponent)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(birthdateRangeFilterComponent); + + return dateFilterRowLayout; + } + private void onApplyClick(EpiWeekAndDateFilterComponent weekAndDateFilter) { ContactCriteria criteria = getValue(); @@ -555,6 +574,18 @@ private void onApplyClick(EpiWeekAndDateFilterComponent weekAnd } } + private void onApplyClick(BirthdateRangeFilterComponent birthdateRangeFilter) { + Date birthdateFrom, birthdateTo; + Date dateFrom = birthdateRangeFilter.getDateFromFilter().getValue(); + birthdateFrom = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = birthdateRangeFilter.getDateToFilter().getValue(); + birthdateTo = dateTo != null ? DateHelper.getEndOfDay(dateTo) : null; + ContactCriteria criteria = getValue(); + criteria.setBirthdateFrom(birthdateFrom); + criteria.setBirthdateTo(birthdateTo); + criteria.setIncludePartialMatch(birthdateRangeFilter.getIncludePartialMatch().getValue()); + } + private void populateContactResponsiblesForRegion(RegionReferenceDto regionReferenceDto) { List items = fetchContactResponsiblesByRegion(regionReferenceDto != null ? regionReferenceDto : currentUserDto().getRegion()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java index 2dc0fdf58b1..aec6e9ecf83 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java @@ -29,6 +29,7 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.ui.SormasUI; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.AefiDashboardView; import de.symeda.sormas.ui.dashboard.campaigns.CampaignDashboardView; import de.symeda.sormas.ui.dashboard.contacts.ContactsDashboardView; import de.symeda.sormas.ui.dashboard.sample.SampleDashboardView; @@ -66,6 +67,11 @@ protected AbstractDashboardView(String viewName) { dashboardSwitcher.setItemCaption(DashboardType.SAMPLES, I18nProperties.getEnumCaption(DashboardType.SAMPLES)); } + if (permitted(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, UserRight.DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + dashboardSwitcher.addItem(DashboardType.ADVERSE_EVENTS); + dashboardSwitcher.setItemCaption(DashboardType.ADVERSE_EVENTS, I18nProperties.getEnumCaption(DashboardType.ADVERSE_EVENTS)); + } + if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { dashboardSwitcher.addItem(DashboardType.CAMPAIGNS); dashboardSwitcher.setItemCaption(DashboardType.CAMPAIGNS, I18nProperties.getEnumCaption(DashboardType.CAMPAIGNS)); @@ -96,6 +102,8 @@ protected void navigateToDashboardView(Property.ValueChangeEvent e) { SormasUI.get().getNavigator().navigateTo(ContactsDashboardView.VIEW_NAME); } else if (DashboardType.SAMPLES.equals(e.getProperty().getValue())) { SormasUI.get().getNavigator().navigateTo(SampleDashboardView.VIEW_NAME); + } else if (DashboardType.ADVERSE_EVENTS.equals(e.getProperty().getValue())) { + SormasUI.get().getNavigator().navigateTo(AefiDashboardView.VIEW_NAME); } else { SormasUI.get().getNavigator().navigateTo(CampaignDashboardView.VIEW_NAME); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java index d65f29e12a0..d8a6414fbd7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java @@ -23,6 +23,7 @@ import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.AefiDashboardView; import de.symeda.sormas.ui.dashboard.campaigns.CampaignDashboardView; import de.symeda.sormas.ui.dashboard.contacts.ContactsDashboardView; import de.symeda.sormas.ui.dashboard.sample.SampleDashboardView; @@ -48,5 +49,9 @@ public void registerViews(Navigator navigator) { if (permitted(FeatureType.SAMPLES_LAB, UserRight.DASHBOARD_SAMPLES_VIEW)) { navigator.addView(SampleDashboardView.VIEW_NAME, SampleDashboardView.class); } + + if (permitted(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT, UserRight.DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW)) { + navigator.addView(AefiDashboardView.VIEW_NAME, AefiDashboardView.class); + } } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardType.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardType.java index 245918b091d..d1325b7ccb7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardType.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardType.java @@ -24,7 +24,8 @@ public enum DashboardType { SURVEILLANCE, CONTACTS, CAMPAIGNS, - SAMPLES; + SAMPLES, + ADVERSE_EVENTS; @Override public String toString() { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardDataProvider.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardDataProvider.java new file mode 100644 index 00000000000..2945bb8f54f --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardDataProvider.java @@ -0,0 +1,105 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization; + +import java.util.Map; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDashboardFilterDateType; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartData; +import de.symeda.sormas.ui.dashboard.AbstractDashboardDataProvider; + +public class AefiDashboardDataProvider extends AbstractDashboardDataProvider { + + private AefiDashboardFilterDateType dateType = AefiDashboardFilterDateType.REPORT_DATE; + + private Map aefiCountsByType; + private int totalAefiInvestigations; + private Map> aefiInvestigationCountsByInvestigationStatus; + private Map> aefiInvestigationCountsByAefiClassification; + private Map> aefiCountsByVaccine; + private AefiChartData aefiByVaccineDoseChartData; + private AefiChartData aefiEventsByGenderChartData; + + @Override + public void refreshData() { + aefiCountsByType = FacadeProvider.getAefiDashboardFacade().getAefiCountsByType(buildDashboardCriteriaWithDates()); + aefiInvestigationCountsByInvestigationStatus = + FacadeProvider.getAefiDashboardFacade().getAefiInvestigationCountsByInvestigationStatus(buildDashboardCriteriaWithDates()); + + totalAefiInvestigations = 0; + for (Map investigationStatusValue : aefiInvestigationCountsByInvestigationStatus.values()) { + totalAefiInvestigations += Integer.parseInt(investigationStatusValue.get("total")); + } + + aefiInvestigationCountsByAefiClassification = + FacadeProvider.getAefiDashboardFacade().getAefiInvestigationCountsByAefiClassification(buildDashboardCriteriaWithDates()); + aefiCountsByVaccine = FacadeProvider.getAefiDashboardFacade().getAefiCountsByVaccine(buildDashboardCriteriaWithDates()); + aefiByVaccineDoseChartData = FacadeProvider.getAefiDashboardFacade().getAefiByVaccineDoseChartData(buildDashboardCriteriaWithDates()); + aefiEventsByGenderChartData = FacadeProvider.getAefiDashboardFacade().getAefiEventsByGenderChartData(buildDashboardCriteriaWithDates()); + } + + @Override + protected AefiDashboardCriteria newCriteria() { + return new AefiDashboardCriteria(); + } + + @Override + protected AefiDashboardCriteria buildDashboardCriteria() { + return super.buildDashboardCriteria().aefiDashboardDateType(dateType); + } + + public AefiDashboardFilterDateType getDateType() { + return dateType; + } + + public void setDateType(AefiDashboardFilterDateType dateType) { + this.dateType = dateType; + } + + public Map getAefiCountsByType() { + return aefiCountsByType; + } + + public int getTotalAefiInvestigations() { + return totalAefiInvestigations; + } + + public Map> getAefiInvestigationCountsByInvestigationStatus() { + return aefiInvestigationCountsByInvestigationStatus; + } + + public Map> getAefiInvestigationCountsByAefiClassification() { + return aefiInvestigationCountsByAefiClassification; + } + + public Map> getAefiCountsByVaccine() { + return aefiCountsByVaccine; + } + + public AefiChartData getAefiByVaccineDoseChartData() { + return aefiByVaccineDoseChartData; + } + + public AefiChartData getAefiEventsByGenderChartData() { + return aefiEventsByGenderChartData; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardFilterLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardFilterLayout.java new file mode 100644 index 00000000000..c4f2cc2ff1a --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardFilterLayout.java @@ -0,0 +1,109 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.vaadin.v7.ui.ComboBox; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDashboardFilterDateType; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.ui.dashboard.components.DashboardFilterLayout; +import de.symeda.sormas.ui.utils.ComboBoxHelper; +import de.symeda.sormas.ui.utils.components.datetypeselector.DateTypeSelectorComponent; + +public class AefiDashboardFilterLayout extends DashboardFilterLayout { + + public static final String DATE_TYPE_FILTER = "dateTypeFilter"; + public static final String DISEASE_FILTER = "diseaseFilter"; + + private final static String[] FILTERS = new String[] { + DATE_TYPE_FILTER, + REGION_FILTER, + DISTRICT_FILTER, + DISEASE_FILTER }; + + public AefiDashboardFilterLayout(AefiDashboardView dashboardView, AefiDashboardDataProvider dashboardDataProvider) { + super(dashboardView, dashboardDataProvider, FILTERS); + } + + @Override + public void populateLayout() { + super.populateLayout(); + + createDateTypeSelector(); + createRegionFilter(I18nProperties.getDescription(Descriptions.aefiDashboardRegionFilter)); + createDistrictFilter(I18nProperties.getDescription(Descriptions.aefiDashboardDistrictFilter)); + createDiseaseFilter(); + } + + private void createDateTypeSelector() { + @SuppressWarnings("unchecked") + DateTypeSelectorComponent dateTypeSelectorComponent = new DateTypeSelectorComponent.Builder<>(AefiDashboardFilterDateType.class) + .dateTypePrompt(I18nProperties.getString(Strings.promptAefiDashboardFilterDateType)) + .defaultDateType(dashboardDataProvider.getDateType()) + .build(); + + dateTypeSelectorComponent.addValueChangeListener(e -> { + dashboardDataProvider.setDateType((AefiDashboardFilterDateType) e.getProperty().getValue()); + }); + + addCustomComponent(dateTypeSelectorComponent, DATE_TYPE_FILTER); + } + + private void createDiseaseFilter() { + ComboBox diseaseFilter = ComboBoxHelper.createComboBoxV7(); + diseaseFilter.setWidth(200, Unit.PIXELS); + diseaseFilter.setInputPrompt(I18nProperties.getString(Strings.promptDisease)); + diseaseFilter.setDescription(I18nProperties.getDescription(Descriptions.aefiDashboardDiseaseFilter)); + List availableDisease = FacadeProvider.getDiseaseConfigurationFacade().getAllDiseases(true, true, true); + + diseaseFilter + .addItems(Stream.concat(availableDisease.stream(), Stream.of(AefiDashboardCustomDiseaseFilter.values())).collect(Collectors.toList())); + diseaseFilter.setValue(dashboardDataProvider.getDisease()); + + diseaseFilter.addValueChangeListener(e -> { + Object filterValue = diseaseFilter.getValue(); + if (filterValue instanceof Disease) { + dashboardDataProvider.setDisease((Disease) filterValue); + } else if (filterValue == AefiDashboardCustomDiseaseFilter.NO_DISEASE) { + dashboardDataProvider.setDisease(null); + } else if (filterValue == null) { + dashboardDataProvider.setDisease(null); + } else { + throw new RuntimeException("Disease filter [" + filterValue + "] not handled!"); + } + }); + + addCustomComponent(diseaseFilter, DISEASE_FILTER); + } + + enum AefiDashboardCustomDiseaseFilter { + + NO_DISEASE; + + @Override + public String toString() { + return I18nProperties.getEnumCaptionShort(this); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardView.java new file mode 100644 index 00000000000..f21df5a8aaf --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiDashboardView.java @@ -0,0 +1,305 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization; + +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidColumn; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidColumnLoc; +import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowCss; +import static de.symeda.sormas.ui.utils.LayoutUtil.locCss; + +import java.util.Map; + +import com.vaadin.shared.ui.MarginInfo; +import com.vaadin.ui.Component; +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiClassification; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationStatus; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.dashboard.AbstractDashboardView; +import de.symeda.sormas.ui.dashboard.DashboardCssStyles; +import de.symeda.sormas.ui.dashboard.DashboardType; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components.AefiByVaccineDoseChart; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components.AefiCountTilesComponent; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components.AefiDashboardMapComponent; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components.AefiReactionsBySexChart; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components.AefiTypeStatisticsGroupComponent; +import de.symeda.sormas.ui.dashboard.components.DashboardHeadingComponent; +import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsPercentageElement; +import de.symeda.sormas.ui.utils.CssStyles; + +public class AefiDashboardView extends AbstractDashboardView { + + public static final String VIEW_NAME = ROOT_VIEW_NAME + "/adverseevents"; + + private static final int EPI_CURVE_AND_MAP_HEIGHT = 555; + + private static final String ALL_AEFI_HEADING_LOC = "allAefiHeadingLoc"; + private static final String AEFI_TYPE_LOC = "aefiTypeLoc"; + private static final String ALL_AEFI_INVESTIGATION_HEADING_LOC = "allAefiInvestigationHeadingLoc"; + private static final String INVESTIGATION_STATUS_LOC = "investigationStatusLoc"; + private static final String AEFI_CLASSIFICATION_LOC = "aefiClassificationLoc"; + private static final String VACCINES_LOC = "vaccinesLoc"; + private static final String VACCINE_DOSE_LOC = "vaccineDoseLoc"; + private static final String REACTIONS_LOC = "reactionsLoc"; + + private final AefiDashboardDataProvider dataProvider; + + private final CustomLayout aefiCountsLayout; + private final HorizontalLayout epiCurveAndMapLayout; + private final VerticalLayout epiCurveLayout; + private final VerticalLayout mapLayout; + + private final DashboardHeadingComponent allAefiHeading; + private final AefiCountTilesComponent aefiCountsByType; + private final DashboardHeadingComponent allAefiInvestigationHeading; + private DashboardStatisticsPercentageElement investigationStatusDone; + private DashboardStatisticsPercentageElement investigationStatusDiscarded; + private DashboardStatisticsPercentageElement aefiClassificationVaccineRelated; + private DashboardStatisticsPercentageElement aefiClassificationConincidentalAefi; + private DashboardStatisticsPercentageElement aefiClassificationUndetermined; + private final AefiTypeStatisticsGroupComponent aefiCountsByVaccine; + private final AefiByVaccineDoseChart vaccineDoseChart; + private final AefiReactionsBySexChart reactionsBySexChart; + private final AefiEpiCurveComponent epiCurveComponent; + private final AefiDashboardMapComponent mapComponent; + + public AefiDashboardView() { + super(VIEW_NAME); + + CssStyles.style(getViewTitleLabel(), CssStyles.PAGE_TITLE); + + dashboardSwitcher.setValue(DashboardType.ADVERSE_EVENTS); + dashboardSwitcher.addValueChangeListener(this::navigateToDashboardView); + + dashboardLayout.setHeightUndefined(); + + dataProvider = new AefiDashboardDataProvider(); + AefiDashboardFilterLayout filterLayout = new AefiDashboardFilterLayout(this, dataProvider); + + dashboardLayout.addComponent(filterLayout); + dashboardLayout.setExpandRatio(filterLayout, 0); + + aefiCountsLayout = new CustomLayout(); + //@formatter:off + aefiCountsLayout.setTemplateContents( + fluidRowCss( + CssStyles.PADDING_X_20 + " " + CssStyles.VSPACE_TOP_2, + fluidColumn(1, 0, locCss("", ALL_AEFI_HEADING_LOC)), + fluidColumn(3, 0, locCss("", AEFI_TYPE_LOC)), + fluidColumn(2, 0, locCss("", ALL_AEFI_INVESTIGATION_HEADING_LOC)), + fluidColumn(3, 0, locCss("", INVESTIGATION_STATUS_LOC)), + fluidColumn(3, 0, locCss("", AEFI_CLASSIFICATION_LOC)) + ) + + fluidRowCss( + CssStyles.VSPACE_TOP_2, + fluidColumnLoc(12, 0, 12, 0, VACCINES_LOC) + ) + + fluidRowCss( + CssStyles.PADDING_X_20 + " " + CssStyles.VSPACE_TOP_2, + fluidColumn(6, 0, locCss("", VACCINE_DOSE_LOC)), + fluidColumn(6, 0, locCss("", REACTIONS_LOC)) + ) + ); + //@formatter:on + dashboardLayout.addComponent(aefiCountsLayout); + + allAefiHeading = new DashboardHeadingComponent(Captions.aefiDashboardAllAefi, null); + allAefiHeading.setMargin(false); + aefiCountsLayout.addComponent(allAefiHeading, ALL_AEFI_HEADING_LOC); + + aefiCountsByType = new AefiCountTilesComponent<>(AefiType.class, "", this::getBackgroundStyleForAefiCountByType, null); + aefiCountsByType.setTitleStyleNames(CssStyles.H3, CssStyles.VSPACE_TOP_5); + aefiCountsByType.setGroupLabelStyle(CssStyles.LABEL_LARGE + " " + CssStyles.LABEL_WHITE_SPACE_NORMAL); + aefiCountsLayout.addComponent(aefiCountsByType, AEFI_TYPE_LOC); + + allAefiInvestigationHeading = new DashboardHeadingComponent(Captions.aefiDashboardAllAefiInvestigation, null); + allAefiInvestigationHeading.setMargin(false); + aefiCountsLayout.addComponent(allAefiInvestigationHeading, ALL_AEFI_INVESTIGATION_HEADING_LOC); + + VerticalLayout investigationStatusLayout = new VerticalLayout(); + investigationStatusLayout.setMargin(new MarginInfo(false, true, false, true)); + investigationStatusLayout.setSpacing(false); + + investigationStatusDone = new DashboardStatisticsPercentageElement( + I18nProperties.getCaption(Captions.aefiDashboardAefiInvestigationDone), + CssStyles.SVG_FILL_POSITIVE); + investigationStatusDiscarded = new DashboardStatisticsPercentageElement( + I18nProperties.getCaption(Captions.aefiDashboardAefiInvestigationDiscarded), + CssStyles.SVG_FILL_NEUTRAL); + + investigationStatusLayout.addComponent(investigationStatusDone); + investigationStatusLayout.addComponent(investigationStatusDiscarded); + aefiCountsLayout.addComponent(investigationStatusLayout, INVESTIGATION_STATUS_LOC); + + VerticalLayout aefiClassificationLayout = new VerticalLayout(); + aefiClassificationLayout.setMargin(new MarginInfo(false, true, false, true)); + aefiClassificationLayout.setSpacing(false); + + aefiClassificationVaccineRelated = new DashboardStatisticsPercentageElement( + I18nProperties.getCaption(Captions.aefiDashboardAefiClassificationRelatedToVaccination), + CssStyles.SVG_FILL_POSITIVE); + aefiClassificationConincidentalAefi = new DashboardStatisticsPercentageElement( + I18nProperties.getCaption(Captions.aefiDashboardAefiClassificationCoincidentalAdverseEvent), + CssStyles.SVG_FILL_IMPORTANT); + aefiClassificationUndetermined = new DashboardStatisticsPercentageElement( + I18nProperties.getCaption(Captions.aefiDashboardAefiClassificationUndetermined), + CssStyles.SVG_FILL_NEUTRAL); + + aefiClassificationLayout.addComponent(aefiClassificationVaccineRelated); + aefiClassificationLayout.addComponent(aefiClassificationConincidentalAefi); + aefiClassificationLayout.addComponent(aefiClassificationUndetermined); + aefiCountsLayout.addComponent(aefiClassificationLayout, AEFI_CLASSIFICATION_LOC); + + aefiCountsByVaccine = new AefiTypeStatisticsGroupComponent(); + aefiCountsByVaccine.addStyleNames(CssStyles.PADDING_X_20); + aefiCountsLayout.addComponent(aefiCountsByVaccine, VACCINES_LOC); + + vaccineDoseChart = new AefiByVaccineDoseChart(); + aefiCountsLayout.addComponent(vaccineDoseChart, VACCINE_DOSE_LOC); + + reactionsBySexChart = new AefiReactionsBySexChart(); + aefiCountsLayout.addComponent(reactionsBySexChart, REACTIONS_LOC); + + epiCurveComponent = new AefiEpiCurveComponent(dataProvider); + epiCurveLayout = createEpiCurveLayout(); + + mapComponent = new AefiDashboardMapComponent(dataProvider); + mapLayout = createMapLayout(mapComponent); + + epiCurveAndMapLayout = createEpiCurveAndMapLayout(epiCurveLayout, mapLayout); + epiCurveAndMapLayout.addStyleName(CssStyles.VSPACE_TOP_1); + dashboardLayout.addComponent(epiCurveAndMapLayout); + dashboardLayout.setExpandRatio(epiCurveAndMapLayout, 1); + } + + @Override + public void refreshDashboard() { + dataProvider.refreshData(); + + allAefiHeading.updateTotalLabel(String.valueOf(dataProvider.getAefiCountsByType().values().stream().mapToLong(Long::longValue).sum())); + aefiCountsByType.update(dataProvider.getAefiCountsByType()); + + allAefiInvestigationHeading.updateTotalLabel(String.valueOf(dataProvider.getTotalAefiInvestigations())); + Map> investigationStatusCountMap = + dataProvider.getAefiInvestigationCountsByInvestigationStatus(); + investigationStatusDone.updatePercentageValueWithCount( + Integer.parseInt(investigationStatusCountMap.get(AefiInvestigationStatus.DONE).get("total")), + Integer.parseInt(investigationStatusCountMap.get(AefiInvestigationStatus.DONE).get("percent"))); + investigationStatusDiscarded.updatePercentageValueWithCount( + Integer.parseInt(investigationStatusCountMap.get(AefiInvestigationStatus.DISCARDED).get("total")), + Integer.parseInt(investigationStatusCountMap.get(AefiInvestigationStatus.DISCARDED).get("percent"))); + + Map> aefiClassificationCountMap = dataProvider.getAefiInvestigationCountsByAefiClassification(); + aefiClassificationVaccineRelated.updatePercentageValueWithCount( + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.RELATED_TO_VACCINE_OR_VACCINATION).get("total")), + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.RELATED_TO_VACCINE_OR_VACCINATION).get("percent"))); + aefiClassificationConincidentalAefi.updatePercentageValueWithCount( + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.COINCIDENTAL_ADVERSE_EVENT).get("total")), + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.COINCIDENTAL_ADVERSE_EVENT).get("percent"))); + aefiClassificationUndetermined.updatePercentageValueWithCount( + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.UNDETERMINED).get("total")), + Integer.parseInt(aefiClassificationCountMap.get(AefiClassification.UNDETERMINED).get("percent"))); + + aefiCountsByVaccine.update(dataProvider.getAefiCountsByVaccine()); + vaccineDoseChart.update(dataProvider.getAefiByVaccineDoseChartData()); + reactionsBySexChart.update(dataProvider.getAefiEventsByGenderChartData()); + epiCurveComponent.clearAndFillEpiCurveChart(); + mapComponent.refreshMap(); + } + + private String getBackgroundStyleForAefiCountByType(AefiType aefiType) { + return aefiType == AefiType.SERIOUS ? "background-shipment-status-not-shipped" : "background-internal-lab-samples"; + } + + protected HorizontalLayout createEpiCurveAndMapLayout(VerticalLayout epiCurveLayout, VerticalLayout mapLayout) { + HorizontalLayout layout = new HorizontalLayout(epiCurveLayout, mapLayout); + layout.addStyleName(DashboardCssStyles.CURVE_AND_MAP_LAYOUT); + layout.setWidth(100, Unit.PERCENTAGE); + layout.setMargin(false); + layout.setSpacing(false); + + return layout; + } + + protected VerticalLayout createEpiCurveLayout() { + if (epiCurveComponent == null) { + throw new UnsupportedOperationException("EpiCurveComponent needs to be initialized before calling createEpiCurveLayout"); + } + + VerticalLayout layout = new VerticalLayout(); + layout.setMargin(false); + layout.setSpacing(false); + layout.setHeight(EPI_CURVE_AND_MAP_HEIGHT, Unit.PIXELS); + + epiCurveComponent.setSizeFull(); + + layout.addComponent(epiCurveComponent); + layout.setExpandRatio(epiCurveComponent, 1); + + epiCurveComponent.setExpandListener(expanded -> { + setExpanded(expanded, layout, mapLayout, 1); + }); + + return layout; + } + + private VerticalLayout createMapLayout(AefiDashboardMapComponent mapComponent) { + VerticalLayout layout = new VerticalLayout(); + layout.setMargin(false); + layout.setSpacing(false); + layout.setHeight(EPI_CURVE_AND_MAP_HEIGHT, Unit.PIXELS); + + mapComponent.setSizeFull(); + + layout.addComponent(mapComponent); + layout.setExpandRatio(mapComponent, 1); + + mapComponent.setExpandListener(expanded -> { + setExpanded(expanded, layout, epiCurveLayout, 0); + }); + + return layout; + } + + private void setExpanded(Boolean expanded, Component componentToExpand, Component componentToRemove, int removedComponentIndex) { + if (expanded) { + dashboardLayout.removeComponent(allAefiHeading); + dashboardLayout.removeComponent(aefiCountsLayout); + epiCurveAndMapLayout.removeComponent(componentToRemove); + setHeight(100, Unit.PERCENTAGE); + + epiCurveAndMapLayout.setHeightFull(); + setHeightFull(); + componentToExpand.setSizeFull(); + dashboardLayout.setHeightFull(); + } else { + dashboardLayout.addComponent(allAefiHeading, 1); + dashboardLayout.addComponent(aefiCountsLayout, 2); + epiCurveAndMapLayout.addComponent(componentToRemove, removedComponentIndex); + mapComponent.refreshMap(); + + componentToExpand.setHeight(EPI_CURVE_AND_MAP_HEIGHT, Unit.PIXELS); + setHeightUndefined(); + epiCurveAndMapLayout.setHeightUndefined(); + dashboardLayout.setHeightUndefined(); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiEpiCurveComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiEpiCurveComponent.java new file mode 100644 index 00000000000..0cc3a0ef910 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/AefiEpiCurveComponent.java @@ -0,0 +1,97 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.vaadin.ui.AbstractComponent; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; +import de.symeda.sormas.api.dashboard.EpiCurveGrouping; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.ui.dashboard.diagram.AbstractEpiCurveBuilder; +import de.symeda.sormas.ui.dashboard.diagram.AbstractEpiCurveComponent; +import de.symeda.sormas.ui.dashboard.diagram.EpiCurveSeriesElement; + +public class AefiEpiCurveComponent extends AbstractEpiCurveComponent { + + private static final long serialVersionUID = 6767165953640006853L; + + public AefiEpiCurveComponent(AefiDashboardDataProvider dashboardDataProvider) { + super(dashboardDataProvider); + epiCurveLabel.setValue(I18nProperties.getString(Strings.headingAefiDashboardEpiCurve)); + } + + @Override + protected AbstractComponent createEpiCurveModeSelector() { + return null; + } + + @Override + public void clearAndFillEpiCurveChart() { + epiCurveChart.setHcjs(new AefiEpiCurveBuilder(epiCurveGrouping).buildFrom(buildListOfFilteredDates(), dashboardDataProvider)); + } + + private static class AefiEpiCurveBuilder extends AbstractEpiCurveBuilder { + + public AefiEpiCurveBuilder(EpiCurveGrouping epiCurveGrouping) { + super(Captions.dashboardNumberOfAdverseEvents, epiCurveGrouping); + } + + @Override + protected List getEpiCurveElements(List datesGroupedBy, AefiDashboardDataProvider dashboardDataProvider) { + int[] seriousNumbers = new int[datesGroupedBy.size()]; + int[] nonSeriousNumbers = new int[datesGroupedBy.size()]; + + for (int i = 0; i < datesGroupedBy.size(); i++) { + Date date = datesGroupedBy.get(i); + + AefiDashboardCriteria criteria = + dashboardDataProvider.buildDashboardCriteria().aefiDashboardDateType(dashboardDataProvider.getDateType()); + if (epiCurveGrouping == EpiCurveGrouping.DAY) { + criteria.dateBetween(DateHelper.getStartOfDay(date), DateHelper.getEndOfDay(date)); + } else if (epiCurveGrouping == EpiCurveGrouping.WEEK) { + criteria.dateBetween(DateHelper.getStartOfWeek(date), DateHelper.getEndOfWeek(date)); + } else { + criteria.dateBetween(DateHelper.getStartOfMonth(date), DateHelper.getEndOfMonth(date)); + } + + Map aefiCounts = FacadeProvider.getAefiDashboardFacade().getAefiCountsByType(criteria); + + Long seriousCount = aefiCounts.get(AefiType.SERIOUS); + Long nonSeriousCount = aefiCounts.get(AefiType.NON_SERIOUS); + + seriousNumbers[i] = seriousCount != null ? seriousCount.intValue() : 0; + nonSeriousNumbers[i] = nonSeriousCount != null ? nonSeriousCount.intValue() : 0; + } + + return Arrays.asList( + new EpiCurveSeriesElement(AefiType.SERIOUS, "#c80000", seriousNumbers), + new EpiCurveSeriesElement(AefiType.NON_SERIOUS, "#32CD32", nonSeriousNumbers)); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiByVaccineDoseChart.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiByVaccineDoseChart.java new file mode 100644 index 00000000000..964db0c07cd --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiByVaccineDoseChart.java @@ -0,0 +1,158 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartData; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartSeries; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.highcharts.HighChart; + +public class AefiByVaccineDoseChart extends VerticalLayout { + + protected final HighChart chart; + + public AefiByVaccineDoseChart() { + + setMargin(false); + setSpacing(false); + setSizeFull(); + + chart = new HighChart(); + chart.setSizeFull(); + + addComponent(chart); + setExpandRatio(chart, 1); + } + + public void update(AefiChartData chartData) { + + StringBuilder hcjs = new StringBuilder(); + + //@formatter:off + hcjs.append( + "var options = {" + + " chart: {" + + " type: 'bar'," + + " borderRadius: '8px'" + + " }," + + " title: {" + + " text: 'Adverse events by vaccine dose'," + + " align: 'left'," + + " style: {" + + " fontSize: '15px'," + + " fontWeight: 'bold'" + + " }" + + " }," + + " subtitle: {" + + " text: ''," + + " align: 'left'" + + " }," + ); + //@formatter:on + + List xAxisCategories = chartData.getxAxisCategories(); + + StringBuilder categoryBuilder = new StringBuilder(); + if (!xAxisCategories.isEmpty()) { + categoryBuilder.append("["); + } + for (Object s : xAxisCategories) { + if (xAxisCategories.indexOf(s) == xAxisCategories.size() - 1) { + categoryBuilder.append("'" + I18nProperties.getCaption(String.valueOf(s)) + "']"); + } else { + categoryBuilder.append("'" + I18nProperties.getCaption(String.valueOf(s)) + "', "); + } + } + String categories = !StringUtils.isBlank(categoryBuilder.toString()) ? categoryBuilder.toString() : "[]"; + + //@formatter:off + hcjs.append("xAxis: { " + + " categories: " + categories + "," + + " title: {" + + " text: 'Vaccine dose'," + + " style: {" + + " fontWeight: 'bold'" + + " }" + + " }," + + "},"); + //@formatter:on + + //@formatter:off + hcjs.append("yAxis: {" + + " min: 0," + + " title: {" + + " text: 'No. of AEFI Reports'," + + " align: 'high'," + + " style: {" + + " fontWeight: 'bold'" + + " }" + + " }," + + " labels: {" + + " overflow: 'justify'" + + " }," + + " gridLineWidth: 0" + + " }," + + " tooltip: {" + + " valueSuffix: ''" + + " }," + + " plotOptions: {" + + " bar: {" + + " dataLabels: {" + + " enabled: true" + + " }," + + " groupPadding: 0.1" + + " }" + + " }," + + " credits: {" + + " enabled: false" + + " },"); + //@formatter:on + + hcjs.append("series: ["); + List chartSeries = chartData.getSeries(); + for (AefiChartSeries series : chartSeries) { + hcjs.append("{") + .append("name: '") + .append(series.getName()) + .append("',") + .append("color: '") + .append(series.getColor()) + .append("',") + .append("data: [") + .append(String.join(",", series.getSeriesData())) + .append("]") + .append("}"); + + if (chartSeries.indexOf(series) < chartSeries.size() - 1) { + hcjs.append(","); + } + } + hcjs.append("]"); + + hcjs.append("};"); + + chart.setHcjs(hcjs.toString()); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiCountTilesComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiCountTilesComponent.java new file mode 100644 index 00000000000..7a08ff88730 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiCountTilesComponent.java @@ -0,0 +1,203 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Map; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.icons.VaadinIcons; +import com.vaadin.shared.ui.ContentMode; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.utils.CssStyles; + +public class AefiCountTilesComponent> extends VerticalLayout { + + private static final long serialVersionUID = 3342746874277667267L; + private final Class groupType; + private final Function tileBackgroundFactory; + private boolean withPercentage; + private String groupLabelStyle; + + private final Label title; + private Label infoIcon; + private final HorizontalLayout countsLayout; + private String[] titleStyleNames = new String[] { + CssStyles.H3 }; + + public AefiCountTilesComponent( + Class groupType, + String titleCaption, + Function tileBackgroundFactory, + @Nullable String descriptionTag) { + this.groupType = groupType; + this.tileBackgroundFactory = tileBackgroundFactory; + + setMargin(false); + setSpacing(false); + setWidthFull(); + + HorizontalLayout titleLayout = new HorizontalLayout(); + titleLayout.setMargin(false); + titleLayout.setSpacing(false); + addComponent(titleLayout); + + title = new Label(I18nProperties.getCaption(titleCaption)); + title.addStyleNames(titleStyleNames); + + titleLayout.addComponent(title); + + if (StringUtils.isNotBlank(descriptionTag)) { + infoIcon = new Label(VaadinIcons.INFO_CIRCLE.getHtml(), ContentMode.HTML); + infoIcon.setDescription(I18nProperties.getDescription(descriptionTag)); + infoIcon.addStyleName(CssStyles.HSPACE_LEFT_4); + infoIcon.addStyleNames(titleStyleNames); + + titleLayout.addComponent(infoIcon); + } + + titleLayout.setVisible(false); + + countsLayout = new HorizontalLayout(); + countsLayout.setWidthFull(); + addComponent(countsLayout); + } + + public void update(Map counts) { + countsLayout.removeAllComponents(); + + Long total = null; + if (withPercentage) { + total = counts.values().stream().reduce(0L, Long::sum); + } + + addTiles(counts, total); + } + + private void addTiles(Map counts, @Nullable Long total) { + for (T group : groupType.getEnumConstants()) { + addTileForGroup(counts, group, total, String.valueOf(group)); + } + + if (counts.containsKey(null)) { + addTileForGroup(counts, null, total, I18nProperties.getCaption(Captions.notSpecified)); + } + } + + private void addTileForGroup(Map counts, T group, Long total, String groupCaption) { + Long count = counts.getOrDefault(group, 0L); + + BigDecimal percentage = null; + if (total != null) { + percentage = total == 0 + ? BigDecimal.ZERO + : BigDecimal.valueOf(count).divide(BigDecimal.valueOf(total), MathContext.DECIMAL32).multiply(new BigDecimal(100)); + percentage = percentage.setScale(0, RoundingMode.HALF_UP); + } + + TileComponent tile = new TileComponent<>(groupCaption, count, percentage, groupLabelStyle, tileBackgroundFactory.apply(group)); + tile.setWidthFull(); + + countsLayout.addComponent(tile); + countsLayout.setExpandRatio(tile, 1); + } + + public void setTitleStyleNames(String... styleNames) { + title.removeStyleNames(titleStyleNames); + title.addStyleNames(styleNames); + + if (infoIcon != null) { + infoIcon.removeStyleNames(titleStyleNames); + infoIcon.addStyleNames(styleNames); + } + + this.titleStyleNames = styleNames; + } + + public void setWithPercentage(boolean withPercentage) { + this.withPercentage = withPercentage; + } + + public void setGroupLabelStyle(String groupLabelStyle) { + this.groupLabelStyle = groupLabelStyle; + } + + private static class TileComponent extends VerticalLayout { + + private static final long serialVersionUID = 5055236377479070515L; + + TileComponent(String group, Long count, @Nullable BigDecimal percentage, String groupLabelStyle, String backgroundStyle) { + setSpacing(false); + setMargin(false); + + VerticalLayout numbersLayout = new VerticalLayout(); + numbersLayout.setWidthFull(); + numbersLayout.setMargin(false); + numbersLayout.setSpacing(false); + numbersLayout.addStyleNames(backgroundStyle, CssStyles.ROUNDED_BORDER_TOP); + addComponent(numbersLayout); + + Label countLabel = new Label(count.toString()); + countLabel + .addStyleNames(CssStyles.LABEL_WHITE, CssStyles.LABEL_BOLD, CssStyles.LABEL_LARGE, CssStyles.ALIGN_CENTER, CssStyles.VSPACE_TOP_4); + + numbersLayout.addComponent(countLabel); + numbersLayout.setComponentAlignment(countLabel, Alignment.TOP_CENTER); + + if (percentage != null) { + Label percentageLabel = new Label(percentage + "%"); + percentageLabel.addStyleNames(CssStyles.LABEL_WHITE, CssStyles.ALIGN_CENTER, CssStyles.VSPACE_4); + + numbersLayout.addComponent(percentageLabel); + numbersLayout.setComponentAlignment(percentageLabel, Alignment.MIDDLE_CENTER); + } + + Label groupLabel = new Label(group); + groupLabel.addStyleNames( + CssStyles.LABEL_WHITE, + CssStyles.LABEL_BOLD, + CssStyles.VSPACE_TOP_4, + CssStyles.VSPACE_4, + CssStyles.HSPACE_LEFT_4, + CssStyles.HSPACE_RIGHT_4); + + if (groupLabelStyle != null) { + groupLabel.addStyleName(groupLabelStyle); + } + + VerticalLayout groupLabelLayout = new VerticalLayout(); + groupLabelLayout.setMargin(false); + groupLabelLayout.setSpacing(false); + groupLabelLayout.addStyleNames(backgroundStyle, CssStyles.BACKGROUND_DARKER, CssStyles.ROUNDED_BORDER_BOTTOM); + groupLabelLayout.addComponent(groupLabel); + groupLabelLayout.setComponentAlignment(groupLabel, Alignment.TOP_CENTER); + + addComponent(groupLabelLayout); + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiDashboardMapComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiDashboardMapComponent.java new file mode 100644 index 00000000000..be94e75e9a4 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiDashboardMapComponent.java @@ -0,0 +1,161 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import com.vaadin.ui.Component; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.v7.ui.CheckBox; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.dashboard.AefiDashboardCriteria; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.MapAefiDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.AefiDashboardDataProvider; +import de.symeda.sormas.ui.dashboard.map.BaseDashboardMapComponent; +import de.symeda.sormas.ui.map.LeafletMarker; +import de.symeda.sormas.ui.map.MarkerIcon; +import de.symeda.sormas.ui.utils.CssStyles; + +public class AefiDashboardMapComponent extends BaseDashboardMapComponent { + + public AefiDashboardMapComponent(AefiDashboardDataProvider dashboardDataProvider) { + super(Strings.headingAefiDashboardMap, dashboardDataProvider, Strings.infoHeadingAefiDashboardMap); + } + + @Override + protected void addComponents() { + super.addComponents(); + } + + @Override + protected Long getMarkerCount(Date fromDate, Date toDate, int maxCount) { + return FacadeProvider.getAefiDashboardFacade().countAefiForMap(dashboardDataProvider.buildDashboardCriteriaWithDates()); + } + + @Override + protected void loadMapData(Date fromDate, Date toDate) { + String markerGroup = "adverseevents"; + map.removeGroup(markerGroup); + + AefiDashboardCriteria criteria = dashboardDataProvider.buildDashboardCriteriaWithDates(); + List aefiMapData = FacadeProvider.getAefiDashboardFacade().getAefiForMap(criteria); + + //temporary fix: remove data without coordinates + //ideally do this in the backend code + List filteredAefiMapData = new ArrayList<>(); + for (MapAefiDto mapAefiDto : aefiMapData) { + if (mapAefiDto.getLatitude() != null && mapAefiDto.getLongitude() != null) { + filteredAefiMapData.add(mapAefiDto); + } + } + + List markers = new ArrayList<>(aefiMapData.size()); + + markers.addAll(filteredAefiMapData.stream().map(mapAefiDto -> { + LeafletMarker marker = new LeafletMarker(); + switch (mapAefiDto.getAefiType()) { + case SERIOUS: + marker.setIcon(MarkerIcon.SAMPLE_CASE); + break; + case NON_SERIOUS: + marker.setIcon(MarkerIcon.SAMPLE_CONTACT); + break; + default: + marker.setIcon(MarkerIcon.SAMPLE_EVENT_PARTICIPANT); + } + marker.setLatLon(mapAefiDto.getLatitude(), mapAefiDto.getLongitude()); + + return marker; + }).collect(Collectors.toList())); + + map.addMarkerGroup(markerGroup, markers); + } + + @Override + protected void addLayerOptions(VerticalLayout layersLayout) { + + CheckBox showSeriousAefiCheckBox = new CheckBox(); + showSeriousAefiCheckBox.setId(Captions.aefiDashboardShowSeriousAefi); + showSeriousAefiCheckBox.setCaption(I18nProperties.getCaption(Captions.aefiDashboardShowSeriousAefi)); + showSeriousAefiCheckBox.setValue(shouldShowSeriousAefi()); + showSeriousAefiCheckBox.addValueChangeListener(e -> { + dashboardDataProvider.buildDashboardCriteriaWithDates().aefiType(AefiType.SERIOUS); + + refreshMap(true); + }); + + layersLayout.addComponent(showSeriousAefiCheckBox); + + CheckBox showNonSeriousAefiCheckBox = new CheckBox(); + showNonSeriousAefiCheckBox.setId(Captions.aefiDashboardShowNonSeriousAefi); + showNonSeriousAefiCheckBox.setCaption(I18nProperties.getCaption(Captions.aefiDashboardShowNonSeriousAefi)); + showNonSeriousAefiCheckBox.setValue(shouldShowNonSeriousAefi()); + showNonSeriousAefiCheckBox.addValueChangeListener(e -> { + dashboardDataProvider.buildDashboardCriteriaWithDates().aefiType(AefiType.NON_SERIOUS); + + refreshMap(true); + }); + + layersLayout.addComponent(showNonSeriousAefiCheckBox); + } + + @Override + protected List getLegendComponents() { + + HorizontalLayout samplesLegendLayout = new HorizontalLayout(); + samplesLegendLayout.setSpacing(false); + samplesLegendLayout.setMargin(false); + + //if (shouldShowSeriousAefi()) { + HorizontalLayout seriousLegendEntry = + buildMarkerLegendEntry(MarkerIcon.SAMPLE_CASE, I18nProperties.getCaption(Captions.aefiDashboardSeriousAefi)); + CssStyles.style(seriousLegendEntry, CssStyles.HSPACE_RIGHT_3); + samplesLegendLayout.addComponent(seriousLegendEntry); + //} + + //if (shouldShowNonSeriousAefi()) { + HorizontalLayout nonSeriousLegendEntry = + buildMarkerLegendEntry(MarkerIcon.SAMPLE_CONTACT, I18nProperties.getCaption(Captions.aefiDashboardNonSeriousAefi)); + CssStyles.style(nonSeriousLegendEntry, CssStyles.HSPACE_RIGHT_3); + samplesLegendLayout.addComponent(nonSeriousLegendEntry); + //} + + return Collections.singletonList(samplesLegendLayout); + } + + private boolean shouldShowSeriousAefi() { + return dashboardDataProvider.buildDashboardCriteriaWithDates().getAefiType() == AefiType.SERIOUS; + } + + private boolean shouldShowNonSeriousAefi() { + return dashboardDataProvider.buildDashboardCriteriaWithDates().getAefiType() == AefiType.NON_SERIOUS; + } + + @Override + protected void onMarkerClicked(String groupId, int markerIndex) { + + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiReactionsBySexChart.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiReactionsBySexChart.java new file mode 100644 index 00000000000..8b923778206 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiReactionsBySexChart.java @@ -0,0 +1,173 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartData; +import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiChartSeries; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.highcharts.HighChart; + +public class AefiReactionsBySexChart extends VerticalLayout { + + protected final HighChart chart; + + public AefiReactionsBySexChart() { + + setMargin(false); + setSpacing(false); + setSizeFull(); + + chart = new HighChart(); + chart.setSizeFull(); + + addComponent(chart); + setExpandRatio(chart, 1); + } + + public void update(AefiChartData chartData) { + + StringBuilder hcjs = new StringBuilder(); + + //@formatter:off + hcjs.append( + "var options = {" + + " chart: {" + + " type: 'bar'," + + " borderRadius: '8px'" + + " }," + + " title: {" + + " text: 'Proportion of AEFI reactions (events) by sex'," + + " align: 'left'," + + " style: {" + + " fontSize: '15px'," + + " fontWeight: 'bold'" + + " }" + + " }," + + " subtitle: {" + + " text: ''," + + " align: 'left'" + + " }," + ); + //@formatter:on + + List xAxisCategories = chartData.getxAxisCategories(); + + StringBuilder categoryBuilder = new StringBuilder(); + if (!xAxisCategories.isEmpty()) { + categoryBuilder.append("["); + } + for (Object s : xAxisCategories) { + if (xAxisCategories.indexOf(s) == xAxisCategories.size() - 1) { + categoryBuilder.append("'" + I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, String.valueOf(s)) + "']"); + } else { + categoryBuilder.append("'" + I18nProperties.getPrefixCaption(AdverseEventsDto.I18N_PREFIX, String.valueOf(s)) + "', "); + } + } + String categories = !StringUtils.isBlank(categoryBuilder.toString()) ? categoryBuilder.toString() : "[]"; + + //@formatter:off + hcjs.append("xAxis: [{" + + " categories: " + categories + "," + + " title: {" + + " text: 'AEFI Reactions (events)'," + + " style: {" + + " fontWeight: 'bold'" + + " }" + + " }," + + " reversed: true," + + " labels: {" + + " step: 1" + + " }" + + " }, { " + + " title: {" + + " text: 'AEFI Reactions (events)'," + + " style: {" + + " fontWeight: 'bold'" + + " }" + + " }," + + " opposite: true," + + " reversed: false," + + " categories: " + categories + "," + + " linkedTo: 0," + + " labels: {" + + " step: 1" + + " }" + + " }],"); + //@formatter:on + + //@formatter:off + hcjs.append("yAxis: {" + + " title: {" + + " text: 'Proportion of AEFI reactions'," + + " align: 'high'," + + " style: {" + + " fontWeight: 'bold'" + + " }" + + " }," + + " labels: {" + + " formatter: function() {" + + " return Math.abs(this.value);" + + " }" + + " }" + + " }," + + " plotOptions: {" + + " series: {" + + " stacking: 'normal'" + + " }" + + " }," + + " credits: {" + + " enabled: false" + + " }," + + " tooltip: {" + + " formatter: function() {" + + " return this.point.category + ': ' + this.series.name + ' ' + Math.abs(this.y);" + + " }" + + " },"); + //@formatter:on + + hcjs.append("series: ["); + List chartSeries = chartData.getSeries(); + for (AefiChartSeries series : chartSeries) { + hcjs.append("{") + .append("name: '") + .append(series.getName()) + .append("',") + .append("color: '") + .append(series.getColor()) + .append("',") + .append("data: [") + .append(String.join(",", series.getSeriesData())) + .append("]") + .append("}"); + + if (chartSeries.indexOf(series) < chartSeries.size() - 1) { + hcjs.append(","); + } + } + hcjs.append("]"); + + hcjs.append("};"); + + chart.setHcjs(hcjs.toString()); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsComponent.java new file mode 100644 index 00000000000..697d17fe4d3 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsComponent.java @@ -0,0 +1,100 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.util.Map; + +import com.vaadin.ui.Label; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.ui.dashboard.components.DashboardHeadingComponent; +import de.symeda.sormas.ui.dashboard.statistics.CountElementStyle; +import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsCountElement; +import de.symeda.sormas.ui.dashboard.surveillance.components.statistics.DiseaseSectionStatisticsComponent; +import de.symeda.sormas.ui.utils.CssStyles; + +public class AefiTypeStatisticsComponent extends DiseaseSectionStatisticsComponent { + + private final DashboardStatisticsCountElement seriousCount; + private final DashboardStatisticsCountElement nonSeriousCount; + private boolean withPercentage; + + public AefiTypeStatisticsComponent(String titleCaption, String description, String subtitleCaption, boolean showInfoIcon) { + super(titleCaption, description, ""); + + setWidthUndefined(); + + if (subtitleCaption != null) { + Label subTitleLabel = new Label(I18nProperties.getCaption(subtitleCaption)); + CssStyles.style(subTitleLabel, CssStyles.H3, CssStyles.VSPACE_TOP_5); + addComponent(subTitleLabel); + } + + // Count layout + seriousCount = new DashboardStatisticsCountElement(I18nProperties.getCaption(Captions.aefiDashboardSerious), CountElementStyle.CRITICAL); + nonSeriousCount = + new DashboardStatisticsCountElement(I18nProperties.getCaption(Captions.aefiDashboardNonSerious), CountElementStyle.POSITIVE); + + buildCountLayout(seriousCount, nonSeriousCount); + } + + public void update(Map aefiTypeData) { + if (aefiTypeData != null) { + Long totalCount = null; + Long seriousTotal = aefiTypeData.getOrDefault(AefiType.SERIOUS, 0L); + Long nonSeriousTotal = aefiTypeData.getOrDefault(AefiType.NON_SERIOUS, 0L); + + //updateTotalLabel(((Long) aefiTypeData.values().stream().mapToLong(Long::longValue).sum()).toString()); + if (withPercentage) { + totalCount = aefiTypeData.values().stream().reduce(0L, Long::sum); + seriousCount.updateCountLabel(seriousTotal + " (" + calculatePercentage(totalCount, seriousTotal) + " %)"); + nonSeriousCount.updateCountLabel(nonSeriousTotal + " (" + calculatePercentage(totalCount, nonSeriousTotal) + " %)"); + } else { + seriousCount.updateCountLabel(seriousTotal.toString()); + nonSeriousCount.updateCountLabel(nonSeriousTotal.toString()); + } + } + } + + public int calculatePercentage(Long totalCount, Long labResultCount) { + return totalCount == 0 ? 0 : (int) ((labResultCount * 100.0f) / totalCount); + } + + public void setWithPercentage(boolean withPercentage) { + this.withPercentage = withPercentage; + } + + public void setTitleStyleNamesOnTitleLabel(String... styleNames) { + DashboardHeadingComponent dashboardHeadingComponent = this.getHeading(); + Label titleLabel = dashboardHeadingComponent.getTitleLabel(); + + titleLabel.removeStyleNames(dashboardHeadingComponent.getTitleStyleNames()); + titleLabel.addStyleNames(styleNames); + } + + public void setTitleStyleNamesOnTotalLabel(String... styleNames) { + DashboardHeadingComponent dashboardHeadingComponent = this.getHeading(); + Label totalLabel = dashboardHeadingComponent.getTotalLabel(); + + totalLabel.removeStyleNames(dashboardHeadingComponent.getTotalLabelStyleNames()); + totalLabel.addStyleNames(styleNames); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsGroupComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsGroupComponent.java new file mode 100644 index 00000000000..aed7bba874e --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/adverseeventsfollowingimmunization/components/AefiTypeStatisticsGroupComponent.java @@ -0,0 +1,59 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.dashboard.adverseeventsfollowingimmunization.components; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.ui.CssLayout; + +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiType; +import de.symeda.sormas.api.caze.Vaccine; +import de.symeda.sormas.ui.utils.CssStyles; + +public class AefiTypeStatisticsGroupComponent extends CssLayout { + + Map componentMap = new HashMap<>(); + + public AefiTypeStatisticsGroupComponent() { + + setWidthFull(); + } + + public void update(Map> countsByVaccineData) { + + //temporary fix: re-use stored components and hide/unhide if not in new update + removeAllComponents(); + componentMap.clear(); + + AefiTypeStatisticsComponent statisticsComponent; + + for (Map.Entry> entry : countsByVaccineData.entrySet()) { + if (componentMap.containsKey(entry.getKey())) { + componentMap.get(entry.getKey()).update(entry.getValue()); + } else { + statisticsComponent = new AefiTypeStatisticsComponent("", null, entry.getKey().toString(), false); + //statisticsComponent.getHeading().getTitleLabel().setValue(entry.getKey().toString()); + statisticsComponent.hideHeading(); + statisticsComponent.update(entry.getValue()); + statisticsComponent.addStyleNames(CssStyles.VIEW_SECTION, CssStyles.PADDING_X_8, CssStyles.HSPACE_RIGHT_3, CssStyles.VSPACE_4); + componentMap.put(entry.getKey(), statisticsComponent); + + addComponent(statisticsComponent); + } + } + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/AbstractDocgenerationLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/AbstractDocgenerationLayout.java index 7e67258e814..742c36004ed 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/AbstractDocgenerationLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/AbstractDocgenerationLayout.java @@ -20,7 +20,6 @@ import java.util.Properties; import java.util.function.Function; -import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; import com.vaadin.icons.VaadinIcons; @@ -41,7 +40,11 @@ import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -56,23 +59,24 @@ public abstract class AbstractDocgenerationLayout extends VerticalLayout { protected final Button createButton; protected final Button cancelButton; - public ComboBox templateSelector; + public ComboBox templateSelector; public final VerticalLayout additionalVariablesComponent; public final VerticalLayout additionalParametersComponent; public FileDownloader fileDownloader; public DocumentVariables documentVariables; public CheckBox checkBoxUploadGeneratedDoc; public HorizontalLayout buttonBar; + private Disease defaultDisease; - public boolean isCheckBoxAfterTemplateSelector; - - public AbstractDocgenerationLayout( + protected AbstractDocgenerationLayout( + Disease defaultDisease, String captionTemplateSelector, - Function fileNameFunction, + Function fileNameFunction, boolean isMultiFilesMode, - boolean isCheckBoxAfterTemplateSelector) { + boolean uploadCheckboxFirst) { + + this.defaultDisease = defaultDisease; - this.isCheckBoxAfterTemplateSelector = isCheckBoxAfterTemplateSelector; additionalVariablesComponent = new VerticalLayout(); additionalVariablesComponent.setSpacing(false); additionalVariablesComponent.setMargin(new MarginInfo(false, false, true, false)); @@ -84,11 +88,13 @@ public AbstractDocgenerationLayout( hideTextfields(); hideAdditionalParameters(); - if (isCheckBoxAfterTemplateSelector) { + if (uploadCheckboxFirst) { + addDiseaseSelector(defaultDisease); addTemplateSelector(captionTemplateSelector, fileNameFunction); addCheckboxUploadButton(isMultiFilesMode); } else { addCheckboxUploadButton(isMultiFilesMode); + addDiseaseSelector(defaultDisease); addTemplateSelector(captionTemplateSelector, fileNameFunction); } @@ -125,19 +131,40 @@ private void addCheckboxUploadButton(boolean isMultiFilesMode) { } } - private void addTemplateSelector(String captionTemplateSelector, Function fileNameFunction) { + private void addDiseaseSelector(Disease defaultDisease) { + ComboBox diseaseSelector = new ComboBox<>(); + diseaseSelector.setCaption(I18nProperties.getCaption(Captions.disease)); + diseaseSelector.setItems(FacadeProvider.getDiseaseConfigurationFacade().getAllDiseases(true, true, true)); + diseaseSelector.setPlaceholder(I18nProperties.getString(Strings.all)); + diseaseSelector.setEmptySelectionAllowed(true); + diseaseSelector.setWidth(100F, Unit.PERCENTAGE); + diseaseSelector.addStyleName(CssStyles.SOFT_REQUIRED); + diseaseSelector.setValue(defaultDisease); + + diseaseSelector.addValueChangeListener(e -> { + Disease disease = e.getValue(); + templateSelector.setValue(null); + + templateSelector.setItems(getAvailableTemplates(disease)); + templateSelector.setItemCaptionGenerator(DocumentTemplateDto::getFileName); + }); + + addComponent(diseaseSelector); + } + + private void addTemplateSelector(String captionTemplateSelector, Function fileNameFunction) { templateSelector = new ComboBox<>(captionTemplateSelector); templateSelector.setWidth(100F, Unit.PERCENTAGE); templateSelector.addValueChangeListener(e -> { - String templateFile = e.getValue(); - boolean isValidTemplateFile = StringUtils.isNotBlank(templateFile); + DocumentTemplateDto template = e.getValue(); + boolean isValidTemplateFile = template != null; createButton.setEnabled(isValidTemplateFile); additionalVariablesComponent.removeAllComponents(); hideTextfields(); documentVariables = null; if (isValidTemplateFile) { try { - documentVariables = getDocumentVariables(templateFile); + documentVariables = getDocumentVariables(template.toReference()); List additionalVariables = documentVariables.getAdditionalVariables(); if (additionalVariables != null && !additionalVariables.isEmpty()) { for (String variable : additionalVariables) { @@ -149,7 +176,7 @@ private void addTemplateSelector(String captionTemplateSelector, Function function) { } } - private void setStreamResource(String templateFile, String fileName) { - StreamResource streamResource = createStreamResource(templateFile, fileName); + private void setStreamResource(DocumentTemplateDto template, String fileName) { + StreamResource streamResource = createStreamResource(template, fileName); if (fileDownloader == null) { fileDownloader = new FileDownloader(streamResource); fileDownloader.extend(createButton); @@ -235,19 +263,12 @@ protected boolean shouldUploadGeneratedDocument() { return checkBoxUploadGeneratedDoc != null && Boolean.TRUE.equals(checkBoxUploadGeneratedDoc.getValue()); } - protected abstract List getAvailableTemplates(); + protected abstract List getAvailableTemplates(Disease disease); - protected abstract DocumentVariables getDocumentVariables(String templateFile) throws IOException, DocumentTemplateException; + protected abstract DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) + throws IOException, DocumentTemplateException; - protected abstract StreamResource createStreamResource(String templateFile, String filename); + protected abstract StreamResource createStreamResource(DocumentTemplateDto template, String filename); protected abstract String getWindowCaption(); - - public boolean isCheckBoxAfterTemplateSelector() { - return isCheckBoxAfterTemplateSelector; - } - - public void setCheckBoxAfterTemplateSelector(boolean checkBoxAfterTemplateSelector) { - isCheckBoxAfterTemplateSelector = checkBoxAfterTemplateSelector; - } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/DocGenerationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/DocGenerationController.java index 95086c7a8ef..cd73d296e73 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/DocGenerationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/DocGenerationController.java @@ -39,10 +39,12 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EventDocumentFacade; import de.symeda.sormas.api.docgeneneration.QuarantineOrderFacade; import de.symeda.sormas.api.docgeneneration.RootEntityType; +import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventParticipantReferenceDto; import de.symeda.sormas.api.event.EventReferenceDto; import de.symeda.sormas.api.i18n.Captions; @@ -65,22 +67,23 @@ public void showQuarantineOrderDocumentDialog( RootEntityType rootEntityType, ReferenceDto referenceDto, DocumentWorkflow workflow, + Disease defaultDisease, SampleCriteria sampleCriteria, VaccinationCriteria vaccinationCriteria, DocumentListComponent documentListComponent) { showDialog( new QuarantineOrderLayout( workflow, + defaultDisease, sampleCriteria, vaccinationCriteria, documentListComponent, - (templateFile, sample, pathogenTest, vaccination, extraProperties, shouldUploadGeneratedDoc) -> { + (template, sample, pathogenTest, vaccination, extraProperties, shouldUploadGeneratedDoc) -> { QuarantineOrderFacade quarantineOrderFacade = FacadeProvider.getQuarantineOrderFacade(); return new ByteArrayInputStream( quarantineOrderFacade.getGeneratedDocument( - templateFile, - workflow, + template.toReference(), rootEntityType, referenceDto, sample, @@ -89,7 +92,7 @@ public void showQuarantineOrderDocumentDialog( extraProperties, shouldUploadGeneratedDoc)); }, - (templateFile) -> getDocumentFileName(referenceDto, templateFile))); + (template) -> getDocumentFileName(referenceDto, template))); } public void showBulkQuarantineOrderDocumentDialog(List referenceDtos, DocumentWorkflow workflow) { @@ -100,13 +103,14 @@ public void showBulkQuarantineOrderDocumentDialog(List referenceDt null, null, null, - (templateFile, sample, pathogenTest, vaccination, extraProperties, shouldUploadGeneratedDoc) -> { + null, + (template, sample, pathogenTest, vaccination, extraProperties, shouldUploadGeneratedDoc) -> { QuarantineOrderFacade quarantineOrderFacade = FacadeProvider.getQuarantineOrderFacade(); Map generatedDocumentContents = - quarantineOrderFacade.getGeneratedDocuments(templateFile, workflow, referenceDtos, extraProperties, shouldUploadGeneratedDoc); + quarantineOrderFacade.getGeneratedDocuments(template.toReference(), referenceDtos, extraProperties, shouldUploadGeneratedDoc); - return generateZip(templateFile, shouldUploadGeneratedDoc, generatedDocumentContents); + return generateZip(template, shouldUploadGeneratedDoc, generatedDocumentContents); }, (templateFile) -> filename)); @@ -117,27 +121,28 @@ public void showBulkEventParticipantQuarantineOrderDocumentDialog(List { + (template, sample, pathogenTest, vaccination, extraProperties, shouldUploadGeneratedDoc) -> { QuarantineOrderFacade quarantineOrderFacade = FacadeProvider.getQuarantineOrderFacade(); Map generatedDocumentContents = quarantineOrderFacade.getGeneratedDocumentsForEventParticipants( - templateFile, + template.toReference(), referenceDtos, eventDisease, extraProperties, shouldUploadGeneratedDoc); - return generateZip(templateFile, shouldUploadGeneratedDoc, generatedDocumentContents); + return generateZip(template, shouldUploadGeneratedDoc, generatedDocumentContents); }, (templateFile) -> filename)); } private ByteArrayInputStream generateZip( - String templateFile, + DocumentTemplateDto template, Boolean shouldUploadGeneratedDoc, Map generatedDocumentContents) { long fileSizeLimitMB = FacadeProvider.getConfigFacade().getDocumentUploadSizeLimitMb(); @@ -149,7 +154,7 @@ private ByteArrayInputStream generateZip( for (Map.Entry referenceDocumentContent : generatedDocumentContents.entrySet()) { ReferenceDto referenceDto = referenceDocumentContent.getKey(); - ZipEntry entry = new ZipEntry(getDocumentFileName(referenceDto, templateFile)); + ZipEntry entry = new ZipEntry(getDocumentFileName(referenceDto, template)); zos.putNextEntry(entry); byte[] document = referenceDocumentContent.getValue(); @@ -206,16 +211,17 @@ private void buildDocumentUploadWarningWindow(List fileSizeLimitExceeded window.setWidth(1024, Sizeable.Unit.PIXELS); } - public void showEventDocumentDialog(EventReferenceDto eventReferenceDto, DocumentListComponent documentListComponent) { + public void showEventDocumentDialog(EventDto event, DocumentListComponent documentListComponent) { showDialog( new EventDocumentLayout( + event.getDisease(), documentListComponent, - (templateFileName) -> getDocumentFileName(eventReferenceDto, templateFileName), - (templateFile, properties, shouldUploadGeneratedDoc) -> { + (template) -> getDocumentFileName(event.toReference(), template), + (template, properties, shouldUploadGeneratedDoc) -> { EventDocumentFacade eventDocumentFacade = FacadeProvider.getEventDocumentFacade(); return new ByteArrayInputStream( - eventDocumentFacade.getGeneratedDocument(templateFile, eventReferenceDto, properties, shouldUploadGeneratedDoc) + eventDocumentFacade.getGeneratedDocument(template.toReference(), event.toReference(), properties, shouldUploadGeneratedDoc) .getBytes(StandardCharsets.UTF_8)); })); } @@ -223,13 +229,13 @@ public void showEventDocumentDialog(EventReferenceDto eventReferenceDto, Documen public void showEventDocumentDialog(List referenceDtos) { String filename = DownloadUtil.createFileNameWithCurrentDate(ExportEntityName.EVENTS, ".zip"); - showDialog(new EventDocumentLayout(null, (templateFile) -> filename, (templateFile, properties, shouldUploadGeneratedDoc) -> { + showDialog(new EventDocumentLayout(null, null, (templateFile) -> filename, (template, properties, shouldUploadGeneratedDoc) -> { EventDocumentFacade eventDocumentFacade = FacadeProvider.getEventDocumentFacade(); Map generatedDocumentContents = - eventDocumentFacade.getGeneratedDocuments(templateFile, referenceDtos, properties, shouldUploadGeneratedDoc); + eventDocumentFacade.getGeneratedDocuments(template.toReference(), referenceDtos, properties, shouldUploadGeneratedDoc); - return generateZip(templateFile, shouldUploadGeneratedDoc, generatedDocumentContents); + return generateZip(template, shouldUploadGeneratedDoc, generatedDocumentContents); })); } @@ -240,7 +246,7 @@ private void showDialog(AbstractDocgenerationLayout docgenerationLayout) { window.setCaption(I18nProperties.getCaption(docgenerationLayout.getWindowCaption())); } - private String getDocumentFileName(ReferenceDto eventReferenceDto, String templateFileName) { - return DataHelper.getShortUuid(eventReferenceDto) + '-' + templateFileName; + private String getDocumentFileName(ReferenceDto eventReferenceDto, DocumentTemplateDto template) { + return DataHelper.getShortUuid(eventReferenceDto) + '-' + template.getFileName(); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentLayout.java index 5ed024ae1fc..2ff77315502 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentLayout.java @@ -27,8 +27,11 @@ import com.vaadin.server.StreamResource; import com.vaadin.ui.Notification; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -41,10 +44,16 @@ public class EventDocumentLayout extends AbstractDocgenerationLayout { private DocumentListComponent documentListComponent; public EventDocumentLayout( + Disease defaultDisease, DocumentListComponent documentListComponent, - Function fileNameFunction, + Function fileNameFunction, DocumentInputStreamSupplier documentInputStreamSupplier) { - super(I18nProperties.getCaption(Captions.DocumentTemplate_EventHandout), fileNameFunction, isNull(documentListComponent), false); + super( + defaultDisease, + I18nProperties.getCaption(Captions.DocumentTemplate_EventHandout), + fileNameFunction, + isNull(documentListComponent), + false); this.documentListComponent = documentListComponent; this.documentInputStreamSupplier = documentInputStreamSupplier; @@ -53,20 +62,20 @@ public EventDocumentLayout( } @Override - protected List getAvailableTemplates() { - return FacadeProvider.getEventDocumentFacade().getAvailableTemplates(); + protected List getAvailableTemplates(Disease disease) { + return FacadeProvider.getEventDocumentFacade().getAvailableTemplates(disease); } @Override - protected DocumentVariables getDocumentVariables(String templateFile) throws DocumentTemplateException { - return FacadeProvider.getEventDocumentFacade().getDocumentVariables(templateFile); + protected DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + return FacadeProvider.getEventDocumentFacade().getDocumentVariables(templateReference); } @Override - protected StreamResource createStreamResource(String templateFile, String filename) { + protected StreamResource createStreamResource(DocumentTemplateDto template, String filename) { return new StreamResource((StreamResource.StreamSource) () -> { try { - return documentInputStreamSupplier.get(templateFile, readAdditionalVariables(), shouldUploadGeneratedDocument()); + return documentInputStreamSupplier.get(template, readAdditionalVariables(), shouldUploadGeneratedDocument()); } catch (Exception e) { new Notification(I18nProperties.getString(Strings.errorProcessingTemplate), e.getMessage(), Notification.Type.ERROR_MESSAGE) .show(Page.getCurrent()); @@ -86,6 +95,6 @@ protected String getWindowCaption() { interface DocumentInputStreamSupplier { - InputStream get(String templateFile, Properties properties, Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException; + InputStream get(DocumentTemplateDto template, Properties properties, Boolean shouldUploadGeneratedDoc) throws DocumentTemplateException; } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentsComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentsComponent.java index 334d1f1d3f3..1f474c4724a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentsComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/EventDocumentsComponent.java @@ -1,6 +1,6 @@ package de.symeda.sormas.ui.docgeneration; -import de.symeda.sormas.api.event.EventReferenceDto; +import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.ui.ControllerProvider; @@ -10,11 +10,11 @@ public class EventDocumentsComponent extends AbstractDocumentGenerationComponent public static final String DOCGENERATION_LOC = "docgeneration"; - public EventDocumentsComponent(EventReferenceDto eventReferenceDto, DocumentListComponent documentListComponent) { + public EventDocumentsComponent(EventDto event, DocumentListComponent documentListComponent) { super(); if (DocGenerationHelper.isDocGenerationAllowed()) { addDocumentBar( - () -> ControllerProvider.getDocGenerationController().showEventDocumentDialog(eventReferenceDto, documentListComponent), + () -> ControllerProvider.getDocGenerationController().showEventDocumentDialog(event, documentListComponent), I18nProperties.getCaption(Captions.DocumentTemplate_EventHandout_create)); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderDocumentsComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderDocumentsComponent.java index b67a41076de..6f1d830e937 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderDocumentsComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderDocumentsComponent.java @@ -17,6 +17,7 @@ import static de.symeda.sormas.ui.docgeneration.DocGenerationHelper.isDocGenerationAllowed; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.contact.ContactDto; @@ -33,18 +34,21 @@ public class QuarantineOrderDocumentsComponent extends AbstractDocumentGenerationComponent { + private static final long serialVersionUID = 85800761803338225L; + public static final String QUARANTINE_LOC = "quarantine"; - public QuarantineOrderDocumentsComponent( + private QuarantineOrderDocumentsComponent( RootEntityType rootEntityType, ReferenceDto referenceDto, DocumentWorkflow workflow, + Disease defaultDisease, SampleCriteria sampleCriteria, VaccinationCriteria vaccinationCriteria) { super(); addDocumentBar( () -> ControllerProvider.getDocGenerationController() - .showQuarantineOrderDocumentDialog(rootEntityType, referenceDto, workflow, sampleCriteria, vaccinationCriteria, null), + .showQuarantineOrderDocumentDialog(rootEntityType, referenceDto, workflow, defaultDisease, sampleCriteria, vaccinationCriteria, null), Captions.DocumentTemplate_QuarantineOrder); } @@ -56,12 +60,17 @@ public static void addComponentToLayout(LayoutWithSidePanel targetLayout, CaseDa RootEntityType.ROOT_CASE, caze.toReference(), DocumentWorkflow.QUARANTINE_ORDER_CASE, + caze.getDisease(), sampleCriteria, vaccinationCriteria, documentList); } - public static void addComponentToLayout(LayoutWithSidePanel targetLayout, ContactDto contact, DocumentListComponent documentList) { + public static void addComponentToLayout( + LayoutWithSidePanel targetLayout, + ContactDto contact, + Disease defaultDisease, + DocumentListComponent documentList) { VaccinationCriteria vaccinationCriteria = new VaccinationCriteria.Builder(contact.getPerson()).withDisease(contact.getDisease()).build(); SampleCriteria sampleCriteria = new SampleCriteria().contact(contact.toReference()); @@ -70,6 +79,7 @@ public static void addComponentToLayout(LayoutWithSidePanel targetLayout, Contac RootEntityType.ROOT_CONTACT, contact.toReference(), DocumentWorkflow.QUARANTINE_ORDER_CONTACT, + defaultDisease, sampleCriteria, vaccinationCriteria, documentList); @@ -81,6 +91,7 @@ public static void addComponentToLayout(LayoutWithSidePanel targetLayout, Travel RootEntityType.ROOT_TRAVEL_ENTRY, travelEntry.toReference(), DocumentWorkflow.QUARANTINE_ORDER_TRAVEL_ENTRY, + travelEntry.getDisease(), null, null, documentList); @@ -91,21 +102,23 @@ public static void addComponentToLayout( RootEntityType rootEntityType, ReferenceDto referenceDto, DocumentWorkflow workflow, + Disease defaultDisease, SampleCriteria sampleCriteria, VaccinationCriteria vaccinationCriteria) { if (isDocGenerationAllowed()) { QuarantineOrderDocumentsComponent docGenerationComponent = - new QuarantineOrderDocumentsComponent(rootEntityType, referenceDto, workflow, sampleCriteria, vaccinationCriteria); + new QuarantineOrderDocumentsComponent(rootEntityType, referenceDto, workflow, defaultDisease, sampleCriteria, vaccinationCriteria); docGenerationComponent.addStyleName(CssStyles.SIDE_COMPONENT); targetLayout.addSidePanelComponent(docGenerationComponent, QUARANTINE_LOC); } } - public static void addComponentToLayout( + private static void addComponentToLayout( LayoutWithSidePanel targetLayout, RootEntityType rootEntityType, ReferenceDto referenceDto, DocumentWorkflow workflow, + Disease defaultDisease, SampleCriteria sampleCriteria, VaccinationCriteria vaccinationCriteria, DocumentListComponent documentListComponent) { @@ -114,6 +127,7 @@ public static void addComponentToLayout( rootEntityType, referenceDto, workflow, + defaultDisease, sampleCriteria, vaccinationCriteria, documentListComponent); @@ -122,10 +136,11 @@ public static void addComponentToLayout( } } - public QuarantineOrderDocumentsComponent( + private QuarantineOrderDocumentsComponent( RootEntityType rootEntityType, ReferenceDto referenceDto, DocumentWorkflow workflow, + Disease defaultDisease, SampleCriteria sampleCriteria, VaccinationCriteria vaccinationCriteria, DocumentListComponent documentListComponent) { @@ -136,6 +151,7 @@ public QuarantineOrderDocumentsComponent( rootEntityType, referenceDto, workflow, + defaultDisease, sampleCriteria, vaccinationCriteria, documentListComponent), diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderLayout.java index b31f8320381..86119927bd9 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/docgeneration/QuarantineOrderLayout.java @@ -26,7 +26,6 @@ import javax.annotation.Nullable; -import de.symeda.sormas.ui.utils.CssStyles; import org.slf4j.LoggerFactory; import com.vaadin.server.Page; @@ -35,8 +34,11 @@ import com.vaadin.ui.ComboBox; import com.vaadin.ui.Notification; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentTemplateException; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentVariables; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.QuarantineOrderDocumentOptionsDto; @@ -56,6 +58,7 @@ import de.symeda.sormas.api.vaccination.VaccinationListEntryDto; import de.symeda.sormas.api.vaccination.VaccinationReferenceDto; import de.symeda.sormas.ui.document.DocumentListComponent; +import de.symeda.sormas.ui.utils.CssStyles; public class QuarantineOrderLayout extends AbstractDocgenerationLayout { @@ -71,12 +74,14 @@ public class QuarantineOrderLayout extends AbstractDocgenerationLayout { public QuarantineOrderLayout( DocumentWorkflow workflow, + Disease defaultDisease, @Nullable SampleCriteria sampleCriteria, @Nullable VaccinationCriteria vaccinationCriteria, DocumentListComponent documentListComponent, DocumentStreamSupplier documentStreamSupplier, - Function fileNameFunction) { + Function fileNameFunction) { super( + defaultDisease, I18nProperties.getCaption(Captions.DocumentTemplate_QuarantineOrder), fileNameFunction, isNull(sampleCriteria) && isNull(documentListComponent), @@ -99,7 +104,7 @@ public QuarantineOrderLayout( } public QuarantineOrderLayout(DocumentWorkflow workflow) { - super(I18nProperties.getCaption(Captions.DocumentTemplate_QuarantineOrder), null, true, true); + super(null, I18nProperties.getCaption(Captions.DocumentTemplate_QuarantineOrder), null, true, true); this.workflow = workflow; this.documentStreamSupplier = null; @@ -164,9 +169,9 @@ protected void createVaccinationSelector(VaccinationCriteria vaccinationCriteria } @Override - protected List getAvailableTemplates() { + protected List getAvailableTemplates(Disease disease) { try { - return FacadeProvider.getQuarantineOrderFacade().getAvailableTemplates(workflow); + return FacadeProvider.getQuarantineOrderFacade().getAvailableTemplates(workflow, disease); } catch (Exception e) { new Notification(I18nProperties.getString(Strings.errorProcessingTemplate), e.getMessage(), Notification.Type.ERROR_MESSAGE) .show(Page.getCurrent()); @@ -175,12 +180,12 @@ protected List getAvailableTemplates() { } @Override - protected DocumentVariables getDocumentVariables(String templateFile) throws DocumentTemplateException { - return FacadeProvider.getQuarantineOrderFacade().getDocumentVariables(workflow, templateFile); + protected DocumentVariables getDocumentVariables(DocumentTemplateReferenceDto templateReference) throws DocumentTemplateException { + return FacadeProvider.getQuarantineOrderFacade().getDocumentVariables(templateReference); } @Override - protected StreamResource createStreamResource(String templateFile, String filename) { + protected StreamResource createStreamResource(DocumentTemplateDto template, String filename) { return new StreamResource((StreamSource) () -> { SampleReferenceDto sampleReference = sampleSelector != null && sampleSelector.getValue() != null ? sampleSelector.getValue().toReference() : null; @@ -192,7 +197,7 @@ protected StreamResource createStreamResource(String templateFile, String filena try { InputStream stream = documentStreamSupplier.getStream( - templateFile, + template, sampleReference, pathogenTestReference, vaccinationReference, @@ -260,7 +265,7 @@ public QuarantineOrderDocumentOptionsDto getFieldValues() { options.setPathogenTest(new PathogenTestReferenceDto(pathogenTestSelector.getValue().getUuid())); } if (templateSelector != null) { - options.setTemplateFile(templateSelector.getValue()); + options.setTemplate(templateSelector.getValue().toReference()); } options.setShouldUploadGeneratedDoc(shouldUploadGeneratedDocument()); @@ -275,7 +280,7 @@ public QuarantineOrderDocumentOptionsDto getFieldValues() { public interface DocumentStreamSupplier { InputStream getStream( - String templateFile, + DocumentTemplateDto template, SampleReferenceDto sample, PathogenTestReferenceDto pathogenTest, VaccinationReferenceDto vaccinationReference, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalBulkEmailOptionsForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalBulkEmailOptionsForm.java index d1021d75aa2..1cb156d7f63 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalBulkEmailOptionsForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalBulkEmailOptionsForm.java @@ -44,6 +44,7 @@ import de.symeda.sormas.api.DocumentHelper; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.EmailAttachementDto; import de.symeda.sormas.api.docgeneneration.RootEntityType; @@ -113,7 +114,7 @@ protected String createHtmlLayout() { protected void addFields() { ComboBox templateCombo = addField(ExternalEmailOptionsWithAttachmentsDto.TEMPLATE_NAME, ComboBox.class); templateCombo.setRequired(true); - List templateNames = FacadeProvider.getExternalEmailFacade().getTemplateNames(documentWorkflow); + List templateNames = FacadeProvider.getExternalEmailFacade().getTemplates(documentWorkflow); FieldHelper.updateItems(templateCombo, templateNames); if (Arrays.asList(DocumentWorkflow.CASE_EMAIL, DocumentWorkflow.CONTACT_EMAIL, DocumentWorkflow.TRAVEL_ENTRY_EMAIL) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalEmailOptionsForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalEmailOptionsForm.java index 5a9787a8007..507bf0385b4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalEmailOptionsForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/email/ExternalEmailOptionsForm.java @@ -18,6 +18,7 @@ import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs; import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -27,6 +28,8 @@ import com.vaadin.v7.ui.ComboBox; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateReferenceDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.document.DocumentReferenceDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; @@ -43,28 +46,28 @@ public class ExternalEmailOptionsForm extends AbstractEditForm { - private static final String ATTACHMENT_NOT_AVAILABLE_INFO_LOC = "attachmentNotAvailableInfoLoc"; - private static final String HTML_LAYOUT = fluidRowLocs(ExternalEmailOptionsDto.TEMPLATE_NAME) - + fluidRowLocs(ExternalEmailOptionsDto.RECIPIENT_EMAIL) - + fluidRowLocs(ExternalEmailOptionsDto.ATTACHED_DOCUMENTS) - + fluidRowLocs(ATTACHMENT_NOT_AVAILABLE_INFO_LOC); + private static final String ATTACHMENT_NOT_AVAILABLE_INFO_LOC = "attachmentNotAvailableInfoLoc"; + private static final String HTML_LAYOUT = fluidRowLocs(ExternalEmailOptionsDto.TEMPLATE) + + fluidRowLocs(ExternalEmailOptionsDto.RECIPIENT_EMAIL) + + fluidRowLocs(ExternalEmailOptionsDto.ATTACHED_DOCUMENTS) + + fluidRowLocs(ATTACHMENT_NOT_AVAILABLE_INFO_LOC); private final DocumentWorkflow documentWorkflow; - private final DocumentRelatedEntityType documentRelatedEntityType; + private final DocumentRelatedEntityType documentRelatedEntityType; private final PersonDto person; - private final boolean isAttachmentAvailable; - private MultiSelect attachedDocumentsField; - - protected ExternalEmailOptionsForm( - DocumentWorkflow documentWorkflow, - DocumentRelatedEntityType documentRelatedEntityType, - PersonDto person, - boolean isAttachmentAvailable) { + private final boolean isAttachmentAvailable; + private MultiSelect attachedDocumentsField; + + protected ExternalEmailOptionsForm( + DocumentWorkflow documentWorkflow, + DocumentRelatedEntityType documentRelatedEntityType, + PersonDto person, + boolean isAttachmentAvailable) { super(ExternalEmailOptionsDto.class, ExternalEmailOptionsDto.I18N_PREFIX, false); this.documentWorkflow = documentWorkflow; - this.documentRelatedEntityType = documentRelatedEntityType; + this.documentRelatedEntityType = documentRelatedEntityType; this.person = person; - this.isAttachmentAvailable = isAttachmentAvailable; + this.isAttachmentAvailable = isAttachmentAvailable; addFields(); hideValidationUntilNextCommit(); @@ -77,10 +80,14 @@ protected String createHtmlLayout() { @Override protected void addFields() { - ComboBox templateCombo = addField(ExternalEmailOptionsDto.TEMPLATE_NAME, ComboBox.class); + ComboBox templateCombo = addField(ExternalEmailOptionsDto.TEMPLATE, ComboBox.class); templateCombo.setRequired(true); - List templateNames = FacadeProvider.getExternalEmailFacade().getTemplateNames(documentWorkflow); - FieldHelper.updateItems(templateCombo, templateNames); + List templates = FacadeProvider.getExternalEmailFacade() + .getTemplates(documentWorkflow) + .stream() + .map(DocumentTemplateDto::toReference) + .collect(Collectors.toList()); + FieldHelper.updateItems(templateCombo, templates); ComboBox recipientEmailCombo = addField(ExternalEmailOptionsDto.RECIPIENT_EMAIL, ComboBox.class); recipientEmailCombo.setRequired(true); @@ -89,30 +96,30 @@ protected void addFields() { String primaryEmailAddress = person.getEmailAddress(true); if (StringUtils.isNotBlank(primaryEmailAddress)) { recipientEmailCombo - .setItemCaption(primaryEmailAddress, primaryEmailAddress + " (" + I18nProperties.getCaption(Captions.primarySuffix) + ")"); + .setItemCaption(primaryEmailAddress, primaryEmailAddress + " (" + I18nProperties.getCaption(Captions.primarySuffix) + ")"); } - if (documentRelatedEntityType != null) { - attachedDocumentsField = addField(ExternalEmailOptionsDto.ATTACHED_DOCUMENTS, MultiSelect.class); - if (!isAttachmentAvailable) { - attachedDocumentsField.setEnabled(false); - - MultilineLabel attachmentUnavailableInfo = new MultilineLabel( - VaadinIcons.INFO_CIRCLE.getHtml() + " " + I18nProperties.getString(Strings.messageExternalEmailAttachmentNotAvailableInfo), - ContentMode.HTML); - attachmentUnavailableInfo.addStyleNames(CssStyles.VSPACE_2, CssStyles.VSPACE_TOP_4); - getContent().addComponent(attachmentUnavailableInfo, ATTACHMENT_NOT_AVAILABLE_INFO_LOC); - } - } - } - - @Override - public void setValue(ExternalEmailOptionsDto newFieldValue) throws ReadOnlyException, Converter.ConversionException { - super.setValue(newFieldValue); - - if (attachedDocumentsField != null) { - attachedDocumentsField.setItems( - FacadeProvider.getExternalEmailFacade().getAttachableDocuments(documentWorkflow, newFieldValue.getRootEntityReference().getUuid())); - } + if (documentRelatedEntityType != null) { + attachedDocumentsField = addField(ExternalEmailOptionsDto.ATTACHED_DOCUMENTS, MultiSelect.class); + if (!isAttachmentAvailable) { + attachedDocumentsField.setEnabled(false); + + MultilineLabel attachmentUnavailableInfo = new MultilineLabel( + VaadinIcons.INFO_CIRCLE.getHtml() + " " + I18nProperties.getString(Strings.messageExternalEmailAttachmentNotAvailableInfo), + ContentMode.HTML); + attachmentUnavailableInfo.addStyleNames(CssStyles.VSPACE_2, CssStyles.VSPACE_TOP_4); + getContent().addComponent(attachmentUnavailableInfo, ATTACHMENT_NOT_AVAILABLE_INFO_LOC); + } + } + } + + @Override + public void setValue(ExternalEmailOptionsDto newFieldValue) throws ReadOnlyException, Converter.ConversionException { + super.setValue(newFieldValue); + + if (attachedDocumentsField != null) { + attachedDocumentsField.setItems( + FacadeProvider.getExternalEmailFacade().getAttachableDocuments(documentWorkflow, newFieldValue.getRootEntityReference().getUuid())); + } } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/environment/EnvironmentDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/environment/EnvironmentDataForm.java index 154a0bedbd4..96fed8d8d73 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/environment/EnvironmentDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/environment/EnvironmentDataForm.java @@ -30,13 +30,12 @@ import de.symeda.sormas.api.user.JurisdictionLevel; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.location.LocationEditForm; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CheckBoxTree; import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.ResizableTextAreaWrapper; import de.symeda.sormas.ui.utils.UserField; @@ -71,7 +70,7 @@ public EnvironmentDataForm(boolean isPseudonymized, boolean inJurisdiction, bool EnvironmentDto.I18N_PREFIX, false, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized), isEditAllowed); addFields(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java index 21f396a0e1f..81fa1fe4cd6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java @@ -44,12 +44,11 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.ActivityAsCase.ActivityAsCaseField; import de.symeda.sormas.ui.exposure.ExposuresField; import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.components.MultilineLabel; @@ -98,7 +97,7 @@ public EpiDataForm( EpiDataDto.I18N_PREFIX, false, FieldVisibilityCheckers.withDisease(disease).andWithCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized), isEditAllowed); this.disease = disease; this.parentClass = parentClass; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java index c704207bec8..b75bfbe3bcc 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java @@ -79,13 +79,13 @@ import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.location.LocationEditForm; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CheckBoxTree; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.PhoneNumberValidator; @@ -197,7 +197,7 @@ private static UiFieldAccessCheckers createFieldAccessCheckers( boolean withPersonalAndSensitive) { if (withPersonalAndSensitive) { - return UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized); + return FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized); } return UiFieldAccessCheckers.getNoop(); @@ -222,7 +222,7 @@ protected void addFields() { getContent().addComponent(locationHeadingLabel, LOCATION_HEADING_LOC); addField(EventDto.UUID, TextField.class); - ComboBox diseaseField = addDiseaseField(EventDto.DISEASE, false, isCreateForm); + ComboBox diseaseField = addDiseaseField(EventDto.DISEASE, false, isCreateForm, false); addField(EventDto.DISEASE_DETAILS, TextField.class); ComboBox diseaseVariantField = addCustomizableEnumField(EventDto.DISEASE_VARIANT); diseaseVariantField.setNullSelectionAllowed(true); @@ -454,7 +454,7 @@ protected void addFields() { diseaseVariantDetailsField.setVisible(diseaseVariant != null && diseaseVariant.matchPropertyValue(DiseaseVariant.HAS_DETAILS, true)); }); - setRequired(true, EventDto.EVENT_STATUS, EventDto.UUID, EventDto.EVENT_TITLE, EventDto.REPORT_DATE_TIME, EventDto.REPORTING_USER); + setRequired(true, EventDto.EVENT_STATUS, EventDto.UUID, EventDto.EVENT_TITLE, EventDto.REPORT_DATE_TIME); reportDate.addValidator( new DateComparisonValidator( diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java index cb2733d9a47..46db076f7db 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java @@ -140,7 +140,7 @@ protected void initView(String params) { layout.addSidePanelComponent(new SideComponentLayout(documentList), DOCUMENTS_LOC); } - EventDocumentsComponent eventDocuments = new EventDocumentsComponent(getEventRef(), documentList); + EventDocumentsComponent eventDocuments = new EventDocumentsComponent(event, documentList); eventDocuments.addStyleName(CssStyles.SIDE_COMPONENT); layout.addSidePanelComponent(eventDocuments, EventDocumentsComponent.DOCGENERATION_LOC); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java index 0e067d6f6bc..f34e16f0225 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java @@ -151,6 +151,7 @@ protected void initView(String params) { RootEntityType.ROOT_EVENT_PARTICIPANT, eventParticipantRef, DocumentWorkflow.QUARANTINE_ORDER_EVENT_PARTICIPANT, + event.getDisease(), sampleCriteria, vaccinationCriteria); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantEditForm.java index 0ceb8e3094d..4b4a439cd83 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantEditForm.java @@ -32,10 +32,10 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.location.LocationDto; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.UserField; @@ -63,7 +63,7 @@ public EventParticipantEditForm(EventDto event, boolean isPseudonymized, boolean EventParticipantDto.I18N_PREFIX, false, FieldVisibilityCheckers.withDisease(event.getDisease()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.event = event; addFields(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/SuperordinateEventComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/SuperordinateEventComponent.java index 6c51364f2ad..71cdf0688e1 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/SuperordinateEventComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/SuperordinateEventComponent.java @@ -33,13 +33,13 @@ import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.ui.AbstractInfoLayout; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateFormatHelper; +import de.symeda.sormas.ui.utils.FieldAccessHelper; public class SuperordinateEventComponent extends VerticalLayout { @@ -129,11 +129,7 @@ private class SuperordinateEventInfoLayout extends AbstractInfoLayout private final EventDto superordinateEvent; public SuperordinateEventInfoLayout(EventDto superordinateEvent) { - super( - EventDto.class, - UiFieldAccessCheckers.forDataAccessLevel( - UiUtil.getPseudonymizableDataAccessLevel(superordinateEvent.isInJurisdiction()), - superordinateEvent.isPseudonymized())); + super(EventDto.class, FieldAccessHelper.getFieldAccessCheckers(superordinateEvent)); this.superordinateEvent = superordinateEvent; setSpacing(true); setMargin(false); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposuresField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposuresField.java index 3bdde88a1e1..4b02af90252 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposuresField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposuresField.java @@ -32,6 +32,7 @@ import com.vaadin.v7.ui.Table; import de.symeda.sormas.api.EntityDto; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactReferenceDto; @@ -112,7 +113,9 @@ protected void updateColumns() { COLUMN_DESCRIPTION); } table.setCellStyleGenerator( - FieldAccessCellStyleGenerator.withFieldAccessCheckers(ExposureDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + ExposureDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); for (Object columnId : table.getVisibleColumns()) { if (columnId.equals(ACTION_COLUMN_ID)) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseImmunizationsComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseImmunizationsComponent.java index ee1f9f9e4bf..bc2c86116a7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseImmunizationsComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/physiciansreport/PhysiciansReportCaseImmunizationsComponent.java @@ -57,6 +57,7 @@ import de.symeda.sormas.ui.utils.DateFormatHelper; import de.symeda.sormas.ui.utils.DeletableUtils; import de.symeda.sormas.ui.utils.DirtyCheckPopup; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.vaccination.VaccinationEditForm; public class PhysiciansReportCaseImmunizationsComponent extends CommitDiscardWrapperComponent { @@ -210,18 +211,11 @@ private void handleEditVaccination(VaccinationDto vaccination, CaseDataDto caze) VaccinationListItem collapsedComponent = vaccinationList.getItemByVaccination(vaccination); currentVaccinationEditComponent = ControllerProvider.getVaccinationController() - .getVaccinationEditComponent( - vaccination, - caze.getDisease(), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(caze.isInJurisdiction()), caze.isPseudonymized()), - false, - (v) -> { - if (!vaccinationsToCreate.contains(v)) { - vaccinationsToUpdate.add(v); - } - }, - true, - UiUtil.permitted(UserRight.IMMUNIZATION_DELETE)); + .getVaccinationEditComponent(vaccination, caze.getDisease(), FieldAccessHelper.getFieldAccessCheckers(caze), false, (v) -> { + if (!vaccinationsToCreate.contains(v)) { + vaccinationsToUpdate.add(v); + } + }, true, UiUtil.permitted(UserRight.IMMUNIZATION_DELETE)); currentVaccinationEditComponent.getDiscardButton().setCaption(I18nProperties.getCaption(Captions.actionCancel)); currentVaccinationEditComponent.getButtonsPanel() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java index 716ba30ac49..7f00d8bdc11 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java @@ -50,12 +50,12 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DateComparator; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.OutbreakFieldVisibilityChecker; @@ -100,7 +100,7 @@ public HospitalizationForm(CaseDataDto caze, ViewMode viewMode, boolean isPseudo false, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()) .add(new OutbreakFieldVisibilityChecker(viewMode)), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized), isEditAllowed); this.caze = caze; this.viewMode = viewMode; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index e39ccc96b84..7e535b5e0cd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -30,6 +30,7 @@ import de.symeda.sormas.ui.immunization.components.fields.popup.SimilarImmunizationPopup; import de.symeda.sormas.ui.immunization.components.form.ImmunizationCreationForm; import de.symeda.sormas.ui.immunization.components.form.ImmunizationDataForm; +import de.symeda.sormas.ui.person.PersonSelectionGrid; import de.symeda.sormas.ui.utils.ArchiveHandlers; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.NotificationHelper; @@ -40,6 +41,9 @@ public class ImmunizationController { + private boolean immunizationSaveTriggered; + private CommitDiscardWrapperComponent immunizationCreateComponent; + public void registerViews(Navigator navigator) { navigator.addView(ImmunizationsView.VIEW_NAME, ImmunizationsView.class); navigator.addView(ImmunizationDataView.VIEW_NAME, ImmunizationDataView.class); @@ -47,7 +51,7 @@ public void registerViews(Navigator navigator) { } public void create() { - CommitDiscardWrapperComponent immunizationCreateComponent = getImmunizationCreateComponent(); + immunizationCreateComponent = getImmunizationCreateComponent(); if (immunizationCreateComponent != null) { VaadinUiUtil.showModalPopupWindow(immunizationCreateComponent, I18nProperties.getString(Strings.headingCreateNewImmunization)); } @@ -81,6 +85,7 @@ private CommitDiscardWrapperComponent getImmunizationC currentUserProvider.hasUserRight(UserRight.IMMUNIZATION_CREATE), createForm.getFieldGroup()); + immunizationSaveTriggered = false; viewComponent.addCommitListener(() -> { if (!createForm.getFieldGroup().isModified()) { final ImmunizationDto dto = createForm.getValue(); @@ -90,16 +95,44 @@ private CommitDiscardWrapperComponent getImmunizationC selectOrCreateimmunizationForPerson(dto, searchedPerson.toReference()); } else { final PersonDto person = createForm.getPerson(); - ControllerProvider.getPersonController() - .selectOrCreatePerson( - person, - I18nProperties.getString(Strings.infoSelectOrCreatePersonForImmunization), - selectedPerson -> { - if (selectedPerson != null) { - selectOrCreateimmunizationForPerson(dto, selectedPerson); - } - }, - true); + if (createForm.getWarningSimilarPersons() != null) { + CommitDiscardWrapperComponent warningPopUpDuplicatePerson = + (CommitDiscardWrapperComponent) viewComponent.getWrappedComponent() + .getWarningSimilarPersons() + .getContent(); + warningPopUpDuplicatePerson.getDiscardButton().setVisible(true); + warningPopUpDuplicatePerson.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionContinue)); + warningPopUpDuplicatePerson.addDoneListener(() -> { + if (!immunizationSaveTriggered) { + VaadinUiUtil.showModalPopupWindow(viewComponent, I18nProperties.getString(Strings.headingCreateNewImmunization)); + } + }); + + warningPopUpDuplicatePerson.addCommitListener(() -> { + immunizationSaveTriggered = true; + ControllerProvider.getPersonController() + .selectOrCreatePerson( + person, + I18nProperties.getString(Strings.infoSelectOrCreatePersonForImmunization), + selectedPerson -> { + if (selectedPerson != null) { + selectOrCreateimmunizationForPerson(dto, selectedPerson); + } + }, + true); + }); + } else { + ControllerProvider.getPersonController() + .selectOrCreatePerson( + person, + I18nProperties.getString(Strings.infoSelectOrCreatePersonForImmunization), + selectedPerson -> { + if (selectedPerson != null) { + selectOrCreateimmunizationForPerson(dto, selectedPerson); + } + }, + true); + } } } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationDataView.java index bc59daabd97..d2cba6a96d0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationDataView.java @@ -4,20 +4,25 @@ import de.symeda.sormas.api.EditPermissionType; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiListCriteria; import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.immunization.ImmunizationDto; +import de.symeda.sormas.api.immunization.MeansOfImmunization; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.aefilink.AefiListComponent; import de.symeda.sormas.ui.immunization.components.form.ImmunizationDataForm; import de.symeda.sormas.ui.sormastosormas.SormasToSormasListComponent; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; import de.symeda.sormas.ui.utils.LayoutWithSidePanel; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentLayout; public class ImmunizationDataView extends AbstractImmunizationView { public static final String VIEW_NAME = ROOT_VIEW_NAME + "/data"; public static final String IMMUNIZATION_LOC = "immunization"; + public static final String ADVERSE_EVENTS_LOC = "adverseEvents"; public static final String SORMAS_TO_SORMAS_LOC = "sormsToSormas"; private CommitDiscardWrapperComponent editComponent; @@ -46,11 +51,24 @@ protected void initView(String params) { setSubComponent(container); container.setEnabled(true); - LayoutWithSidePanel layout = new LayoutWithSidePanel(editComponent, SORMAS_TO_SORMAS_LOC); + LayoutWithSidePanel layout = new LayoutWithSidePanel(editComponent, SORMAS_TO_SORMAS_LOC, ADVERSE_EVENTS_LOC); container.addComponent(layout); ImmunizationDto immunization = FacadeProvider.getImmunizationFacade().getImmunizationByUuid(getReference().getUuid()); + + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_MANAGEMENT) + && (immunization.getMeansOfImmunization() == MeansOfImmunization.VACCINATION + || immunization.getMeansOfImmunization() == MeansOfImmunization.VACCINATION_RECOVERY)) { + AefiListCriteria aefiListCriteria = new AefiListCriteria.Builder(getReference()).build(); + + AefiListComponent aefiListComponent = + new AefiListComponent(aefiListCriteria, this::showUnsavedChangesPopup, isEditAllowed(), immunization.getVaccinations().size()); + CssStyles.style(aefiListComponent, CssStyles.VIEW_SECTION); + + layout.addSidePanelComponent(new SideComponentLayout(aefiListComponent), ADVERSE_EVENTS_LOC); + } + boolean sormasToSormasEnabled = FacadeProvider.getSormasToSormasFacade() .isAnyFeatureConfigured( FeatureType.SORMAS_TO_SORMAS_SHARE_CASES, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationCreationForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationCreationForm.java index f8d955c3ee1..87265176ea6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationCreationForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationCreationForm.java @@ -27,6 +27,7 @@ import java.util.Collections; import com.vaadin.ui.Label; +import com.vaadin.ui.Window; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.ComboBox; import com.vaadin.v7.ui.DateField; @@ -56,6 +57,7 @@ import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UiUtil; 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.DateComparisonValidator; @@ -96,6 +98,7 @@ public class ImmunizationCreationForm extends AbstractEditForm private ComboBox responsibleRegion; private ComboBox responsibleDistrict; private ComboBox responsibleCommunity; + private Window warningSimilarPersons; public ImmunizationCreationForm() { this(null, null); @@ -125,7 +128,7 @@ protected void addFields() { TextField externalIdField = addField(ImmunizationDto.EXTERNAL_ID, TextField.class); style(externalIdField, ERROR_COLOR_PRIMARY); - ComboBox diseaseField = addDiseaseField(ImmunizationDto.DISEASE, false, true); + ComboBox diseaseField = addDiseaseField(ImmunizationDto.DISEASE, false, true, false); addField(ImmunizationDto.DISEASE_DETAILS, TextField.class); ComboBox meansOfImmunizationField = addField(ImmunizationDto.MEANS_OF_IMMUNIZATION, ComboBox.class); @@ -191,6 +194,11 @@ protected void addFields() { personCreateForm = new PersonCreateForm(false, true, false); personCreateForm.setWidth(100, Unit.PERCENTAGE); personCreateForm.setValue(new PersonDto()); + personCreateForm.getNationalHealthIdField().addTextFieldValueChangeListener(e -> { + warningSimilarPersons = PersonFormHelper + .warningSimilarPersons(personCreateForm.getNationalHealthIdField().getValue(), null, () -> warningSimilarPersons = null); + }); + diseaseField.addValueChangeListener( (ValueChangeListener) valueChangeEvent -> personCreateForm .updatePresentConditionEnum((Disease) valueChangeEvent.getProperty().getValue())); @@ -406,4 +414,8 @@ protected void setInternalValue(ImmunizationDto newValue) { hideAndFillJurisdictionFields(); } } + + public Window getWarningSimilarPersons() { + return warningSimilarPersons; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java index af1e2f96a19..09baebb7a43 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java @@ -66,7 +66,6 @@ import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.infrastructure.facility.FacilityTypeGroup; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.SearchSpecificLayout; @@ -78,6 +77,7 @@ import de.symeda.sormas.ui.utils.ComboBoxWithPlaceholder; import de.symeda.sormas.ui.utils.ConfirmationComponent; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.InfrastructureFieldsHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -139,7 +139,7 @@ public ImmunizationDataForm(boolean isPseudonymized, boolean inJurisdiction, Cas ImmunizationDto.I18N_PREFIX, false, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.relatedCase = relatedCase; this.actionCallback = actionCallback; addFields(); @@ -164,7 +164,7 @@ protected void addFields() { UserField reportingUser = addField(ImmunizationDto.REPORTING_USER, UserField.class); reportingUser.setParentPseudonymizedSupplier(() -> getValue().isPseudonymized()); - ComboBox cbDisease = addDiseaseField(ImmunizationDto.DISEASE, false); + ComboBox cbDisease = addDiseaseField(ImmunizationDto.DISEASE, false, false); addField(ImmunizationDto.DISEASE_DETAILS, TextField.class); ComboBox meansOfImmunizationField = addField(ImmunizationDto.MEANS_OF_IMMUNIZATION, ComboBox.class); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DataImporter.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DataImporter.java index dbd5ac555d3..9a1da11079d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DataImporter.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DataImporter.java @@ -448,7 +448,7 @@ protected boolean executeDefaultInvoke(PropertyDescriptor pd, Object element, St if (propertyType.isAssignableFrom(OccupationType.class)) { OccupationType occupationType = null; try { - occupationType = FacadeProvider.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.OCCUPATION_TYPE, entry); + occupationType = FacadeProvider.getCustomizableEnumFacade().getEnumValue(CustomizableEnumType.OCCUPATION_TYPE, null, entry); } catch (EJBException e) { //ignore, occupationType will remain null } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DocumentTemplateReceiver.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DocumentTemplateReceiver.java index b8336e890c4..dda954b2d26 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DocumentTemplateReceiver.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/importer/DocumentTemplateReceiver.java @@ -10,13 +10,16 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Date; +import java.util.function.Supplier; import com.vaadin.server.Page; import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.v7.ui.Upload.StartedEvent; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.docgeneneration.DocumentTemplateDto; import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -35,9 +38,11 @@ public class DocumentTemplateReceiver private File file; private String fName; private final DocumentWorkflow documentWorkflow; + private final Supplier diseaseSupplier; - public DocumentTemplateReceiver(DocumentWorkflow documentWorkflow) { + public DocumentTemplateReceiver(DocumentWorkflow documentWorkflow, Supplier diseaseSupplier) { this.documentWorkflow = documentWorkflow; + this.diseaseSupplier = diseaseSupplier; } @Override @@ -89,7 +94,7 @@ public void uploadSucceeded(com.vaadin.v7.ui.Upload.SucceededEvent succeededEven } // Check for duplicate files - if (FacadeProvider.getDocumentTemplateFacade().isExistingTemplate(documentWorkflow, fName)) { + if (FacadeProvider.getDocumentTemplateFacade().isExistingTemplateFile(documentWorkflow, diseaseSupplier.get(), fName)) { VaadinUiUtil.showConfirmationPopup( I18nProperties.getString(Strings.headingFileExists), new Label(String.format(I18nProperties.getString(Strings.infoDocumentAlreadyExists), fName)), @@ -108,8 +113,9 @@ public void uploadSucceeded(com.vaadin.v7.ui.Upload.SucceededEvent succeededEven private void writeTemplateFile() { try { - byte[] filecontent = Files.readAllBytes(file.toPath()); - FacadeProvider.getDocumentTemplateFacade().writeDocumentTemplate(documentWorkflow, fName, filecontent); + byte[] fileContent = Files.readAllBytes(file.toPath()); + DocumentTemplateDto documentTemplateDto = DocumentTemplateDto.build(documentWorkflow, fName, diseaseSupplier.get()); + FacadeProvider.getDocumentTemplateFacade().saveDocumentTemplate(documentTemplateDto, fileContent); VaadinUiUtil.showSimplePopupWindow( I18nProperties.getString(Strings.headingUploadSuccess), I18nProperties.getString(Strings.messageUploadSuccessful)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginScreen.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginScreen.java index bd13ce6b7f3..f5c100950db 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginScreen.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/login/LoginScreen.java @@ -315,12 +315,6 @@ private Layout buildLoginSidebarLayout() { imgSormasFoundation.setWidth(isCustomBranding ? CUSTOM_BRANDING_LOGO_WIDTH : LOGO_WIDTH, Unit.PIXELS); poweredByLayout.addComponent(imgSormasFoundation); - if (!isCustomBranding) { - Image imgGiz = new Image(null, new ThemeResource("img/giz-logo.png")); - imgGiz.setWidth(isCustomBranding ? CUSTOM_BRANDING_LOGO_WIDTH : LOGO_WIDTH, Unit.PIXELS); - poweredByLayout.addComponent(imgGiz); - } - loginSidebarLayout.addComponent(poweredByLayout); Label customSidebarLabel = new Label(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonContactDetailsField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonContactDetailsField.java index 66c471fd9da..491cd82be6a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonContactDetailsField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonContactDetailsField.java @@ -11,6 +11,7 @@ import com.vaadin.v7.data.Property; import com.vaadin.v7.ui.Table; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -161,8 +162,9 @@ protected void updateColumns() { table.setColumnExpandRatio(ACTION_COLUMN_ID, 0); table.setCellStyleGenerator( - FieldAccessCellStyleGenerator - .withFieldAccessCheckers(PersonContactDetailDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + PersonContactDetailDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); table.setColumnExpandRatio(COLUMN_PRIMARY, 0); table.setColumnExpandRatio(COLUMN_OWNER, 0); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java index 03e117f37fa..88f53a0b9e9 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java @@ -474,7 +474,14 @@ public CommitDiscardWrapperComponent getPersonEditComponent( editView.addCommitListener(() -> { if (!editForm.getFieldGroup().isModified()) { PersonDto dto = editForm.getValue(); - savePerson(dto); + if (editForm.getWarningSimilarPersons() != null) { + CommitDiscardWrapperComponent content = + (CommitDiscardWrapperComponent) editView.getWrappedComponent().getWarningSimilarPersons().getContent(); + content.getDiscardButton().setVisible(true); + content.addCommitListener(() -> savePerson(dto)); + } else { + savePerson(dto); + } } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonCreateForm.java index 075fc55ed00..0827f474a00 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonCreateForm.java @@ -33,6 +33,7 @@ import com.vaadin.icons.VaadinIcons; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Window; import com.vaadin.v7.data.validator.EmailValidator; import com.vaadin.v7.ui.AbstractSelect; import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode; @@ -65,6 +66,7 @@ import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.PhoneNumberValidator; import de.symeda.sormas.ui.utils.VaadinUiUtil; +import de.symeda.sormas.ui.utils.components.SormasTextField; public class PersonCreateForm extends AbstractEditForm { @@ -86,6 +88,8 @@ public class PersonCreateForm extends AbstractEditForm { private final boolean showPresentCondition; private final boolean showSymptomsOnsetDate; private final boolean showPersonSearchButton; + private SormasTextField nationalHealthIdField; + private Window warningSimilarPersons; private static final String HTML_LAYOUT = "%s" + fluidRow(fluidRowLocs(PersonDto.BIRTH_DATE_YYYY, PersonDto.BIRTH_DATE_MM, PersonDto.BIRTH_DATE_DD), fluidRowLocs(PersonDto.SEX)) @@ -111,7 +115,7 @@ public PersonCreateForm( PersonDto.I18N_PREFIX, false, FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.getDefault(false)); + UiFieldAccessCheckers.getDefault(false, FacadeProvider.getConfigFacade().getCountryLocale())); this.showHomeAddressForm = showHomeAddressForm; this.showPresentCondition = showPresentCondition; this.showSymptomsOnsetDate = showSymptomsOnsetDate; @@ -186,7 +190,9 @@ protected void addFields() { ComboBox sex = addField(PersonDto.SEX, ComboBox.class); addField(PersonDto.PASSPORT_NUMBER, TextField.class); - addField(PersonDto.NATIONAL_HEALTH_ID, TextField.class); + + nationalHealthIdField = addField(PersonDto.NATIONAL_HEALTH_ID, SormasTextField.class); + nationalHealthIdField.setNullRepresentation(""); ComboBox presentCondition = addField(PersonDto.PRESENT_CONDITION, ComboBox.class); presentCondition.setVisible(showPresentCondition); @@ -498,4 +504,12 @@ public PersonDto getSearchedPerson() { public void setSearchedPerson(PersonDto searchedPerson) { this.person = searchedPerson; } + + public Window getWarningSimilarPersons() { + return warningSimilarPersons; + } + + public SormasTextField getNationalHealthIdField() { + return nationalHealthIdField; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java index d3af772d3bc..c1d2af88566 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java @@ -33,6 +33,7 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -40,6 +41,7 @@ import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Window; import com.vaadin.v7.data.Item; import com.vaadin.v7.data.Property; import com.vaadin.v7.ui.AbstractSelect; @@ -78,23 +80,23 @@ import de.symeda.sormas.api.person.Salutation; import de.symeda.sormas.api.utils.DataHelper.Pair; import de.symeda.sormas.api.utils.DateHelper; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.api.utils.fieldvisibility.checkers.CountryFieldVisibilityChecker; import de.symeda.sormas.api.utils.luxembourg.LuxembourgNationalHealthIdValidator; import de.symeda.sormas.ui.ControllerProvider; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.location.LocationEditForm; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.ApproximateAgeValidator; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.OutbreakFieldVisibilityChecker; import de.symeda.sormas.ui.utils.ResizableTextAreaWrapper; import de.symeda.sormas.ui.utils.SormasFieldGroupFieldFactory; import de.symeda.sormas.ui.utils.ValidationUtils; import de.symeda.sormas.ui.utils.ViewMode; +import de.symeda.sormas.ui.utils.components.SormasTextField; public class PersonEditForm extends AbstractEditForm { @@ -185,6 +187,8 @@ public class PersonEditForm extends AbstractEditForm { private boolean isPseudonymized; private LocationEditForm addressForm; private PresentConditionChangeListener presentConditionChangeListener; + private SormasTextField nationalHealthIdField; + private Window warningSimilarPersons; //@formatter:on public PersonEditForm( @@ -202,7 +206,7 @@ public PersonEditForm( FieldVisibilityCheckers.withDisease(disease) .add(new OutbreakFieldVisibilityChecker(viewMode)) .add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized), isEditAllowed); this.personContext = personContext; @@ -233,7 +237,7 @@ public PersonEditForm( FieldVisibilityCheckers.withDisease(disease) .add(new OutbreakFieldVisibilityChecker(viewMode)) .add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); this.personContext = personContext; this.disease = disease; @@ -256,7 +260,7 @@ public PersonEditForm(boolean isEditAllowed, boolean isPseudonymized, boolean in false, new FieldVisibilityCheckers().add(new OutbreakFieldVisibilityChecker(ViewMode.NORMAL)) .add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized), + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized), isEditAllowed); CssStyles.style(CssStyles.H3, occupationHeader, addressHeader, addressesHeader, contactInformationHeader); @@ -297,13 +301,8 @@ protected void addFields() { ComboBox birthDateMonth = addField(PersonDto.BIRTH_DATE_MM, ComboBox.class); // @TODO: Done for nullselection Bug, fixed in Vaadin 7.7.3 birthDateMonth.setNullSelectionAllowed(true); - birthDateMonth.addItems(DateHelper.getMonthsInYear()); - birthDateMonth.setPageLength(12); birthDateMonth.setInputPrompt(I18nProperties.getString(Strings.month)); birthDateMonth.setCaption(""); - DateHelper.getMonthsInYear() - .forEach(month -> birthDateMonth.setItemCaption(month, de.symeda.sormas.api.Month.values()[month - 1].toString())); - setItemCaptionsForMonths(birthDateMonth); ComboBox birthDateYear = addField(PersonDto.BIRTH_DATE_YYYY, ComboBox.class); birthDateYear.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.BIRTH_DATE)); // @TODO: Done for nullselection Bug, fixed in Vaadin 7.7.3 @@ -373,7 +372,8 @@ protected void addFields() { addField(PersonDto.PASSPORT_NUMBER); - TextField nationalHealthIdField = addField(PersonDto.NATIONAL_HEALTH_ID); + nationalHealthIdField = addField(PersonDto.NATIONAL_HEALTH_ID, SormasTextField.class); + nationalHealthIdField.setNullRepresentation(""); Label nationalHealthIdWarningLabel = new Label(I18nProperties.getString(Strings.messagePersonNationalHealthIdInvalid)); nationalHealthIdWarningLabel.addStyleNames(VSPACE_3, LABEL_WHITE_SPACE_NORMAL); nationalHealthIdWarningLabel.setVisible(false); @@ -389,6 +389,17 @@ protected void addFields() { getContent().addComponent(externalTokenWarningLabel, EXTERNAL_TOKEN_WARNING_LOC); addField(PersonDto.INTERNAL_TOKEN); + AtomicBoolean nationalHealthIdFirstLoading = new AtomicBoolean(true); + nationalHealthIdField.addTextFieldValueChangeListener(e -> { + String currentPersonUuid = this.getValue().getUuid(); + if (nationalHealthIdFirstLoading.get()) { + nationalHealthIdFirstLoading.set(false); + } else { + warningSimilarPersons = + PersonFormHelper.warningSimilarPersons(nationalHealthIdField.getValue(), currentPersonUuid, () -> warningSimilarPersons = null); + } + }); + addField(PersonDto.HAS_COVID_APP).addStyleName(CssStyles.FORCE_CAPTION_CHECKBOX); addField(PersonDto.COVID_CODE_DELIVERED).addStyleName(CssStyles.FORCE_CAPTION_CHECKBOX); @@ -408,7 +419,7 @@ protected void addFields() { TextField tfPlaceOfBirthFacilityDetails = addField(PersonDto.PLACE_OF_BIRTH_FACILITY_DETAILS, TextField.class); causeOfDeathField = addField(PersonDto.CAUSE_OF_DEATH, ComboBox.class); - causeOfDeathDiseaseField = addDiseaseField(PersonDto.CAUSE_OF_DEATH_DISEASE, true); + causeOfDeathDiseaseField = addDiseaseField(PersonDto.CAUSE_OF_DEATH_DISEASE, true, false); causeOfDeathDetailsField = addField(PersonDto.CAUSE_OF_DEATH_DETAILS, TextField.class); // Set requirements that don't need visibility changes and read only status @@ -447,6 +458,13 @@ protected void addFields() { initializeVisibilitiesAndAllowedVisibilities(); initializeAccessAndAllowedAccesses(); + if (isEditableAllowed(PersonDto.BIRTH_DATE_MM)) { + birthDateMonth.addItems(DateHelper.getMonthsInYear()); + birthDateMonth.setPageLength(13); + DateHelper.getMonthsInYear() + .forEach(month -> birthDateMonth.setItemCaption(month, de.symeda.sormas.api.Month.values()[month - 1].toString())); + } + if (!getField(PersonDto.OCCUPATION_TYPE).isVisible() && !getField(PersonDto.ARMED_FORCES_RELATION_TYPE).isVisible() && !getField(PersonDto.EDUCATION_TYPE).isVisible()) @@ -904,6 +922,10 @@ public Field getLastNameField() { return lastNameField; } + public Window getWarningSimilarPersons() { + return warningSimilarPersons; + } + @Override protected F addFieldToLayout(CustomLayout layout, String propertyId, F field) { field.addValueChangeListener(e -> fireValueChange(false)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java index 399151f8558..4b727d62fdd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java @@ -1,5 +1,11 @@ package de.symeda.sormas.ui.person; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; + +import java.util.Date; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.HorizontalLayout; import com.vaadin.v7.data.Property; import com.vaadin.v7.ui.ComboBox; import com.vaadin.v7.ui.TextField; @@ -19,11 +25,16 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractFilterForm; +import de.symeda.sormas.ui.utils.BirthdateRangeFilterComponent; import de.symeda.sormas.ui.utils.FieldConfiguration; import de.symeda.sormas.ui.utils.FieldHelper; public class PersonFilterForm extends AbstractFilterForm { + private static final String BIRTHDATE_RANGE_FILTER = "birthdateRangeFilter"; + + private static final String MORE_FILTERS_HTML_LAYOUT = loc(BIRTHDATE_RANGE_FILTER); + protected PersonFilterForm() { super( PersonCriteria.class, @@ -44,6 +55,11 @@ protected String[] getMainFilterLocators() { PersonCriteria.COMMUNITY }; } + @Override + protected String createMoreFiltersHtmlLayout() { + return MORE_FILTERS_HTML_LAYOUT; + } + @Override protected void addFields() { @@ -78,6 +94,37 @@ protected void addFields() { FieldConfiguration.withCaptionAndPixelSized(PersonCriteria.COMMUNITY, I18nProperties.getCaption(Captions.personCommunityPrompt), 140)); } + @Override + public void addMoreFilters(CustomLayout moreFiltersContainer) { + + moreFiltersContainer.addComponent(buildBirthdayRangeFilter(), BIRTHDATE_RANGE_FILTER); + } + + private HorizontalLayout buildBirthdayRangeFilter() { + BirthdateRangeFilterComponent birthdateRangeFilterComponent = new BirthdateRangeFilterComponent(false, this); + addApplyHandler(e -> onApplyClick(birthdateRangeFilterComponent)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(birthdateRangeFilterComponent); + + return dateFilterRowLayout; + } + + private void onApplyClick(BirthdateRangeFilterComponent birthdateRangeFilter) { + Date birthdateFrom, birthdateTo; + Date dateFrom = birthdateRangeFilter.getDateFromFilter().getValue(); + birthdateFrom = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = birthdateRangeFilter.getDateToFilter().getValue(); + birthdateTo = dateTo != null ? DateHelper.getEndOfDay(dateTo) : null; + PersonCriteria criteria = getValue(); + criteria.setBirthdateFrom(birthdateFrom); + criteria.setBirthdateTo(birthdateTo); + criteria.setIncludePartialMatch(birthdateRangeFilter.getIncludePartialMatch().getValue()); + } + @Override protected void applyDependenciesOnFieldChange(String propertyId, Property.ValueChangeEvent event) { super.applyDependenciesOnFieldChange(propertyId, event); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFormHelper.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFormHelper.java new file mode 100644 index 00000000000..427a3536fad --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFormHelper.java @@ -0,0 +1,55 @@ +package de.symeda.sormas.ui.person; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; + +import com.vaadin.server.Sizeable; +import com.vaadin.ui.Window; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.person.PersonSimilarityCriteria; +import de.symeda.sormas.api.person.SimilarPersonDto; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.VaadinUiUtil; + +public class PersonFormHelper { + + public static Window warningSimilarPersons(String nationalHealthId, String currentPersonUuid, Runnable callback) { + if (StringUtils.isNoneBlank(nationalHealthId)) { + PersonDto currentPerson = new PersonDto(); + currentPerson.setNationalHealthId(nationalHealthId); + List similarPersonDtos = + FacadeProvider.getPersonFacade().getSimilarPersonDtos(PersonSimilarityCriteria.forPerson(currentPerson, true)); + List filteredSimilarPersons = similarPersonDtos.stream() + .filter(similarPersonDto -> !similarPersonDto.getUuid().equals(currentPersonUuid)) + .collect(Collectors.toList()); + + if (!filteredSimilarPersons.isEmpty()) { + PersonSelectionGrid similarPersonGrid = new PersonSelectionGrid(); + similarPersonGrid.loadData(filteredSimilarPersons); + + final CommitDiscardWrapperComponent component = new CommitDiscardWrapperComponent<>(similarPersonGrid); + component.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionDone)); + component.getCommitButton().setDescription(I18nProperties.getCaption(Captions.actionOkay)); + component.getDiscardButton().setVisible(false); + component.getWrappedComponent().setWidth(800, Sizeable.Unit.PIXELS); + + Window popupWindow = VaadinUiUtil.showPopupWindow(component); + component.addDoneListener(() -> { + popupWindow.close(); + callback.run(); + }); + popupWindow.setCaption(I18nProperties.getString(Strings.headingSimilarPerson)); + popupWindow.setWidth(900, Sizeable.Unit.PIXELS); + return popupWindow; + } + } + return null; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java index 3cfdbf8d70f..8640ddf7df2 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java @@ -269,7 +269,7 @@ protected void addFilterForm() { * Load a grid of all persons similar to the given reference person. */ protected void initializeGrid() { - defaultCriteria = PersonSimilarityCriteria.forPerson(referencePerson, true); + defaultCriteria = PersonSimilarityCriteria.forPerson(referencePerson, true, false); personGrid = new PersonSelectionGrid(); personGrid.addSelectionListener(e -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java index 0762c264e40..e4fe4f63b59 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java @@ -104,4 +104,11 @@ public void loadData(PersonSimilarityCriteria criteria) { getContainer().addAll(similarPersons); setHeightByRows(similarPersons.size() > 0 ? (Math.min(similarPersons.size(), 10)) : 1); } + + public void loadData(List similarPersons) { + getContainer().removeAllItems(); + getContainer().addAll(similarPersons); + setHeightByRows(similarPersons.size() > 0 ? (Math.min(similarPersons.size(), 10)) : 1); + } + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java index d2b201c05e5..0d21235cd02 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java @@ -58,14 +58,13 @@ import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SamplePurpose; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.DateFormatHelper; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldConfiguration; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -158,9 +157,7 @@ public PathogenTestForm(boolean create, int caseSampleCount, boolean isPseudonym PathogenTestDto.I18N_PREFIX, false, FieldVisibilityCheckers.withDisease(null).andWithCountry(FacadeProvider.getConfigFacade().getCountryLocale()), - UiFieldAccessCheckers.forDataAccessLevel( - UiUtil.getPseudonymizableDataAccessLevel(create || inJurisdiction), // Jurisdiction doesn't matter for creation forms - !create && isPseudonymized)); // Pseudonymization doesn't matter for creation forms + FieldAccessHelper.getFieldAccessCheckers(create || inJurisdiction, !create && isPseudonymized));// Jurisdiction doesn't matter for creation forms // Pseudonymization doesn't matter for creation forms this.caseSampleCount = caseSampleCount; this.create = create; @@ -256,7 +253,7 @@ protected void addFields() { typingIdField.setVisible(false); // Tested Desease or Tested Pathogen, depending on sample type - ComboBox diseaseField = addDiseaseField(PathogenTestDto.TESTED_DISEASE, true, create); + ComboBox diseaseField = addDiseaseField(PathogenTestDto.TESTED_DISEASE, true, create, false); addField(PathogenTestDto.TESTED_DISEASE_DETAILS, TextField.class); ComboBox diseaseVariantField = addCustomizableEnumField(PathogenTestDto.TESTED_DISEASE_VARIANT); diseaseVariantField.setNullSelectionAllowed(true); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/environmentsample/EnvironmentSampleEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/environmentsample/EnvironmentSampleEditForm.java index 530e5d69aea..799b3380fb1 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/environmentsample/EnvironmentSampleEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/environmentsample/EnvironmentSampleEditForm.java @@ -117,7 +117,7 @@ public EnvironmentSampleEditForm(boolean isPseudonymized, boolean isCreate) { EnvironmentSampleDto.I18N_PREFIX, false, FieldVisibilityCheckers.getNoop(), - UiFieldAccessCheckers.getDefault(isPseudonymized)); + UiFieldAccessCheckers.getDefault(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale())); this.isCreate = isCreate; addFields(); addValueChangeListener(e -> defaultValueChangeListener((EnvironmentSampleDto) e.getProperty().getValue())); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleDataView.java index cca12f46ed6..0544db8e6c4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleDataView.java @@ -37,7 +37,6 @@ import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.ui.AbstractInfoLayout; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UiUtil; @@ -52,6 +51,7 @@ import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.LayoutWithSidePanel; import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentLayout; @@ -201,8 +201,7 @@ private AbstractInfoLayout getDependentSideComponent(SampleDto sample disease = contactDto.getDisease(); - final ContactInfoLayout contactInfoLayout = - new ContactInfoLayout(contactDto, UiFieldAccessCheckers.getDefault(contactDto.isPseudonymized())); + final ContactInfoLayout contactInfoLayout = new ContactInfoLayout(contactDto, FieldAccessHelper.getFieldAccessCheckers(contactDto)); contactInfoLayout.addStyleName(CssStyles.SIDE_COMPONENT); return (AbstractInfoLayout) contactInfoLayout; @@ -216,10 +215,8 @@ private AbstractInfoLayout getDependentSideComponent(SampleDto sample disease = eventDto.getDisease(); - final EventParticipantInfoLayout eventParticipantInfoLayout = new EventParticipantInfoLayout( - eventParticipantDto, - eventDto, - UiFieldAccessCheckers.getDefault(eventParticipantDto.isPseudonymized())); + final EventParticipantInfoLayout eventParticipantInfoLayout = + new EventParticipantInfoLayout(eventParticipantDto, eventDto, FieldAccessHelper.getFieldAccessCheckers(eventParticipantDto)); eventParticipantInfoLayout.addStyleName(CssStyles.SIDE_COMPONENT); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleEditForm.java index f2f6cabaa40..8e5073026a7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/humansample/SampleEditForm.java @@ -41,12 +41,12 @@ import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.samples.AbstractSampleForm; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.DateFormatHelper; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; public class SampleEditForm extends AbstractSampleForm { @@ -62,11 +62,7 @@ public class SampleEditForm extends AbstractSampleForm { private Label laboratorySampleHeadingLabel; public SampleEditForm(boolean isPseudonymized, boolean inJurisdiction, Disease disease) { - super( - SampleDto.class, - SampleDto.I18N_PREFIX, - disease, - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + super(SampleDto.class, SampleDto.I18N_PREFIX, disease, FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); testsToBeRemovedOnCommit = new ArrayList(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/selfreport/SelfReportDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/selfreport/SelfReportDataForm.java index fc9861b1581..902941e6a3b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/selfreport/SelfReportDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/selfreport/SelfReportDataForm.java @@ -49,14 +49,13 @@ import de.symeda.sormas.api.user.JurisdictionLevel; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.api.utils.fieldvisibility.checkers.CountryFieldVisibilityChecker; import de.symeda.sormas.api.utils.luxembourg.LuxembourgNationalHealthIdValidator; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.location.LocationEditForm; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.PhoneNumberValidator; import de.symeda.sormas.ui.utils.ValidationUtils; @@ -95,7 +94,7 @@ public SelfReportDataForm(Disease disease, boolean inJurisdiction, boolean isPse SelfReportDto.I18N_PREFIX, true, FieldVisibilityCheckers.withDisease(disease).add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); } @Override @@ -115,7 +114,7 @@ protected void addFields() { addField(SelfReportDto.CASE_REFERENCE); //disease related fieldss - ComboBox diseaseField = addDiseaseField(SelfReportDto.DISEASE, false); + ComboBox diseaseField = addDiseaseField(SelfReportDto.DISEASE, false, false); addField(SelfReportDto.DISEASE_DETAILS, TextField.class); diseaseField.setRequired(true); ComboBox diseaseVariantField = addCustomizableEnumField(SelfReportDto.DISEASE_VARIANT); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskEditForm.java index 6b28f33007c..63d02222c71 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskEditForm.java @@ -63,6 +63,7 @@ import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; import de.symeda.sormas.ui.utils.TaskStatusValidator; +import de.symeda.sormas.ui.utils.VaadinUiUtil; import de.symeda.sormas.ui.utils.components.MultiSelect; @SuppressWarnings("deprecation") @@ -161,7 +162,11 @@ protected void addFields() { TextArea creatorComment = addField(TaskDto.CREATOR_COMMENT, TextArea.class); creatorComment.setRows(2); creatorComment.setImmediate(true); - addField(TaskDto.ASSIGNEE_REPLY, TextArea.class).setRows(4); + VaadinUiUtil.addGdprMessageOnClick(creatorComment); + + TextArea assigneeReply = addField(TaskDto.ASSIGNEE_REPLY, TextArea.class); + assigneeReply.setRows(4); + VaadinUiUtil.addGdprMessageOnClick(assigneeReply); MultiSelect observerUsers = addField(TaskDto.OBSERVER_USERS, MultiSelect.class); observerUsers.addValueChangeListener(e -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskGrid.java index c723f40551b..a20d3560303 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskGrid.java @@ -166,7 +166,7 @@ public TaskGrid(TaskCriteria criteria) { getColumn(TaskIndexDto.CONTEXT_REFERENCE).setStyleGenerator(new FieldAccessColumnStyleGenerator<>(task -> { boolean isInJurisdiction = task.getTaskJurisdictionFlagsDto().getInJurisdiction(); - return UiFieldAccessCheckers.getDefault(!isInJurisdiction).hasRight(); + return UiFieldAccessCheckers.getDefault(!isInJurisdiction, FacadeProvider.getConfigFacade().getCountryLocale()).hasRight(); })); addItemClickListener(new ShowDetailsListener<>(TaskIndexDto.CONTEXT_REFERENCE, false, this::navigateToData)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionForm.java index ce174d85b2e..80bba42de13 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionForm.java @@ -17,11 +17,10 @@ import de.symeda.sormas.api.therapy.PrescriptionDto; import de.symeda.sormas.api.therapy.TreatmentRoute; import de.symeda.sormas.api.therapy.TreatmentType; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -43,7 +42,7 @@ public PrescriptionForm(boolean create, boolean readOnly, boolean isPseudonymize PrescriptionDto.I18N_PREFIX, false, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); addFields(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionGrid.java index f4c18f9d98b..fb60dd7c797 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/PrescriptionGrid.java @@ -96,8 +96,9 @@ public Class getType() { I18nProperties.getPrefixCaption(PrescriptionIndexDto.I18N_PREFIX, column.getPropertyId().toString(), column.getHeaderCaption())); setCellStyleGenerator( - FieldAccessCellStyleGenerator - .withFieldAccessCheckers(PrescriptionIndexDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + PrescriptionIndexDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); } addItemClickListener(e -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentForm.java index e91756f128b..ecf5bd9d10e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentForm.java @@ -13,11 +13,10 @@ import de.symeda.sormas.api.therapy.TreatmentDto; import de.symeda.sormas.api.therapy.TreatmentRoute; import de.symeda.sormas.api.therapy.TreatmentType; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -38,7 +37,7 @@ public TreatmentForm(boolean create, boolean isPseudonymized, boolean inJurisdic TreatmentDto.I18N_PREFIX, true, new FieldVisibilityCheckers(), - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized)); setWidth(680, Unit.PIXELS); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentGrid.java index 6172746f547..13d534355bd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TreatmentGrid.java @@ -67,8 +67,9 @@ public TreatmentGrid( I18nProperties.getPrefixCaption(TreatmentIndexDto.I18N_PREFIX, column.getPropertyId().toString(), column.getHeaderCaption())); setCellStyleGenerator( - FieldAccessCellStyleGenerator - .withFieldAccessCheckers(TreatmentIndexDto.class, UiFieldAccessCheckers.forSensitiveData(isPseudonymized))); + FieldAccessCellStyleGenerator.withFieldAccessCheckers( + TreatmentIndexDto.class, + UiFieldAccessCheckers.forSensitiveData(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()))); } addItemClickListener(e -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java index 8432275a15c..579d7702030 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java @@ -20,6 +20,7 @@ import de.symeda.sormas.api.docgeneneration.DocumentWorkflow; import de.symeda.sormas.api.docgeneneration.RootEntityType; import de.symeda.sormas.api.document.DocumentRelatedEntityType; +import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.person.PersonDto; @@ -32,6 +33,7 @@ import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UiUtil; +import de.symeda.sormas.ui.person.PersonSelectionGrid; import de.symeda.sormas.ui.travelentry.components.TravelEntryCreateForm; import de.symeda.sormas.ui.utils.ArchiveHandlers; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; @@ -43,6 +45,9 @@ public class TravelEntryController { + private boolean travelEntrySaveTriggered; + private CommitDiscardWrapperComponent travelEntryCreateComponent; + public void registerViews(Navigator navigator) { navigator.addView(TravelEntriesView.VIEW_NAME, TravelEntriesView.class); navigator.addView(TravelEntryDataView.VIEW_NAME, TravelEntryDataView.class); @@ -50,7 +55,7 @@ public void registerViews(Navigator navigator) { } public void create() { - CommitDiscardWrapperComponent travelEntryCreateComponent = getTravelEntryCreateComponent(null, null); + travelEntryCreateComponent = getTravelEntryCreateComponent(null, null); VaadinUiUtil.showModalPopupWindow(travelEntryCreateComponent, I18nProperties.getString(Strings.headingCreateNewTravelEntry)); } @@ -106,14 +111,39 @@ private CommitDiscardWrapperComponent getTravelEntryCreat if (dto.getPerson() == null) { final PersonDto person = createForm.getPerson(); - ControllerProvider.getPersonController() - .selectOrCreatePerson(person, I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase), selectedPerson -> { - if (selectedPerson != null) { - dto.setPerson(selectedPerson); - FacadeProvider.getTravelEntryFacade().save(dto); - navigateToTravelEntry(dto.getUuid()); + if (createForm.getWarningSimilarPersons() != null) { + CommitDiscardWrapperComponent warningPopUpDuplicatePerson = + (CommitDiscardWrapperComponent) editView.getWrappedComponent() + .getWarningSimilarPersons() + .getContent(); + warningPopUpDuplicatePerson.getDiscardButton().setVisible(true); + warningPopUpDuplicatePerson.getCommitButton().setCaption(I18nProperties.getCaption(Captions.actionContinue)); + warningPopUpDuplicatePerson.addDoneListener(() -> { + if (!travelEntrySaveTriggered) { + VaadinUiUtil.showModalPopupWindow(editView, I18nProperties.getString(Strings.headingCreateNewImmunization)); } - }, true); + }); + warningPopUpDuplicatePerson.addCommitListener(() -> { + travelEntrySaveTriggered = true; + ControllerProvider.getPersonController() + .selectOrCreatePerson(person, I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase), selectedPerson -> { + if (selectedPerson != null) { + dto.setPerson(selectedPerson); + FacadeProvider.getTravelEntryFacade().save(dto); + navigateToTravelEntry(dto.getUuid()); + } + }, true); + }); + } else { + ControllerProvider.getPersonController() + .selectOrCreatePerson(person, I18nProperties.getString(Strings.infoSelectOrCreatePersonForCase), selectedPerson -> { + if (selectedPerson != null) { + dto.setPerson(selectedPerson); + FacadeProvider.getTravelEntryFacade().save(dto); + navigateToTravelEntry(dto.getUuid()); + } + }, true); + } } else { FacadeProvider.getTravelEntryFacade().save(dto); navigateToTravelEntry(dto.getUuid()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataForm.java index a5b7c5979ee..f73ced0d30d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataForm.java @@ -52,6 +52,7 @@ import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.InfrastructureFieldsHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -152,7 +153,7 @@ protected void addFields() { TextField externalIdField = addField(TravelEntryDto.EXTERNAL_ID, TextField.class); style(externalIdField, ERROR_COLOR_PRIMARY); - ComboBox diseaseField = addDiseaseField(TravelEntryDto.DISEASE, false); + ComboBox diseaseField = addDiseaseField(TravelEntryDto.DISEASE, false, false); ComboBox diseaseVariantField = addCustomizableEnumField(TravelEntryDto.DISEASE_VARIANT); diseaseVariantField.setNullSelectionAllowed(true); diseaseVariantField.setVisible(false); @@ -439,7 +440,7 @@ private static UiFieldAccessCheckers createFieldAccessCheckers( boolean inJurisdiction, boolean withPersonalAndSensitive) { if (withPersonalAndSensitive) { - return UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), isPseudonymized); + return FieldAccessHelper.getFieldAccessCheckers(inJurisdiction, isPseudonymized); } return UiFieldAccessCheckers.getNoop(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/components/TravelEntryCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/components/TravelEntryCreateForm.java index cbf92e0a21f..0e8e974759a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/components/TravelEntryCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/components/TravelEntryCreateForm.java @@ -17,6 +17,7 @@ import org.apache.commons.collections4.CollectionUtils; import com.vaadin.ui.Label; +import com.vaadin.ui.Window; import com.vaadin.v7.data.util.converter.Converter; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.ComboBox; @@ -44,6 +45,7 @@ import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.person.PersonCreateForm; +import de.symeda.sormas.ui.person.PersonFormHelper; import de.symeda.sormas.ui.travelentry.DEAFormBuilder; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.FieldHelper; @@ -86,6 +88,7 @@ public class TravelEntryCreateForm extends AbstractEditForm { private PersonCreateForm personCreateForm; private final PersonReferenceDto personDto; + private Window warningSimilarPersons; public TravelEntryCreateForm() { this(null); @@ -113,7 +116,7 @@ protected void addFields() { TextField externalIdField = addField(TravelEntryDto.EXTERNAL_ID, TextField.class); style(externalIdField, ERROR_COLOR_PRIMARY); - ComboBox diseaseField = addDiseaseField(TravelEntryDto.DISEASE, false, true); + ComboBox diseaseField = addDiseaseField(TravelEntryDto.DISEASE, false, true, false); ComboBox diseaseVariantField = addField(TravelEntryDto.DISEASE_VARIANT, ComboBox.class); diseaseVariantField.setNullSelectionAllowed(true); diseaseVariantField.setVisible(false); @@ -156,6 +159,10 @@ protected void addFields() { personCreateForm.setWidth(100, Unit.PERCENTAGE); personCreateForm.setValue(new PersonDto()); getContent().addComponent(personCreateForm, TravelEntryDto.PERSON); + personCreateForm.getNationalHealthIdField().addTextFieldValueChangeListener(e -> { + warningSimilarPersons = PersonFormHelper + .warningSimilarPersons(personCreateForm.getNationalHealthIdField().getValue(), null, () -> warningSimilarPersons = null); + }); regionCombo.addItems(FacadeProvider.getRegionFacade().getAllActiveByServerCountry()); regionCombo.addValueChangeListener(e -> { @@ -315,4 +322,8 @@ public void setValue(TravelEntryDto newFieldValue) throws ReadOnlyException, Con responsibleCommunity.setReadOnly(true); } } + + public Window getWarningSimilarPersons() { + return warningSimilarPersons; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AbstractEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AbstractEditForm.java index 5e91c4022b7..fb3e4203bac 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AbstractEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AbstractEditForm.java @@ -15,6 +15,8 @@ package de.symeda.sormas.ui.utils; +import static com.vaadin.v7.data.fieldgroup.DefaultFieldGroupFieldFactory.CAPTION_PROPERTY_ID; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -45,6 +47,7 @@ import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; +import de.symeda.sormas.ui.clinicalcourse.HealthConditionsForm; import de.symeda.sormas.ui.utils.components.NotBlankTextValidator; public abstract class AbstractEditForm extends AbstractForm implements FieldGroup.CommitHandler {// implements DtoEditForm { @@ -196,8 +199,8 @@ public void discard() throws SourceException { super.discard(); } - protected ComboBox addDiseaseField(String fieldId, boolean showNonPrimaryDiseases) { - return addDiseaseField(fieldId, showNonPrimaryDiseases, false); + protected ComboBox addDiseaseField(String fieldId, boolean showNonPrimaryDiseases, boolean hideFollowUpDisabledDiseases) { + return addDiseaseField(fieldId, showNonPrimaryDiseases, false, hideFollowUpDisabledDiseases); } /** @@ -212,10 +215,19 @@ protected ComboBox addDiseaseField(String fieldId, boolean showNonPrimaryDisease * If only a single diseases is active on the server, set it as the default value */ @SuppressWarnings("unchecked") - protected ComboBox addDiseaseField(String fieldId, boolean showNonPrimaryDiseases, boolean setServerDiseaseAsDefault) { + protected ComboBox addDiseaseField( + String fieldId, + boolean showNonPrimaryDiseases, + boolean setServerDiseaseAsDefault, + boolean hideFollowUpDisabledDiseases) { diseaseField = addField(fieldId, ComboBox.class); this.setServerDiseaseAsDefault = setServerDiseaseAsDefault; + + if (hideFollowUpDisabledDiseases) { + removeFollowUpDisabledDiseases(diseaseField); + } + if (showNonPrimaryDiseases) { addNonPrimaryDiseasesTo(diseaseField); } @@ -229,9 +241,10 @@ protected ComboBox addDiseaseField(String fieldId, boolean showNonPrimaryDisease Object value = e.getProperty().getValue(); if (value != null && !diseaseField.containsId(value)) { Item newItem = diseaseField.addItem(value); - newItem.getItemProperty(SormasFieldGroupFieldFactory.CAPTION_PROPERTY_ID).setValue(value.toString()); + newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(value.toString()); } }); + return diseaseField; } @@ -498,7 +511,16 @@ protected void addNonPrimaryDiseasesTo(ComboBox diseaseField) { } Item newItem = diseaseField.addItem(disease); - newItem.getItemProperty(SormasFieldGroupFieldFactory.CAPTION_PROPERTY_ID).setValue(disease.toString()); + newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(disease.toString()); + } + } + + protected void removeFollowUpDisabledDiseases(ComboBox diseaseField) { + List allDiseasesWithFollowUp = FacadeProvider.getDiseaseConfigurationFacade().getAllDiseasesWithFollowUp(true, true, true); + diseaseField.removeAllItems(); + for (Object r : allDiseasesWithFollowUp) { + Item newItem = diseaseField.addItem(r); + newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(r.toString()); } } @@ -564,6 +586,12 @@ protected void initializeAccessAndAllowedAccesses() { if (field instanceof ComboBoxWithPlaceholder) { FieldHelper.setComboInaccessible((ComboBoxWithPlaceholder) field); } + + if (field instanceof NullableOptionGroup) { + ((NullableOptionGroup) field).setInaccessible(); + } + if (field instanceof HealthConditionsForm) + ((HealthConditionsForm) field).setInaccessible(); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AefiDownloadUtil.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AefiDownloadUtil.java new file mode 100644 index 00000000000..1f8174ec575 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/AefiDownloadUtil.java @@ -0,0 +1,67 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2024 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.utils; + +import java.util.Collection; +import java.util.Date; +import java.util.function.Supplier; + +import com.vaadin.server.StreamResource; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventsDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiCriteria; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiExportDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiIndexDto; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.importexport.ExportConfigurationDto; + +public class AefiDownloadUtil { + + private AefiDownloadUtil() { + } + + public static StreamResource createAefiExportResource( + AefiCriteria aefiCriteria, + Supplier> selectedRows, + ExportConfigurationDto exportConfiguration) { + return DownloadUtil.createCsvExportStreamResource( + AefiExportDto.class, + null, + (Integer start, Integer max) -> FacadeProvider.getAefiFacade().getExportList(aefiCriteria, selectedRows.get(), start, max), + AefiDownloadUtil::captionProvider, + ExportEntityName.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION, + exportConfiguration); + } + + public static String getPropertyCaption(String propertyId, String prefixId) { + if (prefixId != null) { + return I18nProperties.getPrefixCaption(prefixId, propertyId); + } + + return I18nProperties.findPrefixCaption(propertyId, AefiExportDto.I18N_PREFIX, AefiIndexDto.I18N_PREFIX, AdverseEventsDto.I18N_PREFIX); + } + + private static String captionProvider(String propertyId, Class type) { + String caption = getPropertyCaption(propertyId, null); + + if (Date.class.isAssignableFrom(type)) { + caption += " (" + DateFormatHelper.getDateFormatPattern() + ")"; + } + + return caption; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveHandlers.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveHandlers.java index 48f3db9e746..ae367e005a7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveHandlers.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveHandlers.java @@ -30,6 +30,10 @@ import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiFacade; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AefiInvestigationFacade; import de.symeda.sormas.api.campaign.CampaignDto; import de.symeda.sormas.api.campaign.CampaignFacade; import de.symeda.sormas.api.caze.CaseDataDto; @@ -93,6 +97,16 @@ public static CoreEntityArchiveHandler forI return new CoreEntityArchiveHandler<>(FacadeProvider.getImmunizationFacade(), ArchiveMessages.IMMUNIZATION); } + public static CoreEntityArchiveHandler forAefi() { + return new CoreEntityArchiveHandler<>(FacadeProvider.getAefiFacade(), ArchiveMessages.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION); + } + + public static CoreEntityArchiveHandler forAefiInvestigation() { + return new CoreEntityArchiveHandler<>( + FacadeProvider.getAefiInvestigationFacade(), + ArchiveMessages.ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_INVESTIGATION); + } + public static CoreEntityArchiveHandler forTravelEntry() { return new CoreEntityArchiveHandler<>(FacadeProvider.getTravelEntryFacade(), ArchiveMessages.TRAVEL_ENTRY); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveMessages.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveMessages.java index 8b0aef3c5e9..f7504095812 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveMessages.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveMessages.java @@ -106,6 +106,39 @@ public enum ArchiveMessages { null, null), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION(Strings.headingArchiveAdverseEvent, + Strings.confirmationArchiveAdverseEvent, + null, + Strings.messageAdverseEventArchived, + Strings.headingDearchiveAdverseEvent, + Strings.confirmationDearchiveAdverseEvent, + null, + Strings.messageAdverseEventDearchived, + null, + null, + null, + null, + null, + null, + null, + null), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_INVESTIGATION(Strings.headingArchiveAdverseEventInvestigation, + Strings.confirmationArchiveAdverseEventInvestigation, + null, + Strings.messageAdverseEventInvestigationArchived, + Strings.headingDearchiveAdverseEventInvestigation, + Strings.confirmationDearchiveAdverseEventInvestigation, + null, + Strings.messageAdverseEventInvestigationDearchived, + null, + null, + null, + null, + null, + null, + null, + null), + TRAVEL_ENTRY(Strings.headingArchiveTravelEntry, Strings.confirmationArchiveTravelEntry, null, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/BirthdateRangeFilterComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/BirthdateRangeFilterComponent.java new file mode 100644 index 00000000000..3bfded5b7e0 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/BirthdateRangeFilterComponent.java @@ -0,0 +1,104 @@ +package de.symeda.sormas.ui.utils; + +import static de.symeda.sormas.ui.utils.CssStyles.VSPACE_TOP_4; + +import java.util.Calendar; +import java.util.Date; + +import com.vaadin.server.Page; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Notification; +import com.vaadin.v7.ui.CheckBox; +import com.vaadin.v7.ui.PopupDateField; + +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.Descriptions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.utils.DateHelper; + +public class BirthdateRangeFilterComponent extends HorizontalLayout { + + private static final long serialVersionUID = 8752630393182144501L; + + private final PopupDateField dateFromFilter; + private final PopupDateField dateToFilter; + private final CheckBox includePartialMatch; + + public BirthdateRangeFilterComponent(boolean showCaption, AbstractFilterForm parentFilterForm) { + setSpacing(true); + + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + + dateFromFilter = new PopupDateField(); + dateToFilter = new PopupDateField(); + includePartialMatch = new CheckBox(); + + addComponent(dateFromFilter); + addComponent(dateToFilter); + + // Date filter + dateFromFilter.setDateFormat(DateFormatHelper.getDateFormatPattern()); + dateFromFilter.setId("dateFrom"); + dateFromFilter.setWidth(200, Unit.PIXELS); + if (showCaption) { + dateFromFilter.setCaption(I18nProperties.getCaption(Captions.from)); + } + dateFromFilter.setInputPrompt(I18nProperties.getString(Strings.promptBirthdateFrom)); + + dateToFilter.setDateFormat(DateFormatHelper.getDateFormatPattern()); + dateToFilter.setId("dateTo"); + dateToFilter.setWidth(200, Unit.PIXELS); + if (showCaption) { + dateToFilter.setCaption(I18nProperties.getCaption(Captions.to)); + } + dateToFilter.setInputPrompt(I18nProperties.getString(Strings.promptBirthdateTo)); + + dateFromFilter.addValueChangeListener(e -> { + Date dateFrom = (Date) e.getProperty().getValue(); + Date dateTo = dateToFilter.getValue(); + notifyIfIncorrectRange(dateFrom, dateTo); + parentFilterForm.onChange(); + }); + + dateToFilter.addValueChangeListener(e -> { + Date dateTo = (Date) e.getProperty().getValue(); + Date dateFrom = dateFromFilter.getValue(); + notifyIfIncorrectRange(dateFrom, dateTo); + parentFilterForm.onChange(); + }); + + includePartialMatch.setCaption(I18nProperties.getCaption(Captions.includePartialBirthdates)); + includePartialMatch.addStyleName(VSPACE_TOP_4); + includePartialMatch.setDescription(I18nProperties.getDescription(Descriptions.birthdateFilterPartialMatchDescription)); + addComponent(includePartialMatch); + } + + private static void notifyIfIncorrectRange(Date dateFrom, Date dateTo) { + if (dateFrom != null & dateTo != null) { + if (DateHelper.isDateAfter(dateFrom, dateTo)) { + Notification notification = new Notification( + I18nProperties.getString(Strings.headingIncorrectDateRange), + I18nProperties.getString(Strings.messageIncorrectDateRange), + Notification.Type.WARNING_MESSAGE, + false); + + notification.setDelayMsec(-1); + notification.show(Page.getCurrent()); + } + } + } + + public PopupDateField getDateFromFilter() { + return dateFromFilter; + } + + public PopupDateField getDateToFilter() { + return dateToFilter; + } + + public CheckBox getIncludePartialMatch() { + return includePartialMatch; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java index 130e7bfad5f..a1bee68b7c0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java @@ -80,6 +80,7 @@ private CssStyles() { public static final String INDENT_LEFT_1 = "indent-left-1"; public static final String INDENT_LEFT_2 = "indent-left-2"; public static final String INDENT_LEFT_3 = "indent-left-3"; + public static final String PADDING_NONE = "padding-none"; public static final String VAADIN_LABEL = "v-label"; public static final String VAADIN_CAPTION = "v-caption"; @@ -238,6 +239,7 @@ private CssStyles() { public static final String GRID_ROW_STATUS_PROGRESS = "status-progress"; public static final String GRID_ROW_TITLE = "row-title"; + public static final String GRID_ROW_SELECTED = "v-grid-row-selected"; public static final String LABEL_CONFIGURATION_SEVERITY_INDICATOR = "severity-indicator"; public static final String BADGE = "badge"; @@ -309,6 +311,23 @@ private CssStyles() { @Deprecated public static final String CALLOUT = "callout"; + public static final String VIEW_SECTION = "view-section"; + public static final String PAGE_TITLE = "page-title"; + public static final String ROUNDED_BORDER = "rounded-border"; + public static final String ROUNDED_BORDER_TOP = "rounded-border-top"; + public static final String ROUNDED_BORDER_BOTTOM = "rounded-border-bottom"; + public static final String ROUNDED_BORDER_SM = "rounded-border-sm"; + public static final String ROUNDED_BORDER_TOP_SM = "rounded-border-sm-top"; + public static final String ROUNDED_BORDER_BOTTOM_SM = "rounded-border-sm-bottom"; + public static final String MARGIN_X_4 = "margin-x-4"; + public static final String MARGIN_TOP_4 = "margin-top-4"; + public static final String PADDING_X_8 = "padding-x-8"; + public static final String PADDING_X_20 = "padding-x-20"; + public static final String FORM_SECTION_ACCORDION_PANEL_TITLE_BUTTON = "form-section-accordion-panel-title-button"; + public static final String OPTIONGROUP_CAPTION_FLEX = "optiongroup-caption-flex"; + public static final String VIEW_SECTION_MARGIN_X_4 = VIEW_SECTION + " " + MARGIN_X_4; + public static final String VIEW_SECTION_MARGIN_TOP_4_MARGIN_X_4 = VIEW_SECTION + " " + MARGIN_X_4 + " " + MARGIN_TOP_4; + public static String buildVaadinStyle(String primaryStyle, String... styles) { StringBuilder styleBuilder = new StringBuilder(); styleBuilder.append(primaryStyle); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExportEntityName.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExportEntityName.java index fd9ad184630..e00f41dfe45 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExportEntityName.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExportEntityName.java @@ -42,7 +42,9 @@ public enum ExportEntityName { PERSONS("entityPersons", "persons"), ENVIRONMENTS("entityEnvironments", "environments"), ENVIRONMENT_SAMPLES("entityEnvironmentSamples", "environment samples"), - SELF_REPORTS("entitySelfReports", "self reports"); + SELF_REPORTS("entitySelfReports", "self reports"), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION("entityAdverseEvents", "adverse events following immunization"), + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_INVESTIGATION("entityAdverseEventInvestigations", "aefi investigations"); private final String languageKey; private final String defaultName; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessColumnStyleGenerator.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessColumnStyleGenerator.java index 7ab5f9338ac..d602b942a3a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessColumnStyleGenerator.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessColumnStyleGenerator.java @@ -19,6 +19,7 @@ import com.vaadin.ui.StyleGenerator; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.pseudonymization.Pseudonymizable; @@ -28,12 +29,18 @@ public class FieldAccessColumnStyleGenerator implements StyleGenerator { public static FieldAccessColumnStyleGenerator getDefault(Class beanType, String columnId) { - return forFieldAccessCheckers(beanType, columnId, UiFieldAccessCheckers.getDefault(true)); + return forFieldAccessCheckers( + beanType, + columnId, + UiFieldAccessCheckers.getDefault(true, FacadeProvider.getConfigFacade().getCountryLocale())); } public static FieldAccessColumnStyleGenerator forSensitiveData(Class beanType, String columnId) { - return forFieldAccessCheckers(beanType, columnId, UiFieldAccessCheckers.forSensitiveData(true)); + return forFieldAccessCheckers( + beanType, + columnId, + UiFieldAccessCheckers.forSensitiveData(true, FacadeProvider.getConfigFacade().getCountryLocale())); } private static FieldAccessColumnStyleGenerator forFieldAccessCheckers( diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessHelper.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessHelper.java index 0c4ea358aa3..fe9a895990a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessHelper.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldAccessHelper.java @@ -17,12 +17,31 @@ import java.util.stream.Stream; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; +import de.symeda.sormas.api.utils.pseudonymization.PseudonymizableDto; +import de.symeda.sormas.ui.UiUtil; public class FieldAccessHelper { public static boolean isAllInaccessible(String... values) { return Stream.of(values).allMatch(v -> I18nProperties.getCaption(Captions.inaccessibleValue).equals(v)); } + + public static UiFieldAccessCheckers getFieldAccessCheckers(boolean inJurisdiction, boolean isPseudonymized) { + return UiFieldAccessCheckers.forDataAccessLevel( + UiUtil.getPseudonymizableDataAccessLevel(inJurisdiction), + isPseudonymized, + FacadeProvider.getConfigFacade().getCountryLocale()); + } + + public static UiFieldAccessCheckers getFieldAccessCheckers(T dto) { + return UiFieldAccessCheckers.forDataAccessLevel( + UiUtil.getPseudonymizableDataAccessLevel(dto.isInJurisdiction()), + dto.isPseudonymized(), + FacadeProvider.getConfigFacade().getCountryLocale()); + } + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/NullableOptionGroup.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/NullableOptionGroup.java index 91dd75ae380..69a6fcfb312 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/NullableOptionGroup.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/NullableOptionGroup.java @@ -23,9 +23,13 @@ import org.apache.commons.lang3.ObjectUtils; import com.vaadin.v7.data.Container; +import com.vaadin.v7.data.Item; import com.vaadin.v7.data.util.converter.Converter; import com.vaadin.v7.ui.OptionGroup; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; + public class NullableOptionGroup extends OptionGroup { public NullableOptionGroup() { @@ -79,4 +83,10 @@ public void setRequired(boolean required) { private Object getFirstValue(Set value) { return value.stream().findFirst().orElse(null); } + + public void setInaccessible() { + this.removeAllItems(); + Item item = this.addItem(1); + item.getItemProperty(item.getItemPropertyIds().stream().findFirst().get()).setValue(I18nProperties.getCaption(Captions.inaccessibleValue)); + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/SormasFieldGroupFieldFactory.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/SormasFieldGroupFieldFactory.java index ad062f3b4b8..11d08a40b3d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/SormasFieldGroupFieldFactory.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/SormasFieldGroupFieldFactory.java @@ -15,10 +15,12 @@ import com.vaadin.v7.ui.DateField; import com.vaadin.v7.ui.Field; import com.vaadin.v7.ui.OptionGroup; +import com.vaadin.v7.ui.RichTextArea; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.adverseeventsfollowingimmunization.AdverseEventState; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.symptoms.SymptomState; import de.symeda.sormas.api.utils.FieldConstraints; @@ -26,6 +28,8 @@ import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.ActivityAsCase.ActivityAsCaseField; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.fields.vaccines.AefiVaccinationsField; +import de.symeda.sormas.ui.adverseeventsfollowingimmunization.components.form.AdverseEventsForm; import de.symeda.sormas.ui.clinicalcourse.HealthConditionsForm; import de.symeda.sormas.ui.exposure.ExposuresField; import de.symeda.sormas.ui.hospitalization.PreviousHospitalizationsField; @@ -39,6 +43,7 @@ import de.symeda.sormas.ui.utils.components.JsonForm; import de.symeda.sormas.ui.utils.components.MultiSelect; import de.symeda.sormas.ui.utils.components.MultiSelectFiles; +import de.symeda.sormas.ui.utils.components.SormasTextField; import de.symeda.sormas.ui.vaccination.VaccinationsField; public class SormasFieldGroupFieldFactory extends DefaultFieldGroupFieldFactory { @@ -72,7 +77,9 @@ public SormasFieldGroupFieldFactory( public T createField(Class type, Class fieldType) { if (type.isEnum()) { if (fieldType.isAssignableFrom(Field.class) // no specific fieldType defined? - && (SymptomState.class.isAssignableFrom(type) || YesNoUnknown.class.isAssignableFrom(type))) { + && (SymptomState.class.isAssignableFrom(type) + || YesNoUnknown.class.isAssignableFrom(type) + || AdverseEventState.class.isAssignableFrom(type))) { NullableOptionGroup field = new NullableOptionGroup(); field.setImmediate(true); populateWithEnumData(field, (Class) type); @@ -177,8 +184,16 @@ public T createField(Class type, Class fieldType) { return (T) new CustomizableEnumPropertiesComponent(); } else if (UserField.class.isAssignableFrom(fieldType)) { return (T) new UserField(); + } else if (AefiVaccinationsField.class.isAssignableFrom(fieldType)) { + return (T) new AefiVaccinationsField(fieldAccessCheckers); + } else if (AdverseEventsForm.class.isAssignableFrom(fieldType)) { + return (T) new AdverseEventsForm(fieldVisibilityCheckers, fieldAccessCheckers); } else if (CheckBoxTree.class.isAssignableFrom(fieldType)) { return (T) new CheckBoxTree<>(); + } else if (RichTextArea.class.isAssignableFrom(fieldType)) { + return (T) new RichTextArea(); + }else if (SormasTextField.class.isAssignableFrom(fieldType)) { + return (T) new SormasTextField(); } return super.createField(type, fieldType); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java index a4de6114cdf..6f53c037eb8 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java @@ -21,6 +21,7 @@ import java.math.RoundingMode; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -43,12 +44,16 @@ import com.vaadin.v7.data.Item; import com.vaadin.v7.data.util.GeneratedPropertyContainer; import com.vaadin.v7.data.util.PropertyValueGenerator; +import com.vaadin.v7.ui.AbstractField; import com.vaadin.v7.ui.Grid; +import com.vaadin.v7.ui.RichTextArea; +import com.vaadin.v7.ui.TextArea; import com.vaadin.v7.ui.renderers.HtmlRenderer; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.user.UserDto; public final class VaadinUiUtil { @@ -632,4 +637,65 @@ public static void showWarningPopup(String message) { popupWindow.addCloseListener(e -> popupWindow.close()); popupWindow.setWidth(400, Unit.PIXELS); } + + public static void addGdprMessageOnClick(TextArea textArea) { + AtomicBoolean gdprMessageTriggered = new AtomicBoolean(false); + Window subWindowGdpR = VaadinUiUtil.createPopupWindow(); + + textArea.addFocusListener(i -> { + showGdprWindow(textArea, gdprMessageTriggered, subWindowGdpR); + }); + + textArea.addBlurListener(blurEvent -> { + if (gdprMessageTriggered.get() && subWindowGdpR.getParent() == null) { + gdprMessageTriggered.set(false); + } + }); + } + + public static void addGdprMessageOnClick(RichTextArea richTextArea) { + AtomicBoolean gdprMessageTriggered = new AtomicBoolean(false); + Window subWindowGdpR = VaadinUiUtil.createPopupWindow(); + + richTextArea.addValueChangeListener(event -> { + if (!gdprMessageTriggered.get()) { + showGdprWindow(richTextArea, gdprMessageTriggered, subWindowGdpR); + subWindowGdpR.focus(); + gdprMessageTriggered.set(true); + } + }); + } + + private static void showGdprWindow(AbstractField textArea, AtomicBoolean gdprMessageTriggered, Window subWindowGdpR) { + if (!gdprMessageTriggered.get()) { + gdprMessageTriggered.set(true); + subWindowGdpR.setCaption(I18nProperties.getPrefixCaption(UserDto.I18N_PREFIX, UserDto.HAS_CONSENTED_TO_GDPR)); + VerticalLayout subContentGdpr = new VerticalLayout(); + subWindowGdpR.setContent(subContentGdpr); + subWindowGdpR.center(); + subWindowGdpR.setWidth("40%"); + subWindowGdpR.setModal(true); + subWindowGdpR.setClosable(true); + + Label textGdpr = new Label(); + textGdpr.setWidth("80%"); + textGdpr.setSizeFull(); + textGdpr.setValue(I18nProperties.getString(Strings.messageGdpr)); + subContentGdpr.addComponent(textGdpr); + + HorizontalLayout buttonLayout = new HorizontalLayout(); + buttonLayout.setMargin(false); + buttonLayout.setSpacing(true); + buttonLayout.setWidth(100, Unit.PERCENTAGE); + Button buttonGdpr = ButtonHelper.createButton(I18nProperties.getCaption(Captions.actionConfirm), event -> { + subWindowGdpR.close(); + textArea.focus(); + }, ValoTheme.BUTTON_PRIMARY); + buttonLayout.addComponent(buttonGdpr); + subContentGdpr.addComponent(buttonLayout); + buttonLayout.setComponentAlignment(buttonGdpr, Alignment.BOTTOM_RIGHT); + buttonLayout.setExpandRatio(buttonGdpr, 0); + UI.getCurrent().addWindow(subWindowGdpR); + } + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/SormasTextField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/SormasTextField.java new file mode 100644 index 00000000000..7245a6c9b8b --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/SormasTextField.java @@ -0,0 +1,33 @@ +package de.symeda.sormas.ui.utils.components; + +import java.lang.reflect.Method; + +import com.vaadin.shared.Registration; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.ui.TextField; + +public class SormasTextField extends TextField { + + /* Value change events */ + + private static final Method VALUE_CHANGE_METHOD; + + static { + try { + VALUE_CHANGE_METHOD = Property.ValueChangeListener.class.getDeclaredMethod( + "valueChange", + new Class[] { + Property.ValueChangeEvent.class }); + } catch (final NoSuchMethodException e) { + // This should never happen + throw new RuntimeException("Internal error finding methods in AbstractField"); + } + } + + public Registration addTextFieldValueChangeListener(Property.ValueChangeListener listener) { + Registration registration = addListener(ValueChangeEvent.class, listener, VALUE_CHANGE_METHOD); + // ensure "automatic immediate handling" works + markAsDirty(); + return registration; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java index 81f86a48f2e..4dc5127e504 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java @@ -26,11 +26,11 @@ import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.vaccination.VaccinationListEntryDto; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UiUtil; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.PaginationList; public class VaccinationList extends PaginationList { @@ -88,9 +88,7 @@ protected void drawDisplayedEntries() { .edit( FacadeProvider.getVaccinationFacade().getByUuid(listEntry.getVaccination().getUuid()), listEntry.getVaccination().getDisease(), - UiFieldAccessCheckers.forDataAccessLevel( - UiUtil.getPseudonymizableDataAccessLevel(vaccination.isInJurisdiction()), - vaccination.isPseudonymized()), + FieldAccessHelper.getFieldAccessCheckers(vaccination.isInJurisdiction(), vaccination.isPseudonymized()), true, v -> SormasUI.refreshView(), deleteCallback(), diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java index 6f4d7259a62..f8db4394dac 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java @@ -42,13 +42,12 @@ import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.symptoms.SymptomsContext; import de.symeda.sormas.api.utils.DateHelper; -import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.visit.VisitDto; import de.symeda.sormas.api.visit.VisitStatus; -import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.symptoms.SymptomsForm; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.DateTimeField; +import de.symeda.sormas.ui.utils.FieldAccessHelper; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -82,7 +81,7 @@ public VisitEditForm( VisitDto.I18N_PREFIX, false, null, - UiFieldAccessCheckers.forDataAccessLevel(UiUtil.getPseudonymizableDataAccessLevel(create || inJurisdiction), !create && isPseudonymized)); + FieldAccessHelper.getFieldAccessCheckers(create || inJurisdiction, !create && isPseudonymized)); if (create) { hideValidationUntilNextCommit(); } diff --git a/sormas-ui/src/main/webapp/VAADIN/themes/sormas/global.scss b/sormas-ui/src/main/webapp/VAADIN/themes/sormas/global.scss index 6e6c108f8eb..aaa7a9eea7e 100644 --- a/sormas-ui/src/main/webapp/VAADIN/themes/sormas/global.scss +++ b/sormas-ui/src/main/webapp/VAADIN/themes/sormas/global.scss @@ -250,6 +250,27 @@ margin-left: 45px; } + .margin-x-4{ + margin-left: 4px; + margin-right: 4px; + } + + .margin-top-4{ + margin-top: 4px; + } + + .padding-none{ + padding: 0 !important; + } + + .padding-x-8{ + padding: 0 8px !important; + } + + .padding-x-20{ + padding: 0 20px !important; + } + .vertical-rule { border-right: 1px solid #CDD8EC; } @@ -343,6 +364,60 @@ padding: 6px; } + .view-section{ + padding: 10px 10px; + border-radius: 4px; + background-color: #ffffff; + border-width: 0; + border-style: solid; + border-color: #ffffff; + + /*box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12);*/ + + -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14);; + box-shadow: 0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14);; + } + + .page-title{ + font-size: 24px !important; + } + + .rounded-border{ + border-radius: 8px; + } + + .rounded-border-top{ + border-top-left-radius: 8px; + border-top-right-radius: 8px; + } + + .rounded-border-bottom{ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + } + + .rounded-border-sm{ + border-radius: 4px; + } + + .rounded-border-sm-top{ + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } + + .rounded-border-sm-bottom{ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + } + + .form-section-accordion-panel-title-button{ + font-size: 16px !important; + font-weight: 600; + color: #6591C4; + text-decoration: none !important; + padding-left: 0; + } + .spacing-small { .v-spacing { width: 4px; diff --git a/sormas-ui/src/main/webapp/WEB-INF/glassfish-web.xml b/sormas-ui/src/main/webapp/WEB-INF/glassfish-web.xml index 99b99fa4b15..cc6f9e6ccf8 100644 --- a/sormas-ui/src/main/webapp/WEB-INF/glassfish-web.xml +++ b/sormas-ui/src/main/webapp/WEB-INF/glassfish-web.xml @@ -115,6 +115,36 @@ IMMUNIZATION_ARCHIVE + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + + PERSON_VIEW PERSON_VIEW @@ -590,6 +620,11 @@ DASHBOARD_SAMPLES_VIEW + + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + CASE_CLINICIAN_VIEW CASE_CLINICIAN_VIEW diff --git a/sormas-ui/src/main/webapp/WEB-INF/web.xml b/sormas-ui/src/main/webapp/WEB-INF/web.xml index 998d7088943..b62eb6a327a 100644 --- a/sormas-ui/src/main/webapp/WEB-INF/web.xml +++ b/sormas-ui/src/main/webapp/WEB-INF/web.xml @@ -105,6 +105,30 @@ IMMUNIZATION_ARCHIVE + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_CREATE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EDIT + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_ARCHIVE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_DELETE + + + + ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_EXPORT + + PERSON_VIEW @@ -485,6 +509,10 @@ DASHBOARD_SAMPLES_VIEW + + DASHBOARD_ADVERSE_EVENTS_FOLLOWING_IMMUNIZATION_VIEW + + CASE_CLINICIAN_VIEW diff --git a/sormas-ui/src/test/resources/META-INF/persistence.xml b/sormas-ui/src/test/resources/META-INF/persistence.xml index f0c6e5b197e..0242f19fa99 100644 --- a/sormas-ui/src/test/resources/META-INF/persistence.xml +++ b/sormas-ui/src/test/resources/META-INF/persistence.xml @@ -89,6 +89,7 @@ de.symeda.sormas.backend.environment.environmentsample.EnvironmentSample de.symeda.sormas.backend.specialcaseaccess.SpecialCaseAccess de.symeda.sormas.backend.selfreport.SelfReport + de.symeda.sormas.backend.docgeneration.DocumentTemplate true diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 7a1cfb76348..64262b9eaa8 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.99.0-SNAPSHOT + 1.101.0-SNAPSHOT ../sormas-base 4.0.0