Skip to content

Commit 01c1335

Browse files
authored
Merge pull request #13987 from SORMAS-Foundation/feature/13948-lab-results-view
Adds Lab results (tests/samples/AST) tab to the cases view
2 parents bffe2f2 + 9853df3 commit 01c1335

13 files changed

Lines changed: 679 additions & 1 deletion

File tree

sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase {
137137
public static final String EPI_DATA = "epiData";
138138
public static final String THERAPY = "therapy";
139139
public static final String CLINICAL_COURSE = "clinicalCourse";
140+
public static final String LAB_RESULTS = "labResults";
140141
public static final String MATERNAL_HISTORY = "maternalHistory";
141142
public static final String PORT_HEALTH_INFO = "portHealthInfo";
142143
public static final String HEALTH_CONDITIONS = "healthConditions";
@@ -166,6 +167,9 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase {
166167
public static final String POINT_OF_ENTRY = "pointOfEntry";
167168
public static final String POINT_OF_ENTRY_DETAILS = "pointOfEntryDetails";
168169
public static final String ADDITIONAL_DETAILS = "additionalDetails";
170+
public static final String DATE_OTHER = "dateOther";
171+
public static final String DATE_OTHER_DETAILS = "dateOtherDetails";
172+
public static final String EXTERNAL_COMMENTS = "externalComments";
169173
public static final String EXTERNAL_ID = "externalID";
170174
public static final String EXTERNAL_TOKEN = "externalToken";
171175
public static final String INTERNAL_TOKEN = "internalToken";
@@ -484,6 +488,15 @@ public class CaseDataDto extends SormasToSormasShareableDto implements IsCase {
484488
@SensitiveData
485489
@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
486490
private String additionalDetails;
491+
@S2SIgnoreProperty(configProperty = SormasToSormasConfig.SORMAS2SORMAS_IGNORE_ADDITIONAL_DETAILS)
492+
private Date dateOther;
493+
@S2SIgnoreProperty(configProperty = SormasToSormasConfig.SORMAS2SORMAS_IGNORE_ADDITIONAL_DETAILS)
494+
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
495+
private String dateOtherDetails;
496+
@S2SIgnoreProperty(configProperty = SormasToSormasConfig.SORMAS2SORMAS_IGNORE_ADDITIONAL_DETAILS)
497+
@SensitiveData
498+
@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
499+
private String externalComments;
487500
@HideForCountriesExcept(countries = {
488501
COUNTRY_CODE_GERMANY,
489502
COUNTRY_CODE_SWITZERLAND })
@@ -1383,6 +1396,30 @@ public void setAdditionalDetails(String additionalDetails) {
13831396
this.additionalDetails = additionalDetails;
13841397
}
13851398

1399+
public Date getDateOther() {
1400+
return dateOther;
1401+
}
1402+
1403+
public void setDateOther(Date dateOther) {
1404+
this.dateOther = dateOther;
1405+
}
1406+
1407+
public String getDateOtherDetails() {
1408+
return dateOtherDetails;
1409+
}
1410+
1411+
public void setDateOtherDetails(String dateOtherDetails) {
1412+
this.dateOtherDetails = dateOtherDetails;
1413+
}
1414+
1415+
public String getExternalComments() {
1416+
return externalComments;
1417+
}
1418+
1419+
public void setExternalComments(String externalComments) {
1420+
this.externalComments = externalComments;
1421+
}
1422+
13861423
public String getExternalID() {
13871424
return externalID;
13881425
}

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ public interface Captions {
682682
String CaseData_contactTracingFirstContactDate = "CaseData.contactTracingFirstContactDate";
683683
String CaseData_contactTracingFirstContactType = "CaseData.contactTracingFirstContactType";
684684
String CaseData_creationDate = "CaseData.creationDate";
685+
String CaseData_dateOther = "CaseData.dateOther";
686+
String CaseData_dateOtherDetails = "CaseData.dateOtherDetails";
685687
String CaseData_deletionReason = "CaseData.deletionReason";
686688
String CaseData_dengueFeverType = "CaseData.dengueFeverType";
687689
String CaseData_department = "CaseData.department";
@@ -700,6 +702,7 @@ public interface Captions {
700702
String CaseData_epidNumber = "CaseData.epidNumber";
701703
String CaseData_eventCount = "CaseData.eventCount";
702704
String CaseData_expectedFollowUpUntil = "CaseData.expectedFollowUpUntil";
705+
String CaseData_externalComments = "CaseData.externalComments";
703706
String CaseData_externalData = "CaseData.externalData";
704707
String CaseData_externalID = "CaseData.externalID";
705708
String CaseData_externalToken = "CaseData.externalToken";
@@ -720,6 +723,7 @@ public interface Captions {
720723
String CaseData_investigatedDate = "CaseData.investigatedDate";
721724
String CaseData_investigationStatus = "CaseData.investigationStatus";
722725
String CaseData_laboratoryDiagnosticConfirmation = "CaseData.laboratoryDiagnosticConfirmation";
726+
String CaseData_labResults = "CaseData.labResults";
723727
String CaseData_latestEventId = "CaseData.latestEventId";
724728
String CaseData_latestEventStatus = "CaseData.latestEventStatus";
725729
String CaseData_latestEventTitle = "CaseData.latestEventTitle";
@@ -918,6 +922,19 @@ public interface Captions {
918922
String caseImportMergeCase = "caseImportMergeCase";
919923
String caseInfrastructureDataChanged = "caseInfrastructureDataChanged";
920924
String caseJurisdictionType = "caseJurisdictionType";
925+
String caseLabResultsAntibiotic = "caseLabResultsAntibiotic";
926+
String caseLabResultsClinicalInterpretation = "caseLabResultsClinicalInterpretation";
927+
String caseLabResultsComments = "caseLabResultsComments";
928+
String caseLabResultsDateCollected = "caseLabResultsDateCollected";
929+
String caseLabResultsDrugSusceptibilityHeading = "caseLabResultsDrugSusceptibilityHeading";
930+
String caseLabResultsMethod = "caseLabResultsMethod";
931+
String caseLabResultsMicValue = "caseLabResultsMicValue";
932+
String caseLabResultsSample = "caseLabResultsSample";
933+
String caseLabResultsSamplesHeading = "caseLabResultsSamplesHeading";
934+
String caseLabResultsSurveillanceInterpretation = "caseLabResultsSurveillanceInterpretation";
935+
String caseLabResultsTestsHeading = "caseLabResultsTestsHeading";
936+
String caseLabResultsTestsPerformed = "caseLabResultsTestsPerformed";
937+
String caseLabResultsZoneDiameter = "caseLabResultsZoneDiameter";
921938
String caseLinkToSamples = "caseLinkToSamples";
922939
String caseMergeDuplicates = "caseMergeDuplicates";
923940
String caseMinusDays = "caseMinusDays";

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,8 @@ public interface Strings {
11021102
String infoNoAccessToPersonEntities = "infoNoAccessToPersonEntities";
11031103
String infoNoAdditionalTests = "infoNoAdditionalTests";
11041104
String infoNoAefiInvestigations = "infoNoAefiInvestigations";
1105+
String infoNoCaseLabResultsSamples = "infoNoCaseLabResultsSamples";
1106+
String infoNoCaseLabResultsTests = "infoNoCaseLabResultsTests";
11051107
String infoNoCasesFoundStatistics = "infoNoCasesFoundStatistics";
11061108
String infoNoCustomizableEnumTranslations = "infoNoCustomizableEnumTranslations";
11071109
String infoNoCustomizableFieldOptions = "infoNoCustomizableFieldOptions";

sormas-api/src/main/resources/captions.properties

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,19 @@ CampaignFormData.edit=Edit
358358
# CaseData
359359
caseCasesList=Cases list
360360
caseInfrastructureDataChanged=Infrastructure data has changed
361+
caseLabResultsTestsHeading=Tests
362+
caseLabResultsSamplesHeading=Samples
363+
caseLabResultsDrugSusceptibilityHeading=Drug susceptibility tests
364+
caseLabResultsSample=Sample
365+
caseLabResultsDateCollected=Date collected
366+
caseLabResultsTestsPerformed=Tests performed
367+
caseLabResultsAntibiotic=Antibiotic
368+
caseLabResultsMethod=Method
369+
caseLabResultsMicValue=MIC value (mg/l)
370+
caseLabResultsZoneDiameter=Zone (mm)
371+
caseLabResultsClinicalInterpretation=Clinical interpretation
372+
caseLabResultsSurveillanceInterpretation=Surveillance interpretation
373+
caseLabResultsComments=Comments
361374
caseCloneCaseWithNewDisease=Generate new case for
362375
caseContacts=Contacts
363376
caseDocuments=Case Documents
@@ -441,6 +454,8 @@ CaseData.clinicianName=Name of responsible clinician
441454
CaseData.clinicianPhone=Phone number of responsible clinician
442455
CaseData.clinicianEmail=Email address of responsible clinician
443456
CaseData.contactOfficer=Contact officer
457+
CaseData.dateOther=Date other
458+
CaseData.dateOtherDetails=Date other details
444459
CaseData.dengueFeverType=Dengue fever type
445460
CaseData.diseaseVariant=Disease variant
446461
CaseData.diseaseDetails=Disease name
@@ -449,8 +464,10 @@ CaseData.districtLevelDate=Date received at district level
449464
CaseData.doses=How many doses
450465
CaseData.epiData=Epidemiological data
451466
CaseData.epidNumber=EPID number
467+
CaseData.labResults=Laboratory results
452468
CaseData.postMortem=Post Mortem
453469
CaseData.department=Facility Department
470+
CaseData.externalComments=External comments
454471
CaseData.externalID=External ID
455472
CaseData.externalToken=External Token
456473
CaseData.internalToken=Internal Token

sormas-api/src/main/resources/strings.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,8 @@ infoCaseIncidenceNotPossible = The following regions have missing population dat
10371037
infoCaseIncidenceMissingPopulationData = The following regions and/or districts have missing population data:<br/><br/>%s.<br/><br/>Incidence proportion cannot be calculated for these regions and/or districts.
10381038
infoCaseIncidenceIncompatible = No population data is available for communities and facilities. Case incidence cannot be calculated and case counts are displayed instead. If you want to view case incidence, please remove any community and facilitiy filters and groupings.
10391039
infoNoPathogenTests = No pathogen tests have been created for this sample
1040+
infoNoCaseLabResultsTests = No tests have been performed for this case
1041+
infoNoCaseLabResultsSamples = No samples have been collected for this case
10401042
infoPickOrCreateCase = There are existing cases in the database that seem very similar to the one you are about to create. Please have a look at the list of existing cases and verify that the case you want to create is not a duplicate of one of them. If you find a case that is most likely the same as yours, please <b>click on it in the list</b> and confirm.
10411043
infoPickOrCreateCaseNewCase = Newly added case information
10421044
infoPickOrCreateImmunization = The system already contains at least one immunization for %s for this person and means of immunization that overlaps with the specified immunziation period. Please compare the most recent existing immunization with the one you created and decide whether to discard the new immunization, use its information to update the existing one, or create it anyway.

sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ public class Case extends CoreAdo implements IsCase, SormasToSormasShareable, Ha
181181
public static final String POINT_OF_ENTRY_DETAILS = "pointOfEntryDetails";
182182
public static final String COMPLETENESS = "completeness";
183183
public static final String ADDITIONAL_DETAILS = "additionalDetails";
184+
public static final String DATE_OTHER = "dateOther";
185+
public static final String DATE_OTHER_DETAILS = "dateOtherDetails";
186+
public static final String EXTERNAL_COMMENTS = "externalComments";
184187
public static final String EXTERNAL_ID = "externalID";
185188
public static final String EXTERNAL_TOKEN = "externalToken";
186189
public static final String INTERNAL_TOKEN = "internalToken";
@@ -364,6 +367,9 @@ public class Case extends CoreAdo implements IsCase, SormasToSormasShareable, Ha
364367

365368
private Float completeness;
366369
private String additionalDetails;
370+
private Date dateOther;
371+
private String dateOtherDetails;
372+
private String externalComments;
367373
private String externalID;
368374
private String externalToken;
369375
private String internalToken;
@@ -1258,6 +1264,33 @@ public void setAdditionalDetails(String additionalDetails) {
12581264
this.additionalDetails = additionalDetails;
12591265
}
12601266

1267+
@Temporal(TemporalType.TIMESTAMP)
1268+
public Date getDateOther() {
1269+
return dateOther;
1270+
}
1271+
1272+
public void setDateOther(Date dateOther) {
1273+
this.dateOther = dateOther;
1274+
}
1275+
1276+
@Column(length = CHARACTER_LIMIT_DEFAULT)
1277+
public String getDateOtherDetails() {
1278+
return dateOtherDetails;
1279+
}
1280+
1281+
public void setDateOtherDetails(String dateOtherDetails) {
1282+
this.dateOtherDetails = dateOtherDetails;
1283+
}
1284+
1285+
@Column(columnDefinition = "text")
1286+
public String getExternalComments() {
1287+
return externalComments;
1288+
}
1289+
1290+
public void setExternalComments(String externalComments) {
1291+
this.externalComments = externalComments;
1292+
}
1293+
12611294
@Column(length = CHARACTER_LIMIT_DEFAULT)
12621295
public String getExternalID() {
12631296
return externalID;
@@ -1279,7 +1312,7 @@ public String getExternalId() {
12791312

12801313
/**
12811314
* Extra setter for externalID needed to comply with the HasExternalData interface
1282-
*
1315+
*
12831316
* @param externalId
12841317
* the value to be set for externalID
12851318
*/

sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3189,6 +3189,9 @@ public static CaseDataDto toCaseDto(Case source) {
31893189
target.setPointOfEntry(PointOfEntryFacadeEjb.toReferenceDto(source.getPointOfEntry()));
31903190
target.setPointOfEntryDetails(source.getPointOfEntryDetails());
31913191
target.setAdditionalDetails(source.getAdditionalDetails());
3192+
target.setDateOther(source.getDateOther());
3193+
target.setDateOtherDetails(source.getDateOtherDetails());
3194+
target.setExternalComments(source.getExternalComments());
31923195
target.setExternalID(source.getExternalID());
31933196
target.setExternalToken(source.getExternalToken());
31943197
target.setInternalToken(source.getInternalToken());
@@ -3418,6 +3421,9 @@ public Case fillOrBuildEntity(@NotNull CaseDataDto source, Case target, boolean
34183421
target.setPointOfEntry(pointOfEntryService.getByReferenceDto(source.getPointOfEntry()));
34193422
target.setPointOfEntryDetails(source.getPointOfEntryDetails());
34203423
target.setAdditionalDetails(source.getAdditionalDetails());
3424+
target.setDateOther(source.getDateOther());
3425+
target.setDateOtherDetails(source.getDateOtherDetails());
3426+
target.setExternalComments(source.getExternalComments());
34213427
target.setExternalID(source.getExternalID());
34223428
target.setExternalToken(source.getExternalToken());
34233429
target.setInternalToken(source.getInternalToken());

sormas-backend/src/main/resources/sql/sormas_schema.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16295,4 +16295,15 @@ alter table samples_history alter column retestrequested set not null;
1629516295

1629616296
INSERT INTO schema_version (version_number, comment) VALUES (637, 'Reference laboratory + retest indicators on sample #13954 (#13948)');
1629716297

16298+
-- 2026-06-08 Laboratory results tab: date other + external comments on case #13948 (#13955)
16299+
alter table cases add column IF NOT EXISTS dateother timestamp;
16300+
alter table cases add column IF NOT EXISTS dateotherdetails varchar(255);
16301+
alter table cases add column IF NOT EXISTS externalcomments text;
16302+
16303+
alter table cases_history add column IF NOT EXISTS dateother timestamp;
16304+
alter table cases_history add column IF NOT EXISTS dateotherdetails varchar(255);
16305+
alter table cases_history add column IF NOT EXISTS externalcomments text;
16306+
16307+
INSERT INTO schema_version (version_number, comment) VALUES (638, 'Laboratory results tab: dateOther, dateOtherDetails, externalComments on case #13955');
16308+
1629816309
-- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. ***

sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3443,6 +3443,32 @@ public void testBulkUpdateBulkEditDiseaseClearVariantOfChangedDisease() {
34433443
assertThat(caze.getDiseaseVariantDetails(), is(nullValue()));
34443444
}
34453445

3446+
@Test
3447+
public void testLabResultsFieldsRoundTrip() {
3448+
// Guards the hand-written CaseFacadeEjb mapper for the lab-results tab header fields (#13948).
3449+
CaseDataDto caze = creator.createCase(
3450+
surveillanceSupervisor.toReference(),
3451+
creator.createPerson("Lab", "Case").toReference(),
3452+
Disease.EVD,
3453+
CaseClassification.PROBABLE,
3454+
InvestigationStatus.PENDING,
3455+
new Date(),
3456+
rdcf);
3457+
3458+
// Truncate to day granularity so the round-trip assertion is not brittle to sub-second precision
3459+
// differences in DB/JPA timestamp handling.
3460+
Date dateOther = DateHelper.getStartOfDay(new Date());
3461+
caze.setDateOther(dateOther);
3462+
caze.setDateOtherDetails("Sampling visit");
3463+
caze.setExternalComments("Lab sent confirmation");
3464+
getCaseFacade().save(caze);
3465+
3466+
CaseDataDto reloaded = getCaseFacade().getCaseDataByUuid(caze.getUuid());
3467+
assertEquals(dateOther, reloaded.getDateOther());
3468+
assertEquals("Sampling visit", reloaded.getDateOtherDetails());
3469+
assertEquals("Lab sent confirmation", reloaded.getExternalComments());
3470+
}
3471+
34463472
private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ";
34473473
private static final SecureRandom rnd = new SecureRandom();
34483474

sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ public void refreshMenu(SubMenu menu, String params) {
235235
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
236236
params);
237237
}
238+
239+
if (UiUtil.permitted(FeatureType.SAMPLES_LAB, UserRight.SAMPLE_VIEW) && !caze.checkIsUnreferredPortHealthCase()) {
240+
menu.addView(CaseLabResultsView.VIEW_NAME, I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.LAB_RESULTS), params);
241+
}
238242
}
239243
if (FacadeProvider.getDiseaseConfigurationFacade().hasFollowUp(caze.getDisease())
240244
&& UiUtil.permitted(UserRight.CONTACT_VIEW)

0 commit comments

Comments
 (0)