11/*
22 * SORMAS® - Surveillance Outbreak Response Management & Analysis System
3- * Copyright © 2016-2023 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI)
3+ * Copyright © 2016-2026 SORMAS Foundation gGmbH
44 * This program is free software: you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
66 * the Free Software Foundation, either version 3 of the License, or
1515
1616package de .symeda .sormas .api .externalmessage .processing .labmessage ;
1717
18+ import java .util .ArrayList ;
1819import java .util .Date ;
20+ import java .util .List ;
1921
2022import org .slf4j .Logger ;
2123import org .slf4j .LoggerFactory ;
2224
25+ import com .fasterxml .jackson .core .type .TypeReference ;
26+ import com .fasterxml .jackson .databind .ObjectMapper ;
27+
28+ import de .symeda .sormas .api .activityascase .ActivityAsCaseDto ;
29+ import de .symeda .sormas .api .activityascase .ActivityAsCaseType ;
2330import de .symeda .sormas .api .caze .CaseDataDto ;
2431import de .symeda .sormas .api .caze .CaseOutcome ;
2532import de .symeda .sormas .api .caze .CaseSelectionDto ;
2633import de .symeda .sormas .api .caze .InvestigationStatus ;
2734import de .symeda .sormas .api .caze .surveillancereport .SurveillanceReportDto ;
2835import de .symeda .sormas .api .contact .ContactDto ;
2936import de .symeda .sormas .api .contact .SimilarContactDto ;
37+ import de .symeda .sormas .api .epidata .EpiDataDto ;
3038import de .symeda .sormas .api .event .EventDto ;
3139import de .symeda .sormas .api .event .EventParticipantDto ;
3240import de .symeda .sormas .api .event .SimilarEventParticipantDto ;
41+ import de .symeda .sormas .api .exposure .ExposureDto ;
42+ import de .symeda .sormas .api .exposure .ExposureType ;
3343import de .symeda .sormas .api .externalmessage .ExternalMessageDto ;
3444import de .symeda .sormas .api .externalmessage .ExternalMessageStatus ;
3545import de .symeda .sormas .api .externalmessage .processing .AbstractMessageProcessingFlowBase ;
4555import de .symeda .sormas .api .therapy .TreatmentDto ;
4656import de .symeda .sormas .api .user .UserDto ;
4757import de .symeda .sormas .api .utils .DtoCopyHelper ;
58+ import de .symeda .sormas .api .utils .YesNoUnknown ;
4859import de .symeda .sormas .api .utils .dataprocessing .ProcessingResult ;
4960import de .symeda .sormas .api .utils .dataprocessing .flow .FlowThen ;
5061
@@ -231,11 +242,21 @@ protected void postBuildCase(CaseDataDto caseDto, ExternalMessageDto externalMes
231242
232243 postBuildCaseSymptoms (caseDto , externalMessageDto );
233244 postBuildCaseTherapy (caseDto , externalMessageDto );
245+ postBuildActivitiesAsCase (caseDto , externalMessageDto );
246+ postBuildExposure (caseDto , externalMessageDto );
234247
235248 caseDto .setInvestigationStatus (InvestigationStatus .PENDING );
236249 caseDto .setOutcome (CaseOutcome .NO_OUTCOME );
237250 }
238251
252+ /**
253+ * Sets the symptoms for the case from the external message, if present.
254+ *
255+ * @param caseDto
256+ * The case data transfer object to update.
257+ * @param externalMessageDto
258+ * The external message containing symptom data.
259+ */
239260 protected void postBuildCaseSymptoms (CaseDataDto caseDto , ExternalMessageDto externalMessageDto ) {
240261 if (externalMessageDto .getCaseSymptoms () != null ) {
241262 final SymptomsDto symptomsDto = SymptomsDto .build ();
@@ -246,6 +267,14 @@ protected void postBuildCaseSymptoms(CaseDataDto caseDto, ExternalMessageDto ext
246267 }
247268 }
248269
270+ /**
271+ * Sets the therapy information for the case from the external message, if present.
272+ *
273+ * @param caseDto
274+ * The case data transfer object to update.
275+ * @param externalMessageDto
276+ * The external message containing therapy data.
277+ */
249278 protected void postBuildCaseTherapy (CaseDataDto caseDto , ExternalMessageDto externalMessageDto ) {
250279
251280 TherapyDto therapyDto = caseDto .getTherapy ();
@@ -258,6 +287,112 @@ protected void postBuildCaseTherapy(CaseDataDto caseDto, ExternalMessageDto exte
258287
259288 }
260289
290+ /**
291+ * Sets the activities as case for the case from the external message, if present.
292+ * <p>
293+ * This method deserializes the activities as case from a JSON string in the external message
294+ * into a list of {@link ActivityAsCaseDto} objects. Each activity is built and copied, and if
295+ * the activity type is missing, it is set to {@link ActivityAsCaseType#UNKNOWN}.
296+ * If there are activities, the {@code activityAsCaseDetailsKnown} field is set to {@link YesNoUnknown#YES}.
297+ * </p>
298+ *
299+ * @param caseDto
300+ * The case data transfer object to update.
301+ * @param externalMessageDto
302+ * The external message containing activities as case data in JSON format.
303+ */
304+ protected void postBuildActivitiesAsCase (CaseDataDto caseDto , ExternalMessageDto externalMessageDto ) {
305+
306+ if (externalMessageDto .getActivitiesAsCase () != null && !externalMessageDto .getActivitiesAsCase ().isEmpty ()) {
307+ final ArrayList <ActivityAsCaseDto > activitiesAsCase = new ArrayList <>();
308+
309+ try {
310+ ObjectMapper objectMapper = new ObjectMapper ();
311+ List <ActivityAsCaseDto > deserialActivityAsCaseDtos =
312+ objectMapper .readValue (externalMessageDto .getActivitiesAsCase (), new TypeReference <List <ActivityAsCaseDto >>() {
313+ });
314+ for (ActivityAsCaseDto activityAsCaseDto : deserialActivityAsCaseDtos ) {
315+ ActivityAsCaseDto newActivityAsCase = ActivityAsCaseDto .build (activityAsCaseDto .getActivityAsCaseType ());
316+ if (newActivityAsCase .getActivityAsCaseType () == null ) {
317+ newActivityAsCase .setActivityAsCaseType (ActivityAsCaseType .UNKNOWN );
318+ }
319+ DtoCopyHelper .copyDtoValues (newActivityAsCase , activityAsCaseDto , true , "uuid" );
320+ activitiesAsCase .add (newActivityAsCase );
321+ }
322+ } catch (Exception e ) {
323+ logger .error ("[POST BUILD CASE] Error while processing activities as case for case with UUID: {}" , caseDto .getUuid (), e );
324+ return ;
325+ }
326+
327+ if (!activitiesAsCase .isEmpty ()) {
328+ EpiDataDto epiData = caseDto .getEpiData ();
329+ if (epiData == null ) {
330+ epiData = EpiDataDto .build ();
331+ caseDto .setEpiData (epiData );
332+ }
333+
334+ epiData .setActivityAsCaseDetailsKnown (YesNoUnknown .YES );
335+ epiData .setActivitiesAsCase (activitiesAsCase );
336+ }
337+
338+ } else {
339+ logger .debug ("[POST BUILD CASE] No activities to set for case with UUID: {}" , caseDto .getUuid ());
340+ }
341+ }
342+
343+ /**
344+ * Sets the exposure information for the case from the external message, if present.
345+ * <p>
346+ * This method deserializes the exposures from a JSON string in the external message
347+ * into a list of {@link ExposureDto} objects. Each exposure is built and copied, and if
348+ * the exposure type is missing, it is set to {@link ExposureType#UNKNOWN}.
349+ * If there are exposures, the {@code exposureDetailsKnown} field is set to {@link YesNoUnknown#YES}.
350+ * </p>
351+ *
352+ * @param caseDto
353+ * The case data transfer object to update.
354+ * @param externalMessageDto
355+ * The external message containing exposure data in JSON format.
356+ */
357+ protected void postBuildExposure (CaseDataDto caseDto , ExternalMessageDto externalMessageDto ) {
358+
359+ if (externalMessageDto .getExposures () != null && !externalMessageDto .getExposures ().isEmpty ()) {
360+ final ArrayList <ExposureDto > exposures = new ArrayList <>();
361+
362+ try {
363+ ObjectMapper objectMapper = new ObjectMapper ();
364+ List <ExposureDto > deserialExposureDtos =
365+ objectMapper .readValue (externalMessageDto .getExposures (), new TypeReference <List <ExposureDto >>() {
366+ });
367+ for (ExposureDto exposureDto : deserialExposureDtos ) {
368+ ExposureDto newExposure = ExposureDto .build (exposureDto .getExposureType ());
369+ if (newExposure .getExposureType () == null ) {
370+ newExposure .setExposureType (ExposureType .UNKNOWN );
371+ }
372+ DtoCopyHelper .copyDtoValues (newExposure , exposureDto , true , "uuid" );
373+ exposures .add (newExposure );
374+ }
375+ } catch (Exception e ) {
376+ logger .error ("[POST BUILD CASE] Error while processing exposures for case with UUID: {}" , caseDto .getUuid (), e );
377+ return ;
378+ }
379+
380+ if (!exposures .isEmpty ()) {
381+ EpiDataDto epiData = caseDto .getEpiData ();
382+ if (epiData == null ) {
383+ epiData = EpiDataDto .build ();
384+ caseDto .setEpiData (epiData );
385+ }
386+
387+ epiData .setExposureDetailsKnown (YesNoUnknown .YES );
388+ epiData .setExposures (exposures );
389+ }
390+
391+ } else {
392+ logger .debug ("[POST BUILD CASE] No exposures to set for case with UUID: {}" , caseDto .getUuid ());
393+ }
394+ }
395+
261396 /**
262397 * Custom logic to execute after building a person.
263398 *
0 commit comments