diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java index eb7610c9d88..ed2504f8a75 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java @@ -56,6 +56,7 @@ public class EpiDataDto extends PseudonymizableDto { public static final String CASE_IMPORTED_STATUS = "caseImportedStatus"; public static final String CLUSTER_TYPE = "clusterType"; public static final String CLUSTER_TYPE_TEXT = "clusterTypeText"; + public static final String CLUSTER_RELATED = "clusterRelated"; private YesNoUnknown exposureDetailsKnown; private YesNoUnknown activityAsCaseDetailsKnown; @@ -71,6 +72,11 @@ public class EpiDataDto extends PseudonymizableDto { @HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG}) private ClusterType clusterType; + @Diseases({ + Disease.MEASLES}) + @HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG}) + private boolean clusterRelated; + @HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG}) @Diseases({ Disease.MEASLES}) @@ -189,6 +195,14 @@ public void setClusterTypeText(String clusterTypeText) { this.clusterTypeText = clusterTypeText; } + public boolean isClusterRelated() { + return clusterRelated; + } + + public void setClusterRelated(boolean clusterRelated) { + this.clusterRelated = clusterRelated; + } + @Override public EpiDataDto clone() throws CloneNotSupportedException { EpiDataDto clone = (EpiDataDto) super.clone(); 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 2c595bfac89..4ef6c884310 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 @@ -1561,6 +1561,7 @@ public interface Captions { String EpiData_activityAsCaseDetailsKnown = "EpiData.activityAsCaseDetailsKnown"; String EpiData_areaInfectedAnimals = "EpiData.areaInfectedAnimals"; String EpiData_caseImportedStatus = "EpiData.caseImportedStatus"; + String EpiData_clusterRelated = "EpiData.clusterRelated"; String EpiData_clusterType = "EpiData.clusterType"; String EpiData_clusterTypeText = "EpiData.clusterTypeText"; String EpiData_contactWithSourceCaseKnown = "EpiData.contactWithSourceCaseKnown"; 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 7dbe6dc670f..efcc05d7f0e 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 @@ -134,7 +134,8 @@ public enum PathogenTestType { CQ_VALUE_DETECTION, @Diseases(value = { - Disease.RESPIRATORY_SYNCYTIAL_VIRUS }) + Disease.RESPIRATORY_SYNCYTIAL_VIRUS, + Disease.MEASLES}) SEQUENCING, @Diseases(value = { diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index 50562b20a9e..f32940af39c 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -1145,6 +1145,7 @@ EpiData.highTransmissionRiskArea=Residing or working in an area with high risk o EpiData.largeOutbreaksArea=Residing or travelling to countries/territories/areas experiencing larger outbreaks of local transmission EpiData.contactWithSourceCaseKnown=Contacts with source case known EpiData.caseImportedStatus=Case imported status +EpiData.clusterRelated=Cluster Related EpiData.clusterType=Cluster type EpiData.clusterTypeText=Specify cluster type text #Therapy diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java index 50864fb6d21..e394c6d3145 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java @@ -22,6 +22,7 @@ import java.util.List; import javax.persistence.CascadeType; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -56,6 +57,7 @@ public class EpiData extends AbstractDomainObject { private CaseImportedStatus caseImportedStatus; private ClusterType clusterType; private String clusterTypeText; + private boolean clusterRelated; private List exposures = new ArrayList<>(); private List activitiesAsCase = new ArrayList<>(); @@ -170,4 +172,13 @@ public String getClusterTypeText() { public void setClusterTypeText(String clusterTypeText) { this.clusterTypeText = clusterTypeText; } + + @Column(nullable = false) + public boolean isClusterRelated() { + return clusterRelated; + } + + public void setClusterRelated(boolean clusterRelated) { + this.clusterRelated = clusterRelated; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java index 018f91af140..aa8ef4ffecb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java @@ -103,6 +103,7 @@ public EpiData fillOrBuildEntity(EpiDataDto source, EpiData target, boolean chec target.setClusterType(source.getClusterType()); target.setCaseImportedStatus(source.getCaseImportedStatus()); target.setClusterTypeText(source.getClusterTypeText()); + target.setClusterRelated(source.isClusterRelated()); return target; } @@ -249,6 +250,7 @@ public static EpiDataDto toDto(EpiData epiData) { target.setClusterType(source.getClusterType()); target.setCaseImportedStatus(source.getCaseImportedStatus()); target.setClusterTypeText(source.getClusterTypeText()); + target.setClusterRelated(source.isClusterRelated()); return target; } diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 2492990b2a4..bc7918f655c 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -14647,5 +14647,13 @@ ALTER TABLE testreport_history ADD COLUMN IF NOT EXISTS tubemitogenegt10 boolean INSERT INTO schema_version (version_number, comment) VALUES (591, 'Implement functionality to receive messages from laboratory for TB #13563'); +-- 2025-09-09 - Lux measles - cluster related checkbox #13365 +alter table epidata add column IF NOT EXISTS clusterRelated boolean DEFAULT false; +update epidata set clusterRelated = false where clusterRelated is null; +alter table epidata alter column clusterRelated set not null; +alter table epidata_history add column IF NOT EXISTS clusterRelated boolean DEFAULT false; +update epidata_history set clusterRelated = false where clusterRelated is null; +alter table epidata_history alter column clusterRelated set not null; +INSERT INTO schema_version (version_number, comment) VALUES (592, 'Added cluster related checkbox for LUX Measles #13365'); -- *** 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/caze/CaseClassificationLogicTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java index a304382204e..8f932fdf188 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java @@ -1079,7 +1079,7 @@ public void testAutomaticClassificationForIMI() { caze.setEpidemiologicalConfirmation(YesNoUnknown.YES); caze = getCaseFacade().save(caze); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); - assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); + assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed caze = getCaseFacade().save(buildSuspectCase(Disease.INVASIVE_MENINGOCOCCAL_INFECTION)); @@ -1137,7 +1137,7 @@ public void ruleOutFalsePositivesForIMI() { PathogenTestType.PCR_RT_PCR, PathogenTestType.ANTIGEN_DETECTION, PathogenTestType.ANTIBIOTIC_SUSCEPTIBILITY); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); - assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); + assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); } @Test 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 1d2e5f3effa..97f5ae81871 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 @@ -179,6 +179,7 @@ public class ContactDataForm extends AbstractEditForm { private final ViewMode viewMode; private final Disease disease; private final boolean diseaseHasFollowUp; + private final boolean luxMeasles; private NullableOptionGroup contactProximity; private ComboBox region; private ComboBox district; @@ -219,6 +220,7 @@ public ContactDataForm(Disease disease, ViewMode viewMode, boolean isPseudonymiz this.viewMode = viewMode; this.disease = disease; this.diseaseHasFollowUp = FacadeProvider.getDiseaseConfigurationFacade().hasFollowUp(disease); + this.luxMeasles = Disease.MEASLES == disease && FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG); addFields(); } @@ -241,7 +243,7 @@ protected void addFields() { Label followUpStausHeadingLabel = new Label(I18nProperties.getString(Strings.headingFollowUpStatus)); followUpStausHeadingLabel.addStyleName(H3); getContent().addComponent(followUpStausHeadingLabel, FOLLOW_UP_STATUS_HEADING_LOC); - followUpStausHeadingLabel.setVisible(diseaseHasFollowUp); + followUpStausHeadingLabel.setVisible(diseaseHasFollowUp && !isLuxMeasles(this.disease)); Label prophylaxisLabel = new Label(I18nProperties.getString(Strings.headingProphylaxisLoc)); prophylaxisLabel.addStyleName(H3); @@ -889,6 +891,20 @@ private void updateDiseaseConfiguration(Disease disease) { field -> diseaseHasFollowUp, field -> false); + // For LUX measles cases do not require the follow-up details. For other countries works as it is + FieldHelper.setMultipleVisible( + getFieldGroup(), + Arrays.asList( + ContactDto.FOLLOW_UP_STATUS, + ContactDto.FOLLOW_UP_STATUS_CHANGE_DATE, + ContactDto.FOLLOW_UP_STATUS_CHANGE_USER, + ContactDto.FOLLOW_UP_COMMENT, + ContactDto.FOLLOW_UP_UNTIL, + ContactDto.CONTACT_OFFICER, + ContactDto.OVERWRITE_FOLLOW_UP_UNTIL), + field -> !isLuxMeasles(disease), + field -> false); + FieldHelper.updateEnumData( contactProximity, Arrays.asList(ContactProximity.getValues(disease, FacadeProvider.getConfigFacade().getCountryLocale()))); @@ -1140,4 +1156,14 @@ public void setValue(ContactDto newFieldValue) throws ReadOnlyException, Convert // this hopefully resets everything to its correct value discard(); } + + /** + * To validate the Lux specific measles rules + * + * @param disease + * @return + */ + private boolean isLuxMeasles(Disease disease) { + return Disease.MEASLES == disease && isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG); + } } 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 8bb3acc62c8..bbb5e79ef1c 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 @@ -32,6 +32,7 @@ import java.util.function.Supplier; import com.vaadin.v7.ui.TextField; +import de.symeda.sormas.api.CountryHelper; import de.symeda.sormas.api.epidata.ClusterType; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.checkers.CountryFieldVisibilityChecker; @@ -81,7 +82,7 @@ public class EpiDataForm extends AbstractEditForm { loc(EpiDataDto.ACTIVITY_AS_CASE_DETAILS_KNOWN)+ loc(EpiDataDto.ACTIVITIES_AS_CASE) + loc(LOC_CLUSTER_TYPE_HEADING)+ - fluidRowLocs(6,EpiDataDto.CLUSTER_TYPE,6,EpiDataDto.CLUSTER_TYPE_TEXT) + + fluidRowLocs(3, EpiDataDto.CLUSTER_RELATED,5,EpiDataDto.CLUSTER_TYPE,4,EpiDataDto.CLUSTER_TYPE_TEXT) + locCss(VSPACE_TOP_3, LOC_EPI_DATA_FIELDS_HINT) + loc(EpiDataDto.HIGH_TRANSMISSION_RISK_AREA) + loc(EpiDataDto.LARGE_OUTBREAKS_AREA) + @@ -152,7 +153,9 @@ protected void addFields() { addField(EpiDataDto.CASE_IMPORTED_STATUS); addField(EpiDataDto.CLUSTER_TYPE); + addField(EpiDataDto.CLUSTER_RELATED); TextField clustorTypeTF = addField(EpiDataDto.CLUSTER_TYPE_TEXT); + FieldHelper.setVisibleWhen(getFieldGroup(), EpiDataDto.CLUSTER_TYPE, EpiDataDto.CLUSTER_RELATED, Collections.singletonList(Boolean.TRUE), true); FieldHelper.setVisibleWhen(getField(EpiDataDto.CLUSTER_TYPE), Arrays.asList(clustorTypeTF), Arrays.asList(ClusterType.OTHER), true); FieldHelper.setVisibleWhen( getFieldGroup(), @@ -210,11 +213,12 @@ private void addHeadingsAndInfoTexts() { new MultilineLabel(divsCss(VSPACE_3, I18nProperties.getString(Strings.infoEpiDataFieldsHint)), ContentMode.HTML), LOC_EPI_DATA_FIELDS_HINT); - getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingEpiCaseImport)) + divsCss(VSPACE_3), ContentMode.HTML), - LOC_CASE_IMPORT_HEADING); - - getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingClusterType)) + divsCss(VSPACE_3), ContentMode.HTML), - LOC_CLUSTER_TYPE_HEADING); + if (isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG) && Disease.MEASLES == disease) { + getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingEpiCaseImport)) + divsCss(VSPACE_3), ContentMode.HTML), + LOC_CASE_IMPORT_HEADING); + getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingClusterType)) + divsCss(VSPACE_3), ContentMode.HTML), + LOC_CLUSTER_TYPE_HEADING); + } getContent().addComponent( new MultilineLabel( 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 3ca9a14ee7c..10004dc032e 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 @@ -363,11 +363,7 @@ protected void addFields() { // Initialize means of immunization field based on current disease if (currentDisease != null) { - FieldHelper.updateItems( - meansOfImmunizationField, - Arrays.asList(MeansOfImmunization.values()), - FieldVisibilityCheckers.withDisease(currentDisease), - MeansOfImmunization.class); + updateMeansOfImmunizationField(currentDisease); } if (disease != null) {