Skip to content

Summary: Malaria and Dengue Sample and Pathogentestform changes.#13889

Open
KarnaiahPesula wants to merge 2 commits intodevelopmentfrom
feature-13814-dengue-enhance-sample-form
Open

Summary: Malaria and Dengue Sample and Pathogentestform changes.#13889
KarnaiahPesula wants to merge 2 commits intodevelopmentfrom
feature-13814-dengue-enhance-sample-form

Conversation

@KarnaiahPesula
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula commented Mar 26, 2026

Changes:
#13801 #13814

Fixes # Enhancing the sample and pathogen changes for Malaria and Dengue diseases

Summary by CodeRabbit

  • New Features

    • Malaria health condition and infection-year capture; exposure start/end dates auto-calculated from incubation
    • Disease transmission classification added
    • Enhanced pathogen test capture: serotype/specie free-text, antibody titre, reference-lab flag, retest tracking, result details
    • Variant-summary display for malaria and dengue samples; expanded test types and species
  • Refactor

    • Serotype model reworked to enum + free-text; genotype field renamed/standardized
  • Documentation

    • Updated captions and localization for new fields and enums

@KarnaiahPesula KarnaiahPesula requested a review from raulbob March 26, 2026 09:18
@KarnaiahPesula KarnaiahPesula linked an issue Mar 26, 2026 that may be closed by this pull request
33 tasks
@coderabbitai
Copy link

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

Added malaria and dengue sample/test support, genotype/serotype refactors, new Serotype and DiseaseTransmission enums, exposure date fields and population logic, UI form changes, i18n updates, DTO/entity/mapping updates, and corresponding DB schema migrations.

Changes

Cohort / File(s) Summary
Health Conditions (malaria)
sormas-api/.../clinicalcourse/HealthConditionsDto.java, sormas-backend/.../clinicalcourse/HealthConditions.java, sormas-backend/.../clinicalcourse/HealthConditionsMapper.java, sormas-ui/.../clinicalcourse/HealthConditionsForm.java
Added malaria and malariaInfectedYear fields to DTO/entity, mapper and UI form (including infected-year subfield and visibility wiring).
Disease configuration RPC
sormas-api/.../disease/DiseaseConfigurationFacade.java, sormas-backend/.../disease/DiseaseConfigurationFacadeEjb.java
Added getDiseaseConfiguration(Disease) method to facade and backend implementation.
EpiData exposure dates
sormas-api/.../epidata/EpiDataDto.java, sormas-ui/.../epidata/EpiDataForm.java, sormas-ui/.../caze/CaseController.java, sormas-api/.../i18n/Strings.java, src/main/resources/strings.properties
Added exposureStartDate/exposureEndDate fields, UI rendering (disabled), localization keys, and logic to populate exposure dates using disease incubation configuration.
Enums: Serotype & DiseaseTransmission
sormas-api/.../sample/Serotype.java, sormas-api/.../epidata/DiseaseTransmission.java
Added Serotype enum for DENV_1–4/OTHER with fromString and localized toString; added DiseaseTransmission enum with localized captions.
GenoType rename/refactor
sormas-api/.../sample/GenoType.java, sormas-api/.../sample/PathogenTestDto.java, sormas-api/.../externalmessage/labmessage/TestReportDto.java, sormas-backend/.../externalmessage/labmessage/TestReport.java, sormas-backend/.../sample/PathogenTest.java, sormas-backend/.../externalmessage/labmessage/TestReportFacadeEjb.java
Renamed GenoTypeResultGenoType; updated DTO/entity fields, getters/setters, mappings and TestReport handling to use new type and names.
PathogenSpecie / PathogenTestType expansions
sormas-api/.../sample/PathogenSpecie.java, sormas-api/.../sample/PathogenTestType.java, sormas-api/.../sample/SampleMaterial.java
Added malaria species constants and broadened applicable test metadata; added new test types (NAAT, THICK/THIN BLOOD SMEAR, Q_PCR, LAMP, OTHER_*); adjusted SampleMaterial annotations.
PathogenTest DTO/entity & mappings
sormas-api/.../sample/PathogenTestDto.java, sormas-backend/.../sample/PathogenTest.java, sormas-backend/.../sample/PathogenTestFacadeEjb.java, sormas-api/.../externalmessage/processing/ExternalMessageMapper.java
Refactored serotype from String→Serotype with serotypeText, renamed genotype fields, added specieText and dengue/malaria result metadata (antibodyTitre, performedByReferenceLaboratory, retestRequested, resultDetails), and adapted mapping logic (including Serotype.fromString usage).
UI: PathogenTest form & list / sample list
sormas-ui/.../samples/PathogenTestForm.java, sormas-ui/.../samples/pathogentestlink/PathogenTestListEntry.java, sormas-ui/.../samples/sampleLink/SampleListEntry.java, sormas-ui/.../samples/PathogenTestListEntry.java
Major form/layout changes: combo/text pairs for serotype/specie, genotype combobox updates, new visibility maps (SEROTYPE_VISIBILITY_MAP, SPECIE_VISIBILITY_MAP), disease/test-type-specific visibility and population logic, and variant display in sample/test list entries.
Symptoms / Case symptom component changes
sormas-ui/.../symptoms/SymptomsForm.java, sormas-ui/.../caze/CaseSymptomSideViewComponent.java, sormas-ui/.../caze/CaseDataForm.java, sormas-api/.../symptoms/SymptomsDto.java
Refactored complication toggling to use Field-based flow, adjusted symptom annotations/groupings, and improved blank-check logic for manual case definitions.
Internationalization & resources
sormas-api/.../i18n/Captions.java, sormas-api/.../i18n/Strings.java, sormas-api/src/main/resources/captions.properties, sormas-api/src/main/resources/enum.properties, sormas-api/src/main/resources/strings.properties
Added/renamed caption keys for malaria, serotype, specie, genotype rename, antibodyTitre, resultDetails, retestRequested, DiseaseTransmission enum captions, and exposure date strings.
Epipulse / Measles export
sormas-api/.../epipulse/EpipulseDiseaseExportEntryDto.java, sormas-api/.../epipulse/EpipulseLaboratoryMapper.java, sormas-backend/.../epipulse/MeaslesExportStrategy.java
Doc updates referencing genotype naming and SQL adjusted to use genotype column.
DB schema migration
sormas-backend/src/main/resources/sql/sormas_schema.sql
Added/renamed columns: serotypetext, antibodyTitre, performedByReferenceLaboratory, retestRequested, resultdetails, specietext; renamed genotyperesultgenotype, genotyperesulttextgenotypetext; added malaria and malariainfectedyear and new migration version entry.
External message mapping updates
sormas-api/.../externalmessage/processing/ExternalMessageMapper.java
Adjusted mapping to new genotype/serotype getters/setters and converted serotype string to Serotype enum; updated serotype mapping and imports.
Minor docs/Javadoc adjustments
sormas-api/.../epipulse/*, sormas-api/.../epipulse/EpipulseLaboratoryMapper.java, sormas-api/.../epipulse/EpipulseDiseaseExportEntryDto.java
Updated Javadoc/comments to reference renamed genotype fields; no logic change.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI (CaseController / Form)
    participant Facade as DiseaseConfigurationFacade (API)
    participant Backend as DiseaseConfigurationFacadeEjb
    participant Service as DiseaseConfigurationService/Repo
    UI->>Facade: getDiseaseConfiguration(disease)
    Facade->>Backend: remote call getDiseaseConfiguration(disease)
    Backend->>Service: service.getDiseaseConfiguration(disease)
    Service-->>Backend: DiseaseConfiguration (min/max/incubation, enabled)
    Backend-->>Facade: DiseaseConfigurationDto
    Facade-->>UI: DiseaseConfigurationDto
    UI->>UI: compute exposureStartDate/endDate using symptomOnsetDate and incubation bounds (DateHelper.subtractDays)
    UI-->>EpiDataDto: setExposureStartDate / setExposureEndDate
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

  • #13801: Implements malaria sample/test enhancements (PathogenSpecie, PathogenTestType, DTOs, UI) — aligns with malaria additions in this PR.
  • #13814: Implements dengue serotype/serology/test-type enhancements — aligns with Serotype, antibody and dengue-specific UI/fields in this PR.

Possibly related PRs

  • PR#13765: Related changes to ExternalMessageMapper and serotype/genotype mapping logic.
  • PR#13729: Related PathogenTestForm modifications and result-field decision logic.
  • PR#13680: Related genotype UI/population behavior and transitions to new GenoType handling.

Suggested reviewers

  • raulbob
  • obinna-h-n

"🐰 I hopped through enums, forms, and fields so bright,
Serotypes, genotypes, malaria in sight,
I stitched DTOs and DB columns with care,
Forms now show variants bold and fair,
A tiny rabbit celebrates this code-flight! 🥕✨"

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description references two related issues (#13801 and #13814) and provides a high-level summary of the changes. However, it lacks structured detail about implementation scope and specific changes made across multiple components. Consider adding more structured detail: specific components modified (HealthConditions, PathogenTest, SerologyForm, etc.), key architectural changes (enum refactoring, field additions), and testing scope to better communicate implementation breadth.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding Malaria and Dengue support to sample and pathogen test form changes. It is concise, specific, and reflects the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature-13814-dengue-enhance-sample-form

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (1)

1135-1162: ⚠️ Potential issue | 🟠 Major

Missing visibility update calls in disease change listener.

When the disease changes, updateSerotypeField and updateSpecieField BiConsumers are not invoked. This means if a user changes the disease, the serotype and specie field visibility won't update until they also change the test type. The items are updated (lines 1151-1152), but the visibility logic is missing.

🐛 Proposed fix
 			FieldHelper.updateItems(disease, seroTypeField, Serotype.class);
 			FieldHelper.updateItems(disease, specieField, PathogenSpecie.class);
+			// Update visibility based on disease and current test type
+			PathogenTestType currentTestType = (PathogenTestType) testTypeField.getValue();
+			updateSerotypeField.accept(disease, currentTestType);
+			updateSpecieField.accept(disease, currentTestType);
 			if (FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`
around lines 1135 - 1162, The disease change listener on diseaseField doesn't
invoke the visibility BiConsumers updateSerotypeField and updateSpecieField, so
update their visibility when the disease changes: inside the ValueChangeListener
(the lambda registered on diseaseField) after setting disease and after calling
FieldHelper.updateItems for seroTypeField and specieField, call
updateSerotypeField.accept(disease) and updateSpecieField.accept(disease) (or
the appropriate BiConsumer signatures) so serotype and specie visibility updates
immediately on disease change; ensure the calls are placed alongside the
existing FieldHelper.updateItems calls and before any early returns.
🟡 Minor comments (6)
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/sampleLink/SampleListEntry.java-163-170 (1)

163-170: ⚠️ Potential issue | 🟡 Minor

Gate measles variants by VARIANT_MAP too.

Unlike the malaria and dengue branches, this one ignores the allowed test-type list. If the latest measles test isn't a genotyping assay but still has genoType populated, the side panel will show a variant that doesn't belong to that test.

💡 Proposed fix
-				} else if (latestTest.getTestedDisease() == Disease.MEASLES) {
+				} else if (latestTest.getTestedDisease() == Disease.MEASLES
+					&& PathogenTestListEntry.VARIANT_MAP.get(latestTest.getTestedDisease()).stream().anyMatch(latestTest.getTestType()::equals)) {
 					variant = StringUtils.abbreviate((latestTest.getGenoType() != null ? latestTest.getGenoType().toString() : ""), 125);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/sampleLink/SampleListEntry.java`
around lines 163 - 170, The measles branch currently ignores the allowed
test-type list and always uses latestTest.getGenoType(); modify the
Disease.MEASLES case to first check
PathogenTestListEntry.VARIANT_MAP.get(latestTest.getTestedDisease()).stream().anyMatch(latestTest.getTestType()::equals)
(same pattern as the MALARIA and DENGUE branches) and only then set variant =
StringUtils.abbreviate((latestTest.getGenoType() != null ?
latestTest.getGenoType().toString() : ""), 125); otherwise leave variant
unset/null.
sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java-84-85 (1)

84-85: ⚠️ Potential issue | 🟡 Minor

Remove the extra CASE_IMPORTED_STATUS slot.

EpiDataDto.CASE_IMPORTED_STATUS is already rendered in the conclusion row below. Reusing the same layout location here can leave the field attached to the wrong section or one of the rows blank.

💡 Proposed fix
-			fluidRowLocs(6, EpiDataDto.EXPOSURE_START_DATE, 6, EpiDataDto.EXPOSURE_END_DATE)+
-			fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"") +
+			fluidRowLocs(6, EpiDataDto.EXPOSURE_START_DATE, 6, EpiDataDto.EXPOSURE_END_DATE) +
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java` around
lines 84 - 85, The second fluidRowLocs invocation currently passes
EpiDataDto.CASE_IMPORTED_STATUS
(fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"")), but that field is
already rendered in the conclusion row below; remove the duplicate by replacing
EpiDataDto.CASE_IMPORTED_STATUS with an empty slot (e.g. "") or otherwise
dropping that parameter so the call does not render CASE_IMPORTED_STATUS here;
update the fluidRowLocs call in EpiDataForm to no longer reference
EpiDataDto.CASE_IMPORTED_STATUS.
sormas-backend/src/main/resources/sql/sormas_schema.sql-15496-15496 (1)

15496-15496: ⚠️ Potential issue | 🟡 Minor

Typo in schema version comment: "sampel" should be "sample".

-INSERT INTO schema_version (version_number, comment) VALUES (615, '#13801, `#13814` - Malaria and Dengue sampel changes');
+INSERT INTO schema_version (version_number, comment) VALUES (615, '#13801, `#13814` - Malaria and Dengue sample changes');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql` at line 15496, Fix
the typo in the schema version comment for the INSERT INTO schema_version row
(the VALUES entry for version_number 615): change the string '#13801, `#13814` -
Malaria and Dengue sampel changes' to '#13801, `#13814` - Malaria and Dengue
sample changes' so the comment text for that INSERT reflects the correct
spelling.
sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java-328-329 (1)

328-329: ⚠️ Potential issue | 🟡 Minor

Avoid nullable state for retestRequested when default is false.

Line 328 initializes retestRequested to false, but Line 948-950 allows setting null, which reintroduces tri-state behavior.

🔧 Suggested fix
-	private Boolean retestRequested = false;
+	private Boolean retestRequested = Boolean.FALSE;
@@
 	public void setRetestRequested(Boolean retestRequested) {
-		this.retestRequested = retestRequested;
+		this.retestRequested = Boolean.TRUE.equals(retestRequested);
 	}

Also applies to: 944-950

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java`
around lines 328 - 329, The field retestRequested is declared as a boxed Boolean
with default false but elsewhere (setter/getRetestRequested methods) allow null,
reintroducing tri-state; change the field to primitive boolean (retestRequested)
and update its accessor methods (getRetestRequested / setRetestRequested or
isRetestRequested) and any places that accept/assign null to use primitive
boolean (or treat null as false) so the property can never be null; ensure
serialization/deserialization and any callers are adjusted to pass a boolean
instead of null.
sormas-api/src/main/resources/enum.properties-1199-1203 (1)

1199-1203: ⚠️ Potential issue | 🟡 Minor

Use acronym casing for LAMP caption.

Line 1203 currently uses Lamp; this should be uppercase (LAMP) for consistency with lab-test acronym style.

✏️ Suggested fix
-PathogenTestType.LAMP = Lamp
+PathogenTestType.LAMP = LAMP
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/resources/enum.properties` around lines 1199 - 1203, The
caption for the enum key PathogenTestType.LAMP uses "Lamp" but should be the
uppercase acronym "LAMP"; update the value for PathogenTestType.LAMP in
enum.properties from "Lamp" to "LAMP" to match the lab-test acronym style and
maintain consistency with other test-type captions.
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java-176-176 (1)

176-176: ⚠️ Potential issue | 🟡 Minor

Incorrect formatter annotation.

Line 176 should be //@formatter:on to close the formatter-off section that started at line 147. Currently it says //@formatter:off which leaves the formatter disabled.

🔧 Proposed fix
-	//@formatter:off
+	//@formatter:on
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java` at
line 176, In PathogenTestForm (class PathogenTestForm) the inline formatter
region was never closed: replace the second occurrence of the comment marker
currently written as //@formatter:off with //@formatter:on to close the
formatter-off started earlier (the pair around the block beginning at line 147);
update the comment so formatter directives are matched (ensure only the trailing
comment near the end of the hand-formatted block uses //@formatter:on).
🧹 Nitpick comments (7)
sormas-backend/src/main/resources/sql/sormas_schema.sql (1)

15475-15479: Inconsistent column naming conventions: mixed camelCase and lowercase.

PostgreSQL lowercases unquoted identifiers, so antibodyTitre becomes antibodytitre in the catalog. However, the inconsistency between explicit lowercase (serotypetext, resultdetails, specietext) and camelCase (antibodyTitre, performedByReferenceLaboratory, retestRequested) can cause confusion when the Java entity field names don't match.

Consider using consistent lowercase with underscores (e.g., antibody_titre, performed_by_reference_laboratory) or consistent lowercase without separators to match the existing pattern in this migration.

Also applies to: 15488-15492

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql` around lines 15475 -
15479, The ALTER TABLE statements on table pathogentest introduce mixed
camelCase and lowercase column names; rename them to a consistent
lowercase_snake_case convention (or match the existing lowercase pattern) so
Java entity mappings remain predictable — replace antibodyTitre,
performedByReferenceLaboratory, retestRequested, resultdetails, specietext with
antibody_titre, performed_by_reference_laboratory, retest_requested,
result_details, species_text (and apply the same renaming in the subsequent
related statements at the other block referenced: 15488-15492), ensuring
defaults and boolean types are preserved and update any corresponding Java
entity/ORM mappings to use the new column names.
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java (2)

154-159: Inconsistent membership check style.

Lines 155 and 158 use .stream().anyMatch(testType::equals) while line 141 uses .contains(testType). For consistency and simplicity, prefer .contains() throughout.

Suggested simplification
-		} else if (pathogenTest.getTestedDisease() == Disease.MALARIA
-			&& VARIANT_MAP.get(pathogenTest.getTestedDisease()).stream().anyMatch(testType::equals)) {
+		} else if (pathogenTest.getTestedDisease() == Disease.MALARIA
+			&& VARIANT_MAP.get(Disease.MALARIA).contains(testType)) {
 			resultText = StringUtils.abbreviate((pathogenTest.getSpecie() != null ? pathogenTest.getSpecie().toString() : ""), 125);
-		} else if (pathogenTest.getTestedDisease() == Disease.DENGUE
-			&& VARIANT_MAP.get(pathogenTest.getTestedDisease()).stream().anyMatch(testType::equals)) {
+		} else if (pathogenTest.getTestedDisease() == Disease.DENGUE
+			&& VARIANT_MAP.get(Disease.DENGUE).contains(testType)) {
 			resultText = StringUtils.abbreviate((pathogenTest.getSerotype() != null ? pathogenTest.getSerotype().toString() : ""), 125);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`
around lines 154 - 159, In PathogenTestListEntry, the membership checks against
VARIANT_MAP currently use stream().anyMatch(testType::equals) for MALARIA and
DENGUE; replace those with the simpler
VARIANT_MAP.get(pathogenTest.getTestedDisease()).contains(testType) to match the
style used elsewhere (e.g., the check on line 141) so all variant membership
checks are consistent and clearer.

56-68: Avoid double-brace initialization for static map.

Double-brace initialization (new HashMap<>() {{ ... }}) creates an anonymous inner class, which can cause subtle issues (e.g., serialization problems, retaining references). For a public static final constant, prefer Map.of() and List.of() (available in Java 9+, supported by this project's Java 11+ target).

Suggested refactor using Map.of()
-	public static final Map<Disease, List<PathogenTestType>> VARIANT_MAP = Collections.unmodifiableMap(new HashMap<>() {
-		{
-			put(Disease.MALARIA, Collections.unmodifiableList(Arrays.asList(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.RAPID_TEST, PathogenTestType.PCR_RT_PCR,
-					PathogenTestType.Q_PCR, PathogenTestType.LAMP, PathogenTestType.IFAT)));
-			put(Disease.DENGUE, Collections.unmodifiableList(Arrays.asList(PathogenTestType.NAAT, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestType.PCR_RT_PCR)));
-			put(Disease.MEASLES, Collections.unmodifiableList(Arrays.asList(PathogenTestType.GENOTYPING)));
-			put(Disease.INVASIVE_PNEUMOCOCCAL_INFECTION, Collections.unmodifiableList(Arrays.asList(PathogenTestType.SEROGROUPING, PathogenTestType.MULTILOCUS_SEQUENCE_TYPING,
-					PathogenTestType.SLIDE_AGGLUTINATION,PathogenTestType.WHOLE_GENOME_SEQUENCING, PathogenTestType.SEQUENCING)));
-			put(Disease.TUBERCULOSIS, Collections.unmodifiableList(Arrays.asList(PathogenTestType.MICROSCOPY, PathogenTestType.BEIJINGGENOTYPING,
-							PathogenTestType.SPOLIGOTYPING, PathogenTestType.MIRU_PATTERN_CODE)));
-		}
-	});
+	public static final Map<Disease, List<PathogenTestType>> VARIANT_MAP = Map.of(
+		Disease.MALARIA, List.of(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.RAPID_TEST, PathogenTestType.PCR_RT_PCR,
+			PathogenTestType.Q_PCR, PathogenTestType.LAMP, PathogenTestType.IFAT),
+		Disease.DENGUE, List.of(PathogenTestType.NAAT, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestType.PCR_RT_PCR),
+		Disease.MEASLES, List.of(PathogenTestType.GENOTYPING),
+		Disease.INVASIVE_PNEUMOCOCCAL_INFECTION, List.of(PathogenTestType.SEROGROUPING, PathogenTestType.MULTILOCUS_SEQUENCE_TYPING,
+			PathogenTestType.SLIDE_AGGLUTINATION, PathogenTestType.WHOLE_GENOME_SEQUENCING, PathogenTestType.SEQUENCING),
+		Disease.TUBERCULOSIS, List.of(PathogenTestType.MICROSCOPY, PathogenTestType.BEIJINGGENOTYPING,
+			PathogenTestType.SPOLIGOTYPING, PathogenTestType.MIRU_PATTERN_CODE)
+	);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`
around lines 56 - 68, Replace the double-brace anonymous-map initialization for
VARIANT_MAP with an explicit immutable construction using Map.of(...) and
List.of(...) to avoid creating an anonymous inner class; specifically, in
PathogenTestListEntry change the public static final Map<Disease,
List<PathogenTestType>> VARIANT_MAP declaration to use Map.of(...) with each
Disease mapped to a List.of(...) of PathogenTestType (keeping the same Disease
keys: MALARIA, DENGUE, MEASLES, INVASIVE_PNEUMOCOCCAL_INFECTION, TUBERCULOSIS)
so the map and lists are truly unmodifiable and no anonymous inner class is
created.
sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java (1)

294-300: Redundant null check inside isNotBlank block.

Line 296 contains source.getSerotypeText() == null ? null : source.getSerotypeText().toString(), but this is inside a block where StringUtils.isNotBlank(source.getSerotypeText()) already ensures the value is non-null and non-empty. The null check is unnecessary.

Additionally, calling .toString() on a String is redundant.

Suggested simplification
-		// If serotypetext is not null, then serotype is Other, otherwise it'd be normal serotype
-		if (StringUtils.isNotBlank(source.getSerotypeText())) {
-			target.setSerotype(Serotype.fromString(source.getSerotypeText() == null ? null : source.getSerotypeText().toString()));
-		} else {
-			target.setSerotype(source.getSerotype());
-		}
+		// If serotypeText is not blank, derive serotype from text; otherwise use existing serotype
+		if (StringUtils.isNotBlank(source.getSerotypeText())) {
+			target.setSerotype(Serotype.fromString(source.getSerotypeText()));
+		} else {
+			target.setSerotype(source.getSerotype());
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java`
around lines 294 - 300, In PathogenTestFacadeEjb where you set the serotype
(inside the block guarded by StringUtils.isNotBlank(source.getSerotypeText())),
remove the redundant null check and the unnecessary .toString() call; call
Serotype.fromString(source.getSerotypeText()) directly when setting
target.setSerotype(...) (leave the else branch
target.setSerotype(source.getSerotype()) and the subsequent
target.setSerotypeText(source.getSerotypeText()) unchanged).
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (3)

520-523: Initial visibility may cause premature field display.

Both genoTypingCB and genoTypingResultTextTF are set to setVisible(true) immediately after creation. However, the visibility should depend on disease/test type combinations (as handled by cryptoGenoTypingDependencies at line 1090). Setting true here may cause these fields to briefly appear before the conditional visibility logic is applied.

Consider initializing with setVisible(false) to match the typical pattern used for other conditional fields in this form.

♻️ Suggested change
 		genoTypingCB = addField(PathogenTestDto.GENOTYPE, ComboBox.class);
-		genoTypingCB.setVisible(true);
+		genoTypingCB.setVisible(false);
 		genoTypingResultTextTF = addField(PathogenTestDto.GENOTYPE_TEXT, TextField.class);
-		genoTypingResultTextTF.setVisible(true);
+		genoTypingResultTextTF.setVisible(false);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`
around lines 520 - 523, In PathogenTestForm change the initial visibility of the
genotype fields so they don't flash before dependency logic runs: set
genoTypingCB and genoTypingResultTextTF to not visible on creation (replace
setVisible(true) with setVisible(false)) so the conditional visibility
controlled by cryptoGenoTypingDependencies (and any similar dependency methods)
determines when they become visible.

611-611: Remove commented-out code if no longer needed.

If the old SPECIE_VISIBILITY_CONDITIONS approach has been replaced by the new SPECIE_VISIBILITY_MAP with BiConsumer, this commented line should be removed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java` at
line 611, Remove the stale commented-out line that references the old
SPECIE_VISIBILITY_CONDITIONS to avoid confusion: delete the comment "//
FieldHelper.setVisibleWhen(getFieldGroup(), PathogenTestDto.SPECIE,
SPECIE_VISIBILITY_CONDITIONS, true);" from PathogenTestForm.java since the code
now uses SPECIE_VISIBILITY_MAP with a BiConsumer-based approach; ensure no other
references to SPECIE_VISIBILITY_CONDITIONS remain and confirm behavior relies on
SPECIE_VISIBILITY_MAP and its consumer logic for PathogenTestDto.SPECIE
visibility.

1293-1300: Consider removing commented-out code.

Line 1295 contains commented-out code. If this is no longer needed, it should be removed to improve code cleanliness.

♻️ Suggested cleanup
 		// displaying the serotype text field only if the serotype is "other" and it has the visibility
 		if (isVisibleAllowed(PathogenTestDto.SEROTYPE)) {
-			//			FieldHelper.setVisibleWhen(getFieldGroup(), PathogenTestDto.SEROTYPE, SEROTYPE_VISIBILITY_MAP, true);
 			FieldHelper.setVisibleWhen(getFieldGroup(), PathogenTestDto.SEROTYPE_TEXT, PathogenTestDto.SEROTYPE, Serotype.OTHER, true);
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`
around lines 1293 - 1300, Remove the leftover commented-out call to
FieldHelper.setVisibleWhen inside PathogenTestForm (the commented line
referencing PathogenTestDto.SEROTYPE) to clean up the code; keep the active
visibility rules for PathogenTestDto.SEROTYPE_TEXT and
PathogenTestDto.SPECIE_TEXT intact and ensure no other logic depended on that
commented invocation (search for FieldHelper.setVisibleWhen and the symbols
PathogenTestDto.SEROTYPE, SEROTYPE_VISIBILITY_MAP to confirm).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenSpecie.java`:
- Around line 55-65: In PathogenSpecie add the missing malaria disease marker to
FALCIPARUM: update the enum constant FALCIPARUM to include the annotation
`@Diseases`(Disease.MALARIA) alongside its existing `@ApplicableToPathogenTests` so
disease-filtered lookups include this primary malaria species; locate the
FALCIPARUM enum entry in class PathogenSpecie and annotate it with
`@Diseases`(Disease.MALARIA).

In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java`:
- Line 232: The new free-text fields in PathogenTestDto (specieText,
antibodyTitre, resultDetails) lack `@Size` validation like neighboring string
fields; add appropriate `@Size`(max = N) annotations (matching nearby fields'
limits) to each of these fields in the PathogenTestDto class so input length is
constrained and consistent with existing DTO validations, and update any
existing imports to include javax.validation.constraints.Size if needed.
- Around line 116-117: PathogenTestDto renamed the fields GENOTYPE/GENOTYPE_TEXT
from the old genoTypeResult/gen oTypeResultText keys which breaks
deserialization for clients using the old names; add backward-compatible aliases
by annotating the getters getGenoType and getGenoTypeText (or the corresponding
fields) with `@JsonAlias`("genoTypeResult") and `@JsonAlias`("genoTypeResultText")
respectively and keep the existing GENOTYPE/GENOTYPE_TEXT constants (optionally
add GENOTYPE_RESULT/GENOTYPE_RESULT_TEXT constants for clarity) so incoming JSON
with the old keys will map to the current genoType and genoTypeText properties.

In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java`:
- Around line 298-301: Remove the duplicate IFAT enum constant from the
PathogenTestType enum and replace all usages of IFAT with
INDIRECT_FLUORESCENT_ANTIBODY so the API and UI agree; specifically, delete the
IFAT entry in PathogenTestType (preserving the Diseases({Disease.MALARIA})
semantics by applying it to INDIRECT_FLUORESCENT_ANTIBODY if needed) and update
references in UI classes PathogenTestListEntry and PathogenTestForm (and any
other callers) to use PathogenTestType.INDIRECT_FLUORESCENT_ANTIBODY; run a
quick compile/search to ensure no lingering references to IFAT remain.

In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/Serotype.java`:
- Around line 50-56: The method Serotype.fromString currently builds
serotypeEnumVal from the raw input which can include surrounding whitespace,
causing valid inputs like " DENV-1 " to map to OTHER; fix by trimming and
normalizing the input first. In Serotype.fromString, after the initial
null/blank check, create a normalized string from serotype.trim() then call
toUpperCase().replaceAll("[-_]", "_") (use this normalized value instead of the
original serotype when computing serotypeEnumVal and when calling
Serotype.valueOf), and use that normalized serotypeEnumVal in the noneMatch(...)
check and the valueOf(...) call so trimmed inputs are resolved correctly.

In `@sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java`:
- Around line 2864-2875: The `@Complication`() annotation on fields reoccurrence
and overnightStayRequired is empty so getComplicatedSymptomsWithDiseases (which
checks Arrays.asList(complicationAnnotation.value()).contains(disease)) will
never match; fix by either adding explicit disease values to the annotations
(e.g., change `@Complication`() to `@Complication`({GIARDIASIS, CRYPTOSPORIDIOSIS})
on reoccurrence and overnightStayRequired) or modify
getComplicatedSymptomsWithDiseases to treat an empty
complicationAnnotation.value() as a wildcard by falling back to the field's
`@Diseases` values when the complication array is empty.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditions.java`:
- Around line 341-347: The getter getMalaria() is missing the JPA enum mapping
annotation and will default to ordinal storage; add `@Enumerated`(EnumType.STRING)
to the getMalaria() method so the YesNoUnknown enum is persisted as a VARCHAR
(matching existing fields and the DB schema), leaving setMalaria(...) unchanged.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`:
- Around line 182-184: getDiseaseConfiguration currently returns the raw DTO
from toDto(service.getDiseaseConfiguration(disease)) without applying default
normalization; change it to store the DTO in a local variable, call
updateDtoNullPropertiesWithDefaultDiseaseEnumProperties(dto) to fill null config
values, then return the normalized dto so behavior matches existing retrieval
logic (use the existing toDto, service.getDiseaseConfiguration(disease) and
updateDtoNullPropertiesWithDefaultDiseaseEnumProperties(...) methods).

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/TestReport.java`:
- Line 127: The genoType field in class TestReport is mapped implicitly to
column "genotype" but the DB column is "genotyperesult"; fix by adding an
explicit column mapping—annotate the getter (or the field) for genoType with
`@Column`(name = "genotyperesult") in TestReport so Hibernate uses the correct
column name, or alternatively run an SQL migration to rename the testreport
table column to "genotype" to match the implicit mapping; ensure the change
targets the genoType property in TestReport.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java`:
- Around line 614-615: The serotype conversion in fillOrBuildEntity() is
asymmetric with toDto(): update the logic in
PathogenTestFacadeEjb.fillOrBuildEntity (where target.setSerotype(...) and
target.setSerotypeText(...) are set) so that it mirrors toDto(): if
source.getSerotypeText() is not blank, derive the entity serotype from that text
(and set serotypeText accordingly); otherwise fall back to
Serotype.fromString(source.getSerotype() == null ? null :
source.getSerotype().toString()). Keep setting
target.setSerotypeText(source.getSerotypeText()) as before to preserve the
custom text.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Around line 15486-15487: The two unconditional ALTER TABLE statements renaming
columns in pathogentest_history (genotyperesult → genotype and
genotyperesulttext → genotypetext) must be made idempotent; update them to first
check for the existence of the old columns (and absence of the new names) and
only perform the ALTER TABLE ... RENAME COLUMN if needed. Locate the ALTER TABLE
pathogentest_history statements referring to genotyperesult and
genotyperesulttext and wrap each rename in a conditional that queries
information_schema.columns for the column names before executing the rename so
repeated runs won’t error.
- Around line 15473-15474: The plain RENAME COLUMN statements (ALTER TABLE
pathogentest rename column genotyperesult to genotype; and rename column
genotyperesulttext to genotypetext;) are not idempotent and will fail on re-run;
replace each with a small conditional DO block that checks for the existence of
the source column (e.g., "genotyperesult" / "genotyperesulttext") and the
non-existence of the target column ("genotype" / "genotypetext") using
pg_catalog or information_schema queries, and only then issues the ALTER TABLE
... RENAME COLUMN command via EXECUTE; do this for both renames (reference the
exact identifiers pathogentest, genotyperesult->genotype and
genotyperesulttext->genotypetext) so the migration becomes safe to re-run.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java`:
- Around line 1397-1409: The code mutates the live DTO by calling
includeExposureDates(symptomOnsetDate, epiDataDto, caze.getDisease()) on
epiDataDto which is caze.getEpiData(), causing UI-only derived exposure dates to
be persisted; to fix, create a detached copy of the epi data (e.g., new
EpiDataDto(copy constructor or clone) or build a new EpiDataDto from
caze.getEpiData()), call includeExposureDates(...) on that copy, and pass the
copy to EpiDataForm.setValue(...) so the persisted caze.getEpiData() is not
mutated by the UI; alternatively move the exposure-date derivation into the
backend read/save path used by the CaseController.
- Around line 1443-1444: The null check for the boxed Integer returned by
diseaseConfigurationDto.getMaxIncubationPeriod() must be performed before any
numeric comparison to avoid auto-unboxing NPE; update the conditional in
CaseController (where getMaxIncubationPeriod() is used) to check for null first
(e.g., if (diseaseConfigurationDto.getMaxIncubationPeriod() == null ||
diseaseConfigurationDto.getMaxIncubationPeriod() == 0) return;) or use
Objects.equals(Integer.valueOf(0),
diseaseConfigurationDto.getMaxIncubationPeriod()) to safely compare to zero.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java`:
- Around line 100-105: The branch in CaseSymptomSideViewComponent that handles
String sourceFieldObj should not skip updates when componentMap already contains
the key; remove the !componentMap.containsKey(...) gate and instead, for
sourceField.getId() in complicatedSymptoms, check
componentMap.get(sourceField.getId())—if it's a Label update its text to
sourceField.getValue().toString(), otherwise create a new Label and put it into
componentMap; ensure you still only act when sourceFieldObj is a non-blank
String to avoid overwriting with empty values.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`:
- Around line 136-137: The fieldsList used to build the disabled/unbound set in
setInaccessible() is missing the MALARIA_INFECTED_YEAR constant, so add
MALARIA_INFECTED_YEAR to the fieldsList declaration alongside
RECURRENT_BRONCHIOLITIS and MALARIA (i.e., include MALARIA_INFECTED_YEAR in the
same array/collection initialization) so that setInaccessible() will properly
disable and unbind that field.
- Around line 307-330: The visibility/access initialization calls
initializeVisibilitiesAndAllowedVisibilities() and
initializeAccessAndAllowedAccesses() are executed before the
MALARIA_INFECTED_YEAR field is created, which can skip enforcing field-level
rules; move those two initialization calls to after the code that creates and
configures the malaria infected year components (the addField call that returns
malInfectedYearCB, the malariaInfectedYearLayout setup, and the
FieldHelper.setVisibleWhen call) so that the new field is present when
visibilities/accesses are initialized; ensure
initializeVisibilitiesAndAllowedVisibilities() and
initializeAccessAndAllowedAccesses() run once after creating
MALARIA_INFECTED_YEAR (and any similar dynamic fields) to enforce correct
visibility/access.

---

Outside diff comments:
In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`:
- Around line 1135-1162: The disease change listener on diseaseField doesn't
invoke the visibility BiConsumers updateSerotypeField and updateSpecieField, so
update their visibility when the disease changes: inside the ValueChangeListener
(the lambda registered on diseaseField) after setting disease and after calling
FieldHelper.updateItems for seroTypeField and specieField, call
updateSerotypeField.accept(disease) and updateSpecieField.accept(disease) (or
the appropriate BiConsumer signatures) so serotype and specie visibility updates
immediately on disease change; ensure the calls are placed alongside the
existing FieldHelper.updateItems calls and before any early returns.

---

Minor comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java`:
- Around line 328-329: The field retestRequested is declared as a boxed Boolean
with default false but elsewhere (setter/getRetestRequested methods) allow null,
reintroducing tri-state; change the field to primitive boolean (retestRequested)
and update its accessor methods (getRetestRequested / setRetestRequested or
isRetestRequested) and any places that accept/assign null to use primitive
boolean (or treat null as false) so the property can never be null; ensure
serialization/deserialization and any callers are adjusted to pass a boolean
instead of null.

In `@sormas-api/src/main/resources/enum.properties`:
- Around line 1199-1203: The caption for the enum key PathogenTestType.LAMP uses
"Lamp" but should be the uppercase acronym "LAMP"; update the value for
PathogenTestType.LAMP in enum.properties from "Lamp" to "LAMP" to match the
lab-test acronym style and maintain consistency with other test-type captions.

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Line 15496: Fix the typo in the schema version comment for the INSERT INTO
schema_version row (the VALUES entry for version_number 615): change the string
'#13801, `#13814` - Malaria and Dengue sampel changes' to '#13801, `#13814` -
Malaria and Dengue sample changes' so the comment text for that INSERT reflects
the correct spelling.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java`:
- Around line 84-85: The second fluidRowLocs invocation currently passes
EpiDataDto.CASE_IMPORTED_STATUS
(fluidRowLocs(6,EpiDataDto.CASE_IMPORTED_STATUS,6,"")), but that field is
already rendered in the conclusion row below; remove the duplicate by replacing
EpiDataDto.CASE_IMPORTED_STATUS with an empty slot (e.g. "") or otherwise
dropping that parameter so the call does not render CASE_IMPORTED_STATUS here;
update the fluidRowLocs call in EpiDataForm to no longer reference
EpiDataDto.CASE_IMPORTED_STATUS.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`:
- Line 176: In PathogenTestForm (class PathogenTestForm) the inline formatter
region was never closed: replace the second occurrence of the comment marker
currently written as //@formatter:off with //@formatter:on to close the
formatter-off started earlier (the pair around the block beginning at line 147);
update the comment so formatter directives are matched (ensure only the trailing
comment near the end of the hand-formatted block uses //@formatter:on).

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/sampleLink/SampleListEntry.java`:
- Around line 163-170: The measles branch currently ignores the allowed
test-type list and always uses latestTest.getGenoType(); modify the
Disease.MEASLES case to first check
PathogenTestListEntry.VARIANT_MAP.get(latestTest.getTestedDisease()).stream().anyMatch(latestTest.getTestType()::equals)
(same pattern as the MALARIA and DENGUE branches) and only then set variant =
StringUtils.abbreviate((latestTest.getGenoType() != null ?
latestTest.getGenoType().toString() : ""), 125); otherwise leave variant
unset/null.

---

Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java`:
- Around line 294-300: In PathogenTestFacadeEjb where you set the serotype
(inside the block guarded by StringUtils.isNotBlank(source.getSerotypeText())),
remove the redundant null check and the unnecessary .toString() call; call
Serotype.fromString(source.getSerotypeText()) directly when setting
target.setSerotype(...) (leave the else branch
target.setSerotype(source.getSerotype()) and the subsequent
target.setSerotypeText(source.getSerotypeText()) unchanged).

In `@sormas-backend/src/main/resources/sql/sormas_schema.sql`:
- Around line 15475-15479: The ALTER TABLE statements on table pathogentest
introduce mixed camelCase and lowercase column names; rename them to a
consistent lowercase_snake_case convention (or match the existing lowercase
pattern) so Java entity mappings remain predictable — replace antibodyTitre,
performedByReferenceLaboratory, retestRequested, resultdetails, specietext with
antibody_titre, performed_by_reference_laboratory, retest_requested,
result_details, species_text (and apply the same renaming in the subsequent
related statements at the other block referenced: 15488-15492), ensuring
defaults and boolean types are preserved and update any corresponding Java
entity/ORM mappings to use the new column names.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`:
- Around line 520-523: In PathogenTestForm change the initial visibility of the
genotype fields so they don't flash before dependency logic runs: set
genoTypingCB and genoTypingResultTextTF to not visible on creation (replace
setVisible(true) with setVisible(false)) so the conditional visibility
controlled by cryptoGenoTypingDependencies (and any similar dependency methods)
determines when they become visible.
- Line 611: Remove the stale commented-out line that references the old
SPECIE_VISIBILITY_CONDITIONS to avoid confusion: delete the comment "//
FieldHelper.setVisibleWhen(getFieldGroup(), PathogenTestDto.SPECIE,
SPECIE_VISIBILITY_CONDITIONS, true);" from PathogenTestForm.java since the code
now uses SPECIE_VISIBILITY_MAP with a BiConsumer-based approach; ensure no other
references to SPECIE_VISIBILITY_CONDITIONS remain and confirm behavior relies on
SPECIE_VISIBILITY_MAP and its consumer logic for PathogenTestDto.SPECIE
visibility.
- Around line 1293-1300: Remove the leftover commented-out call to
FieldHelper.setVisibleWhen inside PathogenTestForm (the commented line
referencing PathogenTestDto.SEROTYPE) to clean up the code; keep the active
visibility rules for PathogenTestDto.SEROTYPE_TEXT and
PathogenTestDto.SPECIE_TEXT intact and ensure no other logic depended on that
commented invocation (search for FieldHelper.setVisibleWhen and the symbols
PathogenTestDto.SEROTYPE, SEROTYPE_VISIBILITY_MAP to confirm).

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`:
- Around line 154-159: In PathogenTestListEntry, the membership checks against
VARIANT_MAP currently use stream().anyMatch(testType::equals) for MALARIA and
DENGUE; replace those with the simpler
VARIANT_MAP.get(pathogenTest.getTestedDisease()).contains(testType) to match the
style used elsewhere (e.g., the check on line 141) so all variant membership
checks are consistent and clearer.
- Around line 56-68: Replace the double-brace anonymous-map initialization for
VARIANT_MAP with an explicit immutable construction using Map.of(...) and
List.of(...) to avoid creating an anonymous inner class; specifically, in
PathogenTestListEntry change the public static final Map<Disease,
List<PathogenTestType>> VARIANT_MAP declaration to use Map.of(...) with each
Disease mapped to a List.of(...) of PathogenTestType (keeping the same Disease
keys: MALARIA, DENGUE, MEASLES, INVASIVE_PNEUMOCOCCAL_INFECTION, TUBERCULOSIS)
so the map and lists are truly unmodifiable and no anonymous inner class is
created.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6000b50a-8495-46ae-92ae-334eee6d733d

📥 Commits

Reviewing files that changed from the base of the PR and between 2100265 and cd45796.

📒 Files selected for processing (39)
  • sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/HealthConditionsDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java
  • sormas-api/src/main/java/de/symeda/sormas/api/epidata/DiseaseTransmission.java
  • sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/epipulse/EpipulseDiseaseExportEntryDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/epipulse/EpipulseLaboratoryMapper.java
  • sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/labmessage/TestReportDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/ExternalMessageMapper.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoType.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenSpecie.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleListEntryDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/Serotype.java
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java
  • sormas-api/src/main/resources/captions.properties
  • sormas-api/src/main/resources/enum.properties
  • sormas-api/src/main/resources/strings.properties
  • sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditions.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/epipulse/strategy/MeaslesExportStrategy.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/TestReport.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/TestReportFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java
  • sormas-backend/src/main/resources/sql/sormas_schema.sql
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/sampleLink/SampleListEntry.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java

Comment on lines +1397 to +1409
EpiDataDto epiDataDto = caze.getEpiData();
// Exposure start date and end date should be calculated based on symptom onsetDate and incubation start periods
Date symptomOnsetDate = caze.getSymptoms().getOnsetDate();

includeExposureDates(symptomOnsetDate, epiDataDto, caze.getDisease());
EpiDataForm epiDataForm = new EpiDataForm(
caze.getDisease(),
CaseDataDto.class,
caze.isPseudonymized(),
caze.isInJurisdiction(),
sourceContactsToggleCallback,
isEditAllowed);
epiDataForm.setValue(caze.getEpiData());
epiDataForm.setValue(epiDataDto);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't persist UI-derived exposure dates from the live DTO.

epiDataDto points to caze.getEpiData(), so includeExposureDates(...) mutates the same object that later gets saved on any epi-data edit. That makes these dates depend on whether the tab was opened and can leave stale values behind when onset date or incubation settings change. Compute them on a detached copy for display, or move the derivation into a shared backend read/save path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java` around
lines 1397 - 1409, The code mutates the live DTO by calling
includeExposureDates(symptomOnsetDate, epiDataDto, caze.getDisease()) on
epiDataDto which is caze.getEpiData(), causing UI-only derived exposure dates to
be persisted; to fix, create a detached copy of the epi data (e.g., new
EpiDataDto(copy constructor or clone) or build a new EpiDataDto from
caze.getEpiData()), call includeExposureDates(...) on that copy, and pass the
copy to EpiDataForm.setValue(...) so the persisted caze.getEpiData() is not
mutated by the UI; alternatively move the exposure-date derivation into the
backend read/save path used by the CaseController.

Comment on lines +136 to +137
RECURRENT_BRONCHIOLITIS,
MALARIA);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

MALARIA_INFECTED_YEAR is missing from fieldsList, affecting inaccessible mode cleanup.

setInaccessible() builds its disabled/unbound field set from fieldsList (Line 392). Since MALARIA_INFECTED_YEAR isn’t included at Lines 136-137, that field may remain visible/bound when the form is set inaccessible.

Suggested fix
 		VACCINATED_AGAINST_MOSQUITO_BORNE_VIRUSES,
 		RECURRENT_BRONCHIOLITIS,
-		MALARIA);
+		MALARIA,
+		MALARIA_INFECTED_YEAR);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RECURRENT_BRONCHIOLITIS,
MALARIA);
VACCINATED_AGAINST_MOSQUITO_BORNE_VIRUSES,
RECURRENT_BRONCHIOLITIS,
MALARIA,
MALARIA_INFECTED_YEAR);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`
around lines 136 - 137, The fieldsList used to build the disabled/unbound set in
setInaccessible() is missing the MALARIA_INFECTED_YEAR constant, so add
MALARIA_INFECTED_YEAR to the fieldsList declaration alongside
RECURRENT_BRONCHIOLITIS and MALARIA (i.e., include MALARIA_INFECTED_YEAR in the
same array/collection initialization) so that setInaccessible() will properly
disable and unbind that field.

Comment on lines 307 to +330
initializeVisibilitiesAndAllowedVisibilities();
initializeAccessAndAllowedAccesses();

if (isVisibleAllowed(MALARIA)) {
// Malaria infected year visibility.
CustomLayout malariaInfectedYearLayout = new CustomLayout();
malariaInfectedYearLayout.setTemplateContents(MALARIA_YEAR_LAYOUT);

// infected year label
Label lblInfectedYear = new Label(I18nProperties.getCaption(Captions.HealthConditions_malariaInfectedYear));
malariaInfectedYearLayout.addComponent(lblInfectedYear, "LBL_MALARIA_INFECTED_YEAR");
getContent().addComponent(malariaInfectedYearLayout, "MALARIA_INFECTED_YEAR_LAYOUT");

// infection year combobox
ComboBox malInfectedYearCB = addField(malariaInfectedYearLayout, MALARIA_INFECTED_YEAR, ComboBox.class);
malInfectedYearCB.setInputPrompt(I18nProperties.getString(Strings.year));
malInfectedYearCB.setNullSelectionAllowed(true);
malInfectedYearCB.setCaption(null);
malInfectedYearCB.addItems(DateHelper.getYearsToNow());
malInfectedYearCB.setItemCaptionMode(AbstractSelect.ItemCaptionMode.ID_TOSTRING);
malariaInfectedYearLayout.addComponent(malInfectedYearCB, MALARIA_INFECTED_YEAR);

FieldHelper.setVisibleWhen(getFieldGroup(), Arrays.asList(MALARIA_INFECTED_YEAR), MALARIA, Arrays.asList(YesNoUnknown.YES), true);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Initialize visibilities/access after adding MALARIA_INFECTED_YEAR.

At Line 307 and Line 308, visibility/access initialization runs before the field is created at Line 321. This can bypass normal field-level visibility/access enforcement for the new malaria year field.

Suggested fix
-		initializeVisibilitiesAndAllowedVisibilities();
-		initializeAccessAndAllowedAccesses();
-
-		if (isVisibleAllowed(MALARIA)) {
+		if (isVisibleAllowed(MALARIA) && isVisibleAllowed(MALARIA_INFECTED_YEAR)) {
 			// Malaria infected year visibility.
 			CustomLayout malariaInfectedYearLayout = new CustomLayout();
 			malariaInfectedYearLayout.setTemplateContents(MALARIA_YEAR_LAYOUT);
@@
 			FieldHelper.setVisibleWhen(getFieldGroup(), Arrays.asList(MALARIA_INFECTED_YEAR), MALARIA, Arrays.asList(YesNoUnknown.YES), true);
 		}
+
+		initializeVisibilitiesAndAllowedVisibilities();
+		initializeAccessAndAllowedAccesses();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/HealthConditionsForm.java`
around lines 307 - 330, The visibility/access initialization calls
initializeVisibilitiesAndAllowedVisibilities() and
initializeAccessAndAllowedAccesses() are executed before the
MALARIA_INFECTED_YEAR field is created, which can skip enforcing field-level
rules; move those two initialization calls to after the code that creates and
configures the malaria infected year components (the addField call that returns
malInfectedYearCB, the malariaInfectedYearLayout setup, and the
FieldHelper.setVisibleWhen call) so that the new field is present when
visibilities/accesses are initialized; ensure
initializeVisibilitiesAndAllowedVisibilities() and
initializeAccessAndAllowedAccesses() run once after creating
MALARIA_INFECTED_YEAR (and any similar dynamic fields) to enforce correct
visibility/access.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java`:
- Around line 168-170: The serotype field in PathogenTestDto is too narrow
(typed as Serotype) and loses non-dengue values; change the field to a generic
String (e.g., replace private Serotype serotype with private String serotype)
and add the same `@Size`(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message =
Validations.textTooLong) validation as used for serotypeText, update the
corresponding getter/setter and any JSON/serialization annotations, and adjust
callers (including PathogenTestForm.SEROTYPE_VISIBILITY_MAP and any code
handling Disease.INVASIVE_PNEUMOCOCCAL_INFECTION) to treat serotype as a raw
string value so raw/non-dengue serotypes are preserved.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java`:
- Around line 1440-1442: The current check in CaseController using
!diseaseConfigurationDto.getIncubationPeriodEnabled() can NPE when
getIncubationPeriodEnabled() returns null; change the null-unsafe negation to a
null-safe comparison such as using
Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled()) (e.g.,
if (!Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled()))
return;), or explicitly handle null (check for null first) so
DiseaseConfigurationDto.getIncubationPeriodEnabled() is never auto-unboxed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`:
- Around line 593-598: PERFORMED_BY_REFERENCE_LABORATORY and RETEST_REQUESTED
are currently added unconditionally and thus show for all pathogen tests; update
PathogenTestForm so these fields (added via
addField(PathogenTestDto.PERFORMED_BY_REFERENCE_LABORATORY,
NullableOptionGroup.class) and addField(PathogenTestDto.RETEST_REQUESTED,
NullableOptionGroup.class)) are only visible for the malaria/dengue
workflows—e.g. after adding the fields, call setVisible(false) by default and
add the same disease-gating logic used for RESULT_DETAILS (or use the form's
pathogen/disease getter to setVisible(true) when pathogen type indicates malaria
or dengue), ensuring the visibility check uses the DTO/pathogen value in
PathogenTestForm rather than leaving them global.
- Around line 1227-1230: When toggling visibility for resultDetailsField and
seroTypeMetCB based on disease/testType, also clear their bound values when they
are hidden to avoid saving stale data; update the logic around
resultDetailsField.setVisible(...) and seroTypeMetCB.setVisible(...) so that if
visibility is set to false you call the respective clear/reset method on the
underlying model/binder (e.g., null or empty value via the field's setter or
binder) for resultDetails and serotyping method, using the same identifiers
resultDetailsField, seroTypeMetCB, testType and disease/PathogenTestType/Disease
to locate the code.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`:
- Around line 57-68: The VARIANT_MAP entry for Disease.MALARIA is missing
several PathogenTestType values that PathogenTestForm.SPECIE_VISIBILITY_MAP
treats as specie-driven; update the Disease.MALARIA list inside VARIANT_MAP to
include PathogenTestType.ANTIGEN_DETECTION,
PathogenTestType.ENZYME_LINKED_IMMUNOSORBENT_ASSAY and the OTHER_* malaria test
types (the exact OTHER_* enum names used elsewhere) so the map aligns with
PathogenTestForm.SPECIE_VISIBILITY_MAP and those records will render
species-specific results; keep the list wrapped with
Collections.unmodifiableList and maintain the same construction pattern used for
the other disease entries.
- Around line 153-159: In PathogenTestListEntry where resultText is set for
genoType/specie/serotype, update the logic to use the free-text companion fields
when the enum value is OTHER instead of rendering the literal "Other": for the
genoType branch use pathogenTest.getGenoTypeText() when
pathogenTest.getGenoType() == OTHER (otherwise use
pathogenTest.getGenoType().toString()), for the specie branch use
pathogenTest.getSpecieText() when pathogenTest.getSpecie() == OTHER (otherwise
use pathogenTest.getSpecie().toString()), and for the serotype branch use
pathogenTest.getSerotypeText() when pathogenTest.getSerotype() == OTHER
(otherwise use pathogenTest.getSerotype().toString()); keep the existing
VARIANT_MAP and testType checks and still pass the chosen text through
StringUtils.abbreviate before assigning to resultText.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0dc46871-42a0-4e19-87b8-edff2ff91873

📥 Commits

Reviewing files that changed from the base of the PR and between cd45796 and 72886de.

📒 Files selected for processing (9)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenSpecie.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/Serotype.java
  • sormas-api/src/main/resources/enum.properties
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseSymptomSideViewComponent.java
  • sormas-api/src/main/resources/enum.properties

Comment on lines +168 to +170
private Serotype serotype;
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String serotype;
private String serotypeText;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

serotype is now too narrow for the shared DTO contract.

This field is still reused outside dengue — PathogenTestForm.SEROTYPE_VISIBILITY_MAP still exposes it for Disease.INVASIVE_PNEUMOCOCCAL_INFECTION — but the backing enum only contains DENV_1..4/OTHER. Non-dengue or raw serotype values can now only degrade to OTHER, which loses the actual result unless every caller also keeps serotypeText in sync.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java`
around lines 168 - 170, The serotype field in PathogenTestDto is too narrow
(typed as Serotype) and loses non-dengue values; change the field to a generic
String (e.g., replace private Serotype serotype with private String serotype)
and add the same `@Size`(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message =
Validations.textTooLong) validation as used for serotypeText, update the
corresponding getter/setter and any JSON/serialization annotations, and adjust
callers (including PathogenTestForm.SEROTYPE_VISIBILITY_MAP and any code
handling Disease.INVASIVE_PNEUMOCOCCAL_INFECTION) to treat serotype as a raw
string value so raw/non-dengue serotypes are preserved.

Comment on lines +1440 to +1442
if (!diseaseConfigurationDto.getIncubationPeriodEnabled()) {
return;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the return type of getIncubationPeriodEnabled()
ast-grep --pattern $'class DiseaseConfigurationDto {
  $$$
  getIncubationPeriodEnabled() {
    $$$
  }
  $$$
}'

# Alternative: search for the field and getter declaration
rg -n -A3 'incubationPeriodEnabled' --glob '**/DiseaseConfigurationDto.java'

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 2143


Potential NPE if getIncubationPeriodEnabled() returns null.

The field incubationPeriodEnabled is declared as Boolean (wrapper type) in DiseaseConfigurationDto. When the getter returns null and the code applies the ! operator, it triggers auto-unboxing and throws a NullPointerException.

Consider using a null-safe comparison:

Suggested fix
-		if (!diseaseConfigurationDto.getIncubationPeriodEnabled()) {
+		if (!Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled())) {
 			return;
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!diseaseConfigurationDto.getIncubationPeriodEnabled()) {
return;
}
if (!Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled())) {
return;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java` around
lines 1440 - 1442, The current check in CaseController using
!diseaseConfigurationDto.getIncubationPeriodEnabled() can NPE when
getIncubationPeriodEnabled() returns null; change the null-unsafe negation to a
null-safe comparison such as using
Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled()) (e.g.,
if (!Boolean.TRUE.equals(diseaseConfigurationDto.getIncubationPeriodEnabled()))
return;), or explicitly handle null (check for null first) so
DiseaseConfigurationDto.getIncubationPeriodEnabled() is never auto-unboxed.

Comment on lines +593 to +598
// Malaria and Dengue fields
addField(PathogenTestDto.ANTIBODY_TITRE, TextField.class);
addField(PathogenTestDto.PERFORMED_BY_REFERENCE_LABORATORY, NullableOptionGroup.class);
addField(PathogenTestDto.RETEST_REQUESTED, NullableOptionGroup.class);
Field<?> resultDetailsField = addField(PathogenTestDto.RESULT_DETAILS);
resultDetailsField.setVisible(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

These new controls are globally visible.

Only resultDetailsField is hidden here. PERFORMED_BY_REFERENCE_LABORATORY and RETEST_REQUESTED have no disease gating in the DTO or the form, so they render on every pathogen-test form instead of just the malaria/dengue workflows introduced by this PR.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`
around lines 593 - 598, PERFORMED_BY_REFERENCE_LABORATORY and RETEST_REQUESTED
are currently added unconditionally and thus show for all pathogen tests; update
PathogenTestForm so these fields (added via
addField(PathogenTestDto.PERFORMED_BY_REFERENCE_LABORATORY,
NullableOptionGroup.class) and addField(PathogenTestDto.RETEST_REQUESTED,
NullableOptionGroup.class)) are only visible for the malaria/dengue
workflows—e.g. after adding the fields, call setVisible(false) by default and
add the same disease-gating logic used for RESULT_DETAILS (or use the form's
pathogen/disease getter to setVisible(true) when pathogen type indicates malaria
or dengue), ensuring the visibility check uses the DTO/pathogen value in
PathogenTestForm rather than leaving them global.

Comment on lines +1227 to +1230
// Result details should be visible for Malaria and test-types with PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.Q_PCR
resultDetailsField.setVisible(
Disease.MALARIA == disease && Arrays.asList(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.Q_PCR).contains(testType));
seroTypeMetCB.setVisible(testType == PathogenTestType.SEROGROUPING && Disease.INVASIVE_PNEUMOCOCCAL_INFECTION == disease);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clear hidden values when these fields turn off.

setVisible(...) hides the widgets but leaves their bound values untouched. After switching test type, stale malaria resultDetails or pneumococcal serotyping-method data can still be saved on a test that no longer supports them.

💡 Proposed fix
-				resultDetailsField.setVisible(
-					Disease.MALARIA == disease && Arrays.asList(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.Q_PCR).contains(testType));
-				seroTypeMetCB.setVisible(testType == PathogenTestType.SEROGROUPING && Disease.INVASIVE_PNEUMOCOCCAL_INFECTION == disease);
+				boolean showResultDetails =
+					Disease.MALARIA == disease && Arrays.asList(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.Q_PCR).contains(testType);
+				if (!showResultDetails) {
+					resultDetailsField.clear();
+				}
+				resultDetailsField.setVisible(showResultDetails);
+
+				boolean showSeroTypingMethod =
+					testType == PathogenTestType.SEROGROUPING && Disease.INVASIVE_PNEUMOCOCCAL_INFECTION == disease;
+				if (!showSeroTypingMethod) {
+					seroTypeMetCB.clear();
+					getField(PathogenTestDto.SERO_TYPING_METHOD_TEXT).clear();
+				}
+				seroTypeMetCB.setVisible(showSeroTypingMethod);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java`
around lines 1227 - 1230, When toggling visibility for resultDetailsField and
seroTypeMetCB based on disease/testType, also clear their bound values when they
are hidden to avoid saving stale data; update the logic around
resultDetailsField.setVisible(...) and seroTypeMetCB.setVisible(...) so that if
visibility is set to false you call the respective clear/reset method on the
underlying model/binder (e.g., null or empty value via the field's setter or
binder) for resultDetails and serotyping method, using the same identifiers
resultDetailsField, seroTypeMetCB, testType and disease/PathogenTestType/Disease
to locate the code.

Comment on lines +57 to +68
public static final Map<Disease, List<PathogenTestType>> VARIANT_MAP = Collections.unmodifiableMap(new HashMap<>() {
{
put(Disease.MALARIA, Collections.unmodifiableList(Arrays.asList(PathogenTestType.THIN_BLOOD_SMEAR, PathogenTestType.RAPID_TEST, PathogenTestType.PCR_RT_PCR,
PathogenTestType.Q_PCR, PathogenTestType.LAMP, PathogenTestType.INDIRECT_FLUORESCENT_ANTIBODY)));
put(Disease.DENGUE, Collections.unmodifiableList(Arrays.asList(PathogenTestType.NAAT, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestType.PCR_RT_PCR)));
put(Disease.MEASLES, Collections.unmodifiableList(Arrays.asList(PathogenTestType.GENOTYPING)));
put(Disease.INVASIVE_PNEUMOCOCCAL_INFECTION, Collections.unmodifiableList(Arrays.asList(PathogenTestType.SEROGROUPING, PathogenTestType.MULTILOCUS_SEQUENCE_TYPING,
PathogenTestType.SLIDE_AGGLUTINATION,PathogenTestType.WHOLE_GENOME_SEQUENCING, PathogenTestType.SEQUENCING)));
put(Disease.TUBERCULOSIS, Collections.unmodifiableList(Arrays.asList(PathogenTestType.MICROSCOPY, PathogenTestType.BEIJINGGENOTYPING,
PathogenTestType.SPOLIGOTYPING, PathogenTestType.MIRU_PATTERN_CODE)));
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The malaria variant map already diverges from the form rules.

PathogenTestForm.SPECIE_VISIBILITY_MAP also treats ANTIGEN_DETECTION, ENZYME_LINKED_IMMUNOSORBENT_ASSAY, and the OTHER_* malaria test types as specie-driven, but this map omits them. Those records will fall back to the generic test result in list entries even when a species was captured.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`
around lines 57 - 68, The VARIANT_MAP entry for Disease.MALARIA is missing
several PathogenTestType values that PathogenTestForm.SPECIE_VISIBILITY_MAP
treats as specie-driven; update the Disease.MALARIA list inside VARIANT_MAP to
include PathogenTestType.ANTIGEN_DETECTION,
PathogenTestType.ENZYME_LINKED_IMMUNOSORBENT_ASSAY and the OTHER_* malaria test
types (the exact OTHER_* enum names used elsewhere) so the map aligns with
PathogenTestForm.SPECIE_VISIBILITY_MAP and those records will render
species-specific results; keep the list wrapped with
Collections.unmodifiableList and maintain the same construction pattern used for
the other disease entries.

Comment on lines +153 to +159
resultText = StringUtils.abbreviate((pathogenTest.getGenoType() != null ? pathogenTest.getGenoType().toString() : ""), 125);
} else if (pathogenTest.getTestedDisease() == Disease.MALARIA
&& VARIANT_MAP.get(pathogenTest.getTestedDisease()).stream().anyMatch(testType::equals)) {
resultText = StringUtils.abbreviate((pathogenTest.getSpecie() != null ? pathogenTest.getSpecie().toString() : ""), 125);
} else if (pathogenTest.getTestedDisease() == Disease.DENGUE
&& VARIANT_MAP.get(pathogenTest.getTestedDisease()).stream().anyMatch(testType::equals)) {
resultText = StringUtils.abbreviate((pathogenTest.getSerotype() != null ? pathogenTest.getSerotype().toString() : ""), 125);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the free-text companions instead of rendering literal Other.

These new branches ignore genoTypeText, specieText, and serotypeText. When the selected enum is OTHER, list entries will show just Other and hide the actual value the user or importer entered.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java`
around lines 153 - 159, In PathogenTestListEntry where resultText is set for
genoType/specie/serotype, update the logic to use the free-text companion fields
when the enum value is OTHER instead of rendering the literal "Other": for the
genoType branch use pathogenTest.getGenoTypeText() when
pathogenTest.getGenoType() == OTHER (otherwise use
pathogenTest.getGenoType().toString()), for the specie branch use
pathogenTest.getSpecieText() when pathogenTest.getSpecie() == OTHER (otherwise
use pathogenTest.getSpecie().toString()), and for the serotype branch use
pathogenTest.getSerotypeText() when pathogenTest.getSerotype() == OTHER
(otherwise use pathogenTest.getSerotype().toString()); keep the existing
VARIANT_MAP and testType checks and still pass the chosen text through
StringUtils.abbreviate before assigning to resultText.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dengue - Enhance Sample form

1 participant