Search in sources :

Example 1 with FileStore

use of org.hl7.davinci.endpoint.files.FileStore in project CRD by HL7-DaVinci.

the class OrderSelectService method createCqlExecutionContexts.

@Override
public List<CoverageRequirementRuleResult> createCqlExecutionContexts(OrderSelectRequest orderSelectRequest, FileStore fileStore, String baseUrl) {
    List<String> selections = Arrays.asList(orderSelectRequest.getContext().getSelections());
    FhirBundleProcessor fhirBundleProcessor = new FhirBundleProcessor(fileStore, baseUrl, selections);
    CrdPrefetch prefetch = orderSelectRequest.getPrefetch();
    fhirBundleProcessor.processOrderSelectMedicationStatements(prefetch.getMedicationRequestBundle(), prefetch.getMedicationStatementBundle());
    List<CoverageRequirementRuleResult> results = fhirBundleProcessor.getResults();
    if (results.isEmpty()) {
        throw RequestIncompleteException.NoSupportedBundlesFound();
    }
    return results;
}
Also used : CrdPrefetch(org.hl7.davinci.r4.crdhook.CrdPrefetch) CoverageRequirementRuleResult(org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult)

Example 2 with FileStore

use of org.hl7.davinci.endpoint.files.FileStore in project CRD by HL7-DaVinci.

the class QuestionnaireValueSetProcessor method findAndReplaceValueSetReferences.

/**
 * Recursively visits every questionnaire item and replaces every `answerValueSet` that isn't a local
 * hash (#) reference into a local reference. This fills the valueSetMap with the loaded valuesets.
 *
 * @param itemComponents The item components to visit.
 * @param valueSetMap A mapping of ValueSet urls to loaded valuesets that should be filled as references are found.
 * @param fileStore The file store that is used to load valuesets from.
 * @param baseUrl The base url of the server from the request. Used to identify local valuesets.
 */
private void findAndReplaceValueSetReferences(List<QuestionnaireItemComponent> itemComponents, Map<String, ValueSet> valueSetMap, FileStore fileStore, String baseUrl) {
    for (QuestionnaireItemComponent itemComponent : itemComponents) {
        // If there is an answerValueSet field we need to do some work on this item
        if (itemComponent.hasAnswerValueSet()) {
            // Only look for a valueset to embed if it does not appear to be a hash reference
            if (!itemComponent.getAnswerValueSet().startsWith("#")) {
                logger.info("answerValueSet found with url - " + itemComponent.getAnswerValueSet());
                String valueSetId = findAndLoadValueSet(itemComponent.getAnswerValueSet(), valueSetMap, fileStore, baseUrl);
                if (valueSetId != null) {
                    itemComponent.getAnswerValueSet();
                    itemComponent.setAnswerValueSet("#" + valueSetId);
                    logger.info("answerValueSet replaced with  - " + itemComponent.getAnswerValueSet());
                } else {
                    logger.warn("Referenced ValueSet: " + itemComponent.getAnswerValueSet() + " was not found.");
                }
            }
        }
        // Recurse down into child items.
        if (itemComponent.hasItem()) {
            findAndReplaceValueSetReferences(itemComponent.getItem(), valueSetMap, fileStore, baseUrl);
        }
    }
}
Also used : QuestionnaireItemComponent(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent)

Example 3 with FileStore

use of org.hl7.davinci.endpoint.files.FileStore in project CRD by HL7-DaVinci.

the class QuestionnaireValueSetProcessor method findAndLoadValueSet.

/**
 * Finds a value set, loads it and modifies its id and url fields to work in the contains field.
 *
 * @param url The canonical url of the valueset to look for.
 * @param valueSetMap The map of valuesets that have been loaded already.
 * @return The local ID to use for the valueset. null if valueset wasn't found.
 */
private String findAndLoadValueSet(String url, Map<String, ValueSet> valueSetMap, FileStore fileStore, String baseUrl) {
    if (valueSetMap.containsKey(url)) {
        return valueSetMap.get(url).getId();
    }
    FileResource valueSetFileResource;
    ValueSet valueSet;
    // If URL starts with this server's base url, pull out id and search by id
    if (url.startsWith(baseUrl)) {
        String valueSetId = url.split("ValueSet/")[1];
        valueSetFileResource = fileStore.getFhirResourceById("R4", "valueset", valueSetId, baseUrl);
    } else {
        valueSetFileResource = fileStore.getFhirResourceByUrl("R4", "valueset", url, baseUrl);
    }
    if (valueSetFileResource != null) {
        // parse value set and modify ID and #URL to match.
        valueSet = (ValueSet) this.parseFhirFileResource(valueSetFileResource);
        String valueSetId = valueSet.getIdElement().getIdPart();
        valueSet.setId(valueSetId);
        valueSet.setUrl("#" + valueSetId);
        // add it to the value set map so it can be reused
        valueSetMap.put(url, valueSet);
        return valueSetId;
    } else {
        return null;
    }
}
Also used : ValueSet(org.hl7.fhir.r4.model.ValueSet)

Example 4 with FileStore

use of org.hl7.davinci.endpoint.files.FileStore in project CRD by HL7-DaVinci.

the class SubQuestionnaireProcessor method processItem.

/**
 * Determines if this item is a sub-questionnaire reference and returns the items to replace it with. Returns the same list
 * otherwise. Also recursively continues scanning if this is just a grouping item.
 *
 * @param item The item to check for sub-questionnaire referece.
 * @param fileStore The FileStore to be used for fetching sub-questionnaires.
 * @param baseUrl The base url from the server.
 * @param containedList List of contained resources to put in the assembled Questionnaire. This will be filled while iterating.
 * @param extensionList List of extensions to put in the assembled Questionnaire. This will be filled while iterating.
 * @return New list of items to replace this item with.
 */
private List<QuestionnaireItemComponent> processItem(QuestionnaireItemComponent item, FileStore fileStore, String baseUrl, Hashtable<String, org.hl7.fhir.r4.model.Resource> containedList, List<Extension> extensionList) {
    // find if item has an extension is sub-questionnaire
    Extension e = item.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/sub-questionnaire");
    if (e != null) {
        // read sub questionnaire from file store
        CanonicalType value = e.castToCanonical(e.getValue());
        logger.info("SubQuestionnaireProcessor::parseItem(): Looking for SubQuestionnaire " + value);
        // strip the type off of the id if it is there
        String id = value.asStringValue();
        String[] parts = id.split("/");
        if (parts.length > 1) {
            id = parts[1];
        }
        boolean expandRootItem = false;
        Extension expand = item.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/sub-questionnaire-expand");
        if (expand != null) {
            expandRootItem = expand.castToBoolean(expand.getValue()).booleanValue();
        }
        FileResource subFileResource = fileStore.getFhirResourceById("R4", "questionnaire", id, baseUrl, false);
        if (subFileResource != null) {
            Questionnaire subQuestionnaire = (Questionnaire) this.parseFhirFileResource(subFileResource);
            if (subQuestionnaire != null) {
                // merge extensions
                for (Extension subExtension : subQuestionnaire.getExtension()) {
                    if (extensionList.stream().noneMatch(ext -> ext.equalsDeep(subExtension))) {
                        extensionList.add(subExtension);
                    }
                }
                // merge contained resources
                for (org.hl7.fhir.r4.model.Resource r : subQuestionnaire.getContained()) {
                    containedList.put(r.getId(), r);
                }
                List<QuestionnaireItemComponent> rootItems = subQuestionnaire.getItem();
                // there are more than one root items in sub questionnaire, don't expand
                if (!expandRootItem || rootItems.size() > 1) {
                    return rootItems;
                } else {
                    return rootItems.get(0).getItem();
                }
            } else {
                // SubQuestionnaire could not be loaded
                logger.warn("SubQuestionnaireProcessor::parseItem(): Could not load SubQuestionnaire " + value.asStringValue());
                return Arrays.asList(item);
            }
        } else {
            // SubQuestionnaire could not be found
            logger.warn("SubQuestionnaireProcessor::parseItem(): Could not find SubQuestionnaire " + value.asStringValue());
            return Arrays.asList(item);
        }
    }
    // parse sub-items
    this.processItemList(item.getItem(), fileStore, baseUrl, containedList, extensionList);
    return Arrays.asList(item);
}
Also used : QuestionnaireItemComponent(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent) Questionnaire(org.hl7.fhir.r4.model.Questionnaire) CanonicalType(org.hl7.fhir.r4.model.CanonicalType) Extension(org.hl7.fhir.r4.model.Extension)

Example 5 with FileStore

use of org.hl7.davinci.endpoint.files.FileStore in project CRD by HL7-DaVinci.

the class CdsService method handleRequest.

/**
 * Performs generic operations for incoming requests of any type.
 *
 * @param request the generically typed incoming request
 * @return The response from the server
 */
public CdsResponse handleRequest(@Valid @RequestBody requestTypeT request, URL applicationBaseUrl) {
    // create the RequestLog
    RequestLog requestLog = new RequestLog(request, new Date().getTime(), this.fhirComponents.getFhirVersion().toString(), this.id, requestService, 5);
    // Parsed request
    requestLog.advanceTimeline(requestService);
    PrefetchHydrator prefetchHydrator = new PrefetchHydrator(this, request, this.fhirComponents);
    prefetchHydrator.hydrate();
    // hydrated
    requestLog.advanceTimeline(requestService);
    // Attempt a Query Batch Request to backfill missing attributes.
    if (myConfig.isQueryBatchRequest()) {
        QueryBatchRequest qbr = new QueryBatchRequest(this.fhirComponents);
        this.attempQueryBatchRequest(request, qbr);
    }
    logger.info("***** ***** request from requestLog: " + requestLog.toString());
    CdsResponse response = new CdsResponse();
    Gson gson = new Gson();
    final String jsonObject = gson.toJson(request.getPrefetch());
    logger.info("Final populated CRDPrefetch: " + jsonObject);
    // CQL Fetched
    List<CoverageRequirementRuleResult> lookupResults;
    try {
        lookupResults = this.createCqlExecutionContexts(request, fileStore, applicationBaseUrl.toString() + "/");
        requestLog.advanceTimeline(requestService);
    } catch (RequestIncompleteException e) {
        logger.warn("RequestIncompleteException " + request);
        logger.warn(e.getMessage() + "; summary card sent to client");
        response.addCard(CardBuilder.summaryCard(CardTypes.COVERAGE, e.getMessage()));
        requestLog.setCardListFromCards(response.getCards());
        requestLog.setResults(e.getMessage());
        requestService.edit(requestLog);
        return response;
    }
    // process the extension for the configuration
    // load hook configuration with default values
    Configuration hookConfiguration = new Configuration();
    Extension extension = request.getExtension();
    if (extension != null) {
        if (extension.getConfiguration() != null) {
            hookConfiguration = extension.getConfiguration();
        }
    }
    boolean errorCardOnEmpty = !(request instanceof OrderSelectRequest);
    // no error cards on empty when order-select request
    boolean foundApplicableRule = false;
    for (CoverageRequirementRuleResult lookupResult : lookupResults) {
        requestLog.addTopic(requestService, lookupResult.getTopic());
        CqlResultsForCard results = executeCqlAndGetRelevantResults(lookupResult.getContext(), lookupResult.getTopic());
        CoverageRequirements coverageRequirements = results.getCoverageRequirements();
        if (results.ruleApplies()) {
            foundApplicableRule = true;
            if (results.getCoverageRequirements().getApplies()) {
                // if prior auth already approved
                if (coverageRequirements.isPriorAuthApproved()) {
                    response.addCard(CardBuilder.priorAuthCard(results, results.getRequest(), fhirComponents, coverageRequirements.getPriorAuthId(), request.getContext().getPatientId(), lookupResult.getCriteria().getPayorId(), request.getContext().getUserId(), applicationBaseUrl.toString() + "/fhir/" + fhirComponents.getFhirVersion().toString(), fhirResourceRepository));
                } else if (coverageRequirements.isDocumentationRequired() || coverageRequirements.isPriorAuthRequired()) {
                    if (StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireOrderUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireFaceToFaceUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireLabUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireProgressNoteUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnairePARequestUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnairePlanOfCareUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireDispenseUri()) || StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireAdditionalUri())) {
                        List<Link> smartAppLinks = createQuestionnaireLinks(request, applicationBaseUrl, lookupResult, results);
                        if (coverageRequirements.isPriorAuthRequired()) {
                            Card card = CardBuilder.transform(CardTypes.PRIOR_AUTH, results, smartAppLinks);
                            card.addSuggestionsItem(CardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents, "Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note", true, CoverageGuidance.ADMIN));
                            response.addCard(card);
                        } else if (coverageRequirements.isDocumentationRequired()) {
                            Card card = CardBuilder.transform(CardTypes.DTR_CLIN, results, smartAppLinks);
                            card.addSuggestionsItem(CardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents, "Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note", true, CoverageGuidance.CLINICAL));
                            response.addCard(card);
                        }
                        // add a card for an alternative therapy if there is one
                        if (results.getAlternativeTherapy().getApplies() && hookConfiguration.getAlternativeTherapy()) {
                            try {
                                response.addCard(CardBuilder.alternativeTherapyCard(results.getAlternativeTherapy(), results.getRequest(), fhirComponents));
                            } catch (RuntimeException e) {
                                logger.warn("Failed to process alternative therapy: " + e.getMessage());
                            }
                        }
                    } else {
                        logger.warn("Unspecified Questionnaire URI; summary card sent to client");
                        response.addCard(CardBuilder.transform(CardTypes.COVERAGE, results));
                    }
                } else {
                    // no prior auth or documentation required
                    logger.info("Add the no doc or prior auth required card");
                    Card card = CardBuilder.transform(CardTypes.COVERAGE, results);
                    card.addSuggestionsItem(CardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents, "Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note", true, CoverageGuidance.COVERED));
                    card.setSelectionBehavior(Card.SelectionBehaviorEnum.ANY);
                    response.addCard(card);
                }
            }
            // apply the DrugInteractions
            if (results.getDrugInteraction().getApplies()) {
                response.addCard(CardBuilder.drugInteractionCard(results.getDrugInteraction(), results.getRequest()));
            }
        }
    }
    // CQL Executed
    requestLog.advanceTimeline(requestService);
    if (errorCardOnEmpty) {
        if (!foundApplicableRule) {
            String msg = "No documentation rules found";
            logger.warn(msg + "; summary card sent to client");
            response.addCard(CardBuilder.summaryCard(CardTypes.COVERAGE, msg));
        }
        CardBuilder.errorCardIfNonePresent(CardTypes.COVERAGE, response);
    }
    // Ading card to requestLog
    requestLog.setCardListFromCards(response.getCards());
    requestService.edit(requestLog);
    return response;
}
Also used : CqlResultsForCard(org.hl7.davinci.endpoint.components.CardBuilder.CqlResultsForCard) OrderSelectRequest(org.hl7.davinci.r4.crdhook.orderselect.OrderSelectRequest) PrefetchHydrator(org.hl7.davinci.endpoint.components.PrefetchHydrator) Gson(com.google.gson.Gson) Date(java.util.Date) CqlResultsForCard(org.hl7.davinci.endpoint.components.CardBuilder.CqlResultsForCard) DiscoveryExtension(org.hl7.davinci.r4.crdhook.DiscoveryExtension) RequestLog(org.hl7.davinci.endpoint.database.RequestLog) RequestIncompleteException(org.hl7.davinci.RequestIncompleteException) CoverageRequirementRuleResult(org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult) ArrayList(java.util.ArrayList) List(java.util.List) QueryBatchRequest(org.hl7.davinci.endpoint.components.QueryBatchRequest)

Aggregations

ArrayList (java.util.ArrayList)4 Questionnaire (org.hl7.fhir.r4.model.Questionnaire)4 DataFormatException (ca.uhn.fhir.parser.DataFormatException)3 CoverageRequirementRuleResult (org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult)3 Extension (org.hl7.fhir.r4.model.Extension)3 FhirContext (ca.uhn.fhir.context.FhirContext)2 IParser (ca.uhn.fhir.parser.IParser)2 FileNotFoundException (java.io.FileNotFoundException)2 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 List (java.util.List)2 FileResource (org.hl7.davinci.endpoint.files.FileResource)2 CrdPrefetch (org.hl7.davinci.r4.crdhook.CrdPrefetch)2 QuestionnaireItemComponent (org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent)2 Reference (org.hl7.fhir.r4.model.Reference)2 Resource (org.hl7.fhir.r4.model.Resource)2 HttpStatus (org.springframework.http.HttpStatus)2 MediaType (org.springframework.http.MediaType)2 Gson (com.google.gson.Gson)1 Date (java.util.Date)1