Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 38440ee

Browse files
Event View Case and Death Count [3276, 3562] (SORMAS-Foundation#3760)
* Add basic case and contact count to event overview table SORMAS-Foundation#3276 * Add i18n support (implement german and english) SORMAS-Foundation#3276 * Add another contact count calculation method and corresponding checkbox SORMAS-Foundation#3276 * Fixes SORMAS-Foundation#3348 null value in create Event Actions * Add i18n SORMAS-Foundation#3276 * Revert "Fixes SORMAS-Foundation#3348 null value in create Event Actions" This reverts commit 997259b. * WIP SORMAS-Foundation#3276 SORMAS-Foundation#3562: add deathcount, move count calculation to EventFacadeEjb * WIP SORMAS-Foundation#3276 SORMAS-Foundation#3562: Add source case restraint to contact count calculation method. Add i18n for deathcount. Code cleanup. * Code cleanup SORMAS-Foundation#3276 SORMAS-Foundation#3562 * Add deathCount, caseCount, contactCounts to event export SORMAS-Foundation#3276 SORMAS-Foundation#3562 * Add counts to detailed export and fix captioning SORMAS-Foundation#3276 SORMAS-Foundation#3562 * Update Captions.java * Continue Merge SORMAS-Foundation#3376 * Minor improvements SORMAS-Foundation#3276 * Move Case, Contact and Deathcount queries behind main query SORMAS-Foundation#3276 * Move particpantCount into second query SORMAS-Foundation#3276 * Rename table headers to improve readability SORMAS-Foundation#3276 * Add death and case count to event view SORMAS-Foundation#3276 SORMAS-Foundation#3562 Co-authored-by: syntakker <[email protected]>
1 parent 9c4d464 commit 38440ee

8 files changed

Lines changed: 173 additions & 29 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/event/EventExportDto.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public class EventExportDto implements Serializable {
3131
private EventStatus eventStatus;
3232
private RiskLevel riskLevel;
3333
private EventInvestigationStatus eventInvestigationStatus;
34-
private long participantsCount;
34+
private long participantCount;
35+
private long caseCount;
36+
private long deathCount;
3537
private Disease disease;
3638
private String diseaseDetails;
3739
private Date startDate;
@@ -65,7 +67,6 @@ public EventExportDto(
6567
EventStatus eventStatus,
6668
RiskLevel riskLevel,
6769
EventInvestigationStatus eventInvestigationStatus,
68-
long participantsCount,
6970
Disease disease,
7071
String diseaseDetails,
7172
Date startDate,
@@ -101,7 +102,6 @@ public EventExportDto(
101102
this.eventStatus = eventStatus;
102103
this.riskLevel = riskLevel;
103104
this.eventInvestigationStatus = eventInvestigationStatus;
104-
this.participantsCount = participantsCount;
105105
this.disease = disease;
106106
this.diseaseDetails = diseaseDetails;
107107
this.startDate = startDate;
@@ -356,12 +356,30 @@ public void setReportDateTime(Date reportDateTime) {
356356
}
357357

358358
@Order(29)
359-
public long getParticipantsCount() {
360-
return participantsCount;
359+
public long getParticipantCount() {
360+
return participantCount;
361361
}
362362

363-
public void setParticipantsCount(long participantsCount) {
364-
this.participantsCount = participantsCount;
363+
public void setParticipantCount(long participantCount) {
364+
this.participantCount = participantCount;
365+
}
366+
367+
@Order(30)
368+
public long getCaseCount() {
369+
return caseCount;
370+
}
371+
372+
public void setCaseCount(long caseCount) {
373+
this.caseCount = caseCount;
374+
}
375+
376+
@Order(31)
377+
public long getDeathCount() {
378+
return deathCount;
379+
}
380+
381+
public void setDeathCount(long deathCount) {
382+
this.deathCount = deathCount;
365383
}
366384

367385
public EventJurisdictionDto getJurisdiction() {

sormas-api/src/main/java/de/symeda/sormas/api/event/EventIndexDto.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class EventIndexDto extends PseudonymizableIndexDto implements Serializab
3434
public static final String EVENT_STATUS = "eventStatus";
3535
public static final String EVENT_INVESTIGATION_STATUS = "eventInvestigationStatus";
3636
public static final String PARTICIPANT_COUNT = "participantCount";
37+
public static final String CASE_COUNT = "caseCount";
38+
public static final String DEATH_COUNT = "deathCount";
3739
public static final String DISEASE = "disease";
3840
public static final String DISEASE_DETAILS = "diseaseDetails";
3941
public static final String START_DATE = "startDate";
@@ -54,6 +56,8 @@ public class EventIndexDto extends PseudonymizableIndexDto implements Serializab
5456
private EventStatus eventStatus;
5557
private EventInvestigationStatus eventInvestigationStatus;
5658
private long participantCount;
59+
private long caseCount;
60+
private long deathCount;
5761
private Disease disease;
5862
private String diseaseDetails;
5963
private Date startDate;
@@ -73,7 +77,6 @@ public EventIndexDto(
7377
String uuid,
7478
EventStatus eventStatus,
7579
EventInvestigationStatus eventInvestigationStatus,
76-
Long participantCount,
7780
Disease disease,
7881
String diseaseDetails,
7982
Date startDate,
@@ -116,7 +119,6 @@ public EventIndexDto(
116119
this.srcMediaName = srcMediaName;
117120
this.reportDateTime = reportDateTime;
118121
this.jurisdiction = new EventJurisdictionDto(reportingUserUuid, surveillanceOfficerUuid, regionUuid, districtUuid, communityUuid);
119-
this.participantCount = participantCount;
120122
}
121123

122124
public String getUuid() {
@@ -251,6 +253,22 @@ public void setParticipantCount(long participantCount) {
251253
this.participantCount = participantCount;
252254
}
253255

256+
public long getCaseCount() {
257+
return caseCount;
258+
}
259+
260+
public void setCaseCount(long caseCount) {
261+
this.caseCount = caseCount;
262+
}
263+
264+
public long getDeathCount() {
265+
return deathCount;
266+
}
267+
268+
public void setDeathCount(long deathCount) {
269+
this.deathCount = deathCount;
270+
}
271+
254272
public String getRegion() {
255273
return getEventLocation().getRegion();
256274
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ public interface Captions {
761761
String epiWeekFrom = "epiWeekFrom";
762762
String epiWeekTo = "epiWeekTo";
763763
String Event = "Event";
764+
String Event_caseCount = "Event.caseCount";
765+
String Event_deathCount = "Event.deathCount";
764766
String Event_diseaseDetails = "Event.diseaseDetails";
765767
String Event_diseaseShort = "Event.diseaseShort";
766768
String Event_endDate = "Event.endDate";

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,8 @@ eventDefaultView=Events
858858
eventActionsView=Actions
859859

860860
Event=Event
861+
Event.caseCount=Cases
862+
Event.deathCount=Fatalities
861863
Event.diseaseDetails=Disease name
862864
Event.diseaseShort=Disease
863865
singleDayEventDate=Date of event
@@ -876,7 +878,7 @@ Event.eventLocation=Event location
876878
Event.eventParticipants=Persons involved
877879
Event.eventPersons=Persons involved
878880
Event.eventStatus=Event status
879-
Event.participantCount=Participant Count
881+
Event.participantCount=Participants
880882
Event.eventType=Event type
881883
Event.informationSource=Source of information
882884
Event.numberOfPendingTasks=Pending tasks

sormas-api/src/main/resources/captions_de-DE.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,8 @@ eventDefaultView=Ereignisse
857857
eventActionsView=Aktionen
858858

859859
Event=Ereignis
860+
Event.caseCount=Fälle
861+
Event.deathCount=Todesfälle
860862
Event.diseaseDetails=Name der Krankheit
861863
Event.diseaseShort=Krankheit
862864
singleDayEventDate=Datum des Ereignisses
@@ -875,7 +877,7 @@ Event.eventLocation=Ereignisort
875877
Event.eventParticipants=Beteiligte Personen
876878
Event.eventPersons=Beteiligte Personen
877879
Event.eventStatus=Ereignisstatus
878-
Event.participantCount=Teilnehmeranzahl
880+
Event.participantCount=Teilnehmer
879881
Event.eventType=Ereignistyp
880882
Event.informationSource=Informationsquelle
881883
Event.numberOfPendingTasks=Ausstehende Aufgaben

sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java

Lines changed: 115 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import java.util.ArrayList;
2323
import java.util.Collections;
2424
import java.util.Date;
25+
import java.util.HashMap;
2526
import java.util.List;
2627
import java.util.Map;
28+
import java.util.Optional;
2729
import java.util.stream.Collectors;
2830

2931
import javax.ejb.EJB;
@@ -46,6 +48,7 @@
4648
import javax.validation.constraints.NotNull;
4749

4850
import de.symeda.sormas.api.Disease;
51+
import de.symeda.sormas.api.caze.CaseOutcome;
4952
import de.symeda.sormas.api.event.DashboardEventDto;
5053
import de.symeda.sormas.api.event.EventCriteria;
5154
import de.symeda.sormas.api.event.EventDto;
@@ -56,6 +59,7 @@
5659
import de.symeda.sormas.api.event.EventStatus;
5760
import de.symeda.sormas.api.user.UserRight;
5861
import de.symeda.sormas.api.utils.SortProperty;
62+
import de.symeda.sormas.backend.caze.Case;
5963
import de.symeda.sormas.backend.common.AbstractAdoService;
6064
import de.symeda.sormas.backend.common.AbstractDomainObject;
6165
import de.symeda.sormas.backend.contact.Contact;
@@ -220,18 +224,10 @@ public List<EventIndexDto> getIndexList(EventCriteria eventCriteria, Integer fir
220224
Join<Location, District> district = location.join(Location.DISTRICT, JoinType.LEFT);
221225
Join<Location, Community> community = location.join(Location.COMMUNITY, JoinType.LEFT);
222226

223-
Subquery<Long> participantCount = cq.subquery(Long.class);
224-
Root<EventParticipant> eventParticipantRoot = participantCount.from(EventParticipant.class);
225-
Predicate assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), event.get(AbstractDomainObject.ID));
226-
Predicate notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
227-
participantCount.select(cb.count(eventParticipantRoot));
228-
participantCount.where(assignedToEvent, notDeleted);
229-
230227
cq.multiselect(
231228
event.get(Event.UUID),
232229
event.get(Event.EVENT_STATUS),
233230
event.get(Event.EVENT_INVESTIGATION_STATUS),
234-
participantCount,
235231
event.get(Event.DISEASE),
236232
event.get(Event.DISEASE_DETAILS),
237233
event.get(Event.START_DATE),
@@ -331,7 +327,63 @@ public List<EventIndexDto> getIndexList(EventCriteria eventCriteria, Integer fir
331327
indexList = em.createQuery(cq).getResultList();
332328
}
333329

330+
Map<String, Long> participantCounts = new HashMap<>();
331+
Map<String, Long> caseCounts = new HashMap<>();;
332+
Map<String, Long> deathCounts = new HashMap<>();
333+
if (indexList != null) {
334+
List<Object[]> objectQueryList = null;
335+
336+
CriteriaQuery<Object[]> objectCQ = cb.createQuery(Object[].class);
337+
Root<Event> eventRoot = objectCQ.from(Event.class);
338+
339+
// number of Participants
340+
Subquery<Long> participantCount = objectCQ.subquery(Long.class);
341+
Root<EventParticipant> eventParticipantRoot = participantCount.from(EventParticipant.class);
342+
Predicate assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
343+
Predicate notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
344+
participantCount.select(cb.count(eventParticipantRoot));
345+
participantCount.where(assignedToEvent, notDeleted);
346+
347+
// number of cases among event participants
348+
Subquery<Long> caseCount = objectCQ.subquery(Long.class);
349+
eventParticipantRoot = caseCount.from(EventParticipant.class);
350+
assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
351+
notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
352+
Predicate isCase = cb.isNotNull(eventParticipantRoot.get(EventParticipant.RESULTING_CASE));
353+
caseCount.select(cb.count(eventParticipantRoot));
354+
caseCount.where(assignedToEvent, notDeleted, isCase);
355+
356+
// number of fatalities among event participant cases
357+
Subquery<Long> deathsCount = objectCQ.subquery(Long.class);
358+
eventParticipantRoot = deathsCount.from(EventParticipant.class);
359+
Join<EventParticipant, Case> caseJoin = eventParticipantRoot.join(EventParticipant.RESULTING_CASE, JoinType.LEFT);
360+
assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
361+
notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
362+
isCase = cb.isNotNull(eventParticipantRoot.get(EventParticipant.RESULTING_CASE));
363+
Predicate isDead = cb.equal(caseJoin.get(Case.OUTCOME), CaseOutcome.DECEASED);
364+
deathsCount.select(cb.count(eventParticipantRoot));
365+
deathsCount.where(assignedToEvent, notDeleted, isCase, isDead);
366+
367+
objectCQ.multiselect(eventRoot.get(Event.UUID), participantCount, caseCount, deathsCount);
368+
objectQueryList = em.createQuery(objectCQ).getResultList();
369+
objectQueryList.forEach(r -> {
370+
participantCounts.put((String) r[0], (Long) r[1]);
371+
caseCounts.put((String) r[0], (Long) r[2]);
372+
deathCounts.put((String) r[0], (Long) r[3]);
373+
});
374+
375+
}
376+
377+
if (indexList != null) {
378+
for (EventIndexDto eventDto : indexList) {
379+
Optional.ofNullable(participantCounts.get(eventDto.getUuid())).ifPresent(eventDto::setParticipantCount);
380+
Optional.ofNullable(caseCounts.get(eventDto.getUuid())).ifPresent(eventDto::setCaseCount);
381+
Optional.ofNullable(deathCounts.get(eventDto.getUuid())).ifPresent(eventDto::setDeathCount);
382+
}
383+
}
384+
334385
return indexList;
386+
335387
}
336388

337389
@Override
@@ -344,20 +396,12 @@ public List<EventExportDto> getExportList(EventCriteria eventCriteria, Integer f
344396
Join<Location, District> district = location.join(Location.DISTRICT, JoinType.LEFT);
345397
Join<Location, Community> community = location.join(Location.COMMUNITY, JoinType.LEFT);
346398

347-
Subquery<Long> participantCount = cq.subquery(Long.class);
348-
Root<EventParticipant> eventParticipantRoot = participantCount.from(EventParticipant.class);
349-
Predicate assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), event.get(AbstractDomainObject.ID));
350-
Predicate notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
351-
participantCount.select(cb.count(eventParticipantRoot));
352-
participantCount.where(assignedToEvent, notDeleted);
353-
354399
cq.multiselect(
355400
event.get(Event.UUID),
356401
event.get(Event.EXTERNAL_ID),
357402
event.get(Event.EVENT_STATUS),
358403
event.get(Event.RISK_LEVEL),
359404
event.get(Event.EVENT_INVESTIGATION_STATUS),
360-
participantCount,
361405
event.get(Event.DISEASE),
362406
event.get(Event.DISEASE_DETAILS),
363407
event.get(Event.START_DATE),
@@ -407,6 +451,61 @@ public List<EventExportDto> getExportList(EventCriteria eventCriteria, Integer f
407451
exportList = em.createQuery(cq).getResultList();
408452
}
409453

454+
Map<String, Long> participantCounts = new HashMap<>();
455+
Map<String, Long> caseCounts = new HashMap<>();;
456+
Map<String, Long> deathCounts = new HashMap<>();
457+
if (exportList != null) {
458+
List<Object[]> objectQueryList = null;
459+
460+
CriteriaQuery<Object[]> objectCQ = cb.createQuery(Object[].class);
461+
Root<Event> eventRoot = objectCQ.from(Event.class);
462+
463+
// number of Participants
464+
Subquery<Long> participantCount = objectCQ.subquery(Long.class);
465+
Root<EventParticipant> eventParticipantRoot = participantCount.from(EventParticipant.class);
466+
Predicate assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
467+
Predicate notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
468+
participantCount.select(cb.count(eventParticipantRoot));
469+
participantCount.where(assignedToEvent, notDeleted);
470+
471+
// number of cases among event participants
472+
Subquery<Long> caseCount = objectCQ.subquery(Long.class);
473+
eventParticipantRoot = caseCount.from(EventParticipant.class);
474+
assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
475+
notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
476+
Predicate isCase = cb.isNotNull(eventParticipantRoot.get(EventParticipant.RESULTING_CASE));
477+
caseCount.select(cb.count(eventParticipantRoot));
478+
caseCount.where(assignedToEvent, notDeleted, isCase);
479+
480+
// number of fatalities among event participant cases
481+
Subquery<Long> deathsCount = objectCQ.subquery(Long.class);
482+
eventParticipantRoot = deathsCount.from(EventParticipant.class);
483+
Join<EventParticipant, Case> caseJoin = eventParticipantRoot.join(EventParticipant.RESULTING_CASE, JoinType.LEFT);
484+
assignedToEvent = cb.equal(eventParticipantRoot.get(EventParticipant.EVENT), eventRoot.get(AbstractDomainObject.ID));
485+
notDeleted = cb.isFalse(eventParticipantRoot.get(EventParticipant.DELETED));
486+
isCase = cb.isNotNull(eventParticipantRoot.get(EventParticipant.RESULTING_CASE));
487+
Predicate isDead = cb.equal(caseJoin.get(Case.OUTCOME), CaseOutcome.DECEASED);
488+
deathsCount.select(cb.count(eventParticipantRoot));
489+
deathsCount.where(assignedToEvent, notDeleted, isCase, isDead);
490+
491+
objectCQ.multiselect(eventRoot.get(Event.UUID), participantCount, caseCount, deathsCount);
492+
objectQueryList = em.createQuery(objectCQ).getResultList();
493+
objectQueryList.forEach(r -> {
494+
participantCounts.put((String) r[0], (Long) r[1]);
495+
caseCounts.put((String) r[0], (Long) r[2]);
496+
deathCounts.put((String) r[0], (Long) r[3]);
497+
});
498+
499+
}
500+
501+
if (exportList != null) {
502+
for (EventExportDto exportDto : exportList) {
503+
Optional.ofNullable(participantCounts.get(exportDto.getUuid())).ifPresent(exportDto::setParticipantCount);
504+
Optional.ofNullable(caseCounts.get(exportDto.getUuid())).ifPresent(exportDto::setCaseCount);
505+
Optional.ofNullable(deathCounts.get(exportDto.getUuid())).ifPresent(exportDto::setDeathCount);
506+
}
507+
}
508+
410509
return exportList;
411510
}
412511

sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.List;
2323

2424
import org.apache.commons.lang3.StringUtils;
25-
import org.apache.commons.text.StringEscapeUtils;
2625

2726
import com.vaadin.navigator.Navigator;
2827
import com.vaadin.server.Page;

sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventGrid.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ public <V extends View> EventGrid(EventCriteria criteria, Class<V> viewClass) {
116116
INFORMATION_SOURCE,
117117
EventIndexDto.REPORT_DATE_TIME,
118118
NUMBER_OF_PENDING_TASKS,
119-
EventIndexDto.PARTICIPANT_COUNT));
119+
EventIndexDto.PARTICIPANT_COUNT,
120+
EventIndexDto.CASE_COUNT,
121+
EventIndexDto.DEATH_COUNT));
120122

121123
if (!tasksFeatureEnabled) {
122124
columnIds.remove(NUMBER_OF_PENDING_TASKS);
@@ -125,6 +127,8 @@ public <V extends View> EventGrid(EventCriteria criteria, Class<V> viewClass) {
125127
setColumns(columnIds.toArray(new String[columnIds.size()]));
126128

127129
getColumn(EventIndexDto.PARTICIPANT_COUNT).setSortable(false);
130+
getColumn(EventIndexDto.CASE_COUNT).setSortable(false);
131+
getColumn(EventIndexDto.DEATH_COUNT).setSortable(false);
128132

129133
((Column<EventIndexDto, String>) getColumn(EventIndexDto.UUID)).setRenderer(new UuidRenderer());
130134
((Column<EventIndexDto, Date>) getColumn(EventIndexDto.REPORT_DATE_TIME))

0 commit comments

Comments
 (0)