Skip to content

Commit ef17b1e

Browse files
committed
#13771 - Add Epipulse export functionality for Measles disease
1 parent c89a203 commit ef17b1e

File tree

4 files changed

+53
-11
lines changed

4 files changed

+53
-11
lines changed

sormas-api/src/main/java/de/symeda/sormas/api/epipulse/EpipulseLaboratoryMapper.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static String mapSampleMaterialToEpipulseCode(SampleMaterial sampleMateri
6969
case EDTA_WHOLE_BLOOD:
7070
return "EDTA"; // EDTA whole blood
7171
default:
72-
return "OTH";
72+
return null;
7373
}
7474
}
7575

@@ -129,8 +129,8 @@ public static String normalizeGenotypeForEpipulse(String genotypeText) {
129129
}
130130

131131
// Try to parse formats like "A", "B1", "D10", etc. and add MEASV_ prefix
132-
// This matches a single uppercase letter optionally followed by digits
133-
if (normalized.matches("^[A-Z]\\d*$")) {
132+
// Measles genotypes are limited (e.g., A, B1-3, C1-2, D1-11, E, F, G1-3, H1-2)
133+
if (normalized.matches("^(A|B[1-3]|C[1-2]|D(1[0-1]|[1-9])|E|F|G[1-3]|H[1-2])$")) {
134134
return "MEASV_" + normalized;
135135
}
136136

@@ -301,6 +301,9 @@ public static List<String> mapSymptomsToComplicationCodes(
301301
* @return true if clinically confirmed, false otherwise
302302
*/
303303
public static Boolean deriveClinicalCriteriaStatus(YesNoUnknown clinicalConfirmation) {
304+
if (clinicalConfirmation == null || clinicalConfirmation == YesNoUnknown.UNKNOWN) {
305+
return null;
306+
}
304307
return clinicalConfirmation == YesNoUnknown.YES;
305308
}
306309
}

sormas-backend/src/main/java/de/symeda/sormas/backend/epipulse/EpipulseCsvExportOrchestrator.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,15 @@ public void orchestrateExport(String uuid, ExportFunction exportFunction, CsvExp
9494
return;
9595
}
9696

97-
if (epipulseExport.getStatus() != EpipulseExportStatus.PENDING) {
98-
logger.error("EpipulseExport with uuid " + uuid + " is not in status PENDING");
97+
// Atomic status claim: try to update from PENDING to IN_PROGRESS
98+
boolean claimed = diseaseExportService.tryClaimExportForProcessing(uuid);
99+
if (!claimed) {
100+
logger.info("Export {} not claimed - either already processing or not in PENDING status", uuid);
99101
return;
100102
}
101103

102104
shouldUpdateStatus = true;
103105

104-
// Update status to IN_PROGRESS
105-
diseaseExportService.updateStatusForBackgroundProcess(uuid, EpipulseExportStatus.IN_PROGRESS, null, null, null);
106-
107106
// Load configuration
108107
EpipulseExportDto exportDto = epipulseExportEjb.toEpipulseExportDto(epipulseExport);
109108
String serverCountryCode = configFacadeEjb.getCountryCode();

sormas-backend/src/main/java/de/symeda/sormas/backend/epipulse/EpipulseDiseaseExportService.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,39 @@ public EpipulseDiseaseExportResult exportMeaslesCaseBased(EpipulseExportDto expo
6767
return measlesExportStrategy.export(exportDto, serverCountryLocale, serverCountryName);
6868
}
6969

70+
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
71+
public boolean tryClaimExportForProcessing(String exportUuid) {
72+
try {
73+
String sql = "UPDATE epipulse_export SET " +
74+
"status = :newStatus, " +
75+
"status_change_date = now(), " +
76+
"changedate = now() " +
77+
"WHERE uuid = :uuid AND status = :expectedStatus";
78+
79+
int updated = em.createNativeQuery(sql)
80+
.setParameter("newStatus", EpipulseExportStatus.IN_PROGRESS.name())
81+
.setParameter("uuid", exportUuid)
82+
.setParameter("expectedStatus", EpipulseExportStatus.PENDING.name())
83+
.executeUpdate();
84+
85+
em.flush();
86+
87+
if (updated > 0) {
88+
logger.info("Successfully claimed export {} for processing", exportUuid);
89+
return true;
90+
} else {
91+
logger.info("Export {} already claimed by another process or not in PENDING status", exportUuid);
92+
return false;
93+
}
94+
95+
} catch (Exception e) {
96+
logger.error("Failed to claim export {} for processing: {}", exportUuid, e.getMessage(), e);
97+
return false;
98+
} finally {
99+
em.clear();
100+
}
101+
}
102+
70103
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
71104
public void updateStatusForBackgroundProcess(
72105
String exportUuid,

sormas-backend/src/main/java/de/symeda/sormas/backend/epipulse/strategy/MeaslesExportStrategy.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,13 @@ private String buildSampleDataCte() {
223223
" STRING_AGG(DISTINCT CAST(s3.samplematerial AS text), ',' ORDER BY CAST(s3.samplematerial AS text)) as specimen_types_serology " +
224224
" FROM filtered_cases c " +
225225
" LEFT JOIN samples s ON s.associatedcase_id = c.id AND s.deleted = false " +
226-
" LEFT JOIN samples s2 ON s2.associatedcase_id = c.id AND s2.deleted = false AND s2.samplematerial IS NOT NULL " +
226+
" LEFT JOIN (SELECT DISTINCT s_vir.id, s_vir.associatedcase_id, s_vir.samplematerial " +
227+
" FROM samples s_vir " +
228+
" JOIN pathogentest pt_vir ON pt_vir.sample_id = s_vir.id " +
229+
" WHERE s_vir.deleted = false " +
230+
" AND s_vir.samplematerial IS NOT NULL " +
231+
" AND pt_vir.testtype IN ('PCR_RT_PCR', 'CULTURE', 'ISOLATION', 'DIRECT_FLUORESCENT_ANTIBODY', 'INDIRECT_FLUORESCENT_ANTIBODY')) s2 " +
232+
" ON s2.associatedcase_id = c.id " +
227233
" LEFT JOIN (SELECT DISTINCT s_sero.id, s_sero.associatedcase_id, s_sero.samplematerial " +
228234
" FROM samples s_sero " +
229235
" JOIN pathogentest pt_sero ON pt_sero.sample_id = s_sero.id " +
@@ -316,13 +322,14 @@ private String buildExposureLocationsCte() {
316322
" CASE " +
317323
" WHEN co.defaultname IS NOT NULL THEN co.defaultname " +
318324
" WHEN l.city IS NOT NULL THEN l.city " +
319-
" ELSE l.details " +
325+
" WHEN l.details IS NOT NULL THEN l.details " +
326+
" ELSE 'Unknown' " +
320327
" END, " +
321328
" '; ' " +
322329
" ORDER BY e.startdate DESC" +
323330
" ) as infection_locations " +
324331
" FROM exposures e " +
325-
" JOIN location l ON e.location_id = l.id " +
332+
" LEFT JOIN location l ON e.location_id = l.id " +
326333
" LEFT JOIN country co ON l.country_id = co.id " +
327334
" WHERE e.epidata_id IN (SELECT epidata_id FROM filtered_cases WHERE epidata_id IS NOT NULL) " +
328335
" GROUP BY e.epidata_id), ";

0 commit comments

Comments
 (0)