ContactFacadeEjb implements ContactFacade { @Override public List<ContactExportDto> getExportList(ContactCriteria contactCriteria, int first, int max, Language userLanguage) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<ContactExportDto> cq = cb.createQuery(ContactExportDto.class); Root<Contact> contact = cq.from(Contact.class); ContactJoins joins = new ContactJoins(contact); cq.multiselect( Stream.concat( Stream.of( contact.get(Contact.ID), joins.getPerson().get(Person.ID), contact.get(Contact.UUID), joins.getCaze().get(Case.UUID), joins.getCaze().get(Case.CASE_CLASSIFICATION), contact.get(Contact.DISEASE), contact.get(Contact.DISEASE_DETAILS), contact.get(Contact.CONTACT_CLASSIFICATION), contact.get(Contact.LAST_CONTACT_DATE), joins.getPerson().get(Person.FIRST_NAME), joins.getPerson().get(Person.LAST_NAME), joins.getPerson().get(Person.SEX), joins.getPerson().get(Person.BIRTHDATE_DD), joins.getPerson().get(Person.BIRTHDATE_MM), joins.getPerson().get(Person.BIRTHDATE_YYYY), joins.getPerson().get(Person.APPROXIMATE_AGE), joins.getPerson().get(Person.APPROXIMATE_AGE_TYPE), contact.get(Contact.REPORT_DATE_TIME), contact.get(Contact.CONTACT_IDENTIFICATION_SOURCE), contact.get(Contact.CONTACT_IDENTIFICATION_SOURCE_DETAILS), contact.get(Contact.TRACING_APP), contact.get(Contact.TRACING_APP_DETAILS), contact.get(Contact.CONTACT_PROXIMITY), contact.get(Contact.CONTACT_STATUS), contact.get(Contact.FOLLOW_UP_STATUS), contact.get(Contact.FOLLOW_UP_UNTIL), contact.get(Contact.QUARANTINE), contact.get(Contact.QUARANTINE_TYPE_DETAILS), contact.get(Contact.QUARANTINE_FROM), contact.get(Contact.QUARANTINE_TO), contact.get(Contact.QUARANTINE_HELP_NEEDED), contact.get(Contact.QUARANTINE_ORDERED_VERBALLY), contact.get(Contact.QUARANTINE_ORDERED_OFFICIAL_DOCUMENT), contact.get(Contact.QUARANTINE_ORDERED_VERBALLY_DATE), contact.get(Contact.QUARANTINE_ORDERED_OFFICIAL_DOCUMENT_DATE), contact.get(Contact.QUARANTINE_EXTENDED), contact.get(Contact.QUARANTINE_REDUCED), contact.get(Contact.QUARANTINE_OFFICIAL_ORDER_SENT), contact.get(Contact.QUARANTINE_OFFICIAL_ORDER_SENT_DATE), joins.getPerson().get(Person.PRESENT_CONDITION), joins.getPerson().get(Person.DEATH_DATE), joins.getAddressRegion().get(Region.NAME), joins.getAddressDistrict().get(District.NAME), joins.getAddressCommunity().get(Community.NAME), joins.getAddress().get(Location.CITY), joins.getAddress().get(Location.STREET), joins.getAddress().get(Location.HOUSE_NUMBER), joins.getAddress().get(Location.ADDITIONAL_INFORMATION), joins.getAddress().get(Location.POSTAL_CODE), joins.getAddressFacility().get(Facility.NAME), joins.getAddressFacility().get(Facility.UUID), joins.getAddress().get(Location.FACILITY_DETAILS), joins.getPerson().get(Person.PHONE), joins.getPerson().get(Person.PHONE_OWNER), joins.getPerson().get(Person.OCCUPATION_TYPE), joins.getPerson().get(Person.OCCUPATION_DETAILS), joins.getRegion().get(Region.NAME), joins.getDistrict().get(District.NAME), joins.getCommunity().get(Community.NAME), joins.getEpiData().get(EpiData.ID), joins.getEpiData().get(EpiData.TRAVELED), joins.getEpiData().get(EpiData.BURIAL_ATTENDED), joins.getEpiData().get(EpiData.DIRECT_CONTACT_CONFIRMED_CASE), joins.getEpiData().get(EpiData.DIRECT_CONTACT_PROBABLE_CASE), joins.getEpiData().get(EpiData.RODENTS), contact.get(Contact.RETURNING_TRAVELER)), listCriteriaBuilder.getJurisdictionSelections(joins)).collect(Collectors.toList())); cq.distinct(true); Predicate filter = listCriteriaBuilder.buildContactFilter(contactCriteria, cb, contact, cq); if (filter != null) { cq.where(filter); } cq.orderBy(cb.desc(contact.get(Contact.REPORT_DATE_TIME)), cb.desc(contact.get(Contact.ID))); List<ContactExportDto> exportContacts = em.createQuery(cq).setFirstResult(first).setMaxResults(max).getResultList(); if (!exportContacts.isEmpty()) { List<Long> exportContactIds = exportContacts.stream().map(e -> e.getId()).collect(Collectors.toList()); CriteriaQuery<VisitSummaryExportDetails> visitsCq = cb.createQuery(VisitSummaryExportDetails.class); Root<Contact> visitsCqRoot = visitsCq.from(Contact.class); ContactJoins visitContactJoins = new ContactJoins(visitsCqRoot); visitsCq.where( ContactService.and(cb, contact.get(AbstractDomainObject.ID).in(exportContactIds), cb.isNotEmpty(visitsCqRoot.get(Contact.VISITS)))); visitsCq.multiselect( Stream .concat( Stream.of( visitsCqRoot.get(AbstractDomainObject.ID), visitContactJoins.getVisits().get(Visit.VISIT_DATE_TIME), visitContactJoins.getVisits().get(Visit.VISIT_STATUS), visitContactJoins.getVisitSymptoms()), listCriteriaBuilder.getJurisdictionSelections(visitContactJoins)) .collect(Collectors.toList())); List<VisitSummaryExportDetails> visitSummaries = em.createQuery(visitsCq).getResultList(); Map<Long, List<EpiDataTravel>> travels = null; List<EpiDataTravel> travelsList = null; CriteriaQuery<EpiDataTravel> travelsCq = cb.createQuery(EpiDataTravel.class); Root<EpiDataTravel> travelsRoot = travelsCq.from(EpiDataTravel.class); Join<EpiDataTravel, EpiData> travelsEpiDataJoin = travelsRoot.join(EpiDataTravel.EPI_DATA, JoinType.LEFT); Expression<String> epiDataIdsExpr = travelsEpiDataJoin.get(EpiData.ID); travelsCq.where(epiDataIdsExpr.in(exportContacts.stream().map(ContactExportDto::getEpiDataId).collect(Collectors.toList()))); travelsCq.orderBy(cb.asc(travelsEpiDataJoin.get(EpiData.ID))); travelsList = em.createQuery(travelsCq).setHint(ModelConstants.HINT_HIBERNATE_READ_ONLY, true).getResultList(); travels = travelsList.stream().collect(Collectors.groupingBy(t -> ((EpiDataTravel) t).getEpiData().getId())); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); for (ContactExportDto exportContact : exportContacts) { boolean inJurisdiction = contactJurisdictionChecker.isInJurisdictionOrOwned(exportContact.getJurisdiction()); List<VisitSummaryExportDetails> visits = visitSummaries.stream().filter(v -> v.getContactId() == exportContact.getId()).collect(Collectors.toList()); VisitSummaryExportDetails lastCooperativeVisit = visits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.COOPERATIVE) .max(Comparator.comparing(VisitSummaryExportDetails::getVisitDateTime)) .orElse(null); exportContact.setNumberOfVisits(visits.size()); if (lastCooperativeVisit != null) { SymptomsDto symptoms = SymptomsFacadeEjb.toDto(lastCooperativeVisit.getSymptoms()); pseudonymizer.pseudonymizeDto(SymptomsDto.class, symptoms, inJurisdiction, null); exportContact.setLastCooperativeVisitDate(lastCooperativeVisit.getVisitDateTime()); exportContact.setLastCooperativeVisitSymptoms(SymptomsHelper.buildSymptomsHumanString(symptoms, true, userLanguage)); exportContact.setLastCooperativeVisitSymptomatic(symptoms.getSymptomatic() ? YesNoUnknown.YES : YesNoUnknown.NO); } if (travels != null) { Optional.ofNullable(travels.get(exportContact.getEpiDataId())).ifPresent(caseTravels -> { StringBuilder travelHistoryBuilder = new StringBuilder(); caseTravels.forEach(travel -> { travelHistoryBuilder.append( EpiDataTravelHelper.buildTravelString( travel.getTravelType(), travel.getTravelDestination(), travel.getTravelDateFrom(), travel.getTravelDateTo(), userLanguage)) .append(", "); }); if (travelHistoryBuilder.length() > 0) { travelHistoryBuilder.delete(travelHistoryBuilder.lastIndexOf(", "), travelHistoryBuilder.length()); } if (travelHistoryBuilder.length() == 0 && exportContact.getTraveled() != null) { travelHistoryBuilder.append(exportContact.getTraveled()); } exportContact.setTravelHistory(travelHistoryBuilder.toString()); }); } pseudonymizer.pseudonymizeDto(ContactExportDto.class, exportContact, inJurisdiction, null); } } return exportContacts; }  @Override List<String> getAllActiveUuids(); @Override List<ContactDto> getAllActiveContactsAfter(Date date); @Override List<ContactDto> getByUuids(List<String> uuids); @Override List<String> getDeletedUuidsSince(Date since); @Override ContactDto getContactByUuid(String uuid); @Override Boolean isValidContactUuid(String uuid); @Override ContactReferenceDto getReferenceByUuid(String uuid); @Override ContactDto saveContact(ContactDto dto); @Override ContactDto saveContact(ContactDto dto, boolean handleChanges); @Override List<MapContactDto> getContactsForMap(
		RegionReferenceDto regionRef,
		DistrictReferenceDto districtRef,
		Disease disease,
		Date fromDate,
		Date toDate,
		List<MapCaseDto> mapCaseDtos); @Override void deleteContact(String contactUuid); @Override List<ContactExportDto> getExportList(ContactCriteria contactCriteria, int first, int max, Language userLanguage); @Override List<VisitSummaryExportDto> getVisitSummaryExportList(ContactCriteria contactCriteria, int first, int max, Language userLanguage); @Override long countMaximumFollowUpDays(ContactCriteria contactCriteria); @Override long count(ContactCriteria contactCriteria); @Override List<ContactFollowUpDto> getContactFollowUpList(
		ContactCriteria contactCriteria,
		Date referenceDate,
		int interval,
		Integer first,
		Integer max,
		List<SortProperty> sortProperties); @Override List<ContactIndexDto> getIndexList(ContactCriteria contactCriteria, Integer first, Integer max, List<SortProperty> sortProperties); @Override List<ContactIndexDetailedDto> getIndexDetailedList(
		ContactCriteria contactCriteria,
		Integer first,
		Integer max,
		List<SortProperty> sortProperties); @Override int[] getContactCountsByCasesForDashboard(List<Long> contactIds); @Override int getNonSourceCaseCountForDashboard(List<String> caseUuids); Contact fromDto(@NotNull ContactDto source); @Override boolean isDeleted(String contactUuid); @Override List<DashboardContactDto> getContactsForDashboard(
		RegionReferenceDto regionRef,
		DistrictReferenceDto districtRef,
		Disease disease,
		Date from,
		Date to); @Override List<DashboardQuarantineDataDto> getQuarantineDataForDashBoard(
		RegionReferenceDto regionRef,
		DistrictReferenceDto districtRef,
		Disease disease,
		Date from,
		Date to); @Override Map<ContactStatus, Long> getNewContactCountPerStatus(ContactCriteria contactCriteria); @Override Map<ContactClassification, Long> getNewContactCountPerClassification(ContactCriteria contactCriteria); @Override Map<FollowUpStatus, Long> getNewContactCountPerFollowUpStatus(ContactCriteria contactCriteria); @Override int getFollowUpUntilCount(ContactCriteria contactCriteria); ContactDto convertToDto(Contact source, Pseudonymizer pseudonymizer); static ContactReferenceDto toReferenceDto(Contact source); static ContactDto toDto(Contact source); @RolesAllowed(UserRole._SYSTEM) @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) void generateContactFollowUpTasks(); @Override void validate(ContactDto contact); @Override List<SimilarContactDto> getMatchingContacts(ContactSimilarityCriteria criteria); @Override boolean exists(String uuid); @Override boolean isContactEditAllowed(String contactUuid);  }
@Test public void testGetExportList() { TestDataCreator.RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = useSurveillanceOfficerLogin(rdcf); PersonDto cazePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase( user.toReference(), cazePerson.toReference(), Disease.EVD, CaseClassification.PROBABLE, InvestigationStatus.PENDING, new Date(), rdcf); ContactDto contact = creator.createContact( user.toReference(), user.toReference(), creator.createPerson("Contact", "Person").toReference(), caze, new Date(), new Date(), null, rdcf); PersonDto contactPerson = getPersonFacade().getPersonByUuid(contact.getPerson().getUuid()); VisitDto visit = creator.createVisit(caze.getDisease(), contactPerson.toReference(), new Date(), VisitStatus.COOPERATIVE); EpiDataDto epiData = contact.getEpiData(); epiData.setTraveled(YesNoUnknown.YES); List<EpiDataTravelDto> travels = new ArrayList<>(); EpiDataTravelDto travel = EpiDataTravelDto.build(); travel.setTravelDateFrom(DateHelper.subtractDays(new Date(), 15)); travel.setTravelDateTo(DateHelper.subtractDays(new Date(), 7)); travel.setTravelDestination("Mallorca"); travel.setTravelType(TravelType.ABROAD); travels.add(travel); epiData.setTravels(travels); contact.setEpiData(epiData); getContactFacade().saveContact(contact); contactPerson.getAddress().setRegion(new RegionReferenceDto(rdcf.region.getUuid())); contactPerson.getAddress().setDistrict(new DistrictReferenceDto(rdcf.district.getUuid())); contactPerson.getAddress().setCity("City"); contactPerson.getAddress().setStreet("Test street"); contactPerson.getAddress().setHouseNumber("Test number"); contactPerson.getAddress().setAdditionalInformation("Test information"); contactPerson.getAddress().setPostalCode("1234"); getPersonFacade().savePerson(contactPerson); visit.getSymptoms().setAbdominalPain(SymptomState.YES); getVisitFacade().saveVisit(visit); List<ContactExportDto> results = getContactFacade().getExportList(null, 0, 100, Language.EN); assertEquals(1, results.size()); ContactExportDto exportDto = results.get(0); assertEquals(rdcf.region.getCaption(), exportDto.getAddressRegion()); assertEquals(rdcf.district.getCaption(), exportDto.getAddressDistrict()); assertEquals("City", exportDto.getCity()); assertEquals("Test street", exportDto.getStreet()); assertEquals("Test number", exportDto.getHouseNumber()); assertEquals("Test information", exportDto.getAdditionalInformation()); assertEquals("1234", exportDto.getPostalCode()); assertNotNull(exportDto.getLastCooperativeVisitDate()); assertTrue(StringUtils.isNotEmpty(exportDto.getLastCooperativeVisitSymptoms())); assertEquals(YesNoUnknown.YES, exportDto.getLastCooperativeVisitSymptomatic()); assertNotNull(exportDto.getEpiDataId()); assertEquals(YesNoUnknown.YES, exportDto.getTraveled()); assertEquals( EpiDataTravelHelper.buildTravelString( travel.getTravelType(), travel.getTravelDestination(), travel.getTravelDateFrom(), travel.getTravelDateTo(), Language.EN), exportDto.getTravelHistory()); }