Skip to content

Commit c444740

Browse files
authored
Merge pull request #13581 from SORMAS-Foundation/bugfix-rsv_corrections
Bugfix rsv corrections
2 parents 45fbef5 + c238ba2 commit c444740

File tree

5 files changed

+210
-72
lines changed

5 files changed

+210
-72
lines changed

sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
import javax.validation.Valid;
2525
import javax.validation.constraints.Size;
2626

27+
import de.symeda.sormas.api.Disease;
2728
import de.symeda.sormas.api.EntityDto;
2829
import de.symeda.sormas.api.ImportIgnore;
2930
import de.symeda.sormas.api.feature.FeatureType;
3031
import de.symeda.sormas.api.i18n.Validations;
3132
import de.symeda.sormas.api.utils.DataHelper;
3233
import de.symeda.sormas.api.utils.DependingOnFeatureType;
34+
import de.symeda.sormas.api.utils.Diseases;
3335
import de.symeda.sormas.api.utils.FieldConstraints;
3436
import de.symeda.sormas.api.utils.Outbreaks;
3537
import de.symeda.sormas.api.utils.YesNoUnknown;
@@ -73,12 +75,27 @@ public class HospitalizationDto extends EntityDto {
7375
private YesNoUnknown hospitalizedPreviously;
7476
@Valid
7577
private List<PreviousHospitalizationDto> previousHospitalizations = new ArrayList<>();
78+
79+
@Diseases({
80+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
7681
private YesNoUnknown intensiveCareUnit;
82+
@Diseases({
83+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
7784
private Date intensiveCareUnitStart;
85+
@Diseases({
86+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
7887
private Date intensiveCareUnitEnd;
88+
89+
@Diseases({
90+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
7991
private YesNoUnknown oxygenPrescribed;
92+
@Diseases({
93+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
8094
private YesNoUnknown stillHospitalized;
95+
@Diseases({
96+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
8197
private Integer icuLengthOfStay;
98+
8299
private HospitalizationReasonType hospitalizationReason;
83100
@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
84101
private String otherHospitalizationReason;

sormas-api/src/main/java/de/symeda/sormas/api/immunization/MeansOfImmunization.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,31 @@
1515

1616
package de.symeda.sormas.api.immunization;
1717

18+
import de.symeda.sormas.api.Disease;
1819
import de.symeda.sormas.api.i18n.I18nProperties;
20+
import de.symeda.sormas.api.utils.Diseases;
1921

2022
public enum MeansOfImmunization {
2123

2224
VACCINATION,
2325
RECOVERY,
2426
VACCINATION_RECOVERY,
27+
28+
@Diseases(value = {
29+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
2530
MATERNAL_VACCINATION,
31+
32+
@Diseases(value = {
33+
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
2634
MONOCLONAL_ANTIBODY,
35+
2736
OTHER;
2837

2938
public static boolean isVaccination(MeansOfImmunization meansOfImmunization) {
30-
return meansOfImmunization == VACCINATION || meansOfImmunization == VACCINATION_RECOVERY
31-
|| meansOfImmunization == MATERNAL_VACCINATION || meansOfImmunization == MONOCLONAL_ANTIBODY;
39+
return meansOfImmunization == VACCINATION
40+
|| meansOfImmunization == VACCINATION_RECOVERY
41+
|| meansOfImmunization == MATERNAL_VACCINATION
42+
|| meansOfImmunization == MONOCLONAL_ANTIBODY;
3243
}
3344

3445
public static boolean isRecovery(MeansOfImmunization meansOfImmunization) {

sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java

Lines changed: 84 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,22 @@ public class HospitalizationForm extends AbstractEditForm<HospitalizationDto> {
8181
fluidRowLocs(HEALTH_FACILITY, HEALTH_FACILITY_DEPARTMENT) +
8282
fluidRowLocs(HospitalizationDto.ADMISSION_DATE, HospitalizationDto.DISCHARGE_DATE, HospitalizationDto.LEFT_AGAINST_ADVICE, "") +
8383
fluidRowLocs(HospitalizationDto.HOSPITALIZATION_REASON, HospitalizationDto.OTHER_HOSPITALIZATION_REASON) +
84-
fluidRowLocs(3, HospitalizationDto.INTENSIVE_CARE_UNIT, 3,
85-
HospitalizationDto.INTENSIVE_CARE_UNIT_START,
86-
3,
87-
HospitalizationDto.INTENSIVE_CARE_UNIT_END)
88-
+ fluidRowLocs(HospitalizationDto.ICU_LENGTH_OF_STAY, HospitalizationDto.OXYGEN_PRESCRIBED, HospitalizationDto.STILL_HOSPITALIZED)
89-
+ fluidRowLocs(HospitalizationDto.ISOLATED, HospitalizationDto.ISOLATION_DATE, "")
90-
+ fluidRowLocs(HospitalizationDto.DESCRIPTION) +
84+
fluidRowLocs(3, HospitalizationDto.INTENSIVE_CARE_UNIT,
85+
3, HospitalizationDto.INTENSIVE_CARE_UNIT_START,
86+
3, HospitalizationDto.INTENSIVE_CARE_UNIT_END,
87+
3, HospitalizationDto.ICU_LENGTH_OF_STAY) +
88+
fluidRowLocs(HospitalizationDto.OXYGEN_PRESCRIBED, HospitalizationDto.STILL_HOSPITALIZED) +
89+
fluidRowLocs(HospitalizationDto.ISOLATED, HospitalizationDto.ISOLATION_DATE, "") +
90+
fluidRowLocs(HospitalizationDto.DESCRIPTION) +
9191
loc(PREVIOUS_HOSPITALIZATIONS_HEADING_LOC) +
9292
fluidRowLocs(HospitalizationDto.HOSPITALIZED_PREVIOUSLY) +
9393
fluidRowLocs(HospitalizationDto.PREVIOUS_HOSPITALIZATIONS);
94+
//@formatter:on
9495
private final CaseDataDto caze;
9596
private final ViewMode viewMode;
9697
private NullableOptionGroup intensiveCareUnit;
9798
private DateField intensiveCareUnitStart;
9899
private DateField intensiveCareUnitEnd;
99-
//@formatter:on
100100

101101
public HospitalizationForm(CaseDataDto caze, ViewMode viewMode, boolean isPseudonymized, boolean inJurisdiction, boolean isEditAllowed) {
102102

@@ -145,19 +145,37 @@ protected void addFields() {
145145
final NullableOptionGroup currentlyHospitalizedField = addField(HospitalizationDto.CURRENTLY_HOSPITALIZED, NullableOptionGroup.class);
146146
final DateField admissionDateField = addField(HospitalizationDto.ADMISSION_DATE, DateField.class);
147147
final DateField dischargeDateField = addDateField(HospitalizationDto.DISCHARGE_DATE, DateField.class, 7);
148+
149+
// RSV-specific fields
148150
intensiveCareUnit = addField(HospitalizationDto.INTENSIVE_CARE_UNIT, NullableOptionGroup.class);
149151
intensiveCareUnitStart = addField(HospitalizationDto.INTENSIVE_CARE_UNIT_START, DateField.class);
150152
intensiveCareUnitStart.setVisible(false);
151153
intensiveCareUnitEnd = addField(HospitalizationDto.INTENSIVE_CARE_UNIT_END, DateField.class);
152154
intensiveCareUnitEnd.setVisible(false);
153-
FieldHelper
154-
.setVisibleWhen(intensiveCareUnit, Arrays.asList(intensiveCareUnitStart, intensiveCareUnitEnd), Arrays.asList(YesNoUnknown.YES), true);
155+
156+
if (caze.getDisease() == Disease.RESPIRATORY_SYNCYTIAL_VIRUS) {
157+
FieldHelper.setVisibleWhen(
158+
intensiveCareUnit,
159+
Arrays.asList(intensiveCareUnitStart, intensiveCareUnitEnd),
160+
Arrays.asList(YesNoUnknown.YES),
161+
true);
162+
} else {
163+
intensiveCareUnit.setVisible(false);
164+
intensiveCareUnitStart.setVisible(false);
165+
intensiveCareUnitEnd.setVisible(false);
166+
}
155167

156168
// RSV-specific fields
157169
final TextField icuLengthOfStayField = addField(HospitalizationDto.ICU_LENGTH_OF_STAY, TextField.class);
158170
final NullableOptionGroup oxygenPrescribedField = addField(HospitalizationDto.OXYGEN_PRESCRIBED, NullableOptionGroup.class);
159171
final NullableOptionGroup stillHospitalizedField = addField(HospitalizationDto.STILL_HOSPITALIZED, NullableOptionGroup.class);
160172

173+
if (caze.getDisease() != Disease.RESPIRATORY_SYNCYTIAL_VIRUS) {
174+
icuLengthOfStayField.setVisible(false);
175+
oxygenPrescribedField.setVisible(false);
176+
stillHospitalizedField.setVisible(false);
177+
}
178+
161179
final Field isolationDateField = addField(HospitalizationDto.ISOLATION_DATE);
162180
final TextArea descriptionField = addField(HospitalizationDto.DESCRIPTION, TextArea.class);
163181
descriptionField.setRows(4);
@@ -175,12 +193,9 @@ protected void addFields() {
175193
// Add listener to trigger RSV hospitalization reason defaulting when admitted to health facility
176194
admittedToHealthFacilityField.addValueChangeListener(event -> {
177195
final Object eventValue = event.getProperty().getValue();
178-
final boolean isAdmitted = eventValue != null && eventValue instanceof Collection<?>
179-
? ((Collection<?>) eventValue).contains(YesNoUnknown.YES)
180-
: false;
181-
if (caze.getDisease() == Disease.RESPIRATORY_SYNCYTIAL_VIRUS
182-
&& isAdmitted
183-
&& hospitalizationReason.getValue() == null) {
196+
final boolean isAdmitted =
197+
eventValue != null && eventValue instanceof Collection<?> ? ((Collection<?>) eventValue).contains(YesNoUnknown.YES) : false;
198+
if (caze.getDisease() == Disease.RESPIRATORY_SYNCYTIAL_VIRUS && isAdmitted && hospitalizationReason.getValue() == null) {
184199
hospitalizationReason.setValue(HospitalizationReasonType.REPORTED_DISEASE);
185200
}
186201
});
@@ -200,6 +215,8 @@ protected void addFields() {
200215
intensiveCareUnit,
201216
intensiveCareUnitStart,
202217
intensiveCareUnitEnd,
218+
oxygenPrescribedField,
219+
stillHospitalizedField,
203220
isolationDateField,
204221
descriptionField,
205222
isolatedField,
@@ -278,52 +295,59 @@ public String getFormattedHtmlMessage() {
278295
false,
279296
I18nProperties.getValidationError(Validations.afterDate, dischargeDateField.getCaption(), admissionDateField.getCaption())));
280297
dischargeDateField.addValueChangeListener(event -> admissionDateField.markAsDirty()); // re-evaluate admission date for consistent validation of all fields
281-
intensiveCareUnitStart.addValidator(
282-
new DateComparisonValidator(
283-
intensiveCareUnitStart,
284-
admissionDateField,
285-
false,
286-
false,
287-
I18nProperties.getValidationError(Validations.afterDate, intensiveCareUnitStart.getCaption(), admissionDateField.getCaption())));
288-
intensiveCareUnitStart.addValidator(
289-
new DateComparisonValidator(
290-
intensiveCareUnitStart,
291-
intensiveCareUnitEnd,
292-
true,
293-
false,
294-
I18nProperties.getValidationError(Validations.beforeDate, intensiveCareUnitStart.getCaption(), intensiveCareUnitEnd.getCaption())));
295-
intensiveCareUnitEnd.addValidator(
296-
new DateComparisonValidator(
297-
intensiveCareUnitEnd,
298-
intensiveCareUnitStart,
299-
false,
300-
false,
301-
I18nProperties.getValidationError(Validations.afterDate, intensiveCareUnitEnd.getCaption(), intensiveCareUnitStart.getCaption())));
302-
intensiveCareUnitEnd.addValidator(
303-
new DateComparisonValidator(
304-
intensiveCareUnitEnd,
305-
dischargeDateField,
306-
true,
307-
false,
308-
I18nProperties.getValidationError(Validations.beforeDate, intensiveCareUnitEnd.getCaption(), dischargeDateField.getCaption())));
309-
intensiveCareUnitStart.addValueChangeListener(event -> intensiveCareUnitEnd.markAsDirty());
310-
intensiveCareUnitEnd.addValueChangeListener(event -> intensiveCareUnitStart.markAsDirty());
311-
hospitalizedPreviouslyField.addValueChangeListener(e -> updatePrevHospHint(hospitalizedPreviouslyField, previousHospitalizationsField));
312-
previousHospitalizationsField.addValueChangeListener(e -> updatePrevHospHint(hospitalizedPreviouslyField, previousHospitalizationsField));
313298

314-
// RSV-specific conditional visibility logic
315-
// stillHospitalized should not be visible/writable if discharge date is filled
316-
dischargeDateField.addValueChangeListener(event -> {
317-
boolean hasDischargeDate = dischargeDateField.getValue() != null;
318-
stillHospitalizedField.setVisible(!hasDischargeDate);
319-
stillHospitalizedField.setEnabled(!hasDischargeDate);
320-
if (hasDischargeDate) {
321-
stillHospitalizedField.setValue(null);
322-
}
323-
});
299+
// RSV specific logic
300+
if (caze.getDisease() == Disease.RESPIRATORY_SYNCYTIAL_VIRUS) {
301+
intensiveCareUnitStart.addValidator(
302+
new DateComparisonValidator(
303+
intensiveCareUnitStart,
304+
admissionDateField,
305+
false,
306+
false,
307+
I18nProperties.getValidationError(Validations.afterDate, intensiveCareUnitStart.getCaption(), admissionDateField.getCaption())));
308+
intensiveCareUnitStart.addValidator(
309+
new DateComparisonValidator(
310+
intensiveCareUnitStart,
311+
intensiveCareUnitEnd,
312+
true,
313+
false,
314+
I18nProperties
315+
.getValidationError(Validations.beforeDate, intensiveCareUnitStart.getCaption(), intensiveCareUnitEnd.getCaption())));
316+
intensiveCareUnitEnd.addValidator(
317+
new DateComparisonValidator(
318+
intensiveCareUnitEnd,
319+
intensiveCareUnitStart,
320+
false,
321+
false,
322+
I18nProperties
323+
.getValidationError(Validations.afterDate, intensiveCareUnitEnd.getCaption(), intensiveCareUnitStart.getCaption())));
324+
intensiveCareUnitEnd.addValidator(
325+
new DateComparisonValidator(
326+
intensiveCareUnitEnd,
327+
dischargeDateField,
328+
true,
329+
false,
330+
I18nProperties.getValidationError(Validations.beforeDate, intensiveCareUnitEnd.getCaption(), dischargeDateField.getCaption())));
331+
intensiveCareUnitStart.addValueChangeListener(event -> intensiveCareUnitEnd.markAsDirty());
332+
intensiveCareUnitEnd.addValueChangeListener(event -> intensiveCareUnitStart.markAsDirty());
333+
334+
// RSV-specific conditional visibility logic
335+
// stillHospitalized should not be visible/writable if discharge date is filled
336+
337+
dischargeDateField.addValueChangeListener(event -> {
338+
boolean hasDischargeDate = dischargeDateField.getValue() != null;
339+
stillHospitalizedField.setVisible(!hasDischargeDate);
340+
stillHospitalizedField.setEnabled(!hasDischargeDate);
341+
if (hasDischargeDate) {
342+
stillHospitalizedField.setValue(null);
343+
}
344+
});
345+
// Show icuLengthOfStay when ICU dates are not available but survey has length information
346+
FieldHelper.setVisibleWhen(intensiveCareUnit, Collections.singletonList(icuLengthOfStayField), Arrays.asList(YesNoUnknown.YES), true);
347+
}
324348

325-
// Show icuLengthOfStay when ICU dates are not available but survey has length information
326-
FieldHelper.setVisibleWhen(intensiveCareUnit, Collections.singletonList(icuLengthOfStayField), Arrays.asList(YesNoUnknown.YES), true);
349+
hospitalizedPreviouslyField.addValueChangeListener(e -> updatePrevHospHint(hospitalizedPreviouslyField, previousHospitalizationsField));
350+
previousHospitalizationsField.addValueChangeListener(e -> updatePrevHospHint(hospitalizedPreviouslyField, previousHospitalizationsField));
327351
}
328352

329353
private void updatePrevHospHint(NullableOptionGroup hospitalizedPreviouslyField, PreviousHospitalizationsField previousHospitalizationsField) {

sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationCreationForm.java

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import java.util.Arrays;
2828
import java.util.Collections;
29+
import java.util.List;
30+
import java.util.stream.Collectors;
2931

3032
import com.vaadin.ui.Label;
3133
import com.vaadin.ui.Window;
@@ -55,6 +57,7 @@
5557
import de.symeda.sormas.api.person.PersonDto;
5658
import de.symeda.sormas.api.person.PersonReferenceDto;
5759
import de.symeda.sormas.api.travelentry.TravelEntryDto;
60+
import de.symeda.sormas.api.utils.Diseases;
5861
import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers;
5962
import de.symeda.sormas.ui.UiUtil;
6063
import de.symeda.sormas.ui.person.PersonCreateForm;
@@ -100,6 +103,7 @@ public class ImmunizationCreationForm extends AbstractEditForm<ImmunizationDto>
100103
private ComboBox responsibleRegion;
101104
private ComboBox responsibleDistrict;
102105
private ComboBox responsibleCommunity;
106+
private ComboBox meansOfImmunizationField;
103107
private Window warningSimilarPersons;
104108

105109
public ImmunizationCreationForm() {
@@ -134,6 +138,7 @@ protected void addFields() {
134138
addField(ImmunizationDto.DISEASE_DETAILS, TextField.class);
135139

136140
ComboBox meansOfImmunizationField = addField(ImmunizationDto.MEANS_OF_IMMUNIZATION, ComboBox.class);
141+
this.meansOfImmunizationField = meansOfImmunizationField;
137142
addField(ImmunizationDto.MEANS_OF_IMMUNIZATION_DETAILS, TextField.class);
138143

139144
CheckBox overwriteImmunizationManagementStatus = addCustomField(OVERWRITE_IMMUNIZATION_MANAGEMENT_STATUS, Boolean.class, CheckBox.class);
@@ -210,9 +215,13 @@ protected void addFields() {
210215
.warningSimilarPersons(personCreateForm.getNationalHealthIdField().getValue(), null, () -> warningSimilarPersons = null);
211216
});
212217

213-
diseaseField.addValueChangeListener(
214-
(ValueChangeListener) valueChangeEvent -> personCreateForm
215-
.updatePresentConditionEnum((Disease) valueChangeEvent.getProperty().getValue()));
218+
diseaseField.addValueChangeListener((ValueChangeListener) valueChangeEvent -> {
219+
final Disease selectedDisease = (Disease) valueChangeEvent.getProperty().getValue();
220+
personCreateForm.updatePresentConditionEnum(selectedDisease);
221+
222+
// Update means of immunization field based on selected disease using filtered enum data
223+
updateMeansOfImmunizationField(selectedDisease);
224+
});
216225
getContent().addComponent(personCreateForm, TravelEntryDto.PERSON);
217226

218227
// Set initial visibilities & accesses
@@ -254,8 +263,9 @@ protected void addFields() {
254263
} else {
255264
managementStatusField.setValue(ImmunizationManagementStatus.SCHEDULED);
256265
}
257-
boolean isVaccinationVisible =
258-
MeansOfImmunization.VACCINATION.equals(meansOfImmunization) || MeansOfImmunization.VACCINATION_RECOVERY.equals(meansOfImmunization);
266+
// Use the isVaccination method from the enum to determine vaccination visibility
267+
// This includes VACCINATION, VACCINATION_RECOVERY, MATERNAL_VACCINATION, and MONOCLONAL_ANTIBODY
268+
boolean isVaccinationVisible = MeansOfImmunization.isVaccination(meansOfImmunization);
259269
numberOfDosesField.setVisible(isVaccinationVisible);
260270
if (!isVaccinationVisible) {
261271
numberOfDosesField.setValue(null);
@@ -346,6 +356,20 @@ protected void addFields() {
346356
});
347357

348358
addValueChangeListener(e -> {
359+
Disease currentDisease = disease;
360+
if (currentDisease == null && diseaseField.getValue() != null) {
361+
currentDisease = (Disease) diseaseField.getValue();
362+
}
363+
364+
// Initialize means of immunization field based on current disease
365+
if (currentDisease != null) {
366+
FieldHelper.updateItems(
367+
meansOfImmunizationField,
368+
Arrays.asList(MeansOfImmunization.values()),
369+
FieldVisibilityCheckers.withDisease(currentDisease),
370+
MeansOfImmunization.class);
371+
}
372+
349373
if (disease != null) {
350374
setVisible(false, ImmunizationDto.DISEASE, ImmunizationDto.DISEASE_DETAILS);
351375
setReadOnly(false, ImmunizationDto.DISEASE, ImmunizationDto.DISEASE_DETAILS);
@@ -361,6 +385,27 @@ protected void addFields() {
361385
});
362386
}
363387

388+
/**
389+
* Updates the means of immunization field with disease-specific filtering.
390+
* Uses {@link Diseases} annotations on enum values to determine visibility.
391+
*
392+
* @param disease
393+
* The selected disease to filter means of immunization options.
394+
*/
395+
private void updateMeansOfImmunizationField(Disease disease) {
396+
List<MeansOfImmunization> filteredValues = Arrays.stream(MeansOfImmunization.values()).filter(value -> {
397+
try {
398+
java.lang.reflect.Field enumField = MeansOfImmunization.class.getField(value.name());
399+
return FieldVisibilityCheckers.withDisease(disease).isVisible(MeansOfImmunization.class, enumField);
400+
} catch (NoSuchFieldException e) {
401+
// If field doesn't exist, include it by default
402+
return true;
403+
}
404+
}).collect(Collectors.toList());
405+
406+
FieldHelper.updateEnumData(meansOfImmunizationField, filteredValues);
407+
}
408+
364409
private void updateFacilityFields(ComboBox cbFacility, TextField tfFacilityDetails) {
365410

366411
if (cbFacility.getValue() != null) {

0 commit comments

Comments
 (0)