Search in sources :

Example 1 with ContactImportSimilarityResult

use of de.symeda.sormas.ui.importer.ContactImportSimilarityResult in project SORMAS-Project by hzi-braunschweig.

the class ContactImporter method importDataFromCsvLine.

@Override
protected ImportLineResult importDataFromCsvLine(String[] values, String[] entityClasses, String[] entityProperties, String[][] entityPropertyPaths, boolean firstLine) throws IOException, InterruptedException {
    // Check whether the new line has the same length as the header line
    if (values.length > entityProperties.length) {
        writeImportError(values, I18nProperties.getValidationError(Validations.importLineTooLong));
        return ImportLineResult.ERROR;
    }
    // regenerate the UUID to prevent overwrite in case of export and import of the same entities
    int uuidIndex = ArrayUtils.indexOf(entityProperties, ContactDto.UUID);
    if (uuidIndex >= 0) {
        values[uuidIndex] = DataHelper.createUuid();
    }
    final PersonDto newPersonTemp = PersonDto.buildImportEntity();
    final ContactDto newContactTemp = caze != null ? ContactDto.build(caze) : ContactDto.build();
    newContactTemp.setReportingUser(currentUser.toReference());
    final List<VaccinationDto> vaccinations = new ArrayList<>();
    ImportRelatedObjectsMapper.Builder relatedObjectsMapperBuilder = new ImportRelatedObjectsMapper.Builder();
    if (FacadeProvider.getFeatureConfigurationFacade().isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) {
        relatedObjectsMapperBuilder.addMapper(VaccinationDto.class, vaccinations, () -> VaccinationDto.build(currentUser.toReference()), this::insertColumnEntryIntoRelatedObject);
    }
    ImportRelatedObjectsMapper relatedMapper = relatedObjectsMapperBuilder.build();
    boolean contactHasImportError = insertRowIntoData(values, entityClasses, entityPropertyPaths, true, importColumnInformation -> {
        try {
            if (!relatedMapper.map(importColumnInformation)) {
                // If the cell entry is not empty, try to insert it into the current contact or person object
                if (!StringUtils.isEmpty(importColumnInformation.getValue())) {
                    insertColumnEntryIntoData(newContactTemp, newPersonTemp, importColumnInformation.getValue(), importColumnInformation.getEntityPropertyPath());
                }
            }
        } catch (ImportErrorException | InvalidColumnException e) {
            return e;
        }
        return null;
    });
    // try to assign the contact to an existing case
    if (caze == null && newContactTemp.getCaseIdExternalSystem() != null) {
        CaseDataDto existingCase = FacadeProvider.getCaseFacade().getCaseDataByUuid(newContactTemp.getCaseIdExternalSystem().trim());
        if (existingCase != null) {
            newContactTemp.assignCase(existingCase);
            newContactTemp.setCaseIdExternalSystem(null);
        }
    }
    // If the row does not have any import errors, call the backend validation of all associated entities
    if (!contactHasImportError) {
        try {
            FacadeProvider.getPersonFacade().validate(newPersonTemp);
            FacadeProvider.getContactFacade().validate(newContactTemp);
        } catch (ValidationRuntimeException e) {
            contactHasImportError = true;
            writeImportError(values, e.getMessage());
        }
    }
    PersonDto newPerson = newPersonTemp;
    // Sanitize non-HOME address
    PersonHelper.sanitizeNonHomeAddress(newPerson);
    // if there are any, display a window to resolve the conflict to the user
    if (!contactHasImportError) {
        try {
            ContactImportConsumer consumer = new ContactImportConsumer();
            ImportSimilarityResultOption resultOption = null;
            ContactImportLock personSelectLock = new ContactImportLock();
            // We need to pause the current thread to prevent the import from continuing until the user has acted
            synchronized (personSelectLock) {
                // Call the logic that allows the user to handle the similarity; once this has been done, the LOCK should be notified
                // to allow the importer to resume
                handlePersonSimilarity(newPerson, result -> consumer.onImportResult(result, personSelectLock), (person, similarityResultOption) -> new ContactImportSimilarityResult(person, null, similarityResultOption), Strings.infoSelectOrCreatePersonForImport, currentUI);
                try {
                    if (!personSelectLock.wasNotified) {
                        personSelectLock.wait();
                    }
                } catch (InterruptedException e) {
                    logger.error("InterruptedException when trying to perform LOCK.wait() in contact import: " + e.getMessage());
                    throw e;
                }
                if (consumer.result != null) {
                    resultOption = consumer.result.getResultOption();
                }
                // If the user picked an existing person, override the contact person with it
                if (ImportSimilarityResultOption.PICK.equals(resultOption)) {
                    newPerson = FacadeProvider.getPersonFacade().getPersonByUuid(consumer.result.getMatchingPerson().getUuid());
                }
            }
            // or an existing person was picked, save the contact and person to the database
            if (ImportSimilarityResultOption.SKIP.equals(resultOption)) {
                return ImportLineResult.SKIPPED;
            } else {
                boolean skipPersonValidation = ImportSimilarityResultOption.PICK.equals(resultOption);
                final PersonDto savedPerson = FacadeProvider.getPersonFacade().savePerson(newPerson, skipPersonValidation);
                newContactTemp.setPerson(savedPerson.toReference());
                ContactDto newContact = newContactTemp;
                final ContactImportLock contactSelectLock = new ContactImportLock();
                synchronized (contactSelectLock) {
                    handleContactSimilarity(newContactTemp, savedPerson, result -> consumer.onImportResult(result, contactSelectLock));
                    try {
                        if (!contactSelectLock.wasNotified) {
                            contactSelectLock.wait();
                        }
                    } catch (InterruptedException e) {
                        logger.error("InterruptedException when trying to perform LOCK.wait() in contact import: " + e.getMessage());
                        throw e;
                    }
                    if (consumer.result != null) {
                        resultOption = consumer.result.getResultOption();
                    }
                    if (ImportSimilarityResultOption.PICK.equals(resultOption)) {
                        newContact = FacadeProvider.getContactFacade().getByUuid(consumer.result.getMatchingContact().getUuid());
                    }
                }
                // Workaround: Reset the change date to avoid OutdatedEntityExceptions
                newContact.setChangeDate(new Date());
                FacadeProvider.getContactFacade().save(newContact, true, false);
                for (VaccinationDto vaccination : vaccinations) {
                    FacadeProvider.getVaccinationFacade().createWithImmunization(vaccination, newContact.getRegion(), newContact.getDistrict(), newContact.getPerson(), newContact.getDisease());
                }
                consumer.result = null;
                return ImportLineResult.SUCCESS;
            }
        } catch (ValidationRuntimeException e) {
            writeImportError(values, e.getMessage());
            return ImportLineResult.ERROR;
        }
    } else {
        return ImportLineResult.ERROR;
    }
}
Also used : ImportErrorException(de.symeda.sormas.api.importexport.ImportErrorException) CaseDataDto(de.symeda.sormas.api.caze.CaseDataDto) PersonDto(de.symeda.sormas.api.person.PersonDto) ArrayList(java.util.ArrayList) VaccinationDto(de.symeda.sormas.api.vaccination.VaccinationDto) ValidationRuntimeException(de.symeda.sormas.api.utils.ValidationRuntimeException) Date(java.util.Date) InvalidColumnException(de.symeda.sormas.api.importexport.InvalidColumnException) ContactDto(de.symeda.sormas.api.contact.ContactDto) SimilarContactDto(de.symeda.sormas.api.contact.SimilarContactDto) ContactImportSimilarityResult(de.symeda.sormas.ui.importer.ContactImportSimilarityResult) ImportSimilarityResultOption(de.symeda.sormas.ui.importer.ImportSimilarityResultOption) ImportRelatedObjectsMapper(de.symeda.sormas.api.importexport.ImportRelatedObjectsMapper)

Example 2 with ContactImportSimilarityResult

use of de.symeda.sormas.ui.importer.ContactImportSimilarityResult in project SORMAS-Project by hzi-braunschweig.

the class ContactImporterTest method testImportCaseContacts.

@Test
public void testImportCaseContacts() throws IOException, InvalidColumnException, InterruptedException, CsvValidationException, URISyntaxException {
    ContactFacadeEjb contactFacade = getBean(ContactFacadeEjbLocal.class);
    RDCF rdcf = creator.createRDCF("Abia", "Umuahia North", "Urban Ward 2", "Anelechi Hospital");
    UserDto user = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR);
    PersonDto casePerson = creator.createPerson("John", "Smith");
    CaseDataDto caze = creator.createCase(user.toReference(), casePerson.toReference(), Disease.CORONAVIRUS, CaseClassification.CONFIRMED, InvestigationStatus.PENDING, new Date(), rdcf);
    // Successful import of 5 case contacts
    File csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_success.csv").toURI());
    ContactImporter contactImporter = new ContactImporterExtension(csvFile, user, caze);
    ImportResultStatus importResult = contactImporter.runImport();
    assertEquals(ImportResultStatus.COMPLETED, importResult);
    assertEquals(5, contactFacade.count(null));
    // Person Similarity: pick
    List<SimilarPersonDto> persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria());
    csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_similarities.csv").toURI());
    contactImporter = new ContactImporterExtension(csvFile, user, caze) {

        @Override
        protected <T extends PersonImportSimilarityResult> void handlePersonSimilarity(PersonDto newPerson, Consumer<T> resultConsumer, BiFunction<SimilarPersonDto, ImportSimilarityResultOption, T> createSimilarityResult, String infoText, UI currentUI) {
            List<SimilarPersonDto> entries = new ArrayList<>();
            for (SimilarPersonDto person : persons) {
                if (PersonHelper.areNamesSimilar(newPerson.getFirstName(), newPerson.getLastName(), person.getFirstName(), person.getLastName(), null)) {
                    entries.add(person);
                }
            }
            resultConsumer.accept((T) new ContactImportSimilarityResult(entries.get(0), null, ImportSimilarityResultOption.PICK));
        }
    };
    importResult = contactImporter.runImport();
    assertEquals(ImportResultStatus.COMPLETED, importResult);
    assertEquals(6, contactFacade.count(null));
    assertEquals(6, getPersonFacade().getAllUuids().size());
    // Person Similarity: skip
    csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_similarities.csv").toURI());
    contactImporter = new ContactImporterExtension(csvFile, user, caze) {

        @Override
        protected <T extends PersonImportSimilarityResult> void handlePersonSimilarity(PersonDto newPerson, Consumer<T> resultConsumer, BiFunction<SimilarPersonDto, ImportSimilarityResultOption, T> createSimilarityResult, String infoText, UI currentUI) {
            resultConsumer.accept((T) new ContactImportSimilarityResult(null, null, ImportSimilarityResultOption.SKIP));
        }
    };
    importResult = contactImporter.runImport();
    assertEquals(ImportResultStatus.COMPLETED, importResult);
    assertEquals(6, contactFacade.count(null));
    assertEquals(6, getPersonFacade().getAllUuids().size());
    // Person Similarity: create
    csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_similarities.csv").toURI());
    contactImporter = new ContactImporterExtension(csvFile, user, caze);
    importResult = contactImporter.runImport();
    assertEquals(ImportResultStatus.COMPLETED, importResult);
    assertEquals(7, contactFacade.count(null));
    assertEquals(7, getPersonFacade().getAllUuids().size());
    // Test import contacts from a commented CSV file
    // Successful import of 5 case contacts
    csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_comment_success.csv").toURI());
    contactImporter = new ContactImporterExtension(csvFile, user, caze);
    importResult = contactImporter.runImport();
    assertEquals(ImportResultStatus.COMPLETED, importResult);
    assertEquals(12, contactFacade.count(null));
}
Also used : CaseDataDto(de.symeda.sormas.api.caze.CaseDataDto) PersonDto(de.symeda.sormas.api.person.PersonDto) SimilarPersonDto(de.symeda.sormas.api.person.SimilarPersonDto) UserDto(de.symeda.sormas.api.user.UserDto) ContactFacadeEjb(de.symeda.sormas.backend.contact.ContactFacadeEjb) Date(java.util.Date) PersonSimilarityCriteria(de.symeda.sormas.api.person.PersonSimilarityCriteria) SimilarPersonDto(de.symeda.sormas.api.person.SimilarPersonDto) RDCF(de.symeda.sormas.ui.TestDataCreator.RDCF) UI(com.vaadin.ui.UI) ContactImportSimilarityResult(de.symeda.sormas.ui.importer.ContactImportSimilarityResult) ImportSimilarityResultOption(de.symeda.sormas.ui.importer.ImportSimilarityResultOption) ImportResultStatus(de.symeda.sormas.ui.importer.ImportResultStatus) List(java.util.List) ArrayList(java.util.ArrayList) File(java.io.File) AbstractBeanTest(de.symeda.sormas.ui.AbstractBeanTest) Test(org.junit.Test)

Example 3 with ContactImportSimilarityResult

use of de.symeda.sormas.ui.importer.ContactImportSimilarityResult in project SORMAS-Project by hzi-braunschweig.

the class ContactImporter method handleContactSimilarity.

protected void handleContactSimilarity(ContactDto newContact, PersonDto person, Consumer<ContactImportSimilarityResult> resultConsumer) {
    currentUI.accessSynchronously(() -> {
        ContactSelectionField contactSelection = new ContactSelectionField(newContact, I18nProperties.getString(Strings.infoSelectOrCreateContactImport), person.getFirstName(), person.getLastName());
        contactSelection.setWidth(1024, Unit.PIXELS);
        if (contactSelection.hasMatches()) {
            final CommitDiscardWrapperComponent<ContactSelectionField> component = new CommitDiscardWrapperComponent<>(contactSelection);
            component.addCommitListener(() -> {
                SimilarContactDto similarContactDto = contactSelection.getValue();
                if (similarContactDto == null) {
                    resultConsumer.accept(new ContactImportSimilarityResult(null, null, ImportSimilarityResultOption.CREATE));
                } else {
                    resultConsumer.accept(new ContactImportSimilarityResult(null, similarContactDto, ImportSimilarityResultOption.PICK));
                }
            });
            component.addDiscardListener(() -> resultConsumer.accept(new ContactImportSimilarityResult(null, null, ImportSimilarityResultOption.SKIP)));
            contactSelection.setSelectionChangeCallback((commitAllowed) -> {
                component.getCommitButton().setEnabled(commitAllowed);
            });
            VaadinUiUtil.showModalPopupWindow(component, I18nProperties.getString(Strings.headingPickOrCreateContact));
            contactSelection.selectBestMatch();
        } else {
            resultConsumer.accept(new ContactImportSimilarityResult(null, null, ImportSimilarityResultOption.CREATE));
        }
    });
}
Also used : ContactImportSimilarityResult(de.symeda.sormas.ui.importer.ContactImportSimilarityResult) CommitDiscardWrapperComponent(de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent) SimilarContactDto(de.symeda.sormas.api.contact.SimilarContactDto) ContactSelectionField(de.symeda.sormas.ui.contact.ContactSelectionField)

Aggregations

ContactImportSimilarityResult (de.symeda.sormas.ui.importer.ContactImportSimilarityResult)3 CaseDataDto (de.symeda.sormas.api.caze.CaseDataDto)2 SimilarContactDto (de.symeda.sormas.api.contact.SimilarContactDto)2 PersonDto (de.symeda.sormas.api.person.PersonDto)2 ImportSimilarityResultOption (de.symeda.sormas.ui.importer.ImportSimilarityResultOption)2 ArrayList (java.util.ArrayList)2 Date (java.util.Date)2 UI (com.vaadin.ui.UI)1 ContactDto (de.symeda.sormas.api.contact.ContactDto)1 ImportErrorException (de.symeda.sormas.api.importexport.ImportErrorException)1 ImportRelatedObjectsMapper (de.symeda.sormas.api.importexport.ImportRelatedObjectsMapper)1 InvalidColumnException (de.symeda.sormas.api.importexport.InvalidColumnException)1 PersonSimilarityCriteria (de.symeda.sormas.api.person.PersonSimilarityCriteria)1 SimilarPersonDto (de.symeda.sormas.api.person.SimilarPersonDto)1 UserDto (de.symeda.sormas.api.user.UserDto)1 ValidationRuntimeException (de.symeda.sormas.api.utils.ValidationRuntimeException)1 VaccinationDto (de.symeda.sormas.api.vaccination.VaccinationDto)1 ContactFacadeEjb (de.symeda.sormas.backend.contact.ContactFacadeEjb)1 AbstractBeanTest (de.symeda.sormas.ui.AbstractBeanTest)1 RDCF (de.symeda.sormas.ui.TestDataCreator.RDCF)1