Search in sources :

Example 1 with CrdPrefetch

use of org.hl7.davinci.r4.crdhook.CrdPrefetch 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 CrdPrefetch

use of org.hl7.davinci.r4.crdhook.CrdPrefetch in project CRD by HL7-DaVinci.

the class QueryBatchRequest method performQueryBatchRequest.

/**
 * Backfills the missing required values of the response that prefetch may have missed.
 * This implementation pulls the IDs of the required references from the request object's draft
 * orders, checks which of those values are missing from the current CRD response, builds the
 * Query Batch JSON request using
 * http://build.fhir.org/ig/HL7/davinci-crd/hooks.html#fhir-resource-access,
 * then populates the CRD response with the response from the Query Batch.
 */
public void performQueryBatchRequest(CdsRequest<?, ?> cdsRequest, CrdPrefetch crdPrefetch) {
    logger.info("***** ***** Performing Query Batch Request.");
    CrdPrefetch crdResponse = crdPrefetch;
    // The list of references that should be queried in the batch request.
    List<String> requiredReferences = new ArrayList<String>();
    // Get the IDs of references in the request's draft orders.
    Bundle draftOrdersBundle = cdsRequest.getContext().getDraftOrders();
    // This assumes that only the first draft order is relevant.
    Resource initialRequestResource = draftOrdersBundle.getEntry().get(0).getResource();
    ResourceType requestType = initialRequestResource.getResourceType();
    // Extract the references by iterating through the JSON.
    Gson gson = new Gson();
    final JsonObject jsonObject = gson.toJsonTree(initialRequestResource).getAsJsonObject();
    for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
        FhirRequestProcessor.extractReferenceIds(requiredReferences, entry.getValue());
    }
    // Filter out references that already exist in the CRD Response.
    requiredReferences = requiredReferences.stream().filter(referenceId -> !crdResponse.containsRequestResourceId(referenceId)).collect(Collectors.toList());
    logger.info("References to query: " + requiredReferences);
    if (requiredReferences.isEmpty()) {
        logger.info("A Query Batch Request is not needed: all references have already already fetched.");
        return;
    }
    // Build the Query Batch Request JSON.
    Bundle queryBatchRequestBundle = buildQueryBatchRequestBundle(requiredReferences);
    String queryBatchRequestBody = FhirContext.forR4().newJsonParser().encodeResourceToString(queryBatchRequestBundle);
    // Make the query batch request to the EHR server.
    Bundle queryResponseBundle = null;
    try {
        logger.info("Executing Query Batch Request: " + queryBatchRequestBody);
        queryResponseBundle = (Bundle) FhirRequestProcessor.executeFhirQueryBody(queryBatchRequestBody, cdsRequest, this.fhirComponents, HttpMethod.POST);
        queryResponseBundle = extractNestedBundledResources(queryResponseBundle);
        logger.info("Extracted Query Batch Resources: " + (queryResponseBundle).getEntry().stream().map(entry -> entry.getResource()).collect(Collectors.toList()));
    } catch (Exception e) {
        logger.error("Failed to backfill prefetch with Query Batch Request " + queryBatchRequestBody, e);
    }
    if (queryResponseBundle == null) {
        logger.error("No response recieved from the Query Batch Request.");
        return;
    }
    // Add the request resource to the query batch response as it may be missing.
    // Coverage and Subject are not automatically being
    // linked to the request object. It seems to somehow automatically link during
    // standard prefetch, but not here so we're doing it manually.
    List<Coverage> coverages = FhirRequestProcessor.extractCoverageFromBundle(queryResponseBundle);
    List<Patient> patients = FhirRequestProcessor.extractPatientsFromBundle(queryResponseBundle);
    FhirRequestProcessor.addInsuranceAndSubject(initialRequestResource, patients, coverages);
    BundleEntryComponent newEntry = new BundleEntryComponent();
    newEntry.setResource(initialRequestResource);
    queryResponseBundle.addEntry(newEntry);
    // Add the query batch response resources to the CRD Prefetch request.
    logger.info("Query Batch Response Entries: " + queryResponseBundle.getEntry());
    FhirRequestProcessor.addToCrdPrefetchRequest(crdResponse, requestType, queryResponseBundle.getEntry());
    logger.info("Post-Query Batch CRDResponse: " + crdResponse);
}
Also used : CrdPrefetch(org.hl7.davinci.r4.crdhook.CrdPrefetch) JsonObject(com.google.gson.JsonObject) Logger(org.slf4j.Logger) FhirRequestProcessor(org.hl7.davinci.endpoint.cdshooks.services.crd.r4.FhirRequestProcessor) LoggerFactory(org.slf4j.LoggerFactory) HttpMethod(org.springframework.http.HttpMethod) Resource(org.hl7.fhir.r4.model.Resource) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) HTTPVerb(org.hl7.fhir.r4.model.Bundle.HTTPVerb) JsonElement(com.google.gson.JsonElement) FhirComponentsT(org.hl7.davinci.FhirComponentsT) BundleEntryRequestComponent(org.hl7.fhir.r4.model.Bundle.BundleEntryRequestComponent) ResourceType(org.hl7.fhir.r4.model.ResourceType) FhirContext(ca.uhn.fhir.context.FhirContext) List(java.util.List) Gson(com.google.gson.Gson) Map(java.util.Map) BundleEntryComponent(org.hl7.fhir.r4.model.Bundle.BundleEntryComponent) Bundle(org.hl7.fhir.r4.model.Bundle) CdsRequest(org.cdshooks.CdsRequest) BundleType(org.hl7.fhir.r4.model.Bundle.BundleType) Coverage(org.hl7.fhir.r4.model.Coverage) Patient(org.hl7.fhir.r4.model.Patient) Bundle(org.hl7.fhir.r4.model.Bundle) ArrayList(java.util.ArrayList) Resource(org.hl7.fhir.r4.model.Resource) Gson(com.google.gson.Gson) JsonObject(com.google.gson.JsonObject) Patient(org.hl7.fhir.r4.model.Patient) ResourceType(org.hl7.fhir.r4.model.ResourceType) Coverage(org.hl7.fhir.r4.model.Coverage) BundleEntryComponent(org.hl7.fhir.r4.model.Bundle.BundleEntryComponent) JsonElement(com.google.gson.JsonElement) CrdPrefetch(org.hl7.davinci.r4.crdhook.CrdPrefetch) Map(java.util.Map)

Example 3 with CrdPrefetch

use of org.hl7.davinci.r4.crdhook.CrdPrefetch in project CRD by HL7-DaVinci.

the class CrdRequestCreator method createOrderSignRequest.

/**
 * Generate a order sign request that contains a ServiceRequest.
 *
 * @param patientGender Desired gender of the patient in the request
 * @param patientBirthdate Desired birth date of the patient in the request
 * @return Fully populated CdsRequest
 */
public static OrderSignRequest createOrderSignRequest(Enumerations.AdministrativeGender patientGender, Date patientBirthdate, String patientAddressState, String providerAddressState) {
    OrderSignRequest request = new OrderSignRequest();
    request.setHook(Hook.ORDER_SIGN);
    request.setHookInstance(UUID.randomUUID().toString());
    OrderSignContext context = new OrderSignContext();
    request.setContext(context);
    context.setUserId("Practitioner/1234");
    Patient patient = createPatient(patientGender, patientBirthdate, patientAddressState);
    context.setPatientId(patient.getId());
    ServiceRequest sr = new ServiceRequest();
    sr.setStatus(ServiceRequest.ServiceRequestStatus.DRAFT);
    sr.setId("DeviceRequest/123");
    sr.setIntent(ServiceRequest.ServiceRequestIntent.ORDER);
    PrefetchCallback callback = (p, c) -> {
        sr.addPerformer(new Reference(p));
        sr.addInsurance(new Reference(c));
    };
    sr.setSubject(new Reference(patient));
    Practitioner provider = createPractitioner();
    Bundle prefetchBundle = createPrefetchBundle(patient, provider, callback, providerAddressState);
    Coding oxygen = new Coding().setCode("A0426").setSystem("https://bluebutton.cms.gov/resources/codesystem/hcpcs").setDisplay("Ambulance service, advanced life support, non-emergency transport, level 1 (als 1)");
    sr.setCode(new CodeableConcept().addCoding(oxygen).setText("Ambulance service Non-Emergency Transport"));
    Bundle orderBundle = new Bundle();
    Bundle.BundleEntryComponent bec = new Bundle.BundleEntryComponent();
    bec.setResource(sr);
    orderBundle.addEntry(bec);
    Bundle.BundleEntryComponent pfDrBec = new Bundle.BundleEntryComponent();
    pfDrBec.setResource(sr);
    prefetchBundle.addEntry(pfDrBec);
    context.setDraftOrders(orderBundle);
    Device device = new Device();
    device.setType(new CodeableConcept().addCoding(oxygen));
    bec = new Bundle.BundleEntryComponent();
    bec.setResource(device);
    prefetchBundle.addEntry(bec);
    CrdPrefetch prefetch = new CrdPrefetch();
    prefetch.setServiceRequestBundle(prefetchBundle);
    request.setPrefetch(prefetch);
    return request;
}
Also used : CrdPrefetch(org.hl7.davinci.r4.crdhook.CrdPrefetch) Logger(org.slf4j.Logger) OrderSignContext(org.hl7.davinci.r4.crdhook.ordersign.OrderSignContext) Date(java.util.Date) org.hl7.fhir.r4.model(org.hl7.fhir.r4.model) LoggerFactory(org.slf4j.LoggerFactory) UUID(java.util.UUID) OrderSignRequest(org.hl7.davinci.r4.crdhook.ordersign.OrderSignRequest) OrderSelectContext(org.hl7.davinci.r4.crdhook.orderselect.OrderSelectContext) AddressUse(org.hl7.fhir.r4.model.Address.AddressUse) ArrayList(java.util.ArrayList) List(java.util.List) OrderSelectRequest(org.hl7.davinci.r4.crdhook.orderselect.OrderSelectRequest) Hook(org.cdshooks.Hook) AddressType(org.hl7.fhir.r4.model.Address.AddressType) OrderSignContext(org.hl7.davinci.r4.crdhook.ordersign.OrderSignContext) CrdPrefetch(org.hl7.davinci.r4.crdhook.CrdPrefetch) OrderSignRequest(org.hl7.davinci.r4.crdhook.ordersign.OrderSignRequest)

Example 4 with CrdPrefetch

use of org.hl7.davinci.r4.crdhook.CrdPrefetch 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)

Example 5 with CrdPrefetch

use of org.hl7.davinci.r4.crdhook.CrdPrefetch in project CRD by HL7-DaVinci.

the class OrderSignService method createCqlExecutionContexts.

@Override
public List<CoverageRequirementRuleResult> createCqlExecutionContexts(OrderSignRequest orderSignRequest, FileStore fileStore, String baseUrl) {
    FhirBundleProcessor fhirBundleProcessor = new FhirBundleProcessor(fileStore, baseUrl);
    CrdPrefetch prefetch = orderSignRequest.getPrefetch();
    fhirBundleProcessor.processDeviceRequests(prefetch.getDeviceRequestBundle());
    fhirBundleProcessor.processMedicationRequests(prefetch.getMedicationRequestBundle());
    fhirBundleProcessor.processServiceRequests(prefetch.getServiceRequestBundle());
    fhirBundleProcessor.processMedicationDispenses(prefetch.getMedicationDispenseBundle());
    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)

Aggregations

CrdPrefetch (org.hl7.davinci.r4.crdhook.CrdPrefetch)5 ArrayList (java.util.ArrayList)4 List (java.util.List)4 Date (java.util.Date)3 CoverageRequirementRuleResult (org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult)3 OrderSelectRequest (org.hl7.davinci.r4.crdhook.orderselect.OrderSelectRequest)3 Logger (org.slf4j.Logger)3 LoggerFactory (org.slf4j.LoggerFactory)3 Gson (com.google.gson.Gson)2 UUID (java.util.UUID)2 Hook (org.cdshooks.Hook)2 OrderSelectContext (org.hl7.davinci.r4.crdhook.orderselect.OrderSelectContext)2 OrderSignContext (org.hl7.davinci.r4.crdhook.ordersign.OrderSignContext)2 OrderSignRequest (org.hl7.davinci.r4.crdhook.ordersign.OrderSignRequest)2 org.hl7.fhir.r4.model (org.hl7.fhir.r4.model)2 AddressType (org.hl7.fhir.r4.model.Address.AddressType)2 AddressUse (org.hl7.fhir.r4.model.Address.AddressUse)2 FhirContext (ca.uhn.fhir.context.FhirContext)1 JsonElement (com.google.gson.JsonElement)1 JsonObject (com.google.gson.JsonObject)1