use of de.symeda.sormas.backend.caze.Case in project SORMAS-Project by hzi-braunschweig.
the class PersonFacadeEjb method getCaseLatestFollowUpEndDates.
private Stream<PersonFollowUpEndDto> getCaseLatestFollowUpEndDates(Date since, boolean forSymptomJournal) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<PersonFollowUpEndDto> cq = cb.createQuery(PersonFollowUpEndDto.class);
Root<Case> caseRoot = cq.from(Case.class);
Join<Case, Person> personJoin = caseRoot.join(Case.PERSON, JoinType.LEFT);
Predicate filter = caseService.createUserFilter(cb, cq, caseRoot);
if (since != null) {
filter = CriteriaBuilderHelper.and(cb, filter, caseService.createChangeDateFilter(cb, caseRoot, since));
}
if (forSymptomJournal) {
filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(personJoin.get(Person.SYMPTOM_JOURNAL_STATUS), SymptomJournalStatus.ACCEPTED));
}
if (filter != null) {
cq.where(filter);
}
final Date minDate = new Date(0);
final Expression<Object> followUpStatusExpression = cb.selectCase().when(cb.equal(caseRoot.get(Case.FOLLOW_UP_STATUS), FollowUpStatus.CANCELED), cb.nullLiteral(Date.class)).otherwise(caseRoot.get(Case.FOLLOW_UP_UNTIL));
cq.multiselect(personJoin.get(Person.UUID), followUpStatusExpression);
cq.orderBy(cb.asc(personJoin.get(Person.UUID)), cb.desc(cb.coalesce(caseRoot.get(Case.FOLLOW_UP_UNTIL), minDate)));
return em.createQuery(cq).getResultList().stream().distinct();
}
use of de.symeda.sormas.backend.caze.Case in project SORMAS-Project by hzi-braunschweig.
the class PersonFacadeEjb method onPersonChanged.
public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean syncShares) {
List<Case> personCases = null;
// Do not bother to update existing cases/contacts/eventparticipants on new Persons, as none should exist yet
if (existingPerson != null) {
personCases = caseService.findBy(new CaseCriteria().person(new PersonReferenceDto(newPerson.getUuid())), true);
// Attention: this may lead to infinite recursion when not properly implemented
for (Case personCase : personCases) {
CaseDataDto existingCase = caseFacade.toDto(personCase);
caseFacade.onCaseChanged(existingCase, personCase, syncShares);
}
List<Contact> personContacts = contactService.findBy(new ContactCriteria().setPerson(new PersonReferenceDto(newPerson.getUuid())), null);
// Attention: this may lead to infinite recursion when not properly implemented
for (Contact personContact : personContacts) {
contactFacade.onContactChanged(contactFacade.toDto(personContact), syncShares);
}
List<EventParticipant> personEventParticipants = eventParticipantService.findBy(new EventParticipantCriteria().withPerson(new PersonReferenceDto(newPerson.getUuid())), null);
// Attention: this may lead to infinite recursion when not properly implemented
for (EventParticipant personEventParticipant : personEventParticipants) {
eventParticipantFacade.onEventParticipantChanged(eventFacade.toDto(personEventParticipant.getEvent()), eventParticipantFacade.toDto(personEventParticipant), personEventParticipant, syncShares);
}
// get the updated personCases
personCases = caseService.findBy(new CaseCriteria().person(new PersonReferenceDto(newPerson.getUuid())), true);
// sort cases based on recency
Collections.sort(personCases, (c1, c2) -> CaseLogic.getStartDate(c1.getSymptoms().getOnsetDate(), c1.getReportDate()).before(CaseLogic.getStartDate(c2.getSymptoms().getOnsetDate(), c2.getReportDate())) ? 1 : -1);
if (newPerson.getPresentCondition() != null && existingPerson.getPresentCondition() != newPerson.getPresentCondition()) {
// get the latest case with disease==causeofdeathdisease
Case personCase = personCases.stream().filter(caze -> caze.getDisease() == newPerson.getCauseOfDeathDisease()).findFirst().orElse(null);
if (newPerson.getPresentCondition().isDeceased() && newPerson.getDeathDate() != null && newPerson.getCauseOfDeath() == CauseOfDeath.EPIDEMIC_DISEASE && newPerson.getCauseOfDeathDisease() != null) {
// update the latest associated case
if (personCase != null && personCase.getOutcome() != CaseOutcome.DECEASED && (personCase.getReportDate().before(DateHelper.addDays(newPerson.getDeathDate(), 30)) && personCase.getReportDate().after(DateHelper.subtractDays(newPerson.getDeathDate(), 30)))) {
CaseDataDto existingCase = caseFacade.toDto(personCase);
personCase.setOutcome(CaseOutcome.DECEASED);
personCase.setOutcomeDate(newPerson.getDeathDate());
caseFacade.onCaseChanged(existingCase, personCase, syncShares);
}
} else if (!newPerson.getPresentCondition().isDeceased() && (existingPerson.getPresentCondition() == PresentCondition.DEAD || existingPerson.getPresentCondition() == PresentCondition.BURIED)) {
// Person was put "back alive"
// make sure other values are set to null
newPerson.setCauseOfDeath(null);
newPerson.setCauseOfDeathDisease(null);
newPerson.setDeathPlaceDescription(null);
newPerson.setDeathPlaceType(null);
newPerson.setBurialDate(null);
newPerson.setCauseOfDeathDisease(null);
// update the latest associated case, if it was set to deceased && and if the case-disease was also the causeofdeath-disease
if (personCase != null && personCase.getOutcome() == CaseOutcome.DECEASED) {
CaseDataDto existingCase = caseFacade.toDto(personCase);
personCase.setOutcome(CaseOutcome.NO_OUTCOME);
personCase.setOutcomeDate(null);
caseFacade.onCaseChanged(existingCase, personCase, syncShares);
}
}
} else if (newPerson.getPresentCondition() != null && newPerson.getPresentCondition().isDeceased() && !Objects.equals(newPerson.getDeathDate(), existingPerson.getDeathDate()) && newPerson.getDeathDate() != null) {
// only Deathdate has changed
// update the latest associated case to the new deathdate, if causeOfDeath matches
Case personCase = personCases.isEmpty() ? null : personCases.get(0);
if (personCase != null && personCase.getOutcome() == CaseOutcome.DECEASED && newPerson.getCauseOfDeath() == CauseOfDeath.EPIDEMIC_DISEASE) {
CaseDataDto existingCase = caseFacade.toDto(personCase);
personCase.setOutcomeDate(newPerson.getDeathDate());
caseFacade.onCaseChanged(existingCase, personCase, syncShares);
}
}
}
// Set approximate age if it hasn't been set before
if (newPerson.getApproximateAge() == null && newPerson.getBirthdateYYYY() != null) {
Pair<Integer, ApproximateAgeType> pair = ApproximateAgeHelper.getApproximateAge(newPerson.getBirthdateYYYY(), newPerson.getBirthdateMM(), newPerson.getBirthdateDD(), newPerson.getDeathDate());
newPerson.setApproximateAge(pair.getElement0());
newPerson.setApproximateAgeType(pair.getElement1());
newPerson.setApproximateAgeReferenceDate(newPerson.getDeathDate() != null ? newPerson.getDeathDate() : new Date());
}
// Update caseAge of all associated cases when approximateAge has changed
if (existingPerson != null && existingPerson.getApproximateAge() != newPerson.getApproximateAge()) {
// Update case list after previous onCaseChanged
personCases = caseService.findBy(new CaseCriteria().person(new PersonReferenceDto(newPerson.getUuid())), true);
for (Case personCase : personCases) {
CaseDataDto existingCase = caseFacade.toDto(personCase);
if (newPerson.getApproximateAge() == null) {
personCase.setCaseAge(null);
} else if (newPerson.getApproximateAgeType() == ApproximateAgeType.MONTHS) {
personCase.setCaseAge(0);
} else {
Date now = new Date();
personCase.setCaseAge(newPerson.getApproximateAge() - DateHelper.getYearsBetween(personCase.getReportDate(), now));
if (personCase.getCaseAge() < 0) {
personCase.setCaseAge(0);
}
}
caseFacade.onCaseChanged(existingCase, personCase, syncShares);
}
}
// For newly created persons, assume no registration in external journals
if (existingPerson == null && newPerson.getSymptomJournalStatus() == null) {
newPerson.setSymptomJournalStatus(SymptomJournalStatus.UNREGISTERED);
}
cleanUp(newPerson);
}
use of de.symeda.sormas.backend.caze.Case in project SORMAS-Project by hzi-braunschweig.
the class PersonService method getAllAfter.
@Override
public // todo refactor this to use the create user filter form persons
List<Person> getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) {
User user = getCurrentUser();
CriteriaBuilder cb = em.getCriteriaBuilder();
// persons by LGA
CriteriaQuery<Person> personsQuery = cb.createQuery(Person.class);
Root<Person> personsRoot = personsQuery.from(Person.class);
Join<Person, Location> address = personsRoot.join(Person.ADDRESS);
Predicate lgaFilter = cb.equal(address.get(Location.DISTRICT), user.getDistrict());
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, personsRoot, DateHelper.toTimestampUpper(date), lastSynchronizedUuid);
lgaFilter = cb.and(lgaFilter, dateFilter);
}
personsQuery.where(lgaFilter);
List<Person> lgaResultList = getBatchedQueryResults(cb, personsQuery, personsRoot, batchSize);
// persons by case
CriteriaQuery<Person> casePersonsQuery = cb.createQuery(Person.class);
Root<Case> casePersonsRoot = casePersonsQuery.from(Case.class);
Join<Person, Person> casePersonsSelect = casePersonsRoot.join(Case.PERSON);
casePersonsSelect.fetch(Person.ADDRESS);
casePersonsQuery.select(casePersonsSelect);
Predicate casePersonsFilter = caseService.createUserFilter(cb, casePersonsQuery, casePersonsRoot);
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, casePersonsSelect, DateHelper.toTimestampUpper(date), lastSynchronizedUuid);
if (batchSize == null) {
// include case change dates: When a case is relocated it may become available to another user and this will have to include the person as-well
Predicate caseDateFilter = caseService.createChangeDateFilter(cb, casePersonsRoot, DateHelper.toTimestampUpper(date));
dateFilter = cb.or(dateFilter, caseDateFilter);
}
if (casePersonsFilter != null) {
casePersonsFilter = cb.and(casePersonsFilter, dateFilter);
} else {
casePersonsFilter = dateFilter;
}
}
if (casePersonsFilter != null) {
casePersonsQuery.where(casePersonsFilter);
}
casePersonsQuery.distinct(true);
List<Person> casePersonsResultList = getBatchedQueryResults(cb, casePersonsQuery, casePersonsSelect, batchSize);
// persons by contact
CriteriaQuery<Person> contactPersonsQuery = cb.createQuery(Person.class);
Root<Contact> contactPersonsRoot = contactPersonsQuery.from(Contact.class);
Join<Person, Person> contactPersonsSelect = contactPersonsRoot.join(Contact.PERSON);
contactPersonsSelect.fetch(Person.ADDRESS);
contactPersonsQuery.select(contactPersonsSelect);
Predicate contactPersonsFilter = contactService.createUserFilter(cb, contactPersonsQuery, contactPersonsRoot);
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, contactPersonsSelect, DateHelper.toTimestampUpper(date), lastSynchronizedUuid);
if (batchSize == null) {
Predicate contactDateFilter = contactService.createChangeDateFilter(cb, contactPersonsRoot, date);
dateFilter = cb.or(dateFilter, contactDateFilter);
}
contactPersonsFilter = and(cb, contactPersonsFilter, dateFilter);
}
if (contactPersonsFilter != null) {
contactPersonsQuery.where(contactPersonsFilter);
}
contactPersonsQuery.distinct(true);
List<Person> contactPersonsResultList = getBatchedQueryResults(cb, contactPersonsQuery, contactPersonsSelect, batchSize);
// persons by event participant
CriteriaQuery<Person> eventPersonsQuery = cb.createQuery(Person.class);
Root<EventParticipant> eventPersonsRoot = eventPersonsQuery.from(EventParticipant.class);
Join<Person, Person> eventPersonsSelect = eventPersonsRoot.join(EventParticipant.PERSON);
eventPersonsSelect.fetch(Person.ADDRESS);
eventPersonsQuery.select(eventPersonsSelect);
Predicate eventPersonsFilter = eventParticipantService.createUserFilter(cb, eventPersonsQuery, eventPersonsRoot);
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, eventPersonsSelect, DateHelper.toTimestampUpper(date), lastSynchronizedUuid);
if (batchSize == null) {
Predicate eventParticipantDateFilter = eventParticipantService.createChangeDateFilter(cb, eventPersonsRoot, DateHelper.toTimestampUpper(date));
dateFilter = cb.or(dateFilter, eventParticipantDateFilter);
}
eventPersonsFilter = and(cb, eventPersonsFilter, dateFilter);
}
if (eventPersonsFilter != null) {
eventPersonsQuery.where(eventPersonsFilter);
}
eventPersonsQuery.distinct(true);
List<Person> eventPersonsResultList = getBatchedQueryResults(cb, eventPersonsQuery, eventPersonsSelect, batchSize);
// persons by immunization
List<Person> immunizationPersonsResultList = new ArrayList<>();
if (!featureConfigurationFacade.isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) {
CriteriaQuery<Person> immunizationPersonsQuery = cb.createQuery(Person.class);
Root<Immunization> immunizationPersonsRoot = immunizationPersonsQuery.from(Immunization.class);
Join<Immunization, Person> immunizationPersonsSelect = immunizationPersonsRoot.join(Immunization.PERSON);
immunizationPersonsSelect.fetch(Person.ADDRESS);
immunizationPersonsQuery.select(immunizationPersonsSelect);
Predicate immunizationPersonsFilter = immunizationService.createUserFilter(cb, immunizationPersonsQuery, immunizationPersonsRoot);
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, immunizationPersonsSelect, DateHelper.toTimestampUpper(date), lastSynchronizedUuid);
if (batchSize == null) {
Predicate immunizationDateFilter = immunizationService.createChangeDateFilter(cb, immunizationPersonsRoot, DateHelper.toTimestampUpper(date));
dateFilter = cb.or(dateFilter, immunizationDateFilter);
}
immunizationPersonsFilter = and(cb, immunizationPersonsFilter, dateFilter);
}
if (immunizationPersonsFilter != null) {
immunizationPersonsQuery.where(immunizationPersonsFilter);
}
immunizationPersonsQuery.distinct(true);
immunizationPersonsResultList = getBatchedQueryResults(cb, immunizationPersonsQuery, immunizationPersonsSelect, batchSize);
}
List<Person> travelEntryPersonsResultList = new ArrayList<>();
// if a batch size is given, this is a sync from the mobile app where travel entries are not relevant for now
if (batchSize == null) {
// persons by travel entries
CriteriaQuery<Person> tepQuery = cb.createQuery(Person.class);
Root<TravelEntry> tepRoot = tepQuery.from(TravelEntry.class);
Join<TravelEntry, Person> tepSelect = tepRoot.join(TravelEntry.PERSON);
tepSelect.fetch(Person.ADDRESS);
tepQuery.select(tepSelect);
Predicate tepFilter = travelEntryService.createUserFilter(cb, tepQuery, tepRoot);
// date range
if (date != null) {
Predicate dateFilter = createChangeDateFilter(cb, tepSelect, DateHelper.toTimestampUpper(date));
Predicate travelEntryDateFilter = travelEntryService.createChangeDateFilter(cb, tepRoot, DateHelper.toTimestampUpper(date));
tepFilter = and(cb, tepFilter, cb.or(dateFilter, travelEntryDateFilter));
}
if (tepFilter != null) {
tepQuery.where(tepFilter);
}
tepQuery.distinct(true);
travelEntryPersonsResultList = em.createQuery(tepQuery).getResultList();
}
return Stream.of(lgaResultList, casePersonsResultList, contactPersonsResultList, eventPersonsResultList, immunizationPersonsResultList, travelEntryPersonsResultList).flatMap(List<Person>::stream).distinct().sorted(new ChangeDateUuidComparator<>()).limit(batchSize == null ? Long.MAX_VALUE : batchSize).collect(Collectors.toList());
}
use of de.symeda.sormas.backend.caze.Case in project SORMAS-Project by hzi-braunschweig.
the class PersonService method getSimilarPersonDtos.
public List<SimilarPersonDto> getSimilarPersonDtos(PersonSimilarityCriteria criteria, Integer limit) {
setSimilarityThresholdQuery();
boolean activeEntriesOnly = configFacade.isDuplicateChecksExcludePersonsOfArchivedEntries();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> personQuery = cb.createQuery(Person.class);
Root<Person> personRoot = personQuery.from(Person.class);
Join<Person, Case> personCaseJoin = personRoot.join(Person.CASES, JoinType.LEFT);
Join<Person, Contact> personContactJoin = personRoot.join(Person.CONTACTS, JoinType.LEFT);
Join<Person, EventParticipant> personEventParticipantJoin = personRoot.join(Person.EVENT_PARTICIPANTS, JoinType.LEFT);
Join<Person, Immunization> personImmunizationJoin = personRoot.join(Person.IMMUNIZATIONS, JoinType.LEFT);
Join<Person, TravelEntry> personTravelEntryJoin = personRoot.join(Person.TRAVEL_ENTRIES, JoinType.LEFT);
// Persons of active cases
Predicate personSimilarityFilter = buildSimilarityCriteriaFilter(criteria, cb, personRoot);
Predicate activeCasesFilter = activeEntriesOnly ? caseService.createActiveCasesFilter(cb, personCaseJoin) : caseService.createDefaultFilter(cb, personCaseJoin);
Predicate caseUserFilter = caseService.createUserFilter(cb, personQuery, personCaseJoin);
Predicate personCasePredicate = and(cb, personCaseJoin.get(Case.ID).isNotNull(), activeCasesFilter, caseUserFilter);
// Persons of active contacts
Predicate activeContactsFilter = activeEntriesOnly ? contactService.createActiveContactsFilter(cb, personContactJoin) : contactService.createDefaultFilter(cb, personContactJoin);
Predicate contactUserFilter = contactService.createUserFilter(cb, personQuery, personContactJoin);
Predicate personContactPredicate = and(cb, personContactJoin.get(Contact.ID).isNotNull(), contactUserFilter, activeContactsFilter);
// Persons of event participants in active events
Predicate activeEventParticipantsFilter = activeEntriesOnly ? eventParticipantService.createActiveEventParticipantsInActiveEventsFilter(cb, personEventParticipantJoin) : eventParticipantService.createDefaultInUndeletedEventsFilter(cb, personEventParticipantJoin);
Predicate eventParticipantUserFilter = eventParticipantService.createUserFilter(cb, personQuery, personEventParticipantJoin);
Predicate personEventParticipantPredicate = and(cb, personEventParticipantJoin.get(EventParticipant.ID).isNotNull(), activeEventParticipantsFilter, eventParticipantUserFilter);
// Persons of active immunizations
Predicate personImmunizationPredicate = null;
if (!featureConfigurationFacade.isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) {
Predicate activeImmunizationsFilter = activeEntriesOnly ? immunizationService.createActiveImmunizationsFilter(cb, personImmunizationJoin) : immunizationService.createDefaultFilter(cb, personImmunizationJoin);
Predicate immunizationUserFilter = immunizationService.createUserFilter(cb, personQuery, personImmunizationJoin);
personImmunizationPredicate = and(cb, personImmunizationJoin.get(Immunization.ID).isNotNull(), immunizationUserFilter, activeImmunizationsFilter);
}
// Persons of active travel entries
Predicate activeTravelEntriesFilter = activeEntriesOnly ? travelEntryService.createActiveTravelEntriesFilter(cb, personTravelEntryJoin) : travelEntryService.createDefaultFilter(cb, personTravelEntryJoin);
Predicate travelEntryUserFilter = travelEntryService.createUserFilter(cb, personQuery, personTravelEntryJoin);
Predicate personTravelEntryPredicate = and(cb, personTravelEntryJoin.get(TravelEntry.ID).isNotNull(), travelEntryUserFilter, activeTravelEntriesFilter);
Predicate finalPredicate = CriteriaBuilderHelper.or(cb, personCasePredicate, personContactPredicate, personEventParticipantPredicate, personImmunizationPredicate, personTravelEntryPredicate);
personQuery.where(and(cb, personSimilarityFilter, finalPredicate));
personQuery.distinct(true);
TypedQuery<Person> query = em.createQuery(personQuery);
if (limit != null) {
query.setMaxResults(limit);
}
List<Person> persons = query.getResultList();
List<Long> personsInJurisdiction = getInJurisdictionIDs(persons);
return persons.stream().filter(p -> personsInJurisdiction.contains(p.getId())).map(this::toSimilarPersonDto).collect(Collectors.toList());
}
use of de.symeda.sormas.backend.caze.Case in project SORMAS-Project by hzi-braunschweig.
the class AdditionalTestService method createActiveSamplesFilter.
/**
* Creates a filter that excludes all samples that are {@link DeletableAdo#deleted} or associated with
* cases that are {@link Case#archived}, contacts that are {@link Contact#deleted}. or event participants that are
* {@link EventParticipant#deleted}
*/
public Predicate createActiveSamplesFilter(CriteriaBuilder cb, Root<AdditionalTest> root) {
Join<AdditionalTest, Sample> sample = root.join(AdditionalTest.SAMPLE, JoinType.LEFT);
Join<Sample, Case> caze = sample.join(Sample.ASSOCIATED_CASE, JoinType.LEFT);
Join<Sample, Contact> contact = sample.join(Sample.ASSOCIATED_CONTACT, JoinType.LEFT);
Join<Sample, EventParticipant> event = sample.join(Sample.ASSOCIATED_EVENT_PARTICIPANT, JoinType.LEFT);
Predicate pred = cb.or(cb.isFalse(caze.get(Case.ARCHIVED)), cb.isFalse(contact.get(Contact.DELETED)), cb.isFalse(event.get(EventParticipant.DELETED)));
return cb.and(pred, cb.isFalse(sample.get(Sample.DELETED)));
}
Aggregations