Skip to content

Commit 114b51c

Browse files
Merge pull request #285 from HL7-DaVinci/CRD-Card-Configuration
Added additional card configurations
2 parents a5f922d + 6935d25 commit 114b51c

File tree

8 files changed

+168
-65
lines changed

8 files changed

+168
-65
lines changed

resources/src/main/java/org/cdshooks/Configuration.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,22 @@ public class Configuration {
1010

1111
@JsonProperty("alt-drug")
1212
private Boolean alternativeTherapy = true;
13+
@JsonProperty("dtr-clin")
14+
private Boolean dtrClin = true;
15+
@JsonProperty("prior-auth")
16+
private Boolean priorAuth = true;
17+
@JsonProperty("coverage")
18+
private Boolean coverage = true;
19+
20+
@JsonProperty("max-cards")
21+
private int maxCards = 10;
1322

1423
public Boolean getAlternativeTherapy() { return alternativeTherapy; }
1524

1625
public void setAlternativeTherapy(Boolean alternativeTherapy) { this.alternativeTherapy = alternativeTherapy; }
26+
27+
public Boolean getDTRClin() { return dtrClin; }
28+
public Boolean getPriorAuth() { return priorAuth; }
29+
public Boolean getCoverage() { return coverage; }
30+
public int getMaxCards() { return maxCards; }
1731
}

resources/src/main/java/org/cdshooks/CoverageRequirements.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.cdshooks;
22

3+
import org.apache.commons.lang3.StringUtils;
4+
35
import java.util.UUID;
46

57
public class CoverageRequirements {
@@ -171,4 +173,15 @@ public String getQuestionnaireAdditionalUri() {
171173
public void setQuestionnaireAdditionalUri(String questionnaireAdditionalUri) {
172174
this.questionnaireAdditionalUri = questionnaireAdditionalUri;
173175
}
176+
177+
public boolean hasQuestionnaireUri() {
178+
return StringUtils.isNotEmpty(this.questionnaireOrderUri)
179+
|| StringUtils.isNotEmpty(this.questionnaireFaceToFaceUri)
180+
|| StringUtils.isNotEmpty(this.questionnaireLabUri)
181+
|| StringUtils.isNotEmpty(this.questionnaireProgressNoteUri)
182+
|| StringUtils.isNotEmpty(this.questionnairePARequestUri)
183+
|| StringUtils.isNotEmpty(this.questionnairePlanOfCareUri)
184+
|| StringUtils.isNotEmpty(this.questionnaireDispenseUri)
185+
|| StringUtils.isNotEmpty(this.questionnaireAdditionalUri);
186+
}
174187
}

resources/src/main/java/org/hl7/davinci/r4/crdhook/ConfigurationOption.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ public class ConfigurationOption {
99
private String name;
1010
private String description;
1111
@JsonProperty("value")
12-
private Boolean defaultValue;
12+
private String defaultValue;
1313

14-
public ConfigurationOption(String code, String type, String name, String description, Boolean defaultValue) {
14+
public ConfigurationOption(String code, String type, String name, String description, String defaultValue) {
1515
this.code = code;
1616
this.type = type;
1717
this.name = name;
@@ -35,7 +35,7 @@ public ConfigurationOption(String code, String type, String name, String descrip
3535

3636
public void setDescription(String description) { this.description = description; }
3737

38-
public Boolean getDefaultValue() { return defaultValue; }
38+
public String getDefaultValue() { return defaultValue; }
3939

40-
public void setDefaultValue(Boolean defaultValue) { this.defaultValue = defaultValue; }
40+
public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; }
4141
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
package org.hl7.davinci.r4.crdhook.orderselect;
22

3+
import org.cdshooks.Configuration;
4+
import org.hl7.davinci.r4.crdhook.ConfigurationOption;
5+
36
public class CrdExtensionConfigurationOptions {
7+
public static final ConfigurationOption COVERAGE = new ConfigurationOption(
8+
"coverage",
9+
"boolean",
10+
"Coverage",
11+
"Provides indications of whether coverage is required for the proposed order",
12+
new Configuration().getPriorAuth().toString()
13+
);
14+
15+
public static final ConfigurationOption MAX_CARDS = new ConfigurationOption(
16+
"max-cards",
17+
"integer",
18+
"Maximum cards",
19+
"Indicates the maximum number of cards to be returned from the service. The services will prioritize cards such as highest priority ones are delivered",
20+
String.valueOf(new Configuration().getMaxCards())
21+
);
422
}

resources/src/main/java/org/hl7/davinci/r4/crdhook/ordersign/CrdExtensionConfigurationOptions.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,44 @@
88
* Configuration.java.
99
*/
1010
public class CrdExtensionConfigurationOptions {
11-
1211
public static final ConfigurationOption ALTERNATIVE_THERAPY = new ConfigurationOption(
1312
"alt-drug",
1413
"boolean",
1514
"Alternative therapy",
1615
"Provides recommendations for alternative therapy with equivalent/similar "
1716
+ "clinical effect for which the patient has better coverage, that will incur lesser code",
18-
new Configuration().getAlternativeTherapy()
17+
new Configuration().getAlternativeTherapy().toString()
18+
);
19+
20+
public static final ConfigurationOption DTR_CLIN = new ConfigurationOption(
21+
"dtr-clin",
22+
"boolean",
23+
"DTR Clin",
24+
"Indication that DTR is relevant for prior authorization, claim or other documentation requirements and that at least some clinical information needs to be captured",
25+
new Configuration().getDTRClin().toString()
26+
);
27+
28+
public static final ConfigurationOption PRIOR_AUTH = new ConfigurationOption(
29+
"prior-auth",
30+
"boolean",
31+
"Prior Auth",
32+
"Provides indications of whether prior authorization is required for the proposed order",
33+
new Configuration().getPriorAuth().toString()
34+
);
35+
36+
public static final ConfigurationOption COVERAGE = new ConfigurationOption(
37+
"coverage",
38+
"boolean",
39+
"Coverage",
40+
"Provides indications of whether coverage is required for the proposed order",
41+
new Configuration().getPriorAuth().toString()
42+
);
43+
44+
public static final ConfigurationOption MAX_CARDS = new ConfigurationOption(
45+
"max-cards",
46+
"integer",
47+
"Maximum cards",
48+
"Indicates the maximum number of cards to be returned from the service. The services will prioritize cards such as highest priority ones are delivered",
49+
String.valueOf(new Configuration().getMaxCards())
1950
);
2051
}

server/src/main/java/org/hl7/davinci/endpoint/cdshooks/services/crd/CdsService.java

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult;
2020
import org.hl7.davinci.r4.CardTypes;
2121
import org.hl7.davinci.r4.CoverageGuidance;
22+
import org.hl7.davinci.r4.crdhook.ConfigurationOption;
2223
import org.hl7.davinci.r4.crdhook.DiscoveryExtension;
2324
import org.hl7.davinci.r4.crdhook.orderselect.OrderSelectRequest;
2425
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -195,78 +196,91 @@ public CdsResponse handleRequest(@Valid @RequestBody requestTypeT request, URL a
195196
// no error cards on empty when order-select request
196197

197198
boolean foundApplicableRule = false;
199+
int availableCardsLeft = hookConfiguration.getMaxCards();
200+
198201
for (CoverageRequirementRuleResult lookupResult : lookupResults) {
199202
requestLog.addTopic(requestService, lookupResult.getTopic());
200203
CqlResultsForCard results = executeCqlAndGetRelevantResults(lookupResult.getContext(), lookupResult.getTopic());
201204
CoverageRequirements coverageRequirements = results.getCoverageRequirements();
202205
cardBuilder.setDeidentifiedResourcesContainsPhi(lookupResult.getDeidentifiedResourceContainsPhi());
203206

204-
if (results.ruleApplies()) {
205-
foundApplicableRule = true;
206-
207-
if (results.getCoverageRequirements().getApplies()) {
208-
209-
// if prior auth already approved
210-
if (coverageRequirements.isPriorAuthApproved()) {
211-
response.addCard(cardBuilder.priorAuthCard(results, results.getRequest(), fhirComponents, coverageRequirements.getPriorAuthId(),
212-
request.getContext().getPatientId(), lookupResult.getCriteria().getPayorId(), request.getContext().getUserId(),
213-
applicationBaseUrl.toString() + "/fhir/" + fhirComponents.getFhirVersion().toString(),
214-
fhirResourceRepository));
215-
216-
} else if (coverageRequirements.isDocumentationRequired() || coverageRequirements.isPriorAuthRequired()) {
217-
if (StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireOrderUri())
218-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireFaceToFaceUri())
219-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireLabUri())
220-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireProgressNoteUri())
221-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnairePARequestUri())
222-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnairePlanOfCareUri())
223-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireDispenseUri())
224-
|| StringUtils.isNotEmpty(coverageRequirements.getQuestionnaireAdditionalUri())) {
225-
List<Link> smartAppLinks = createQuestionnaireLinks(request, applicationBaseUrl, lookupResult, results);
226-
227-
if (coverageRequirements.isPriorAuthRequired()) {
228-
Card card = cardBuilder.transform(CardTypes.PRIOR_AUTH, results, smartAppLinks);
229-
card.addSuggestionsItem(cardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents,
230-
"Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note",
231-
true, CoverageGuidance.ADMIN));
232-
response.addCard(card);
233-
} else if (coverageRequirements.isDocumentationRequired()) {
234-
Card card = cardBuilder.transform(CardTypes.DTR_CLIN, results, smartAppLinks);
235-
card.addSuggestionsItem(cardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents,
236-
"Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note",
237-
true, CoverageGuidance.CLINICAL));
238-
response.addCard(card);
239-
}
240-
241-
// add a card for an alternative therapy if there is one
242-
if (results.getAlternativeTherapy().getApplies() && hookConfiguration.getAlternativeTherapy()) {
243-
try {
244-
response.addCard(cardBuilder.alternativeTherapyCard(results.getAlternativeTherapy(),
245-
results.getRequest(), fhirComponents));
246-
} catch (RuntimeException e) {
247-
logger.warn("Failed to process alternative therapy: " + e.getMessage());
248-
}
249-
}
250-
} else {
251-
logger.warn("Unspecified Questionnaire URI; summary card sent to client");
207+
if (!results.ruleApplies())
208+
continue;
209+
210+
logger.info(String.valueOf(availableCardsLeft));
211+
212+
if (availableCardsLeft <= 0)
213+
break;
214+
215+
foundApplicableRule = true;
216+
217+
if (results.getCoverageRequirements().getApplies()) {
218+
// if prior auth already approved
219+
if (coverageRequirements.isPriorAuthApproved()) {
220+
response.addCard(cardBuilder.priorAuthCard(results, results.getRequest(), fhirComponents, coverageRequirements.getPriorAuthId(),
221+
request.getContext().getPatientId(), lookupResult.getCriteria().getPayorId(), request.getContext().getUserId(),
222+
applicationBaseUrl.toString() + "/fhir/" + fhirComponents.getFhirVersion().toString(),
223+
fhirResourceRepository));
224+
break;
225+
}
226+
227+
if (coverageRequirements.isDocumentationRequired() || coverageRequirements.isPriorAuthRequired()) {
228+
if (!coverageRequirements.hasQuestionnaireUri()) {
229+
logger.warn("Unspecified Questionnaire URI; summary card sent to client");
230+
if (hookConfiguration.getCoverage()) {
252231
response.addCard(cardBuilder.transform(CardTypes.COVERAGE, results));
253232
}
254-
} else {
255-
// no prior auth or documentation required
256-
logger.info("Add the no doc or prior auth required card");
257-
Card card = cardBuilder.transform(CardTypes.COVERAGE, results);
233+
break;
234+
}
235+
236+
List<Link> smartAppLinks = createQuestionnaireLinks(request, applicationBaseUrl, lookupResult, results);
237+
238+
if (coverageRequirements.isPriorAuthRequired() && hookConfiguration.getPriorAuth()) {
239+
Card card = cardBuilder.transform(CardTypes.PRIOR_AUTH, results, smartAppLinks);
258240
card.addSuggestionsItem(cardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents,
259241
"Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note",
260-
true, CoverageGuidance.COVERED));
261-
card.setSelectionBehavior(Card.SelectionBehaviorEnum.ANY);
242+
true, CoverageGuidance.ADMIN));
243+
response.addCard(card);
244+
availableCardsLeft--;
245+
} else if (coverageRequirements.isDocumentationRequired() && hookConfiguration.getDTRClin()) {
246+
Card card = cardBuilder.transform(CardTypes.DTR_CLIN, results, smartAppLinks);
247+
card.addSuggestionsItem(cardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents,
248+
"Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note",
249+
true, CoverageGuidance.CLINICAL));
262250
response.addCard(card);
251+
availableCardsLeft--;
263252
}
253+
254+
// add a card for an alternative therapy if there is one
255+
if (availableCardsLeft != 0 && results.getAlternativeTherapy().getApplies() && hookConfiguration.getAlternativeTherapy()) {
256+
try {
257+
response.addCard(cardBuilder.alternativeTherapyCard(results.getAlternativeTherapy(),
258+
results.getRequest(), fhirComponents));
259+
} catch (RuntimeException e) {
260+
logger.warn("Failed to process alternative therapy: " + e.getMessage());
261+
}
262+
}
263+
break;
264264
}
265265

266-
// apply the DrugInteractions
267-
if (results.getDrugInteraction().getApplies()) {
268-
response.addCard(cardBuilder.drugInteractionCard(results.getDrugInteraction(), results.getRequest()));
266+
// no prior auth or documentation required
267+
logger.info("Add the no doc or prior auth required card");
268+
if (availableCardsLeft != 0 && hookConfiguration.getCoverage()) {
269+
Card card = cardBuilder.transform(CardTypes.COVERAGE, results);
270+
card.addSuggestionsItem(cardBuilder.createSuggestionWithNote(card, results.getRequest(), fhirComponents,
271+
"Save Update To EHR", "Update original " + results.getRequest().fhirType() + " to add note",
272+
true, CoverageGuidance.COVERED));
273+
card.setSelectionBehavior(Card.SelectionBehaviorEnum.ANY);
274+
response.addCard(card);
269275
}
276+
277+
logger.info(String.valueOf(availableCardsLeft));
278+
}
279+
280+
// apply the DrugInteractions
281+
if (availableCardsLeft != 0 && results.getDrugInteraction().getApplies()) {
282+
response.addCard(cardBuilder.drugInteractionCard(results.getDrugInteraction(), results.getRequest()));
283+
availableCardsLeft--;
270284
}
271285
}
272286

server/src/main/java/org/hl7/davinci/endpoint/cdshooks/services/crd/r4/OrderSelectService.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
import org.hl7.davinci.endpoint.files.FileStore;
1818
import org.hl7.davinci.endpoint.rules.CoverageRequirementRuleResult;
1919
import org.hl7.davinci.r4.FhirComponents;
20+
import org.hl7.davinci.r4.crdhook.ConfigurationOption;
2021
import org.hl7.davinci.r4.crdhook.CrdPrefetch;
22+
import org.hl7.davinci.r4.crdhook.DiscoveryExtension;
23+
import org.hl7.davinci.r4.crdhook.orderselect.CrdExtensionConfigurationOptions;
2124
import org.hl7.davinci.r4.crdhook.orderselect.CrdPrefetchTemplateElements;
2225
import org.hl7.davinci.r4.crdhook.orderselect.OrderSelectRequest;
2326
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -44,7 +47,13 @@ public class OrderSelectService extends CdsService<OrderSelectRequest> {
4447
public static final FhirComponents FHIRCOMPONENTS = new FhirComponents();
4548
static final Logger logger = LoggerFactory.getLogger(OrderSelectService.class);
4649

47-
public OrderSelectService() { super(ID, HOOK, TITLE, DESCRIPTION, PREFETCH_ELEMENTS, FHIRCOMPONENTS, null); }
50+
public static final List<ConfigurationOption> CONFIGURATION_OPTIONS = Arrays.asList(
51+
CrdExtensionConfigurationOptions.COVERAGE,
52+
CrdExtensionConfigurationOptions.MAX_CARDS
53+
);
54+
public static final DiscoveryExtension EXTENSION = new DiscoveryExtension(CONFIGURATION_OPTIONS);
55+
56+
public OrderSelectService() { super(ID, HOOK, TITLE, DESCRIPTION, PREFETCH_ELEMENTS, FHIRCOMPONENTS, EXTENSION); }
4857

4958
@Override
5059
public List<CoverageRequirementRuleResult> createCqlExecutionContexts(OrderSelectRequest orderSelectRequest, FileStore fileStore, String baseUrl) {

server/src/main/java/org/hl7/davinci/endpoint/cdshooks/services/crd/r4/OrderSignService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ public class OrderSignService extends CdsService<OrderSignRequest> {
5353
static final Logger logger = LoggerFactory.getLogger(OrderSignService.class);
5454

5555
public static final List<ConfigurationOption> CONFIGURATION_OPTIONS = Arrays.asList(
56-
CrdExtensionConfigurationOptions.ALTERNATIVE_THERAPY
56+
CrdExtensionConfigurationOptions.ALTERNATIVE_THERAPY,
57+
CrdExtensionConfigurationOptions.DTR_CLIN,
58+
CrdExtensionConfigurationOptions.PRIOR_AUTH,
59+
CrdExtensionConfigurationOptions.COVERAGE,
60+
CrdExtensionConfigurationOptions.MAX_CARDS
5761
);
5862
public static final DiscoveryExtension EXTENSION = new DiscoveryExtension(CONFIGURATION_OPTIONS);
5963

0 commit comments

Comments
 (0)