Search in sources :

Example 1 with ConceptAnswer

use of org.openmrs.ConceptAnswer in project openmrs-core by openmrs.

the class ConceptAnswersEditor method setAsText.

/**
 * loops over the textbox assigned to this property. The textbox is assumed to be a string of
 * conceptIds^drugIds separated by spaces.
 *
 * @param text list of conceptIds (not conceptAnswerIds)
 * @should set the sort weights with the least possible changes
 */
@Override
public void setAsText(String text) throws IllegalArgumentException {
    if (StringUtils.hasText(text)) {
        ConceptService cs = Context.getConceptService();
        String[] conceptIds = text.split(" ");
        List<String> requestConceptIds = new ArrayList<>();
        // set up parameter answer Set for easier add/delete functions and removal of duplicates
        for (String id : conceptIds) {
            id = id.trim();
            if (!("".equals(id)) && !requestConceptIds.contains(id)) {
                // remove whitespace, blank lines, and duplicates
                requestConceptIds.add(id);
            }
        }
        Collection<ConceptAnswer> deletedConceptAnswers = new HashSet<>();
        // loop over original concept answers to find any deleted answers
        for (ConceptAnswer origConceptAnswer : originalConceptAnswers) {
            boolean answerDeleted = true;
            for (String conceptId : requestConceptIds) {
                Integer id = getConceptId(conceptId);
                Integer drugId = getDrugId(conceptId);
                Drug answerDrug = origConceptAnswer.getAnswerDrug();
                if (id.equals(origConceptAnswer.getAnswerConcept().getConceptId())) {
                    if (drugId == null && answerDrug == null) {
                        answerDeleted = false;
                    } else if ((drugId != null && answerDrug != null) && drugId.equals(origConceptAnswer.getAnswerDrug().getDrugId())) {
                        answerDeleted = false;
                    }
                }
            }
            if (answerDeleted) {
                deletedConceptAnswers.add(origConceptAnswer);
            }
        }
        // loop over those deleted answers to delete them
        for (ConceptAnswer conceptAnswer : deletedConceptAnswers) {
            originalConceptAnswers.remove(conceptAnswer);
        }
        // loop over concept ids in the request to add any that are new
        for (String conceptId : requestConceptIds) {
            Integer id = getConceptId(conceptId);
            Integer drugId = getDrugId(conceptId);
            boolean newAnswerConcept = true;
            for (ConceptAnswer origConceptAnswer : originalConceptAnswers) {
                Drug answerDrug = origConceptAnswer.getAnswerDrug();
                if (id.equals(origConceptAnswer.getAnswerConcept().getConceptId())) {
                    if (drugId == null && answerDrug == null) {
                        newAnswerConcept = false;
                    } else if ((drugId != null && answerDrug != null) && drugId.equals(answerDrug.getDrugId())) {
                        newAnswerConcept = false;
                    }
                }
            }
            // if the current request answer is new, add it to the originals
            if (newAnswerConcept) {
                Concept answer = cs.getConcept(id);
                Drug drug = null;
                if (drugId != null) {
                    drug = cs.getDrug(drugId);
                }
                ConceptAnswer ac = new ConceptAnswer(answer, drug);
                originalConceptAnswers.add(ac);
            }
        }
        // loop over to set the order
        // as the list comes into 'requestConceptIds' in the order the user wants
        // there are 2 conditions that will require the sort_weights to be reassigned
        // 1) any ConceptAnswer.sortWeight == NULL (meaning it is just added)
        // 2) the list is not in ASCENDING order (example sort order of the list is 1, 2, 10, 9)
        // -startIdx (start index) is where in this list we will start to reassign the sort_weights
        Double lastWeightSeen = null;
        // the idx to start at, if we have a NULL sort weight (new concept answer) or sort weights are not ascending
        int startIdx = -1;
        for (int i = 0; i < requestConceptIds.size() - 1; i++) {
            Integer id1 = getConceptId(requestConceptIds.get(i));
            ConceptAnswer ca1 = getConceptAnswerFromOriginal(id1);
            if (ca1.getSortWeight() == null) {
                if (lastWeightSeen == null) {
                    // start at 1, we're at the beginning
                    lastWeightSeen = 1d;
                } else {
                    // we start at +1
                    lastWeightSeen += 1;
                }
                startIdx = i;
                break;
            }
            Integer id2 = getConceptId(requestConceptIds.get(i + 1));
            ConceptAnswer ca2 = getConceptAnswerFromOriginal(id2);
            int c = ca1.compareTo(ca2);
            if (c > 0) {
                startIdx = i;
                lastWeightSeen = ca1.getSortWeight();
                break;
            }
            lastWeightSeen = ca1.getSortWeight();
        }
        if (startIdx != -1) {
            // then we need to re-weight
            for (int i = startIdx; i < requestConceptIds.size(); i++) {
                Integer id = getConceptId(requestConceptIds.get(i));
                ConceptAnswer ca = getConceptAnswerFromOriginal(id);
                ca.setSortWeight(lastWeightSeen++);
            }
        }
        log.debug("originalConceptAnswers.getConceptId(): ");
        for (ConceptAnswer a : originalConceptAnswers) {
            log.debug("id: " + a.getAnswerConcept().getConceptId());
        }
        log.debug("requestConceptIds: ");
        for (String i : requestConceptIds) {
            log.debug("id: " + i);
        }
    } else {
        originalConceptAnswers.clear();
    }
    setValue(originalConceptAnswers);
}
Also used : Drug(org.openmrs.Drug) Concept(org.openmrs.Concept) ConceptAnswer(org.openmrs.ConceptAnswer) ArrayList(java.util.ArrayList) ConceptService(org.openmrs.api.ConceptService) HashSet(java.util.HashSet)

Example 2 with ConceptAnswer

use of org.openmrs.ConceptAnswer in project openmrs-core by openmrs.

the class ConceptAnswersEditorTest method setAsText_shouldSetTheSortWeightsWithTheLeastPossibleChanges.

/**
 * @see ConceptAnswersEditor#setAsText(String)
 */
@Test
public void setAsText_shouldSetTheSortWeightsWithTheLeastPossibleChanges() {
    ConceptService service = Context.getConceptService();
    Concept c = service.getConcept(21);
    ConceptAnswersEditor editor = new ConceptAnswersEditor(c.getAnswers(true));
    editor.setAsText("22 7 8");
    // conceptId=7
    ConceptAnswer ca1 = service.getConceptAnswer(1);
    // conceptId=8
    ConceptAnswer ca2 = service.getConceptAnswer(2);
    // conceptId=22
    ConceptAnswer ca3 = service.getConceptAnswer(3);
    Concept cafter = service.getConcept(21);
    Assert.assertEquals(3, cafter.getAnswers(true).size());
    Assert.assertTrue(ca3.getSortWeight() < ca1.getSortWeight());
    Assert.assertTrue(ca1.getSortWeight() < ca2.getSortWeight());
}
Also used : Concept(org.openmrs.Concept) ConceptAnswer(org.openmrs.ConceptAnswer) ConceptService(org.openmrs.api.ConceptService) Test(org.junit.Test) BaseContextSensitiveTest(org.openmrs.test.BaseContextSensitiveTest)

Example 3 with ConceptAnswer

use of org.openmrs.ConceptAnswer in project openmrs-core by openmrs.

the class ConceptValidator method validate.

/**
 * Checks that a given concept object is valid.
 *
 * @see org.springframework.validation.Validator#validate(java.lang.Object,
 *      org.springframework.validation.Errors)
 * @should pass if the concept has at least one fully specified name added to it
 * @should fail if there is a duplicate unretired concept name in the locale
 * @should fail if there is a duplicate unretired preferred name in the same locale
 * @should fail if there is a duplicate unretired fully specified name in the same locale
 * @should fail if any names in the same locale for this concept are similar
 * @should pass if the concept with a duplicate name is retired
 * @should pass if the concept being validated is retired and has a duplicate name
 * @should fail if any name is an empty string
 * @should fail if the object parameter is null
 * @should pass if the concept is being updated with no name change
 * @should fail if any name is a null value
 * @should not allow multiple preferred names in a given locale
 * @should not allow multiple fully specified conceptNames in a given locale
 * @should not allow multiple short names in a given locale
 * @should not allow an index term to be a locale preferred name
 * @should fail if there is no name explicitly marked as fully specified
 * @should pass if the duplicate ConceptName is neither preferred nor fully Specified
 * @should pass if the concept has a synonym that is also a short name
 * @should fail if a term is mapped multiple times to the same concept
 * @should not fail if a term has two new mappings on it
 * @should fail if there is a duplicate unretired concept name in the same locale different than
 *         the system locale
 * @should pass for a new concept with a map created with deprecated concept map methods
 * @should pass for an edited concept with a map created with deprecated concept map methods
 * @should pass validation if field lengths are correct
 * @should fail validation if field lengths are not correct
 * @should pass if fully specified name is the same as short name
 * @should pass if different concepts have the same short name
 * @should fail if the concept datatype is null
 * @should fail if the concept class is null
 */
@Override
public void validate(Object obj, Errors errors) throws APIException, DuplicateConceptNameException {
    if (obj == null || !(obj instanceof Concept)) {
        throw new IllegalArgumentException("The parameter obj should not be null and must be of type" + Concept.class);
    }
    Concept conceptToValidate = (Concept) obj;
    // no name to validate, but why is this the case?
    if (conceptToValidate.getNames().isEmpty()) {
        errors.reject("Concept.name.atLeastOneRequired");
        return;
    }
    ValidationUtils.rejectIfEmpty(errors, "datatype", "Concept.datatype.empty");
    ValidationUtils.rejectIfEmpty(errors, "conceptClass", "Concept.conceptClass.empty");
    boolean hasFullySpecifiedName = false;
    for (Locale conceptNameLocale : conceptToValidate.getAllConceptNameLocales()) {
        boolean fullySpecifiedNameForLocaleFound = false;
        boolean preferredNameForLocaleFound = false;
        boolean shortNameForLocaleFound = false;
        Set<String> validNamesFoundInLocale = new HashSet<>();
        Collection<ConceptName> namesInLocale = conceptToValidate.getNames(conceptNameLocale);
        for (ConceptName nameInLocale : namesInLocale) {
            if (StringUtils.isBlank(nameInLocale.getName())) {
                log.debug("Name in locale '" + conceptNameLocale.toString() + "' cannot be an empty string or white space");
                errors.reject("Concept.name.empty");
            }
            if (nameInLocale.getLocalePreferred() != null) {
                if (nameInLocale.getLocalePreferred() && !preferredNameForLocaleFound) {
                    if (nameInLocale.isIndexTerm()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be an index term");
                        errors.reject("Concept.error.preferredName.is.indexTerm");
                    } else if (nameInLocale.isShort()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be a short name");
                        errors.reject("Concept.error.preferredName.is.shortName");
                    } else if (nameInLocale.getVoided()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be a voided name");
                        errors.reject("Concept.error.preferredName.is.voided");
                    }
                    preferredNameForLocaleFound = true;
                } else // should have one preferred name per locale
                if (nameInLocale.getLocalePreferred() && preferredNameForLocaleFound) {
                    log.warn("Found multiple preferred names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleLocalePreferredNames");
                }
            }
            if (nameInLocale.isFullySpecifiedName()) {
                if (!hasFullySpecifiedName) {
                    hasFullySpecifiedName = true;
                }
                if (!fullySpecifiedNameForLocaleFound) {
                    fullySpecifiedNameForLocaleFound = true;
                } else {
                    log.warn("Found multiple fully specified names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleFullySpecifiedNames");
                }
                if (nameInLocale.getVoided()) {
                    log.warn("Fully Specified name in locale '" + conceptNameLocale.toString() + "' shouldn't be a voided name");
                    errors.reject("Concept.error.fullySpecifiedName.is.voided");
                }
            }
            if (nameInLocale.isShort()) {
                if (!shortNameForLocaleFound) {
                    shortNameForLocaleFound = true;
                } else // should have one short name per locale
                {
                    log.warn("Found multiple short names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleShortNames");
                }
            }
            // find duplicate names for a non-retired concept
            if (Context.getConceptService().isConceptNameDuplicate(nameInLocale)) {
                throw new DuplicateConceptNameException("'" + nameInLocale.getName() + "' is a duplicate name in locale '" + conceptNameLocale.toString() + "'");
            }
            // 
            if (errors.hasErrors()) {
                log.debug("Concept name '" + nameInLocale.getName() + "' for locale '" + conceptNameLocale + "' is invalid");
                // for different conceptNames
                return;
            }
            // except for short names
            if (!nameInLocale.isShort() && !validNamesFoundInLocale.add(nameInLocale.getName().toLowerCase())) {
                throw new DuplicateConceptNameException("'" + nameInLocale.getName() + "' is a duplicate name in locale '" + conceptNameLocale.toString() + "' for the same concept");
            }
            if (log.isDebugEnabled()) {
                log.debug("Valid name found: " + nameInLocale.getName());
            }
        }
    }
    // Ensure that each concept has at least a fully specified name
    if (!hasFullySpecifiedName) {
        log.debug("Concept has no fully specified name");
        errors.reject("Concept.error.no.FullySpecifiedName");
    }
    if (CollectionUtils.isNotEmpty(conceptToValidate.getConceptMappings())) {
        // validate all the concept maps
        int index = 0;
        Set<Integer> mappedTermIds = null;
        for (ConceptMap map : conceptToValidate.getConceptMappings()) {
            if (map.getConceptReferenceTerm().getConceptReferenceTermId() == null) {
                // if this term is getting created on the fly e.g. from old legacy code, validate it
                try {
                    errors.pushNestedPath("conceptMappings[" + index + "].conceptReferenceTerm");
                    ValidationUtils.invokeValidator(new ConceptReferenceTermValidator(), map.getConceptReferenceTerm(), errors);
                } finally {
                    errors.popNestedPath();
                }
            }
            // don't proceed to the next maps since the current one already has errors
            if (errors.hasErrors()) {
                return;
            }
            if (mappedTermIds == null) {
                mappedTermIds = new HashSet<>();
            }
            // if we already have a mapping to this term, reject it this map
            if (map.getConceptReferenceTerm().getId() != null && !mappedTermIds.add(map.getConceptReferenceTerm().getId())) {
                errors.rejectValue("conceptMappings[" + index + "]", "ConceptReferenceTerm.term.alreadyMapped", "Cannot map a reference term multiple times to the same concept");
            }
            index++;
        }
    }
    if (CollectionUtils.isNotEmpty(conceptToValidate.getAnswers())) {
        for (ConceptAnswer conceptAnswer : conceptToValidate.getAnswers()) {
            if (conceptAnswer.getAnswerConcept().equals(conceptToValidate)) {
                errors.reject("Concept.contains.itself.as.answer");
            }
        }
    }
    ValidateUtil.validateFieldLengths(errors, obj.getClass(), "version", "retireReason");
    super.validateAttributes(conceptToValidate, errors, Context.getConceptService().getAllConceptAttributeTypes());
}
Also used : Concept(org.openmrs.Concept) Locale(java.util.Locale) ConceptAnswer(org.openmrs.ConceptAnswer) DuplicateConceptNameException(org.openmrs.api.DuplicateConceptNameException) ConceptName(org.openmrs.ConceptName) ConceptMap(org.openmrs.ConceptMap) HashSet(java.util.HashSet)

Example 4 with ConceptAnswer

use of org.openmrs.ConceptAnswer in project openmrs-core by openmrs.

the class ConceptValidatorTest method validate_shouldFailIfCodedConceptContainsItselfAsAnAnswer.

@Test
public void validate_shouldFailIfCodedConceptContainsItselfAsAnAnswer() {
    Concept concept = conceptService.getConcept(30);
    ConceptAnswer conceptAnswer = new ConceptAnswer(concept);
    concept.addAnswer(conceptAnswer);
    Errors errors = new BindException(concept, "concept");
    validator.validate(concept, errors);
    assertThat(errors, hasGlobalErrors("Concept.contains.itself.as.answer"));
}
Also used : Concept(org.openmrs.Concept) Errors(org.springframework.validation.Errors) HasFieldErrors.hasFieldErrors(org.openmrs.test.matchers.HasFieldErrors.hasFieldErrors) HasGlobalErrors.hasGlobalErrors(org.openmrs.test.matchers.HasGlobalErrors.hasGlobalErrors) ConceptAnswer(org.openmrs.ConceptAnswer) BindException(org.springframework.validation.BindException) Test(org.junit.Test) BaseContextSensitiveTest(org.openmrs.test.BaseContextSensitiveTest)

Example 5 with ConceptAnswer

use of org.openmrs.ConceptAnswer in project openmrs-core by openmrs.

the class ConceptServiceTest method saveConcept_shouldSetAuditInfoIfAnItemIsRemovedFromAnyOfItsChildCollections.

/**
 * @see ConceptService#saveConcept(Concept)
 */
@Test
public void saveConcept_shouldSetAuditInfoIfAnItemIsRemovedFromAnyOfItsChildCollections() {
    Concept concept = conceptService.getConcept(3);
    Assert.assertNull(concept.getDateChanged());
    Assert.assertNull(concept.getChangedBy());
    Concept concept1 = conceptService.getConcept(5);
    ConceptAnswer conceptanswer = new ConceptAnswer(concept1);
    concept.addAnswer(conceptanswer);
    conceptService.saveConcept(concept);
    Assert.assertNotNull(concept.getDateChanged());
    Date date = concept.getDateChanged();
    Assert.assertTrue(concept.removeAnswer(conceptanswer));
    conceptService.saveConcept(concept);
    Assert.assertNotNull(concept.getDateChanged());
    Date date1 = concept.getDateChanged();
    Assert.assertFalse(date.equals(date1));
    Assert.assertNotNull(concept.getChangedBy());
}
Also used : OpenmrsMatchers.hasConcept(org.openmrs.test.OpenmrsMatchers.hasConcept) Concept(org.openmrs.Concept) ConceptAnswer(org.openmrs.ConceptAnswer) Date(java.util.Date) BaseContextSensitiveTest(org.openmrs.test.BaseContextSensitiveTest) Test(org.junit.Test)

Aggregations

ConceptAnswer (org.openmrs.ConceptAnswer)16 Concept (org.openmrs.Concept)11 Test (org.junit.Test)7 BaseContextSensitiveTest (org.openmrs.test.BaseContextSensitiveTest)6 ArrayList (java.util.ArrayList)4 ConceptName (org.openmrs.ConceptName)3 OpenmrsMatchers.hasConcept (org.openmrs.test.OpenmrsMatchers.hasConcept)3 Date (java.util.Date)2 HashSet (java.util.HashSet)2 Locale (java.util.Locale)2 Drug (org.openmrs.Drug)2 ConceptService (org.openmrs.api.ConceptService)2 HL7Exception (ca.uhn.hl7v2.HL7Exception)1 Type (ca.uhn.hl7v2.model.Type)1 Varies (ca.uhn.hl7v2.model.Varies)1 CE (ca.uhn.hl7v2.model.v25.datatype.CE)1 CWE (ca.uhn.hl7v2.model.v25.datatype.CWE)1 DT (ca.uhn.hl7v2.model.v25.datatype.DT)1 DTM (ca.uhn.hl7v2.model.v25.datatype.DTM)1 ED (ca.uhn.hl7v2.model.v25.datatype.ED)1